-
Notifications
You must be signed in to change notification settings - Fork 2
Feat/super admin batch roles #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
fe9a0ec
ab637b9
7dc70f9
1ce02e9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you didn't accept the incoming changes when you merged main -> your branch, make sure to use what main has for these
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, look at the lost comment to see what im talking about |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,7 +58,7 @@ type ApplicationWithQuestions struct { | |
| // | ||
| // @Summary Get or create application | ||
| // @Description Returns the authenticated user's hackathon application. If no application exists, creates a new draft application. | ||
| // @Tags hackers | ||
| // @Tags applications | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you didn't accept the incoming changes when you merged main -> your branch, make sure to use what main has for these |
||
| // @Accept json | ||
| // @Produce json | ||
| // @Success 200 {object} store.Application | ||
|
|
@@ -119,7 +119,7 @@ func (app *application) getOrCreateApplicationHandler(w http.ResponseWriter, r * | |
| // | ||
| // @Summary Update application | ||
| // @Description Partially updates the authenticated user's application. Only fields included in the request body are updated. Application must be in draft status. | ||
| // @Tags hackers | ||
| // @Tags applications | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Param application body UpdateApplicationPayload true "Fields to update" | ||
|
|
@@ -257,7 +257,7 @@ func (app *application) updateApplicationHandler(w http.ResponseWriter, r *http. | |
| // | ||
| // @Summary Submit application | ||
| // @Description Submits the authenticated user's application for review. All required fields must be filled and acknowledgments must be accepted. Application must be in draft status. | ||
| // @Tags hackers | ||
| // @Tags applications | ||
| // @Produce json | ||
| // @Success 200 {object} store.Application | ||
| // @Failure 400 {object} object{error=string} "Missing required fields" | ||
|
|
@@ -394,7 +394,7 @@ func (app *application) submitApplicationHandler(w http.ResponseWriter, r *http. | |
| // | ||
| // @Summary Get application stats (Admin) | ||
| // @Description Returns aggregated statistics for all applications | ||
| // @Tags admin/applications | ||
| // @Tags admin | ||
| // @Produce json | ||
| // @Success 200 {object} store.ApplicationStats | ||
| // @Failure 401 {object} object{error=string} | ||
|
|
@@ -418,13 +418,12 @@ func (app *application) getApplicationStatsHandler(w http.ResponseWriter, r *htt | |
| // | ||
| // @Summary List applications (Admin) | ||
| // @Description Lists all applications with cursor-based pagination and optional status filter | ||
| // @Tags admin/applications | ||
| // @Tags admin | ||
| // @Produce json | ||
| // @Param cursor query string false "Pagination cursor" | ||
| // @Param status query string false "Filter by status (draft, submitted, accepted, rejected, waitlisted)" | ||
| // @Param limit query int false "Page size (default 50, max 100)" | ||
| // @Param direction query string false "Pagination direction: forward (default) or backward" | ||
| // @Param sort_by query string false "Sort column: created_at (default), accept_votes, reject_votes, waitlist_votes" | ||
| // @Success 200 {object} store.ApplicationListResult | ||
| // @Failure 400 {object} object{error=string} | ||
| // @Failure 401 {object} object{error=string} | ||
|
|
@@ -542,7 +541,7 @@ type EmailListResponse struct { | |
| // | ||
| // @Summary Set application status (Super Admin) | ||
| // @Description Sets the final status (accepted, rejected, or waitlisted) on an application | ||
| // @Tags superadmin/applications | ||
| // @Tags superadmin | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Param applicationID path string true "Application ID" | ||
|
|
@@ -592,7 +591,7 @@ func (app *application) setApplicationStatus(w http.ResponseWriter, r *http.Requ | |
| // | ||
| // @Summary Get application by ID (Admin) | ||
| // @Description Returns a single application by its ID with embedded short answer questions | ||
| // @Tags admin/applications | ||
| // @Tags admin | ||
| // @Produce json | ||
| // @Param applicationID path string true "Application ID" | ||
| // @Success 200 {object} ApplicationWithQuestions | ||
|
|
@@ -641,7 +640,7 @@ func (app *application) getApplication(w http.ResponseWriter, r *http.Request) { | |
| // | ||
| // @Summary Get applicant emails by status (Super Admin) | ||
| // @Description Returns a list of applicant emails filtered by application status (accepted, rejected, or waitlisted) | ||
| // @Tags superadmin/applications | ||
| // @Tags superadmin | ||
| // @Produce json | ||
| // @Param status query string true "Application status (accepted, rejected, or waitlisted)" | ||
| // @Success 200 {object} EmailListResponse | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same thing |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same thing |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same thing |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Request payload is swapped but should be fine: The response payload should be: you currently have: |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "errors" | ||
| "net/http" | ||
|
|
||
| "github.com/hackutd/portal/internal/store" | ||
| ) | ||
|
|
||
| type BatchUpdateRolesPayload struct { | ||
| UserIDs []string `json:"user_ids" validate:"required,min=1,max=50,dive,uuid"` | ||
| Role store.UserRole `json:"role" validate:"required,oneof=hacker admin"` | ||
| } | ||
|
|
||
| type BatchUpdateRolesResponse struct { | ||
| Users []*store.User `json:"users"` | ||
| } | ||
|
|
||
| // batchUpdateRolesHandler updates the role for a batch of users | ||
| // | ||
| // @Summary Batch update user roles (Super Admin) | ||
| // @Description Updates the role for up to 50 users. Cannot modify own role. | ||
| // @Tags superadmin | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Param payload body BatchUpdateRolesPayload true "User IDs and target role" | ||
| // @Success 200 {object} BatchUpdateRolesResponse | ||
| // @Failure 400 {object} object{error=string} | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 403 {object} object{error=string} | ||
| // @Failure 500 {object} object{error=string} | ||
| // @Security CookieAuth | ||
| // @Router /superadmin/users/role [patch] | ||
| func (app *application) batchUpdateRolesHandler(w http.ResponseWriter, r *http.Request) { | ||
| var req BatchUpdateRolesPayload | ||
| if err := readJSON(w, r, &req); err != nil { | ||
| app.badRequestResponse(w, r, err) | ||
| return | ||
| } | ||
|
|
||
| if err := Validate.Struct(req); err != nil { | ||
| app.badRequestResponse(w, r, err) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. give a proper error message, i thought you didn't implement this feature |
||
| return | ||
| } | ||
|
|
||
| caller := getUserFromContext(r.Context()) | ||
| if caller == nil { | ||
| app.internalServerError(w, r, errors.New("user not in context")) | ||
| return | ||
| } | ||
|
|
||
| for _, id := range req.UserIDs { | ||
| if id == caller.ID { | ||
| app.badRequestResponse(w, r, errors.New("cannot modify your own role")) | ||
| return | ||
| } | ||
| } | ||
|
|
||
| users, err := app.store.Users.BatchUpdateRoles(r.Context(), req.UserIDs, req.Role) | ||
| if err != nil { | ||
| app.internalServerError(w, r, err) | ||
| return | ||
| } | ||
|
|
||
| if len(users) != len(req.UserIDs) { | ||
| app.badRequestResponse(w, r, errors.New("one or more user IDs do not exist")) | ||
| return | ||
| } | ||
|
|
||
| if err := app.jsonResponse(w, http.StatusOK, BatchUpdateRolesResponse{Users: users}); err != nil { | ||
| app.internalServerError(w, r, err) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is like a 95% chance changing the allowedOrigins is not allowed, you shouldn't have to edit configs
Check w/ Caleb