mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2024-11-23 10:16:32 -05:00
Merge pull request #1344 from hedgedoc/feature/rename_authorship_edit
This commit is contained in:
commit
3bfde06007
20 changed files with 77 additions and 81 deletions
|
@ -21,7 +21,7 @@ import { User } from '../../../../users/user.entity';
|
||||||
import { Note } from '../../../../notes/note.entity';
|
import { Note } from '../../../../notes/note.entity';
|
||||||
import { AuthToken } from '../../../../auth/auth-token.entity';
|
import { AuthToken } from '../../../../auth/auth-token.entity';
|
||||||
import { Identity } from '../../../../users/identity.entity';
|
import { Identity } from '../../../../users/identity.entity';
|
||||||
import { Authorship } from '../../../../revisions/authorship.entity';
|
import { Edit } from '../../../../revisions/edit.entity';
|
||||||
import { Revision } from '../../../../revisions/revision.entity';
|
import { Revision } from '../../../../revisions/revision.entity';
|
||||||
import { Tag } from '../../../../notes/tag.entity';
|
import { Tag } from '../../../../notes/tag.entity';
|
||||||
import { HistoryEntry } from '../../../../history/history-entry.entity';
|
import { HistoryEntry } from '../../../../history/history-entry.entity';
|
||||||
|
@ -59,7 +59,7 @@ describe('HistoryController', () => {
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Identity))
|
.overrideProvider(getRepositoryToken(Identity))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Revision))
|
.overrideProvider(getRepositoryToken(Revision))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Identity } from '../../../users/identity.entity';
|
||||||
import { MediaModule } from '../../../media/media.module';
|
import { MediaModule } from '../../../media/media.module';
|
||||||
import { NoteGroupPermission } from '../../../permissions/note-group-permission.entity';
|
import { NoteGroupPermission } from '../../../permissions/note-group-permission.entity';
|
||||||
import { NoteUserPermission } from '../../../permissions/note-user-permission.entity';
|
import { NoteUserPermission } from '../../../permissions/note-user-permission.entity';
|
||||||
import { Authorship } from '../../../revisions/authorship.entity';
|
import { Edit } from '../../../revisions/edit.entity';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import appConfigMock from '../../../config/mock/app.config.mock';
|
import appConfigMock from '../../../config/mock/app.config.mock';
|
||||||
import authConfigMock from '../../../config/mock/auth.config.mock';
|
import authConfigMock from '../../../config/mock/auth.config.mock';
|
||||||
|
@ -67,7 +67,7 @@ describe('MeController', () => {
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(NoteUserPermission))
|
.overrideProvider(getRepositoryToken(NoteUserPermission))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(MediaUpload))
|
.overrideProvider(getRepositoryToken(MediaUpload))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -19,7 +19,7 @@ import externalConfigMock from '../../../config/mock/external-services.config.mo
|
||||||
import { MediaModule } from '../../../media/media.module';
|
import { MediaModule } from '../../../media/media.module';
|
||||||
import { NotesModule } from '../../../notes/notes.module';
|
import { NotesModule } from '../../../notes/notes.module';
|
||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import { Authorship } from '../../../revisions/authorship.entity';
|
import { Edit } from '../../../revisions/edit.entity';
|
||||||
import { AuthToken } from '../../../auth/auth-token.entity';
|
import { AuthToken } from '../../../auth/auth-token.entity';
|
||||||
import { Identity } from '../../../users/identity.entity';
|
import { Identity } from '../../../users/identity.entity';
|
||||||
import { MediaUpload } from '../../../media/media-upload.entity';
|
import { MediaUpload } from '../../../media/media-upload.entity';
|
||||||
|
@ -54,7 +54,7 @@ describe('MediaController', () => {
|
||||||
],
|
],
|
||||||
controllers: [MediaController],
|
controllers: [MediaController],
|
||||||
})
|
})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(AuthToken))
|
.overrideProvider(getRepositoryToken(AuthToken))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { ConfigModule } from '@nestjs/config';
|
||||||
import appConfigMock from '../../../config/mock/app.config.mock';
|
import appConfigMock from '../../../config/mock/app.config.mock';
|
||||||
import mediaConfigMock from '../../../config/mock/media.config.mock';
|
import mediaConfigMock from '../../../config/mock/media.config.mock';
|
||||||
import { Revision } from '../../../revisions/revision.entity';
|
import { Revision } from '../../../revisions/revision.entity';
|
||||||
import { Authorship } from '../../../revisions/authorship.entity';
|
import { Edit } from '../../../revisions/edit.entity';
|
||||||
import { User } from '../../../users/user.entity';
|
import { User } from '../../../users/user.entity';
|
||||||
import { AuthToken } from '../../../auth/auth-token.entity';
|
import { AuthToken } from '../../../auth/auth-token.entity';
|
||||||
import { Identity } from '../../../users/identity.entity';
|
import { Identity } from '../../../users/identity.entity';
|
||||||
|
@ -77,7 +77,7 @@ describe('NotesController', () => {
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Revision))
|
.overrideProvider(getRepositoryToken(Revision))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(User))
|
.overrideProvider(getRepositoryToken(User))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { LoggerModule } from '../../../logger/logger.module';
|
||||||
import { Note } from '../../../notes/note.entity';
|
import { Note } from '../../../notes/note.entity';
|
||||||
import { NotesModule } from '../../../notes/notes.module';
|
import { NotesModule } from '../../../notes/notes.module';
|
||||||
import { Tag } from '../../../notes/tag.entity';
|
import { Tag } from '../../../notes/tag.entity';
|
||||||
import { Authorship } from '../../../revisions/authorship.entity';
|
import { Edit } from '../../../revisions/edit.entity';
|
||||||
import { Revision } from '../../../revisions/revision.entity';
|
import { Revision } from '../../../revisions/revision.entity';
|
||||||
import { AuthToken } from '../../../auth/auth-token.entity';
|
import { AuthToken } from '../../../auth/auth-token.entity';
|
||||||
import { Identity } from '../../../users/identity.entity';
|
import { Identity } from '../../../users/identity.entity';
|
||||||
|
@ -63,7 +63,7 @@ describe('Me Controller', () => {
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Identity))
|
.overrideProvider(getRepositoryToken(Identity))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Revision))
|
.overrideProvider(getRepositoryToken(Revision))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { MediaModule } from '../../../media/media.module';
|
||||||
import { Note } from '../../../notes/note.entity';
|
import { Note } from '../../../notes/note.entity';
|
||||||
import { NotesModule } from '../../../notes/notes.module';
|
import { NotesModule } from '../../../notes/notes.module';
|
||||||
import { Tag } from '../../../notes/tag.entity';
|
import { Tag } from '../../../notes/tag.entity';
|
||||||
import { Authorship } from '../../../revisions/authorship.entity';
|
import { Edit } from '../../../revisions/edit.entity';
|
||||||
import { Revision } from '../../../revisions/revision.entity';
|
import { Revision } from '../../../revisions/revision.entity';
|
||||||
import { AuthToken } from '../../../auth/auth-token.entity';
|
import { AuthToken } from '../../../auth/auth-token.entity';
|
||||||
import { Identity } from '../../../users/identity.entity';
|
import { Identity } from '../../../users/identity.entity';
|
||||||
|
@ -43,7 +43,7 @@ describe('Media Controller', () => {
|
||||||
NotesModule,
|
NotesModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(AuthToken))
|
.overrideProvider(getRepositoryToken(AuthToken))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { LoggerModule } from '../../../logger/logger.module';
|
||||||
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 { Tag } from '../../../notes/tag.entity';
|
import { Tag } from '../../../notes/tag.entity';
|
||||||
import { Authorship } from '../../../revisions/authorship.entity';
|
import { Edit } from '../../../revisions/edit.entity';
|
||||||
import { Revision } from '../../../revisions/revision.entity';
|
import { Revision } from '../../../revisions/revision.entity';
|
||||||
import { RevisionsModule } from '../../../revisions/revisions.module';
|
import { RevisionsModule } from '../../../revisions/revisions.module';
|
||||||
import { AuthToken } from '../../../auth/auth-token.entity';
|
import { AuthToken } from '../../../auth/auth-token.entity';
|
||||||
|
@ -79,7 +79,7 @@ describe('Notes Controller', () => {
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Revision))
|
.overrideProvider(getRepositoryToken(Revision))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(User))
|
.overrideProvider(getRepositoryToken(User))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
OneToMany,
|
OneToMany,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { Authorship } from '../revisions/authorship.entity';
|
import { Edit } from '../revisions/edit.entity';
|
||||||
import { Session } from '../users/session.entity';
|
import { Session } from '../users/session.entity';
|
||||||
import { User } from '../users/user.entity';
|
import { User } from '../users/user.entity';
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export type AuthorColor = number;
|
||||||
/**
|
/**
|
||||||
* The author represents a single user editing a note.
|
* The author represents a single user editing a note.
|
||||||
* A 'user' can either be a registered and logged-in user or a browser session identified by its cookie.
|
* A 'user' can either be a registered and logged-in user or a browser session identified by its cookie.
|
||||||
* All edits (aka authorships) of one user in a note must belong to the same author, so that the same color can be displayed.
|
* All edits of one user in a note must belong to the same author, so that the same color can be displayed.
|
||||||
*/
|
*/
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Author {
|
export class Author {
|
||||||
|
@ -49,23 +49,23 @@ export class Author {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of authorships that this author created
|
* List of edits that this author created
|
||||||
* All authorships must belong to the same note
|
* All edits must belong to the same note
|
||||||
*/
|
*/
|
||||||
@OneToMany(() => Authorship, (authorship) => authorship.author)
|
@OneToMany(() => Edit, (edit) => edit.author)
|
||||||
authorships: Authorship[];
|
edits: Edit[];
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
||||||
public static create(
|
public static create(
|
||||||
color: number,
|
color: number,
|
||||||
): Pick<Author, 'color' | 'sessions' | 'user' | 'authorships'> {
|
): Pick<Author, 'color' | 'sessions' | 'user' | 'edits'> {
|
||||||
const newAuthor = new Author();
|
const newAuthor = new Author();
|
||||||
newAuthor.color = color;
|
newAuthor.color = color;
|
||||||
newAuthor.sessions = [];
|
newAuthor.sessions = [];
|
||||||
newAuthor.user = null;
|
newAuthor.user = null;
|
||||||
newAuthor.authorships = [];
|
newAuthor.edits = [];
|
||||||
return newAuthor;
|
return newAuthor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { NotesModule } from '../notes/notes.module';
|
||||||
import { getConnectionToken, getRepositoryToken } from '@nestjs/typeorm';
|
import { getConnectionToken, getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import { Identity } from '../users/identity.entity';
|
import { Identity } from '../users/identity.entity';
|
||||||
import { User } from '../users/user.entity';
|
import { User } from '../users/user.entity';
|
||||||
import { Authorship } from '../revisions/authorship.entity';
|
import { Edit } from '../revisions/edit.entity';
|
||||||
import { HistoryEntry } from './history-entry.entity';
|
import { HistoryEntry } from './history-entry.entity';
|
||||||
import { Note } from '../notes/note.entity';
|
import { Note } from '../notes/note.entity';
|
||||||
import { Tag } from '../notes/tag.entity';
|
import { Tag } from '../notes/tag.entity';
|
||||||
|
@ -74,7 +74,7 @@ describe('HistoryService', () => {
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Identity))
|
.overrideProvider(getRepositoryToken(Identity))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Revision))
|
.overrideProvider(getRepositoryToken(Revision))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { LoggerModule } from '../logger/logger.module';
|
||||||
import { Note } from '../notes/note.entity';
|
import { Note } from '../notes/note.entity';
|
||||||
import { NotesModule } from '../notes/notes.module';
|
import { NotesModule } from '../notes/notes.module';
|
||||||
import { Tag } from '../notes/tag.entity';
|
import { Tag } from '../notes/tag.entity';
|
||||||
import { Authorship } from '../revisions/authorship.entity';
|
import { Edit } from '../revisions/edit.entity';
|
||||||
import { Revision } from '../revisions/revision.entity';
|
import { Revision } from '../revisions/revision.entity';
|
||||||
import { AuthToken } from '../auth/auth-token.entity';
|
import { AuthToken } from '../auth/auth-token.entity';
|
||||||
import { Identity } from '../users/identity.entity';
|
import { Identity } from '../users/identity.entity';
|
||||||
|
@ -57,7 +57,7 @@ describe('MediaService', () => {
|
||||||
UsersModule,
|
UsersModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(AuthToken))
|
.overrideProvider(getRepositoryToken(AuthToken))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IsArray, IsString, ValidateNested } from 'class-validator';
|
import { IsArray, IsString, ValidateNested } from 'class-validator';
|
||||||
import { NoteAuthorshipDto } from './note-authorship.dto';
|
import { EditDto } from '../revisions/edit.dto';
|
||||||
import { NoteMetadataDto } from './note-metadata.dto';
|
import { NoteMetadataDto } from './note-metadata.dto';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
@ -26,10 +26,10 @@ export class NoteDto {
|
||||||
metadata: NoteMetadataDto;
|
metadata: NoteMetadataDto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authorship information of this note
|
* Edit information of this note
|
||||||
*/
|
*/
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
@ApiProperty({ isArray: true, type: NoteAuthorshipDto })
|
@ApiProperty({ isArray: true, type: EditDto })
|
||||||
editedByAtPosition: NoteAuthorshipDto[];
|
editedByAtPosition: EditDto[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import { Author } from '../authors/author.entity';
|
import { Author } from '../authors/author.entity';
|
||||||
import { LoggerModule } from '../logger/logger.module';
|
import { LoggerModule } from '../logger/logger.module';
|
||||||
import { Authorship } from '../revisions/authorship.entity';
|
import { Edit } from '../revisions/edit.entity';
|
||||||
import { Revision } from '../revisions/revision.entity';
|
import { Revision } from '../revisions/revision.entity';
|
||||||
import { RevisionsModule } from '../revisions/revisions.module';
|
import { RevisionsModule } from '../revisions/revisions.module';
|
||||||
import { AuthToken } from '../auth/auth-token.entity';
|
import { AuthToken } from '../auth/auth-token.entity';
|
||||||
|
@ -89,7 +89,7 @@ describe('NotesService', () => {
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Identity))
|
.overrideProvider(getRepositoryToken(Identity))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Revision))
|
.overrideProvider(getRepositoryToken(Revision))
|
||||||
.useClass(Repository)
|
.useClass(Repository)
|
||||||
|
@ -680,21 +680,21 @@ describe('NotesService', () => {
|
||||||
.mockImplementation(async (note: Note): Promise<Note> => note);
|
.mockImplementation(async (note: Note): Promise<Note> => note);
|
||||||
const note = await service.createNote(content);
|
const note = await service.createNote(content);
|
||||||
const revisions = await note.revisions;
|
const revisions = await note.revisions;
|
||||||
revisions[0].authorships = [
|
revisions[0].edits = [
|
||||||
{
|
{
|
||||||
revisions: revisions,
|
revisions: revisions,
|
||||||
startPos: 0,
|
startPos: 0,
|
||||||
endPos: 1,
|
endPos: 1,
|
||||||
updatedAt: new Date(1549312452000),
|
updatedAt: new Date(1549312452000),
|
||||||
author: author,
|
author: author,
|
||||||
} as Authorship,
|
} as Edit,
|
||||||
{
|
{
|
||||||
revisions: revisions,
|
revisions: revisions,
|
||||||
startPos: 0,
|
startPos: 0,
|
||||||
endPos: 1,
|
endPos: 1,
|
||||||
updatedAt: new Date(1549312452001),
|
updatedAt: new Date(1549312452001),
|
||||||
author: author,
|
author: author,
|
||||||
} as Authorship,
|
} as Edit,
|
||||||
];
|
];
|
||||||
revisions[0].createdAt = new Date(1549312452000);
|
revisions[0].createdAt = new Date(1549312452000);
|
||||||
jest.spyOn(revisionRepo, 'findOne').mockResolvedValue(revisions[0]);
|
jest.spyOn(revisionRepo, 'findOne').mockResolvedValue(revisions[0]);
|
||||||
|
@ -776,21 +776,21 @@ describe('NotesService', () => {
|
||||||
.mockImplementation(async (note: Note): Promise<Note> => note);
|
.mockImplementation(async (note: Note): Promise<Note> => note);
|
||||||
const note = await service.createNote(content);
|
const note = await service.createNote(content);
|
||||||
const revisions = await note.revisions;
|
const revisions = await note.revisions;
|
||||||
revisions[0].authorships = [
|
revisions[0].edits = [
|
||||||
{
|
{
|
||||||
revisions: revisions,
|
revisions: revisions,
|
||||||
startPos: 0,
|
startPos: 0,
|
||||||
endPos: 1,
|
endPos: 1,
|
||||||
updatedAt: new Date(1549312452000),
|
updatedAt: new Date(1549312452000),
|
||||||
author: author,
|
author: author,
|
||||||
} as Authorship,
|
} as Edit,
|
||||||
{
|
{
|
||||||
revisions: revisions,
|
revisions: revisions,
|
||||||
startPos: 0,
|
startPos: 0,
|
||||||
endPos: 1,
|
endPos: 1,
|
||||||
updatedAt: new Date(1549312452001),
|
updatedAt: new Date(1549312452001),
|
||||||
author: author,
|
author: author,
|
||||||
} as Authorship,
|
} as Edit,
|
||||||
];
|
];
|
||||||
revisions[0].createdAt = new Date(1549312452000);
|
revisions[0].createdAt = new Date(1549312452000);
|
||||||
jest
|
jest
|
||||||
|
|
|
@ -198,8 +198,8 @@ export class NotesService {
|
||||||
return await this.userRepository
|
return await this.userRepository
|
||||||
.createQueryBuilder('user')
|
.createQueryBuilder('user')
|
||||||
.innerJoin('user.authors', 'author')
|
.innerJoin('user.authors', 'author')
|
||||||
.innerJoin('author.authorships', 'authorship')
|
.innerJoin('author.edits', 'edit')
|
||||||
.innerJoin('authorship.revisions', 'revision')
|
.innerJoin('edit.revisions', 'revision')
|
||||||
.innerJoin('revision.note', 'note')
|
.innerJoin('revision.note', 'note')
|
||||||
.where('note.id = :id', { id: note.id })
|
.where('note.id = :id', { id: note.id })
|
||||||
.getMany();
|
.getMany();
|
||||||
|
@ -322,14 +322,14 @@ export class NotesService {
|
||||||
*/
|
*/
|
||||||
async calculateUpdateUser(note: Note): Promise<User | null> {
|
async calculateUpdateUser(note: Note): Promise<User | null> {
|
||||||
const lastRevision = await this.getLatestRevision(note);
|
const lastRevision = await this.getLatestRevision(note);
|
||||||
if (lastRevision && lastRevision.authorships) {
|
if (lastRevision && lastRevision.edits) {
|
||||||
// Sort the last Revisions Authorships by their updatedAt Date to get the latest one
|
// Sort the last Revisions Edits by their updatedAt Date to get the latest one
|
||||||
// the user of that Authorship is the updateUser
|
// the user of that Edit is the updateUser
|
||||||
return lastRevision.authorships.sort(
|
return lastRevision.edits.sort(
|
||||||
(a, b) => b.updatedAt.getTime() - a.updatedAt.getTime(),
|
(a, b) => b.updatedAt.getTime() - a.updatedAt.getTime(),
|
||||||
)[0].author.user;
|
)[0].author.user;
|
||||||
}
|
}
|
||||||
// If there are no Authorships, the owner is the updateUser
|
// If there are no Edits, the owner is the updateUser
|
||||||
return note.owner;
|
return note.owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { LoggerModule } from '../logger/logger.module';
|
||||||
import { Note } from '../notes/note.entity';
|
import { Note } from '../notes/note.entity';
|
||||||
import { NotesModule } from '../notes/notes.module';
|
import { NotesModule } from '../notes/notes.module';
|
||||||
import { Tag } from '../notes/tag.entity';
|
import { Tag } from '../notes/tag.entity';
|
||||||
import { Authorship } from '../revisions/authorship.entity';
|
import { Edit } from '../revisions/edit.entity';
|
||||||
import { Revision } from '../revisions/revision.entity';
|
import { Revision } from '../revisions/revision.entity';
|
||||||
import { Identity } from '../users/identity.entity';
|
import { Identity } from '../users/identity.entity';
|
||||||
import { Session } from '../users/session.entity';
|
import { Session } from '../users/session.entity';
|
||||||
|
@ -49,7 +49,7 @@ describe('PermissionsService', () => {
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Identity))
|
.overrideProvider(getRepositoryToken(Identity))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(Revision))
|
.overrideProvider(getRepositoryToken(Revision))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
|
@ -4,18 +4,20 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IsDate, IsNumber, IsString, Min } from 'class-validator';
|
import { IsDate, IsNumber, IsOptional, IsString, Min } from 'class-validator';
|
||||||
import { UserInfoDto } from '../users/user-info.dto';
|
import { UserInfoDto } from '../users/user-info.dto';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
|
||||||
export class NoteAuthorshipDto {
|
export class EditDto {
|
||||||
/**
|
/**
|
||||||
* Username of the user who authored this section
|
* Username of the user who authored this section
|
||||||
|
* Is `null` if the user is anonymous
|
||||||
* @example "john.smith"
|
* @example "john.smith"
|
||||||
*/
|
*/
|
||||||
@IsString()
|
@IsString()
|
||||||
@ApiProperty()
|
@IsOptional()
|
||||||
userName: UserInfoDto['userName'];
|
@ApiPropertyOptional()
|
||||||
|
userName: UserInfoDto['userName'] | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Character index of the start of this section
|
* Character index of the start of this section
|
|
@ -17,23 +17,23 @@ import { Author } from '../authors/author.entity';
|
||||||
import { Revision } from './revision.entity';
|
import { Revision } from './revision.entity';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Authorship represents a change in the content of a note by a particular {@link Author}
|
* The Edit represents a change in the content of a note by a particular {@link Author}
|
||||||
*/
|
*/
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Authorship {
|
export class Edit {
|
||||||
@PrimaryGeneratedColumn('uuid')
|
@PrimaryGeneratedColumn('uuid')
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Revisions this authorship appears in
|
* Revisions this edit appears in
|
||||||
*/
|
*/
|
||||||
@ManyToMany((_) => Revision, (revision) => revision.authorships)
|
@ManyToMany((_) => Revision, (revision) => revision.edits)
|
||||||
revisions: Revision[];
|
revisions: Revision[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Author that created the change
|
* Author that created the change
|
||||||
*/
|
*/
|
||||||
@ManyToOne(() => Author, (author) => author.authorships)
|
@ManyToOne(() => Author, (author) => author.edits)
|
||||||
author: Author;
|
author: Author;
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
|
@ -52,10 +52,10 @@ export class Authorship {
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
||||||
public static create(author: Author, startPos: number, endPos: number) {
|
public static create(author: Author, startPos: number, endPos: number) {
|
||||||
const newAuthorship = new Authorship();
|
const newEdit = new Edit();
|
||||||
newAuthorship.author = author;
|
newEdit.author = author;
|
||||||
newAuthorship.startPos = startPos;
|
newEdit.startPos = startPos;
|
||||||
newAuthorship.endPos = endPos;
|
newEdit.endPos = endPos;
|
||||||
return newAuthorship;
|
return newEdit;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@ import {
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { JoinTable, ManyToMany } from 'typeorm';
|
import { JoinTable, ManyToMany } from 'typeorm';
|
||||||
import { Note } from '../notes/note.entity';
|
import { Note } from '../notes/note.entity';
|
||||||
import { Authorship } from './authorship.entity';
|
import { Edit } from './edit.entity';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The state of a note at a particular point in time,
|
* The state of a note at a particular point in time,
|
||||||
|
@ -59,11 +59,11 @@ export class Revision {
|
||||||
@ManyToOne((_) => Note, (note) => note.revisions, { onDelete: 'CASCADE' })
|
@ManyToOne((_) => Note, (note) => note.revisions, { onDelete: 'CASCADE' })
|
||||||
note: Note;
|
note: Note;
|
||||||
/**
|
/**
|
||||||
* All authorship objects which are used in the revision.
|
* All edit objects which are used in the revision.
|
||||||
*/
|
*/
|
||||||
@ManyToMany((_) => Authorship, (authorship) => authorship.revisions)
|
@ManyToMany((_) => Edit, (edit) => edit.revisions)
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
authorships: Authorship[];
|
edits: Edit[];
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
|
|
|
@ -9,14 +9,14 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { AuthorsModule } from '../authors/authors.module';
|
import { AuthorsModule } from '../authors/authors.module';
|
||||||
import { LoggerModule } from '../logger/logger.module';
|
import { LoggerModule } from '../logger/logger.module';
|
||||||
import { NotesModule } from '../notes/notes.module';
|
import { NotesModule } from '../notes/notes.module';
|
||||||
import { Authorship } from './authorship.entity';
|
import { Edit } from './edit.entity';
|
||||||
import { Revision } from './revision.entity';
|
import { Revision } from './revision.entity';
|
||||||
import { RevisionsService } from './revisions.service';
|
import { RevisionsService } from './revisions.service';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([Revision, Authorship]),
|
TypeOrmModule.forFeature([Revision, Edit]),
|
||||||
forwardRef(() => NotesModule),
|
forwardRef(() => NotesModule),
|
||||||
LoggerModule,
|
LoggerModule,
|
||||||
ConfigModule,
|
ConfigModule,
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { AuthToken } from '../auth/auth-token.entity';
|
||||||
import { Identity } from '../users/identity.entity';
|
import { Identity } from '../users/identity.entity';
|
||||||
import { Session } from '../users/session.entity';
|
import { Session } from '../users/session.entity';
|
||||||
import { User } from '../users/user.entity';
|
import { User } from '../users/user.entity';
|
||||||
import { Authorship } from './authorship.entity';
|
import { Edit } from './edit.entity';
|
||||||
import { Revision } from './revision.entity';
|
import { Revision } from './revision.entity';
|
||||||
import { RevisionsService } from './revisions.service';
|
import { RevisionsService } from './revisions.service';
|
||||||
import { Tag } from '../notes/tag.entity';
|
import { Tag } from '../notes/tag.entity';
|
||||||
|
@ -49,7 +49,7 @@ describe('RevisionsService', () => {
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.overrideProvider(getRepositoryToken(Authorship))
|
.overrideProvider(getRepositoryToken(Edit))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
.overrideProvider(getRepositoryToken(User))
|
.overrideProvider(getRepositoryToken(User))
|
||||||
.useValue({})
|
.useValue({})
|
||||||
|
|
16
src/seed.ts
16
src/seed.ts
|
@ -10,7 +10,7 @@ import { Session } from './users/session.entity';
|
||||||
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 { Revision } from './revisions/revision.entity';
|
import { Revision } from './revisions/revision.entity';
|
||||||
import { Authorship } from './revisions/authorship.entity';
|
import { Edit } from './revisions/edit.entity';
|
||||||
import { NoteGroupPermission } from './permissions/note-group-permission.entity';
|
import { NoteGroupPermission } from './permissions/note-group-permission.entity';
|
||||||
import { NoteUserPermission } from './permissions/note-user-permission.entity';
|
import { NoteUserPermission } from './permissions/note-user-permission.entity';
|
||||||
import { Group } from './groups/group.entity';
|
import { Group } from './groups/group.entity';
|
||||||
|
@ -30,7 +30,7 @@ createConnection({
|
||||||
User,
|
User,
|
||||||
Note,
|
Note,
|
||||||
Revision,
|
Revision,
|
||||||
Authorship,
|
Edit,
|
||||||
NoteGroupPermission,
|
NoteGroupPermission,
|
||||||
NoteUserPermission,
|
NoteUserPermission,
|
||||||
Group,
|
Group,
|
||||||
|
@ -64,19 +64,13 @@ createConnection({
|
||||||
'This is a test note',
|
'This is a test note',
|
||||||
'This is a test note',
|
'This is a test note',
|
||||||
);
|
);
|
||||||
const authorship = Authorship.create(author, 1, 42);
|
const edit = Edit.create(author, 1, 42);
|
||||||
revision.authorships = [authorship];
|
revision.edits = [edit];
|
||||||
notes[i].revisions = Promise.all([revision]);
|
notes[i].revisions = Promise.all([revision]);
|
||||||
notes[i].userPermissions = [];
|
notes[i].userPermissions = [];
|
||||||
notes[i].groupPermissions = [];
|
notes[i].groupPermissions = [];
|
||||||
user.ownedNotes = [notes[i]];
|
user.ownedNotes = [notes[i]];
|
||||||
await connection.manager.save([
|
await connection.manager.save([notes[i], user, revision, edit, author]);
|
||||||
notes[i],
|
|
||||||
user,
|
|
||||||
revision,
|
|
||||||
authorship,
|
|
||||||
author,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
const foundUser = await connection.manager.findOne(User);
|
const foundUser = await connection.manager.findOne(User);
|
||||||
if (!foundUser) {
|
if (!foundUser) {
|
||||||
|
|
Loading…
Reference in a new issue