mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-03-23 21:13:54 +00:00
feat: add realtime announcements for permission changes and note deletion
Co-authored-by: Erik Michelson <github@erik.michelson.eu> Signed-off-by: Erik Michelson <github@erik.michelson.eu> Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
parent
c363d0834e
commit
331747f61b
6 changed files with 56 additions and 3 deletions
|
@ -260,6 +260,10 @@ export class NotesService {
|
|||
* @throws {NotInDBError} there is no note with this id or alias
|
||||
*/
|
||||
async deleteNote(note: Note): Promise<Note> {
|
||||
const realtimeNote = this.realtimeNoteStore.find(note.id);
|
||||
if (realtimeNote) {
|
||||
realtimeNote.announceNoteDeletion();
|
||||
}
|
||||
return await this.noteRepository.remove(note);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { Module } from '@nestjs/common';
|
||||
import { forwardRef, Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { GroupsModule } from '../groups/groups.module';
|
||||
import { LoggerModule } from '../logger/logger.module';
|
||||
import { Note } from '../notes/note.entity';
|
||||
import { RealtimeNoteModule } from '../realtime/realtime-note/realtime-note.module';
|
||||
import { UsersModule } from '../users/users.module';
|
||||
import { PermissionsService } from './permissions.service';
|
||||
|
||||
|
@ -18,6 +19,7 @@ import { PermissionsService } from './permissions.service';
|
|||
UsersModule,
|
||||
GroupsModule,
|
||||
LoggerModule,
|
||||
forwardRef(() => RealtimeNoteModule),
|
||||
],
|
||||
exports: [PermissionsService],
|
||||
providers: [PermissionsService],
|
||||
|
|
|
@ -34,6 +34,7 @@ import {
|
|||
import { Note } from '../notes/note.entity';
|
||||
import { NotesModule } from '../notes/notes.module';
|
||||
import { Tag } from '../notes/tag.entity';
|
||||
import { RealtimeNoteModule } from '../realtime/realtime-note/realtime-note.module';
|
||||
import { Edit } from '../revisions/edit.entity';
|
||||
import { Revision } from '../revisions/revision.entity';
|
||||
import { Session } from '../users/session.entity';
|
||||
|
@ -109,6 +110,7 @@ describe('PermissionsService', () => {
|
|||
],
|
||||
}),
|
||||
GroupsModule,
|
||||
RealtimeNoteModule,
|
||||
],
|
||||
})
|
||||
.overrideProvider(getRepositoryToken(User))
|
||||
|
|
|
@ -19,6 +19,8 @@ import { SpecialGroup } from '../groups/groups.special';
|
|||
import { ConsoleLoggerService } from '../logger/console-logger.service';
|
||||
import { NotePermissionsUpdateDto } from '../notes/note-permissions.dto';
|
||||
import { Note } from '../notes/note.entity';
|
||||
import { RealtimeNoteStore } from '../realtime/realtime-note/realtime-note-store';
|
||||
import { RealtimeNoteService } from '../realtime/realtime-note/realtime-note.service';
|
||||
import { User } from '../users/user.entity';
|
||||
import { UsersService } from '../users/users.service';
|
||||
import { checkArrayForDuplicates } from '../utils/arrayDuplicatCheck';
|
||||
|
@ -34,6 +36,8 @@ export class PermissionsService {
|
|||
private readonly logger: ConsoleLoggerService,
|
||||
@Inject(noteConfiguration.KEY)
|
||||
private noteConfig: NoteConfig,
|
||||
private realtimeNoteService: RealtimeNoteService,
|
||||
private realtimeNoteStore: RealtimeNoteStore,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
@ -150,6 +154,13 @@ export class PermissionsService {
|
|||
return false;
|
||||
}
|
||||
|
||||
private notifyOthers(noteId: Note['id']): void {
|
||||
const realtimeNote = this.realtimeNoteStore.find(noteId);
|
||||
if (realtimeNote) {
|
||||
realtimeNote.announcePermissionChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @async
|
||||
* Update a notes permissions.
|
||||
|
@ -211,7 +222,7 @@ export class PermissionsService {
|
|||
createdPermission.note = Promise.resolve(note);
|
||||
(await note.groupPermissions).push(createdPermission);
|
||||
}
|
||||
|
||||
this.notifyOthers(note.id);
|
||||
return await this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
|
@ -245,6 +256,7 @@ export class PermissionsService {
|
|||
);
|
||||
(await note.userPermissions).push(noteUserPermission);
|
||||
}
|
||||
this.notifyOthers(note.id);
|
||||
return await this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
|
@ -264,6 +276,7 @@ export class PermissionsService {
|
|||
}
|
||||
}
|
||||
note.userPermissions = Promise.resolve(newPermissions);
|
||||
this.notifyOthers(note.id);
|
||||
return await this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
|
@ -305,6 +318,7 @@ export class PermissionsService {
|
|||
);
|
||||
(await note.groupPermissions).push(noteGroupPermission);
|
||||
}
|
||||
this.notifyOthers(note.id);
|
||||
return await this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
|
@ -327,6 +341,7 @@ export class PermissionsService {
|
|||
}
|
||||
}
|
||||
note.groupPermissions = Promise.resolve(newPermissions);
|
||||
this.notifyOthers(note.id);
|
||||
return await this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
|
@ -339,6 +354,7 @@ export class PermissionsService {
|
|||
*/
|
||||
async changeOwner(note: Note, owner: User): Promise<Note> {
|
||||
note.owner = Promise.resolve(owner);
|
||||
this.notifyOthers(note.id);
|
||||
return await this.noteRepository.save(note);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ export class RealtimeNoteService implements BeforeApplicationShutdown {
|
|||
|
||||
/**
|
||||
* Creates or reuses a {@link RealtimeNote} that is handling the real time editing of the {@link Note} which is identified by the given note id.
|
||||
* @param note The for which a {@link RealtimeNote realtime note} should be retrieved.
|
||||
* @param note The {@link Note} for which a {@link RealtimeNote realtime note} should be retrieved.
|
||||
* @throws NotInDBError if note doesn't exist or has no revisions.
|
||||
* @return A {@link RealtimeNote} that is linked to the given note.
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import {
|
||||
encodeDocumentDeletedMessage,
|
||||
encodeMetadataUpdatedMessage,
|
||||
} from '@hedgedoc/realtime';
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { EventEmitter } from 'events';
|
||||
import TypedEventEmitter, { EventMap } from 'typed-emitter';
|
||||
|
@ -130,4 +134,29 @@ export class RealtimeNote extends (EventEmitter as TypedEventEmitterConstructor<
|
|||
public getNote(): Note {
|
||||
return this.note;
|
||||
}
|
||||
|
||||
/**
|
||||
* Announce to all clients that the permissions of the note have been changed.
|
||||
*/
|
||||
public announcePermissionChange(): void {
|
||||
this.sendToAllClients(encodeMetadataUpdatedMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Announce to all clients that the note has been deleted.
|
||||
*/
|
||||
public announceNoteDeletion(): void {
|
||||
this.sendToAllClients(encodeDocumentDeletedMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcasts the given content to all connected clients.
|
||||
*
|
||||
* @param {Uint8Array} content The binary message to broadcast
|
||||
*/
|
||||
private sendToAllClients(content: Uint8Array): void {
|
||||
this.getConnections().forEach((connection) => {
|
||||
connection.send(content);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue