From bfb263ca508582fa6839b78b973be65c9f9db8b7 Mon Sep 17 00:00:00 2001 From: Hoang Date: Mon, 8 Nov 2021 11:53:03 +0700 Subject: [PATCH 1/4] add createMethod --- .gitignore | 2 + action_create.go | 82 +++++++++++++++++++++ constant.go | 8 +++ go.mod | 44 ++++++++++++ go.sum | 184 +++++++++++++++++++++++++++++++++++++++++++++++ helper.go | 42 +++++++++++ model.go | 21 ++++++ time.go | 20 ++++++ usermngmt.go | 63 ++++++++++++++++ validate.go | 59 +++++++++++++++ 10 files changed, 525 insertions(+) create mode 100644 action_create.go create mode 100644 constant.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 helper.go create mode 100644 model.go create mode 100644 time.go create mode 100644 usermngmt.go create mode 100644 validate.go diff --git a/.gitignore b/.gitignore index 66fd13c..398baf2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +.idea diff --git a/action_create.go b/action_create.go new file mode 100644 index 0000000..4f3e743 --- /dev/null +++ b/action_create.go @@ -0,0 +1,82 @@ +package usermngmt + +import ( + "context" + "errors" + "fmt" + + "github.com/Selly-Modules/logger" + "github.com/Selly-Modules/mongodb" +) + +// CreateOptions ... +type CreateOptions struct { + Name string + Phone string + Email string + HashPassword string + Status string + RoleID string + Other string +} + +// Create ... +func (s Service) Create(payload CreateOptions) error { + var ( + col = s.getUserCollection() + ctx = context.Background() + ) + + // Validate payload + err := payload.validate() + if err != nil { + return err + } + + // New user data from payload + userData, err := payload.newUser() + if err != nil { + return err + } + + // Find phone,email exists or not + if s.haveNameOrPhoneExisted(ctx, userData.Phone, userData.Email) { + return errors.New("have name or phone existed") + } + + // Create device + _, err = col.InsertOne(ctx, userData) + if err != nil { + logger.Error("usermngmt - Create ", logger.LogData{ + "doc": userData, + "err": err.Error(), + }) + return fmt.Errorf("error when create user: %s", err.Error()) + } + + return nil +} + +func (payload CreateOptions) newUser() (result User, err error) { + timeNow := now() + + // New RoleID from string + roleID, isValid := mongodb.NewIDFromString(payload.RoleID) + if !isValid { + err = errors.New("invalid roleID") + return + } + + return User{ + ID: mongodb.NewObjectID(), + Name: payload.Name, + Phone: payload.Phone, + Email: payload.Email, + HashPassword: payload.HashPassword, + Status: payload.Status, + RoleID: roleID, + Other: payload.Other, + CreatedAt: timeNow, + UpdatedAt: timeNow, + }, nil +} diff --git a/constant.go b/constant.go new file mode 100644 index 0000000..d9d6e28 --- /dev/null +++ b/constant.go @@ -0,0 +1,8 @@ +package usermngmt + +// Constant ... +const ( + tableUser = "users" + + timezoneHCM = "Asia/Ho_Chi_Minh" +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8091cd4 --- /dev/null +++ b/go.mod @@ -0,0 +1,44 @@ +module github.com/selly-Modules/usermngmt + +go 1.17 + +require ( + github.com/Selly-Modules/logger v0.0.0-20210809034923-140a51f39ec9 + github.com/Selly-Modules/mongodb v0.0.0-20211013094205-a8ab24a96c4c + go.mongodb.org/mongo-driver v1.7.4 +) + +require ( + github.com/armon/go-radix v1.0.0 // indirect + github.com/elastic/go-licenser v0.3.1 // indirect + github.com/elastic/go-sysinfo v1.1.1 // indirect + github.com/elastic/go-windows v1.0.0 // 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/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0 // indirect + github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.0.2 // indirect + github.com/xdg-go/stringprep v1.0.2 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + go.elastic.co/apm v1.13.1 // indirect + go.elastic.co/apm/module/apmzap v1.13.1 // indirect + go.elastic.co/fastjson v1.1.0 // 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/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 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7fdc319 --- /dev/null +++ b/go.sum @@ -0,0 +1,184 @@ +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/Selly-Modules/logger v0.0.0-20210809034923-140a51f39ec9/go.mod h1:RWhSQ3F01an8KD00VjzRBZOMcE5eV2Cy0/l4ZkeieyU= +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.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/elastic/go-licenser v0.3.1 h1:RmRukU/JUmts+rpexAw0Fvt2ly7VVu6mw8z4HrEzObU= +github.com/elastic/go-licenser v0.3.1/go.mod h1:D8eNQk70FOCVBl3smCGQt/lv7meBeQno2eI1S5apiHQ= +github.com/elastic/go-sysinfo v1.1.1 h1:ZVlaLDyhVkDfjwPGU55CQRCRolNpc7P0BbyhhQZQmMI= +github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= +github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= +github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +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.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= +github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= +github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= +github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= +github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= +github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= +github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= +github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= +github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= +github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= +github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= +github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= +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/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +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/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= +github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +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/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +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.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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.2.2/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.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +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.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +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/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/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/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= +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/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.elastic.co/apm v1.13.1 h1:ICIcUcQOImg/bve9mQVyLCvm1cSUZ1afdwK6ACnxczU= +go.elastic.co/apm v1.13.1/go.mod h1:dylGv2HKR0tiCV+wliJz1KHtDyuD8SPe69oV7VyK6WY= +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.4 h1:sllcioag8Mec0LYkftYWq+cKNPIR4Kqq3iv9ZXY0g/E= +go.mongodb.org/mongo-driver v1.7.4/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= +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-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-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/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +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/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-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/sync v0.0.0-20181221193216-37e7f081c4d4/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-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/sys v0.0.0-20180905080454-ebe1bf3edb33/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-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-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-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +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/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-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-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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +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-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= +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/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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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= +howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= +howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= diff --git a/helper.go b/helper.go new file mode 100644 index 0000000..396baca --- /dev/null +++ b/helper.go @@ -0,0 +1,42 @@ +package usermngmt + +import ( + "context" + "fmt" + + "github.com/Selly-Modules/logger" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +// getUserCollection ... +func (s Service) getUserCollection() *mongo.Collection { + return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableUser)) +} + +func (s Service) haveNameOrPhoneExisted(ctx context.Context, phone, email string) bool { + var ( + col = s.getUserCollection() + user = User{} + ) + + // Find + cond := bson.M{ + "$or": []bson.M{ + { + "phone": phone, + }, + { + "email": email, + }, + }, + } + if err := col.FindOne(ctx, cond).Decode(&user); err != nil { + logger.Error("usermngmt - findByCondition", logger.LogData{ + "condition": cond, + "err": err.Error(), + }) + return true + } + return !user.ID.IsZero() +} diff --git a/model.go b/model.go new file mode 100644 index 0000000..da79edd --- /dev/null +++ b/model.go @@ -0,0 +1,21 @@ +package usermngmt + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +// User ... +type User struct { + ID primitive.ObjectID `bson:"_id" json:"_id"` + Name string `bson:"name" json:"name"` + Phone string `bson:"phone" json:"phone"` // unique + Email string `bson:"email" json:"email"` // unique + HashPassword string `bson:"hashPassword" json:"hashPassword"` + Status string `bson:"status" json:"status"` + RoleID primitive.ObjectID `bson:"roleID" json:"roleId"` + Other string `bson:"other" json:"other"` + CreatedAt time.Time `bson:"createdAt" json:"createdAt"` + UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` +} diff --git a/time.go b/time.go new file mode 100644 index 0000000..8e31061 --- /dev/null +++ b/time.go @@ -0,0 +1,20 @@ +package usermngmt + +import "time" + +// +// NOTE: due to unique timezone in server's code, all using time will be convert to HCM timezone (UTC +7) +// All functions generate time, must be call util functions here +// WARNING: don't accept call time.Now() directly +// + +// getHCMLocation ... +func getHCMLocation() *time.Location { + l, _ := time.LoadLocation(timezoneHCM) + return l +} + +// now ... +func now() time.Time { + return time.Now().In(getHCMLocation()) +} diff --git a/usermngmt.go b/usermngmt.go new file mode 100644 index 0000000..22034d4 --- /dev/null +++ b/usermngmt.go @@ -0,0 +1,63 @@ +package usermngmt + +import ( + "errors" + "fmt" + + "github.com/Selly-Modules/mongodb" + "go.mongodb.org/mongo-driver/mongo" +) + +// MongoDBConfig ... +type MongoDBConfig struct { + Host, User, Password, DBName, Mechanism, Source string +} + +// Config ... +type Config struct { + // MongoDB config, for save documents + MongoDB MongoDBConfig + // Table prefix, each service has its own prefix + TablePrefix string +} + +// Service ... +type Service struct { + Config + DB *mongo.Database +} + +var s *Service + +// Init ... +func Init(config Config) (*Service, error) { + if config.MongoDB.Host == "" || config.TablePrefix == "" { + return nil, errors.New("please provide all necessary information for init user") + } + + // Connect MongoDB + db, err := mongodb.Connect( + config.MongoDB.Host, + config.MongoDB.User, + config.MongoDB.Password, + config.MongoDB.DBName, + config.MongoDB.Mechanism, + config.MongoDB.Source, + ) + if err != nil { + fmt.Println("Cannot init module User MANAGEMENT", err) + return nil, err + } + + s = &Service{ + Config: config, + DB: db, + } + + return s, nil +} + +// GetInstance ... +func GetInstance() *Service { + return s +} diff --git a/validate.go b/validate.go new file mode 100644 index 0000000..6354fac --- /dev/null +++ b/validate.go @@ -0,0 +1,59 @@ +package usermngmt + +import ( + "errors" + + "github.com/Selly-Modules/logger" +) + +func (co CreateOptions) validate() error { + // Name + if co.Name == "" { + logger.Error("usermngmt - Create: no Name data", logger.LogData{ + "payload": co, + }) + return errors.New("no name data") + } + + // Phone + if co.Phone == "" { + logger.Error("usermngmt - Create: no phone data", logger.LogData{ + "payload": co, + }) + return errors.New("no phone data") + } + + // Email + if co.Email == "" { + logger.Error("usermngmt - Create: no email data", logger.LogData{ + "payload": co, + }) + return errors.New("no email data") + } + + // HashPassword + if co.HashPassword == "" { + logger.Error("usermngmt - Create: no hashPassword data", logger.LogData{ + "payload": co, + }) + return errors.New("no hashPassword data") + } + + // Status + if co.Status == "" { + logger.Error("usermngmt - Create: no status data", logger.LogData{ + "payload": co, + }) + return errors.New("no status data") + } + + // RoleID + if co.RoleID == "" { + logger.Error("usermngmt - Create: no roleID data", logger.LogData{ + "payload": co, + }) + return errors.New("no roleID data") + } + + return nil +} From b06431b9b994c26e71e2c36b072ff6591088bb51 Mon Sep 17 00:00:00 2001 From: Hoang Date: Mon, 8 Nov 2021 15:34:20 +0700 Subject: [PATCH 2/4] fix comment --- action_create.go | 54 ++++++++++++++++++-------------------- constant.go | 1 + db.go | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ helper.go | 41 ----------------------------- model.go | 30 ++++++++++++++------- validate.go | 14 +++++----- 6 files changed, 122 insertions(+), 86 deletions(-) create mode 100644 db.go diff --git a/action_create.go b/action_create.go index 4f3e743..c8e068f 100644 --- a/action_create.go +++ b/action_create.go @@ -7,17 +7,18 @@ import ( "github.com/Selly-Modules/logger" "github.com/Selly-Modules/mongodb" + "go.mongodb.org/mongo-driver/bson/primitive" ) // CreateOptions ... type CreateOptions struct { - Name string - Phone string - Email string - HashPassword string - Status string - RoleID string - Other string + Name string + Phone string + Email string + HashedPassword string + Status string + RoleID primitive.ObjectID + Other string } // Create ... @@ -39,9 +40,14 @@ func (s Service) Create(payload CreateOptions) error { return err } - // Find phone,email exists or not - if s.haveNameOrPhoneExisted(ctx, userData.Phone, userData.Email) { - return errors.New("have name or phone existed") + // Find roleID exists or not + if !s.isRoleIDAlreadyExisted(ctx, userData.RoleID) { + return errors.New("roleID does not exist") + } + + // Find phone number,email exists or not + if s.isPhoneNumberOrEmailAlreadyExisted(ctx, userData.Phone, userData.Email) { + return errors.New("phone number or email already existed") } // Create device @@ -59,24 +65,16 @@ func (s Service) Create(payload CreateOptions) error { func (payload CreateOptions) newUser() (result User, err error) { timeNow := now() - - // New RoleID from string - roleID, isValid := mongodb.NewIDFromString(payload.RoleID) - if !isValid { - err = errors.New("invalid roleID") - return - } - return User{ - ID: mongodb.NewObjectID(), - Name: payload.Name, - Phone: payload.Phone, - Email: payload.Email, - HashPassword: payload.HashPassword, - Status: payload.Status, - RoleID: roleID, - Other: payload.Other, - CreatedAt: timeNow, - UpdatedAt: timeNow, + ID: mongodb.NewObjectID(), + Name: payload.Name, + Phone: payload.Phone, + Email: payload.Email, + HashedPassword: payload.HashedPassword, + Status: payload.Status, + RoleID: payload.RoleID, + Other: payload.Other, + CreatedAt: timeNow, + UpdatedAt: timeNow, }, nil } diff --git a/constant.go b/constant.go index d9d6e28..452d4b2 100644 --- a/constant.go +++ b/constant.go @@ -3,6 +3,7 @@ package usermngmt // Constant ... const ( tableUser = "users" + tableRole = "roles" timezoneHCM = "Asia/Ho_Chi_Minh" ) diff --git a/db.go b/db.go new file mode 100644 index 0000000..3204684 --- /dev/null +++ b/db.go @@ -0,0 +1,68 @@ +package usermngmt + +import ( + "context" + "fmt" + + "github.com/Selly-Modules/logger" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" +) + +// getUserCollection ... +func (s Service) getUserCollection() *mongo.Collection { + return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableUser)) +} + +// getRoleCollection ... +func (s Service) getRoleCollection() *mongo.Collection { + return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableRole)) +} + +func (s Service) isPhoneNumberOrEmailAlreadyExisted(ctx context.Context, phone, email string) bool { + var ( + col = s.getUserCollection() + user = User{} + ) + + // Find + cond := bson.M{ + "$or": []bson.M{ + { + "phone": phone, + }, + { + "email": email, + }, + }, + } + if err := col.FindOne(ctx, cond).Decode(&user); err != nil { + logger.Error("usermngmt - findByCondition", logger.LogData{ + "condition": cond, + "err": err.Error(), + }) + return true + } + return !user.ID.IsZero() +} + +func (s Service) isRoleIDAlreadyExisted(ctx context.Context, roleID primitive.ObjectID) bool { + var ( + col = s.getRoleCollection() + role = Role{} + ) + + // Find + cond := bson.M{ + "_id": roleID, + } + if err := col.FindOne(ctx, cond).Decode(&role); err != nil { + logger.Error("usermngmt - findRoleByCondition", logger.LogData{ + "condition": cond, + "err": err.Error(), + }) + return false + } + return !role.ID.IsZero() +} diff --git a/helper.go b/helper.go index 396baca..3d4670c 100644 --- a/helper.go +++ b/helper.go @@ -1,42 +1 @@ package usermngmt - -import ( - "context" - "fmt" - - "github.com/Selly-Modules/logger" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" -) - -// getUserCollection ... -func (s Service) getUserCollection() *mongo.Collection { - return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableUser)) -} - -func (s Service) haveNameOrPhoneExisted(ctx context.Context, phone, email string) bool { - var ( - col = s.getUserCollection() - user = User{} - ) - - // Find - cond := bson.M{ - "$or": []bson.M{ - { - "phone": phone, - }, - { - "email": email, - }, - }, - } - if err := col.FindOne(ctx, cond).Decode(&user); err != nil { - logger.Error("usermngmt - findByCondition", logger.LogData{ - "condition": cond, - "err": err.Error(), - }) - return true - } - return !user.ID.IsZero() -} diff --git a/model.go b/model.go index da79edd..cba9c56 100644 --- a/model.go +++ b/model.go @@ -8,14 +8,24 @@ import ( // User ... type User struct { - ID primitive.ObjectID `bson:"_id" json:"_id"` - Name string `bson:"name" json:"name"` - Phone string `bson:"phone" json:"phone"` // unique - Email string `bson:"email" json:"email"` // unique - HashPassword string `bson:"hashPassword" json:"hashPassword"` - Status string `bson:"status" json:"status"` - RoleID primitive.ObjectID `bson:"roleID" json:"roleId"` - Other string `bson:"other" json:"other"` - CreatedAt time.Time `bson:"createdAt" json:"createdAt"` - UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` + ID primitive.ObjectID `bson:"_id" json:"_id"` + Name string `bson:"name" json:"name"` + Phone string `bson:"phone" json:"phone"` // unique + Email string `bson:"email" json:"email"` // unique + HashedPassword string `bson:"hashedPassword" json:"hashedPassword"` + Status string `bson:"status" json:"status"` + RoleID primitive.ObjectID `bson:"roleID" json:"roleId"` + Other string `bson:"other" json:"other"` + CreatedAt time.Time `bson:"createdAt" json:"createdAt"` + UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` +} + +// Role ... +type Role struct { + ID primitive.ObjectID `bson:"_id" json:"_id"` + Name string `bson:"name" json:"name"` + Code string `bson:"code" json:"code"` + IsAdmin bool `bson:"isAdmin" json:"isAdmin"` + CreatedAt time.Time `bson:"createdAt" json:"createdAt"` + UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` } diff --git a/validate.go b/validate.go index 6354fac..2d5d017 100644 --- a/validate.go +++ b/validate.go @@ -31,12 +31,12 @@ func (co CreateOptions) validate() error { return errors.New("no email data") } - // HashPassword - if co.HashPassword == "" { - logger.Error("usermngmt - Create: no hashPassword data", logger.LogData{ + // HashedPassword + if co.HashedPassword == "" { + logger.Error("usermngmt - Create: no hashedPassword data", logger.LogData{ "payload": co, }) - return errors.New("no hashPassword data") + return errors.New("no hashedPassword data") } // Status @@ -48,11 +48,11 @@ func (co CreateOptions) validate() error { } // RoleID - if co.RoleID == "" { - logger.Error("usermngmt - Create: no roleID data", logger.LogData{ + if co.RoleID.IsZero() { + logger.Error("usermngmt - Create: invalid roleID data", logger.LogData{ "payload": co, }) - return errors.New("no roleID data") + return errors.New("invalid roleID data") } return nil From d620c7c40e8a1cd52a11424363d51e88f2bf49ed Mon Sep 17 00:00:00 2001 From: Hoang Date: Mon, 8 Nov 2021 17:04:01 +0700 Subject: [PATCH 3/4] fix comment again --- action_create.go | 31 ++++++++++--------------------- constant.go | 2 ++ db.go | 34 ++++++++++++++++++++-------------- helper.go | 12 ++++++++++++ model.go | 4 ++-- usermngmt.go | 2 +- validate.go | 21 ++++++++++++++++----- 7 files changed, 63 insertions(+), 43 deletions(-) diff --git a/action_create.go b/action_create.go index c8e068f..3a59fd3 100644 --- a/action_create.go +++ b/action_create.go @@ -2,7 +2,6 @@ package usermngmt import ( "context" - "errors" "fmt" "github.com/Selly-Modules/logger" @@ -12,13 +11,13 @@ import ( // CreateOptions ... type CreateOptions struct { - Name string - Phone string - Email string - HashedPassword string - Status string - RoleID primitive.ObjectID - Other string + Name string + Phone string + Email string + Password string + Status string + RoleID primitive.ObjectID + Other string } // Create ... @@ -29,7 +28,7 @@ func (s Service) Create(payload CreateOptions) error { ) // Validate payload - err := payload.validate() + err := payload.validate(ctx) if err != nil { return err } @@ -40,20 +39,10 @@ func (s Service) Create(payload CreateOptions) error { return err } - // Find roleID exists or not - if !s.isRoleIDAlreadyExisted(ctx, userData.RoleID) { - return errors.New("roleID does not exist") - } - - // Find phone number,email exists or not - if s.isPhoneNumberOrEmailAlreadyExisted(ctx, userData.Phone, userData.Email) { - return errors.New("phone number or email already existed") - } - // Create device _, err = col.InsertOne(ctx, userData) if err != nil { - logger.Error("usermngmt - Create ", logger.LogData{ + logger.Error("usermngmt - Create", logger.LogData{ "doc": userData, "err": err.Error(), }) @@ -70,7 +59,7 @@ func (payload CreateOptions) newUser() (result User, err error) { Name: payload.Name, Phone: payload.Phone, Email: payload.Email, - HashedPassword: payload.HashedPassword, + HashedPassword: hashPassword(payload.Password), Status: payload.Status, RoleID: payload.RoleID, Other: payload.Other, diff --git a/constant.go b/constant.go index 452d4b2..6b6e124 100644 --- a/constant.go +++ b/constant.go @@ -6,4 +6,6 @@ const ( tableRole = "roles" timezoneHCM = "Asia/Ho_Chi_Minh" + + passwordHashingCost = 14 ) diff --git a/db.go b/db.go index 3204684..08eb7b1 100644 --- a/db.go +++ b/db.go @@ -12,18 +12,23 @@ import ( // getUserCollection ... func (s Service) getUserCollection() *mongo.Collection { - return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableUser)) + if s.TablePrefix != "" { + return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableUser)) + } + return s.DB.Collection(tableUser) } // getRoleCollection ... func (s Service) getRoleCollection() *mongo.Collection { - return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableRole)) + if s.TablePrefix != "" { + s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableRole)) + } + return s.DB.Collection(tableRole) } -func (s Service) isPhoneNumberOrEmailAlreadyExisted(ctx context.Context, phone, email string) bool { +func (s Service) isPhoneNumberOrEmailExisted(ctx context.Context, phone, email string) bool { var ( - col = s.getUserCollection() - user = User{} + col = s.getUserCollection() ) // Find @@ -37,32 +42,33 @@ func (s Service) isPhoneNumberOrEmailAlreadyExisted(ctx context.Context, phone, }, }, } - if err := col.FindOne(ctx, cond).Decode(&user); err != nil { - logger.Error("usermngmt - findByCondition", logger.LogData{ + total, err := col.CountDocuments(ctx, cond) + if err != nil { + logger.Error("usermngmt - countUserByCondition", logger.LogData{ "condition": cond, "err": err.Error(), }) return true } - return !user.ID.IsZero() + return total != 0 } -func (s Service) isRoleIDAlreadyExisted(ctx context.Context, roleID primitive.ObjectID) bool { +func (s Service) isRoleIDExisted(ctx context.Context, roleID primitive.ObjectID) bool { var ( - col = s.getRoleCollection() - role = Role{} + col = s.getRoleCollection() ) // Find cond := bson.M{ "_id": roleID, } - if err := col.FindOne(ctx, cond).Decode(&role); err != nil { - logger.Error("usermngmt - findRoleByCondition", logger.LogData{ + total, err := col.CountDocuments(ctx, cond) + if err != nil { + logger.Error("usermngmt - countRoleByCondition", logger.LogData{ "condition": cond, "err": err.Error(), }) return false } - return !role.ID.IsZero() + return total != 0 } diff --git a/helper.go b/helper.go index 3d4670c..ca80f04 100644 --- a/helper.go +++ b/helper.go @@ -1 +1,13 @@ package usermngmt + +import "golang.org/x/crypto/bcrypt" + +func hashPassword(password string) string { + bytes, _ := bcrypt.GenerateFromPassword([]byte(password), passwordHashingCost) + return string(bytes) +} + +func checkPasswordHash(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} diff --git a/model.go b/model.go index cba9c56..135b037 100644 --- a/model.go +++ b/model.go @@ -12,9 +12,9 @@ type User struct { Name string `bson:"name" json:"name"` Phone string `bson:"phone" json:"phone"` // unique Email string `bson:"email" json:"email"` // unique - HashedPassword string `bson:"hashedPassword" json:"hashedPassword"` + HashedPassword string `bson:"hashedPassword" json:"-"` Status string `bson:"status" json:"status"` - RoleID primitive.ObjectID `bson:"roleID" json:"roleId"` + RoleID primitive.ObjectID `bson:"roleId" json:"roleId"` Other string `bson:"other" json:"other"` CreatedAt time.Time `bson:"createdAt" json:"createdAt"` UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` diff --git a/usermngmt.go b/usermngmt.go index 22034d4..ef63c29 100644 --- a/usermngmt.go +++ b/usermngmt.go @@ -31,7 +31,7 @@ var s *Service // Init ... func Init(config Config) (*Service, error) { - if config.MongoDB.Host == "" || config.TablePrefix == "" { + if config.MongoDB.Host == "" { return nil, errors.New("please provide all necessary information for init user") } diff --git a/validate.go b/validate.go index 2d5d017..13b45c4 100644 --- a/validate.go +++ b/validate.go @@ -1,12 +1,13 @@ package usermngmt import ( + "context" "errors" "github.com/Selly-Modules/logger" ) -func (co CreateOptions) validate() error { +func (co CreateOptions) validate(ctx context.Context) error { // Name if co.Name == "" { logger.Error("usermngmt - Create: no Name data", logger.LogData{ @@ -31,12 +32,12 @@ func (co CreateOptions) validate() error { return errors.New("no email data") } - // HashedPassword - if co.HashedPassword == "" { - logger.Error("usermngmt - Create: no hashedPassword data", logger.LogData{ + // Password + if co.Password == "" { + logger.Error("usermngmt - Create: no password data", logger.LogData{ "payload": co, }) - return errors.New("no hashedPassword data") + return errors.New("no password data") } // Status @@ -55,5 +56,15 @@ func (co CreateOptions) validate() error { return errors.New("invalid roleID data") } + // Find roleID exists or not + if !s.isRoleIDExisted(ctx, co.RoleID) { + return errors.New("role id does not exist") + } + + // Find phone number,email exists or not + if s.isPhoneNumberOrEmailExisted(ctx, co.Phone, co.Email) { + return errors.New("phone number or email already existed") + } + return nil } From 518de0245a689d93121fd96fd0b8b1ac2b0d8ca0 Mon Sep 17 00:00:00 2001 From: Hoang Date: Mon, 8 Nov 2021 18:21:52 +0700 Subject: [PATCH 4/4] fix comment again --- action_create.go | 21 +++++++-------------- constant.go | 5 +++-- db.go | 27 +++++++++++++++++++-------- usermngmt.go | 5 +++++ validate.go | 13 +++++++++---- 5 files changed, 43 insertions(+), 28 deletions(-) diff --git a/action_create.go b/action_create.go index 3a59fd3..cc0cb4a 100644 --- a/action_create.go +++ b/action_create.go @@ -2,11 +2,8 @@ package usermngmt import ( "context" - "fmt" - "github.com/Selly-Modules/logger" "github.com/Selly-Modules/mongodb" - "go.mongodb.org/mongo-driver/bson/primitive" ) // CreateOptions ... @@ -16,14 +13,13 @@ type CreateOptions struct { Email string Password string Status string - RoleID primitive.ObjectID + RoleID string Other string } // Create ... func (s Service) Create(payload CreateOptions) error { var ( - col = s.getUserCollection() ctx = context.Background() ) @@ -34,19 +30,15 @@ func (s Service) Create(payload CreateOptions) error { } // New user data from payload - userData, err := payload.newUser() + doc, err := payload.newUser() if err != nil { return err } - // Create device - _, err = col.InsertOne(ctx, userData) + // Create user + err = s.userCreate(ctx, doc) if err != nil { - logger.Error("usermngmt - Create", logger.LogData{ - "doc": userData, - "err": err.Error(), - }) - return fmt.Errorf("error when create user: %s", err.Error()) + return err } return nil @@ -54,6 +46,7 @@ func (s Service) Create(payload CreateOptions) error { func (payload CreateOptions) newUser() (result User, err error) { timeNow := now() + roleID, _ := mongodb.NewIDFromString(payload.RoleID) return User{ ID: mongodb.NewObjectID(), Name: payload.Name, @@ -61,7 +54,7 @@ func (payload CreateOptions) newUser() (result User, err error) { Email: payload.Email, HashedPassword: hashPassword(payload.Password), Status: payload.Status, - RoleID: payload.RoleID, + RoleID: roleID, Other: payload.Other, CreatedAt: timeNow, UpdatedAt: timeNow, diff --git a/constant.go b/constant.go index 6b6e124..ab8a97d 100644 --- a/constant.go +++ b/constant.go @@ -2,8 +2,9 @@ package usermngmt // Constant ... const ( - tableUser = "users" - tableRole = "roles" + tableUser = "users" + tableRole = "roles" + tablePrefixDefault = "usermngmt" timezoneHCM = "Asia/Ho_Chi_Minh" diff --git a/db.go b/db.go index 08eb7b1..c5b0d5b 100644 --- a/db.go +++ b/db.go @@ -12,18 +12,12 @@ import ( // getUserCollection ... func (s Service) getUserCollection() *mongo.Collection { - if s.TablePrefix != "" { - return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableUser)) - } - return s.DB.Collection(tableUser) + return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableUser)) } // getRoleCollection ... func (s Service) getRoleCollection() *mongo.Collection { - if s.TablePrefix != "" { - s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableRole)) - } - return s.DB.Collection(tableRole) + return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableRole)) } func (s Service) isPhoneNumberOrEmailExisted(ctx context.Context, phone, email string) bool { @@ -72,3 +66,20 @@ func (s Service) isRoleIDExisted(ctx context.Context, roleID primitive.ObjectID) } return total != 0 } + +func (s Service) userCreate(ctx context.Context, doc User) error { + var ( + col = s.getUserCollection() + ) + + _, err := col.InsertOne(ctx, doc) + if err != nil { + logger.Error("usermngmt - Create", logger.LogData{ + "doc": doc, + "err": err.Error(), + }) + return fmt.Errorf("error when create user: %s", err.Error()) + } + + return nil +} diff --git a/usermngmt.go b/usermngmt.go index ef63c29..5979cff 100644 --- a/usermngmt.go +++ b/usermngmt.go @@ -35,6 +35,11 @@ func Init(config Config) (*Service, error) { return nil, errors.New("please provide all necessary information for init user") } + // If prefixTable is empty then it is usermngmt + if config.TablePrefix == "" { + config.TablePrefix = tablePrefixDefault + } + // Connect MongoDB db, err := mongodb.Connect( config.MongoDB.Host, diff --git a/validate.go b/validate.go index 13b45c4..71a2b8e 100644 --- a/validate.go +++ b/validate.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/Selly-Modules/logger" + "github.com/Selly-Modules/mongodb" ) func (co CreateOptions) validate(ctx context.Context) error { @@ -49,15 +50,19 @@ func (co CreateOptions) validate(ctx context.Context) error { } // RoleID - if co.RoleID.IsZero() { - logger.Error("usermngmt - Create: invalid roleID data", logger.LogData{ + if co.RoleID == "" { + logger.Error("usermngmt - Create: no roleID data", logger.LogData{ "payload": co, }) - return errors.New("invalid roleID data") + return errors.New("no role id data") } // Find roleID exists or not - if !s.isRoleIDExisted(ctx, co.RoleID) { + roleID, isValid := mongodb.NewIDFromString(co.RoleID) + if !isValid { + return errors.New("invalid role id data") + } + if !s.isRoleIDExisted(ctx, roleID) { return errors.New("role id does not exist") }