hedgedoc/src/notes/notes.service.ts
Philip Molares 195aeed5eb
NotesService: Add JsDoc strings to all functions
Signed-off-by: Philip Molares <philip.molares@udo.edu>
2021-02-20 11:28:19 +01:00

328 lines
9.7 KiB
TypeScript

/*
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { NotInDBError } from '../errors/errors';
import { ConsoleLoggerService } from '../logger/console-logger.service';
import { Revision } from '../revisions/revision.entity';
import { RevisionsService } from '../revisions/revisions.service';
import { User } from '../users/user.entity';
import { UsersService } from '../users/users.service';
import { NoteMetadataDto } from './note-metadata.dto';
import {
NotePermissionsDto,
NotePermissionsUpdateDto,
} from './note-permissions.dto';
import { NoteDto } from './note.dto';
import { Note } from './note.entity';
import { Tag } from './tag.entity';
import { HistoryEntry } from '../history/history-entry.entity';
@Injectable()
export class NotesService {
constructor(
private readonly logger: ConsoleLoggerService,
@InjectRepository(Note) private noteRepository: Repository<Note>,
@InjectRepository(Tag) private tagRepository: Repository<Tag>,
@Inject(UsersService) private usersService: UsersService,
@Inject(forwardRef(() => RevisionsService))
private revisionsService: RevisionsService,
) {
this.logger.setContext(NotesService.name);
}
/**
* @async
* Get all notes owned by a user.
* @param {User} user - the user who owns the notes
* @return {Note[]} arary of notes owned by the user
*/
getUserNotes(user: User): Note[] {
this.logger.warn('Using hardcoded data!');
return [
{
id: 'foobar-barfoo',
alias: null,
shortid: 'abc',
owner: user,
description: 'Very descriptive text.',
userPermissions: [],
groupPermissions: [],
historyEntries: [],
tags: [],
revisions: Promise.resolve([]),
authorColors: [],
title: 'Title!',
viewcount: 42,
},
];
}
/**
* @async
* Create a new note.
* @param {string} noteContent - the content the new note should have
* @param {string=} alias - a optional alias the note should have
* @param {User=} owner - the owner of the note
* @return {Note} the newly created note
*/
async createNote(
noteContent: string,
alias?: NoteMetadataDto['alias'],
owner?: User,
): Promise<Note> {
const newNote = Note.create();
newNote.revisions = Promise.resolve([
//TODO: Calculate patch
Revision.create(noteContent, noteContent),
]);
if (alias) {
newNote.alias = alias;
}
if (owner) {
newNote.historyEntries = [HistoryEntry.create(owner)];
newNote.owner = owner;
}
try {
return await this.noteRepository.save(newNote);
} catch {
this.logger.debug(
`A note with the alias '${alias}' already exists.`,
'createNote',
);
throw new AlreadyInDBError(
`A note with the alias '${alias}' already exists.`,
);
}
}
/**
* @async
* Get the current content of the note.
* @param {Note} note - the note to use
* @return {string} the content of the note
*/
async getNoteContentByNote(note: Note): Promise<string> {
return (await this.getLatestRevision(note)).content;
}
/**
* @async
* Get the first revision of the note.
* @param {Note} note - the note to use
* @return {Revision} the first revision of the note
*/
async getLatestRevision(note: Note): Promise<Revision> {
return this.revisionsService.getLatestRevision(note.id);
}
/**
* @async
* Get the last revision of the note.
* @param {Note} note - the note to use
* @return {Revision} the last revision of the note
*/
async getFirstRevision(note: Note): Promise<Revision> {
return this.revisionsService.getFirstRevision(note.id);
}
/**
* @async
* Get a note by either their id or alias.
* @param {string} noteIdOrAlias - the notes id or alias
* @return {Note} the note
* @throws {NotInDBError} there is no note with this id or alias
*/
async getNoteByIdOrAlias(noteIdOrAlias: string): Promise<Note> {
this.logger.debug(
`Trying to find note '${noteIdOrAlias}'`,
'getNoteByIdOrAlias',
);
const note = await this.noteRepository.findOne({
where: [
{
id: noteIdOrAlias,
},
{
alias: noteIdOrAlias,
},
],
relations: [
'authorColors',
'owner',
'groupPermissions',
'userPermissions',
],
});
if (note === undefined) {
this.logger.debug(
`Could not find note '${noteIdOrAlias}'`,
'getNoteByIdOrAlias',
);
throw new NotInDBError(
`Note with id/alias '${noteIdOrAlias}' not found.`,
);
}
this.logger.debug(`Found note '${noteIdOrAlias}'`, 'getNoteByIdOrAlias');
return note;
}
/**
* @async
* Delete a note by either their id or alias.
* @param {string} noteIdOrAlias - the notes id or alias
* @return {Note} the note, that was deleted
* @throws {NotInDBError} there is no note with this id or alias
*/
async deleteNoteByIdOrAlias(noteIdOrAlias: string): Promise<Note> {
const note = await this.getNoteByIdOrAlias(noteIdOrAlias);
return await this.noteRepository.remove(note);
}
/**
* @async
* Update a notes content. The note is specified by either their id or alias.
* @param {string} noteIdOrAlias - the notes id or alias
* @param {string} noteContent - the new content
* @return {Note} the note with a new revision and new content
* @throws {NotInDBError} there is no note with this id or alias
*/
async updateNoteByIdOrAlias(
noteIdOrAlias: string,
noteContent: string,
): Promise<Note> {
const note = await this.getNoteByIdOrAlias(noteIdOrAlias);
const revisions = await note.revisions;
//TODO: Calculate patch
revisions.push(Revision.create(noteContent, noteContent));
note.revisions = Promise.resolve(revisions);
return this.noteRepository.save(note);
}
/**
* @async
* Update a notes permissions. The note is specified by either their id or alias.
* @param {string} noteIdOrAlias - the notes id or alias
* @param {NotePermissionsUpdateDto} newPermissions - the permissions the not should be set to
* @return {Note} the note with the new permissions
* @throws {NotInDBError} there is no note with this id or alias
* @throws {PermissionsUpdateInconsistent} the new permissions specify a user or group twice.
*/
async updateNotePermissions(
noteIdOrAlias: string,
newPermissions: NotePermissionsUpdateDto,
): Note {
this.logger.warn('Using hardcoded data!', 'updateNotePermissions');
return {
id: 'foobar-barfoo',
alias: null,
shortid: 'abc',
owner: {
authTokens: [],
createdAt: new Date(),
displayName: 'hardcoded',
id: '1',
identities: [],
ownedNotes: [],
historyEntries: [],
updatedAt: new Date(),
userName: 'Testy',
groups: [],
},
description: 'Very descriptive text.',
userPermissions: [],
groupPermissions: [],
historyEntries: [],
tags: [],
revisions: Promise.resolve([]),
authorColors: [],
title: 'Title!',
viewcount: 42,
};
}
async getNoteContent(noteIdOrAlias: string): Promise<string> {
const note = await this.getNoteByIdOrAlias(noteIdOrAlias);
return this.getCurrentContent(note);
}
/**
* Map the tags of a note to a string array of the tags names.
* @param {Note} note - the note to use
* @return {string[]} string array of tags names
*/
toTagList(note: Note): string[] {
return note.tags.map((tag) => tag.name);
}
/**
* @async
* Build NotePermissionsDto from a note.
* @param {Note} note - the note to use
* @return {NotePermissionsDto} the built NotePermissionDto
*/
async toNotePermissionsDto(note: Note): Promise<NotePermissionsDto> {
return {
owner: this.usersService.toUserDto(note.owner),
sharedToUsers: note.userPermissions.map((noteUserPermission) => ({
user: this.usersService.toUserDto(noteUserPermission.user),
canEdit: noteUserPermission.canEdit,
})),
sharedToGroups: note.groupPermissions.map((noteGroupPermission) => ({
group: noteGroupPermission.group,
canEdit: noteGroupPermission.canEdit,
})),
};
}
/**
* @async
* Build NoteMetadataDto from a note.
* @param {Note} note - the note to use
* @return {NoteMetadataDto} the built NoteMetadataDto
*/
async toNoteMetadataDto(note: Note): Promise<NoteMetadataDto> {
return {
// TODO: Convert DB UUID to base64
id: note.id,
alias: note.alias,
title: note.title,
createTime: (await this.getFirstRevision(note)).createdAt,
description: note.description,
editedBy: note.authorColors.map(
(authorColor) => authorColor.user.userName,
),
// TODO: Extract into method
permissions: await this.toNotePermissionsDto(note),
tags: this.toTagList(note),
updateTime: (await this.getLatestRevision(note)).createdAt,
// TODO: Get actual updateUser
updateUser: {
displayName: 'Hardcoded User',
userName: 'hardcoded',
email: 'foo@example.com',
photo: '',
},
viewCount: 42,
};
}
/**
* @async
* Build NoteDto from a note.
* @param {Note} note - the note to use
* @return {NoteDto} the built NoteDto
*/
async toNoteDto(note: Note): Promise<NoteDto> {
return {
content: await this.getCurrentContent(note),
metadata: await this.toNoteMetadataDto(note),
editedByAtPosition: [],
};
}
}