mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-27 12:08:02 -05:00
HistoryService: Add setHistory method
This is the transactional reimplementation of the business logic of the history controllers setHistory method (of the private api). This should prevent the problem that the history gets deleted, but a later error in the handling of the list of HistoryEntryImportDto let's the call fail. See also: https://docs.nestjs.com/techniques/database#transactions Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
parent
353f444f30
commit
ea4c58c68f
2 changed files with 58 additions and 19 deletions
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
BadRequestException,
|
||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
|
@ -16,9 +17,8 @@ import {
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
import { UsersService } from '../../../../users/users.service';
|
import { UsersService } from '../../../../users/users.service';
|
||||||
import { NotesService } from '../../../../notes/notes.service';
|
|
||||||
import { HistoryEntryDto } from '../../../../history/history-entry.dto';
|
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 { HistoryEntryImportDto } from '../../../../history/history-entry-import.dto';
|
||||||
import { HistoryEntryUpdateDto } from '../../../../history/history-entry-update.dto';
|
import { HistoryEntryUpdateDto } from '../../../../history/history-entry-update.dto';
|
||||||
import { ConsoleLoggerService } from '../../../../logger/console-logger.service';
|
import { ConsoleLoggerService } from '../../../../logger/console-logger.service';
|
||||||
|
@ -31,7 +31,6 @@ export class HistoryController {
|
||||||
private readonly logger: ConsoleLoggerService,
|
private readonly logger: ConsoleLoggerService,
|
||||||
private historyService: HistoryService,
|
private historyService: HistoryService,
|
||||||
private userService: UsersService,
|
private userService: UsersService,
|
||||||
private noteService: NotesService,
|
|
||||||
) {
|
) {
|
||||||
this.logger.setContext(HistoryController.name);
|
this.logger.setContext(HistoryController.name);
|
||||||
}
|
}
|
||||||
|
@ -60,21 +59,10 @@ export class HistoryController {
|
||||||
try {
|
try {
|
||||||
// ToDo: use actual user here
|
// ToDo: use actual user here
|
||||||
const user = await this.userService.getUserByUsername('hardcoded');
|
const user = await this.userService.getUserByUsername('hardcoded');
|
||||||
await this.historyService.deleteHistory(user);
|
await this.historyService.setHistory(user, history);
|
||||||
for (const historyEntry of history) {
|
|
||||||
const note = await this.noteService.getNoteByIdOrAlias(
|
|
||||||
historyEntry.note,
|
|
||||||
);
|
|
||||||
await this.historyService.createOrUpdateHistoryEntry(
|
|
||||||
note,
|
|
||||||
user,
|
|
||||||
historyEntry.pinStatus,
|
|
||||||
historyEntry.lastVisited,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof NotInDBError) {
|
if (e instanceof NotInDBError || e instanceof ForbiddenIdError) {
|
||||||
throw new NotFoundException(e.message);
|
throw new BadRequestException(e.message);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,22 @@ import { Injectable } from '@nestjs/common';
|
||||||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||||
import { HistoryEntryUpdateDto } from './history-entry-update.dto';
|
import { HistoryEntryUpdateDto } from './history-entry-update.dto';
|
||||||
import { HistoryEntryDto } from './history-entry.dto';
|
import { HistoryEntryDto } from './history-entry.dto';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectConnection, InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Connection, Repository } from 'typeorm';
|
||||||
import { HistoryEntry } from './history-entry.entity';
|
import { HistoryEntry } from './history-entry.entity';
|
||||||
import { UsersService } from '../users/users.service';
|
import { UsersService } from '../users/users.service';
|
||||||
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 { Note } from '../notes/note.entity';
|
import { Note } from '../notes/note.entity';
|
||||||
import { NotInDBError } from '../errors/errors';
|
import { NotInDBError } from '../errors/errors';
|
||||||
|
import { HistoryEntryImportDto } from './history-entry-import.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HistoryService {
|
export class HistoryService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly logger: ConsoleLoggerService,
|
private readonly logger: ConsoleLoggerService,
|
||||||
|
@InjectConnection()
|
||||||
|
private connection: Connection,
|
||||||
@InjectRepository(HistoryEntry)
|
@InjectRepository(HistoryEntry)
|
||||||
private historyEntryRepository: Repository<HistoryEntry>,
|
private historyEntryRepository: Repository<HistoryEntry>,
|
||||||
private usersService: UsersService,
|
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<void> {
|
||||||
|
await this.connection.transaction(async (manager) => {
|
||||||
|
const currentHistory = await manager.find<HistoryEntry>(HistoryEntry, {
|
||||||
|
where: { user: user },
|
||||||
|
relations: ['note', 'user'],
|
||||||
|
});
|
||||||
|
for (const entry of currentHistory) {
|
||||||
|
await manager.remove<HistoryEntry>(entry);
|
||||||
|
}
|
||||||
|
for (const historyEntry of history) {
|
||||||
|
this.notesService.checkNoteIdOrAlias(historyEntry.note);
|
||||||
|
const note = await manager.findOne<Note>(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<HistoryEntry>(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build HistoryEntryDto from a history entry.
|
* Build HistoryEntryDto from a history entry.
|
||||||
* @param {HistoryEntry} entry - the history entry to use
|
* @param {HistoryEntry} entry - the history entry to use
|
||||||
|
|
Loading…
Reference in a new issue