diff --git a/apis/plans.go b/apis/plans.go index 0664313..dc6942a 100644 --- a/apis/plans.go +++ b/apis/plans.go @@ -21,22 +21,11 @@ func createPlan(c *gin.Context) { Name string `json:"name" form:"name"` } c.Bind(&plan_req) - var plan Plan = Plan{ - Name: plan_req.Name, - Owner: u.Username, - Members: []Member{ - { - UserID: u.Username, - Type: "user", - Status: "ready", - JoinCode: "owner", - }, - }, - } - result := db.Create(&plan) - if result.Error != nil { - c.JSON(http.StatusInternalServerError, result.Error) + _, err := CreatePlan(db, u, plan_req.Name) + + if err != nil { + c.JSON(http.StatusInternalServerError, err) } else { c.JSON(http.StatusOK, plan_req) } @@ -69,7 +58,7 @@ func getPlan(c *gin.Context) { return } - plan, err := GetPlan(db, *user, params.Id) + plan, err := user.GetPlan(db, params.Id) if err == nil { c.JSON(http.StatusOK, plan) @@ -94,7 +83,7 @@ func listPlanMembers(c *gin.Context) { return } - plan, err := GetPlan(db, *user, uint(plan_id)) + plan, err := user.GetPlan(db, uint(plan_id)) members, err := plan.GetAllUsers(db) if err == nil { @@ -120,15 +109,17 @@ func addPlanMember(c *gin.Context) { return } - plan, err := GetPlan(db, *user, uint(plan_id)) + plan, err := user.GetPlan(db, uint(plan_id)) - var new_member Member + var new_member struct { + Name string `json:"name" form:"name"` + } if err := c.ShouldBind(&new_member); err != nil { c.String(http.StatusInternalServerError, err.Error()) return } - err = plan.AddMember(db, &new_member) + err = plan.AddMember(db, &Member{Name: new_member.Name, Type: "non-user"}) if err == nil { c.JSON(http.StatusOK, new_member) @@ -144,6 +135,7 @@ func addPlanMember(c *gin.Context) { func joinPlan(c *gin.Context) { user := extractUser(db, c) if user == nil { + c.Status(http.StatusUnauthorized) return } @@ -152,35 +144,34 @@ func joinPlan(c *gin.Context) { c.Status(http.StatusBadRequest) return } - plan, err := GetPlan(db, *user, uint(plan_id)) - if err != nil { + plan, err := GetPlan(db, uint(plan_id)) + if err != nil || plan == nil { c.Status(http.StatusInternalServerError) return } - member, err := plan.GetMember(db, user) var query struct { - JoinCode string `fdb:"code"` + JoinCode string `form:"code"` } if c.ShouldBindQuery(&query) != nil || query.JoinCode == "" { c.Status(http.StatusBadRequest) return } - if member.Status != "pending" { - c.String(http.StatusConflict, "User is not pending") - return - } - if member.JoinCode == query.JoinCode { - member.Status = "ready" - err := db.Model(&member).Update("status", member.Status).Error - if err != nil { - c.String(http.StatusInternalServerError, err.Error()) - return - } - } else { + if query.JoinCode != plan.JoinCode { c.String(http.StatusConflict, "Invalid join code") return } + + is_member, err := plan.IsMember(db, user) + if err != nil { + c.Status(http.StatusInternalServerError) + return + } + if is_member { + c.String(http.StatusConflict, "User already a member") + return + } + plan.AddMember(db, &Member{Type: "user", UserID: user.Username}) c.Status(http.StatusOK) } @@ -198,7 +189,7 @@ func createPlanPoll(c *gin.Context) { return } - plan, err := GetPlan(db, *user, params.Id) + plan, err := user.GetPlan(db, params.Id) if errors.Is(err, ErrNotFound) { c.Status(http.StatusNotFound) diff --git a/core/models.go b/core/models.go index 87afa0a..53268c0 100644 --- a/core/models.go +++ b/core/models.go @@ -9,15 +9,13 @@ type User struct { } type Member struct { - ID uint `gorm:"primaryKey;autoIncrement:true" json:"-"` - PlanID uint `json:"-"` - Plan Plan `json:"-"` - Type string `gorm:"check:type in ('user','non-user')" json:"type"` - Name string `gorm:"check:type=='member' OR name IS NOT NULL" json:"name"` - Status string `gorm:"check:status in ('pending','ready')" json:"status"` - JoinCode string `gorm:"uniqueIndex;check:type=='non-member' OR join_code IS NOT NULL" json:"join_code,omitempty"` - UserID string `json:"username"` - User User `gorm:"foreignKey:UserID" json:"-"` + ID uint `gorm:"primaryKey;autoIncrement:true" json:"-"` + PlanID uint `json:"-"` + Plan Plan `json:"-"` + Type string `gorm:"check:type in ('user','non-user')" json:"type"` + Name string `gorm:"check:type=='member' OR name IS NOT NULL" json:"name"` + UserID string `json:"username"` + User User `gorm:"foreignKey:UserID" json:"-"` } // CREATE TABLE plans(id INTEGER PRIMARY KEY AUTOINCREMENT, name STRING, owner STRING, FOREIGN KEY(owner) REFERENCES users(username)) @@ -27,6 +25,7 @@ type Plan struct { Name string `json:"name"` Owner string `json:"owner"` Description string `json:"description"` + JoinCode string `gorm:"not null" json:"join_code,omitempty"` Members []Member `json:"-"` Polls []Poll `gorm:"foreignKey:PlanID;references:ID" json:"-"` } diff --git a/core/plans.go b/core/plans.go index 2a96533..32ad597 100644 --- a/core/plans.go +++ b/core/plans.go @@ -8,7 +8,32 @@ import ( "gorm.io/gorm" ) -func GetPlan(orm *gorm.DB, user User, id uint) (*Plan, error) { +func CreatePlan(db *gorm.DB, user *User, name string) (*Plan, error) { + join_code := make([]byte, 32) + _, err := rand.Read(join_code) + if err != nil { + return nil, err + } + + var plan Plan = Plan{ + Name: name, + Owner: user.Username, + Members: []Member{ + { + UserID: user.Username, + Type: "user", + }, + }, + JoinCode: base64.URLEncoding.EncodeToString(join_code), + } + result := db.Create(&plan) + if result.Error != nil { + return nil, result.Error + } + return &plan, nil +} + +func GetPlan(orm *gorm.DB, id uint) (*Plan, error) { var plan Plan = Plan{ ID: id, } @@ -20,16 +45,6 @@ func GetPlan(orm *gorm.DB, user User, id uint) (*Plan, error) { return nil, result.Error } - if plan.Owner == user.Username { - return &plan, nil - } - - isMember, err := plan.IsMember(orm, &user) - - if !isMember || err != nil { - return nil, err - } - return &plan, nil } @@ -81,6 +96,9 @@ func (p *Plan) AddMember(orm *gorm.DB, new_member *Member) error { } new_member.PlanID = p.ID if new_member.Type == "non-user" { + if new_member.Name == "" { + return errors.New("name required for non user") + } found, err := p.HasNonUser(orm, new_member.Name) if err != nil { return nil @@ -88,9 +106,7 @@ func (p *Plan) AddMember(orm *gorm.DB, new_member *Member) error { if found { return errors.New("Non user name taken") } - new_member.Status = "ready" return orm.Create(&new_member).Error - } else if new_member.Type == "user" { user, err := GetUser(orm, new_member.UserID) if err != nil { @@ -105,24 +121,7 @@ func (p *Plan) AddMember(orm *gorm.DB, new_member *Member) error { return errors.New("User already is member") } - new_member.Status = "pending" - var res error - for retries := 3; retries >= 0; retries -= 1 { - join_code := make([]byte, 32) - _, err = rand.Read(join_code) - if err != nil { - return err - } - new_member.JoinCode = base64.URLEncoding.EncodeToString(join_code) - res = orm.Create(&new_member).Error - - if res == nil { - break - } else if !errors.Is(res, gorm.ErrDuplicatedKey) { - return res - } - } - return res + return orm.Create(&new_member).Error } else { return errors.New("Invalid type for user") } diff --git a/core/users.go b/core/users.go index c6a95a7..889e2fb 100644 --- a/core/users.go +++ b/core/users.go @@ -1,6 +1,8 @@ package core import ( + "errors" + "gorm.io/gorm" ) @@ -14,6 +16,31 @@ func (u *User) GetPlans(orm *gorm.DB) ([]Plan, error) { return plans, err.Error } +func (u *User) GetPlan(db *gorm.DB, plan_id uint) (Plan, error) { + var plan Plan = Plan{ + ID: plan_id, + } + result := db.Take(&plan) + + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return plan, ErrNotFound + } else if result.Error != nil { + return plan, result.Error + } + + if plan.Owner == u.Username { + return plan, nil + } + + isMember, err := plan.IsMember(db, u) + + if !isMember || err != nil { + return plan, err + } + + return plan, nil +} + func GetUser(orm *gorm.DB, username string) (User, error) { user := User{Username: username} if err := orm.Take(&user).Error; err != nil {