diff --git a/.gitignore b/.gitignore index 398baf2..66fd13c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,3 @@ # Dependency directories (remove the comment below to include it) # vendor/ - -.idea diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/devicemngmt.iml b/.idea/devicemngmt.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/devicemngmt.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..660daf0 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/action_create.go b/action_create.go index eebbd0e..8b23c5b 100644 --- a/action_create.go +++ b/action_create.go @@ -3,46 +3,47 @@ package devicemngmt import ( "context" "errors" - "fmt" "github.com/Selly-Modules/logger" "github.com/Selly-Modules/mongodb" + ua "github.com/mssola/user_agent" + "go.mongodb.org/mongo-driver/bson" ) -// CreateOptions ... -type CreateOptions struct { +// DeviceCreate ... +type DeviceCreate struct { DeviceID string UserID string UserAgent string AppVersion string IP string FCMToken string - AuthToken string Language string } // Create ... -func (s Service) Create(payload CreateOptions) error { +func (s Service) Create(payload DeviceCreate) error { var ( col = s.getDeviceCollection() ctx = context.Background() ) - // Validate payload - err := payload.validate() - if err != nil { - return err - } - // New device data from payload deviceData, err := payload.newDevice() if err != nil { return err } - // Find deviceID existed or not - if s.isDeviceIDExisted(ctx, deviceData.DeviceID) { - return errors.New("this device is already existed") + // Find device id existed or not + device := Device{} + if err = col.FindOne(ctx, bson.M{"deviceID": deviceData.DeviceID}).Decode(&device); err != nil { + logger.Error("devicemngt - findByDeviceID", logger.LogData{ + "deviceID": deviceData.DeviceID, + "err": err.Error(), + }) + } + if !device.ID.IsZero() { + return errors.New("deviceID already exists") } // Create device @@ -52,33 +53,78 @@ func (s Service) Create(payload CreateOptions) error { "doc": deviceData, "err": err.Error(), }) - return fmt.Errorf("error when create device: %s", err.Error()) + return errors.New("create device fail") } return nil } -func (payload CreateOptions) newDevice() (result Device, err error) { +func (payload DeviceCreate) newDevice() (result Device, err error) { timeNow := now() device := Device{ - ID: mongodb.NewObjectID(), - DeviceID: payload.DeviceID, - OSName: getOSName(payload.UserAgent), - OSVersion: getOSVersion(payload.UserAgent), - IP: payload.IP, - Language: getLanguage(payload.Language), - AuthToken: payload.AuthToken, - LastActivatedAt: timeNow, - CreatedAt: timeNow, - FCMToken: payload.FCMToken, + ID: mongodb.NewObjectID(), + LastActivityAt: timeNow, + CreatedAt: timeNow, + FCMToken: payload.FCMToken, } + // Set deviceID + if payload.DeviceID == "" { + logger.Error("devicemngt - Create: no deviceID data", logger.LogData{ + "payload": payload, + }) + err = errors.New("no deviceID data") + return + } + device.DeviceID = payload.DeviceID + + // OSName, OSVersion + if payload.UserAgent == "" { + logger.Error("devicemngt - Create: no userAgent data", logger.LogData{ + "payload": payload, + }) + err = errors.New("no userAgent data") + return + } + uaData := ua.New(payload.UserAgent) + device.OSName = uaData.OSInfo().Name + device.OSVersion = uaData.OSInfo().Version + // App version if payload.AppVersion != "" { device.AppVersion = payload.AppVersion device.IsMobile = true } + // IP + if payload.IP == "" { + logger.Error("devicemngt - Create: no ip data", logger.LogData{ + "payload": payload, + }) + err = errors.New("no ip data") + return + } + + // Language, default is vietnamese(vi) + if payload.Language == "" { + device.Language = viLanguage + } else { + device.Language = enLanguage + } + + // userIDe + userID, _ := mongodb.NewIDFromString(payload.UserID) + if userID.IsZero() { + logger.Error("devicemngt - Create: invalid userID data", logger.LogData{ + "payload": payload, + }) + err = errors.New("invalid userID data") + return + } + + // Generate authToken from userID + device.AuthToken = s.generateAuthToken(userID) + result = device return } diff --git a/auth_token.go b/auth_token.go new file mode 100644 index 0000000..88c7ddd --- /dev/null +++ b/auth_token.go @@ -0,0 +1,17 @@ +package devicemngmt + +import ( + "time" + + "github.com/dgrijalva/jwt-go" + "go.mongodb.org/mongo-driver/bson/primitive" +) + +func (s Service) generateAuthToken(userID primitive.ObjectID) string { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "_id": userID, + "exp": now().Add(time.Second * 15552000).Unix(), // 6 months + }) + tokenString, _ := token.SignedString([]byte(s.AuthSecret)) + return tokenString +} diff --git a/constant.go b/constant.go index ca4c13f..a6e1949 100644 --- a/constant.go +++ b/constant.go @@ -2,10 +2,10 @@ package devicemngmt // Constant ... const ( - tableDevice = "devices" + TableDevice = "devices" timezoneHCM = "Asia/Ho_Chi_Minh" - langVi = "vi" - langEn = "en" + viLanguage = "vi" + enLanguage = "en" ) diff --git a/devicemngt.go b/devicemngt.go index cc2b7e7..3574ec1 100644 --- a/devicemngt.go +++ b/devicemngt.go @@ -19,6 +19,8 @@ type Config struct { MongoDB MongoDBConfig // Table prefix, each service has its own prefix TablePrefix string + // Auth secret, used to sign token + AuthSecret string } // Service ... @@ -30,9 +32,9 @@ type Service struct { 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 device") +func Init(config Config) error { + if config.MongoDB.Host == "" || config.TablePrefix == "" || config.AuthSecret == "" { + return errors.New("please provide all necessary information for init device") } // Connect MongoDB @@ -46,7 +48,7 @@ func Init(config Config) (*Service, error) { ) if err != nil { fmt.Println("Cannot init module DEVICE MANAGEMENT", err) - return nil, err + return err } s = &Service{ @@ -54,7 +56,7 @@ func Init(config Config) (*Service, error) { DB: db, } - return s, nil + return nil } // GetInstance ... diff --git a/helper.go b/helper.go index 120e9d5..9b7a54f 100644 --- a/helper.go +++ b/helper.go @@ -1,50 +1,12 @@ package devicemngmt import ( - "context" "fmt" - "github.com/Selly-Modules/logger" - ua "github.com/mssola/user_agent" - "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) // getDeviceCollection ... func (s Service) getDeviceCollection() *mongo.Collection { - return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, tableDevice)) -} - -func (s Service) isDeviceIDExisted(ctx context.Context, deviceID string) bool { - var ( - col = s.getDeviceCollection() - device = Device{} - ) - - if err := col.FindOne(ctx, bson.M{"deviceID": deviceID}).Decode(&device); err != nil { - logger.Error("devicemngt - findByDeviceID", logger.LogData{ - "deviceID": deviceID, - "err": err.Error(), - }) - return true - } - return !device.ID.IsZero() -} - -func getOSName(userAgent string) string { - uaData := ua.New(userAgent) - return uaData.OSInfo().Name -} - -func getOSVersion(userAgent string) string { - uaData := ua.New(userAgent) - return uaData.OSInfo().Version -} - -func getLanguage(lang string) string { - // Language, default is vietnamese(vi) - if lang == langEn { - return langEn - } - return langVi + return s.DB.Collection(fmt.Sprintf("%s-%s", s.TablePrefix, TableDevice)) } diff --git a/model.go b/model.go index 7c00d78..bd684f3 100644 --- a/model.go +++ b/model.go @@ -8,17 +8,17 @@ import ( // Device ... type Device struct { - ID primitive.ObjectID `bson:"_id" json:"_id"` - DeviceID string `bson:"deviceID" json:"deviceId"` // unique - IP string `bson:"ip" json:"ip"` - OSName string `bson:"osName" json:"osName"` - OSVersion string `bson:"osVersion" json:"osVersion"` - AppVersion string `bson:"appVersion" json:"appVersion"` - Language string `bson:"language" json:"language"` // vi, en - IsMobile bool `bson:"isMobile" json:"isMobile"` - LastActivatedAt time.Time `bson:"lastActivatedAt" json:"lastActivatedAt"` - UserID primitive.ObjectID `bson:"userID" json:"userId"` - AuthToken string `bson:"authToken" json:"authToken"` - FCMToken string `bson:"fcmToken" json:"fcmToken"` - CreatedAt time.Time `bson:"createdAt" json:"createdAt"` + ID primitive.ObjectID `bson:"_id"` + DeviceID string `bson:"deviceID"` // unique + IP string `bson:"ip"` + OSName string `bson:"osName"` + OSVersion string `bson:"osVersion"` + AppVersion string `bson:"appVersion"` + Language string `bson:"language"` // vi, en + IsMobile bool `bson:"isMobile"` + LastActivityAt time.Time `bson:"lastActivityAt"` + UserID primitive.ObjectID `bson:"userID"` + AuthToken string `bson:"authToken"` + FCMToken string `bson:"fcmToken"` + CreatedAt time.Time `bson:"createdAt"` } diff --git a/validate.go b/validate.go deleted file mode 100644 index 9efc49f..0000000 --- a/validate.go +++ /dev/null @@ -1,51 +0,0 @@ -package devicemngmt - -import ( - "errors" - - "github.com/Selly-Modules/logger" -) - -func (co CreateOptions) validate() error{ - // DeviceID - if co.DeviceID == "" { - logger.Error("devicemngt - Create: no deviceID data", logger.LogData{ - "payload": co, - }) - return errors.New("no deviceID data") - } - - // UserAgent - if co.UserAgent == "" { - logger.Error("devicemngt - Create: no userAgent data", logger.LogData{ - "payload": co, - }) - return errors.New("no userAgent data") - } - - // IP - if co.IP == "" { - logger.Error("devicemngt - Create: no ip data", logger.LogData{ - "payload": co, - }) - return errors.New("no ip data") - } - - // UserID - if co.UserID == "" { - logger.Error("devicemngt - Create: no userID data", logger.LogData{ - "payload": co, - }) - return errors.New("no userID data") - } - - // AuthToken - if co.AuthToken == "" { - logger.Error("devicemngt - Create: no authToken data", logger.LogData{ - "payload": co, - }) - return errors.New("no authToken data") - } - - return nil -}