feat(users): add roles APIs (#63)
* feat(kvstore): add namespace operations for bool * feat(userstore): add methods for roles * chore(multiusers): remove useless todo * feat(multiusers): add apis for roles * test(roles): add e2e tests for role APIs * test(e2e/files): enable files tests
This commit is contained in:
parent
4b6f6d9e1f
commit
9748d0cab4
10 changed files with 316 additions and 11 deletions
|
@ -61,11 +61,50 @@ func (cl *SingleUserClient) AddUser(name, pwd, role string, token *http.Cookie)
|
||||||
}).
|
}).
|
||||||
End()
|
End()
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return nil, nil, errs
|
||||||
|
}
|
||||||
|
|
||||||
auResp := &multiusers.AddUserResp{}
|
auResp := &multiusers.AddUserResp{}
|
||||||
err := json.Unmarshal([]byte(body), auResp)
|
err := json.Unmarshal([]byte(body), auResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
return nil, nil, errs
|
return nil, nil, errs
|
||||||
}
|
}
|
||||||
return resp, auResp, nil
|
return resp, auResp, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *SingleUserClient) AddRole(role string, token *http.Cookie) (*http.Response, string, []error) {
|
||||||
|
return cl.r.Post(cl.url("/v1/roles/")).
|
||||||
|
AddCookie(token).
|
||||||
|
Send(multiusers.AddRoleReq{
|
||||||
|
Role: role,
|
||||||
|
}).
|
||||||
|
End()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *SingleUserClient) DelRole(role string, token *http.Cookie) (*http.Response, string, []error) {
|
||||||
|
return cl.r.Delete(cl.url("/v1/roles/")).
|
||||||
|
AddCookie(token).
|
||||||
|
Send(multiusers.DelRoleReq{
|
||||||
|
Role: role,
|
||||||
|
}).
|
||||||
|
End()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *SingleUserClient) ListRoles(token *http.Cookie) (*http.Response, *multiusers.ListRolesResp, []error) {
|
||||||
|
resp, body, errs := cl.r.Get(cl.url("/v1/roles/")).
|
||||||
|
AddCookie(token).
|
||||||
|
End()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return nil, nil, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
lsResp := &multiusers.ListRolesResp{}
|
||||||
|
err := json.Unmarshal([]byte(body), lsResp)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
return nil, nil, errs
|
||||||
|
}
|
||||||
|
return resp, lsResp, errs
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,7 +176,6 @@ func (h *MultiUsersSvc) AddUser(c *gin.Context) {
|
||||||
c.JSON(q.ErrResp(c, 400, err))
|
c.JSON(q.ErrResp(c, 400, err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO: check privilege?
|
|
||||||
|
|
||||||
// TODO: do more comprehensive validation
|
// TODO: do more comprehensive validation
|
||||||
// Role and duplicated name will be validated by the store
|
// Role and duplicated name will be validated by the store
|
||||||
|
@ -209,6 +208,73 @@ func (h *MultiUsersSvc) AddUser(c *gin.Context) {
|
||||||
c.JSON(200, &AddUserResp{ID: fmt.Sprint(uid)})
|
c.JSON(200, &AddUserResp{ID: fmt.Sprint(uid)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AddRoleReq struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *MultiUsersSvc) AddRole(c *gin.Context) {
|
||||||
|
req := &AddRoleReq{}
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(q.ErrResp(c, 400, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do more comprehensive validation
|
||||||
|
if len(req.Role) < 2 {
|
||||||
|
c.JSON(q.ErrResp(c, 400, errors.New("name length must be greater than 2")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := h.deps.Users().AddRole(req.Role)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(q.Resp(200))
|
||||||
|
}
|
||||||
|
|
||||||
|
type DelRoleReq struct {
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *MultiUsersSvc) DelRole(c *gin.Context) {
|
||||||
|
req := &DelRoleReq{}
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(q.ErrResp(c, 400, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: do more comprehensive validation
|
||||||
|
if len(req.Role) < 2 {
|
||||||
|
c.JSON(q.ErrResp(c, 400, errors.New("name length must be greater than 2")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := h.deps.Users().DelRole(req.Role)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(q.Resp(200))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListRolesReq struct{}
|
||||||
|
type ListRolesResp struct {
|
||||||
|
Roles map[string]bool `json:"roles"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *MultiUsersSvc) ListRoles(c *gin.Context) {
|
||||||
|
roles, err := h.deps.Users().ListRoles()
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(q.ErrResp(c, 500, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, &ListRolesResp{Roles: roles})
|
||||||
|
}
|
||||||
|
|
||||||
func (h *MultiUsersSvc) getUserInfo(c *gin.Context) (map[string]string, error) {
|
func (h *MultiUsersSvc) getUserInfo(c *gin.Context) (map[string]string, error) {
|
||||||
tokenStr, err := c.Cookie(TokenCookie)
|
tokenStr, err := c.Cookie(TokenCookie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -77,10 +77,14 @@ func (bp *BoltPvd) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *BoltPvd) GetBool(key string) (bool, bool) {
|
func (bp *BoltPvd) GetBool(key string) (bool, bool) {
|
||||||
|
return bp.GetBoolIn("bools", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *BoltPvd) GetBoolIn(ns, key string) (bool, bool) {
|
||||||
buf, ok := make([]byte, 1), false
|
buf, ok := make([]byte, 1), false
|
||||||
|
|
||||||
bp.db.View(func(tx *bolt.Tx) error {
|
bp.db.View(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket([]byte("bools"))
|
b := tx.Bucket([]byte(ns))
|
||||||
v := b.Get([]byte(key))
|
v := b.Get([]byte(key))
|
||||||
copy(buf, v)
|
copy(buf, v)
|
||||||
ok = v != nil
|
ok = v != nil
|
||||||
|
@ -92,23 +96,52 @@ func (bp *BoltPvd) GetBool(key string) (bool, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *BoltPvd) SetBool(key string, val bool) error {
|
func (bp *BoltPvd) SetBool(key string, val bool) error {
|
||||||
|
return bp.SetBoolIn("bools", key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *BoltPvd) SetBoolIn(ns, key string, val bool) error {
|
||||||
var bVal byte = 0
|
var bVal byte = 0
|
||||||
if val {
|
if val {
|
||||||
bVal = 1
|
bVal = 1
|
||||||
}
|
}
|
||||||
return bp.db.Update(func(tx *bolt.Tx) error {
|
return bp.db.Update(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket([]byte("bools"))
|
b := tx.Bucket([]byte(ns))
|
||||||
return b.Put([]byte(key), []byte{bVal})
|
return b.Put([]byte(key), []byte{bVal})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bp *BoltPvd) DelBool(key string) error {
|
func (bp *BoltPvd) DelBool(key string) error {
|
||||||
|
return bp.DelBoolIn("bools", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *BoltPvd) DelBoolIn(ns, key string) error {
|
||||||
return bp.db.Update(func(tx *bolt.Tx) error {
|
return bp.db.Update(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket([]byte("bools"))
|
b := tx.Bucket([]byte(ns))
|
||||||
return b.Delete([]byte(key))
|
return b.Delete([]byte(key))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bp *BoltPvd) ListBools() (map[string]bool, error) {
|
||||||
|
return bp.ListBoolsIn("bools")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *BoltPvd) ListBoolsIn(ns string) (map[string]bool, error) {
|
||||||
|
list := map[string]bool{}
|
||||||
|
err := bp.db.View(func(tx *bolt.Tx) error {
|
||||||
|
b := tx.Bucket([]byte(ns))
|
||||||
|
if b == nil {
|
||||||
|
return ErrBucketNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ForEach(func(k, v []byte) error {
|
||||||
|
list[string(k)] = (v[0] == 1)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return list, err
|
||||||
|
}
|
||||||
|
|
||||||
func (bp *BoltPvd) GetInt(key string) (int, bool) {
|
func (bp *BoltPvd) GetInt(key string) (int, bool) {
|
||||||
x, ok := bp.GetInt64(key)
|
x, ok := bp.GetInt64(key)
|
||||||
return int(x), ok
|
return int(x), ok
|
||||||
|
@ -195,7 +228,7 @@ func (bp *BoltPvd) ListInt64sIn(ns string) (map[string]int64, error) {
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
return fmt.Errorf("fail to parse int64 for key (%s)", k)
|
return fmt.Errorf("fail to parse int64 for key (%s)", k)
|
||||||
}
|
}
|
||||||
list[fmt.Sprintf("%s", k)] = x
|
list[string(k)] = x
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
@ -340,7 +373,7 @@ func (bp *BoltPvd) ListStringsIn(ns string) (map[string]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
b.ForEach(func(k, v []byte) error {
|
b.ForEach(func(k, v []byte) error {
|
||||||
kv[fmt.Sprintf("%s", k)] = fmt.Sprintf("%s", v)
|
kv[string(k)] = string(v)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -9,8 +9,13 @@ type IKVStore interface {
|
||||||
AddNamespace(nsName string) error
|
AddNamespace(nsName string) error
|
||||||
DelNamespace(nsName string) error
|
DelNamespace(nsName string) error
|
||||||
GetBool(key string) (bool, bool)
|
GetBool(key string) (bool, bool)
|
||||||
|
GetBoolIn(ns, key string) (bool, bool)
|
||||||
SetBool(key string, val bool) error
|
SetBool(key string, val bool) error
|
||||||
|
SetBoolIn(ns, key string, val bool) error
|
||||||
DelBool(key string) error
|
DelBool(key string) error
|
||||||
|
DelBoolIn(ns, key string) error
|
||||||
|
ListBools() (map[string]bool, error)
|
||||||
|
ListBoolsIn(ns string) (map[string]bool, error)
|
||||||
GetInt(key string) (int, bool)
|
GetInt(key string) (int, bool)
|
||||||
SetInt(key string, val int) error
|
SetInt(key string, val int) error
|
||||||
DelInt(key string) error
|
DelInt(key string) error
|
||||||
|
|
|
@ -15,6 +15,7 @@ func TestKVStoreProviders(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
var ok bool
|
var ok bool
|
||||||
key, boolV, intV, int64V, floatV, stringV := "key", true, 2027, int64(2027), 3.1415, "foobar"
|
key, boolV, intV, int64V, floatV, stringV := "key", true, 2027, int64(2027), 3.1415, "foobar"
|
||||||
|
key2, boolV2 := "key2", false
|
||||||
|
|
||||||
kvstoreTest := func(store kvstore.IKVStore, t *testing.T) {
|
kvstoreTest := func(store kvstore.IKVStore, t *testing.T) {
|
||||||
// test bools
|
// test bools
|
||||||
|
@ -26,6 +27,19 @@ func TestKVStoreProviders(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("there should be no error %v", err)
|
t.Errorf("there should be no error %v", err)
|
||||||
}
|
}
|
||||||
|
err = store.SetBool(key2, boolV2)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("there should be no error %v", err)
|
||||||
|
}
|
||||||
|
boolList, err := store.ListBools()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("there should be no error %v", err)
|
||||||
|
}
|
||||||
|
if boolList[key] != boolV {
|
||||||
|
t.Error("listBool incorrect val1")
|
||||||
|
} else if boolList[key2] != boolV2 {
|
||||||
|
t.Error("listBool incorrect val2")
|
||||||
|
}
|
||||||
boolVGot, ok := store.GetBool(key)
|
boolVGot, ok := store.GetBool(key)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Error("value should exit")
|
t.Error("value should exit")
|
||||||
|
|
|
@ -179,6 +179,11 @@ func initHandlers(router *gin.Engine, cfg gocfg.ICfg, deps *depidx.Deps) (*gin.E
|
||||||
usersAPI.PATCH("/pwd", userHdrs.SetPwd)
|
usersAPI.PATCH("/pwd", userHdrs.SetPwd)
|
||||||
usersAPI.POST("/", userHdrs.AddUser)
|
usersAPI.POST("/", userHdrs.AddUser)
|
||||||
|
|
||||||
|
rolesAPI := v1.Group("/roles")
|
||||||
|
rolesAPI.POST("/", userHdrs.AddRole)
|
||||||
|
rolesAPI.DELETE("/", userHdrs.DelRole)
|
||||||
|
rolesAPI.GET("/", userHdrs.ListRoles)
|
||||||
|
|
||||||
filesAPI := v1.Group("/fs")
|
filesAPI := v1.Group("/fs")
|
||||||
filesAPI.POST("/files", fileHdrs.Create)
|
filesAPI.POST("/files", fileHdrs.Create)
|
||||||
filesAPI.DELETE("/files", fileHdrs.Delete)
|
filesAPI.DELETE("/files", fileHdrs.Delete)
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
"github.com/ihexxa/quickshare/src/handlers/fileshdr"
|
"github.com/ihexxa/quickshare/src/handlers/fileshdr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func xTestFileHandlers(t *testing.T) {
|
func TestFileHandlers(t *testing.T) {
|
||||||
addr := "http://127.0.0.1:8686"
|
addr := "http://127.0.0.1:8686"
|
||||||
root := "testData"
|
root := "testData"
|
||||||
config := `{
|
config := `{
|
||||||
|
|
|
@ -112,4 +112,62 @@ func TestSingleUserHandlers(t *testing.T) {
|
||||||
t.Fatal(resp.StatusCode)
|
t.Fatal(resp.StatusCode)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("test roles APIs: Login-AddRole-ListRoles-DelRole-ListRoles", func(t *testing.T) {
|
||||||
|
resp, _, errs := usersCl.Login(adminName, adminNewPwd)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatal(errs)
|
||||||
|
} else if resp.StatusCode != 200 {
|
||||||
|
t.Fatal(resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
token := client.GetCookie(resp.Cookies(), su.TokenCookie)
|
||||||
|
roles := []string{"role1", "role2"}
|
||||||
|
|
||||||
|
for _, role := range roles {
|
||||||
|
resp, _, errs := usersCl.AddRole(role, token)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatal(errs)
|
||||||
|
} else if resp.StatusCode != 200 {
|
||||||
|
t.Fatal(resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, lsResp, errs := usersCl.ListRoles(token)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatal(errs)
|
||||||
|
} else if resp.StatusCode != 200 {
|
||||||
|
t.Fatal(resp.StatusCode)
|
||||||
|
}
|
||||||
|
for _, role := range append(roles, []string{
|
||||||
|
userstore.AdminRole,
|
||||||
|
userstore.UserRole,
|
||||||
|
userstore.VisitorRole,
|
||||||
|
}...) {
|
||||||
|
if !lsResp.Roles[role] {
|
||||||
|
t.Fatalf("role(%s) not found", role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, role := range roles {
|
||||||
|
resp, _, errs := usersCl.DelRole(role, token)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatal(errs)
|
||||||
|
} else if resp.StatusCode != 200 {
|
||||||
|
t.Fatal(resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, lsResp, errs = usersCl.ListRoles(token)
|
||||||
|
if len(errs) > 0 {
|
||||||
|
t.Fatal(errs)
|
||||||
|
} else if resp.StatusCode != 200 {
|
||||||
|
t.Fatal(resp.StatusCode)
|
||||||
|
}
|
||||||
|
for _, role := range roles {
|
||||||
|
if lsResp.Roles[role] {
|
||||||
|
t.Fatalf("role(%s) should not exist", role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ const (
|
||||||
NamesNs = "users"
|
NamesNs = "users"
|
||||||
PwdsNs = "pwds"
|
PwdsNs = "pwds"
|
||||||
RolesNs = "roles"
|
RolesNs = "roles"
|
||||||
|
RoleListNs = "roleList"
|
||||||
InitTimeKey = "initTime"
|
InitTimeKey = "initTime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -40,6 +41,9 @@ type IUserStore interface {
|
||||||
SetName(id uint64, name string) error
|
SetName(id uint64, name string) error
|
||||||
SetPwd(id uint64, pwd string) error
|
SetPwd(id uint64, pwd string) error
|
||||||
SetRole(id uint64, role string) error
|
SetRole(id uint64, role string) error
|
||||||
|
AddRole(role string) error
|
||||||
|
DelRole(role string) error
|
||||||
|
ListRoles() (map[string]bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type KVUserStore struct {
|
type KVUserStore struct {
|
||||||
|
@ -57,6 +61,7 @@ func NewKVUserStore(store kvstore.IKVStore) (*KVUserStore, error) {
|
||||||
PwdsNs,
|
PwdsNs,
|
||||||
RolesNs,
|
RolesNs,
|
||||||
InitNs,
|
InitNs,
|
||||||
|
RoleListNs,
|
||||||
} {
|
} {
|
||||||
if err = store.AddNamespace(nsName); err != nil {
|
if err = store.AddNamespace(nsName); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -71,7 +76,8 @@ func NewKVUserStore(store kvstore.IKVStore) (*KVUserStore, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us *KVUserStore) Init(rootName, rootPwd string) error {
|
func (us *KVUserStore) Init(rootName, rootPwd string) error {
|
||||||
err := us.AddUser(&User{
|
var err error
|
||||||
|
err = us.AddUser(&User{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
Name: rootName,
|
Name: rootName,
|
||||||
Pwd: rootPwd,
|
Pwd: rootPwd,
|
||||||
|
@ -81,6 +87,13 @@ func (us *KVUserStore) Init(rootName, rootPwd string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, role := range []string{AdminRole, UserRole, VisitorRole} {
|
||||||
|
err = us.AddRole(role)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return us.store.SetStringIn(InitNs, InitTimeKey, fmt.Sprintf("%d", time.Now().Unix()))
|
return us.store.SetStringIn(InitNs, InitTimeKey, fmt.Sprintf("%d", time.Now().Unix()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,3 +257,33 @@ func (us *KVUserStore) SetRole(id uint64, role string) error {
|
||||||
|
|
||||||
return us.store.SetStringIn(RolesNs, userID, role)
|
return us.store.SetStringIn(RolesNs, userID, role)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (us *KVUserStore) AddRole(role string) error {
|
||||||
|
us.mtx.Lock()
|
||||||
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
_, ok := us.store.GetBoolIn(RoleListNs, role)
|
||||||
|
if ok {
|
||||||
|
return fmt.Errorf("role (%s) exists", role)
|
||||||
|
}
|
||||||
|
|
||||||
|
return us.store.SetBoolIn(RoleListNs, role, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (us *KVUserStore) DelRole(role string) error {
|
||||||
|
us.mtx.Lock()
|
||||||
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
if role == AdminRole || role == UserRole || role == VisitorRole {
|
||||||
|
return errors.New("predefined roles can not be deleted")
|
||||||
|
}
|
||||||
|
|
||||||
|
return us.store.DelBoolIn(RoleListNs, role)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (us *KVUserStore) ListRoles() (map[string]bool, error) {
|
||||||
|
us.mtx.Lock()
|
||||||
|
defer us.mtx.Unlock()
|
||||||
|
|
||||||
|
return us.store.ListBoolsIn(RoleListNs)
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
func TestUserStores(t *testing.T) {
|
func TestUserStores(t *testing.T) {
|
||||||
rootName, rootPwd := "root", "rootPwd"
|
rootName, rootPwd := "root", "rootPwd"
|
||||||
|
|
||||||
testUserStore := func(t *testing.T, store IUserStore) {
|
testUserMethods := func(t *testing.T, store IUserStore) {
|
||||||
root, err := store.GetUser(0)
|
root, err := store.GetUser(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -93,6 +93,47 @@ func TestUserStores(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testRoleMethods := func(t *testing.T, store IUserStore) {
|
||||||
|
roles := []string{"role1", "role2"}
|
||||||
|
var err error
|
||||||
|
for _, role := range roles {
|
||||||
|
err = store.AddRole(role)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roleMap, err := store.ListRoles()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, role := range append(roles, []string{
|
||||||
|
AdminRole, UserRole, VisitorRole,
|
||||||
|
}...) {
|
||||||
|
if !roleMap[role] {
|
||||||
|
t.Fatalf("role(%s) not found", role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, role := range roles {
|
||||||
|
err = store.DelRole(role)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roleMap, err = store.ListRoles()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, role := range roles {
|
||||||
|
if roleMap[role] {
|
||||||
|
t.Fatalf("role(%s) should not exist", role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("testing KVUserStore", func(t *testing.T) {
|
t.Run("testing KVUserStore", func(t *testing.T) {
|
||||||
rootPath, err := ioutil.TempDir("./", "quickshare_userstore_test_")
|
rootPath, err := ioutil.TempDir("./", "quickshare_userstore_test_")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -111,6 +152,7 @@ func TestUserStores(t *testing.T) {
|
||||||
t.Fatal("fail to init kvstore", err)
|
t.Fatal("fail to init kvstore", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
testUserStore(t, store)
|
testUserMethods(t, store)
|
||||||
|
testRoleMethods(t, store)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue