Individual document sharing with permissions (#5814)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
This commit is contained in:
Apoorv Mishra
2024-01-31 07:18:22 +05:30
committed by GitHub
parent 717c9b5d64
commit 1490c3a14b
91 changed files with 4004 additions and 1166 deletions

View File

@@ -14,6 +14,7 @@ import {
Team,
Subscription,
Notification,
UserMembership,
} from "@server/models";
import {
presentComment,
@@ -25,12 +26,13 @@ import {
presentStar,
presentSubscription,
presentTeam,
presentMembership,
} from "@server/presenters";
import presentNotification from "@server/presenters/notification";
import { Event } from "../../types";
export default class WebsocketsProcessor {
async perform(event: Event, socketio: Server) {
public async perform(event: Event, socketio: Server) {
switch (event.name) {
case "documents.publish":
case "documents.unpublish":
@@ -43,10 +45,8 @@ export default class WebsocketsProcessor {
return;
}
const channel = document.publishedAt
? `collection-${document.collectionId}`
: `user-${event.actorId}`;
return socketio.to(channel).emit("entities", {
const channels = await this.getDocumentEventChannels(event, document);
return socketio.to(channels).emit("entities", {
event: event.name,
documentIds: [
{
@@ -79,12 +79,9 @@ export default class WebsocketsProcessor {
if (!document) {
return;
}
const channel = document.publishedAt
? `collection-${document.collectionId}`
: `user-${event.actorId}`;
const data = await presentDocument(document);
return socketio.to(channel).emit(event.name, data);
const channels = await this.getDocumentEventChannels(event, document);
return socketio.to(channels).emit(event.name, data);
}
case "documents.create": {
@@ -92,7 +89,9 @@ export default class WebsocketsProcessor {
if (!document) {
return;
}
return socketio.to(`user-${event.actorId}`).emit("entities", {
const channels = await this.getDocumentEventChannels(event, document);
return socketio.to(channels).emit("entities", {
event: event.name,
documentIds: [
{
@@ -139,6 +138,35 @@ export default class WebsocketsProcessor {
return;
}
case "documents.add_user": {
const [document, membership] = await Promise.all([
Document.findByPk(event.documentId),
UserMembership.findByPk(event.modelId),
]);
if (!document || !membership) {
return;
}
const channels = await this.getDocumentEventChannels(event, document);
socketio.to(channels).emit(event.name, presentMembership(membership));
return;
}
case "documents.remove_user": {
const document = await Document.findByPk(event.documentId);
if (!document) {
return;
}
const channels = await this.getDocumentEventChannels(event, document);
socketio.to([...channels, `user-${event.userId}`]).emit(event.name, {
id: event.modelId,
userId: event.userId,
documentId: event.documentId,
});
return;
}
case "collections.create": {
const collection = await Collection.findByPk(event.collectionId, {
paranoid: false,
@@ -372,24 +400,47 @@ export default class WebsocketsProcessor {
case "comments.create":
case "comments.update": {
const comment = await Comment.scope([
"defaultScope",
"withDocument",
]).findByPk(event.modelId);
const comment = await Comment.findByPk(event.modelId, {
include: [
{
model: Document.scope(["withoutState", "withDrafts"]),
as: "document",
required: true,
},
],
});
if (!comment) {
return;
}
return socketio
.to(`collection-${comment.document.collectionId}`)
.emit(event.name, presentComment(comment));
const channels = await this.getDocumentEventChannels(
event,
comment.document
);
return socketio.to(channels).emit(event.name, presentComment(comment));
}
case "comments.delete": {
return socketio
.to(`collection-${event.collectionId}`)
.emit(event.name, {
modelId: event.modelId,
});
const comment = await Comment.findByPk(event.modelId, {
include: [
{
model: Document.scope(["withoutState", "withDrafts"]),
as: "document",
required: true,
},
],
});
if (!comment) {
return;
}
const channels = await this.getDocumentEventChannels(
event,
comment.document
);
return socketio.to(channels).emit(event.name, {
modelId: event.modelId,
});
}
case "notifications.create":
@@ -622,8 +673,41 @@ export default class WebsocketsProcessor {
.emit(event.name, { id: event.userId });
}
case "userMemberships.update": {
return socketio
.to(`user-${event.userId}`)
.emit(event.name, { id: event.modelId, ...event.data });
}
default:
return;
}
}
private async getDocumentEventChannels(
event: Event,
document: Document
): Promise<string[]> {
const channels = [];
if (event.actorId) {
channels.push(`user-${event.actorId}`);
}
if (document.publishedAt) {
channels.push(`collection-${document.collectionId}`);
}
const memberships = await UserMembership.findAll({
where: {
documentId: document.id,
},
});
for (const membership of memberships) {
channels.push(`user-${membership.userId}`);
}
return channels;
}
}