collaborative editor - wip

This commit is contained in:
Philipinho
2023-09-15 01:22:47 +01:00
parent 0d648c17fa
commit 4382c5a1d0
21 changed files with 375 additions and 23 deletions
@@ -0,0 +1,34 @@
import { Extension, onAuthenticatePayload } from '@hocuspocus/server';
import { UserService } from '../../core/user/user.service';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { TokenService } from '../../core/auth/services/token.service';
@Injectable()
export class AuthenticationExtension implements Extension {
constructor(
private tokenService: TokenService,
private userService: UserService,
) {}
async onAuthenticate(data: onAuthenticatePayload) {
const { documentName, token } = data;
let jwtPayload = null;
try {
jwtPayload = await this.tokenService.verifyJwt(token);
} catch (error) {
throw new UnauthorizedException('Could not verify jwt token');
}
const userId = jwtPayload.sub;
const user = await this.userService.findById(userId);
//TODO: Check if the page exists and verify user permissions for page.
// if all fails, abort connection
return {
user,
};
}
}
@@ -0,0 +1,59 @@
import { Extension, onLoadDocumentPayload, onStoreDocumentPayload } from '@hocuspocus/server';
import * as Y from 'yjs';
import { PageService } from '../../core/page/page.service';
import { Injectable } from '@nestjs/common';
import { TiptapTransformer } from '@hocuspocus/transformer';
@Injectable()
export class PersistenceExtension implements Extension {
constructor(private readonly pageService: PageService) {}
async onLoadDocument(data: onLoadDocumentPayload) {
const { documentName, document } = data;
if (!document.isEmpty('default')) {
return;
}
const page = await this.pageService.findById(documentName);
if (!page) {
console.log('page does not exist.');
//TODO: terminate connection if the page does not exist?
return;
}
if (page.ydoc) {
const doc = new Y.Doc();
const dbState = new Uint8Array(page.ydoc);
Y.applyUpdate(doc, dbState);
return doc;
}
// if no ydoc state in db convert json in page.content to Ydoc.
const ydoc = TiptapTransformer.toYdoc(page.content, 'default');
Y.encodeStateAsUpdate(ydoc);
return ydoc;
}
async onStoreDocument(data: onStoreDocumentPayload) {
const { documentName, document, context } = data;
const pageId = documentName;
const tiptapJson = TiptapTransformer.fromYdoc(document, 'default');
const ydocState = Buffer.from(Y.encodeStateAsUpdate(document));
try {
await this.pageService.updateState(
pageId,
tiptapJson,
ydocState,
);
} catch (err) {
console.error(`Failed to update page ${documentName}`);
}
}
}