From aaef0f72baa6be4db5c812682c653d6a7a8cf1b4 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Sun, 6 Jun 2021 17:46:32 +0200 Subject: [PATCH] feat: add list of aliases to note entity One of the aliases can be primary for each note, but all can be used to get information from the apis. Signed-off-by: Philip Molares --- docs/content/dev/db-schema.plantuml | 10 +++- src/notes/alias.entity.ts | 63 ++++++++++++++++++++++++++ src/notes/note-metadata.dto.ts | 16 +++++-- src/notes/note.entity.ts | 15 +++--- src/notes/notes.module.ts | 2 + src/notes/primary.value-transformer.ts | 22 +++++++++ 6 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 src/notes/alias.entity.ts create mode 100644 src/notes/primary.value-transformer.ts diff --git a/docs/content/dev/db-schema.plantuml b/docs/content/dev/db-schema.plantuml index 7a9239184..f3a918e0d 100644 --- a/docs/content/dev/db-schema.plantuml +++ b/docs/content/dev/db-schema.plantuml @@ -6,13 +6,20 @@ entity "note" { *id : uuid <> -- publicId: text - alias : text *viewCount : number *ownerId : uuid <> description: text title: text } +entity "alias" { + *id: uuid <> + --- + name: text + ' If the alias is primary. Can be NULL, which means it's not primary + primary: boolean +} + entity "user" { *id : uuid <> -- @@ -169,6 +176,7 @@ media_upload "0..*" -- "1" note note "1" -d- "1..*" revision note "1" - "0..*" history_entry note "0..*" -l- "0..*" tag +note "1" - "0..*" alias note "0..*" -- "0..*" group user "1..*" -- "0..*" group diff --git a/src/notes/alias.entity.ts b/src/notes/alias.entity.ts new file mode 100644 index 000000000..eb7e746ce --- /dev/null +++ b/src/notes/alias.entity.ts @@ -0,0 +1,63 @@ +/* + * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import { + Column, + Entity, + ManyToOne, + PrimaryGeneratedColumn, + Unique, +} from 'typeorm'; + +import { Note } from './note.entity'; +import { PrimaryValueTransformer } from './primary.value-transformer'; + +@Entity() +@Unique('Only one primary alias per note', ['note', 'primary']) +export class Alias { + @PrimaryGeneratedColumn('uuid') + id: string; + + /** + * the actual alias + */ + @Column({ + nullable: false, + unique: true, + }) + name: string; + + /** + * Is this alias the primary alias, by which people access the note? + */ + @Column({ + /* + Because of the @Unique at the top of this entity, this field must be saved as null instead of false in the DB. + If a non-primary alias would be saved with `primary: false` it would only be possible to have one non-primary and one primary alias. + But a nullable field does not have such problems. + This way the DB keeps track that one note really only has one primary alias. + */ + comment: + 'This field tells you if this is the primary alias of the note. If this field is null, that means this alias is not primary.', + nullable: true, + transformer: new PrimaryValueTransformer(), + }) + primary: boolean; + + @ManyToOne((_) => Note, (note) => note.aliases, { + onDelete: 'CASCADE', // This deletes the Alias, when the associated Note is deleted + }) + note: Note; + + // eslint-disable-next-line @typescript-eslint/no-empty-function + private constructor() {} + + static create(name: string, primary = false): Alias { + const alias = new Alias(); + alias.name = name; + alias.primary = primary; + return alias; + } +} diff --git a/src/notes/note-metadata.dto.ts b/src/notes/note-metadata.dto.ts index 9a588ab5f..48af104fc 100644 --- a/src/notes/note-metadata.dto.ts +++ b/src/notes/note-metadata.dto.ts @@ -25,13 +25,19 @@ export class NoteMetadataDto { id: string; /** - * Alias of the note - * Can be null + * All aliases of the note (including the primaryAlias) + */ + @IsArray() + @IsString({ each: true }) + @ApiProperty() + aliases: string[]; + + /** + * The primary alias of the note */ @IsString() - @IsOptional() - @ApiPropertyOptional() - alias: string | null; + @ApiProperty() + primaryAlias: string | null; /** * Title of the note diff --git a/src/notes/note.entity.ts b/src/notes/note.entity.ts index 916a14c9c..23c964e78 100644 --- a/src/notes/note.entity.ts +++ b/src/notes/note.entity.ts @@ -19,6 +19,7 @@ import { NoteGroupPermission } from '../permissions/note-group-permission.entity import { NoteUserPermission } from '../permissions/note-user-permission.entity'; import { Revision } from '../revisions/revision.entity'; import { User } from '../users/user.entity'; +import { Alias } from './alias.entity'; import { Tag } from './tag.entity'; import { generatePublicId } from './utils'; @@ -28,12 +29,12 @@ export class Note { id: string; @Column({ type: 'text' }) publicId: string; - @Column({ - unique: true, - nullable: true, - type: 'text', - }) - alias: string | null; + @OneToMany( + (_) => Alias, + (alias) => alias.note, + { cascade: true }, // This ensures that embedded Aliases are automatically saved to the database + ) + aliases: Alias[]; @OneToMany( (_) => NoteGroupPermission, (groupPermission) => groupPermission.note, @@ -84,7 +85,7 @@ export class Note { public static create(owner?: User, alias?: string): Note { const newNote = new Note(); newNote.publicId = generatePublicId(); - newNote.alias = alias ?? null; + newNote.aliases = alias ? [Alias.create(alias, true)] : []; newNote.viewCount = 0; newNote.owner = owner ?? null; newNote.userPermissions = []; diff --git a/src/notes/notes.module.ts b/src/notes/notes.module.ts index 80e332288..0bb564f07 100644 --- a/src/notes/notes.module.ts +++ b/src/notes/notes.module.ts @@ -14,6 +14,7 @@ import { NoteUserPermission } from '../permissions/note-user-permission.entity'; import { RevisionsModule } from '../revisions/revisions.module'; import { User } from '../users/user.entity'; import { UsersModule } from '../users/users.module'; +import { Alias } from './alias.entity'; import { Note } from './note.entity'; import { NotesService } from './notes.service'; import { Tag } from './tag.entity'; @@ -26,6 +27,7 @@ import { Tag } from './tag.entity'; NoteGroupPermission, NoteUserPermission, User, + Alias, ]), forwardRef(() => RevisionsModule), UsersModule, diff --git a/src/notes/primary.value-transformer.ts b/src/notes/primary.value-transformer.ts new file mode 100644 index 000000000..21ff8f505 --- /dev/null +++ b/src/notes/primary.value-transformer.ts @@ -0,0 +1,22 @@ +/* + * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ +import { ValueTransformer } from 'typeorm'; + +export class PrimaryValueTransformer implements ValueTransformer { + from(value: boolean | null): boolean { + if (value === null) { + return false; + } + return value; + } + + to(value: boolean): boolean | null { + if (!value) { + return null; + } + return value; + } +}