diff --git a/src/api/private/me/history/history.controller.ts b/src/api/private/me/history/history.controller.ts index da00d7223..f442ccee0 100644 --- a/src/api/private/me/history/history.controller.ts +++ b/src/api/private/me/history/history.controller.ts @@ -5,6 +5,7 @@ */ import { + BadRequestException, Body, Controller, Delete, @@ -16,9 +17,8 @@ import { } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { UsersService } from '../../../../users/users.service'; -import { NotesService } from '../../../../notes/notes.service'; import { HistoryEntryDto } from '../../../../history/history-entry.dto'; -import { NotInDBError } from '../../../../errors/errors'; +import { ForbiddenIdError, NotInDBError } from '../../../../errors/errors'; import { HistoryEntryImportDto } from '../../../../history/history-entry-import.dto'; import { HistoryEntryUpdateDto } from '../../../../history/history-entry-update.dto'; import { ConsoleLoggerService } from '../../../../logger/console-logger.service'; @@ -31,7 +31,6 @@ export class HistoryController { private readonly logger: ConsoleLoggerService, private historyService: HistoryService, private userService: UsersService, - private noteService: NotesService, ) { this.logger.setContext(HistoryController.name); } @@ -60,21 +59,10 @@ export class HistoryController { try { // ToDo: use actual user here const user = await this.userService.getUserByUsername('hardcoded'); - await this.historyService.deleteHistory(user); - for (const historyEntry of history) { - const note = await this.noteService.getNoteByIdOrAlias( - historyEntry.note, - ); - await this.historyService.createOrUpdateHistoryEntry( - note, - user, - historyEntry.pinStatus, - historyEntry.lastVisited, - ); - } + await this.historyService.setHistory(user, history); } catch (e) { - if (e instanceof NotInDBError) { - throw new NotFoundException(e.message); + if (e instanceof NotInDBError || e instanceof ForbiddenIdError) { + throw new BadRequestException(e.message); } throw e; } diff --git a/src/history/history.service.ts b/src/history/history.service.ts index d5f7c826b..fa4aed431 100644 --- a/src/history/history.service.ts +++ b/src/history/history.service.ts @@ -8,19 +8,22 @@ import { Injectable } from '@nestjs/common'; import { ConsoleLoggerService } from '../logger/console-logger.service'; import { HistoryEntryUpdateDto } from './history-entry-update.dto'; import { HistoryEntryDto } from './history-entry.dto'; -import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; +import { InjectConnection, InjectRepository } from '@nestjs/typeorm'; +import { Connection, Repository } from 'typeorm'; import { HistoryEntry } from './history-entry.entity'; import { UsersService } from '../users/users.service'; import { NotesService } from '../notes/notes.service'; import { User } from '../users/user.entity'; import { Note } from '../notes/note.entity'; import { NotInDBError } from '../errors/errors'; +import { HistoryEntryImportDto } from './history-entry-import.dto'; @Injectable() export class HistoryService { constructor( private readonly logger: ConsoleLoggerService, + @InjectConnection() + private connection: Connection, @InjectRepository(HistoryEntry) private historyEntryRepository: Repository, private usersService: UsersService, @@ -148,6 +151,54 @@ export class HistoryService { } } + /** + * @async + * Replace the user history with the provided history + * @param {User} user - the user that get's their history replaces + * @param {HistoryEntryImportDto[]} history + * @throws {ForbiddenIdError} one of the note ids or alias in the new history are forbidden + */ + async setHistory( + user: User, + history: HistoryEntryImportDto[], + ): Promise { + await this.connection.transaction(async (manager) => { + const currentHistory = await manager.find(HistoryEntry, { + where: { user: user }, + relations: ['note', 'user'], + }); + for (const entry of currentHistory) { + await manager.remove(entry); + } + for (const historyEntry of history) { + this.notesService.checkNoteIdOrAlias(historyEntry.note); + const note = await manager.findOne(Note, { + where: [ + { + id: historyEntry.note, + }, + { + alias: historyEntry.note, + }, + ], + }); + if (note === undefined) { + this.logger.debug( + `Could not find note '${historyEntry.note}'`, + 'setHistory', + ); + throw new NotInDBError( + `Note with id/alias '${historyEntry.note}' not found.`, + ); + } + const entry = HistoryEntry.create(user, note); + entry.pinStatus = historyEntry.pinStatus; + entry.updatedAt = historyEntry.lastVisited; + await manager.save(entry); + } + }); + } + /** * Build HistoryEntryDto from a history entry. * @param {HistoryEntry} entry - the history entry to use