From ca70d241d6494b4736ec7789af605981f3ee27a5 Mon Sep 17 00:00:00 2001 From: Preston Baxter Date: Wed, 1 Nov 2023 21:40:50 -0500 Subject: [PATCH] B: Rework Model framework and finish vendor model so UI and callback controller can be built --- ui/config/config.go | 4 +-- ui/controllers/auth.go | 18 ++++------ ui/controllers/auth_middleware.go | 7 ++-- ui/controllers/controllers.go | 8 ++--- ui/controllers/pages.go | 1 + ui/controllers/util.go | 3 +- ui/db/db.go | 39 +++++++++++++++++++-- ui/db/models/user.go | 56 +++++++------------------------ ui/db/models/vendor.go | 52 +++++++++++++++++++--------- ui/db/user.go | 2 +- ui/db/vendors.go | 3 +- 11 files changed, 104 insertions(+), 89 deletions(-) diff --git a/ui/config/config.go b/ui/config/config.go index 9354ee1..aa1d0a8 100644 --- a/ui/config/config.go +++ b/ui/config/config.go @@ -19,8 +19,8 @@ type MongoConfig struct { var cfg *config func Init() { - viper.SetConfigName("config") // name of config file (without extension) - viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name + viper.SetConfigName("config") // name of config file (without extension) + viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name viper.AddConfigPath("/etc/capstone") // path to look for the config file in err := viper.ReadInConfig() diff --git a/ui/controllers/auth.go b/ui/controllers/auth.go index 0e87261..f79b04e 100644 --- a/ui/controllers/auth.go +++ b/ui/controllers/auth.go @@ -16,11 +16,11 @@ import ( var VALIDATE_EMAIL_REGEX = regexp.MustCompile(`^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$`) type LoginPostBody struct { - Email string `json:"email"` + Email string `json:"email"` Password string `json:"password"` } -func SignUpHandler (c *gin.Context) { +func SignUpHandler(c *gin.Context) { //get uname and password. conf := config.Config() reqBody := &LoginPostBody{} @@ -80,16 +80,12 @@ func SignUpHandler (c *gin.Context) { return } - //add vendor accounts - - mongo.AddAccountsForUser(user) - now := time.Now().Unix() exp := time.Now().Add(12 * time.Hour).Unix() //build jwt token := jwt.NewWithClaims(jwt.SigningMethodHS256, AuthClaims{ - Subject: user.UserId, + Subject: user.MongoId().String(), Expires: exp, IssuedAt: now, NotBefore: now, @@ -107,7 +103,7 @@ func SignUpHandler (c *gin.Context) { //store jwt as cookie //TODO: Make sure set secure for prd deployment - c.SetCookie("authorization", jwtStr, 3600 * 24, "", "", false, true) + c.SetCookie("authorization", jwtStr, 3600*24, "", "", false, true) c.Redirect(302, "/dashboard") } @@ -163,7 +159,7 @@ func LoginHandler(c *gin.Context) { //build jwt token := jwt.NewWithClaims(jwt.SigningMethodHS256, AuthClaims{ - Subject: user.UserId, + Subject: user.MongoId().String(), Expires: exp, IssuedAt: now, NotBefore: now, @@ -184,7 +180,7 @@ func LoginHandler(c *gin.Context) { } else { secure = true } - c.SetCookie("authorization", jwtStr, 3600 * 24, "", "", secure, true) + c.SetCookie("authorization", jwtStr, 3600*24, "", "", secure, true) c.Redirect(302, "/dashboard") } @@ -198,7 +194,7 @@ func LogoutHandler(c *gin.Context) { } else { secure = true } - c.SetCookie("authorization", "", 3600 * 24, "", "", secure, true) + c.SetCookie("authorization", "", 3600*24, "", "", secure, true) c.Redirect(302, "/login") } diff --git a/ui/controllers/auth_middleware.go b/ui/controllers/auth_middleware.go index bed23d4..a57bb2d 100644 --- a/ui/controllers/auth_middleware.go +++ b/ui/controllers/auth_middleware.go @@ -73,11 +73,11 @@ func AuthMiddleware(strict bool) gin.HandlerFunc { return []byte(conf.JwtSecret), nil }) if err != nil { - if err == jwt.ErrTokenExpired{ + if err == jwt.ErrTokenExpired { log.Warn("Redirecting, jwt expired") c.Redirect(301, "/login") return - }else{ + } else { if strict { log.Warnf("Redirecting, jwt issue: %s", err) c.Redirect(301, "/login") @@ -89,8 +89,7 @@ func AuthMiddleware(strict bool) gin.HandlerFunc { } } - - if !parsedToken.Valid { + if !parsedToken.Valid { if strict { log.Warn("Redirecting, jwt invalid") c.Redirect(301, "/login") diff --git a/ui/controllers/controllers.go b/ui/controllers/controllers.go index 9506be6..0717585 100644 --- a/ui/controllers/controllers.go +++ b/ui/controllers/controllers.go @@ -21,12 +21,12 @@ func BuildRouter(r *gin.Engine) { log = logrus.New() log.SetFormatter(&logrus.TextFormatter{ - ForceColors: true, + ForceColors: true, }) r.GET("/", AuthMiddleware(false), LandingPage) r.GET("/login", AuthMiddleware(false), LoginPage) - r.GET("/signup",AuthMiddleware(false), SignUpPage) + r.GET("/signup", AuthMiddleware(false), SignUpPage) r.POST("/login", LoginHandler) r.POST("/signup", SignUpHandler) @@ -36,7 +36,3 @@ func BuildRouter(r *gin.Engine) { dashboard.Use(AuthMiddleware(true)) dashboard.GET("/", DashboardPage) } - - - - diff --git a/ui/controllers/pages.go b/ui/controllers/pages.go index 457be2a..d37ad3d 100644 --- a/ui/controllers/pages.go +++ b/ui/controllers/pages.go @@ -25,6 +25,7 @@ func SignUpPage(c *gin.Context) { } func DashboardPage(c *gin.Context) { + //Get vendors if raw, exists := c.Get(USER_OBJ_KEY); exists { if user, ok := raw.(*models.User); ok { renderTempl(c, templates.DashboardPage(user)) diff --git a/ui/controllers/util.go b/ui/controllers/util.go index 4392eec..a486d50 100644 --- a/ui/controllers/util.go +++ b/ui/controllers/util.go @@ -7,7 +7,7 @@ import ( "github.com/gin-gonic/gin" ) -//Responds with 200ok and the rendered template +// Responds with 200ok and the rendered template func renderTempl(c *gin.Context, tmpl templ.Component) { buf := bytes.NewBuffer([]byte{}) tmpl.Render(c.Request.Context(), buf) @@ -19,7 +19,6 @@ func badRequest(c *gin.Context, reason string) { c.JSON(400, map[string]string{"error": reason}) } - func serverError(c *gin.Context, reason string) { c.JSON(504, map[string]string{"error": reason}) } diff --git a/ui/db/db.go b/ui/db/db.go index eb5ab00..434f1d8 100644 --- a/ui/db/db.go +++ b/ui/db/db.go @@ -2,14 +2,19 @@ package db import ( "context" + "errors" + "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config" + "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) type Model interface { - Save(client *mongo.Client) error - Delete(client *mongo.Client) error + MongoId() primitive.ObjectID + UpdateObjectInfo() } type DB struct { @@ -26,5 +31,33 @@ func NewClient(uri string) (*DB, error) { } func (db *DB) SaveModel(m Model) error { - return m.Save(db.client) + conf := config.Config() + + opts := options.Update().SetUpsert(true) + res, err := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).UpdateOne(context.Background(), bson.M{"_id": m.MongoId()}, bson.M{"$set": m}, opts) + if err != nil { + return err + } + + if res.MatchedCount == 0 && res.ModifiedCount == 0 && res.UpsertedCount == 0 { + return errors.New("Failed to update vendor account properly") + } + + return nil +} + +func (db *DB) DeleteModel(m Model) error { + conf := config.Config() + + opts := options.Delete() + res, err := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).DeleteOne(context.Background(), bson.M{"_id": m.MongoId()}, opts) + if err != nil { + return err + } + + if res.DeletedCount == 0 { + return errors.New("There was no item to delete") + } + + return nil } diff --git a/ui/db/models/user.go b/ui/db/models/user.go index d9aece5..983f09e 100644 --- a/ui/db/models/user.go +++ b/ui/db/models/user.go @@ -1,66 +1,36 @@ package models import ( - "context" - "errors" "time" - "git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config" - "github.com/google/uuid" - "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" ) const USER_TYPE string = "user" type User struct { - CommonFields `bson:"obj_info"` - mongoId primitive.ObjectID `bson:"_id,omitempty"` - UserId string `bson:"user_id,omitempty"` - Email string `bson:"email,omitempty"` - PassowrdHash string `bson:"password_hash,omitempty"` + *CommonFields `bson:"obj_info"` + mongoId primitive.ObjectID `bson:"_id,omitempty"` + Email string `bson:"email,omitempty"` + PassowrdHash string `bson:"password_hash,omitempty"` } -func (user *User) Save(client *mongo.Client) error { - conf := config.Config() +func (user *User) MongoId() primitive.ObjectID { if user.mongoId.IsZero() { now := time.Now() - user.EntityType = USER_TYPE - user.CreatedAt = now - user.UpdatedAt = now - user.UserId = uuid.New().String() user.mongoId = primitive.NewObjectIDFromTimestamp(now) } - opts := options.Update().SetUpsert(true) - - res, err := client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).UpdateOne(context.Background(), bson.M{"user_id": user.UserId}, bson.M{"$set": user},opts) - if err != nil { - return err - } - - if res.MatchedCount == 0 && res.ModifiedCount == 0 && res.UpsertedCount == 0 { - return errors.New("Failed to update client properly") - } - - return nil + return user.mongoId } -func (user *User) Delete(client *mongo.Client) error { - conf := config.Config() - opts := options.Delete() - - res, err := client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).DeleteOne(context.Background(), bson.M{"_id": user.mongoId}, opts) - if err != nil { - return err +func (user *User) UpdateObjectInfo() { + now := time.Now() + if user.CommonFields == nil { + user.CommonFields = new(CommonFields) + user.EntityType = USER_TYPE + user.CreatedAt = now } - - if res.DeletedCount == 0 { - return errors.New("There was no item to delete") - } - - return nil + user.UpdatedAt = now } diff --git a/ui/db/models/vendor.go b/ui/db/models/vendor.go index 5f816f7..9fe16d0 100644 --- a/ui/db/models/vendor.go +++ b/ui/db/models/vendor.go @@ -1,24 +1,46 @@ package models -import "go.mongodb.org/mongo-driver/bson/primitive" +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) -const VENDOR_TYPE = "vendor" const VENDOR_ACCOUNT_TYPE = "vendor_account" -type Vendor struct { - CommonFields `bson:"obj_info"` - mongoId primitive.ObjectID `bson:"_id,omitempty"` - VendorId string `bson:"vendor_id,omitempty"` - Name string `bson:"name,omitempty"` - OAuthUrl string `bson:"oauth_url"` +type OauthCredential struct { + AccessToken string `bson:"access_token,omitempty" json:"access_token,omitempty"` + ExpiresIn int `bson:"expires_in,omitempty" json:"expires_in,omitempty"` + ExpiresAt time.Time `bson:"expires_at,omitempty" json:"expires_at,omitempty"` + TokenType string `bson:"token_type,omitempty" json:"token_type,omitempty"` + Scope string `bson:"scope,omitempty" json:"scope,omitempty"` + RefreshToken string `bson:"refresh_token,omitempty" json:"refresh_token,omitempty"` } type VendorAccount struct { - CommonFields `bson:"obj_info"` - *Vendor - mongoId primitive.ObjectID `bson:"_id,omitempty"` - UserId string `bson:"user_id,omitempty"` - Secret string `bson:"secret,omitempty"` - VendorId string `bson:"vendor_id,omitempty"` - Authenticated bool `bson:"authenticated,omitempty"` + *CommonFields `bson:"obj_info"` + mongoId primitive.ObjectID `bson:"_id,omitempty"` + UserId primitive.ObjectID `bson:"user_id,omitempty"` + Secret string `bson:"secret,omitempty"` + VendorId string `bson:"vendor_id,omitempty"` + OauthCredentials *OauthCredential `bson:"ouath_credentials,omitempty"` +} + +func (va *VendorAccount) MongoId() primitive.ObjectID { + if va.mongoId.IsZero() { + now := time.Now() + va.mongoId = primitive.NewObjectIDFromTimestamp(now) + } + + return va.mongoId +} + +func (va *VendorAccount) UpdateObjectInfo() { + now := time.Now() + if va.CommonFields == nil { + va.CommonFields = new(CommonFields) + va.EntityType = VENDOR_ACCOUNT_TYPE + va.CreatedAt = now + } + va.UpdatedAt = now } diff --git a/ui/db/user.go b/ui/db/user.go index 39d56b2..2801f4b 100644 --- a/ui/db/user.go +++ b/ui/db/user.go @@ -36,7 +36,7 @@ func (db *DB) FindUserById(id string) (*models.User, error) { conf := config.Config() opts := options.FindOne() - res := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).FindOne(context.Background(), bson.M{"user_id": id, "obj_info.ent": models.USER_TYPE}, opts) + res := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).FindOne(context.Background(), bson.M{"_id": id, "obj_info.ent": models.USER_TYPE}, opts) if res.Err() != nil { if res.Err() == mongo.ErrNoDocuments { diff --git a/ui/db/vendors.go b/ui/db/vendors.go index 7a2b9c4..2b63a48 100644 --- a/ui/db/vendors.go +++ b/ui/db/vendors.go @@ -9,7 +9,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -func (db *DB) FindVendorAccountByUser(userId string) ([]models.VendorAccount, error){ +func (db *DB) FindVendorAccountByUser(userId string) ([]models.VendorAccount, error) { conf := config.Config() opts := options.Find() @@ -26,4 +26,3 @@ func (db *DB) FindVendorAccountByUser(userId string) ([]models.VendorAccount, er return vendors, nil } -