mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2026-06-23 04:10:17 +00:00
refactor(controller): improve api responses of controller methods
This should drastically improve how accurate our api document is. Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
committed by
Erik Michelson
parent
c072fd657d
commit
3a4f2c8551
@@ -30,7 +30,7 @@ import { PermissionLevel } from '@hedgedoc/commons';
|
||||
import { NoteAliasesDto } from '../../../dtos/note-aliases.dto';
|
||||
|
||||
@UseGuards(SessionGuard)
|
||||
@OpenApi(401)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('alias')
|
||||
@Controller('alias')
|
||||
export class AliasController {
|
||||
|
||||
@@ -19,7 +19,7 @@ import { OpenApi } from '../../utils/decorators/openapi.decorator';
|
||||
import { RequestUserId } from '../../utils/decorators/request-user-id.decorator';
|
||||
|
||||
@UseGuards(SessionGuard)
|
||||
@OpenApi(401)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('tokens')
|
||||
@Controller('tokens')
|
||||
export class ApiTokensController {
|
||||
|
||||
@@ -27,7 +27,7 @@ export class GuestController {
|
||||
|
||||
@UseGuards(GuestsEnabledGuard)
|
||||
@Post('register')
|
||||
@OpenApi(201, 403)
|
||||
@OpenApi(201, 403, 429)
|
||||
async registerGuestUser(
|
||||
@Req() request: RequestWithSession,
|
||||
): Promise<GuestRegistrationResponseDto> {
|
||||
@@ -42,7 +42,7 @@ export class GuestController {
|
||||
|
||||
@UseGuards(GuestsEnabledGuard)
|
||||
@Post('login')
|
||||
@OpenApi(204, 400)
|
||||
@OpenApi(204, 400, 429)
|
||||
async loginGuestUser(
|
||||
@Req() request: RequestWithSession,
|
||||
@Body() loginDto: GuestLoginDto,
|
||||
|
||||
@@ -54,7 +54,7 @@ export class LocalController {
|
||||
|
||||
@UseGuards(LoginEnabledGuard, SessionGuard)
|
||||
@Put()
|
||||
@OpenApi(200, 400, 401)
|
||||
@OpenApi(200, 400, 401, 403, 429)
|
||||
async updatePassword(
|
||||
@RequestUserId() userId: number,
|
||||
@Body() changePasswordDto: UpdatePasswordDto,
|
||||
@@ -70,7 +70,7 @@ export class LocalController {
|
||||
|
||||
@UseGuards(LoginEnabledGuard)
|
||||
@Post('login')
|
||||
@OpenApi(201, 400, 401)
|
||||
@OpenApi(201, 400, 401, 429)
|
||||
async login(
|
||||
@Req()
|
||||
request: RequestWithSession,
|
||||
|
||||
@@ -44,7 +44,7 @@ export class OidcController {
|
||||
|
||||
@Get(':oidcIdentifier')
|
||||
@Redirect()
|
||||
@OpenApi(201, 400, 401)
|
||||
@OpenApi(201, 400, 401, 429)
|
||||
loginWithOpenIdConnect(
|
||||
@Req() request: RequestWithSession,
|
||||
@Param('oidcIdentifier') oidcIdentifier: string,
|
||||
|
||||
@@ -30,7 +30,7 @@ import { RequestUserId } from '../../utils/decorators/request-user-id.decorator'
|
||||
type OptionalNoteType = NoteType | '';
|
||||
|
||||
@UseGuards(SessionGuard)
|
||||
@OpenApi(401, 403)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('explore')
|
||||
@Controller('explore')
|
||||
export class ExploreController {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
||||
import { OpenApi } from '../../utils/decorators/openapi.decorator';
|
||||
|
||||
@UseGuards(SessionGuard)
|
||||
@OpenApi(401, 403)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('groups')
|
||||
@Controller('groups')
|
||||
export class GroupsController {
|
||||
|
||||
@@ -29,7 +29,7 @@ import { promisify } from 'node:util';
|
||||
import { RequestWithSession } from '../../utils/request.type';
|
||||
|
||||
@UseGuards(SessionGuard)
|
||||
@OpenApi(401)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('me')
|
||||
@Controller('me')
|
||||
export class MeController {
|
||||
|
||||
@@ -33,7 +33,7 @@ import { RequestUserId } from '../../utils/decorators/request-user-id.decorator'
|
||||
import { NoteHeaderInterceptor } from '../../utils/interceptors/note-header.interceptor';
|
||||
|
||||
@UseGuards(SessionGuard)
|
||||
@OpenApi(401)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('media')
|
||||
@Controller('media')
|
||||
export class MediaController {
|
||||
|
||||
@@ -53,7 +53,7 @@ import { RequestUserId } from '../../utils/decorators/request-user-id.decorator'
|
||||
import { GetNoteIdInterceptor } from '../../utils/interceptors/get-note-id.interceptor';
|
||||
|
||||
@UseGuards(SessionGuard, PermissionsGuard)
|
||||
@OpenApi(401, 403)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('notes')
|
||||
@Controller('notes')
|
||||
export class NotesController {
|
||||
@@ -181,7 +181,7 @@ export class NotesController {
|
||||
}
|
||||
|
||||
@Put(':noteAlias/metadata/permissions/users/:username')
|
||||
@OpenApi(200, 403, 404)
|
||||
@OpenApi(200, 404)
|
||||
@UseInterceptors(GetNoteIdInterceptor)
|
||||
@RequirePermission(PermissionLevel.FULL)
|
||||
async setUserPermission(
|
||||
@@ -194,9 +194,10 @@ export class NotesController {
|
||||
return await this.permissionService.getPermissionsDtoForNote(noteId);
|
||||
}
|
||||
|
||||
@Delete(':noteAlias/metadata/permissions/users/:username')
|
||||
@OpenApi(200, 400)
|
||||
@UseInterceptors(GetNoteIdInterceptor)
|
||||
@RequirePermission(PermissionLevel.FULL)
|
||||
@Delete(':noteAlias/metadata/permissions/users/:username')
|
||||
async removeUserPermission(
|
||||
@RequestNoteId() noteId: number,
|
||||
@Param('username') username: NoteUserPermissionEntryDto['username'],
|
||||
@@ -213,9 +214,10 @@ export class NotesController {
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':noteAlias/metadata/permissions/groups/:groupName')
|
||||
@OpenApi(200, 400, 404)
|
||||
@UseInterceptors(GetNoteIdInterceptor)
|
||||
@RequirePermission(PermissionLevel.FULL)
|
||||
@Put(':noteAlias/metadata/permissions/groups/:groupName')
|
||||
async setGroupPermission(
|
||||
@RequestNoteId() noteId: number,
|
||||
@Param('groupName') groupName: NoteGroupPermissionUpdateDto['groupName'],
|
||||
@@ -235,10 +237,11 @@ export class NotesController {
|
||||
return await this.permissionService.getPermissionsDtoForNote(noteId);
|
||||
}
|
||||
|
||||
@Delete(':noteAlias/metadata/permissions/groups/:groupName')
|
||||
@OpenApi(200, 404)
|
||||
@UseInterceptors(GetNoteIdInterceptor)
|
||||
@RequirePermission(PermissionLevel.FULL)
|
||||
@UseGuards(PermissionsGuard)
|
||||
@Delete(':noteAlias/metadata/permissions/groups/:groupName')
|
||||
async removeGroupPermission(
|
||||
@RequestNoteId() noteId: number,
|
||||
@Param('groupName') groupName: NoteGroupPermissionEntryDto['groupName'],
|
||||
|
||||
@@ -14,6 +14,7 @@ import { UsersService } from '../../../users/users.service';
|
||||
import { OpenApi } from '../../utils/decorators/openapi.decorator';
|
||||
|
||||
@ApiTags('users')
|
||||
@OpenApi(403, 429)
|
||||
@Controller('users')
|
||||
export class UsersController {
|
||||
constructor(
|
||||
|
||||
@@ -29,7 +29,7 @@ import { RequestUserId } from '../../utils/decorators/request-user-id.decorator'
|
||||
import { ApiTokenGuard } from '../../utils/guards/api-token.guard';
|
||||
|
||||
@UseGuards(ApiTokenGuard)
|
||||
@OpenApi(401)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('alias')
|
||||
@ApiSecurity('token')
|
||||
@Controller('alias')
|
||||
@@ -50,7 +50,6 @@ export class AliasController {
|
||||
description: 'The new alias',
|
||||
schema: AliasSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async addAlias(
|
||||
@@ -74,7 +73,6 @@ export class AliasController {
|
||||
description: 'The updated aliases',
|
||||
schema: AliasSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async makeAliasPrimary(
|
||||
@@ -102,7 +100,6 @@ export class AliasController {
|
||||
description: 'The aliases was deleted',
|
||||
},
|
||||
400,
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async removeAlias(@RequestUserId() user: number, @Param('alias') alias: string): Promise<void> {
|
||||
|
||||
@@ -25,7 +25,7 @@ import { RequestUserId } from '../../utils/decorators/request-user-id.decorator'
|
||||
import { ApiTokenGuard } from '../../utils/guards/api-token.guard';
|
||||
|
||||
@UseGuards(ApiTokenGuard)
|
||||
@OpenApi(401)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('me')
|
||||
@ApiSecurity('token')
|
||||
@Controller('me')
|
||||
|
||||
@@ -33,7 +33,7 @@ import { ApiTokenGuard } from '../../utils/guards/api-token.guard';
|
||||
import { NoteHeaderInterceptor } from '../../utils/interceptors/note-header.interceptor';
|
||||
|
||||
@UseGuards(ApiTokenGuard)
|
||||
@OpenApi(401)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('media')
|
||||
@ApiSecurity('token')
|
||||
@Controller('media')
|
||||
@@ -70,7 +70,6 @@ export class MediaController {
|
||||
schema: MediaUploadSchema,
|
||||
},
|
||||
400,
|
||||
403,
|
||||
404,
|
||||
500,
|
||||
)
|
||||
@@ -105,7 +104,7 @@ export class MediaController {
|
||||
}
|
||||
|
||||
@Delete(':uuid')
|
||||
@OpenApi(204, 403, 404, 500)
|
||||
@OpenApi(204, 404, 500)
|
||||
async deleteMedia(@RequestUserId() userId: number, @Param('uuid') uuid: string): Promise<void> {
|
||||
const mediaUpload = await this.mediaService.findUploadByUuid(uuid);
|
||||
if (await this.permissionsService.checkMediaDeletePermission(userId, uuid)) {
|
||||
|
||||
@@ -49,7 +49,7 @@ import { ApiTokenGuard } from '../../utils/guards/api-token.guard';
|
||||
import { GetNoteIdInterceptor } from '../../utils/interceptors/get-note-id.interceptor';
|
||||
|
||||
@UseGuards(ApiTokenGuard, PermissionsGuard)
|
||||
@OpenApi(401)
|
||||
@OpenApi(401, 403, 429)
|
||||
@ApiTags('notes')
|
||||
@ApiSecurity('token')
|
||||
@Controller('notes')
|
||||
@@ -68,7 +68,7 @@ export class NotesController {
|
||||
|
||||
@RequirePermission(PermissionLevel.FULL)
|
||||
@Post()
|
||||
@OpenApi(201, 403, 409, 413)
|
||||
@OpenApi(201, 409, 413)
|
||||
async createNote(
|
||||
@RequestUserId() userId: number,
|
||||
@MarkdownBody() text: string,
|
||||
@@ -86,7 +86,6 @@ export class NotesController {
|
||||
description: 'Get information about the newly created note',
|
||||
schema: NoteSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async getNote(
|
||||
@@ -105,7 +104,6 @@ export class NotesController {
|
||||
schema: NoteSchema,
|
||||
},
|
||||
400,
|
||||
403,
|
||||
409,
|
||||
413,
|
||||
)
|
||||
@@ -122,7 +120,7 @@ export class NotesController {
|
||||
@UseInterceptors(GetNoteIdInterceptor)
|
||||
@RequirePermission(PermissionLevel.FULL)
|
||||
@Delete(':noteAlias')
|
||||
@OpenApi(204, 403, 404, 500)
|
||||
@OpenApi(204, 404, 500)
|
||||
async deleteNote(
|
||||
@RequestUserId() userId: number,
|
||||
@RequestNoteId() noteId: number,
|
||||
@@ -151,7 +149,6 @@ export class NotesController {
|
||||
description: 'The new, changed note',
|
||||
schema: NoteSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async updateNote(
|
||||
@@ -173,7 +170,6 @@ export class NotesController {
|
||||
description: 'The raw markdown content of the note',
|
||||
mimeType: 'text/markdown',
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async getNoteContent(
|
||||
@@ -192,7 +188,6 @@ export class NotesController {
|
||||
description: 'The metadata of the note',
|
||||
schema: NoteMetadataSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async getNoteMetadata(@RequestNoteId() noteId: number): Promise<NoteMetadataDto> {
|
||||
@@ -208,7 +203,6 @@ export class NotesController {
|
||||
description: 'Get the permissions for a note',
|
||||
schema: NotePermissionsSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async getPermissions(@RequestNoteId() noteId: number): Promise<NotePermissionsDto> {
|
||||
@@ -224,7 +218,6 @@ export class NotesController {
|
||||
description: 'Set the permissions for a user on a note',
|
||||
schema: NotePermissionsSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async setUserPermission(
|
||||
@@ -247,7 +240,6 @@ export class NotesController {
|
||||
description: 'Remove the permission for a user on a note',
|
||||
schema: NotePermissionsSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async removeUserPermission(
|
||||
@@ -269,7 +261,6 @@ export class NotesController {
|
||||
description: 'Set the permissions for a group on a note',
|
||||
schema: NotePermissionsSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async setGroupPermission(
|
||||
@@ -292,7 +283,6 @@ export class NotesController {
|
||||
description: 'Remove the permission for a group on a note',
|
||||
schema: NotePermissionsSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async removeGroupPermission(
|
||||
@@ -313,7 +303,6 @@ export class NotesController {
|
||||
description: 'Changes the owner of the note',
|
||||
schema: NoteSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async changeOwner(
|
||||
@@ -335,7 +324,6 @@ export class NotesController {
|
||||
description: 'Changes the owner of the note',
|
||||
schema: NoteSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async change(
|
||||
@@ -357,7 +345,6 @@ export class NotesController {
|
||||
isArray: true,
|
||||
schema: RevisionMetadataSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async getNoteRevisions(@RequestNoteId() noteId: number): Promise<RevisionMetadataDto[]> {
|
||||
@@ -373,7 +360,6 @@ export class NotesController {
|
||||
description: 'Revision of the note for the given id or aliases',
|
||||
schema: RevisionSchema,
|
||||
},
|
||||
403,
|
||||
404,
|
||||
)
|
||||
async getNoteRevision(@Param('revisionUuid') revisionUuid: string): Promise<RevisionDto> {
|
||||
|
||||
@@ -4,36 +4,53 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { applyDecorators, Header, HttpCode } from '@nestjs/common';
|
||||
import type { ApiResponseNoStatusOptions } from '@nestjs/swagger';
|
||||
import {
|
||||
ApiBadRequestResponse,
|
||||
ApiConflictResponse,
|
||||
ApiCreatedResponse,
|
||||
ApiForbiddenResponse,
|
||||
ApiFoundResponse,
|
||||
ApiInternalServerErrorResponse,
|
||||
ApiNoContentResponse,
|
||||
ApiNotFoundResponse,
|
||||
ApiOkResponse,
|
||||
ApiProduces,
|
||||
ApiResponseNoStatusOptions,
|
||||
ApiTooManyRequestsResponse,
|
||||
ApiUnauthorizedResponse,
|
||||
} from '@nestjs/swagger';
|
||||
import { zodToOpenAPI } from 'nestjs-zod';
|
||||
import { ZodSchema } from 'zod';
|
||||
import type { ZodSchema } from 'zod';
|
||||
|
||||
import {
|
||||
badRequestDescription,
|
||||
conflictDescription,
|
||||
createdDescription,
|
||||
forbiddenDescription,
|
||||
foundDescription,
|
||||
internalServerErrorDescription,
|
||||
noContentDescription,
|
||||
notFoundDescription,
|
||||
okDescription,
|
||||
payloadTooLargeDescription,
|
||||
tooManyRequestsDescription,
|
||||
unauthorizedDescription,
|
||||
} from '../descriptions';
|
||||
|
||||
export type HttpStatusCodes = 200 | 201 | 204 | 302 | 400 | 401 | 403 | 404 | 409 | 413 | 500 | 503;
|
||||
export type HttpStatusCodes =
|
||||
| 200
|
||||
| 201
|
||||
| 204
|
||||
| 302
|
||||
| 400
|
||||
| 401
|
||||
| 403
|
||||
| 404
|
||||
| 409
|
||||
| 413
|
||||
| 429
|
||||
| 500
|
||||
| 503;
|
||||
|
||||
/**
|
||||
* Defines what the open api route should document.
|
||||
@@ -154,6 +171,13 @@ export const OpenApi = (
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 403:
|
||||
decoratorsToApply.push(
|
||||
ApiForbiddenResponse({
|
||||
description: description ?? forbiddenDescription,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 404:
|
||||
decoratorsToApply.push(
|
||||
ApiNotFoundResponse({
|
||||
@@ -175,6 +199,13 @@ export const OpenApi = (
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 429:
|
||||
decoratorsToApply.push(
|
||||
ApiTooManyRequestsResponse({
|
||||
description: description ?? tooManyRequestsDescription,
|
||||
}),
|
||||
);
|
||||
break;
|
||||
case 500:
|
||||
decoratorsToApply.push(
|
||||
ApiInternalServerErrorResponse({
|
||||
|
||||
@@ -12,10 +12,9 @@ export const badRequestDescription = "The request is malformed and can't be proc
|
||||
export const unauthorizedDescription = 'Authorization information is missing or invalid';
|
||||
export const forbiddenDescription = 'Access to the requested resource is not permitted';
|
||||
export const notFoundDescription = 'The requested resource was not found';
|
||||
export const successfullyDeletedDescription = 'The requested resource was successfully deleted';
|
||||
export const unprocessableEntityDescription = "The request change can't be processed";
|
||||
export const conflictDescription =
|
||||
'The request conflicts with the current state of the application';
|
||||
export const payloadTooLargeDescription =
|
||||
'The note is longer than the maximal allowed length of a note';
|
||||
export const tooManyRequestsDescription = 'The request triggered a rate limit.';
|
||||
export const internalServerErrorDescription = 'The request triggered an internal server error.';
|
||||
|
||||
Reference in New Issue
Block a user