Feature/role create #5
|
@ -0,0 +1,30 @@
|
||||||
|
package usermngmt
|
||||||
|
|
||||||
|
import "github.com/Selly-Modules/usermngmt/internal"
|
||||||
|
|
||||||
|
// Create ...
|
||||||
|
func (s Service) Create(payload internal.CreateOptions) error {
|
||||||
|
return s.userHandle().Create(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update ...
|
||||||
|
func (s Service) Update(userID string, payload internal.UpdateOptions) error {
|
||||||
|
return s.userHandle().UpdateByUserID(userID, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeUserPassword ...
|
||||||
|
func (s Service) ChangeUserPassword(userID string, payload internal.ChangePasswordOptions) error {
|
||||||
|
return s.userHandle().ChangeUserPassword(userID, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) ChangeUserStatus(userID, newStatus string) error {
|
||||||
|
return s.userHandle().ChangeUserStatus(userID, newStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) All(query internal.AllQuery) internal.UserAll {
|
||||||
|
return s.userHandle().All(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) RoleCreate(payload internal.RoleCreateOptions) error {
|
||||||
|
return s.roleHandle().Create(payload)
|
||||||
|
}
|
|
@ -1,61 +0,0 @@
|
||||||
package usermngmt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Selly-Modules/mongodb"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateOptions ...
|
|
||||||
type CreateOptions struct {
|
|
||||||
Name string
|
|
||||||
Phone string
|
|
||||||
Email string
|
|
||||||
Password string
|
|
||||||
Status string
|
|
||||||
RoleID string
|
|
||||||
Other string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create ...
|
|
||||||
func (s Service) Create(payload CreateOptions) error {
|
|
||||||
var (
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validate payload
|
|
||||||
if err := payload.validate(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// New user data from payload
|
|
||||||
doc, err := payload.newUser()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create user
|
|
||||||
if err = s.userCreate(ctx, doc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (payload CreateOptions) newUser() (result dbUser, err error) {
|
|
||||||
timeNow := now()
|
|
||||||
roleID, _ := mongodb.NewIDFromString(payload.RoleID)
|
|
||||||
return dbUser{
|
|
||||||
ID: mongodb.NewObjectID(),
|
|
||||||
Name: payload.Name,
|
|
||||||
SearchString: getSearchString(payload.Name, payload.Phone, payload.Email),
|
|
||||||
Phone: payload.Phone,
|
|
||||||
Email: payload.Email,
|
|
||||||
HashedPassword: hashPassword(payload.Password),
|
|
||||||
Status: payload.Status,
|
|
||||||
RoleID: roleID,
|
|
||||||
Other: payload.Other,
|
|
||||||
CreatedAt: timeNow,
|
|
||||||
UpdatedAt: timeNow,
|
|
||||||
}, nil
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
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 UserAll) {
|
|
||||||
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 []dbUser) []User {
|
|
||||||
res := make([]User, 0)
|
|
||||||
|
|
||||||
for _, user := range users {
|
|
||||||
role, _ := s.roleFindByID(ctx, user.RoleID)
|
|
||||||
res = append(res, User{
|
|
||||||
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
|
|
||||||
}
|
|
125
action_update.go
125
action_update.go
|
@ -1,125 +0,0 @@
|
||||||
package usermngmt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/Selly-Modules/mongodb"
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UpdateOptions ...
|
|
||||||
type UpdateOptions struct {
|
|
||||||
Name string
|
|
||||||
Phone string
|
|
||||||
Email string
|
|
||||||
RoleID string
|
|
||||||
Other string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangePasswordOptions ...
|
|
||||||
type ChangePasswordOptions struct {
|
|
||||||
OldPassword string
|
|
||||||
NewPassword string
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateByUserID ...
|
|
||||||
func (s Service) UpdateByUserID(userID string, payload UpdateOptions) error {
|
|
||||||
var (
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validate payload
|
|
||||||
if err := payload.validate(ctx); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup condition
|
|
||||||
id, _ := mongodb.NewIDFromString(userID)
|
|
||||||
cond := bson.M{
|
|
||||||
"_id": id,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup update data
|
|
||||||
roleID, _ := mongodb.NewIDFromString(payload.RoleID)
|
|
||||||
updateData := bson.M{
|
|
||||||
"$set": bson.M{
|
|
||||||
"name": payload.Name,
|
|
||||||
"searchString": getSearchString(payload.Name, payload.Phone, payload.Email),
|
|
||||||
"phone": payload.Phone,
|
|
||||||
"email": payload.Email,
|
|
||||||
"roleId": roleID,
|
|
||||||
"other": payload.Other,
|
|
||||||
"updatedAt": now(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update
|
|
||||||
if err := s.userUpdateOneByCondition(ctx, cond, updateData); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeUserPassword ...
|
|
||||||
func (s Service) ChangeUserPassword(userID string, opt ChangePasswordOptions) error {
|
|
||||||
var (
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validate payload
|
|
||||||
err := opt.validate(userID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find user
|
|
||||||
id, _ := mongodb.NewIDFromString(userID)
|
|
||||||
user, _ := s.userFindByID(ctx, id)
|
|
||||||
if user.ID.IsZero() {
|
|
||||||
return errors.New("user not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check old password
|
|
||||||
if isValid := checkPasswordHash(opt.OldPassword, user.HashedPassword); !isValid {
|
|
||||||
return errors.New("the password is incorrect")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update password
|
|
||||||
if err = s.userUpdateOneByCondition(ctx, bson.M{"_id": user.ID}, bson.M{
|
|
||||||
"$set": bson.M{
|
|
||||||
"hashedPassword": hashPassword(opt.NewPassword),
|
|
||||||
"updatedAt": now(),
|
|
||||||
},
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChangeUserStatus ...
|
|
||||||
func (s Service) ChangeUserStatus(userID, newStatus string) error {
|
|
||||||
var (
|
|
||||||
ctx = context.Background()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Validate userID
|
|
||||||
id, isValid := mongodb.NewIDFromString(userID)
|
|
||||||
if !isValid {
|
|
||||||
return errors.New("invalid user id data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update status
|
|
||||||
if err := s.userUpdateOneByCondition(ctx, bson.M{"_id": id}, bson.M{
|
|
||||||
"$set": bson.M{
|
|
||||||
"status": newStatus,
|
|
||||||
"updatedAt": now(),
|
|
||||||
},
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -5,8 +5,4 @@ const (
|
||||||
tableUser = "users"
|
tableUser = "users"
|
||||||
tableRole = "roles"
|
tableRole = "roles"
|
||||||
tablePrefixDefault = "usermngmt"
|
tablePrefixDefault = "usermngmt"
|
||||||
|
|
||||||
timezoneHCM = "Asia/Ho_Chi_Minh"
|
|
||||||
|
|
||||||
passwordHashingCost = 14
|
|
||||||
)
|
)
|
||||||
|
|
148
db.go
148
db.go
|
@ -1,14 +1,9 @@
|
||||||
package usermngmt
|
package usermngmt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Selly-Modules/logger"
|
|
||||||
"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"
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// getUserCollection ...
|
// getUserCollection ...
|
||||||
|
@ -20,146 +15,3 @@ func (s Service) getUserCollection() *mongo.Collection {
|
||||||
func (s Service) getRoleCollection() *mongo.Collection {
|
func (s Service) getRoleCollection() *mongo.Collection {
|
||||||
return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableRole))
|
return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableRole))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Service) isPhoneNumberOrEmailExisted(ctx context.Context, phone, email string) bool {
|
|
||||||
var (
|
|
||||||
col = s.getUserCollection()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Find
|
|
||||||
cond := bson.M{
|
|
||||||
"$or": []bson.M{
|
|
||||||
{
|
|
||||||
"phone": phone,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"email": email,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
total, err := col.CountDocuments(ctx, cond)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("usermngmt - countUserByCondition", logger.LogData{
|
|
||||||
"condition": cond,
|
|
||||||
"err": err.Error(),
|
|
||||||
})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return total != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) isRoleIDExisted(ctx context.Context, roleID primitive.ObjectID) bool {
|
|
||||||
var (
|
|
||||||
col = s.getRoleCollection()
|
|
||||||
)
|
|
||||||
|
|
||||||
// Find
|
|
||||||
cond := bson.M{
|
|
||||||
"_id": roleID,
|
|
||||||
}
|
|
||||||
total, err := col.CountDocuments(ctx, cond)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("usermngmt - countRoleByCondition", logger.LogData{
|
|
||||||
"condition": cond,
|
|
||||||
"err": err.Error(),
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return total != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) userCreate(ctx context.Context, doc dbUser) error {
|
|
||||||
var (
|
|
||||||
col = s.getUserCollection()
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err := col.InsertOne(ctx, doc)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("usermngmt - Create", logger.LogData{
|
|
||||||
"doc": doc,
|
|
||||||
"err": err.Error(),
|
|
||||||
})
|
|
||||||
return fmt.Errorf("error when create user: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) userUpdateOneByCondition(ctx context.Context, cond interface{}, payload interface{}) error {
|
|
||||||
var (
|
|
||||||
col = s.getUserCollection()
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err := col.UpdateOne(ctx, cond, payload)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("usermngmt - Update", logger.LogData{
|
|
||||||
"cond": cond,
|
|
||||||
"payload": payload,
|
|
||||||
"err": err.Error(),
|
|
||||||
})
|
|
||||||
return fmt.Errorf("error when update user: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) userFindByID(ctx context.Context, id primitive.ObjectID) (dbUser, error) {
|
|
||||||
var (
|
|
||||||
col = s.getUserCollection()
|
|
||||||
doc dbUser
|
|
||||||
)
|
|
||||||
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 []dbUser) {
|
|
||||||
var (
|
|
||||||
col = s.getUserCollection()
|
|
||||||
)
|
|
||||||
docs = make([]dbUser, 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) (dbRole, error) {
|
|
||||||
var (
|
|
||||||
col = s.getRoleCollection()
|
|
||||||
doc dbRole
|
|
||||||
)
|
|
||||||
err := col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc)
|
|
||||||
return doc, err
|
|
||||||
}
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,4 +1,4 @@
|
||||||
module github.com/selly-Modules/usermngmt
|
module github.com/Selly-Modules/usermngmt
|
||||||
|
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package usermngmt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Selly-Modules/usermngmt/role"
|
||||||
|
"github.com/Selly-Modules/usermngmt/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
// userHandle ...
|
||||||
|
func (s Service) userHandle() user.Handle {
|
||||||
|
return user.Handle{
|
||||||
|
Col: s.getUserCollection(),
|
||||||
|
RoleCol: s.getRoleCollection(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// roleHandle ...
|
||||||
|
func (s Service) roleHandle() role.Handle {
|
||||||
|
return role.Handle{
|
||||||
|
Col: s.getRoleCollection(),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
// Constant ...
|
||||||
|
const (
|
||||||
|
timezoneHCM = "Asia/Ho_Chi_Minh"
|
||||||
|
|
||||||
|
passwordHashingCost = 14
|
||||||
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package usermngmt
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
@ -6,8 +6,18 @@ import (
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dbUser ...
|
// DBRole ...
|
||||||
type dbUser struct {
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DBUser ...
|
||||||
|
type DBUser struct {
|
||||||
ID primitive.ObjectID `bson:"_id"`
|
ID primitive.ObjectID `bson:"_id"`
|
||||||
Name string `bson:"name"`
|
Name string `bson:"name"`
|
||||||
SearchString string `bson:"searchString"`
|
SearchString string `bson:"searchString"`
|
||||||
|
@ -21,12 +31,3 @@ type dbUser struct {
|
||||||
UpdatedAt time.Time `bson:"updatedAt"`
|
UpdatedAt time.Time `bson:"updatedAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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"`
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package usermngmt
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -7,17 +7,17 @@ import (
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func hashPassword(password string) string {
|
func HashPassword(password string) string {
|
||||||
bytes, _ := bcrypt.GenerateFromPassword([]byte(password), passwordHashingCost)
|
bytes, _ := bcrypt.GenerateFromPassword([]byte(password), passwordHashingCost)
|
||||||
return string(bytes)
|
return string(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPasswordHash(password, hash string) bool {
|
func CheckPasswordHash(password, hash string) bool {
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSearchString(fieldList ...string) string {
|
func GetSearchString(fieldList ...string) string {
|
||||||
var (
|
var (
|
||||||
searchList = make([]interface{}, 0)
|
searchList = make([]interface{}, 0)
|
||||||
format = ""
|
format = ""
|
||||||
|
@ -33,3 +33,4 @@ func getSearchString(fieldList ...string) string {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(format, searchList...)
|
return fmt.Sprintf(format, searchList...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package usermngmt
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Selly-Modules/mongodb"
|
"github.com/Selly-Modules/mongodb"
|
||||||
|
@ -6,7 +6,7 @@ import (
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
type commonQuery struct {
|
type CommonQuery struct {
|
||||||
Page int64
|
Page int64
|
||||||
Limit int64
|
Limit int64
|
||||||
Keyword string
|
Keyword string
|
||||||
|
@ -16,14 +16,14 @@ type commonQuery struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssignKeyword ...
|
// AssignKeyword ...
|
||||||
func (q *commonQuery) AssignKeyword(cond bson.M) {
|
func (q *CommonQuery) AssignKeyword(cond bson.M) {
|
||||||
if q.Keyword != "" {
|
if q.Keyword != "" {
|
||||||
cond["searchString"] = mongodb.GenerateQuerySearchString(q.Keyword)
|
cond["searchString"] = mongodb.GenerateQuerySearchString(q.Keyword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssignRoleID ...
|
// AssignRoleID ...
|
||||||
func (q *commonQuery) AssignRoleID(cond bson.M) {
|
func (q *CommonQuery) AssignRoleID(cond bson.M) {
|
||||||
if q.RoleID != "" {
|
if q.RoleID != "" {
|
||||||
if id, isValid := mongodb.NewIDFromString(q.RoleID); isValid {
|
if id, isValid := mongodb.NewIDFromString(q.RoleID); isValid {
|
||||||
cond["roleId"] = id
|
cond["roleId"] = id
|
||||||
|
@ -32,14 +32,14 @@ func (q *commonQuery) AssignRoleID(cond bson.M) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssignStatus ...
|
// AssignStatus ...
|
||||||
func (q *commonQuery) AssignStatus(cond bson.M) {
|
func (q *CommonQuery) AssignStatus(cond bson.M) {
|
||||||
if q.Status != "" {
|
if q.Status != "" {
|
||||||
cond["status"] = q.Status
|
cond["status"] = q.Status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFindOptionsUsingPage ...
|
// GetFindOptionsUsingPage ...
|
||||||
func (q *commonQuery) GetFindOptionsUsingPage() *options.FindOptions {
|
func (q *CommonQuery) GetFindOptionsUsingPage() *options.FindOptions {
|
||||||
opts := options.Find()
|
opts := options.Find()
|
||||||
if q.Limit > 0 {
|
if q.Limit > 0 {
|
||||||
opts.SetLimit(q.Limit).SetSkip(q.Limit * q.Page)
|
opts.SetLimit(q.Limit).SetSkip(q.Limit * q.Page)
|
||||||
|
@ -51,8 +51,9 @@ func (q *commonQuery) GetFindOptionsUsingPage() *options.FindOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaultLimit ...
|
// SetDefaultLimit ...
|
||||||
func (q *commonQuery) SetDefaultLimit() {
|
func (q *CommonQuery) SetDefaultLimit() {
|
||||||
if q.Limit <= 0 || q.Limit > 20 {
|
if q.Limit <= 0 || q.Limit > 20 {
|
||||||
q.Limit = 20
|
q.Limit = 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
type RoleShort struct {
|
||||||
|
ID string `json:"_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
IsAdmin bool `json:"isAdmin"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleCreateOptions ...
|
||||||
|
type RoleCreateOptions struct {
|
||||||
|
Name string
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package usermngmt
|
package internal
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ func getHCMLocation() *time.Location {
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
// now ...
|
// Now ...
|
||||||
func now() time.Time {
|
func Now() time.Time {
|
||||||
return time.Now().In(getHCMLocation())
|
return time.Now().In(getHCMLocation())
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Selly-Modules/logger"
|
||||||
|
"github.com/Selly-Modules/mongodb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateOptions ...
|
||||||
|
type CreateOptions struct {
|
||||||
|
Name string
|
||||||
|
Phone string
|
||||||
|
Email string
|
||||||
|
Password string
|
||||||
|
Status string
|
||||||
|
RoleID string
|
||||||
|
Other string
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateOptions ...
|
||||||
|
type UpdateOptions struct {
|
||||||
|
Name string
|
||||||
|
Phone string
|
||||||
|
Email string
|
||||||
|
RoleID string
|
||||||
|
Other string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangePasswordOptions ...
|
||||||
|
type ChangePasswordOptions struct {
|
||||||
|
OldPassword string
|
||||||
|
NewPassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllQuery ...
|
||||||
|
type AllQuery struct {
|
||||||
|
Page int64
|
||||||
|
Limit int64
|
||||||
|
Keyword string
|
||||||
|
RoleID string
|
||||||
|
Status string
|
||||||
|
}
|
||||||
|
|
||||||
|
// User ...
|
||||||
|
type User 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// UserAll ...
|
||||||
|
UserAll struct {
|
||||||
|
List []User `json:"list"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewUser ...
|
||||||
|
func (payload CreateOptions) NewUser() (result DBUser, err error) {
|
||||||
|
timeNow := Now()
|
||||||
|
roleID, _ := mongodb.NewIDFromString(payload.RoleID)
|
||||||
|
return DBUser{
|
||||||
|
ID: mongodb.NewObjectID(),
|
||||||
|
Name: payload.Name,
|
||||||
|
SearchString: GetSearchString(payload.Name, payload.Phone, payload.Email),
|
||||||
|
Phone: payload.Phone,
|
||||||
|
Email: payload.Email,
|
||||||
|
HashedPassword: HashPassword(payload.Password),
|
||||||
|
Status: payload.Status,
|
||||||
|
RoleID: roleID,
|
||||||
|
Other: payload.Other,
|
||||||
|
CreatedAt: timeNow,
|
||||||
|
UpdatedAt: timeNow,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate ...
|
||||||
|
func (co CreateOptions) Validate() error {
|
||||||
|
// Name
|
||||||
|
if co.Name == "" {
|
||||||
|
logger.Error("usermngmt - Create: no Name data", logger.LogData{
|
||||||
|
"payload": co,
|
||||||
|
})
|
||||||
|
return errors.New("no name data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phone
|
||||||
|
if co.Phone == "" {
|
||||||
|
logger.Error("usermngmt - Create: no phone data", logger.LogData{
|
||||||
|
"payload": co,
|
||||||
|
})
|
||||||
|
return errors.New("no phone data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email
|
||||||
|
if co.Email == "" {
|
||||||
|
logger.Error("usermngmt - Create: no email data", logger.LogData{
|
||||||
|
"payload": co,
|
||||||
|
})
|
||||||
|
return errors.New("no email data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Password
|
||||||
|
if co.Password == "" {
|
||||||
|
logger.Error("usermngmt - Create: no password data", logger.LogData{
|
||||||
|
"payload": co,
|
||||||
|
})
|
||||||
|
return errors.New("no password data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status
|
||||||
|
if co.Status == "" {
|
||||||
|
logger.Error("usermngmt - Create: no status data", logger.LogData{
|
||||||
|
"payload": co,
|
||||||
|
})
|
||||||
|
return errors.New("no status data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleID
|
||||||
|
if co.RoleID == "" {
|
||||||
|
logger.Error("usermngmt - Create: no roleID data", logger.LogData{
|
||||||
|
"payload": co,
|
||||||
|
})
|
||||||
|
return errors.New("no role id data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate ...
|
||||||
|
func (uo UpdateOptions) Validate() error {
|
||||||
|
// Name
|
||||||
|
if uo.Name == "" {
|
||||||
|
logger.Error("usermngmt - Update: no name data", logger.LogData{
|
||||||
|
"payload": uo,
|
||||||
|
})
|
||||||
|
return errors.New("no name data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phone
|
||||||
|
if uo.Phone == "" {
|
||||||
|
logger.Error("usermngmt - Update: no phone data", logger.LogData{
|
||||||
|
"payload": uo,
|
||||||
|
})
|
||||||
|
return errors.New("no phone data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Email
|
||||||
|
if uo.Email == "" {
|
||||||
|
logger.Error("usermngmt - Update: no email data", logger.LogData{
|
||||||
|
"payload": uo,
|
||||||
|
})
|
||||||
|
return errors.New("no email data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoleID
|
||||||
|
if uo.RoleID == "" {
|
||||||
|
logger.Error("usermngmt - Update: no roleID data", logger.LogData{
|
||||||
|
"payload": uo,
|
||||||
|
})
|
||||||
|
return errors.New("no role id data")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate ...
|
||||||
|
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{
|
||||||
|
"payload": co,
|
||||||
|
})
|
||||||
|
return errors.New("old or new password cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
32
model.go
32
model.go
|
@ -1,32 +0,0 @@
|
||||||
package usermngmt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// User ...
|
|
||||||
type User 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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RoleShort struct {
|
|
||||||
ID string `json:"_id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
IsAdmin bool `json:"isAdmin"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type (
|
|
||||||
// UserAll ...
|
|
||||||
UserAll struct {
|
|
||||||
List []User `json:"list"`
|
|
||||||
Total int64 `json:"total"`
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package role
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/Selly-Modules/usermngmt/internal"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h Handle) findByID(ctx context.Context, id primitive.ObjectID) (internal.DBRole, error) {
|
||||||
|
var (
|
||||||
|
doc internal.DBRole
|
||||||
|
)
|
||||||
|
err := h.Col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc)
|
||||||
|
return doc, err
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package role
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/Selly-Modules/usermngmt/internal"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handle struct {
|
||||||
|
Col *mongo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindByID ...
|
||||||
|
func (h Handle) FindByID(ctx context.Context, id primitive.ObjectID) (internal.DBRole, error) {
|
||||||
|
role, err := h.findByID(ctx, id)
|
||||||
|
return role, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create ...
|
||||||
|
func (h Handle) Create(payload internal.RoleCreateOptions) error {
|
||||||
|
// TODO later
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Selly-Modules/logger"
|
||||||
|
"github.com/Selly-Modules/usermngmt/internal"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h Handle) isPhoneNumberOrEmailExisted(ctx context.Context, phone, email string) bool {
|
||||||
|
// Find
|
||||||
|
cond := bson.M{
|
||||||
|
"$or": []bson.M{
|
||||||
|
{
|
||||||
|
"phone": phone,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"email": email,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
total, err := h.Col.CountDocuments(ctx, cond)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("usermngmt - countUserByCondition", logger.LogData{
|
||||||
|
"condition": cond,
|
||||||
|
"err": err.Error(),
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return total != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) isRoleIDExisted(ctx context.Context, roleID primitive.ObjectID) bool {
|
||||||
|
// Find
|
||||||
|
cond := bson.M{
|
||||||
|
"_id": roleID,
|
||||||
|
}
|
||||||
|
total, err := h.RoleCol.CountDocuments(ctx, cond)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("usermngmt - countRoleByCondition", logger.LogData{
|
||||||
|
"condition": cond,
|
||||||
|
"err": err.Error(),
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return total != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) roleFindByID(ctx context.Context, id primitive.ObjectID) (internal.DBRole, error) {
|
||||||
|
var (
|
||||||
|
doc internal.DBRole
|
||||||
|
)
|
||||||
|
err := h.RoleCol.FindOne(ctx, bson.M{"_id": id}).Decode(&doc)
|
||||||
|
return doc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) create(ctx context.Context, doc internal.DBUser) error {
|
||||||
|
_, err := h.Col.InsertOne(ctx, doc)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("usermngmt - Create", logger.LogData{
|
||||||
|
"doc": doc,
|
||||||
|
"err": err.Error(),
|
||||||
|
})
|
||||||
|
return fmt.Errorf("error when create user: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) updateOneByCondition(ctx context.Context, cond interface{}, payload interface{}) error {
|
||||||
|
_, err := h.Col.UpdateOne(ctx, cond, payload)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("usermngmt - Update", logger.LogData{
|
||||||
|
"cond": cond,
|
||||||
|
"payload": payload,
|
||||||
|
"err": err.Error(),
|
||||||
|
})
|
||||||
|
return fmt.Errorf("error when update user: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) findByID(ctx context.Context, id primitive.ObjectID) (internal.DBUser, error) {
|
||||||
|
var (
|
||||||
|
doc internal.DBUser
|
||||||
|
)
|
||||||
|
err := h.Col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc)
|
||||||
|
return doc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) findByCondition(ctx context.Context, cond interface{}, opts ...*options.FindOptions) (docs []internal.DBUser) {
|
||||||
|
docs = make([]internal.DBUser, 0)
|
||||||
|
|
||||||
|
cursor, err := h.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// countByCondition ...
|
||||||
|
func (h Handle) countByCondition(ctx context.Context, cond interface{}) int64 {
|
||||||
|
total, err := h.Col.CountDocuments(ctx, cond)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("usermngmt - Count", logger.LogData{
|
||||||
|
"err": err.Error(),
|
||||||
|
"cond": cond,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
|
@ -0,0 +1,245 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/Selly-Modules/logger"
|
||||||
|
"github.com/Selly-Modules/mongodb"
|
||||||
|
"github.com/Selly-Modules/usermngmt/internal"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handle struct {
|
||||||
|
Col *mongo.Collection
|
||||||
|
RoleCol *mongo.Collection
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create ...
|
||||||
|
func (h Handle) Create(payload internal.CreateOptions) error {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validate payload
|
||||||
|
if err := payload.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find roleID exists or not
|
||||||
|
roleID, isValid := mongodb.NewIDFromString(payload.RoleID)
|
||||||
|
if !isValid {
|
||||||
|
return errors.New("invalid role id data")
|
||||||
|
}
|
||||||
|
if !h.isRoleIDExisted(ctx, roleID) {
|
||||||
|
return errors.New("role id does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find phone number,email exists or not
|
||||||
|
if h.isPhoneNumberOrEmailExisted(ctx, payload.Phone, payload.Email) {
|
||||||
|
return errors.New("phone number or email already existed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// New user data from payload
|
||||||
|
doc, err := payload.NewUser()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create user
|
||||||
|
if err = h.create(ctx, doc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// All ...
|
||||||
|
func (h Handle) All(queryParams internal.AllQuery) (r internal.UserAll) {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
wg sync.WaitGroup
|
||||||
|
cond = bson.M{}
|
||||||
|
)
|
||||||
|
query := internal.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 := h.findByCondition(ctx, cond, query.GetFindOptionsUsingPage())
|
||||||
|
r.List = h.getResponseList(ctx, docs)
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
r.Total = h.countByCondition(ctx, cond)
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) getResponseList(ctx context.Context, users []internal.DBUser) []internal.User {
|
||||||
|
res := make([]internal.User, 0)
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
roleRaw, _ := h.roleFindByID(ctx, user.RoleID)
|
||||||
|
res = append(res, internal.User{
|
||||||
|
ID: user.ID.Hex(),
|
||||||
|
Name: user.Name,
|
||||||
|
Phone: user.Phone,
|
||||||
|
Email: user.Email,
|
||||||
|
Status: user.Status,
|
||||||
|
Role: internal.RoleShort{
|
||||||
|
ID: roleRaw.ID.Hex(),
|
||||||
|
Name: roleRaw.Name,
|
||||||
|
IsAdmin: roleRaw.IsAdmin,
|
||||||
|
},
|
||||||
|
Other: user.Other,
|
||||||
|
CreatedAt: user.CreatedAt,
|
||||||
|
UpdatedAt: user.UpdatedAt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateByUserID ...
|
||||||
|
func (h Handle) UpdateByUserID(userID string, payload internal.UpdateOptions) error {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validate payload
|
||||||
|
if err := payload.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find roleID exists or not
|
||||||
|
roleID, isValid := mongodb.NewIDFromString(payload.RoleID)
|
||||||
|
if !isValid {
|
||||||
|
return errors.New("invalid role id data")
|
||||||
|
}
|
||||||
|
if !h.isRoleIDExisted(ctx, roleID) {
|
||||||
|
return errors.New("role id does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find phone number,email exists or not
|
||||||
|
if h.isPhoneNumberOrEmailExisted(ctx, payload.Phone, payload.Email) {
|
||||||
|
return errors.New("phone number or email already existed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup condition
|
||||||
|
id, _ := mongodb.NewIDFromString(userID)
|
||||||
|
cond := bson.M{
|
||||||
|
"_id": id,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup update data
|
||||||
|
updateData := bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"name": payload.Name,
|
||||||
|
"searchString": internal.GetSearchString(payload.Name, payload.Phone, payload.Email),
|
||||||
|
"phone": payload.Phone,
|
||||||
|
"email": payload.Email,
|
||||||
|
"roleId": roleID,
|
||||||
|
"other": payload.Other,
|
||||||
|
"updatedAt": internal.Now(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
if err := h.updateOneByCondition(ctx, cond, updateData); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeUserPassword ...
|
||||||
|
func (h Handle) ChangeUserPassword(userID string, opt internal.ChangePasswordOptions) error {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validate payload
|
||||||
|
err := opt.Validate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate userID
|
||||||
|
if _, isValid := mongodb.NewIDFromString(userID); !isValid {
|
||||||
|
logger.Error("usermngmt - ChangePassword: invalid userID data", logger.LogData{
|
||||||
|
"payload": opt,
|
||||||
|
"userID": userID,
|
||||||
|
})
|
||||||
|
return errors.New("invalid user id data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find user
|
||||||
|
id, _ := mongodb.NewIDFromString(userID)
|
||||||
|
user, _ := h.findByID(ctx, id)
|
||||||
|
if user.ID.IsZero() {
|
||||||
|
return errors.New("user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check old password
|
||||||
|
if isValid := internal.CheckPasswordHash(opt.OldPassword, user.HashedPassword); !isValid {
|
||||||
|
return errors.New("the password is incorrect")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update password
|
||||||
|
if err = h.updateOneByCondition(ctx, bson.M{"_id": user.ID}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"hashedPassword": internal.HashPassword(opt.NewPassword),
|
||||||
|
"updatedAt": internal.Now(),
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeUserStatus ...
|
||||||
|
func (h Handle) ChangeUserStatus(userID, newStatus string) error {
|
||||||
|
var (
|
||||||
|
ctx = context.Background()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Validate userID
|
||||||
|
id, isValid := mongodb.NewIDFromString(userID)
|
||||||
|
if !isValid {
|
||||||
|
return errors.New("invalid user id data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update status
|
||||||
|
if err := h.updateOneByCondition(ctx, bson.M{"_id": id}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"status": newStatus,
|
||||||
|
"updatedAt": internal.Now(),
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
145
validate.go
145
validate.go
|
@ -1,145 +0,0 @@
|
||||||
package usermngmt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/Selly-Modules/logger"
|
|
||||||
"github.com/Selly-Modules/mongodb"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (co CreateOptions) validate(ctx context.Context) error {
|
|
||||||
// Name
|
|
||||||
if co.Name == "" {
|
|
||||||
logger.Error("usermngmt - Create: no Name data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no name data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phone
|
|
||||||
if co.Phone == "" {
|
|
||||||
logger.Error("usermngmt - Create: no phone data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no phone data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email
|
|
||||||
if co.Email == "" {
|
|
||||||
logger.Error("usermngmt - Create: no email data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no email data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Password
|
|
||||||
if co.Password == "" {
|
|
||||||
logger.Error("usermngmt - Create: no password data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no password data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Status
|
|
||||||
if co.Status == "" {
|
|
||||||
logger.Error("usermngmt - Create: no status data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no status data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoleID
|
|
||||||
if co.RoleID == "" {
|
|
||||||
logger.Error("usermngmt - Create: no roleID data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no role id data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find roleID exists or not
|
|
||||||
roleID, isValid := mongodb.NewIDFromString(co.RoleID)
|
|
||||||
if !isValid {
|
|
||||||
return errors.New("invalid role id data")
|
|
||||||
}
|
|
||||||
if !s.isRoleIDExisted(ctx, roleID) {
|
|
||||||
return errors.New("role id does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find phone number,email exists or not
|
|
||||||
if s.isPhoneNumberOrEmailExisted(ctx, co.Phone, co.Email) {
|
|
||||||
return errors.New("phone number or email already existed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (co UpdateOptions) validate(ctx context.Context) error {
|
|
||||||
// Name
|
|
||||||
if co.Name == "" {
|
|
||||||
logger.Error("usermngmt - Update: no name data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no name data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phone
|
|
||||||
if co.Phone == "" {
|
|
||||||
logger.Error("usermngmt - Update: no phone data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no phone data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Email
|
|
||||||
if co.Email == "" {
|
|
||||||
logger.Error("usermngmt - Update: no email data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no email data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// RoleID
|
|
||||||
if co.RoleID == "" {
|
|
||||||
logger.Error("usermngmt - Update: no roleID data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("no role id data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find roleID exists or not
|
|
||||||
roleID, isValid := mongodb.NewIDFromString(co.RoleID)
|
|
||||||
if !isValid {
|
|
||||||
return errors.New("invalid role id data")
|
|
||||||
}
|
|
||||||
if !s.isRoleIDExisted(ctx, roleID) {
|
|
||||||
return errors.New("role id does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find phone number,email exists or not
|
|
||||||
if s.isPhoneNumberOrEmailExisted(ctx, co.Phone, co.Email) {
|
|
||||||
return errors.New("phone number or email already existed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (co ChangePasswordOptions) validate(userID string) error {
|
|
||||||
// OldPassword, NewPassword
|
|
||||||
if co.OldPassword == "" || co.NewPassword == "" {
|
|
||||||
logger.Error("usermngmt - ChangePassword: old or new password cannot be empty", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("old or new password cannot be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserID
|
|
||||||
if _, isValid := mongodb.NewIDFromString(userID); !isValid {
|
|
||||||
logger.Error("usermngmt - ChangePassword: invalid userID data", logger.LogData{
|
|
||||||
"payload": co,
|
|
||||||
})
|
|
||||||
return errors.New("invalid user id data")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue