Compare commits

...

65 Commits

Author SHA1 Message Date
sinhluu fca744f17a Merge pull request 'fix login' (#17) from fix-login into master
Reviewed-on: #17
2023-04-15 08:42:11 +00:00
Sinh cd94018a17 fix login 2023-04-15 15:35:55 +07:00
sinhluu 3d1c1d7538 Merge pull request 'update-limit' (#15) from update-limit into master
Reviewed-on: #15
2023-04-05 11:03:07 +00:00
sinhluu 7dff7ac4e0 Merge pull request 'fix import module and add func' (#16) from fix-import-module-and-add-func into master
Reviewed-on: #16
2023-04-05 11:02:53 +00:00
Sinh b2ee21527a fix import module and add func 2023-04-05 17:54:05 +07:00
Sinh 645d38f7ce Merge branch 'master' of git.selly.red:Selly-Modules/usermngmt into update-limit 2022-11-17 10:56:13 +07:00
Sinh 29157b2530 update query limit 2022-11-17 10:53:14 +07:00
trunglt251292 6db4919231 [Update] module 2022-10-10 11:43:34 +07:00
trunglt251292 4bb62759b0 [Update] Package name 2022-10-10 10:46:33 +07:00
nguyenphamquangtue e87f36995b
Merge pull request #14 from Selly-Modules/feature/merchant
fix code
2022-10-06 14:10:06 +07:00
Tue fb660c6715 fix code 2022-10-06 14:09:22 +07:00
nguyenphamquangtue 0e6bd566a5
Merge pull request #13 from Selly-Modules/feature/merchant
fix code
2022-10-06 09:26:00 +07:00
Tue 2224a68c98 fix code 2022-10-06 09:25:24 +07:00
nguyenphamquangtue 7a268b4027
Merge pull request #12 from Selly-Modules/feature/merchant
fix code
2022-10-06 09:15:20 +07:00
Tue f41786dd27 fix code 2022-10-06 09:14:45 +07:00
nguyenphamquangtue a6a6fb66cb
Merge pull request #11 from Selly-Modules/feature/merchant
fix code
2022-10-05 17:59:38 +07:00
Tue b80e8054d5 fix code 2022-10-05 17:59:08 +07:00
nguyenphamquangtue a83e938deb
Merge pull request #10 from Selly-Modules/feature/merchant
fix code
2022-10-05 14:08:24 +07:00
Tue 848ffb8ff2 fix code 2022-10-05 14:08:01 +07:00
Hoang 59426ad48f update GetUsersByPermissionFunc 2022-03-29 17:26:35 +07:00
Hoang eb52943468 add GetUsersByPermissionMetho 2022-03-25 14:16:52 +07:00
Nam Huynh ab9bfaacb7
Merge pull request #9 from Selly-Modules/beta
upgrade mongodb version to 1.0.1
2022-02-24 15:21:46 +07:00
Sinh 14d24f5174 upgrade mongodb version to 1.0.1 2022-02-24 15:17:15 +07:00
Hoang 4875c935b7 add ResetAndRequireToChangeUserPassword method 2022-02-18 11:28:27 +07:00
Hoang d85b4c9760 update UserAllQuery 2021-12-28 15:37:57 +07:00
Hoang 81df358020 update AssignOther 2021-12-24 09:38:49 +07:00
Hoang 57ea2d882a change passwordHashingCost to 12 2021-12-14 16:30:41 +07:00
Hoang 6e0eeb652b remove log 2021-12-08 13:47:19 +07:00
Hoang ac0636e7e9 change bigCache to redis 2021-12-08 11:42:31 +07:00
Hoang 9c0ba9312f add log get cache 2021-12-07 18:18:44 +07:00
Hoang 55dff6d477 add log cache role 2021-12-07 16:45:38 +07:00
Hoang ae971f1556 add update response viError 2021-12-07 14:28:52 +07:00
Hoang 4d4bf4db8f add resetPassword 2021-12-01 17:51:44 +07:00
Hoang 445cacc540 add FindUserByEmai 2021-12-01 14:34:52 +07:00
Hoang 4d632ed042 update UserRes 2021-11-29 10:01:04 +07:00
Hoang 8201b658b2 udpate getResponseFunc 2021-11-24 17:26:00 +07:00
Hoang c6dbf1fd94 udpate logger init 2021-11-24 16:28:01 +07:00
Hoang 828fec0abb update 2021-11-24 13:15:40 +07:00
Hoang 54c9a2cc07 update Change password 2021-11-23 17:47:23 +07:00
Hoang 4264ef71f1 update AllMethod 2021-11-23 11:48:40 +07:00
Hoang c33715bdd5 update userAvatar 2021-11-22 17:35:21 +07:00
Hoang 3c4eab8977 update UserAllQuery 2021-11-20 22:00:00 +07:00
Hoang 41c52b6fc6 add findRoleMethod 2021-11-19 13:50:24 +07:00
Hoang 49be1c3c96 update userUpdateMethod 2021-11-19 11:17:58 +07:00
Hoang 14ad6b51d8 add count method 2021-11-19 11:00:18 +07:00
Hoang 14f3f94f98 add findUserMethod 2021-11-19 09:59:33 +07:00
Hoang 7033a27fc0 add other query 2021-11-18 10:30:12 +07:00
Hoang 2a5e05c3ad update User 2021-11-17 13:32:29 +07:00
Hoang 72f30fce59 update permissionAllMethod 2021-11-17 10:13:08 +07:00
Hoang b841ef7d8a update AllModelRes 2021-11-16 17:47:54 +07:00
Hoang 73ef7d69db fix isPermissionIDExistedFunc 2021-11-16 16:05:37 +07:00
Hoang e8547dfcda add DeletePermissionMethod 2021-11-16 15:34:56 +07:00
Hoang 7753de40ef fix allQueryModel 2021-11-16 14:26:50 +07:00
Hoang 79b32fa209 init logger 2021-11-16 12:16:06 +07:00
Hoang ba3b0104ff update AllCreateMethod 2021-11-16 11:11:04 +07:00
Hoang 3a20ec8cd7 update role 2021-11-12 12:16:38 +07:00
Nam Huynh 1e6d2e6b2f
Merge pull request #8 from Selly-Modules/feature/isPermission
add isPermissionMethod
2021-11-11 17:07:15 +07:00
Hoang 45e9f71a3f fix comment again 2021-11-11 16:58:44 +07:00
Hoang 4ee176b9e0 fix comment again 2021-11-11 15:19:38 +07:00
Hoang 8d19c4c09c fix comment again 2021-11-11 15:16:17 +07:00
Hoang 7c232c0434 fix comment again 2021-11-11 10:20:08 +07:00
Hoang b2373bbada change name to HasPermission 2021-11-10 17:02:16 +07:00
Hoang 2a74aa1b8e add isPermissionMethod 2021-11-10 16:53:31 +07:00
Nam Huynh d8dcfbcad4
Merge pull request #7 from Selly-Modules/feature/Permission
add permisstionMethods
2021-11-10 16:29:52 +07:00
Nam Huynh c16b1f153d
Merge pull request #6 from Selly-Modules/feature/Role
add RoleMethods
2021-11-10 15:05:20 +07:00
27 changed files with 1502 additions and 470 deletions

115
action.go
View File

@ -1,10 +1,11 @@
package usermngmt package usermngmt
import ( import (
"github.com/Selly-Modules/usermngmt/model" "git.selly.red/Selly-Modules/usermngmt/cache"
"github.com/Selly-Modules/usermngmt/permission" "git.selly.red/Selly-Modules/usermngmt/model"
"github.com/Selly-Modules/usermngmt/role" "git.selly.red/Selly-Modules/usermngmt/permission"
"github.com/Selly-Modules/usermngmt/user" "git.selly.red/Selly-Modules/usermngmt/role"
"git.selly.red/Selly-Modules/usermngmt/user"
) )
// //
@ -14,10 +15,25 @@ import (
// user methods // user methods
// CreateUser ... // CreateUser ...
func (s Service) CreateUser(payload model.UserCreateOptions) error { func (s Service) CreateUser(payload model.UserCreateOptions) (id string, err error) {
return user.Create(payload) return user.Create(payload)
} }
// FindUser ...
func (s Service) FindUser(userID string) (model.User, error) {
return user.FindUser(userID)
}
// FindUserByEmail ...
func (s Service) FindUserByEmail(email string) (model.User, error) {
return user.FindUserByEmail(email)
}
// GetHashedPassword ...
func (s Service) GetHashedPassword(userID string) (string, error) {
return user.GetHashedPassword(userID)
}
// UpdateUser ... // UpdateUser ...
func (s Service) UpdateUser(userID string, payload model.UserUpdateOptions) error { func (s Service) UpdateUser(userID string, payload model.UserUpdateOptions) error {
return user.UpdateByUserID(userID, payload) return user.UpdateByUserID(userID, payload)
@ -28,16 +44,36 @@ func (s Service) ChangeUserPassword(userID string, payload model.ChangePasswordO
return user.ChangeUserPassword(userID, payload) return user.ChangeUserPassword(userID, payload)
} }
// ResetUserPassword ...
func (s Service) ResetUserPassword(userID string, password string) error {
return user.ResetUserPassword(userID, password)
}
// ResetAndRequireToChangeUserPassword ...
func (s Service) ResetAndRequireToChangeUserPassword(userID string, password string) error {
return user.ResetAndRequireToChangeUserPassword(userID, password)
}
// ChangeUserStatus ... // ChangeUserStatus ...
func (s Service) ChangeUserStatus(userID, newStatus string) error { func (s Service) ChangeUserStatus(userID, newStatus string) error {
return user.ChangeUserStatus(userID, newStatus) return user.ChangeUserStatus(userID, newStatus)
} }
// GetAllUser ... // GetAllUsers ...
func (s Service) GetAllUser(query model.UserAllQuery) model.UserAll { func (s Service) GetAllUsers(query model.UserAllQuery) model.UserAll {
return user.All(query) return user.All(query)
} }
// GetUsersByPermission ...
func (s Service) GetUsersByPermission(query model.UserByPermissionQuery) model.UserAll {
return user.GetUsersByPermission(query)
}
// CountAllUsers ...
func (s Service) CountAllUsers(query model.UserCountQuery) int64 {
return user.Count(query)
}
// ChangeAllUsersStatus ... // ChangeAllUsersStatus ...
func (s Service) ChangeAllUsersStatus(roleID, status string) error { func (s Service) ChangeAllUsersStatus(roleID, status string) error {
return user.ChangeAllUsersStatus(roleID, status) return user.ChangeAllUsersStatus(roleID, status)
@ -48,6 +84,21 @@ func (s Service) LoginWithEmailAndPassword(email, password string) (model.User,
return user.LoginWithEmailAndPassword(email, password) return user.LoginWithEmailAndPassword(email, password)
} }
// HasPermission ...
func (s Service) HasPermission(userID, permission string) bool {
return user.HasPermission(userID, permission)
}
// UpdateUserAvatar ...
func (s Service) UpdateUserAvatar(userID string, avatar interface{}) error {
return user.UpdateAvatar(userID, avatar)
}
// DeleteUser ...
func (s Service) DeleteUser(userID string) error {
return user.Delete(userID)
}
// //
// Role // Role
// //
@ -55,8 +106,14 @@ func (s Service) LoginWithEmailAndPassword(email, password string) (model.User,
// role methods // role methods
// CreateRole ... // CreateRole ...
func (s Service) CreateRole(payload model.RoleCreateOptions) error { func (s Service) CreateRole(payload model.RoleCreateOptions) (id string, err error) {
return role.Create(payload) id, err = role.Create(payload)
if err != nil {
return
}
cache.Roles()
return
} }
// UpdateRole ... // UpdateRole ...
@ -69,6 +126,11 @@ func (s Service) GetAllRoles(query model.RoleAllQuery) model.RoleAll {
return role.All(query) return role.All(query)
} }
// FindRole ...
func (s Service) FindRole(roleID string) (model.Role, error) {
return role.FindRole(roleID)
}
// //
// Permission // Permission
// //
@ -76,13 +138,42 @@ func (s Service) GetAllRoles(query model.RoleAllQuery) model.RoleAll {
// permission methods // permission methods
// CreatePermission ... // CreatePermission ...
func (s Service) CreatePermission(payload model.PermissionCreateOptions) error { func (s Service) CreatePermission(payload model.PermissionCreateOptions) (id string, err error) {
return permission.Create(payload) id, err = permission.Create(payload)
if err != nil {
return
}
cache.Roles()
return
} }
// UpdatePermission ... // UpdatePermission ...
func (s Service) UpdatePermission(permissionID string, payload model.PermissionUpdateOptions) error { func (s Service) UpdatePermission(permissionID string, payload model.PermissionUpdateOptions) error {
return permission.Update(permissionID, payload) if err := permission.Update(permissionID, payload); err != nil {
return err
}
cache.Roles()
return nil
}
// DeletePermission ...
func (s Service) DeletePermission(permissionID string) error {
if err := permission.Delete(permissionID); err != nil {
return err
}
cache.Roles()
return nil
}
// FindAndDeletePermission ...
func (s Service) FindAndDeletePermission(permissionID string) (*model.Permission, error) {
p, err := permission.FindByIDAndDelete(permissionID)
if err != nil {
return nil, err
}
cache.Roles()
return p, nil
} }
// GetAllPermissions ... // GetAllPermissions ...

67
cache/cache.go vendored Normal file
View File

@ -0,0 +1,67 @@
package cache
import (
"context"
"encoding/json"
"fmt"
"log"
"time"
"github.com/go-redis/redis/v8"
"github.com/logrusorgru/aurora"
)
var (
c *redis.Client
)
// Init ...
func Init(uri, pwd string) {
c = redis.NewClient(&redis.Options{
Addr: uri,
Password: pwd,
DB: 0, // use default DB
})
// Test
_, err := c.Ping(context.Background()).Result()
if err != nil {
log.Fatal("Cannot connect to redis", uri, err)
}
fmt.Println(aurora.Green("*** CONNECTED TO REDIS: " + uri))
// Cache roles
Roles()
}
// GetInstance ...
func GetInstance() *redis.Client {
return c
}
// SetKeyValue ...
func SetKeyValue(key string, value interface{}, expiration time.Duration) error {
ctx := context.Background()
dataByte, _ := json.Marshal(value)
r := c.Set(ctx, key, dataByte, expiration)
return r.Err()
}
// GetValueByKey ...
func GetValueByKey(key string) ([]byte, error) {
ctx := context.Background()
return c.Get(ctx, key).Bytes()
}
func GetJSON(key string, result interface{}) bool {
v, err := GetValueByKey(key)
if err != nil {
return false
}
if err = json.Unmarshal(v, result); err != nil {
return false
}
return true
}

44
cache/db.go vendored Normal file
View File

@ -0,0 +1,44 @@
package cache
import (
"context"
"go.mongodb.org/mongo-driver/mongo/options"
"git.selly.red/Selly-Modules/usermngmt/database"
"git.selly.red/Selly-Modules/usermngmt/model"
)
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 {
return
}
defer cursor.Close(ctx)
if err = cursor.All(ctx, &docs); err != nil {
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 {
return
}
defer cursor.Close(ctx)
if err = cursor.All(ctx, &docs); err != nil {
return
}
return
}

9
cache/key.go vendored Normal file
View File

@ -0,0 +1,9 @@
package cache
const (
keyPrefix = "usermngmt_"
)
const (
KeyLoginFailedTimes = keyPrefix + "login_failed_time"
)

8
cache/model.go vendored Normal file
View File

@ -0,0 +1,8 @@
package cache
// CachedRole ...
type CachedRole struct {
Role string `json:"role"`
IsAdmin bool `json:"isAdmin"`
Permissions []string `json:"permissions"`
}

68
cache/role.go vendored Normal file
View File

@ -0,0 +1,68 @@
package cache
import (
"context"
"encoding/json"
"log"
"sync"
"go.mongodb.org/mongo-driver/bson"
"git.selly.red/Selly-Modules/usermngmt/model"
)
// 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 := CachedRole{
Role: role.Code,
IsAdmin: role.IsAdmin,
Permissions: rolePermissions,
}
if err := SetKeyValue(role.ID.Hex(), entry, 0); err != nil {
return
}
}(value)
}
wg.Wait()
return
}
// GetCachedRole ...
func GetCachedRole(key string) CachedRole {
value, err := GetValueByKey(key)
if err != nil {
Roles()
value, _ = GetValueByKey(key)
}
// Unmarshal data
var cachedRole CachedRole
if err := json.Unmarshal(value, &cachedRole); err != nil {
log.Println("usermngmt - GetCachedRole - Unmarshal: ", err)
}
return cachedRole
}

27
config/config.go Normal file
View File

@ -0,0 +1,27 @@
package config
import "time"
const (
MaximumLoginFailedTime = 5
LoginFailedBlockedDuration = time.Hour
)
type Configuration struct {
EmailIsUnique bool
PhoneNumberIsUnique bool
}
var (
c *Configuration
)
// Set ...
func Set(instance *Configuration) {
c = instance
}
// GetInstance ...
func GetInstance() *Configuration {
return c
}

51
go.mod
View File

@ -1,44 +1,31 @@
module github.com/Selly-Modules/usermngmt module git.selly.red/Selly-Modules/usermngmt
go 1.17 go 1.17
require ( require (
github.com/Selly-Modules/logger v0.0.0-20210809034923-140a51f39ec9 git.selly.red/Selly-Modules/mongodb v1.0.6-0.20221010033754-1d897a0f9ea2
github.com/Selly-Modules/mongodb v0.0.0-20211013094205-a8ab24a96c4c github.com/go-redis/redis/v8 v8.11.4
go.mongodb.org/mongo-driver v1.7.4 github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/thoas/go-funk v0.9.1
go.mongodb.org/mongo-driver v1.10.3
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
) )
require ( require (
github.com/armon/go-radix v1.0.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/elastic/go-licenser v0.3.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/elastic/go-sysinfo v1.1.1 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/elastic/go-windows v1.0.0 // indirect github.com/google/go-cmp v0.5.8 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/jcchavezs/porto v0.1.0 // indirect
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect
github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/compress v1.13.6 // indirect
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/montanaflynn/stats v0.6.6 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0 // indirect github.com/stretchr/testify v1.8.0 // indirect
github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
go.elastic.co/apm v1.13.1 // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
go.elastic.co/apm/module/apmzap v1.13.1 // indirect golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 // indirect
go.elastic.co/fastjson v1.1.0 // indirect golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.18.1 // indirect
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 // indirect
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 // indirect
golang.org/x/mod v0.3.0 // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5 // indirect
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect
) )

183
go.sum
View File

@ -1,21 +1,20 @@
git.selly.red/Selly-Modules/mongodb v1.0.6-0.20221010033754-1d897a0f9ea2 h1:bePzcMN/j4V1fvz6UUrN01ey1tkE0w+m5Qj3LtoZs4E=
git.selly.red/Selly-Modules/mongodb v1.0.6-0.20221010033754-1d897a0f9ea2/go.mod h1:Xvs3E6YbTPI5I4+I1aXrY0A79XaCfw+0tqV8dihvheE=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Selly-Modules/logger v0.0.0-20210809034923-140a51f39ec9 h1:AuJ/IIZ7yppyP19ILEYkwz26CwGXR4xUyXANKSG0+1U= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/Selly-Modules/logger v0.0.0-20210809034923-140a51f39ec9/go.mod h1:RWhSQ3F01an8KD00VjzRBZOMcE5eV2Cy0/l4ZkeieyU= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/Selly-Modules/mongodb v0.0.0-20211013094205-a8ab24a96c4c h1:1l6QmAl43maG9zFyUXrPQVUjyVt0vy/2Saz992UR+Sc=
github.com/Selly-Modules/mongodb v0.0.0-20211013094205-a8ab24a96c4c/go.mod h1:C9O0Bgl9i6szjntMjBdEvaFSqG2UPOgHUspIWIJ93JQ=
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/elastic/go-licenser v0.3.1 h1:RmRukU/JUmts+rpexAw0Fvt2ly7VVu6mw8z4HrEzObU= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/elastic/go-licenser v0.3.1/go.mod h1:D8eNQk70FOCVBl3smCGQt/lv7meBeQno2eI1S5apiHQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
@ -40,16 +39,28 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jcchavezs/porto v0.1.0 h1:Xmxxn25zQMmgE7/yHYmh19KcItG81hIwfbEEFnd6w/Q=
github.com/jcchavezs/porto v0.1.0/go.mod h1:fESH0gzDHiutHRdX2hv27ojnOVFco37hg1W6E9EZF4A=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
@ -66,19 +77,29 @@ github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/z
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ=
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0 h1:c8R11WC8m7KNMkTv/0+Be8vvwo4I3/Ut9AC2FW8fX3U=
github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis=
github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@ -86,99 +107,121 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
go.elastic.co/apm v1.13.1 h1:ICIcUcQOImg/bve9mQVyLCvm1cSUZ1afdwK6ACnxczU= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
go.elastic.co/apm v1.13.1/go.mod h1:dylGv2HKR0tiCV+wliJz1KHtDyuD8SPe69oV7VyK6WY= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.elastic.co/apm/module/apmzap v1.13.1 h1:Soa4vNYYabPvOW1vm1A00C0UcEmfEzcx3YBjAgf5ue4=
go.elastic.co/apm/module/apmzap v1.13.1/go.mod h1:Tu8/TwffpBoNGmI05VcL1Ye2AC8oXrlMKNaKD1TIQy0=
go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4=
go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI=
go.mongodb.org/mongo-driver v1.7.1/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= go.mongodb.org/mongo-driver v1.7.1/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
go.mongodb.org/mongo-driver v1.7.4 h1:sllcioag8Mec0LYkftYWq+cKNPIR4Kqq3iv9ZXY0g/E= go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA=
go.mongodb.org/mongo-driver v1.7.4/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5 h1:MeC2gMlMdkd67dn17MEby3rGXRxZtWeiRXOnISfTQ74=
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=

View File

@ -4,7 +4,9 @@ package internal
const ( const (
timezoneHCM = "Asia/Ho_Chi_Minh" timezoneHCM = "Asia/Ho_Chi_Minh"
passwordHashingCost = 14 passwordHashingCost = 12
TablePrefixDefault = "usermngmt" TablePrefixDefault = "usermngmt"
RoleTypeAdmin = "admin"
) )

34
internal/error.go Normal file
View File

@ -0,0 +1,34 @@
package internal
const (
// Invalid
ErrorInvalidName = "tên không hợp lệ"
ErrorInvalidPhoneNumber = "số điện thoại không hợp lệ"
ErrorInvalidEmail = "email không hợp lệ"
ErrorInvalidPassword = "mật khẩu không hợp lệ"
ErrorInvalidStatus = "trạng thái không hợp lệ"
ErrorInvalidRole = "vai trò không hợp lệ"
ErrorInvalidOldPassword = "mật khẩu cũ không hợp lệ"
ErrorInvalidNewPassword = "mật khẩu mới không hợp lệ"
ErrorInvalidPermission = "quyền không hợp lệ"
ErrorInvalidUser = "người dùng không hợp lệ"
ErrorInvalidAvatar = "ảnh đại diện không hợp lệ"
// NotFound
ErrorNotFoundPermission = "quyền không tồn tại"
ErrorNotFoundRole = "vai trò không tồn tại"
ErrorNotFoundUser = "người dùng không tồn tại"
// AlreadyExisted
ErrorAlreadyExistedPhoneNumber = "số điện thoại đã tồn tại"
ErrorAlreadyExistedEmail = "email đã tồn tại"
// Incorrect
ErrorIncorrectPassword = "mật khẩu không chính xác"
ErrorInvalidLogin = "thông tin đăng nhập không đúng"
ErrorExceedMaximumLoginFail = "bạn đã đăng nhập sai thông tin quá số lần cho phép"
)

View File

@ -2,9 +2,11 @@ package internal
import ( import (
"fmt" "fmt"
"github.com/thoas/go-funk"
"go.mongodb.org/mongo-driver/bson/primitive"
"strings" "strings"
"github.com/Selly-Modules/mongodb" "git.selly.red/Selly-Modules/mongodb"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@ -46,3 +48,10 @@ func GenerateCode(s string) string {
) )
return strings.ReplaceAll(mongodb.NonAccentVietnamese(s), emptySpace, underscore) return strings.ReplaceAll(mongodb.NonAccentVietnamese(s), emptySpace, underscore)
} }
// ConvertObjectIDsToStrings ...
func ConvertObjectIDsToStrings(ids []primitive.ObjectID) []string {
return funk.Map(ids, func(item primitive.ObjectID) string {
return item.Hex()
}).([]string)
}

View File

@ -12,23 +12,27 @@ type DBRole struct {
Name string `bson:"name"` Name string `bson:"name"`
Code string `bson:"code"` Code string `bson:"code"`
IsAdmin bool `bson:"isAdmin"` IsAdmin bool `bson:"isAdmin"`
Level int `bson:"level"`
CreatedAt time.Time `bson:"createdAt"` CreatedAt time.Time `bson:"createdAt"`
UpdatedAt time.Time `bson:"updatedAt"` UpdatedAt time.Time `bson:"updatedAt"`
} }
// DBUser ... // DBUser ...
type DBUser struct { 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"`
Phone string `bson:"phone"` // unique Phone string `bson:"phone"` // unique
Email string `bson:"email"` // unique Email string `bson:"email"` // unique
HashedPassword string `bson:"hashedPassword"` HashedPassword string `bson:"hashedPassword"`
Status string `bson:"status"` Status string `bson:"status"`
RoleID primitive.ObjectID `bson:"roleId"` RoleID primitive.ObjectID `bson:"roleId"`
Other string `bson:"other"` RequireToChangePassword bool `bson:"requireToChangePassword"`
CreatedAt time.Time `bson:"createdAt"` Avatar interface{} `bson:"avatar"`
UpdatedAt time.Time `bson:"updatedAt"` Deleted bool `bson:"deleted"`
Other interface{} `bson:"other"` // object
CreatedAt time.Time `bson:"createdAt"`
UpdatedAt time.Time `bson:"updatedAt"`
} }
// DBPermission ... // DBPermission ...

View File

@ -3,13 +3,13 @@ package model
import ( import (
"errors" "errors"
"github.com/Selly-Modules/logger" "git.selly.red/Selly-Modules/mongodb"
"github.com/Selly-Modules/mongodb"
) )
// PermissionCreateOptions ... // PermissionCreateOptions ...
type PermissionCreateOptions struct { type PermissionCreateOptions struct {
Name string Name string
Code string
RoleID string RoleID string
Desc string Desc string
} }
@ -17,31 +17,33 @@ type PermissionCreateOptions struct {
// PermissionUpdateOptions ... // PermissionUpdateOptions ...
type PermissionUpdateOptions struct { type PermissionUpdateOptions struct {
Name string Name string
Code string
RoleID string RoleID string
Desc string Desc string
} }
// PermissionAllQuery ... // PermissionAllQuery ...
type PermissionAllQuery struct { type PermissionAllQuery struct {
Page int64 Page int64
Limit int64 Limit int64
Sort interface{}
RoleID string
} }
// Validate ... // Validate ...
func (co PermissionCreateOptions) Validate() error { func (co PermissionCreateOptions) Validate() error {
// Name // Name
if co.Name == "" { if co.Name == "" {
logger.Error("usermngmt - Permission - Create: no name data", logger.LogData{
"payload": co,
})
return errors.New("no name data") return errors.New("no name data")
} }
// Code
if co.Code == "" {
return errors.New("no code data")
}
// RoleID // RoleID
if co.RoleID == "" { if co.RoleID == "" {
logger.Error("usermngmt - Permission - Create: no roleID data", logger.LogData{
"payload": co,
})
return errors.New("no role id data") return errors.New("no role id data")
} }
if _, isValid := mongodb.NewIDFromString(co.RoleID); !isValid { if _, isValid := mongodb.NewIDFromString(co.RoleID); !isValid {
@ -50,9 +52,6 @@ func (co PermissionCreateOptions) Validate() error {
// Desc // Desc
if co.Desc == "" { if co.Desc == "" {
logger.Error("usermngmt - Permission - Create: no desc data", logger.LogData{
"payload": co,
})
return errors.New("no desc data") return errors.New("no desc data")
} }
return nil return nil
@ -62,17 +61,16 @@ func (co PermissionCreateOptions) Validate() error {
func (co PermissionUpdateOptions) Validate() error { func (co PermissionUpdateOptions) Validate() error {
// Name // Name
if co.Name == "" { if co.Name == "" {
logger.Error("usermngmt - Permission - Update: no name data", logger.LogData{
"payload": co,
})
return errors.New("no name data") return errors.New("no name data")
} }
// Code
if co.Code == "" {
return errors.New("no code data")
}
// RoleID // RoleID
if co.RoleID == "" { if co.RoleID == "" {
logger.Error("usermngmt - Permission - Update: no roleID data", logger.LogData{
"payload": co,
})
return errors.New("no role id data") return errors.New("no role id data")
} }
if _, isValid := mongodb.NewIDFromString(co.RoleID); !isValid { if _, isValid := mongodb.NewIDFromString(co.RoleID); !isValid {
@ -81,9 +79,6 @@ func (co PermissionUpdateOptions) Validate() error {
// Desc // Desc
if co.Desc == "" { if co.Desc == "" {
logger.Error("usermngmt - Permission - Update: no desc data", logger.LogData{
"payload": co,
})
return errors.New("no desc data") return errors.New("no desc data")
} }
return nil return nil

View File

@ -20,5 +20,6 @@ type (
PermissionAll struct { PermissionAll struct {
List []Permission `json:"list"` List []Permission `json:"list"`
Total int64 `json:"total"` Total int64 `json:"total"`
Limit int64 `json:"limit"`
} }
) )

View File

@ -1,11 +1,14 @@
package model package model
import ( import (
"github.com/Selly-Modules/mongodb" "git.selly.red/Selly-Modules/mongodb"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
) )
const maxLimit = 500
// CommonQuery ... // CommonQuery ...
type CommonQuery struct { type CommonQuery struct {
Page int64 Page int64
@ -13,7 +16,20 @@ type CommonQuery struct {
Keyword string Keyword string
RoleID string RoleID string
Status string Status string
Deleted string
Sort interface{} Sort interface{}
Other map[string]interface{}
RoleIDs []primitive.ObjectID
}
// AssignDeleted ...
func (q *CommonQuery) AssignDeleted(cond bson.M) {
if q.Deleted == "true" {
cond["deleted"] = true
}
if q.Deleted == "false" {
cond["deleted"] = false
}
} }
// AssignKeyword ... // AssignKeyword ...
@ -32,6 +48,17 @@ func (q *CommonQuery) AssignRoleID(cond bson.M) {
} }
} }
// AssignRoleIDs ...
func (q *CommonQuery) AssignRoleIDs(cond bson.M) {
if len(q.RoleIDs) == 1 {
cond["roleId"] = q.RoleIDs[0]
} else if len(q.RoleIDs) > 1 {
cond["roleId"] = bson.M{
"$in": q.RoleIDs,
}
}
}
// AssignStatus ... // AssignStatus ...
func (q *CommonQuery) AssignStatus(cond bson.M) { func (q *CommonQuery) AssignStatus(cond bson.M) {
if q.Status != "" { if q.Status != "" {
@ -53,7 +80,31 @@ 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
} }
if q.Limit > maxLimit {
q.Limit = 500
}
}
// AssignOther ...
func (q *CommonQuery) AssignOther(cond bson.M) {
// Query fields in other object
if len(q.Other) > 0 {
for key, value := range q.Other {
switch v := value.(type) {
case []primitive.ObjectID:
cond["other."+key] = bson.M{
"$in": v,
}
case []string:
cond["other."+key] = bson.M{
"$in": v,
}
default:
cond["other."+key] = value
}
}
}
} }

View File

@ -3,33 +3,35 @@ package model
import ( import (
"errors" "errors"
"github.com/Selly-Modules/logger" "git.selly.red/Selly-Modules/usermngmt/internal"
) )
// RoleCreateOptions ... // RoleCreateOptions ...
type RoleCreateOptions struct { type RoleCreateOptions struct {
Name string Name string
Level int
IsAdmin bool
} }
// RoleUpdateOptions ... // RoleUpdateOptions ...
type RoleUpdateOptions struct { type RoleUpdateOptions struct {
Name string Name string
Level int
IsAdmin bool
} }
// RoleAllQuery ... // RoleAllQuery ...
type RoleAllQuery struct { type RoleAllQuery struct {
Page int64 Page int64
Limit int64 Limit int64
Sort interface{}
} }
// Validate ... // Validate ...
func (co RoleCreateOptions) Validate() error { func (co RoleCreateOptions) Validate() error {
// Name // Name
if co.Name == "" { if co.Name == "" {
logger.Error("usermngmt - Role - Create: no name data", logger.LogData{ return errors.New(internal.ErrorInvalidName)
"payload": co,
})
return errors.New("no name data")
} }
return nil return nil
@ -39,10 +41,7 @@ func (co RoleCreateOptions) Validate() error {
func (co RoleUpdateOptions) Validate() error { func (co RoleUpdateOptions) Validate() error {
// Name // Name
if co.Name == "" { if co.Name == "" {
logger.Error("usermngmt - Role - Update: no name data", logger.LogData{ return errors.New(internal.ErrorInvalidName)
"payload": co,
})
return errors.New("no name data")
} }
return nil return nil

View File

@ -8,6 +8,7 @@ import (
type RoleShort struct { type RoleShort struct {
ID string `json:"_id"` ID string `json:"_id"`
Name string `json:"name"` Name string `json:"name"`
Level int `json:"level"`
IsAdmin bool `json:"isAdmin"` IsAdmin bool `json:"isAdmin"`
} }
@ -16,6 +17,7 @@ type Role struct {
ID string `json:"_id"` ID string `json:"_id"`
Name string `json:"name"` Name string `json:"name"`
Code string `json:"code"` Code string `json:"code"`
Level int `json:"level"`
IsAdmin bool `json:"isAdmin"` IsAdmin bool `json:"isAdmin"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"` UpdatedAt time.Time `json:"updatedAt"`
@ -26,5 +28,6 @@ type (
RoleAll struct { RoleAll struct {
List []Role `json:"list"` List []Role `json:"list"`
Total int64 `json:"total"` Total int64 `json:"total"`
Limit int64 `json:"limit"`
} }
) )

View File

@ -3,18 +3,22 @@ package model
import ( import (
"errors" "errors"
"github.com/Selly-Modules/logger" "go.mongodb.org/mongo-driver/bson"
"git.selly.red/Selly-Modules/usermngmt/internal"
) )
// UserCreateOptions ... // UserCreateOptions ...
type UserCreateOptions struct { type UserCreateOptions struct {
Name string Name string
Phone string Phone string
Email string Email string
Password string Password string
Status string Status string
RoleID string RoleID string
Other string RequireToChangePassword bool
Other interface{}
Avatar interface{} // if not, pass default file object
} }
// UserUpdateOptions ... // UserUpdateOptions ...
@ -23,7 +27,7 @@ type UserUpdateOptions struct {
Phone string Phone string
Email string Email string
RoleID string RoleID string
Other string Other map[string]interface{}
} }
// ChangePasswordOptions ... // ChangePasswordOptions ...
@ -39,56 +43,59 @@ type UserAllQuery struct {
Keyword string Keyword string
RoleID string RoleID string
Status string Status string
Sort interface{}
Other map[string]interface{} // query fields in other object
Cond bson.M
}
// UserByPermissionQuery ...
type UserByPermissionQuery struct {
Page int64
Limit int64
Keyword string
Status string
Permission string // permission code
Sort interface{}
Other map[string]interface{} // query fields in other object
Cond bson.M
}
// UserCountQuery ...
type UserCountQuery struct {
RoleID string
Other map[string]interface{} // query fields in other object
} }
// Validate ... // Validate ...
func (co UserCreateOptions) Validate() error { func (co UserCreateOptions) Validate() error {
// Name // Name
if co.Name == "" { if co.Name == "" {
logger.Error("usermngmt - User - Create: no name data", logger.LogData{ return errors.New(internal.ErrorInvalidName)
"payload": co,
})
return errors.New("no name data")
} }
// Phone // Phone
if co.Phone == "" { if co.Phone == "" {
logger.Error("usermngmt - User - Create: no phone data", logger.LogData{ return errors.New(internal.ErrorInvalidPhoneNumber)
"payload": co,
})
return errors.New("no phone data")
} }
// Email // Email
if co.Email == "" { if co.Email == "" {
logger.Error("usermngmt - User - Create: no email data", logger.LogData{ return errors.New(internal.ErrorInvalidEmail)
"payload": co,
})
return errors.New("no email data")
} }
// Password // Password
if co.Password == "" { if co.Password == "" {
logger.Error("usermngmt - User - Create: no password data", logger.LogData{ return errors.New(internal.ErrorInvalidPassword)
"payload": co,
})
return errors.New("no password data")
} }
// Status // Status
if co.Status == "" { if co.Status == "" {
logger.Error("usermngmt - User - Create: no status data", logger.LogData{ return errors.New(internal.ErrorInvalidStatus)
"payload": co,
})
return errors.New("no status data")
} }
// RoleID // RoleID
if co.RoleID == "" { if co.RoleID == "" {
logger.Error("usermngmt - User - Create: no roleID data", logger.LogData{ return errors.New(internal.ErrorInvalidRole)
"payload": co,
})
return errors.New("no role id data")
} }
return nil return nil
@ -98,34 +105,22 @@ func (co UserCreateOptions) Validate() error {
func (uo UserUpdateOptions) Validate() error { func (uo UserUpdateOptions) Validate() error {
// Name // Name
if uo.Name == "" { if uo.Name == "" {
logger.Error("usermngmt - User - Update: no name data", logger.LogData{ return errors.New(internal.ErrorInvalidName)
"payload": uo,
})
return errors.New("no name data")
} }
// Phone // Phone
if uo.Phone == "" { if uo.Phone == "" {
logger.Error("usermngmt - User - Update: no phone data", logger.LogData{ return errors.New(internal.ErrorInvalidPhoneNumber)
"payload": uo,
})
return errors.New("no phone data")
} }
// Email // Email
if uo.Email == "" { if uo.Email == "" {
logger.Error("usermngmt - User - Update: no email data", logger.LogData{ return errors.New(internal.ErrorInvalidEmail)
"payload": uo,
})
return errors.New("no email data")
} }
// RoleID // RoleID
if uo.RoleID == "" { if uo.RoleID == "" {
logger.Error("usermngmt - User - Update: no roleID data", logger.LogData{ return errors.New(internal.ErrorInvalidRole)
"payload": uo,
})
return errors.New("no role id data")
} }
return nil return nil
@ -134,11 +129,22 @@ func (uo UserUpdateOptions) Validate() error {
// Validate ... // Validate ...
func (co ChangePasswordOptions) Validate() error { func (co ChangePasswordOptions) Validate() error {
// OldPassword, NewPassword // OldPassword, NewPassword
if co.OldPassword == "" || co.NewPassword == "" { if co.OldPassword == "" {
logger.Error("usermngmt - User - ChangePassword: old or new password cannot be empty", logger.LogData{ return errors.New(internal.ErrorInvalidOldPassword)
"payload": co, }
})
return errors.New("old or new password cannot be empty") if co.NewPassword == "" {
return errors.New(internal.ErrorInvalidNewPassword)
}
return nil
}
// Validate ...
func (q UserByPermissionQuery) Validate() error {
// OldPassword, NewPassword
if q.Permission == "" {
return errors.New(internal.ErrorInvalidPermission)
} }
return nil return nil

View File

@ -1,20 +1,51 @@
package model package model
import ( import (
"git.selly.red/Selly-Modules/usermngmt/internal"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"time" "time"
) )
// User ... // User ...
type User struct { type User struct {
ID string `json:"_id"` ID string `json:"_id"`
Name string `json:"name"` Name string `json:"name"`
Phone string `json:"phone"` Phone string `json:"phone"`
Email string `json:"email"` Email string `json:"email"`
Status string `json:"status"` Status string `json:"status"`
Role RoleShort `json:"role"` Role RoleShort `json:"role"`
Other string `json:"other"` RequireToChangePassword bool `json:"requireToChangePassword"`
CreatedAt time.Time `json:"createdAt"` Other interface{} `json:"other"`
UpdatedAt time.Time `json:"updatedAt"` Avatar interface{} `json:"avatar"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
// UserOtherBson ...
type UserOtherBson struct {
Supplier primitive.ObjectID `bson:"supplier"`
Inventories []primitive.ObjectID `bson:"inventories"`
IsPresident bool `bson:"isPresident"`
}
type UserOther struct {
Supplier string `json:"supplier"`
Inventories []string `json:"inventories"`
IsPresident bool `json:"isPresident"`
}
func (m User) GetUserOther() UserOther {
var (
userOtherBson UserOtherBson
)
bsonBytes, _ := bson.Marshal(m.Other)
bson.Unmarshal(bsonBytes, &userOtherBson)
return UserOther{
Supplier: userOtherBson.Supplier.Hex(),
Inventories: internal.ConvertObjectIDsToStrings(userOtherBson.Inventories),
IsPresident: userOtherBson.IsPresident,
}
} }
type ( type (
@ -22,5 +53,6 @@ type (
UserAll struct { UserAll struct {
List []User `json:"list"` List []User `json:"list"`
Total int64 `json:"total"` Total int64 `json:"total"`
Limit int64 `json:"limit"`
} }
) )

View File

@ -3,13 +3,14 @@ package permission
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"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"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"git.selly.red/Selly-Modules/usermngmt/database"
"git.selly.red/Selly-Modules/usermngmt/model"
) )
func findByID(ctx context.Context, id primitive.ObjectID) (model.DBPermission, error) { func findByID(ctx context.Context, id primitive.ObjectID) (model.DBPermission, error) {
@ -27,10 +28,6 @@ func create(ctx context.Context, doc model.DBPermission) error {
) )
_, err := col.InsertOne(ctx, doc) _, err := col.InsertOne(ctx, doc)
if err != nil { if err != nil {
logger.Error("usermngmt - Permission - InsertOne", logger.LogData{
"doc": doc,
"err": err.Error(),
})
return fmt.Errorf("error when create permission: %s", err.Error()) return fmt.Errorf("error when create permission: %s", err.Error())
} }
@ -43,17 +40,36 @@ func updateOneByCondition(ctx context.Context, cond interface{}, payload interfa
) )
_, err := col.UpdateOne(ctx, cond, payload) _, err := col.UpdateOne(ctx, cond, payload)
if err != nil { if err != nil {
logger.Error("usermngmt - Permission - UpdateOne", logger.LogData{
"cond": cond,
"payload": payload,
"err": err.Error(),
})
return fmt.Errorf("error when update permission: %s", err.Error()) return fmt.Errorf("error when update permission: %s", err.Error())
} }
return err return err
} }
func deleteOneByCondition(ctx context.Context, cond interface{}) error {
var (
col = database.GetPermissionCol()
)
_, err := col.DeleteOne(ctx, cond)
if err != nil {
return fmt.Errorf("error when delete permission: %s", err.Error())
}
return err
}
func findOneAndDelete(ctx context.Context, cond interface{}) (doc model.DBPermission, err error) {
var (
col = database.GetPermissionCol()
)
err = col.FindOneAndDelete(ctx, cond).Decode(&doc)
if err != nil {
return doc, fmt.Errorf("error when findOneAndDelete permission: %v", err)
}
return doc, nil
}
func findByCondition(ctx context.Context, cond interface{}, opts ...*options.FindOptions) (docs []model.DBPermission) { func findByCondition(ctx context.Context, cond interface{}, opts ...*options.FindOptions) (docs []model.DBPermission) {
var ( var (
col = database.GetPermissionCol() col = database.GetPermissionCol()
@ -62,20 +78,10 @@ func findByCondition(ctx context.Context, cond interface{}, opts ...*options.Fin
cursor, err := col.Find(ctx, cond, opts...) cursor, err := col.Find(ctx, cond, opts...)
if err != nil { if err != nil {
logger.Error("usermngmt - Permission - Find", logger.LogData{
"cond": cond,
"opts": opts,
"err": err.Error(),
})
return return
} }
defer cursor.Close(ctx) defer cursor.Close(ctx)
if err = cursor.All(ctx, &docs); err != nil { if err = cursor.All(ctx, &docs); err != nil {
logger.Error("usermngmt - Permission - Decode", logger.LogData{
"cond": cond,
"opts": opts,
"err": err.Error(),
})
return return
} }
return return
@ -88,10 +94,22 @@ func countByCondition(ctx context.Context, cond interface{}) int64 {
) )
total, err := col.CountDocuments(ctx, cond) total, err := col.CountDocuments(ctx, cond)
if err != nil { if err != nil {
logger.Error("usermngmt - Permission - CountDocuments", logger.LogData{ log.Println("permission - countByCondition", err)
"err": err.Error(),
"cond": cond,
})
} }
return total return total
} }
func isPermissionIDExisted(ctx context.Context, permissionID primitive.ObjectID) bool {
var (
col = database.GetPermissionCol()
)
// Find
cond := bson.M{
"_id": permissionID,
}
total, err := col.CountDocuments(ctx, cond)
if err != nil {
return false
}
return total != 0
}

View File

@ -5,32 +5,34 @@ import (
"errors" "errors"
"sync" "sync"
"github.com/Selly-Modules/mongodb" "git.selly.red/Selly-Modules/mongodb"
"github.com/Selly-Modules/usermngmt/internal"
"github.com/Selly-Modules/usermngmt/model"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"git.selly.red/Selly-Modules/usermngmt/internal"
"git.selly.red/Selly-Modules/usermngmt/model"
) )
// Create ... // Create ...
func Create(payload model.PermissionCreateOptions) error { func Create(payload model.PermissionCreateOptions) (result string, err error) {
var ( var (
ctx = context.Background() ctx = context.Background()
) )
// Validate payload // Validate payload
if err := payload.Validate(); err != nil { if err = payload.Validate(); err != nil {
return err return
} }
// New permission data from payload // New permission data from payload
doc := newPermission(payload) doc := newPermission(payload)
// Create permission // Create permission
if err := create(ctx, doc); err != nil { if err = create(ctx, doc); err != nil {
return err return
} }
return nil result = doc.ID.Hex()
return
} }
// newPermission ... // newPermission ...
@ -40,7 +42,7 @@ func newPermission(payload model.PermissionCreateOptions) model.DBPermission {
return model.DBPermission{ return model.DBPermission{
ID: mongodb.NewObjectID(), ID: mongodb.NewObjectID(),
Name: payload.Name, Name: payload.Name,
Code: internal.GenerateCode(payload.Name), Code: payload.Code,
RoleID: roleID, RoleID: roleID,
Desc: payload.Desc, Desc: payload.Desc,
CreatedAt: timeNow, CreatedAt: timeNow,
@ -59,10 +61,13 @@ func Update(permissionID string, payload model.PermissionUpdateOptions) error {
return err return err
} }
// Validate permissionID // Find permissionID exists or not
id, isValid := mongodb.NewIDFromString(permissionID) id, isValid := mongodb.NewIDFromString(permissionID)
if !isValid { if !isValid {
return errors.New("invalid permission id data") return errors.New(internal.ErrorInvalidPermission)
}
if !isPermissionIDExisted(ctx, id) {
return errors.New(internal.ErrorNotFoundPermission)
} }
// Setup condition // Setup condition
@ -75,7 +80,7 @@ func Update(permissionID string, payload model.PermissionUpdateOptions) error {
updateData := bson.M{ updateData := bson.M{
"$set": bson.M{ "$set": bson.M{
"name": payload.Name, "name": payload.Name,
"code": internal.GenerateCode(payload.Name), "code": payload.Code,
"roleId": roleID, "roleId": roleID,
"desc": payload.Desc, "desc": payload.Desc,
"updatedAt": internal.Now(), "updatedAt": internal.Now(),
@ -90,6 +95,48 @@ func Update(permissionID string, payload model.PermissionUpdateOptions) error {
return nil return nil
} }
// Delete ...
func Delete(permissionID string) error {
var (
ctx = context.Background()
)
// Find permissionID exists or not
id, isValid := mongodb.NewIDFromString(permissionID)
if !isValid {
return errors.New(internal.ErrorInvalidPermission)
}
if !isPermissionIDExisted(ctx, id) {
return errors.New(internal.ErrorNotFoundPermission)
}
// Delete
if err := deleteOneByCondition(ctx, bson.M{"_id": id}); err != nil {
return err
}
return nil
}
func FindByIDAndDelete(permissionID string) (*model.Permission, error) {
var (
ctx = context.Background()
)
// Find permissionID exists or not
id, isValid := mongodb.NewIDFromString(permissionID)
if !isValid {
return nil, errors.New(internal.ErrorInvalidPermission)
}
cond := bson.M{"_id": id}
doc, err := findOneAndDelete(ctx, cond)
if err != nil {
return nil, err
}
res := getResponse(doc)
return &res, nil
}
// All ... // All ...
func All(queryParams model.PermissionAllQuery) (r model.PermissionAll) { func All(queryParams model.PermissionAllQuery) (r model.PermissionAll) {
var ( var (
@ -98,13 +145,15 @@ func All(queryParams model.PermissionAllQuery) (r model.PermissionAll) {
cond = bson.M{} cond = bson.M{}
) )
query := model.CommonQuery{ query := model.CommonQuery{
Page: queryParams.Page, Page: queryParams.Page,
Limit: queryParams.Limit, Limit: queryParams.Limit,
Sort: bson.M{"createdAt": -1}, Sort: queryParams.Sort,
RoleID: queryParams.RoleID,
} }
// Assign condition // Assign condition
query.SetDefaultLimit() query.SetDefaultLimit()
query.AssignRoleID(cond)
wg.Add(1) wg.Add(1)
go func() { go func() {
@ -121,22 +170,27 @@ func All(queryParams model.PermissionAllQuery) (r model.PermissionAll) {
wg.Wait() wg.Wait()
r.Limit = query.Limit
return return
} }
func getResponseList(permissions []model.DBPermission) []model.Permission { func getResponseList(permissions []model.DBPermission) []model.Permission {
res := make([]model.Permission, 0) res := make([]model.Permission, 0)
for _, permission := range permissions { for _, permission := range permissions {
res = append(res, model.Permission{ res = append(res, getResponse(permission))
ID: permission.ID.Hex(),
Name: permission.Name,
Code: permission.Code,
RoleID: permission.RoleID.Hex(),
Desc: permission.Desc,
CreatedAt: permission.CreatedAt,
UpdatedAt: permission.UpdatedAt,
})
} }
return res return res
} }
func getResponse(permission model.DBPermission) model.Permission {
return model.Permission{
ID: permission.ID.Hex(),
Name: permission.Name,
Code: permission.Code,
RoleID: permission.RoleID.Hex(),
Desc: permission.Desc,
CreatedAt: permission.CreatedAt,
UpdatedAt: permission.UpdatedAt,
}
}

View File

@ -3,23 +3,15 @@ package role
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"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"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
)
func findByID(ctx context.Context, id primitive.ObjectID) (model.DBRole, error) { "git.selly.red/Selly-Modules/usermngmt/database"
var ( "git.selly.red/Selly-Modules/usermngmt/model"
doc model.DBRole )
col = database.GetRoleCol()
)
err := col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc)
return doc, err
}
func create(ctx context.Context, doc model.DBRole) error { func create(ctx context.Context, doc model.DBRole) error {
var ( var (
@ -27,10 +19,6 @@ func create(ctx context.Context, doc model.DBRole) error {
) )
_, err := col.InsertOne(ctx, doc) _, err := col.InsertOne(ctx, doc)
if err != nil { 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 fmt.Errorf("error when create role: %s", err.Error())
} }
@ -43,11 +31,6 @@ func updateOneByCondition(ctx context.Context, cond interface{}, payload interfa
) )
_, err := col.UpdateOne(ctx, cond, payload) _, err := col.UpdateOne(ctx, cond, payload)
if err != nil { 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 fmt.Errorf("error when update role: %s", err.Error())
} }
@ -62,20 +45,11 @@ func findByCondition(ctx context.Context, cond interface{}, opts ...*options.Fin
cursor, err := col.Find(ctx, cond, opts...) cursor, err := col.Find(ctx, cond, opts...)
if err != nil { if err != nil {
logger.Error("usermngmt - Role - Find", logger.LogData{ log.Printf("usermngmt.findByCondition - Role - Find cond: %v, opts: %v\n", cond, opts)
"cond": cond,
"opts": opts,
"err": err.Error(),
})
return return
} }
defer cursor.Close(ctx) defer cursor.Close(ctx)
if err = cursor.All(ctx, &docs); err != nil { if err = cursor.All(ctx, &docs); err != nil {
logger.Error("usermngmt - Role - Decode", logger.LogData{
"cond": cond,
"opts": opts,
"err": err.Error(),
})
return return
} }
return return
@ -88,10 +62,31 @@ func countByCondition(ctx context.Context, cond interface{}) int64 {
) )
total, err := col.CountDocuments(ctx, cond) total, err := col.CountDocuments(ctx, cond)
if err != nil { if err != nil {
logger.Error("usermngmt - Role - CountDocuments", logger.LogData{ log.Println("usermngmt.countByCondition - Role: ", err)
"err": err.Error(),
"cond": cond,
})
} }
return total return total
} }
func isRoleIDExisted(ctx context.Context, roleID primitive.ObjectID) bool {
var (
col = database.GetRoleCol()
)
// Find
cond := bson.M{
"_id": roleID,
}
total, err := col.CountDocuments(ctx, cond)
if err != nil {
return false
}
return total != 0
}
func findByID(ctx context.Context, id primitive.ObjectID) (model.DBRole, error) {
var (
doc model.DBRole
col = database.GetRoleCol()
)
err := col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc)
return doc, err
}

View File

@ -5,32 +5,33 @@ import (
"errors" "errors"
"sync" "sync"
"github.com/Selly-Modules/mongodb" "git.selly.red/Selly-Modules/mongodb"
"github.com/Selly-Modules/usermngmt/internal" "git.selly.red/Selly-Modules/usermngmt/internal"
"github.com/Selly-Modules/usermngmt/model" "git.selly.red/Selly-Modules/usermngmt/model"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
) )
// Create ... // Create ...
func Create(payload model.RoleCreateOptions) error { func Create(payload model.RoleCreateOptions) (result string, err error) {
var ( var (
ctx = context.Background() ctx = context.Background()
) )
// Validate payload // Validate payload
if err := payload.Validate(); err != nil { if err = payload.Validate(); err != nil {
return err return
} }
// New role data from payload // New role data from payload
doc := newRole(payload) doc := newRole(payload)
// Create role // Create role
if err := create(ctx, doc); err != nil { if err = create(ctx, doc); err != nil {
return err return
} }
return nil result = doc.ID.Hex()
return
} }
// newRole ... // newRole ...
@ -40,6 +41,8 @@ func newRole(payload model.RoleCreateOptions) model.DBRole {
ID: mongodb.NewObjectID(), ID: mongodb.NewObjectID(),
Name: payload.Name, Name: payload.Name,
Code: internal.GenerateCode(payload.Name), Code: internal.GenerateCode(payload.Name),
Level: payload.Level,
IsAdmin: payload.IsAdmin,
CreatedAt: timeNow, CreatedAt: timeNow,
UpdatedAt: timeNow, UpdatedAt: timeNow,
} }
@ -59,7 +62,12 @@ func Update(roleID string, payload model.RoleUpdateOptions) error {
// Validate roleID // Validate roleID
id, isValid := mongodb.NewIDFromString(roleID) id, isValid := mongodb.NewIDFromString(roleID)
if !isValid { if !isValid {
return errors.New("invalid role id data") return errors.New(internal.ErrorInvalidRole)
}
// Find roleID exists or not
if !isRoleIDExisted(ctx, id) {
return errors.New(internal.ErrorNotFoundRole)
} }
// Setup condition // Setup condition
@ -72,6 +80,8 @@ func Update(roleID string, payload model.RoleUpdateOptions) error {
"$set": bson.M{ "$set": bson.M{
"name": payload.Name, "name": payload.Name,
"code": internal.GenerateCode(payload.Name), "code": internal.GenerateCode(payload.Name),
"level": payload.Level,
"isAdmin": payload.IsAdmin,
"updatedAt": internal.Now(), "updatedAt": internal.Now(),
}, },
} }
@ -94,7 +104,7 @@ func All(queryParams model.RoleAllQuery) (r model.RoleAll) {
query := model.CommonQuery{ query := model.CommonQuery{
Page: queryParams.Page, Page: queryParams.Page,
Limit: queryParams.Limit, Limit: queryParams.Limit,
Sort: bson.M{"createdAt": -1}, Sort: queryParams.Sort,
} }
// Assign condition // Assign condition
@ -104,7 +114,11 @@ func All(queryParams model.RoleAllQuery) (r model.RoleAll) {
go func() { go func() {
defer wg.Done() defer wg.Done()
docs := findByCondition(ctx, cond, query.GetFindOptionsUsingPage()) docs := findByCondition(ctx, cond, query.GetFindOptionsUsingPage())
r.List = getResponseList(docs) res := make([]model.Role, 0)
for _, doc := range docs {
res = append(res, getResponse(doc))
}
r.List = res
}() }()
wg.Add(1) wg.Add(1)
@ -115,20 +129,40 @@ func All(queryParams model.RoleAllQuery) (r model.RoleAll) {
wg.Wait() wg.Wait()
r.Limit = query.Limit
return return
} }
func getResponseList(roles []model.DBRole) []model.Role { func getResponse(role model.DBRole) model.Role {
res := make([]model.Role, 0) return model.Role{
for _, role := range roles { ID: role.ID.Hex(),
res = append(res, model.Role{ Name: role.Name,
ID: role.ID.Hex(), Code: role.Code,
Name: role.Name, Level: role.Level,
Code: role.Code, IsAdmin: role.IsAdmin,
CreatedAt: role.CreatedAt, CreatedAt: role.CreatedAt,
UpdatedAt: role.UpdatedAt, UpdatedAt: role.UpdatedAt,
}) }
}
// FindRole ...
func FindRole(roleID string) (r model.Role, err error) {
var (
ctx = context.Background()
)
// Find role exists or not
id, isValid := mongodb.NewIDFromString(roleID)
if !isValid {
err = errors.New(internal.ErrorInvalidRole)
return
}
role, _ := findByID(ctx, id)
if role.ID.IsZero() {
err = errors.New(internal.ErrorNotFoundRole)
return
} }
return res r = getResponse(role)
return
} }

View File

@ -3,42 +3,49 @@ package user
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"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"
"go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"git.selly.red/Selly-Modules/usermngmt/database"
"git.selly.red/Selly-Modules/usermngmt/model"
) )
func isPhoneNumberOrEmailExisted(ctx context.Context, phone, email string) bool { func isPhoneNumberExisted(ctx context.Context, phone string) bool {
var ( var (
col = database.GetUserCol() col = database.GetUserCol()
) )
// Find // Find
cond := bson.M{ cond := bson.M{
"$or": []bson.M{ "phone": phone,
{ "deleted": false,
"phone": phone,
},
{
"email": email,
},
},
} }
total, err := col.CountDocuments(ctx, cond) total, err := col.CountDocuments(ctx, cond)
if err != nil { if err != nil {
logger.Error("usermngmt - User - CountDocuments", logger.LogData{
"condition": cond,
"err": err.Error(),
})
return true return true
} }
return total != 0 return total != 0
} }
func isRoleIDExisted(ctx context.Context, roleID primitive.ObjectID) bool { func isEmailExisted(ctx context.Context, email string) bool {
var (
col = database.GetUserCol()
)
// Find
cond := bson.M{
"email": email,
"deleted": false,
}
total, err := col.CountDocuments(ctx, cond)
if err != nil {
return true
}
return total != 0
}
func isRoleExisted(ctx context.Context, roleID primitive.ObjectID) bool {
var ( var (
col = database.GetRoleCol() col = database.GetRoleCol()
) )
@ -48,11 +55,7 @@ func isRoleIDExisted(ctx context.Context, roleID primitive.ObjectID) bool {
} }
total, err := col.CountDocuments(ctx, cond) total, err := col.CountDocuments(ctx, cond)
if err != nil { if err != nil {
logger.Error("usermngmt - Role - CountDocuments", logger.LogData{ log.Println("isRoleExisted - count: ", err)
"condition": cond,
"err": err.Error(),
})
return false
} }
return total != 0 return total != 0
} }
@ -66,16 +69,46 @@ func roleFindByID(ctx context.Context, id primitive.ObjectID) (model.DBRole, err
return doc, err return doc, err
} }
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 {
return
}
defer cursor.Close(ctx)
if err = cursor.All(ctx, &docs); err != nil {
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 {
return
}
defer cursor.Close(ctx)
if err = cursor.All(ctx, &docs); err != nil {
return
}
return
}
func create(ctx context.Context, doc model.DBUser) error { func create(ctx context.Context, doc model.DBUser) error {
var ( var (
col = database.GetUserCol() col = database.GetUserCol()
) )
_, err := col.InsertOne(ctx, doc) _, err := col.InsertOne(ctx, doc)
if err != nil { if err != nil {
logger.Error("usermngmt - User - InsertOne", logger.LogData{
"doc": doc,
"err": err.Error(),
})
return fmt.Errorf("error when create user: %s", err.Error()) return fmt.Errorf("error when create user: %s", err.Error())
} }
@ -88,11 +121,6 @@ func updateOneByCondition(ctx context.Context, cond interface{}, payload interfa
) )
_, err := col.UpdateOne(ctx, cond, payload) _, err := col.UpdateOne(ctx, cond, payload)
if err != nil { if err != nil {
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 fmt.Errorf("error when update user: %s", err.Error())
} }
@ -105,11 +133,6 @@ func updateManyByCondition(ctx context.Context, cond interface{}, payload interf
) )
_, err := col.UpdateMany(ctx, cond, payload) _, err := col.UpdateMany(ctx, cond, payload)
if err != nil { if err != nil {
logger.Error("usermngmt - User - UpdateMany", logger.LogData{
"cond": cond,
"payload": payload,
"err": err.Error(),
})
return fmt.Errorf("error when update user: %s", err.Error()) return fmt.Errorf("error when update user: %s", err.Error())
} }
@ -121,7 +144,7 @@ func findByID(ctx context.Context, id primitive.ObjectID) (model.DBUser, error)
doc model.DBUser doc model.DBUser
col = database.GetUserCol() col = database.GetUserCol()
) )
err := col.FindOne(ctx, bson.M{"_id": id}).Decode(&doc) err := col.FindOne(ctx, bson.M{"_id": id, "deleted": false}).Decode(&doc)
return doc, err return doc, err
} }
@ -133,20 +156,10 @@ func findByCondition(ctx context.Context, cond interface{}, opts ...*options.Fin
cursor, err := col.Find(ctx, cond, opts...) cursor, err := col.Find(ctx, cond, opts...)
if err != nil { if err != nil {
logger.Error("usermngmt - User - Find", logger.LogData{
"cond": cond,
"opts": opts,
"err": err.Error(),
})
return return
} }
defer cursor.Close(ctx) defer cursor.Close(ctx)
if err = cursor.All(ctx, &docs); err != nil { if err = cursor.All(ctx, &docs); err != nil {
logger.Error("usermngmt - User - Decode", logger.LogData{
"cond": cond,
"opts": opts,
"err": err.Error(),
})
return return
} }
return return
@ -159,10 +172,7 @@ func countByCondition(ctx context.Context, cond interface{}) int64 {
) )
total, err := col.CountDocuments(ctx, cond) total, err := col.CountDocuments(ctx, cond)
if err != nil { if err != nil {
logger.Error("usermngmt - Count", logger.LogData{ log.Println("user - countByCondition err:", err)
"err": err.Error(),
"cond": cond,
})
} }
return total return total
} }

View File

@ -5,69 +5,149 @@ import (
"errors" "errors"
"sync" "sync"
"github.com/Selly-Modules/logger" "git.selly.red/Selly-Modules/mongodb"
"github.com/Selly-Modules/mongodb" "github.com/thoas/go-funk"
"github.com/Selly-Modules/usermngmt/internal"
"github.com/Selly-Modules/usermngmt/model"
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"git.selly.red/Selly-Modules/usermngmt/cache"
"git.selly.red/Selly-Modules/usermngmt/config"
"git.selly.red/Selly-Modules/usermngmt/internal"
"git.selly.red/Selly-Modules/usermngmt/model"
) )
// Create ... // Create ...
func Create(payload model.UserCreateOptions) error { func Create(payload model.UserCreateOptions) (result string, err error) {
var ( var (
ctx = context.Background() ctx = context.Background()
) )
// Validate payload // Validate payload
if err := payload.Validate(); err != nil { if err = payload.Validate(); err != nil {
return err return
} }
// Find roleID exists or not // Find roleID exists or not
roleID, isValid := mongodb.NewIDFromString(payload.RoleID) roleID, isValid := mongodb.NewIDFromString(payload.RoleID)
if !isValid { if !isValid {
return errors.New("invalid role id data") err = errors.New(internal.ErrorInvalidRole)
return
} }
if !isRoleIDExisted(ctx, roleID) { if !isRoleExisted(ctx, roleID) {
return errors.New("role id does not exist") err = errors.New(internal.ErrorNotFoundRole)
return
} }
// Find phone number,email exists or not // Find phone number,email exists or not
if isPhoneNumberOrEmailExisted(ctx, payload.Phone, payload.Email) { if config.GetInstance().PhoneNumberIsUnique {
return errors.New("phone number or email already existed") if isPhoneNumberExisted(ctx, payload.Phone) {
err = errors.New(internal.ErrorAlreadyExistedPhoneNumber)
return
}
}
if config.GetInstance().EmailIsUnique {
if isEmailExisted(ctx, payload.Email) {
err = errors.New(internal.ErrorAlreadyExistedEmail)
return
}
} }
// New user data from payload // New user data from payload
doc, err := newUser(payload) doc := newUser(payload)
if err != nil {
return err
}
// Create user // Create user
if err = create(ctx, doc); err != nil { if err = create(ctx, doc); err != nil {
return err return
} }
return nil result = doc.ID.Hex()
return
} }
// newUser ... // newUser ...
func newUser(payload model.UserCreateOptions) (result model.DBUser, err error) { func newUser(payload model.UserCreateOptions) model.DBUser {
timeNow := internal.Now() timeNow := internal.Now()
roleID, _ := mongodb.NewIDFromString(payload.RoleID) roleID, _ := mongodb.NewIDFromString(payload.RoleID)
return model.DBUser{ return model.DBUser{
ID: mongodb.NewObjectID(), ID: mongodb.NewObjectID(),
Name: payload.Name, Name: payload.Name,
SearchString: internal.GetSearchString(payload.Name, payload.Phone, payload.Email), SearchString: internal.GetSearchString(payload.Name, payload.Phone, payload.Email),
Phone: payload.Phone, Phone: payload.Phone,
Email: payload.Email, Email: payload.Email,
HashedPassword: internal.HashPassword(payload.Password), HashedPassword: internal.HashPassword(payload.Password),
Status: payload.Status, RequireToChangePassword: payload.RequireToChangePassword,
RoleID: roleID, Status: payload.Status,
Other: payload.Other, RoleID: roleID,
CreatedAt: timeNow, Other: payload.Other,
UpdatedAt: timeNow, Avatar: payload.Avatar,
}, nil CreatedAt: timeNow,
UpdatedAt: timeNow,
}
}
// FindUser ...
func FindUser(userID string) (r model.User, err error) {
var (
ctx = context.Background()
)
// Find user exists or not
id, isValid := mongodb.NewIDFromString(userID)
if !isValid {
err = errors.New(internal.ErrorInvalidUser)
return
}
user, _ := findByID(ctx, id)
if user.ID.IsZero() {
err = errors.New(internal.ErrorNotFoundUser)
return
}
r = getResponse(ctx, user)
return
}
// FindUserByEmail ...
func FindUserByEmail(email string) (r model.User, err error) {
var (
ctx = context.Background()
)
// Find user exists or not
if email == "" {
err = errors.New(internal.ErrorInvalidEmail)
return
}
user, _ := findOneByCondition(ctx, bson.M{"email": email})
if user.ID.IsZero() {
err = errors.New(internal.ErrorNotFoundUser)
return
}
r = getResponse(ctx, user)
return
}
// GetHashedPassword ...
func GetHashedPassword(userID string) (result string, err error) {
var (
ctx = context.Background()
)
// Find user exists or not
id, isValid := mongodb.NewIDFromString(userID)
if !isValid {
err = errors.New(internal.ErrorInvalidUser)
return
}
user, _ := findByID(ctx, id)
if user.ID.IsZero() {
err = errors.New(internal.ErrorNotFoundUser)
return
}
result = user.HashedPassword
return
} }
// All ... // All ...
@ -77,13 +157,18 @@ func All(queryParams model.UserAllQuery) (r model.UserAll) {
wg sync.WaitGroup wg sync.WaitGroup
cond = bson.M{} cond = bson.M{}
) )
if queryParams.Cond != nil {
cond = queryParams.Cond
}
query := model.CommonQuery{ query := model.CommonQuery{
Page: queryParams.Page, Page: queryParams.Page,
Limit: queryParams.Limit, Limit: queryParams.Limit,
Keyword: queryParams.Keyword, Keyword: queryParams.Keyword,
RoleID: queryParams.RoleID, RoleID: queryParams.RoleID,
Status: queryParams.Status, Status: queryParams.Status,
Sort: bson.M{"createdAt": -1}, Sort: queryParams.Sort,
Other: queryParams.Other,
} }
// Assign condition // Assign condition
@ -91,6 +176,9 @@ func All(queryParams model.UserAllQuery) (r model.UserAll) {
query.AssignKeyword(cond) query.AssignKeyword(cond)
query.AssignRoleID(cond) query.AssignRoleID(cond)
query.AssignStatus(cond) query.AssignStatus(cond)
query.AssignDeleted(cond)
query.AssignOther(cond)
cond["deleted"] = false
wg.Add(1) wg.Add(1)
go func() { go func() {
@ -111,9 +199,103 @@ func All(queryParams model.UserAllQuery) (r model.UserAll) {
wg.Wait() wg.Wait()
r.Limit = query.Limit
return return
} }
// GetUsersByPermission ...
func GetUsersByPermission(queryParams model.UserByPermissionQuery) (r model.UserAll) {
var (
ctx = context.Background()
wg sync.WaitGroup
cond = bson.M{}
roles = make([]primitive.ObjectID, 0)
)
// Validate query
if err := queryParams.Validate(); err != nil {
return
}
if queryParams.Cond != nil {
cond = queryParams.Cond
}
// Get role by permission
permissions := permissionFindByCondition(ctx, bson.M{"code": queryParams.Permission})
for _, value := range permissions {
roles = append(roles, value.RoleID)
}
// Get admin role
adminRoles := roleFindByCondition(ctx, bson.M{"isAdmin": true})
for _, value := range adminRoles {
roles = append(roles, value.ID)
}
if len(roles) < 0 {
return
}
query := model.CommonQuery{
Page: queryParams.Page,
Limit: queryParams.Limit,
Keyword: queryParams.Keyword,
Status: queryParams.Status,
Sort: queryParams.Sort,
Other: queryParams.Other,
RoleIDs: roles,
}
// Assign condition
query.SetDefaultLimit()
query.AssignKeyword(cond)
query.AssignRoleIDs(cond)
query.AssignStatus(cond)
query.AssignDeleted(cond)
query.AssignOther(cond)
cond["deleted"] = false
wg.Add(1)
go func() {
defer wg.Done()
docs := findByCondition(ctx, cond, query.GetFindOptionsUsingPage())
res := make([]model.User, 0)
for _, doc := range docs {
res = append(res, getResponse(ctx, doc))
}
r.List = res
}()
wg.Add(1)
go func() {
defer wg.Done()
r.Total = countByCondition(ctx, cond)
}()
wg.Wait()
r.Limit = query.Limit
return
}
// Count ...
func Count(queryParams model.UserCountQuery) int64 {
var (
ctx = context.Background()
cond = bson.M{}
)
query := model.CommonQuery{
RoleID: queryParams.RoleID,
Other: queryParams.Other,
}
// Assign condition
query.AssignRoleID(cond)
query.AssignOther(cond)
return countByCondition(ctx, cond)
}
func getResponse(ctx context.Context, user model.DBUser) model.User { func getResponse(ctx context.Context, user model.DBUser) model.User {
roleRaw, _ := roleFindByID(ctx, user.RoleID) roleRaw, _ := roleFindByID(ctx, user.RoleID)
return model.User{ return model.User{
@ -125,11 +307,14 @@ func getResponse(ctx context.Context, user model.DBUser) model.User {
Role: model.RoleShort{ Role: model.RoleShort{
ID: roleRaw.ID.Hex(), ID: roleRaw.ID.Hex(),
Name: roleRaw.Name, Name: roleRaw.Name,
Level: roleRaw.Level,
IsAdmin: roleRaw.IsAdmin, IsAdmin: roleRaw.IsAdmin,
}, },
Other: user.Other, RequireToChangePassword: user.RequireToChangePassword,
CreatedAt: user.CreatedAt, Avatar: user.Avatar,
UpdatedAt: user.UpdatedAt, Other: user.Other,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
} }
} }
@ -147,38 +332,62 @@ func UpdateByUserID(userID string, payload model.UserUpdateOptions) error {
// Find roleID exists or not // Find roleID exists or not
roleID, isValid := mongodb.NewIDFromString(payload.RoleID) roleID, isValid := mongodb.NewIDFromString(payload.RoleID)
if !isValid { if !isValid {
return errors.New("invalid role id data") return errors.New(internal.ErrorInvalidRole)
} }
if !isRoleIDExisted(ctx, roleID) { if !isRoleExisted(ctx, roleID) {
return errors.New("role id does not exist") return errors.New(internal.ErrorNotFoundRole)
}
// Find user exists or not
id, isValid := mongodb.NewIDFromString(userID)
if !isValid {
return errors.New(internal.ErrorInvalidUser)
}
user, _ := findByID(ctx, id)
if user.ID.IsZero() {
return errors.New(internal.ErrorNotFoundUser)
} }
// Find phone number,email exists or not // Find phone number,email exists or not
if isPhoneNumberOrEmailExisted(ctx, payload.Phone, payload.Email) { if config.GetInstance().PhoneNumberIsUnique {
return errors.New("phone number or email already existed") if user.Phone != payload.Phone {
if isPhoneNumberExisted(ctx, payload.Phone) {
return errors.New(internal.ErrorAlreadyExistedPhoneNumber)
}
}
}
if config.GetInstance().EmailIsUnique {
if user.Email != payload.Email {
if isEmailExisted(ctx, payload.Email) {
return errors.New(internal.ErrorAlreadyExistedEmail)
}
}
} }
// Setup condition // Setup condition
id, _ := mongodb.NewIDFromString(userID)
cond := bson.M{ cond := bson.M{
"_id": id, "_id": id,
} }
// Setup update data // Setup Set operator
updateData := bson.M{ setOperator := bson.M{
"$set": bson.M{ "name": payload.Name,
"name": payload.Name, "searchString": internal.GetSearchString(payload.Name, payload.Phone, payload.Email),
"searchString": internal.GetSearchString(payload.Name, payload.Phone, payload.Email), "phone": payload.Phone,
"phone": payload.Phone, "email": payload.Email,
"email": payload.Email, "roleId": roleID,
"roleId": roleID, "updatedAt": internal.Now(),
"other": payload.Other, }
"updatedAt": internal.Now(), if len(payload.Other) > 0 {
}, for key, value := range payload.Other {
setOperator["other."+key] = value
}
} }
// Update // Update
if err := updateOneByCondition(ctx, cond, updateData); err != nil { if err := updateOneByCondition(ctx, cond, bson.M{
"$set": setOperator,
}); err != nil {
return err return err
} }
@ -199,30 +408,101 @@ func ChangeUserPassword(userID string, opt model.ChangePasswordOptions) error {
// Validate userID // Validate userID
if _, isValid := mongodb.NewIDFromString(userID); !isValid { if _, isValid := mongodb.NewIDFromString(userID); !isValid {
logger.Error("usermngmt - ChangePassword: invalid userID data", logger.LogData{ return errors.New(internal.ErrorInvalidUser)
"payload": opt,
"userID": userID,
})
return errors.New("invalid user id data")
} }
// Find user // Find user
id, _ := mongodb.NewIDFromString(userID) id, _ := mongodb.NewIDFromString(userID)
user, _ := findByID(ctx, id) user, _ := findByID(ctx, id)
if user.ID.IsZero() { if user.ID.IsZero() {
return errors.New("user not found") return errors.New(internal.ErrorNotFoundUser)
} }
// Check old password // Check old password
if isValid := internal.CheckPasswordHash(opt.OldPassword, user.HashedPassword); !isValid { if isValid := internal.CheckPasswordHash(opt.OldPassword, user.HashedPassword); !isValid {
return errors.New("the password is incorrect") return errors.New(internal.ErrorIncorrectPassword)
} }
// Update password // Update password
if err = updateOneByCondition(ctx, bson.M{"_id": user.ID}, bson.M{ if err = updateOneByCondition(ctx, bson.M{"_id": user.ID}, bson.M{
"$set": bson.M{ "$set": bson.M{
"hashedPassword": internal.HashPassword(opt.NewPassword), "hashedPassword": internal.HashPassword(opt.NewPassword),
"updatedAt": internal.Now(), "requireToChangePassword": false,
"updatedAt": internal.Now(),
},
}); err != nil {
return err
}
return nil
}
// ResetUserPassword ...
func ResetUserPassword(userID string, password string) error {
var (
ctx = context.Background()
)
// Validate Password
if password == "" {
return errors.New(internal.ErrorInvalidPassword)
}
// Validate userID
if _, isValid := mongodb.NewIDFromString(userID); !isValid {
return errors.New(internal.ErrorInvalidUser)
}
// Find user
id, _ := mongodb.NewIDFromString(userID)
user, _ := findByID(ctx, id)
if user.ID.IsZero() {
return errors.New(internal.ErrorNotFoundUser)
}
// Update password
if err := updateOneByCondition(ctx, bson.M{"_id": user.ID}, bson.M{
"$set": bson.M{
"hashedPassword": internal.HashPassword(password),
"requireToChangePassword": false,
"updatedAt": internal.Now(),
},
}); err != nil {
return err
}
return nil
}
// ResetAndRequireToChangeUserPassword ...
func ResetAndRequireToChangeUserPassword(userID string, password string) error {
var (
ctx = context.Background()
)
// Validate Password
if password == "" {
return errors.New(internal.ErrorInvalidPassword)
}
// Validate userID
if _, isValid := mongodb.NewIDFromString(userID); !isValid {
return errors.New(internal.ErrorInvalidUser)
}
// Find user
id, _ := mongodb.NewIDFromString(userID)
user, _ := findByID(ctx, id)
if user.ID.IsZero() {
return errors.New(internal.ErrorNotFoundUser)
}
// Update password
if err := updateOneByCondition(ctx, bson.M{"_id": user.ID}, bson.M{
"$set": bson.M{
"hashedPassword": internal.HashPassword(password),
"requireToChangePassword": true,
"updatedAt": internal.Now(),
}, },
}); err != nil { }); err != nil {
return err return err
@ -240,7 +520,10 @@ func ChangeUserStatus(userID, newStatus string) error {
// Validate userID // Validate userID
id, isValid := mongodb.NewIDFromString(userID) id, isValid := mongodb.NewIDFromString(userID)
if !isValid { if !isValid {
return errors.New("invalid user id data") return errors.New(internal.ErrorInvalidUser)
}
if user, _ := findByID(ctx, id); user.ID.IsZero() {
return errors.New(internal.ErrorNotFoundUser)
} }
// Update status // Update status
@ -265,7 +548,10 @@ func ChangeAllUsersStatus(roleID, status string) error {
// Validate roleID // Validate roleID
id, isValid := mongodb.NewIDFromString(roleID) id, isValid := mongodb.NewIDFromString(roleID)
if !isValid { if !isValid {
return errors.New("invalid role id data") return errors.New(internal.ErrorInvalidRole)
}
if !isRoleExisted(ctx, id) {
return errors.New(internal.ErrorNotFoundRole)
} }
// Setup condition // Setup condition
@ -292,30 +578,160 @@ func ChangeAllUsersStatus(roleID, status string) error {
// LoginWithEmailAndPassword ... // LoginWithEmailAndPassword ...
func LoginWithEmailAndPassword(email, password string) (result model.User, err error) { func LoginWithEmailAndPassword(email, password string) (result model.User, err error) {
var ( var (
ctx = context.Background() ctx = context.Background()
numOfLoginFail int
) )
k := cache.KeyLoginFailedTimes + email
// process block if reach maximum of login failed
if ok := cache.GetJSON(k, &numOfLoginFail); ok && numOfLoginFail >= config.MaximumLoginFailedTime {
return model.User{}, errors.New(internal.ErrorExceedMaximumLoginFail)
}
// Validate email, password // Validate email, password
if email == "" || password == "" { if email == "" {
err = errors.New("email or password cannot be empty") err = errors.New(internal.ErrorInvalidLogin)
return
}
if password == "" {
err = errors.New(internal.ErrorInvalidLogin)
return return
} }
// Find user // Find user
user, _ := findOneByCondition(ctx, bson.M{ user, _ := findOneByCondition(ctx, bson.M{
"email": email, "email": email,
"deleted": false,
}) })
if user.ID.IsZero() { if user.ID.IsZero() {
err = errors.New("user not found") err = errors.New(internal.ErrorInvalidLogin)
return return
} }
// Check Password // Check Password
if !internal.CheckPasswordHash(password, user.HashedPassword) { if !internal.CheckPasswordHash(password, user.HashedPassword) {
err = errors.New("the password is incorrect") err = errors.New(internal.ErrorInvalidLogin)
cache.SetKeyValue(k, numOfLoginFail+1, config.LoginFailedBlockedDuration)
return return
} }
result = getResponse(ctx, user) result = getResponse(ctx, user)
return return
} }
// HasPermission ...
func HasPermission(userID, permission string) (result bool) {
var (
ctx = context.Background()
)
// Validate userID, permission
if userID == "" || permission == "" {
return
}
id, isValid := mongodb.NewIDFromString(userID)
if !isValid {
return
}
// Find user
user, _ := findByID(ctx, id)
if user.ID.IsZero() {
return
}
return checkUserHasPermissionFromCache(user.RoleID, permission)
}
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 true
}
return false
}
// UpdateAvatar ...
func UpdateAvatar(userID string, avatar interface{}) error {
var (
ctx = context.Background()
)
if avatar == nil {
return errors.New(internal.ErrorInvalidAvatar)
}
// Find user exists or not
id, isValid := mongodb.NewIDFromString(userID)
if !isValid {
return errors.New(internal.ErrorInvalidUser)
}
user, _ := findByID(ctx, id)
if user.ID.IsZero() {
return errors.New(internal.ErrorNotFoundUser)
}
// Setup condition
cond := bson.M{
"_id": id,
}
// Setup update data
updateData := bson.M{
"$set": bson.M{
"avatar": avatar,
"updatedAt": internal.Now(),
},
}
// Update
if err := updateOneByCondition(ctx, cond, updateData); err != nil {
return err
}
return nil
}
// Delete ...
func Delete(userID string) error {
var (
ctx = context.Background()
)
// Find user exists or not
id, isValid := mongodb.NewIDFromString(userID)
if !isValid {
return errors.New(internal.ErrorInvalidUser)
}
user, _ := findByID(ctx, id)
if user.ID.IsZero() {
return errors.New(internal.ErrorNotFoundUser)
}
// Setup condition
cond := bson.M{
"_id": id,
}
// Setup update data
updateData := bson.M{
"$set": bson.M{
"deleted": true,
"updatedAt": internal.Now(),
},
}
// Update
if err := updateOneByCondition(ctx, cond, updateData); err != nil {
return err
}
return nil
}

View File

@ -4,22 +4,35 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/Selly-Modules/mongodb" "git.selly.red/Selly-Modules/mongodb"
"github.com/Selly-Modules/usermngmt/database"
"github.com/Selly-Modules/usermngmt/internal" "git.selly.red/Selly-Modules/usermngmt/cache"
configMoudle "git.selly.red/Selly-Modules/usermngmt/config"
"git.selly.red/Selly-Modules/usermngmt/database"
"git.selly.red/Selly-Modules/usermngmt/internal"
) )
// MongoDBConfig ... // RedisConfig ...
type MongoDBConfig struct { type RedisConfig struct {
Host, User, Password, DBName, Mechanism, Source string URI, Password string
} }
// Config ... // Config ...
type Config struct { type Config struct {
// MongoDB config, for save documents // MongoDB config, for save documents
MongoDB MongoDBConfig MongoDB mongodb.Config
// Redis
Redis RedisConfig
// Table prefix, each service has its own prefix // Table prefix, each service has its own prefix
TablePrefix string TablePrefix string
// Email is unique
EmailIsUnique bool
// phone number is unique
PhoneNumberIsUnique bool
} }
// Service ... // Service ...
@ -41,14 +54,7 @@ func Init(config Config) (*Service, error) {
} }
// Connect MongoDB // Connect MongoDB
db, err := mongodb.Connect( db, err := mongodb.Connect(config.MongoDB)
config.MongoDB.Host,
config.MongoDB.User,
config.MongoDB.Password,
config.MongoDB.DBName,
config.MongoDB.Mechanism,
config.MongoDB.Source,
)
if err != nil { if err != nil {
fmt.Println("Cannot init module User MANAGEMENT", err) fmt.Println("Cannot init module User MANAGEMENT", err)
return nil, err return nil, err
@ -57,6 +63,15 @@ func Init(config Config) (*Service, error) {
// Set database // Set database
database.Set(db, config.TablePrefix) database.Set(db, config.TablePrefix)
// Set config module
configMoudle.Set(&configMoudle.Configuration{
EmailIsUnique: config.EmailIsUnique,
PhoneNumberIsUnique: config.PhoneNumberIsUnique,
})
// Init cache
cache.Init(config.Redis.URI, config.Redis.Password)
s = &Service{ s = &Service{
config: config, config: config,
} }
@ -68,3 +83,13 @@ func Init(config Config) (*Service, error) {
func GetInstance() *Service { func GetInstance() *Service {
return s return s
} }
// GetConnectOptions ...
func GetConnectOptions(Host, DBName string) mongodb.Config {
return mongodb.Config{
Host: Host,
DBName: DBName,
Standalone: &mongodb.ConnectStandaloneOpts{},
TLS: &mongodb.ConnectTLSOpts{},
}
}