diff --git a/action.go b/action.go index fdeff9c..3b33ee1 100644 --- a/action.go +++ b/action.go @@ -1,6 +1,7 @@ package usermngmt import ( + "github.com/Selly-Modules/usermngmt/cache" "github.com/Selly-Modules/usermngmt/model" "github.com/Selly-Modules/usermngmt/permission" "github.com/Selly-Modules/usermngmt/role" @@ -61,11 +62,11 @@ func (s Service) HasPermission(userID, permission string) bool { // CreateRole ... func (s Service) CreateRole(payload model.RoleCreateOptions) error { - err := role.Create(payload) - if err == nil { - role.CacheRoles() + if err := role.Create(payload); err != nil { + return err } - return err + cache.Roles() + return nil } // UpdateRole ... @@ -86,20 +87,20 @@ func (s Service) GetAllRoles(query model.RoleAllQuery) model.RoleAll { // CreatePermission ... func (s Service) CreatePermission(payload model.PermissionCreateOptions) error { - err := permission.Create(payload) - if err == nil { - role.CacheRoles() + if err := permission.Create(payload); err != nil { + return err } - return err + cache.Roles() + return nil } // UpdatePermission ... func (s Service) UpdatePermission(permissionID string, payload model.PermissionUpdateOptions) error { - err := permission.Update(permissionID, payload) - if err == nil { - role.CacheRoles() + if err := permission.Update(permissionID, payload); err != nil { + return err } - return err + cache.Roles() + return nil } // GetAllPermissions ... diff --git a/cache/cache.go b/cache/cache.go index 25cdd03..c487d03 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -11,12 +11,16 @@ var cache *bigcache.BigCache // Init ... func Init() { - // The time after which entries can be evicted is 5 years - c, err := bigcache.NewBigCache(bigcache.DefaultConfig(43800 * time.Hour)) + // The time after which entries can be evicted is 30 days + const cacheTime = 24 * 30 * time.Hour // 30 days + c, err := bigcache.NewBigCache(bigcache.DefaultConfig(cacheTime)) if err != nil { log.Fatalf("Cannot init Cache %v", err) } cache = c + + // Cache roles + Roles() } // GetInstance ... diff --git a/cache/db.go b/cache/db.go new file mode 100644 index 0000000..6d062cb --- /dev/null +++ b/cache/db.go @@ -0,0 +1,64 @@ +package cache + +import ( + "context" + + "github.com/Selly-Modules/logger" + "github.com/Selly-Modules/usermngmt/database" + "github.com/Selly-Modules/usermngmt/model" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func roleFindByCondition(ctx context.Context, cond interface{}, opts ...*options.FindOptions) (docs []model.DBRole) { + var ( + col = database.GetRoleCol() + ) + docs = make([]model.DBRole, 0) + + cursor, err := col.Find(ctx, cond, opts...) + if err != nil { + logger.Error("usermngmt - Role - Find", logger.LogData{ + "cond": cond, + "opts": opts, + "err": err.Error(), + }) + return + } + defer cursor.Close(ctx) + if err = cursor.All(ctx, &docs); err != nil { + logger.Error("usermngmt - Role - Decode", logger.LogData{ + "cond": cond, + "opts": opts, + "err": err.Error(), + }) + return + } + return +} + +func permissionFindByCondition(ctx context.Context, cond interface{}, opts ...*options.FindOptions) (docs []model.DBPermission) { + var ( + col = database.GetPermissionCol() + ) + docs = make([]model.DBPermission, 0) + + cursor, err := col.Find(ctx, cond, opts...) + if err != nil { + logger.Error("usermngmt - Permission - Find", logger.LogData{ + "cond": cond, + "opts": opts, + "err": err.Error(), + }) + return + } + defer cursor.Close(ctx) + if err = cursor.All(ctx, &docs); err != nil { + logger.Error("usermngmt - Permission - Decode", logger.LogData{ + "cond": cond, + "opts": opts, + "err": err.Error(), + }) + return + } + return +} diff --git a/cache/model.go b/cache/model.go new file mode 100644 index 0000000..96b64cb --- /dev/null +++ b/cache/model.go @@ -0,0 +1,8 @@ +package cache + +// CachedRole ... +type CachedRole struct { + Role string `json:"role"` + IsAdmin bool `json:"isAdmin"` + Permissions []string `json:"permissions"` +} diff --git a/cache/role.go b/cache/role.go new file mode 100644 index 0000000..b4908d2 --- /dev/null +++ b/cache/role.go @@ -0,0 +1,70 @@ +package cache + +import ( + "context" + "encoding/json" + "sync" + + "github.com/Selly-Modules/logger" + "github.com/Selly-Modules/usermngmt/model" + "go.mongodb.org/mongo-driver/bson" +) + +// Roles ... +func Roles() { + var ( + ctx = context.Background() + wg sync.WaitGroup + cond = bson.M{} + ) + + // Find + roles := roleFindByCondition(ctx, cond) + permissions := permissionFindByCondition(ctx, cond) + + wg.Add(len(roles)) + for _, value := range roles { + go func(role model.DBRole) { + defer wg.Done() + rolePermissions := make([]string, 0) + // Get role permissions + for _, permission := range permissions { + if permission.RoleID == role.ID { + rolePermissions = append(rolePermissions, permission.Code) + } + } + + // Cache Role + entry, _ := json.Marshal(CachedRole{ + Role: role.Code, + IsAdmin: role.IsAdmin, + Permissions: rolePermissions, + }) + if err := cache.Set(role.ID.Hex(), entry); err != nil { + logger.Error("usermngmt - CacheRole", logger.LogData{ + "err": err.Error(), + }) + return + } + }(value) + } + + wg.Wait() + return +} + +// GetCachedRole ... +func GetCachedRole(key string) CachedRole { + entry, err := cache.Get(key) + if err != nil { + Roles() + entry, _ = cache.Get(key) + } + var cachedRole CachedRole + if err = json.Unmarshal(entry, &cachedRole); err != nil { + logger.Error("usermngmt - GetCachedRole - Unmarshal", logger.LogData{ + "err": err.Error(), + }) + } + return cachedRole +} diff --git a/role/handle.go b/role/handle.go index 7ba14ee..e4145a6 100644 --- a/role/handle.go +++ b/role/handle.go @@ -3,15 +3,11 @@ package role import ( "context" "errors" - "strings" "sync" - "github.com/Selly-Modules/logger" "github.com/Selly-Modules/mongodb" - "github.com/Selly-Modules/usermngmt/cache" "github.com/Selly-Modules/usermngmt/internal" "github.com/Selly-Modules/usermngmt/model" - "github.com/thoas/go-funk" "go.mongodb.org/mongo-driver/bson" ) @@ -136,49 +132,3 @@ func getResponseList(roles []model.DBRole) []model.Role { return res } - -// CacheRoles ... -func CacheRoles() { - var ( - ctx = context.Background() - wg sync.WaitGroup - ) - - // Find - roles := findByCondition(ctx, bson.M{}) - - wg.Add(len(roles)) - for _, value := range roles { - go func(role model.DBRole) { - defer wg.Done() - - // Check and set role admin: admin - if role.IsAdmin { - if err := cache.GetInstance().Set(role.ID.Hex(), []byte(internal.RoleTypeAdmin)); err != nil { - logger.Error("usermngmt - CacheRole", logger.LogData{ - "err": err.Error(), - }) - return - } - } - - // Set role by permission with format: permissionCode,permissionCode,... - permissions := permissionFindByCondition(ctx, bson.M{ - "roleId": role.ID, - }) - permissionCodes := funk.Map(permissions, func(i model.DBPermission) string { - return i.Code - }).([]string) - permissionCodeString := strings.Join(permissionCodes, ",") - if err := cache.GetInstance().Set(role.ID.Hex(), []byte(permissionCodeString)); err != nil { - logger.Error("usermngmt - CacheRole", logger.LogData{ - "err": err.Error(), - }) - return - } - }(value) - } - - wg.Done() - return -} diff --git a/user/handle.go b/user/handle.go index ac98f98..23864d4 100644 --- a/user/handle.go +++ b/user/handle.go @@ -3,7 +3,6 @@ package user import ( "context" "errors" - "strings" "sync" "github.com/Selly-Modules/logger" @@ -13,6 +12,7 @@ import ( "github.com/Selly-Modules/usermngmt/model" "github.com/thoas/go-funk" "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" ) // Create ... @@ -356,17 +356,21 @@ func HasPermission(userID, permission string) (result bool) { return } - // Get rolePermissions - // Role is saved with the value "admin" or "permissionCode,permissionCode,..." - entry, _ := cache.GetInstance().Get(user.RoleID.Hex()) - rolePermissions := strings.Split(string(entry), ",") + return checkUserHasPermissionFromCache(user.RoleID, permission) +} - // Check Permission - if _, isValid = funk.FindString(rolePermissions, func(s string) bool { - return s == permission || s == internal.RoleTypeAdmin +func checkUserHasPermissionFromCache(roleID primitive.ObjectID, permission string) bool { + cachedRole := cache.GetCachedRole(roleID.Hex()) + + // Check permission + if cachedRole.IsAdmin { + return true + } + if _, isValid := funk.FindString(cachedRole.Permissions, func(s string) bool { + return s == permission }); isValid { - return isValid + return true } - return + return false } diff --git a/usermngmt.go b/usermngmt.go index 112a1a0..b0617e6 100644 --- a/usermngmt.go +++ b/usermngmt.go @@ -8,7 +8,6 @@ import ( "github.com/Selly-Modules/usermngmt/cache" "github.com/Selly-Modules/usermngmt/database" "github.com/Selly-Modules/usermngmt/internal" - "github.com/Selly-Modules/usermngmt/role" ) // MongoDBConfig ... @@ -66,9 +65,6 @@ func Init(config Config) (*Service, error) { config: config, } - // Cache role - role.CacheRoles() - return s, nil }