diff --git a/action.go b/action.go index b94c5b2..9348a19 100644 --- a/action.go +++ b/action.go @@ -37,6 +37,11 @@ func (s Service) GetAllUser(query model.UserAllQuery) model.UserAll { return user.All(query) } +// ChangeAllUsersStatus ... +func (s Service) ChangeAllUsersStatus(roleID, status string) error { + return user.ChangeAllUsersStatus(roleID, status) +} + // // Role // @@ -47,3 +52,13 @@ func (s Service) GetAllUser(query model.UserAllQuery) model.UserAll { func (s Service) CreateRole(payload model.RoleCreateOptions) error { return role.Create(payload) } + +// UpdateRole ... +func (s Service) UpdateRole(roleID string, payload model.RoleUpdateOptions) error { + return role.Update(roleID, payload) +} + +// GetAllRoles ... +func (s Service) GetAllRoles(query model.RoleAllQuery) model.RoleAll { + return role.All(query) +} diff --git a/internal/helper.go b/internal/helper.go index 597fef5..31e8f60 100644 --- a/internal/helper.go +++ b/internal/helper.go @@ -2,6 +2,7 @@ package internal import ( "fmt" + "strings" "github.com/Selly-Modules/mongodb" "golang.org/x/crypto/bcrypt" @@ -36,3 +37,12 @@ func GetSearchString(fieldList ...string) string { } return fmt.Sprintf(format, searchList...) } + +// GenerateCode ... +func GenerateCode(s string) string { + var ( + underscore = "_" + emptySpace = " " + ) + return strings.ReplaceAll(mongodb.NonAccentVietnamese(s), emptySpace, underscore) +} diff --git a/model/db.go b/model/db.go index 53aca13..c6d00d7 100644 --- a/model/db.go +++ b/model/db.go @@ -8,12 +8,12 @@ import ( // DBRole ... type DBRole struct { - ID primitive.ObjectID `bson:"_id" json:"_id"` - Name string `bson:"name" json:"name"` - Code string `bson:"code" json:"code"` - IsAdmin bool `bson:"isAdmin" json:"isAdmin"` - CreatedAt time.Time `bson:"createdAt" json:"createdAt"` - UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` + ID primitive.ObjectID `bson:"_id"` + Name string `bson:"name"` + Code string `bson:"code"` + IsAdmin bool `bson:"isAdmin"` + CreatedAt time.Time `bson:"createdAt"` + UpdatedAt time.Time `bson:"updatedAt"` } // DBUser ... diff --git a/model/role_request.go b/model/role_request.go index 81a8e0f..8fb5f24 100644 --- a/model/role_request.go +++ b/model/role_request.go @@ -1,6 +1,49 @@ package model +import ( + "errors" + + "github.com/Selly-Modules/logger" +) + // RoleCreateOptions ... type RoleCreateOptions struct { Name string } + +// RoleUpdateOptions ... +type RoleUpdateOptions struct { + Name string +} + +// RoleAllQuery ... +type RoleAllQuery struct { + Page int64 + Limit int64 +} + +// Validate ... +func (co RoleCreateOptions) Validate() error { + // Name + if co.Name == "" { + logger.Error("usermngmt - Role - Create: no name data", logger.LogData{ + "payload": co, + }) + return errors.New("no name data") + } + + return nil +} + +// Validate ... +func (co RoleUpdateOptions) Validate() error { + // Name + if co.Name == "" { + logger.Error("usermngmt - Role - Update: no name data", logger.LogData{ + "payload": co, + }) + return errors.New("no name data") + } + + return nil +} diff --git a/model/role_response.go b/model/role_response.go index abe20f0..459963a 100644 --- a/model/role_response.go +++ b/model/role_response.go @@ -1,8 +1,30 @@ package model +import ( + "time" +) + // RoleShort ... type RoleShort struct { ID string `json:"_id"` Name string `json:"name"` IsAdmin bool `json:"isAdmin"` } + +// Role ... +type Role struct { + ID string `json:"_id"` + Name string `json:"name"` + Code string `json:"code"` + IsAdmin bool `json:"isAdmin"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +type ( + // RoleAll ... + RoleAll struct { + List []Role `json:"list"` + Total int64 `json:"total"` + } +) diff --git a/model/user_request.go b/model/user_request.go index d27b3f1..a0b2a88 100644 --- a/model/user_request.go +++ b/model/user_request.go @@ -45,7 +45,7 @@ type UserAllQuery struct { func (co UserCreateOptions) Validate() error { // Name if co.Name == "" { - logger.Error("usermngmt - Create: no Name data", logger.LogData{ + logger.Error("usermngmt - User - Create: no name data", logger.LogData{ "payload": co, }) return errors.New("no name data") @@ -53,7 +53,7 @@ func (co UserCreateOptions) Validate() error { // Phone if co.Phone == "" { - logger.Error("usermngmt - Create: no phone data", logger.LogData{ + logger.Error("usermngmt - User - Create: no phone data", logger.LogData{ "payload": co, }) return errors.New("no phone data") @@ -61,7 +61,7 @@ func (co UserCreateOptions) Validate() error { // Email if co.Email == "" { - logger.Error("usermngmt - Create: no email data", logger.LogData{ + logger.Error("usermngmt - User - Create: no email data", logger.LogData{ "payload": co, }) return errors.New("no email data") @@ -69,7 +69,7 @@ func (co UserCreateOptions) Validate() error { // Password if co.Password == "" { - logger.Error("usermngmt - Create: no password data", logger.LogData{ + logger.Error("usermngmt - User - Create: no password data", logger.LogData{ "payload": co, }) return errors.New("no password data") @@ -77,7 +77,7 @@ func (co UserCreateOptions) Validate() error { // Status if co.Status == "" { - logger.Error("usermngmt - Create: no status data", logger.LogData{ + logger.Error("usermngmt - User - Create: no status data", logger.LogData{ "payload": co, }) return errors.New("no status data") @@ -85,7 +85,7 @@ func (co UserCreateOptions) Validate() error { // RoleID if co.RoleID == "" { - logger.Error("usermngmt - Create: no roleID data", logger.LogData{ + logger.Error("usermngmt - User - Create: no roleID data", logger.LogData{ "payload": co, }) return errors.New("no role id data") @@ -98,7 +98,7 @@ func (co UserCreateOptions) Validate() error { func (uo UserUpdateOptions) Validate() error { // Name if uo.Name == "" { - logger.Error("usermngmt - Update: no name data", logger.LogData{ + logger.Error("usermngmt - User - Update: no name data", logger.LogData{ "payload": uo, }) return errors.New("no name data") @@ -106,7 +106,7 @@ func (uo UserUpdateOptions) Validate() error { // Phone if uo.Phone == "" { - logger.Error("usermngmt - Update: no phone data", logger.LogData{ + logger.Error("usermngmt - User - Update: no phone data", logger.LogData{ "payload": uo, }) return errors.New("no phone data") @@ -114,7 +114,7 @@ func (uo UserUpdateOptions) Validate() error { // Email if uo.Email == "" { - logger.Error("usermngmt - Update: no email data", logger.LogData{ + logger.Error("usermngmt - User - Update: no email data", logger.LogData{ "payload": uo, }) return errors.New("no email data") @@ -122,7 +122,7 @@ func (uo UserUpdateOptions) Validate() error { // RoleID if uo.RoleID == "" { - logger.Error("usermngmt - Update: no roleID data", logger.LogData{ + logger.Error("usermngmt - User - Update: no roleID data", logger.LogData{ "payload": uo, }) return errors.New("no role id data") @@ -135,7 +135,7 @@ func (uo UserUpdateOptions) Validate() error { func (co ChangePasswordOptions) Validate() error { // OldPassword, NewPassword if co.OldPassword == "" || co.NewPassword == "" { - logger.Error("usermngmt - ChangePassword: old or new password cannot be empty", logger.LogData{ + logger.Error("usermngmt - User - ChangePassword: old or new password cannot be empty", logger.LogData{ "payload": co, }) return errors.New("old or new password cannot be empty") diff --git a/role/db.go b/role/db.go index 6b41add..55209e0 100644 --- a/role/db.go +++ b/role/db.go @@ -2,11 +2,14 @@ package role import ( "context" + "fmt" + "github.com/Selly-Modules/logger" "github.com/Selly-Modules/usermngmt/database" "github.com/Selly-Modules/usermngmt/model" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo/options" ) func findByID(ctx context.Context, id primitive.ObjectID) (model.DBRole, error) { @@ -17,3 +20,78 @@ func findByID(ctx context.Context, id primitive.ObjectID) (model.DBRole, error) err := col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc) return doc, err } + +func create(ctx context.Context, doc model.DBRole) error { + var ( + col = database.GetRoleCol() + ) + _, err := col.InsertOne(ctx, doc) + if err != nil { + logger.Error("usermngmt - Role - InsertOne", logger.LogData{ + "doc": doc, + "err": err.Error(), + }) + return fmt.Errorf("error when create role: %s", err.Error()) + } + + return nil +} + +func updateOneByCondition(ctx context.Context, cond interface{}, payload interface{}) error { + var ( + col = database.GetRoleCol() + ) + _, err := col.UpdateOne(ctx, cond, payload) + if err != nil { + logger.Error("usermngmt - Role - UpdateOne", logger.LogData{ + "cond": cond, + "payload": payload, + "err": err.Error(), + }) + return fmt.Errorf("error when update role: %s", err.Error()) + } + + return err +} + +func findByCondition(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 +} + +// countByCondition ... +func countByCondition(ctx context.Context, cond interface{}) int64 { + var ( + col = database.GetRoleCol() + ) + total, err := col.CountDocuments(ctx, cond) + if err != nil { + logger.Error("usermngmt - Role - CountDocuments", logger.LogData{ + "err": err.Error(), + "cond": cond, + }) + } + return total +} diff --git a/role/handle.go b/role/handle.go index 9572478..e4145a6 100644 --- a/role/handle.go +++ b/role/handle.go @@ -2,19 +2,133 @@ package role import ( "context" + "errors" + "sync" + "github.com/Selly-Modules/mongodb" + "github.com/Selly-Modules/usermngmt/internal" "github.com/Selly-Modules/usermngmt/model" - "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/bson" ) -// FindByID ... -func FindByID(ctx context.Context, id primitive.ObjectID) (model.DBRole, error) { - role, err := findByID(ctx, id) - return role, err -} - // Create ... func Create(payload model.RoleCreateOptions) error { - // TODO later + var ( + ctx = context.Background() + ) + + // Validate payload + if err := payload.Validate(); err != nil { + return err + } + + // New role data from payload + doc := newRole(payload) + + // Create role + if err := create(ctx, doc); err != nil { + return err + } + return nil } + +// newRole ... +func newRole(payload model.RoleCreateOptions) model.DBRole { + timeNow := internal.Now() + return model.DBRole{ + ID: mongodb.NewObjectID(), + Name: payload.Name, + Code: internal.GenerateCode(payload.Name), + CreatedAt: timeNow, + UpdatedAt: timeNow, + } +} + +// Update ... +func Update(roleID string, payload model.RoleUpdateOptions) error { + var ( + ctx = context.Background() + ) + + // Validate payload + if err := payload.Validate(); err != nil { + return err + } + + // Validate roleID + id, isValid := mongodb.NewIDFromString(roleID) + if !isValid { + return errors.New("invalid role id data") + } + + // Setup condition + cond := bson.M{ + "_id": id, + } + + // Setup update data + updateData := bson.M{ + "$set": bson.M{ + "name": payload.Name, + "code": internal.GenerateCode(payload.Name), + "updatedAt": internal.Now(), + }, + } + + // Update + if err := updateOneByCondition(ctx, cond, updateData); err != nil { + return err + } + + return nil +} + +// All ... +func All(queryParams model.RoleAllQuery) (r model.RoleAll) { + var ( + ctx = context.Background() + wg sync.WaitGroup + cond = bson.M{} + ) + query := model.CommonQuery{ + Page: queryParams.Page, + Limit: queryParams.Limit, + Sort: bson.M{"createdAt": -1}, + } + + // Assign condition + query.SetDefaultLimit() + + wg.Add(1) + go func() { + defer wg.Done() + docs := findByCondition(ctx, cond, query.GetFindOptionsUsingPage()) + r.List = getResponseList(docs) + }() + + wg.Add(1) + go func() { + defer wg.Done() + r.Total = countByCondition(ctx, cond) + }() + + wg.Wait() + + return +} + +func getResponseList(roles []model.DBRole) []model.Role { + res := make([]model.Role, 0) + for _, role := range roles { + res = append(res, model.Role{ + ID: role.ID.Hex(), + Name: role.Name, + Code: role.Code, + CreatedAt: role.CreatedAt, + UpdatedAt: role.UpdatedAt, + }) + } + + return res +} diff --git a/user/db.go b/user/db.go index 7134c53..b55209b 100644 --- a/user/db.go +++ b/user/db.go @@ -29,7 +29,7 @@ func isPhoneNumberOrEmailExisted(ctx context.Context, phone, email string) bool } total, err := col.CountDocuments(ctx, cond) if err != nil { - logger.Error("usermngmt - countUserByCondition", logger.LogData{ + logger.Error("usermngmt - User - CountDocuments", logger.LogData{ "condition": cond, "err": err.Error(), }) @@ -48,7 +48,7 @@ func isRoleIDExisted(ctx context.Context, roleID primitive.ObjectID) bool { } total, err := col.CountDocuments(ctx, cond) if err != nil { - logger.Error("usermngmt - countRoleByCondition", logger.LogData{ + logger.Error("usermngmt - Role - CountDocuments", logger.LogData{ "condition": cond, "err": err.Error(), }) @@ -72,7 +72,7 @@ func create(ctx context.Context, doc model.DBUser) error { ) _, err := col.InsertOne(ctx, doc) if err != nil { - logger.Error("usermngmt - Create", logger.LogData{ + logger.Error("usermngmt - User - InsertOne", logger.LogData{ "doc": doc, "err": err.Error(), }) @@ -88,7 +88,24 @@ func updateOneByCondition(ctx context.Context, cond interface{}, payload interfa ) _, err := col.UpdateOne(ctx, cond, payload) if err != nil { - logger.Error("usermngmt - Update", logger.LogData{ + logger.Error("usermngmt - User - UpdateOne", logger.LogData{ + "cond": cond, + "payload": payload, + "err": err.Error(), + }) + return fmt.Errorf("error when update user: %s", err.Error()) + } + + return err +} + +func updateManyByCondition(ctx context.Context, cond interface{}, payload interface{}) error { + var ( + col = database.GetUserCol() + ) + _, err := col.UpdateMany(ctx, cond, payload) + if err != nil { + logger.Error("usermngmt - User - UpdateMany", logger.LogData{ "cond": cond, "payload": payload, "err": err.Error(), @@ -116,7 +133,7 @@ func findByCondition(ctx context.Context, cond interface{}, opts ...*options.Fin cursor, err := col.Find(ctx, cond, opts...) if err != nil { - logger.Error("usermngmt - All", logger.LogData{ + logger.Error("usermngmt - User - Find", logger.LogData{ "cond": cond, "opts": opts, "err": err.Error(), @@ -125,7 +142,7 @@ func findByCondition(ctx context.Context, cond interface{}, opts ...*options.Fin } defer cursor.Close(ctx) if err = cursor.All(ctx, &docs); err != nil { - logger.Error("usermngmt - All - decode", logger.LogData{ + logger.Error("usermngmt - User - Decode", logger.LogData{ "cond": cond, "opts": opts, "err": err.Error(), diff --git a/user/handle.go b/user/handle.go index 684013a..7cf8f2d 100644 --- a/user/handle.go +++ b/user/handle.go @@ -257,3 +257,36 @@ func ChangeUserStatus(userID, newStatus string) error { return nil } + +// ChangeAllUsersStatus ... +func ChangeAllUsersStatus(roleID, status string) error { + var ( + ctx = context.Background() + ) + + // Validate roleID + id, isValid := mongodb.NewIDFromString(roleID) + if !isValid { + return errors.New("invalid role id data") + } + + // Setup condition + cond := bson.M{ + "roleId": id, + } + + // Setup update data + updateData := bson.M{ + "$set": bson.M{ + "status": status, + "updatedAt": internal.Now(), + }, + } + + // Update + if err := updateManyByCondition(ctx, cond, updateData); err != nil { + return err + } + + return nil +}