-
Notifications
You must be signed in to change notification settings - Fork 1
Feat/applications enabled #47
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
4ef4146
e8d48ad
fca0226
1267aa9
40c31ea
3800591
683b062
0475cb1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,16 +56,16 @@ type ApplicationWithQuestions struct { | |
|
|
||
| // getOrCreateApplicationHandler returns or creates the user's hackathon application | ||
| // | ||
| // @Summary Get or create application | ||
| // @Description Returns the authenticated user's hackathon application. If no application exists, creates a new draft application. | ||
| // @Tags hackers | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Success 200 {object} store.Application | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 500 {object} object{error=string} | ||
| // @Security CookieAuth | ||
| // @Router /applications/me [get] | ||
| // @Summary Get or create application | ||
| // @Description Returns the authenticated user's hackathon application. If no application exists, creates a new draft application. | ||
| // @Tags hackers | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Success 200 {object} store.Application | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 500 {object} object{error=string} | ||
| // @Security CookieAuth | ||
| // @Router /applications/me [get] | ||
| func (app *application) getOrCreateApplicationHandler(w http.ResponseWriter, r *http.Request) { | ||
| user := getUserFromContext(r.Context()) | ||
| if user == nil { | ||
|
|
@@ -117,19 +117,19 @@ func (app *application) getOrCreateApplicationHandler(w http.ResponseWriter, r * | |
|
|
||
| // updateApplicationHandler partially updates the authenticated user's application | ||
| // | ||
| // @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 | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Param application body UpdateApplicationPayload true "Fields to update" | ||
| // @Success 200 {object} store.Application | ||
| // @Failure 400 {object} object{error=string} | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 404 {object} object{error=string} | ||
| // @Failure 409 {object} object{error=string} "Application not in draft status" | ||
| // @Security CookieAuth | ||
| // @Router /applications/me [patch] | ||
| // @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 | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Param application body UpdateApplicationPayload true "Fields to update" | ||
| // @Success 200 {object} store.Application | ||
| // @Failure 400 {object} object{error=string} | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 404 {object} object{error=string} | ||
| // @Failure 409 {object} object{error=string} "Application not in draft status" | ||
| // @Security CookieAuth | ||
| // @Router /applications/me [patch] | ||
| func (app *application) updateApplicationHandler(w http.ResponseWriter, r *http.Request) { | ||
| user := getUserFromContext(r.Context()) | ||
| if user == nil { | ||
|
|
@@ -255,17 +255,17 @@ func (app *application) updateApplicationHandler(w http.ResponseWriter, r *http. | |
|
|
||
| // submitApplicationHandler submits the authenticated user's application for review | ||
| // | ||
| // @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 | ||
| // @Produce json | ||
| // @Success 200 {object} store.Application | ||
| // @Failure 400 {object} object{error=string} "Missing required fields" | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 404 {object} object{error=string} | ||
| // @Failure 409 {object} object{error=string} "Application not in draft status" | ||
| // @Security CookieAuth | ||
| // @Router /applications/me/submit [post] | ||
| // @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 | ||
| // @Produce json | ||
| // @Success 200 {object} store.Application | ||
| // @Failure 400 {object} object{error=string} "Missing required fields" | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 404 {object} object{error=string} | ||
| // @Failure 409 {object} object{error=string} "Application not in draft status" | ||
| // @Security CookieAuth | ||
| // @Router /applications/me/submit [post] | ||
| func (app *application) submitApplicationHandler(w http.ResponseWriter, r *http.Request) { | ||
| user := getUserFromContext(r.Context()) | ||
| if user == nil { | ||
|
|
@@ -392,16 +392,16 @@ func (app *application) submitApplicationHandler(w http.ResponseWriter, r *http. | |
|
|
||
| // getApplicationStatsHandler returns aggregated statistics for all applications | ||
| // | ||
| // @Summary Get application stats (Admin) | ||
| // @Description Returns aggregated statistics for all applications | ||
| // @Tags admin/applications | ||
| // @Produce json | ||
| // @Success 200 {object} store.ApplicationStats | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 403 {object} object{error=string} | ||
| // @Failure 500 {object} object{error=string} | ||
| // @Security CookieAuth | ||
| // @Router /admin/applications/stats [get] | ||
| // @Summary Get application stats (Admin) | ||
| // @Description Returns aggregated statistics for all applications | ||
| // @Tags admin/applications | ||
| // @Produce json | ||
| // @Success 200 {object} store.ApplicationStats | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 403 {object} object{error=string} | ||
| // @Failure 500 {object} object{error=string} | ||
| // @Security CookieAuth | ||
| // @Router /admin/applications/stats [get] | ||
| func (app *application) getApplicationStatsHandler(w http.ResponseWriter, r *http.Request) { | ||
| stats, err := app.store.Application.GetStats(r.Context()) | ||
| if err != nil { | ||
|
|
@@ -416,22 +416,22 @@ func (app *application) getApplicationStatsHandler(w http.ResponseWriter, r *htt | |
|
|
||
| // listApplicationsHandler lists all applications with cursor-based pagination | ||
| // | ||
| // @Summary List applications (Admin) | ||
| // @Description Lists all applications with cursor-based pagination and optional status filter | ||
| // @Tags admin/applications | ||
| // @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} | ||
| // @Failure 403 {object} object{error=string} | ||
| // @Failure 500 {object} object{error=string} | ||
| // @Security CookieAuth | ||
| // @Router /admin/applications [get] | ||
| // @Summary List applications (Admin) | ||
| // @Description Lists all applications with cursor-based pagination and optional status filter | ||
| // @Tags admin/applications | ||
| // @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} | ||
| // @Failure 403 {object} object{error=string} | ||
| // @Failure 500 {object} object{error=string} | ||
| // @Security CookieAuth | ||
| // @Router /admin/applications [get] | ||
| func (app *application) listApplicationsHandler(w http.ResponseWriter, r *http.Request) { | ||
| query := r.URL.Query() | ||
|
|
||
|
|
@@ -538,11 +538,19 @@ type EmailListResponse struct { | |
| Count int `json:"count"` | ||
| } | ||
|
|
||
| type ApplicationsEnabledResponse struct { | ||
|
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. Get and set response are the same struct just keep them as one ApplicationsEnabledResponse |
||
| Enabled bool `json:"enabled"` | ||
| } | ||
|
|
||
| type SetApplicationsEnabledResponse struct { | ||
| Enabled bool `json:"enabled"` //no validate required because bool enforces the only two possible values, which is what we want | ||
| } | ||
|
|
||
| // setApplicationStatus sets the final status on an application | ||
| // | ||
| // @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 +600,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 +649,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 | ||
|
|
@@ -691,3 +699,67 @@ func (app *application) getApplicantEmailsByStatusHandler(w http.ResponseWriter, | |
| } | ||
|
|
||
| } | ||
|
|
||
| // getApplicationsEnabled returns whether applications are currently open | ||
| // | ||
| // @Summary Get applications enabled status | ||
| // @Description Returns whether the application portal is currently open for submissions | ||
| // @Tags applications | ||
| // @Produce json | ||
| // @Success 200 {object} ApplicationsEnabledResponse | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Failure 500 {object} object{error=string} | ||
| // @Security CookieAuth | ||
| // @Router /applications/enabled [get] | ||
| func (app *application) getApplicationsEnabled(w http.ResponseWriter, r *http.Request) { | ||
|
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. Move these handlers to settings.go |
||
| enabled, err := app.store.Application.GetApplicationsEnabled(r.Context()) | ||
| if err != nil { | ||
| app.internalServerError(w, r, err) | ||
| return | ||
| } | ||
|
|
||
| response := ApplicationsEnabledResponse{ | ||
| Enabled: enabled, | ||
| } | ||
|
|
||
| if err = app.jsonResponse(w, http.StatusOK, response); err != nil { | ||
| app.internalServerError(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. add a return |
||
| } | ||
| } | ||
|
|
||
| // setApplicationsEnabled updates whether applications are currently open | ||
| // | ||
| // @Summary Set applications enabled status | ||
| // @Description Sets whether the application portal is currently open for submissions. Requires SuperAdmin privileges. | ||
| // @Tags superadmin | ||
| // @Produce json | ||
| // @Param enabled query bool true "Enable or disable applications" | ||
| // @Success 200 {object} SetApplicationsEnabledResponse | ||
| // @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/settings/applications-enabled [put] | ||
| func (app *application) setApplicationsEnabled(w http.ResponseWriter, r *http.Request) { | ||
| enabled, err := strconv.ParseBool(r.URL.Query().Get("enabled")) | ||
|
|
||
| if err != nil { | ||
| app.badRequestResponse(w, r, errors.New("enabled must be a boolean value")) | ||
| return | ||
| } | ||
|
|
||
| enabled, err = app.store.Application.SetApplicationsEnabled(r.Context(), enabled) | ||
| if err != nil { | ||
| app.internalServerError(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. add a return |
||
| } | ||
|
|
||
| //NOTE: Following existing design pattern of Get response and Set response structs | ||
| response := SetApplicationsEnabledResponse{ | ||
| Enabled: enabled, | ||
| } | ||
|
|
||
| if err = app.jsonResponse(w, http.StatusOK, response); err != nil { | ||
| app.internalServerError(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. Another return here |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,14 +20,14 @@ type UserResponse struct { | |
|
|
||
| // getCurrentUserHandler returns the authenticated user's profile | ||
| // | ||
| // @Summary Get current user | ||
| // @Description Returns the authenticated user's profile | ||
| // @Tags auth | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Success 200 {object} UserResponse | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Router /auth/me [get] | ||
| // @Summary Get current user | ||
|
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. ugh this is an issue were consistently having I'll standardize it to be tabs in the future. This is good tho |
||
| // @Description Returns the authenticated user's profile | ||
| // @Tags auth | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Success 200 {object} UserResponse | ||
| // @Failure 401 {object} object{error=string} | ||
| // @Router /auth/me [get] | ||
| func (app *application) getCurrentUserHandler(w http.ResponseWriter, r *http.Request) { | ||
| user := getUserFromContext(r.Context()) | ||
| if user == nil { | ||
|
|
@@ -57,15 +57,15 @@ type CheckEmailResponse struct { | |
|
|
||
| // checkEmailAuthMethodHandler checks if an email is registered and returns the auth method | ||
| // | ||
| // @Summary Check email auth method | ||
| // @Description Checks if an email is registered and returns the auth method used | ||
| // @Tags auth | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Param email query string true "Email address to check" | ||
| // @Success 200 {object} CheckEmailResponse | ||
| // @Failure 400 {object} object{error=string} | ||
| // @Router /auth/check-email [get] | ||
| // @Summary Check email auth method | ||
| // @Description Checks if an email is registered and returns the auth method used | ||
| // @Tags auth | ||
| // @Accept json | ||
| // @Produce json | ||
| // @Param email query string true "Email address to check" | ||
| // @Success 200 {object} CheckEmailResponse | ||
| // @Failure 400 {object} object{error=string} | ||
| // @Router /auth/check-email [get] | ||
| func (app *application) checkEmailAuthMethodHandler(w http.ResponseWriter, r *http.Request) { | ||
| email := r.URL.Query().Get("email") | ||
| if email == "" { | ||
|
|
||
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.
Move this to admin routes. gonna change implementation.