diff --git a/action_get_all.go b/action_get_all.go new file mode 100644 index 0000000..47b65c7 --- /dev/null +++ b/action_get_all.go @@ -0,0 +1,82 @@ +package usermngmt + +import ( + "context" + "sync" + + "go.mongodb.org/mongo-driver/bson" +) + +// AllQuery ... +type AllQuery struct { + Page int64 + Limit int64 + Keyword string + RoleID string + Status string +} + +// All ... +func (s Service) All(queryParams AllQuery) (r ResponseUserAll) { + var ( + ctx = context.Background() + wg sync.WaitGroup + cond = bson.M{} + ) + query := commonQuery{ + Page: queryParams.Page, + Limit: queryParams.Limit, + Keyword: queryParams.Keyword, + RoleID: queryParams.RoleID, + Status: queryParams.Status, + Sort: bson.M{"createdAt": -1}, + } + + // Assign condition + query.SetDefaultLimit() + query.AssignKeyword(cond) + query.AssignRoleID(cond) + query.AssignStatus(cond) + + wg.Add(1) + go func() { + defer wg.Done() + docs := s.userFindByCondition(ctx, cond, query.GetFindOptionsUsingPage()) + r.List = getResponseList(ctx, docs) + }() + + wg.Add(1) + go func() { + defer wg.Done() + r.Total = s.userCountByCondition(ctx, cond) + }() + + wg.Wait() + + return +} + +func getResponseList(ctx context.Context, users []User) []ResponseUser { + res := make([]ResponseUser, 0) + + for _, user := range users { + role, _ := s.roleFindByID(ctx, user.RoleID) + res = append(res, ResponseUser{ + ID: user.ID.Hex(), + Name: user.Name, + Phone: user.Phone, + Email: user.Email, + Status: user.Status, + Role: RoleShort{ + ID: role.ID.Hex(), + Name: role.Name, + IsAdmin: role.IsAdmin, + }, + Other: user.Other, + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + }) + } + + return res +} diff --git a/db.go b/db.go index 1a25e54..dbfade4 100644 --- a/db.go +++ b/db.go @@ -8,6 +8,7 @@ import ( "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" ) // getUserCollection ... @@ -92,9 +93,9 @@ func (s Service) userUpdateOneByCondition(ctx context.Context, cond interface{}, _, err := col.UpdateOne(ctx, cond, payload) if err != nil { logger.Error("usermngmt - Update", logger.LogData{ - "cond": cond, + "cond": cond, "payload": payload, - "err": err.Error(), + "err": err.Error(), }) return fmt.Errorf("error when update user: %s", err.Error()) } @@ -109,4 +110,56 @@ func (s Service) userFindByID(ctx context.Context, id primitive.ObjectID) (User, ) err := col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc) return doc, err +} + +func (s Service) userFindByCondition(ctx context.Context, cond interface{}, opts ...*options.FindOptions) (docs []User) { + var ( + col = s.getUserCollection() + ) + docs = make([]User, 0) + + cursor, err := col.Find(ctx, cond, opts...) + if err != nil { + logger.Error("usermngmt - All", 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 - All - decode", logger.LogData{ + "cond": cond, + "opts": opts, + "err": err.Error(), + }) + return + } + return +} + +// userCountByCondition ... +func (s Service) userCountByCondition(ctx context.Context, cond interface{}) int64 { + var ( + col = s.getUserCollection() + ) + + total, err := col.CountDocuments(ctx, cond) + if err != nil { + logger.Error("usermngmt - Count", logger.LogData{ + "err": err.Error(), + "cond": cond, + }) + } + return total +} + +func (s Service) roleFindByID(ctx context.Context, id primitive.ObjectID) (Role, error) { + var ( + col = s.getRoleCollection() + doc Role + ) + err := col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc) + return doc, err } \ No newline at end of file diff --git a/helper.go b/helper.go index ca80f04..ec1dbca 100644 --- a/helper.go +++ b/helper.go @@ -1,6 +1,8 @@ package usermngmt -import "golang.org/x/crypto/bcrypt" +import ( + "golang.org/x/crypto/bcrypt" +) func hashPassword(password string) string { bytes, _ := bcrypt.GenerateFromPassword([]byte(password), passwordHashingCost) diff --git a/model.go b/model.go index 135b037..5479aa4 100644 --- a/model.go +++ b/model.go @@ -20,6 +20,19 @@ type User struct { UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` } +// ResponseUser ... +type ResponseUser struct { + ID string `json:"_id"` + Name string `json:"name"` + Phone string `json:"phone"` + Email string `json:"email"` + Status string `json:"status"` + Role RoleShort `json:"role"` + Other string `json:"other"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + // Role ... type Role struct { ID primitive.ObjectID `bson:"_id" json:"_id"` @@ -29,3 +42,17 @@ type Role struct { CreatedAt time.Time `bson:"createdAt" json:"createdAt"` UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` } + +type RoleShort struct { + ID string `json:"_id"` + Name string `json:"name"` + IsAdmin bool `json:"isAdmin"` +} + +type ( + // ResponseUserAll ... + ResponseUserAll struct { + List []ResponseUser `json:"list"` + Total int64 `json:"total"` + } +) diff --git a/query.go b/query.go new file mode 100644 index 0000000..704edfa --- /dev/null +++ b/query.go @@ -0,0 +1,58 @@ +package usermngmt + +import ( + "github.com/Selly-Modules/mongodb" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type commonQuery struct { + Page int64 + Limit int64 + Keyword string + RoleID string + Status string + Sort interface{} +} + +// AssignKeyword ... +func (q *commonQuery) AssignKeyword(cond bson.M) { + if q.Keyword != "" { + cond["searchString"] = mongodb.GenerateQuerySearchString(q.Keyword) + } +} + +// AssignRoleID ... +func (q *commonQuery) AssignRoleID(cond bson.M) { + if q.RoleID != "" { + if id, isValid := mongodb.NewIDFromString(q.RoleID); isValid { + cond["roleId"] = id + } + } +} + +// AssignStatus ... +func (q *commonQuery) AssignStatus(cond bson.M) { + if q.Status != "" { + cond["status"] = q.Status + } +} + +// GetFindOptionsUsingPage ... +func (q *commonQuery) GetFindOptionsUsingPage() *options.FindOptions { + opts := options.Find() + if q.Limit > 0 { + opts.SetLimit(q.Limit).SetSkip(q.Limit * q.Page) + } + if q.Sort != nil { + opts.SetSort(q.Sort) + } + return opts +} + +// SetDefaultLimit ... +func (q *commonQuery) SetDefaultLimit() { + if q.Limit <= 0 || q.Limit > 20 { + q.Limit = 20 + } +}