From 7b74ea804c17e06b0d89270c69d01f09e8b55e90 Mon Sep 17 00:00:00 2001 From: Zsigmond Date: Thu, 12 Oct 2023 17:55:03 +0100 Subject: [PATCH 01/14] fix: inject user id into context in development env --- internal/auth/middleware.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/auth/middleware.go b/internal/auth/middleware.go index 88987e3..44317d8 100644 --- a/internal/auth/middleware.go +++ b/internal/auth/middleware.go @@ -28,7 +28,10 @@ func MakeMiddlewareFrom(conf *config.Config) func(http.Handler) http.Handler { // Skip auth in development mode if conf.Environment == envutils.ENV_DEVELOPMENT { return func(next http.Handler) http.Handler { - return next + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r = injectUserIDToContext(r, 1) + next.ServeHTTP(w, r) + }) } } From 7d28577400d8614157b9d4fe1e74a511a7437443 Mon Sep 17 00:00:00 2001 From: Zsigmond Date: Thu, 12 Oct 2023 17:56:36 +0100 Subject: [PATCH 02/14] feat: add ID column to list view of Users --- view/users/list.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/view/users/list.go b/view/users/list.go index 654eb1f..dcf4e17 100644 --- a/view/users/list.go +++ b/view/users/list.go @@ -3,6 +3,7 @@ package userviews import "github.com/source-academy/stories-backend/model" type ListView struct { + ID uint `json:"id"` Name string `json:"name"` Username string `json:"username"` LoginProvider string `json:"provider"` @@ -14,6 +15,7 @@ func ListFrom(users []model.User) []ListView { usersListView[i] = ListView{ // Unlike other views, we do not fallback an empty name to // the username for the users' list view. + ID: user.ID, Name: user.FullName, Username: user.Username, LoginProvider: user.LoginProvider.ToString(), From 335ef1e266fe02facbd16efb1798f2acfcaadd7c Mon Sep 17 00:00:00 2001 From: Zsigmond Date: Thu, 12 Oct 2023 19:38:38 +0100 Subject: [PATCH 03/14] feat: add role attribute to /groups/{groupId}/users response a userId could have multiple roles, if it is present in the usergroups table in multiple rows (with different groupId). however, since we specify the groupId in the /group/{groupId}/users route, it makes sense that we only retrieve users that have that groupId. - in controller, get groupId from context - for each user obtained from the users table, call GetUserRoleByID function from usergroups model - store the roles obtained in an array - pass array to updated ListFrom function from users view, which now include a role attribute in its JSON response --- controller/users/list.go | 19 ++++++++++++++++++- model/usergroups.go | 8 ++++++++ view/users/list.go | 27 ++++++++++++++++----------- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/controller/users/list.go b/controller/users/list.go index a5a373d..c050cca 100644 --- a/controller/users/list.go +++ b/controller/users/list.go @@ -8,8 +8,10 @@ import ( "github.com/source-academy/stories-backend/controller" "github.com/source-academy/stories-backend/internal/auth" "github.com/source-academy/stories-backend/internal/database" + groupenums "github.com/source-academy/stories-backend/internal/enums/groups" apierrors "github.com/source-academy/stories-backend/internal/errors" userpermissiongroups "github.com/source-academy/stories-backend/internal/permissiongroups/users" + "github.com/source-academy/stories-backend/internal/usergroups" "github.com/source-academy/stories-backend/model" userviews "github.com/source-academy/stories-backend/view/users" ) @@ -36,6 +38,21 @@ func HandleList(w http.ResponseWriter, r *http.Request) error { return err } - controller.EncodeJSONResponse(w, userviews.ListFrom(users)) + groupId, err := usergroups.GetGroupIDFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + roles := make([]groupenums.Role, len(users)) + for i, user := range users { + roles[i], err = model.GetUserRoleByID(db, user.ID, *groupId) + if err != nil { + logrus.Error(err) + return err + } + } + + controller.EncodeJSONResponse(w, userviews.ListFrom(users, roles)) return nil } diff --git a/model/usergroups.go b/model/usergroups.go index 3bab68e..f01615e 100644 --- a/model/usergroups.go +++ b/model/usergroups.go @@ -38,3 +38,11 @@ func CreateUserGroup(db *gorm.DB, userGroup *UserGroup) error { } return nil } + +func GetUserRoleByID(db *gorm.DB, userID uint, groupID uint) (groupenums.Role, error) { + userGroup, err := GetUserGroupByID(db, userID, groupID) + if err != nil { + return userGroup.Role, database.HandleDBError(err, "userGroup") + } + return userGroup.Role, nil +} diff --git a/view/users/list.go b/view/users/list.go index dcf4e17..561935c 100644 --- a/view/users/list.go +++ b/view/users/list.go @@ -1,24 +1,29 @@ package userviews -import "github.com/source-academy/stories-backend/model" +import ( + groupenums "github.com/source-academy/stories-backend/internal/enums/groups" + "github.com/source-academy/stories-backend/model" +) type ListView struct { - ID uint `json:"id"` - Name string `json:"name"` - Username string `json:"username"` - LoginProvider string `json:"provider"` + ID uint `json:"id"` + Name string `json:"name"` + Username string `json:"username"` + LoginProvider string `json:"provider"` + Role groupenums.Role `json:"role"` } -func ListFrom(users []model.User) []ListView { +func ListFrom(users []model.User, roles []groupenums.Role) []ListView { usersListView := make([]ListView, len(users)) - for i, user := range users { + for i := 0; i < len(users); i++ { usersListView[i] = ListView{ // Unlike other views, we do not fallback an empty name to // the username for the users' list view. - ID: user.ID, - Name: user.FullName, - Username: user.Username, - LoginProvider: user.LoginProvider.ToString(), + ID: users[i].ID, + Name: users[i].FullName, + Username: users[i].Username, + LoginProvider: users[i].LoginProvider.ToString(), + Role: roles[i], } } return usersListView From 62d5baf360aa1f5d809e53aeb9fd0dce08b6cc14 Mon Sep 17 00:00:00 2001 From: Zsigmond Date: Mon, 12 Feb 2024 21:21:08 +0800 Subject: [PATCH 04/14] fix: DeleteUser in users model previously, the DeleteUser function was not working as it chained `.Delete(&user)` after `.First(&user)`. this resulted in a query as shown, and its corresponding error: * `ERROR: table name "users" specified more than once (SQLSTATE 42712) [8.059ms] [rows:1] UPDATE "users" SET "deleted_at"='2024-02-12 20:52:41.02' FROM "users" WHERE id = 4 AND "users"."deleted_at" IS NULL AND "users"."id" = 4` the intent of `.First(&user)` was likely to store the user to be deleted first in the `user` variable with the use of a `SELECT` SQL statement. however, chaining another method at the end of a finisher method likely led to some errors (see chaining [here](https://gorm.io/docs/method_chaining.html)). thus, this commit attempts to separate the two statements, preserving the initial intent of storing the user to be deleted before deleting, and then returning this user. --- model/users.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/model/users.go b/model/users.go index e2986ba..288ccc3 100644 --- a/model/users.go +++ b/model/users.go @@ -54,11 +54,19 @@ func DeleteUser(db *gorm.DB, userID int) (User, error) { err := db. Model(&user). Where("id = ?", userID). - First(&user). // store the value to be returned + First(&user). + Error + if err != nil { + return user, database.HandleDBError(err, "user") + } + + err = db. + Model(&user). Delete(&user). Error if err != nil { return user, database.HandleDBError(err, "user") } + return user, nil } From adecceb23c23fa13d4a3aee81266583e4aa42dc9 Mon Sep 17 00:00:00 2001 From: Zsigmond Date: Sun, 18 Feb 2024 23:08:08 +0800 Subject: [PATCH 05/14] feat: function to update row in users model --- controller/users/update.go | 0 internal/router/router.go | 1 + model/users.go | 13 +++++++++++++ 3 files changed, 14 insertions(+) create mode 100644 controller/users/update.go diff --git a/controller/users/update.go b/controller/users/update.go new file mode 100644 index 0000000..e69de29 diff --git a/internal/router/router.go b/internal/router/router.go index 9c70a40..269a151 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -64,6 +64,7 @@ func Setup(config *config.Config, injectMiddleWares []func(http.Handler) http.Ha r.Route("/users", func(r chi.Router) { r.Get("/", handleAPIError(users.HandleList)) r.Get("/{userID}", handleAPIError(users.HandleRead)) + r.Put("/{userID}/role", handleAPIError(users.HandleUpdate)) r.Delete("/{userID}", handleAPIError(users.HandleDelete)) r.Post("/", handleAPIError(users.HandleCreate)) r.Post("/batch", handleAPIError(usergroupscontroller.HandleBatchCreate)) diff --git a/model/users.go b/model/users.go index 288ccc3..d35e6eb 100644 --- a/model/users.go +++ b/model/users.go @@ -70,3 +70,16 @@ func DeleteUser(db *gorm.DB, userID int) (User, error) { return user, nil } + +func UpdateUser(db *gorm.DB, userID int, user *User) (User, error) { + err := db. + Model(&user). + Where("id = ?", userID). + First(&user). + Updates(&user). + Error + if err != nil { + return *user, database.HandleDBError(err, "user") + } + return *user, nil +} From 0fa8e0b09c46e6f7b08a50e1660a5a7e7c34fbda Mon Sep 17 00:00:00 2001 From: Zsigmond Date: Sun, 18 Feb 2024 23:59:46 +0800 Subject: [PATCH 06/14] feat: function to update row in usergroups model --- model/usergroups.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/model/usergroups.go b/model/usergroups.go index f01615e..102db8f 100644 --- a/model/usergroups.go +++ b/model/usergroups.go @@ -46,3 +46,17 @@ func GetUserRoleByID(db *gorm.DB, userID uint, groupID uint) (groupenums.Role, e } return userGroup.Role, nil } + +func UpdateUserGroupByUserID(db *gorm.DB, userID uint, userGroup *UserGroup) (UserGroup, error) { + err := db.Model(&userGroup). + Preload(clause.Associations). + Where(UserGroup{UserID: userID}). + First(&userGroup). + Updates(&userGroup). + Error + + if err != nil { + return *userGroup, database.HandleDBError(err, "userGroup") + } + return *userGroup, nil +} From fa80f01a18cb295517eeba3f7c9c940a751b616b Mon Sep 17 00:00:00 2001 From: Zsigmond Date: Mon, 19 Feb 2024 00:55:58 +0800 Subject: [PATCH 07/14] feat: add /users/{userID}/role put route missing validation for parameters, but seemed unnecessary since there is only one route with parameter validation (creating user) --- controller/usergroups/update.go | 86 +++++++++++++++++++++++++++++++++ controller/users/update.go | 0 internal/router/router.go | 2 +- model/usergroups.go | 3 +- params/usergroups/update.go | 16 ++++++ 5 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 controller/usergroups/update.go delete mode 100644 controller/users/update.go create mode 100644 params/usergroups/update.go diff --git a/controller/usergroups/update.go b/controller/usergroups/update.go new file mode 100644 index 0000000..9da58e8 --- /dev/null +++ b/controller/usergroups/update.go @@ -0,0 +1,86 @@ +package usergroups + +import ( + "encoding/json" + "fmt" + "net/http" + "strconv" + + "github.com/go-chi/chi/v5" + "github.com/sirupsen/logrus" + "github.com/source-academy/stories-backend/controller" + "github.com/source-academy/stories-backend/internal/auth" + "github.com/source-academy/stories-backend/internal/database" + apierrors "github.com/source-academy/stories-backend/internal/errors" + userpermissiongroups "github.com/source-academy/stories-backend/internal/permissiongroups/users" + "github.com/source-academy/stories-backend/model" + userparams "github.com/source-academy/stories-backend/params/users" + userviews "github.com/source-academy/stories-backend/view/users" +) + +func HandleUpdateRole(w http.ResponseWriter, r *http.Request) error { + userIDStr := chi.URLParam(r, "userID") + userID, err := strconv.Atoi(userIDStr) + if err != nil { + return apierrors.ClientBadRequestError{ + Message: fmt.Sprintf("Invalid userID: %v", err), + } + } + + err = auth.CheckPermissions(r, userpermissiongroups.Update(uint(userID))) + if err != nil { + logrus.Error(err) + return apierrors.ClientForbiddenError{ + Message: fmt.Sprintf("Error batch creating users: %v", err), + } + } + + var params userparams.UpdateRole + if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { + e, ok := err.(*json.UnmarshalTypeError) + if !ok { + logrus.Error(err) + return apierrors.ClientBadRequestError{ + Message: fmt.Sprintf("Bad JSON parsing: %v", err), + } + } + + // TODO: Investigate if we should use errors.Wrap instead + return apierrors.ClientUnprocessableEntityError{ + Message: fmt.Sprintf("Invalid JSON format: %s should be a %s.", e.Field, e.Type), + } + } + + // TODO: add validation for updating user? + // err = params.Validate() + // if err != nil { + // logrus.Error(err) + // return apierrors.ClientUnprocessableEntityError{ + // Message: fmt.Sprintf("JSON validation failed: %v", err), + // } + // } + + userGroupModel := *params.ToModel() + + // Get DB instance + db, err := database.GetDBFrom(r) + if err != nil { + logrus.Error(err) + return err + } + + userGroup, err := model.UpdateUserGroupByUserID(db, uint(userID), &userGroupModel) + if err != nil { + logrus.Error(err) + return err + } + + user, err := model.GetUserByID(db, userID) + if err != nil { + logrus.Error(err) + return err + } + + controller.EncodeJSONResponse(w, userviews.SummaryFrom(user, userGroup)) + return nil +} diff --git a/controller/users/update.go b/controller/users/update.go deleted file mode 100644 index e69de29..0000000 diff --git a/internal/router/router.go b/internal/router/router.go index 269a151..0d2c041 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -64,7 +64,7 @@ func Setup(config *config.Config, injectMiddleWares []func(http.Handler) http.Ha r.Route("/users", func(r chi.Router) { r.Get("/", handleAPIError(users.HandleList)) r.Get("/{userID}", handleAPIError(users.HandleRead)) - r.Put("/{userID}/role", handleAPIError(users.HandleUpdate)) + r.Put("/{userID}/role", handleAPIError(usergroupscontroller.HandleUpdateRole)) r.Delete("/{userID}", handleAPIError(users.HandleDelete)) r.Post("/", handleAPIError(users.HandleCreate)) r.Post("/batch", handleAPIError(usergroupscontroller.HandleBatchCreate)) diff --git a/model/usergroups.go b/model/usergroups.go index 102db8f..2a11e9c 100644 --- a/model/usergroups.go +++ b/model/usergroups.go @@ -50,8 +50,7 @@ func GetUserRoleByID(db *gorm.DB, userID uint, groupID uint) (groupenums.Role, e func UpdateUserGroupByUserID(db *gorm.DB, userID uint, userGroup *UserGroup) (UserGroup, error) { err := db.Model(&userGroup). Preload(clause.Associations). - Where(UserGroup{UserID: userID}). - First(&userGroup). + Where("id = ?", userID). Updates(&userGroup). Error diff --git a/params/usergroups/update.go b/params/usergroups/update.go new file mode 100644 index 0000000..fdf4c71 --- /dev/null +++ b/params/usergroups/update.go @@ -0,0 +1,16 @@ +package userparams + +import ( + groupenums "github.com/source-academy/stories-backend/internal/enums/groups" + "github.com/source-academy/stories-backend/model" +) + +type UpdateRole struct { + Role groupenums.Role `json:"role"` +} + +func (params *UpdateRole) ToModel() *model.UserGroup { + return &model.UserGroup{ + Role: params.Role, + } +} From f708b88cf0bf9872d31d1976a6f375e99120a54c Mon Sep 17 00:00:00 2001 From: Zsigmond Date: Mon, 19 Feb 2024 01:10:35 +0800 Subject: [PATCH 08/14] fix: package name for update role's params --- controller/usergroups/update.go | 4 ++-- params/usergroups/update.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/controller/usergroups/update.go b/controller/usergroups/update.go index 9da58e8..679434c 100644 --- a/controller/usergroups/update.go +++ b/controller/usergroups/update.go @@ -14,7 +14,7 @@ import ( apierrors "github.com/source-academy/stories-backend/internal/errors" userpermissiongroups "github.com/source-academy/stories-backend/internal/permissiongroups/users" "github.com/source-academy/stories-backend/model" - userparams "github.com/source-academy/stories-backend/params/users" + usergroupparams "github.com/source-academy/stories-backend/params/usergroups" userviews "github.com/source-academy/stories-backend/view/users" ) @@ -35,7 +35,7 @@ func HandleUpdateRole(w http.ResponseWriter, r *http.Request) error { } } - var params userparams.UpdateRole + var params usergroupparams.UpdateRole if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { e, ok := err.(*json.UnmarshalTypeError) if !ok { diff --git a/params/usergroups/update.go b/params/usergroups/update.go index fdf4c71..c3951c0 100644 --- a/params/usergroups/update.go +++ b/params/usergroups/update.go @@ -1,4 +1,4 @@ -package userparams +package usergroupparams import ( groupenums "github.com/source-academy/stories-backend/internal/enums/groups" From 089952e01734c63a1d22d3598d68541d399afe13 Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sun, 12 May 2024 17:07:12 +0800 Subject: [PATCH 09/14] Use range iterator for users list view --- view/users/list.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/view/users/list.go b/view/users/list.go index 561935c..63acd49 100644 --- a/view/users/list.go +++ b/view/users/list.go @@ -15,14 +15,14 @@ type ListView struct { func ListFrom(users []model.User, roles []groupenums.Role) []ListView { usersListView := make([]ListView, len(users)) - for i := 0; i < len(users); i++ { + for i, user := range users { usersListView[i] = ListView{ // Unlike other views, we do not fallback an empty name to // the username for the users' list view. - ID: users[i].ID, - Name: users[i].FullName, - Username: users[i].Username, - LoginProvider: users[i].LoginProvider.ToString(), + ID: user.ID, + Name: user.FullName, + Username: user.Username, + LoginProvider: user.LoginProvider.ToString(), Role: roles[i], } } From 48f07684968be44aeaf47cfe7e41e447d993545b Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sun, 12 May 2024 17:13:20 +0800 Subject: [PATCH 10/14] Remove unused UpdateUser function --- model/users.go | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/model/users.go b/model/users.go index e15f61c..9265303 100644 --- a/model/users.go +++ b/model/users.go @@ -73,19 +73,5 @@ func DeleteUser(db *gorm.DB, userID int) (User, error) { if err != nil { return user, database.HandleDBError(err, "user") } - return user, nil } - -func UpdateUser(db *gorm.DB, userID int, user *User) (User, error) { - err := db. - Model(&user). - Where("id = ?", userID). - First(&user). - Updates(&user). - Error - if err != nil { - return *user, database.HandleDBError(err, "user") - } - return *user, nil -} From f8e1ab35de35337b5091f010d882f14ab09b8cda Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sun, 12 May 2024 17:15:48 +0800 Subject: [PATCH 11/14] Prevent self-update of roles --- internal/permissiongroups/users/users.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/permissiongroups/users/users.go b/internal/permissiongroups/users/users.go index 807830a..24ca482 100644 --- a/internal/permissiongroups/users/users.go +++ b/internal/permissiongroups/users/users.go @@ -30,7 +30,6 @@ func Update(userID uint) permissions.PermissionGroup { Groups: []permissions.PermissionGroup{ userpermissions. GetRolePermission(userpermissions.CanUpdateUsers), - IsSelf{UserID: userID}, }, } } From 553fff11b7a1ec705d1a59a9faceda0e4c948154 Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sun, 12 May 2024 17:16:39 +0800 Subject: [PATCH 12/14] Fix error message --- controller/usergroups/update.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/usergroups/update.go b/controller/usergroups/update.go index 679434c..1373ed5 100644 --- a/controller/usergroups/update.go +++ b/controller/usergroups/update.go @@ -31,7 +31,7 @@ func HandleUpdateRole(w http.ResponseWriter, r *http.Request) error { if err != nil { logrus.Error(err) return apierrors.ClientForbiddenError{ - Message: fmt.Sprintf("Error batch creating users: %v", err), + Message: fmt.Sprintf("Error updating user: %v", err), } } From cd0df8462e4895c4e135a8c3f169e17c242595eb Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sun, 12 May 2024 17:19:55 +0800 Subject: [PATCH 13/14] Add `UpdateRole` param validation --- controller/usergroups/update.go | 15 +++++++-------- params/usergroups/update.go | 11 +++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/controller/usergroups/update.go b/controller/usergroups/update.go index 1373ed5..3c79c8d 100644 --- a/controller/usergroups/update.go +++ b/controller/usergroups/update.go @@ -51,14 +51,13 @@ func HandleUpdateRole(w http.ResponseWriter, r *http.Request) error { } } - // TODO: add validation for updating user? - // err = params.Validate() - // if err != nil { - // logrus.Error(err) - // return apierrors.ClientUnprocessableEntityError{ - // Message: fmt.Sprintf("JSON validation failed: %v", err), - // } - // } + err = params.Validate() + if err != nil { + logrus.Error(err) + return apierrors.ClientUnprocessableEntityError{ + Message: fmt.Sprintf("JSON validation failed: %v", err), + } + } userGroupModel := *params.ToModel() diff --git a/params/usergroups/update.go b/params/usergroups/update.go index c3951c0..0151ce3 100644 --- a/params/usergroups/update.go +++ b/params/usergroups/update.go @@ -1,6 +1,8 @@ package usergroupparams import ( + "fmt" + groupenums "github.com/source-academy/stories-backend/internal/enums/groups" "github.com/source-academy/stories-backend/model" ) @@ -14,3 +16,12 @@ func (params *UpdateRole) ToModel() *model.UserGroup { Role: params.Role, } } + +func (params *UpdateRole) Validate() error { + // Extra params won't do anything, e.g. authorID can't be changed. + // TODO: Error on extra params? + if !params.Role.IsValid() { + return fmt.Errorf("Invalid role %s.", params.Role) + } + return nil +} From 35970d4e0558c364862997e5bf50292c9b1c8e33 Mon Sep 17 00:00:00 2001 From: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sun, 12 May 2024 17:26:26 +0800 Subject: [PATCH 14/14] Refactor logic --- controller/usergroups/update.go | 7 ++++--- model/usergroups.go | 15 +++++++++++---- params/usergroups/update.go | 5 +++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/controller/usergroups/update.go b/controller/usergroups/update.go index 3c79c8d..570195c 100644 --- a/controller/usergroups/update.go +++ b/controller/usergroups/update.go @@ -59,7 +59,7 @@ func HandleUpdateRole(w http.ResponseWriter, r *http.Request) error { } } - userGroupModel := *params.ToModel() + updateModel := *params.ToModel(uint(userID)) // Get DB instance db, err := database.GetDBFrom(r) @@ -68,13 +68,14 @@ func HandleUpdateRole(w http.ResponseWriter, r *http.Request) error { return err } - userGroup, err := model.UpdateUserGroupByUserID(db, uint(userID), &userGroupModel) + // TODO: Refactor logic + userGroup, err := model.UpdateUserGroupByUserID(db, updateModel.UserID, &updateModel) if err != nil { logrus.Error(err) return err } - user, err := model.GetUserByID(db, userID) + user, err := model.GetUserByID(db, int(userGroup.UserID)) if err != nil { logrus.Error(err) return err diff --git a/model/usergroups.go b/model/usergroups.go index 2a11e9c..25e094f 100644 --- a/model/usergroups.go +++ b/model/usergroups.go @@ -47,15 +47,22 @@ func GetUserRoleByID(db *gorm.DB, userID uint, groupID uint) (groupenums.Role, e return userGroup.Role, nil } -func UpdateUserGroupByUserID(db *gorm.DB, userID uint, userGroup *UserGroup) (UserGroup, error) { +func UpdateUserGroupByUserID(db *gorm.DB, userID uint, updates *UserGroup) (UserGroup, error) { + var userGroup UserGroup + + // Check if the user is trying to update another user's role + if updates.UserID != 0 && updates.UserID != userID { + return userGroup, database.HandleDBError(nil, "userGroup") + } + err := db.Model(&userGroup). Preload(clause.Associations). - Where("id = ?", userID). + Where(UserGroup{UserID: userID}). Updates(&userGroup). Error if err != nil { - return *userGroup, database.HandleDBError(err, "userGroup") + return userGroup, database.HandleDBError(err, "userGroup") } - return *userGroup, nil + return userGroup, nil } diff --git a/params/usergroups/update.go b/params/usergroups/update.go index 0151ce3..1f3843b 100644 --- a/params/usergroups/update.go +++ b/params/usergroups/update.go @@ -11,9 +11,10 @@ type UpdateRole struct { Role groupenums.Role `json:"role"` } -func (params *UpdateRole) ToModel() *model.UserGroup { +func (params *UpdateRole) ToModel(userID uint) *model.UserGroup { return &model.UserGroup{ - Role: params.Role, + UserID: userID, + Role: params.Role, } }