From 5f6700d03fb9b14f89a14ea6345f8820ace0d889 Mon Sep 17 00:00:00 2001 From: Hoang Date: Tue, 9 Nov 2021 11:48:24 +0700 Subject: [PATCH 1/2] add All method --- action_get_all.go | 82 +++++++++++++++++++++++++++++++++++++++++++++++ db.go | 57 ++++++++++++++++++++++++++++++-- helper.go | 4 ++- model.go | 27 ++++++++++++++++ query.go | 58 +++++++++++++++++++++++++++++++++ 5 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 action_get_all.go create mode 100644 query.go 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 + } +} From c055635acef239188f98304a8fbf72dfe83fd863 Mon Sep 17 00:00:00 2001 From: Hoang Date: Tue, 9 Nov 2021 12:26:51 +0700 Subject: [PATCH 2/2] add searchString --- action_create.go | 1 + action_update.go | 13 +++++++------ helper.go | 20 ++++++++++++++++++++ model.go | 1 + 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/action_create.go b/action_create.go index 27a17fc..616eae2 100644 --- a/action_create.go +++ b/action_create.go @@ -48,6 +48,7 @@ func (payload CreateOptions) newUser() (result User, err error) { return User{ ID: mongodb.NewObjectID(), Name: payload.Name, + SearchString: getSearchString(payload.Name, payload.Phone, payload.Email), Phone: payload.Phone, Email: payload.Email, HashedPassword: hashPassword(payload.Password), diff --git a/action_update.go b/action_update.go index 064f091..6612e13 100644 --- a/action_update.go +++ b/action_update.go @@ -44,12 +44,13 @@ func (s Service) UpdateByUserID(userID string, payload UpdateOptions) error { roleID, _ := mongodb.NewIDFromString(payload.RoleID) updateData := bson.M{ "$set": bson.M{ - "name": payload.Name, - "phone": payload.Phone, - "email": payload.Email, - "roleId": roleID, - "other": payload.Other, - "updatedAt": now(), + "name": payload.Name, + "searchString": getSearchString(payload.Name, payload.Phone, payload.Email), + "phone": payload.Phone, + "email": payload.Email, + "roleId": roleID, + "other": payload.Other, + "updatedAt": now(), }, } diff --git a/helper.go b/helper.go index ec1dbca..fbee0db 100644 --- a/helper.go +++ b/helper.go @@ -1,6 +1,9 @@ package usermngmt import ( + "fmt" + + "github.com/Selly-Modules/mongodb" "golang.org/x/crypto/bcrypt" ) @@ -13,3 +16,20 @@ func checkPasswordHash(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } + +func getSearchString(fieldList ...string) string { + var ( + searchList = make([]interface{}, 0) + format = "" + ) + + for i, value := range fieldList { + searchList = append(searchList, mongodb.NonAccentVietnamese(value)) + if i == 0 { + format += "%s" + continue + } + format += " %s" + } + return fmt.Sprintf(format, searchList...) +} diff --git a/model.go b/model.go index 5479aa4..a44ee3d 100644 --- a/model.go +++ b/model.go @@ -10,6 +10,7 @@ import ( type User struct { ID primitive.ObjectID `bson:"_id" json:"_id"` Name string `bson:"name" json:"name"` + SearchString string `bson:"searchString" json:"-"` Phone string `bson:"phone" json:"phone"` // unique Email string `bson:"email" json:"email"` // unique HashedPassword string `bson:"hashedPassword" json:"-"`