refactor(media-apis): Implement a decorator to convert header to Note instance

Just find the related note in an Interceptor (in both public and private routes)

Related issue: https://github.com/hedgedoc/hedgedoc/issues/1594

Signed-off-by: Lautaro Alvarez <lautarolalvarez@gmail.com>
Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
Lautaro Alvarez 2022-05-25 13:22:05 -03:00 committed by David Mehren
parent d36961878d
commit a0b5da6c8b
3 changed files with 47 additions and 10 deletions

View file

@ -6,7 +6,6 @@
import { import {
Controller, Controller,
Delete, Delete,
Headers,
Param, Param,
Post, Post,
UploadedFile, UploadedFile,
@ -25,7 +24,9 @@ import { MulterFile } from '../../../media/multer-file.interface';
import { Note } from '../../../notes/note.entity'; import { Note } from '../../../notes/note.entity';
import { NotesService } from '../../../notes/notes.service'; import { NotesService } from '../../../notes/notes.service';
import { User } from '../../../users/user.entity'; import { User } from '../../../users/user.entity';
import { NoteHeaderInterceptor } from '../../utils/note-header.interceptor';
import { OpenApi } from '../../utils/openapi.decorator'; import { OpenApi } from '../../utils/openapi.decorator';
import { RequestNote } from '../../utils/request-note.decorator';
import { RequestUser } from '../../utils/request-user.decorator'; import { RequestUser } from '../../utils/request-user.decorator';
@UseGuards(SessionGuard) @UseGuards(SessionGuard)
@ -59,6 +60,7 @@ export class MediaController {
description: 'ID or alias of the parent note', description: 'ID or alias of the parent note',
}) })
@UseInterceptors(FileInterceptor('file')) @UseInterceptors(FileInterceptor('file'))
@UseInterceptors(NoteHeaderInterceptor)
@OpenApi( @OpenApi(
{ {
code: 201, code: 201,
@ -72,13 +74,11 @@ export class MediaController {
) )
async uploadMedia( async uploadMedia(
@UploadedFile() file: MulterFile, @UploadedFile() file: MulterFile,
@Headers('HedgeDoc-Note') noteId: string, @RequestNote() note: Note,
@RequestUser() user: User, @RequestUser() user: User,
): Promise<MediaUploadDto> { ): Promise<MediaUploadDto> {
// TODO: Move getting the Note object into a decorator
const note: Note = await this.noteService.getNoteByIdOrAlias(noteId);
this.logger.debug( this.logger.debug(
`Recieved filename '${file.originalname}' for note '${noteId}' from user '${user.username}'`, `Recieved filename '${file.originalname}' for note '${note.id}' from user '${user.username}'`,
'uploadMedia', 'uploadMedia',
); );
const upload = await this.mediaService.saveFile(file.buffer, user, note); const upload = await this.mediaService.saveFile(file.buffer, user, note);

View file

@ -6,7 +6,6 @@
import { import {
Controller, Controller,
Delete, Delete,
Headers,
Param, Param,
Post, Post,
UploadedFile, UploadedFile,
@ -31,7 +30,9 @@ import { MulterFile } from '../../../media/multer-file.interface';
import { Note } from '../../../notes/note.entity'; import { Note } from '../../../notes/note.entity';
import { NotesService } from '../../../notes/notes.service'; import { NotesService } from '../../../notes/notes.service';
import { User } from '../../../users/user.entity'; import { User } from '../../../users/user.entity';
import { NoteHeaderInterceptor } from '../../utils/note-header.interceptor';
import { OpenApi } from '../../utils/openapi.decorator'; import { OpenApi } from '../../utils/openapi.decorator';
import { RequestNote } from '../../utils/request-note.decorator';
import { RequestUser } from '../../utils/request-user.decorator'; import { RequestUser } from '../../utils/request-user.decorator';
@UseGuards(TokenAuthGuard) @UseGuards(TokenAuthGuard)
@ -77,15 +78,14 @@ export class MediaController {
500, 500,
) )
@UseInterceptors(FileInterceptor('file')) @UseInterceptors(FileInterceptor('file'))
@UseInterceptors(NoteHeaderInterceptor)
async uploadMedia( async uploadMedia(
@RequestUser() user: User, @RequestUser() user: User,
@UploadedFile() file: MulterFile, @UploadedFile() file: MulterFile,
@Headers('HedgeDoc-Note') noteId: string, @RequestNote() note: Note,
): Promise<MediaUploadDto> { ): Promise<MediaUploadDto> {
// TODO: Move getting the Note object into a decorator
const note: Note = await this.noteService.getNoteByIdOrAlias(noteId);
this.logger.debug( this.logger.debug(
`Recieved filename '${file.originalname}' for note '${noteId}' from user '${user.username}'`, `Recieved filename '${file.originalname}' for note '${note.id}' from user '${user.username}'`,
'uploadMedia', 'uploadMedia',
); );
const upload = await this.mediaService.saveFile(file.buffer, user, note); const upload = await this.mediaService.saveFile(file.buffer, user, note);

View file

@ -0,0 +1,37 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
} from '@nestjs/common';
import { Request } from 'express';
import { Observable } from 'rxjs';
import { Note } from '../../notes/note.entity';
import { NotesService } from '../../notes/notes.service';
/**
* Saves the note identified by the `HedgeDoc-Note` header
* under the `note` property of the request object.
*/
@Injectable()
export class NoteHeaderInterceptor implements NestInterceptor {
constructor(private noteService: NotesService) {}
async intercept<T>(
context: ExecutionContext,
next: CallHandler,
): Promise<Observable<T>> {
const request: Request & {
note: Note;
} = context.switchToHttp().getRequest();
const noteId: string = request.headers['hedgedoc-note'] as string;
request.note = await this.noteService.getNoteByIdOrAlias(noteId);
return next.handle();
}
}