diff --git a/backend/internal/controller/api_key_controller.go b/backend/internal/controller/api_key_controller.go index 66786e12..01bc0705 100644 --- a/backend/internal/controller/api_key_controller.go +++ b/backend/internal/controller/api_key_controller.go @@ -38,10 +38,10 @@ func NewApiKeyController(group *gin.RouterGroup, authMiddleware *middleware.Auth // @Summary List API keys // @Description Get a paginated list of API keys belonging to the current user // @Tags API Keys -// @Param page query int false "Page number, starting from 1" default(1) -// @Param limit query int false "Number of items per page" default(10) -// @Param sort_column query string false "Column to sort by" default("created_at") -// @Param sort_direction query string false "Sort direction (asc or desc)" default("desc") +// @Param pagination[page] query int false "Page number for pagination" default(1) +// @Param pagination[limit] query int false "Number of items per page" default(20) +// @Param sort[column] query string false "Column to sort by" +// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc") // @Success 200 {object} dto.Paginated[dto.ApiKeyDto] // @Router /api/api-keys [get] func (c *ApiKeyController) listApiKeysHandler(ctx *gin.Context) { diff --git a/backend/internal/controller/app_config_controller.go b/backend/internal/controller/app_config_controller.go index 9b79ef19..afbdeffb 100644 --- a/backend/internal/controller/app_config_controller.go +++ b/backend/internal/controller/app_config_controller.go @@ -85,7 +85,6 @@ func (acc *AppConfigController) listAppConfigHandler(c *gin.Context) { // @Accept json // @Produce json // @Success 200 {array} dto.AppConfigVariableDto -// @Security BearerAuth // @Router /application-configuration/all [get] func (acc *AppConfigController) listAllAppConfigHandler(c *gin.Context) { configuration := acc.appConfigService.ListAppConfig(true) @@ -107,7 +106,6 @@ func (acc *AppConfigController) listAllAppConfigHandler(c *gin.Context) { // @Produce json // @Param body body dto.AppConfigUpdateDto true "Application Configuration" // @Success 200 {array} dto.AppConfigVariableDto -// @Security BearerAuth // @Router /api/application-configuration [put] func (acc *AppConfigController) updateAppConfigHandler(c *gin.Context) { var input dto.AppConfigUpdateDto @@ -192,7 +190,6 @@ func (acc *AppConfigController) getBackgroundImageHandler(c *gin.Context) { // @Param light query boolean false "Light mode logo (true) or dark mode logo (false)" // @Param file formData file true "Logo image file" // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/application-configuration/logo [put] func (acc *AppConfigController) updateLogoHandler(c *gin.Context) { dbConfig := acc.appConfigService.GetDbConfig() @@ -218,7 +215,6 @@ func (acc *AppConfigController) updateLogoHandler(c *gin.Context) { // @Accept multipart/form-data // @Param file formData file true "Favicon file (.ico)" // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/application-configuration/favicon [put] func (acc *AppConfigController) updateFaviconHandler(c *gin.Context) { file, err := c.FormFile("file") @@ -242,7 +238,6 @@ func (acc *AppConfigController) updateFaviconHandler(c *gin.Context) { // @Accept multipart/form-data // @Param file formData file true "Background image file" // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/application-configuration/background-image [put] func (acc *AppConfigController) updateBackgroundImageHandler(c *gin.Context) { imageType := acc.appConfigService.GetDbConfig().BackgroundImageType.Value @@ -280,7 +275,6 @@ func (acc *AppConfigController) updateImage(c *gin.Context, imageName string, ol // @Description Manually trigger LDAP synchronization // @Tags Application Configuration // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/application-configuration/sync-ldap [post] func (acc *AppConfigController) syncLdapHandler(c *gin.Context) { err := acc.ldapService.SyncAll(c.Request.Context()) @@ -297,7 +291,6 @@ func (acc *AppConfigController) syncLdapHandler(c *gin.Context) { // @Description Send a test email to verify email configuration // @Tags Application Configuration // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/application-configuration/test-email [post] func (acc *AppConfigController) testEmailHandler(c *gin.Context) { userID := c.GetString("userID") diff --git a/backend/internal/controller/audit_log_controller.go b/backend/internal/controller/audit_log_controller.go index 28c03f57..fd41bd7b 100644 --- a/backend/internal/controller/audit_log_controller.go +++ b/backend/internal/controller/audit_log_controller.go @@ -34,10 +34,10 @@ type AuditLogController struct { // @Summary List audit logs // @Description Get a paginated list of audit logs for the current user // @Tags Audit Logs -// @Param page query int false "Page number, starting from 1" default(1) -// @Param limit query int false "Number of items per page" default(10) -// @Param sort_column query string false "Column to sort by" default("created_at") -// @Param sort_direction query string false "Sort direction (asc or desc)" default("desc") +// @Param pagination[page] query int false "Page number for pagination" default(1) +// @Param pagination[limit] query int false "Number of items per page" default(20) +// @Param sort[column] query string false "Column to sort by" +// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc") // @Success 200 {object} dto.Paginated[dto.AuditLogDto] // @Router /api/audit-logs [get] func (alc *AuditLogController) listAuditLogsForUserHandler(c *gin.Context) { @@ -82,13 +82,13 @@ func (alc *AuditLogController) listAuditLogsForUserHandler(c *gin.Context) { // @Summary List all audit logs // @Description Get a paginated list of all audit logs (admin only) // @Tags Audit Logs -// @Param page query int false "Page number, starting from 1" default(1) -// @Param limit query int false "Number of items per page" default(10) -// @Param sort_column query string false "Column to sort by" default("created_at") -// @Param sort_direction query string false "Sort direction (asc or desc)" default("desc") -// @Param user_id query string false "Filter by user ID" -// @Param event query string false "Filter by event type" -// @Param client_name query string false "Filter by client name" +// @Param pagination[page] query int false "Page number for pagination" default(1) +// @Param pagination[limit] query int false "Number of items per page" default(20) +// @Param sort[column] query string false "Column to sort by" +// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc") +// @Param filters[userId] query string false "Filter by user ID" +// @Param filters[event] query string false "Filter by event type" +// @Param filters[clientName] query string false "Filter by client name" // @Success 200 {object} dto.Paginated[dto.AuditLogDto] // @Router /api/audit-logs/all [get] func (alc *AuditLogController) listAllAuditLogsHandler(c *gin.Context) { diff --git a/backend/internal/controller/custom_claim_controller.go b/backend/internal/controller/custom_claim_controller.go index e2f67c47..839e0866 100644 --- a/backend/internal/controller/custom_claim_controller.go +++ b/backend/internal/controller/custom_claim_controller.go @@ -38,7 +38,6 @@ type CustomClaimController struct { // @Failure 401 {object} object "Unauthorized" // @Failure 403 {object} object "Forbidden" // @Failure 500 {object} object "Internal server error" -// @Security BearerAuth // @Router /api/custom-claims/suggestions [get] func (ccc *CustomClaimController) getSuggestionsHandler(c *gin.Context) { claims, err := ccc.customClaimService.GetSuggestions(c.Request.Context()) @@ -93,7 +92,6 @@ func (ccc *CustomClaimController) UpdateCustomClaimsForUserHandler(c *gin.Contex // @Param userGroupId path string true "User Group ID" // @Param claims body []dto.CustomClaimCreateDto true "List of custom claims to set for the user group" // @Success 200 {array} dto.CustomClaimDto "Updated custom claims" -// @Security BearerAuth // @Router /api/custom-claims/user-group/{userGroupId} [put] func (ccc *CustomClaimController) UpdateCustomClaimsForUserGroupHandler(c *gin.Context) { var input []dto.CustomClaimCreateDto diff --git a/backend/internal/controller/oidc_controller.go b/backend/internal/controller/oidc_controller.go index 68d7300d..49d3c088 100644 --- a/backend/internal/controller/oidc_controller.go +++ b/backend/internal/controller/oidc_controller.go @@ -69,7 +69,6 @@ type OidcController struct { // @Produce json // @Param request body dto.AuthorizeOidcClientRequestDto true "Authorization request parameters" // @Success 200 {object} dto.AuthorizeOidcClientResponseDto "Authorization code and callback URL" -// @Security BearerAuth // @Router /api/oidc/authorize [post] func (oc *OidcController) authorizeHandler(c *gin.Context) { var input dto.AuthorizeOidcClientRequestDto @@ -100,7 +99,6 @@ func (oc *OidcController) authorizeHandler(c *gin.Context) { // @Produce json // @Param request body dto.AuthorizationRequiredDto true "Authorization check parameters" // @Success 200 {object} object "{ \"authorizationRequired\": true/false }" -// @Security BearerAuth // @Router /api/oidc/authorization-required [post] func (oc *OidcController) authorizationConfirmationRequiredHandler(c *gin.Context) { var input dto.AuthorizationRequiredDto @@ -353,7 +351,6 @@ func (oc *OidcController) getClientMetaDataHandler(c *gin.Context) { // @Produce json // @Param id path string true "Client ID" // @Success 200 {object} dto.OidcClientWithAllowedUserGroupsDto "Client information" -// @Security BearerAuth // @Router /api/oidc/clients/{id} [get] func (oc *OidcController) getClientHandler(c *gin.Context) { clientId := c.Param("id") @@ -378,12 +375,11 @@ func (oc *OidcController) getClientHandler(c *gin.Context) { // @Description Get a paginated list of OIDC clients with optional search and sorting // @Tags OIDC // @Param search query string false "Search term to filter clients by name" -// @Param page query int false "Page number, starting from 1" default(1) -// @Param limit query int false "Number of items per page" default(10) -// @Param sort_column query string false "Column to sort by" default("name") -// @Param sort_direction query string false "Sort direction (asc or desc)" default("asc") +// @Param pagination[page] query int false "Page number for pagination" default(1) +// @Param pagination[limit] query int false "Number of items per page" default(20) +// @Param sort[column] query string false "Column to sort by" +// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc") // @Success 200 {object} dto.Paginated[dto.OidcClientWithAllowedGroupsCountDto] -// @Security BearerAuth // @Router /api/oidc/clients [get] func (oc *OidcController) listClientsHandler(c *gin.Context) { searchTerm := c.Query("search") @@ -429,7 +425,6 @@ func (oc *OidcController) listClientsHandler(c *gin.Context) { // @Produce json // @Param client body dto.OidcClientCreateDto true "Client information" // @Success 201 {object} dto.OidcClientWithAllowedUserGroupsDto "Created client" -// @Security BearerAuth // @Router /api/oidc/clients [post] func (oc *OidcController) createClientHandler(c *gin.Context) { var input dto.OidcClientCreateDto @@ -459,7 +454,6 @@ func (oc *OidcController) createClientHandler(c *gin.Context) { // @Tags OIDC // @Param id path string true "Client ID" // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/oidc/clients/{id} [delete] func (oc *OidcController) deleteClientHandler(c *gin.Context) { err := oc.oidcService.DeleteClient(c.Request.Context(), c.Param("id")) @@ -480,7 +474,6 @@ func (oc *OidcController) deleteClientHandler(c *gin.Context) { // @Param id path string true "Client ID" // @Param client body dto.OidcClientCreateDto true "Client information" // @Success 200 {object} dto.OidcClientWithAllowedUserGroupsDto "Updated client" -// @Security BearerAuth // @Router /api/oidc/clients/{id} [put] func (oc *OidcController) updateClientHandler(c *gin.Context) { var input dto.OidcClientCreateDto @@ -511,7 +504,6 @@ func (oc *OidcController) updateClientHandler(c *gin.Context) { // @Produce json // @Param id path string true "Client ID" // @Success 200 {object} object "{ \"secret\": \"string\" }" -// @Security BearerAuth // @Router /api/oidc/clients/{id}/secret [post] func (oc *OidcController) createClientSecretHandler(c *gin.Context) { secret, err := oc.oidcService.CreateClientSecret(c.Request.Context(), c.Param("id")) @@ -552,7 +544,6 @@ func (oc *OidcController) getClientLogoHandler(c *gin.Context) { // @Param id path string true "Client ID" // @Param file formData file true "Logo image file (PNG, JPG, or SVG, max 2MB)" // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/oidc/clients/{id}/logo [post] func (oc *OidcController) updateClientLogoHandler(c *gin.Context) { file, err := c.FormFile("file") @@ -576,7 +567,6 @@ func (oc *OidcController) updateClientLogoHandler(c *gin.Context) { // @Tags OIDC // @Param id path string true "Client ID" // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/oidc/clients/{id}/logo [delete] func (oc *OidcController) deleteClientLogoHandler(c *gin.Context) { err := oc.oidcService.DeleteClientLogo(c.Request.Context(), c.Param("id")) @@ -597,7 +587,6 @@ func (oc *OidcController) deleteClientLogoHandler(c *gin.Context) { // @Param id path string true "Client ID" // @Param groups body dto.OidcUpdateAllowedUserGroupsDto true "User group IDs" // @Success 200 {object} dto.OidcClientDto "Updated client" -// @Security BearerAuth // @Router /api/oidc/clients/{id}/allowed-user-groups [put] func (oc *OidcController) updateAllowedUserGroupsHandler(c *gin.Context) { var input dto.OidcUpdateAllowedUserGroupsDto @@ -646,12 +635,11 @@ func (oc *OidcController) deviceAuthorizationHandler(c *gin.Context) { // @Summary List authorized clients for current user // @Description Get a paginated list of OIDC clients that the current user has authorized // @Tags OIDC -// @Param page query int false "Page number, starting from 1" default(1) -// @Param limit query int false "Number of items per page" default(10) -// @Param sort_column query string false "Column to sort by" default("name") -// @Param sort_direction query string false "Sort direction (asc or desc)" default("asc") +// @Param pagination[page] query int false "Page number for pagination" default(1) +// @Param pagination[limit] query int false "Number of items per page" default(20) +// @Param sort[column] query string false "Column to sort by" +// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc") // @Success 200 {object} dto.Paginated[dto.AuthorizedOidcClientDto] -// @Security BearerAuth // @Router /api/oidc/users/me/clients [get] func (oc *OidcController) listOwnAuthorizedClientsHandler(c *gin.Context) { userID := c.GetString("userID") @@ -663,12 +651,11 @@ func (oc *OidcController) listOwnAuthorizedClientsHandler(c *gin.Context) { // @Description Get a paginated list of OIDC clients that a specific user has authorized // @Tags OIDC // @Param id path string true "User ID" -// @Param page query int false "Page number, starting from 1" default(1) -// @Param limit query int false "Number of items per page" default(10) -// @Param sort_column query string false "Column to sort by" default("name") -// @Param sort_direction query string false "Sort direction (asc or desc)" default("asc") +// @Param pagination[page] query int false "Page number for pagination" default(1) +// @Param pagination[limit] query int false "Number of items per page" default(20) +// @Param sort[column] query string false "Column to sort by" +// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc") // @Success 200 {object} dto.Paginated[dto.AuthorizedOidcClientDto] -// @Security BearerAuth // @Router /api/oidc/users/{id}/clients [get] func (oc *OidcController) listAuthorizedClientsHandler(c *gin.Context) { userID := c.Param("id") diff --git a/backend/internal/controller/user_controller.go b/backend/internal/controller/user_controller.go index dfa809e0..509b408c 100644 --- a/backend/internal/controller/user_controller.go +++ b/backend/internal/controller/user_controller.go @@ -85,10 +85,10 @@ func (uc *UserController) getUserGroupsHandler(c *gin.Context) { // @Description Get a paginated list of users with optional search and sorting // @Tags Users // @Param search query string false "Search term to filter users" -// @Param page query int false "Page number, starting from 1" default(1) -// @Param limit query int false "Number of items per page" default(10) -// @Param sort_column query string false "Column to sort by" default("created_at") -// @Param sort_direction query string false "Sort direction (asc or desc)" default("desc") +// @Param pagination[page] query int false "Page number for pagination" default(1) +// @Param pagination[limit] query int false "Number of items per page" default(20) +// @Param sort[column] query string false "Column to sort by" +// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc") // @Success 200 {object} dto.Paginated[dto.UserDto] // @Router /api/users [get] func (uc *UserController) listUsersHandler(c *gin.Context) { diff --git a/backend/internal/controller/user_group_controller.go b/backend/internal/controller/user_group_controller.go index 6176c3d1..1c0a24aa 100644 --- a/backend/internal/controller/user_group_controller.go +++ b/backend/internal/controller/user_group_controller.go @@ -40,10 +40,10 @@ type UserGroupController struct { // @Description Get a paginated list of user groups with optional search and sorting // @Tags User Groups // @Param search query string false "Search term to filter user groups by name" -// @Param page query int false "Page number, starting from 1" default(1) -// @Param limit query int false "Number of items per page" default(10) -// @Param sort_column query string false "Column to sort by" default("name") -// @Param sort_direction query string false "Sort direction (asc or desc)" default("asc") +// @Param pagination[page] query int false "Page number for pagination" default(1) +// @Param pagination[limit] query int false "Number of items per page" default(20) +// @Param sort[column] query string false "Column to sort by" +// @Param sort[direction] query string false "Sort direction (asc or desc)" default("asc") // @Success 200 {object} dto.Paginated[dto.UserGroupDtoWithUserCount] // @Router /api/user-groups [get] func (ugc *UserGroupController) list(c *gin.Context) { @@ -92,7 +92,6 @@ func (ugc *UserGroupController) list(c *gin.Context) { // @Produce json // @Param id path string true "User Group ID" // @Success 200 {object} dto.UserGroupDtoWithUsers -// @Security BearerAuth // @Router /api/user-groups/{id} [get] func (ugc *UserGroupController) get(c *gin.Context) { group, err := ugc.UserGroupService.Get(c.Request.Context(), c.Param("id")) @@ -118,7 +117,6 @@ func (ugc *UserGroupController) get(c *gin.Context) { // @Produce json // @Param userGroup body dto.UserGroupCreateDto true "User group information" // @Success 201 {object} dto.UserGroupDtoWithUsers "Created user group" -// @Security BearerAuth // @Router /api/user-groups [post] func (ugc *UserGroupController) create(c *gin.Context) { var input dto.UserGroupCreateDto @@ -151,7 +149,6 @@ func (ugc *UserGroupController) create(c *gin.Context) { // @Param id path string true "User Group ID" // @Param userGroup body dto.UserGroupCreateDto true "User group information" // @Success 200 {object} dto.UserGroupDtoWithUsers "Updated user group" -// @Security BearerAuth // @Router /api/user-groups/{id} [put] func (ugc *UserGroupController) update(c *gin.Context) { var input dto.UserGroupCreateDto @@ -183,7 +180,6 @@ func (ugc *UserGroupController) update(c *gin.Context) { // @Produce json // @Param id path string true "User Group ID" // @Success 204 "No Content" -// @Security BearerAuth // @Router /api/user-groups/{id} [delete] func (ugc *UserGroupController) delete(c *gin.Context) { if err := ugc.UserGroupService.Delete(c.Request.Context(), c.Param("id")); err != nil { @@ -203,7 +199,6 @@ func (ugc *UserGroupController) delete(c *gin.Context) { // @Param id path string true "User Group ID" // @Param users body dto.UserGroupUpdateUsersDto true "List of user IDs to assign to this group" // @Success 200 {object} dto.UserGroupDtoWithUsers -// @Security BearerAuth // @Router /api/user-groups/{id}/users [put] func (ugc *UserGroupController) updateUsers(c *gin.Context) { var input dto.UserGroupUpdateUsersDto diff --git a/backend/internal/utils/paging_util.go b/backend/internal/utils/paging_util.go index af85115d..4ccd0741 100644 --- a/backend/internal/utils/paging_util.go +++ b/backend/internal/utils/paging_util.go @@ -34,9 +34,12 @@ func PaginateAndSort(sortedPaginationRequest SortedPaginationRequest, query *gor sortField, sortFieldFound := reflect.TypeOf(result).Elem().Elem().FieldByName(capitalizedSortColumn) isSortable, _ := strconv.ParseBool(sortField.Tag.Get("sortable")) - isValidSortOrder := sort.Direction == "asc" || sort.Direction == "desc" - if sortFieldFound && isSortable && isValidSortOrder { + if sort.Direction == "" || (sort.Direction != "asc" && sort.Direction != "desc") { + sort.Direction = "asc" + } + + if sortFieldFound && isSortable { columnName := CamelCaseToSnakeCase(sort.Column) query = query.Clauses(clause.OrderBy{ Columns: []clause.OrderByColumn{