-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Change /groups/{group id}/users route (#115)
* fix: inject user id into context in development env * feat: add ID column to list view of Users * 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 * 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. * feat: function to update row in users model * feat: function to update row in usergroups model * 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) * fix: package name for update role's params * Use range iterator for users list view * Remove unused UpdateUser function * Prevent self-update of roles * Fix error message * Add `UpdateRole` param validation * Refactor logic --------- Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com>
- Loading branch information
1 parent
7288818
commit 840e79d
Showing
8 changed files
with
177 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
usergroupparams "github.com/source-academy/stories-backend/params/usergroups" | ||
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 updating user: %v", err), | ||
} | ||
} | ||
|
||
var params usergroupparams.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), | ||
} | ||
} | ||
|
||
err = params.Validate() | ||
if err != nil { | ||
logrus.Error(err) | ||
return apierrors.ClientUnprocessableEntityError{ | ||
Message: fmt.Sprintf("JSON validation failed: %v", err), | ||
} | ||
} | ||
|
||
updateModel := *params.ToModel(uint(userID)) | ||
|
||
// Get DB instance | ||
db, err := database.GetDBFrom(r) | ||
if err != nil { | ||
logrus.Error(err) | ||
return err | ||
} | ||
|
||
// TODO: Refactor logic | ||
userGroup, err := model.UpdateUserGroupByUserID(db, updateModel.UserID, &updateModel) | ||
if err != nil { | ||
logrus.Error(err) | ||
return err | ||
} | ||
|
||
user, err := model.GetUserByID(db, int(userGroup.UserID)) | ||
if err != nil { | ||
logrus.Error(err) | ||
return err | ||
} | ||
|
||
controller.EncodeJSONResponse(w, userviews.SummaryFrom(user, userGroup)) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package usergroupparams | ||
|
||
import ( | ||
"fmt" | ||
|
||
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(userID uint) *model.UserGroup { | ||
return &model.UserGroup{ | ||
UserID: userID, | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters