Removal of non-collaborative editing code paths (#4210)

This commit is contained in:
Tom Moor
2023-03-28 22:13:42 -04:00
committed by GitHub
parent 3108a26793
commit 7ba6a9379b
27 changed files with 45 additions and 552 deletions

View File

@@ -65,13 +65,7 @@ export default async function documentUpdater({
document.fullWidth = fullWidth;
}
if (text !== undefined) {
if (user.team?.collaborativeEditing) {
document = DocumentHelper.applyMarkdownToDocument(document, text, append);
} else if (append) {
document.text += text;
} else {
document.text = text;
}
document = DocumentHelper.applyMarkdownToDocument(document, text, append);
}
const changed = document.changed();

View File

@@ -21,7 +21,6 @@ const teamUpdater = async ({ params, user, team, ip }: TeamUpdaterProps) => {
guestSignin,
documentEmbeds,
memberCollectionCreate,
collaborativeEditing,
defaultCollectionId,
defaultUserRole,
inviteRequired,
@@ -56,9 +55,6 @@ const teamUpdater = async ({ params, user, team, ip }: TeamUpdaterProps) => {
if (defaultCollectionId !== undefined) {
team.defaultCollectionId = defaultCollectionId;
}
if (collaborativeEditing !== undefined) {
team.collaborativeEditing = collaborativeEditing;
}
if (defaultUserRole !== undefined) {
team.defaultUserRole = defaultUserRole;
}

View File

@@ -136,10 +136,6 @@ class Team extends ParanoidModel {
@Column
memberCollectionCreate: boolean;
@Default(true)
@Column
collaborativeEditing: boolean;
@Default("member")
@IsIn([["viewer", "member"]])
@Column

View File

@@ -7,7 +7,6 @@ export default function presentTeam(team: Team) {
avatarUrl: team.avatarUrl,
sharing: team.sharing,
memberCollectionCreate: team.memberCollectionCreate,
collaborativeEditing: team.collaborativeEditing,
defaultCollectionId: team.defaultCollectionId,
documentEmbeds: team.documentEmbeds,
guestSignin: team.emailSigninEnabled,

View File

@@ -220,46 +220,3 @@ describe("documents.delete", () => {
expect(backlinks.length).toBe(0);
});
});
describe("documents.title_change", () => {
test("should update titles in backlinked documents", async () => {
const newTitle = "test";
const document = await buildDocument();
const otherDocument = await buildDocument();
const previousTitle = otherDocument.title;
// create a doc with a link back
document.text = `[${otherDocument.title}](${otherDocument.url})`;
await document.save();
// ensure the backlinks are created
const processor = new BacklinksProcessor();
await processor.perform({
name: "documents.update",
documentId: document.id,
collectionId: document.collectionId,
teamId: document.teamId,
actorId: document.createdById,
createdAt: new Date().toISOString(),
data: { title: document.title, autosave: false, done: true },
ip,
});
// change the title of the linked doc
otherDocument.title = newTitle;
await otherDocument.save();
// does the text get updated with the new title
await processor.perform({
name: "documents.title_change",
documentId: otherDocument.id,
collectionId: otherDocument.collectionId,
teamId: otherDocument.teamId,
actorId: otherDocument.createdById,
createdAt: new Date().toISOString(),
data: {
previousTitle,
title: newTitle,
},
ip,
});
await document.reload();
expect(document.text).toBe(`[${newTitle}](${otherDocument.url})`);
});
});

View File

@@ -1,15 +1,14 @@
import { Op } from "sequelize";
import { Document, Backlink, Team } from "@server/models";
import { Document, Backlink } from "@server/models";
import { Event, DocumentEvent, RevisionEvent } from "@server/types";
import parseDocumentIds from "@server/utils/parseDocumentIds";
import slugify from "@server/utils/slugify";
import BaseProcessor from "./BaseProcessor";
export default class BacklinksProcessor extends BaseProcessor {
static applicableEvents: Event["name"][] = [
"documents.publish",
"documents.update",
"documents.title_change",
//"documents.title_change",
"documents.delete",
];
@@ -98,49 +97,7 @@ export default class BacklinksProcessor extends BaseProcessor {
break;
}
const document = await Document.findByPk(event.documentId);
if (!document) {
return;
}
// TODO: Handle re-writing of titles into CRDT
const team = await Team.findByPk(document.teamId);
if (team?.collaborativeEditing) {
break;
}
// update any link titles in documents that lead to this one
const backlinks = await Backlink.findAll({
where: {
documentId: event.documentId,
},
include: [
{
model: Document,
as: "reverseDocument",
},
],
});
await Promise.all(
backlinks.map(async (backlink) => {
const previousUrl = `/doc/${slugify(previousTitle)}-${
document.urlId
}`;
// find links in the other document that lead to this one and have
// the old title as anchor text. Go ahead and update those to the
// new title automatically
backlink.reverseDocument.text = backlink.reverseDocument.text.replace(
`[${previousTitle}](${previousUrl})`,
`[${title}](${document.url})`
);
await backlink.reverseDocument.save({
silent: true,
hooks: false,
});
})
);
break;
}

View File

@@ -45,15 +45,6 @@ exports[`#documents.search should require authentication 1`] = `
}
`;
exports[`#documents.update should fail if document lastRevision does not match 1`] = `
{
"error": "invalid_request",
"message": "Document has changed since last revision",
"ok": false,
"status": 400,
}
`;
exports[`#documents.update should require authentication 1`] = `
{
"error": "authentication_required",

View File

@@ -2456,7 +2456,6 @@ describe("#documents.update", () => {
id: document.id,
title: "Updated title",
text: "Updated text",
lastRevision: document.revisionCount,
},
});
const body = await res.json();
@@ -2478,7 +2477,6 @@ describe("#documents.update", () => {
id: document.id,
title: "Updated title",
text: "Updated text",
lastRevision: document.revisionCount,
publish: true,
},
});
@@ -2503,7 +2501,6 @@ describe("#documents.update", () => {
id: document.id,
title: "Updated title",
text: "Updated text",
lastRevision: document.revisionCount,
collectionId: collection.id,
publish: true,
},
@@ -2526,7 +2523,6 @@ describe("#documents.update", () => {
id: document.id,
title: "Updated title",
text: "Updated text",
lastRevision: document.revisionCount,
collectionId: collection.id,
publish: true,
},
@@ -2551,7 +2547,6 @@ describe("#documents.update", () => {
id: template.id,
title: "Updated title",
text: "Updated text",
lastRevision: template.revisionCount,
publish: true,
},
});
@@ -2582,7 +2577,6 @@ describe("#documents.update", () => {
id: document.id,
title: "Updated title",
text: "Updated text",
lastRevision: document.revisionCount,
publish: true,
},
});
@@ -2603,27 +2597,11 @@ describe("#documents.update", () => {
id: document.id,
title: "Updated title",
text: "Updated text",
lastRevision: document.revisionCount,
},
});
expect(res.status).toEqual(403);
});
it("should fail if document lastRevision does not match", async () => {
const { user, document } = await seed();
const res = await server.post("/api/documents.update", {
body: {
token: user.getJwtToken(),
id: document.id,
text: "Updated text",
lastRevision: 123,
},
});
const body = await res.json();
expect(res.status).toEqual(400);
expect(body).toMatchSnapshot();
});
it("should update document details for children", async () => {
const { user, document, collection } = await seed();
collection.documentStructure = [
@@ -2670,7 +2648,6 @@ describe("#documents.update", () => {
token: admin.getJwtToken(),
id: document.id,
text: "Changed text",
lastRevision: document.revisionCount,
},
});
const body = await res.json();
@@ -2694,7 +2671,6 @@ describe("#documents.update", () => {
token: user.getJwtToken(),
id: document.id,
text: "Changed text",
lastRevision: document.revisionCount,
},
});
expect(res.status).toEqual(403);
@@ -2709,7 +2685,6 @@ describe("#documents.update", () => {
token: user.getJwtToken(),
id: document.id,
text: "Changed text",
lastRevision: document.revisionCount,
},
});
expect(res.status).toEqual(403);
@@ -2722,7 +2697,6 @@ describe("#documents.update", () => {
token: user.getJwtToken(),
id: document.id,
text: "Additional text",
lastRevision: document.revisionCount,
append: true,
},
});
@@ -2738,7 +2712,6 @@ describe("#documents.update", () => {
body: {
token: user.getJwtToken(),
id: document.id,
lastRevision: document.revisionCount,
title: "Updated Title",
append: true,
},
@@ -2754,7 +2727,6 @@ describe("#documents.update", () => {
body: {
token: user.getJwtToken(),
id: document.id,
lastRevision: document.revisionCount,
title: "Updated Title",
text: "",
},
@@ -2770,7 +2742,6 @@ describe("#documents.update", () => {
body: {
token: user.getJwtToken(),
id: document.id,
lastRevision: document.revisionCount,
title: document.title,
text: document.text,
},
@@ -2851,7 +2822,6 @@ describe("#documents.update", () => {
id: document.id,
title: "Updated title",
text: "Updated text",
lastRevision: document.revisionCount,
collectionId: collection.id,
publish: true,
},

View File

@@ -880,7 +880,6 @@ router.post(
text,
fullWidth,
publish,
lastRevision,
templateId,
collectionId,
append,
@@ -908,10 +907,6 @@ router.post(
authorize(user, "publish", collection);
}
if (lastRevision && lastRevision !== document.revisionCount) {
throw InvalidRequestError("Document has changed since last revision");
}
collection = await sequelize.transaction(async (transaction) => {
await documentUpdater({
document,

View File

@@ -190,9 +190,6 @@ export const DocumentsUpdateSchema = BaseSchema.extend({
/** Boolean to denote if the doc should be published */
publish: z.boolean().optional(),
/** Revision to compare against document revision count */
lastRevision: z.number().optional(),
/** Doc template Id */
templateId: z.string().uuid().nullish(),

View File

@@ -18,8 +18,6 @@ export const TeamsUpdateSchema = BaseSchema.extend({
documentEmbeds: z.boolean().optional(),
/** Whether team members are able to create new collections */
memberCollectionCreate: z.boolean().optional(),
/** Whether collaborative editing is enabled */
collaborativeEditing: z.boolean().optional(),
/** The default landing collection for the team */
defaultCollectionId: z.string().uuid().nullish(),
/** The default user role */

View File

@@ -8,7 +8,7 @@ import Logger from "@server/logging/Logger";
import Metrics from "@server/logging/Metrics";
import * as Tracing from "@server/logging/tracer";
import { traceFunction } from "@server/logging/tracing";
import { Document, Collection, View, User } from "@server/models";
import { Collection, User } from "@server/models";
import { can } from "@server/policies";
import ShutdownHelper, { ShutdownOrder } from "@server/utils/ShutdownHelper";
import { getUserForJWT } from "@server/utils/jwt";
@@ -186,58 +186,6 @@ async function authenticated(io: IO.Server, socket: SocketWithAuth) {
Metrics.increment("websockets.collections.join");
}
}
// user is joining a document channel, because they have navigated to
// view a document.
if (event.documentId) {
const document = await Document.findByPk(event.documentId, {
userId: user.id,
});
if (can(user, "read", document)) {
const room = `document-${event.documentId}`;
await View.touch(event.documentId, user.id, event.isEditing);
const editing = await View.findRecentlyEditingByDocument(
event.documentId
);
await socket.join(room);
Metrics.increment("websockets.documents.join");
// let everyone else in the room know that a new user joined
io.to(room).emit("user.join", {
userId: user.id,
documentId: event.documentId,
isEditing: event.isEditing,
});
// let this user know who else is already present in the room
try {
const socketIds = await io.in(room).allSockets();
// because a single user can have multiple socket connections we
// need to make sure that only unique userIds are returned. A Map
// makes this easy.
const userIds = new Map();
for (const socketId of socketIds) {
const userId = await Redis.defaultClient.hget(socketId, "userId");
userIds.set(userId, userId);
}
socket.emit("document.presence", {
documentId: event.documentId,
userIds: Array.from(userIds.keys()),
editingIds: editing.map((view) => view.userId),
});
} catch (err) {
if (err) {
Logger.error("Error getting clients for room", err);
return;
}
}
}
}
});
// allow the client to request to leave rooms
@@ -246,56 +194,6 @@ async function authenticated(io: IO.Server, socket: SocketWithAuth) {
await socket.leave(`collection-${event.collectionId}`);
Metrics.increment("websockets.collections.leave");
}
if (event.documentId) {
const room = `document-${event.documentId}`;
await socket.leave(room);
Metrics.increment("websockets.documents.leave");
io.to(room).emit("user.leave", {
userId: user.id,
documentId: event.documentId,
});
}
});
socket.on("disconnecting", () => {
socket.rooms.forEach((room) => {
if (room.startsWith("document-")) {
const documentId = room.replace("document-", "");
io.to(room).emit("user.leave", {
userId: user.id,
documentId,
});
}
});
});
socket.on("presence", async (event) => {
Metrics.increment("websockets.presence");
const room = `document-${event.documentId}`;
if (event.documentId && socket.rooms.has(room)) {
await View.touch(event.documentId, user.id, event.isEditing);
io.to(room).emit("user.presence", {
userId: user.id,
documentId: event.documentId,
isEditing: event.isEditing,
});
socket.on("typing", async (event) => {
const room = `document-${event.documentId}`;
if (event.documentId && socket.rooms[room]) {
io.to(room).emit("user.typing", {
userId: user.id,
documentId: event.documentId,
commentId: event.commentId,
});
}
});
}
});
}

View File

@@ -123,7 +123,6 @@ export function buildTeam(overrides: Record<string, any> = {}) {
return Team.create(
{
name: `Team ${count}`,
collaborativeEditing: false,
authenticationProviders: [
{
name: "slack",

View File

@@ -11,7 +11,6 @@ export const seed = async () => {
const team = await Team.create(
{
name: "Team",
collaborativeEditing: false,
authenticationProviders: [
{
name: "slack",