chore: Enable eslint to enforce curly (#3060)
This commit is contained in:
@@ -27,7 +27,9 @@ router.get("/:type/:format", async (ctx) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (!mailerOutput) return;
|
||||
if (!mailerOutput) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.params.format === "text") {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'text' does not exist on type 'never'.
|
||||
|
||||
@@ -92,8 +92,12 @@ class Attachment extends BaseModel {
|
||||
query: FindOptions<Attachment>
|
||||
) => Promise<void>
|
||||
) {
|
||||
if (!query.offset) query.offset = 0;
|
||||
if (!query.limit) query.limit = 10;
|
||||
if (!query.offset) {
|
||||
query.offset = 0;
|
||||
}
|
||||
if (!query.limit) {
|
||||
query.limit = 10;
|
||||
}
|
||||
let results;
|
||||
|
||||
do {
|
||||
|
||||
@@ -186,7 +186,9 @@ class Collection extends ParanoidModel {
|
||||
// getters
|
||||
|
||||
get url(): string {
|
||||
if (!this.name) return `/collection/untitled-${this.urlId}`;
|
||||
if (!this.name) {
|
||||
return `/collection/untitled-${this.urlId}`;
|
||||
}
|
||||
return `/collection/${slugify(this.name)}-${this.urlId}`;
|
||||
}
|
||||
|
||||
@@ -354,7 +356,9 @@ class Collection extends ParanoidModel {
|
||||
}
|
||||
|
||||
getDocumentTree = (documentId: string): NavigationNode | null => {
|
||||
if (!this.documentStructure) return null;
|
||||
if (!this.documentStructure) {
|
||||
return null;
|
||||
}
|
||||
const sort: Sort = this.sort || {
|
||||
field: "title",
|
||||
direction: "asc",
|
||||
@@ -386,7 +390,9 @@ class Collection extends ParanoidModel {
|
||||
loopChildren(this.documentStructure);
|
||||
|
||||
// if the document is a draft loopChildren will not find it in the structure
|
||||
if (!result) return null;
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...result,
|
||||
@@ -548,7 +554,9 @@ class Collection extends ParanoidModel {
|
||||
* Update document's title and url in the documentStructure
|
||||
*/
|
||||
updateDocument = async function (updatedDocument: Document) {
|
||||
if (!this.documentStructure) return;
|
||||
if (!this.documentStructure) {
|
||||
return;
|
||||
}
|
||||
let transaction;
|
||||
|
||||
try {
|
||||
|
||||
@@ -127,7 +127,9 @@ export const DOCUMENT_VERSION = 2;
|
||||
],
|
||||
},
|
||||
withViews: (userId: string) => {
|
||||
if (!userId) return {};
|
||||
if (!userId) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
include: [
|
||||
{
|
||||
@@ -215,7 +217,9 @@ class Document extends ParanoidModel {
|
||||
// getters
|
||||
|
||||
get url() {
|
||||
if (!this.title) return `/doc/untitled-${this.urlId}`;
|
||||
if (!this.title) {
|
||||
return `/doc/untitled-${this.urlId}`;
|
||||
}
|
||||
const slugifiedTitle = slugify(this.title);
|
||||
return `/doc/${slugifiedTitle}-${this.urlId}`;
|
||||
}
|
||||
@@ -721,7 +725,9 @@ class Document extends ParanoidModel {
|
||||
};
|
||||
|
||||
publish = async (userId: string, options?: FindOptions<Document>) => {
|
||||
if (this.publishedAt) return this.save(options);
|
||||
if (this.publishedAt) {
|
||||
return this.save(options);
|
||||
}
|
||||
|
||||
if (!this.template) {
|
||||
const collection = await Collection.findByPk(this.collectionId);
|
||||
@@ -735,7 +741,9 @@ class Document extends ParanoidModel {
|
||||
};
|
||||
|
||||
unpublish = async (userId: string, options?: FindOptions<Document>) => {
|
||||
if (!this.publishedAt) return this;
|
||||
if (!this.publishedAt) {
|
||||
return this;
|
||||
}
|
||||
const collection = await this.$get("collection");
|
||||
await collection?.removeDocumentInStructure(this);
|
||||
|
||||
@@ -777,7 +785,9 @@ class Document extends ParanoidModel {
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!parent) this.parentDocumentId = null;
|
||||
if (!parent) {
|
||||
this.parentDocumentId = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.template && collection) {
|
||||
|
||||
@@ -58,7 +58,9 @@ class Group extends ParanoidModel {
|
||||
|
||||
@AfterDestroy
|
||||
static async deleteGroupUsers(model: Group) {
|
||||
if (!model.deletedAt) return;
|
||||
if (!model.deletedAt) {
|
||||
return;
|
||||
}
|
||||
await GroupUser.destroy({
|
||||
where: {
|
||||
groupId: model.id,
|
||||
|
||||
@@ -125,7 +125,9 @@ class Team extends ParanoidModel {
|
||||
requestedSubdomain: string,
|
||||
options = {}
|
||||
) {
|
||||
if (this.subdomain) return this.subdomain;
|
||||
if (this.subdomain) {
|
||||
return this.subdomain;
|
||||
}
|
||||
let subdomain = requestedSubdomain;
|
||||
let append = 0;
|
||||
|
||||
@@ -234,7 +236,9 @@ class Team extends ParanoidModel {
|
||||
`avatars/${model.id}/${uuidv4()}`,
|
||||
"public-read"
|
||||
);
|
||||
if (newUrl) model.avatarUrl = newUrl;
|
||||
if (newUrl) {
|
||||
model.avatarUrl = newUrl;
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error("Error uploading avatar to S3", err, {
|
||||
url: avatarUrl,
|
||||
|
||||
@@ -360,7 +360,9 @@ class User extends ParanoidModel {
|
||||
`avatars/${model.id}/${uuidv4()}`,
|
||||
"public-read"
|
||||
);
|
||||
if (newUrl) model.avatarUrl = newUrl;
|
||||
if (newUrl) {
|
||||
model.avatarUrl = newUrl;
|
||||
}
|
||||
} catch (err) {
|
||||
Logger.error("Couldn't upload user avatar image to S3", err, {
|
||||
url: avatarUrl,
|
||||
@@ -452,8 +454,12 @@ class User extends ParanoidModel {
|
||||
query: FindOptions<User>,
|
||||
callback: (users: Array<User>, query: FindOptions<User>) => Promise<void>
|
||||
) {
|
||||
if (!query.offset) query.offset = 0;
|
||||
if (!query.limit) query.limit = 10;
|
||||
if (!query.offset) {
|
||||
query.offset = 0;
|
||||
}
|
||||
if (!query.limit) {
|
||||
query.limit = 10;
|
||||
}
|
||||
let results;
|
||||
|
||||
do {
|
||||
|
||||
@@ -2,12 +2,18 @@ import { ApiKey, User, Team } from "@server/models";
|
||||
import { allow } from "./cancan";
|
||||
|
||||
allow(User, "createApiKey", Team, (user, team) => {
|
||||
if (!team || user.isViewer || user.teamId !== team.id) return false;
|
||||
if (!team || user.isViewer || user.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
allow(User, ["read", "update", "delete"], ApiKey, (user, apiKey) => {
|
||||
if (!apiKey) return false;
|
||||
if (user.isViewer) return false;
|
||||
if (!apiKey) {
|
||||
return false;
|
||||
}
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
return user && user.id === apiKey.userId;
|
||||
});
|
||||
|
||||
@@ -2,21 +2,37 @@ import { Attachment, User, Team } from "@server/models";
|
||||
import { allow } from "./cancan";
|
||||
|
||||
allow(User, "createAttachment", Team, (user, team) => {
|
||||
if (!team || user.isViewer || user.teamId !== team.id) return false;
|
||||
if (!team || user.isViewer || user.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
allow(User, "read", Attachment, (actor, attachment) => {
|
||||
if (!attachment || attachment.teamId !== actor.teamId) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (actor.id === attachment.userId) return true;
|
||||
if (!attachment || attachment.teamId !== actor.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
if (actor.id === attachment.userId) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
allow(User, "delete", Attachment, (actor, attachment) => {
|
||||
if (actor.isViewer) return false;
|
||||
if (!attachment || attachment.teamId !== actor.teamId) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (actor.id === attachment.userId) return true;
|
||||
if (actor.isViewer) {
|
||||
return false;
|
||||
}
|
||||
if (!attachment || attachment.teamId !== actor.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
if (actor.id === attachment.userId) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -3,8 +3,12 @@ import { AdminRequiredError } from "../errors";
|
||||
import { allow } from "./cancan";
|
||||
|
||||
allow(User, "createAuthenticationProvider", Team, (actor, team) => {
|
||||
if (!team || actor.teamId !== team.id) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!team || actor.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
@@ -24,8 +28,12 @@ allow(
|
||||
AuthenticationProvider,
|
||||
|
||||
(actor, authenticationProvider) => {
|
||||
if (actor.teamId !== authenticationProvider?.teamId) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (actor.teamId !== authenticationProvider?.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
}
|
||||
|
||||
@@ -5,27 +5,41 @@ import { AdminRequiredError } from "../errors";
|
||||
import { allow } from "./cancan";
|
||||
|
||||
allow(User, "createCollection", Team, (user, team) => {
|
||||
if (!team || user.isViewer || user.teamId !== team.id) return false;
|
||||
if (!team || user.isViewer || user.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
allow(User, "importCollection", Team, (actor, team) => {
|
||||
if (!team || actor.teamId !== team.id) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!team || actor.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
allow(User, "move", Collection, (user, collection) => {
|
||||
if (!collection || user.teamId !== collection.teamId) return false;
|
||||
if (collection.deletedAt) return false;
|
||||
if (user.isAdmin) return true;
|
||||
if (!collection || user.teamId !== collection.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (collection.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (user.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
allow(User, "read", Collection, (user, collection) => {
|
||||
if (!collection || user.teamId !== collection.teamId) return false;
|
||||
if (!collection || user.teamId !== collection.teamId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!collection.permission) {
|
||||
invariant(
|
||||
@@ -45,9 +59,15 @@ allow(User, "read", Collection, (user, collection) => {
|
||||
});
|
||||
|
||||
allow(User, "share", Collection, (user, collection) => {
|
||||
if (user.isViewer) return false;
|
||||
if (!collection || user.teamId !== collection.teamId) return false;
|
||||
if (!collection.sharing) return false;
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
if (!collection || user.teamId !== collection.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (!collection.sharing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (collection.permission !== "read_write") {
|
||||
invariant(
|
||||
@@ -67,8 +87,12 @@ allow(User, "share", Collection, (user, collection) => {
|
||||
});
|
||||
|
||||
allow(User, ["publish", "update"], Collection, (user, collection) => {
|
||||
if (user.isViewer) return false;
|
||||
if (!collection || user.teamId !== collection.teamId) return false;
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
if (!collection || user.teamId !== collection.teamId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (collection.permission !== "read_write") {
|
||||
invariant(
|
||||
@@ -88,8 +112,12 @@ allow(User, ["publish", "update"], Collection, (user, collection) => {
|
||||
});
|
||||
|
||||
allow(User, "delete", Collection, (user, collection) => {
|
||||
if (user.isViewer) return false;
|
||||
if (!collection || user.teamId !== collection.teamId) return false;
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
if (!collection || user.teamId !== collection.teamId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (collection.permission !== "read_write") {
|
||||
invariant(
|
||||
@@ -105,8 +133,12 @@ allow(User, "delete", Collection, (user, collection) => {
|
||||
);
|
||||
}
|
||||
|
||||
if (user.isAdmin) return true;
|
||||
if (user.id === collection.createdById) return true;
|
||||
if (user.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
if (user.id === collection.createdById) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
@@ -4,12 +4,16 @@ import { NavigationNode } from "~/types";
|
||||
import { allow, _cannot as cannot } from "./cancan";
|
||||
|
||||
allow(User, "createDocument", Team, (user, team) => {
|
||||
if (!team || user.isViewer || user.teamId !== team.id) return false;
|
||||
if (!team || user.isViewer || user.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
allow(User, ["read", "download"], Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// existence of collection option is not required here to account for share tokens
|
||||
if (document.collection && cannot(user, "read", document.collection)) {
|
||||
@@ -20,33 +24,55 @@ allow(User, ["read", "download"], Document, (user, document) => {
|
||||
});
|
||||
|
||||
allow(User, "star", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (document.template) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.template) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
if (cannot(user, "read", document.collection)) return false;
|
||||
if (cannot(user, "read", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
return user.teamId === document.teamId;
|
||||
});
|
||||
|
||||
allow(User, "unstar", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.template) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.template) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
if (cannot(user, "read", document.collection)) return false;
|
||||
if (cannot(user, "read", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
return user.teamId === document.teamId;
|
||||
});
|
||||
|
||||
allow(User, "share", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
@@ -60,9 +86,15 @@ allow(User, "share", Document, (user, document) => {
|
||||
});
|
||||
|
||||
allow(User, "update", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cannot(user, "update", document.collection)) {
|
||||
return false;
|
||||
@@ -72,60 +104,110 @@ allow(User, "update", Document, (user, document) => {
|
||||
});
|
||||
|
||||
allow(User, "createChildDocument", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (document.template) return false;
|
||||
if (!document.publishedAt) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.template) {
|
||||
return false;
|
||||
}
|
||||
if (!document.publishedAt) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
if (cannot(user, "update", document.collection)) return false;
|
||||
if (cannot(user, "update", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
return user.teamId === document.teamId;
|
||||
});
|
||||
|
||||
allow(User, "move", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (!document.publishedAt) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (!document.publishedAt) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
if (cannot(user, "update", document.collection)) return false;
|
||||
if (cannot(user, "update", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
return user.teamId === document.teamId;
|
||||
});
|
||||
|
||||
allow(User, ["pin", "unpin"], Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (document.template) return false;
|
||||
if (!document.publishedAt) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.template) {
|
||||
return false;
|
||||
}
|
||||
if (!document.publishedAt) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
if (cannot(user, "update", document.collection)) return false;
|
||||
if (cannot(user, "update", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
return user.teamId === document.teamId;
|
||||
});
|
||||
|
||||
allow(User, ["pinToHome"], Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (document.template) return false;
|
||||
if (!document.publishedAt) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.template) {
|
||||
return false;
|
||||
}
|
||||
if (!document.publishedAt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.teamId === document.teamId && user.isAdmin;
|
||||
});
|
||||
|
||||
allow(User, "delete", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (user.isViewer) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// allow deleting document without a collection
|
||||
if (document.collection && cannot(user, "update", document.collection)) {
|
||||
@@ -145,9 +227,15 @@ allow(User, "delete", Document, (user, document) => {
|
||||
});
|
||||
|
||||
allow(User, "permanentDelete", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (!document.deletedAt) return false;
|
||||
if (user.isViewer) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (!document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// allow deleting document without a collection
|
||||
if (document.collection && cannot(user, "update", document.collection)) {
|
||||
@@ -158,9 +246,15 @@ allow(User, "permanentDelete", Document, (user, document) => {
|
||||
});
|
||||
|
||||
allow(User, "restore", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (!document.deletedAt) return false;
|
||||
if (user.isViewer) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (!document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (document.collection && cannot(user, "update", document.collection)) {
|
||||
return false;
|
||||
@@ -170,27 +264,45 @@ allow(User, "restore", Document, (user, document) => {
|
||||
});
|
||||
|
||||
allow(User, "archive", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (!document.publishedAt) return false;
|
||||
if (document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
if (!document.publishedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
if (cannot(user, "update", document.collection)) return false;
|
||||
if (cannot(user, "update", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
return user.teamId === document.teamId;
|
||||
});
|
||||
|
||||
allow(User, "unarchive", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
if (cannot(user, "update", document.collection)) return false;
|
||||
if (!document.archivedAt) return false;
|
||||
if (document.deletedAt) return false;
|
||||
if (cannot(user, "update", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
if (!document.archivedAt) {
|
||||
return false;
|
||||
}
|
||||
if (document.deletedAt) {
|
||||
return false;
|
||||
}
|
||||
return user.teamId === document.teamId;
|
||||
});
|
||||
|
||||
@@ -202,19 +314,26 @@ allow(
|
||||
);
|
||||
|
||||
allow(User, "unpublish", Document, (user, document) => {
|
||||
if (!document) return false;
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
invariant(
|
||||
document.collection,
|
||||
"collection is missing, did you forget to include in the query scope?"
|
||||
);
|
||||
if (!document.publishedAt || !!document.deletedAt || !!document.archivedAt)
|
||||
if (!document.publishedAt || !!document.deletedAt || !!document.archivedAt) {
|
||||
return false;
|
||||
if (cannot(user, "update", document.collection)) return false;
|
||||
}
|
||||
if (cannot(user, "update", document.collection)) {
|
||||
return false;
|
||||
}
|
||||
const documentID = document.id;
|
||||
|
||||
const hasChild = (documents: NavigationNode[]): boolean =>
|
||||
documents.some((doc) => {
|
||||
if (doc.id === documentID) return doc.children.length > 0;
|
||||
if (doc.id === documentID) {
|
||||
return doc.children.length > 0;
|
||||
}
|
||||
return hasChild(doc.children);
|
||||
});
|
||||
|
||||
|
||||
@@ -3,8 +3,12 @@ import { AdminRequiredError } from "../errors";
|
||||
import { allow } from "./cancan";
|
||||
|
||||
allow(User, "createGroup", Team, (actor, team) => {
|
||||
if (!team || actor.isViewer || actor.teamId !== team.id) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!team || actor.isViewer || actor.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
@@ -12,13 +16,19 @@ allow(User, "createGroup", Team, (actor, team) => {
|
||||
allow(User, "read", Group, (actor, group) => {
|
||||
// for the time being, we're going to let everyone on the team see every group
|
||||
// we may need to make this more granular in the future
|
||||
if (!group || actor.teamId !== group.teamId) return false;
|
||||
if (!group || actor.teamId !== group.teamId) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
allow(User, ["update", "delete"], Group, (actor, group) => {
|
||||
if (!group || actor.isViewer || actor.teamId !== group.teamId) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!group || actor.isViewer || actor.teamId !== group.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
@@ -3,8 +3,12 @@ import { AdminRequiredError } from "../errors";
|
||||
import { allow } from "./cancan";
|
||||
|
||||
allow(User, "createIntegration", Team, (actor, team) => {
|
||||
if (!team || actor.isViewer || actor.teamId !== team.id) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!team || actor.isViewer || actor.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
@@ -17,9 +21,15 @@ allow(
|
||||
);
|
||||
|
||||
allow(User, ["update", "delete"], Integration, (user, integration) => {
|
||||
if (user.isViewer) return false;
|
||||
if (!integration || user.teamId !== integration.teamId) return false;
|
||||
if (user.isAdmin) return true;
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
if (!integration || user.teamId !== integration.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (user.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
@@ -2,7 +2,9 @@ import { NotificationSetting, Team, User } from "@server/models";
|
||||
import { allow } from "./cancan";
|
||||
|
||||
allow(User, "createNotificationSetting", Team, (user, team) => {
|
||||
if (!team || user.teamId !== team.id) return false;
|
||||
if (!team || user.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -5,21 +5,37 @@ import { allow, _cannot as cannot } from "./cancan";
|
||||
allow(User, "read", Share, (user, share) => user.teamId === share?.teamId);
|
||||
|
||||
allow(User, "update", Share, (user, share) => {
|
||||
if (!share) return false;
|
||||
if (user.isViewer) return false;
|
||||
if (!share) {
|
||||
return false;
|
||||
}
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// only the user who can share the document publicly can update the share.
|
||||
if (cannot(user, "share", share.document)) return false;
|
||||
if (cannot(user, "share", share.document)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return user.teamId === share.teamId;
|
||||
});
|
||||
|
||||
allow(User, "revoke", Share, (user, share) => {
|
||||
if (!share) return false;
|
||||
if (user.isViewer) return false;
|
||||
if (user.teamId !== share.teamId) return false;
|
||||
if (user.id === share.userId) return true;
|
||||
if (user.isAdmin) return true;
|
||||
if (!share) {
|
||||
return false;
|
||||
}
|
||||
if (user.isViewer) {
|
||||
return false;
|
||||
}
|
||||
if (user.teamId !== share.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (user.id === share.userId) {
|
||||
return true;
|
||||
}
|
||||
if (user.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
@@ -4,11 +4,15 @@ import { allow } from "./cancan";
|
||||
allow(User, "read", Team, (user, team) => user.teamId === team?.id);
|
||||
|
||||
allow(User, "share", Team, (user, team) => {
|
||||
if (!team || user.isViewer || user.teamId !== team.id) return false;
|
||||
if (!team || user.isViewer || user.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
return team.sharing;
|
||||
});
|
||||
|
||||
allow(User, ["update", "export", "manage"], Team, (user, team) => {
|
||||
if (!team || user.isViewer || user.teamId !== team.id) return false;
|
||||
if (!team || user.isViewer || user.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
return user.isAdmin;
|
||||
});
|
||||
|
||||
@@ -10,52 +10,86 @@ allow(
|
||||
);
|
||||
|
||||
allow(User, "inviteUser", Team, (actor, team) => {
|
||||
if (!team || actor.teamId !== team.id) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!team || actor.teamId !== team.id) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
allow(User, "update", User, (actor, user) => {
|
||||
if (!user || user.teamId !== actor.teamId) return false;
|
||||
if (user.id === actor.id) return true;
|
||||
if (!user || user.teamId !== actor.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (user.id === actor.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
allow(User, "delete", User, (actor, user) => {
|
||||
if (!user || user.teamId !== actor.teamId) return false;
|
||||
if (user.id === actor.id) return true;
|
||||
if (actor.isAdmin && !user.lastActiveAt) return true;
|
||||
if (!user || user.teamId !== actor.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (user.id === actor.id) {
|
||||
return true;
|
||||
}
|
||||
if (actor.isAdmin && !user.lastActiveAt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
allow(User, ["activate", "suspend"], User, (actor, user) => {
|
||||
if (!user || user.teamId !== actor.teamId) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!user || user.teamId !== actor.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
allow(User, "readDetails", User, (actor, user) => {
|
||||
if (!user || user.teamId !== actor.teamId) return false;
|
||||
if (user === actor) return true;
|
||||
if (!user || user.teamId !== actor.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (user === actor) {
|
||||
return true;
|
||||
}
|
||||
return actor.isAdmin;
|
||||
});
|
||||
|
||||
allow(User, "promote", User, (actor, user) => {
|
||||
if (!user || user.teamId !== actor.teamId) return false;
|
||||
if (user.isAdmin || user.isSuspended) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!user || user.teamId !== actor.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (user.isAdmin || user.isSuspended) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
allow(User, "demote", User, (actor, user) => {
|
||||
if (!user || user.teamId !== actor.teamId) return false;
|
||||
if (user.isSuspended) return false;
|
||||
if (actor.isAdmin) return true;
|
||||
if (!user || user.teamId !== actor.teamId) {
|
||||
return false;
|
||||
}
|
||||
if (user.isSuspended) {
|
||||
return false;
|
||||
}
|
||||
if (actor.isAdmin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw AdminRequiredError();
|
||||
});
|
||||
|
||||
@@ -9,7 +9,9 @@ export default class BacklinksProcessor {
|
||||
switch (event.name) {
|
||||
case "documents.publish": {
|
||||
const document = await Document.findByPk(event.documentId);
|
||||
if (!document) return;
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
const linkIds = parseDocumentIds(document.text);
|
||||
await Promise.all(
|
||||
linkIds.map(async (linkId) => {
|
||||
@@ -35,10 +37,14 @@ export default class BacklinksProcessor {
|
||||
|
||||
case "documents.update": {
|
||||
const document = await Document.findByPk(event.documentId);
|
||||
if (!document) return;
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
// backlinks are only created for published documents
|
||||
if (!document.publishedAt) return;
|
||||
if (!document.publishedAt) {
|
||||
return;
|
||||
}
|
||||
|
||||
const linkIds = parseDocumentIds(document.text);
|
||||
const linkedDocumentIds: string[] = [];
|
||||
@@ -80,10 +86,14 @@ export default class BacklinksProcessor {
|
||||
case "documents.title_change": {
|
||||
// might as well check
|
||||
const { title, previousTitle } = event.data;
|
||||
if (!previousTitle || title === previousTitle) break;
|
||||
if (!previousTitle || title === previousTitle) {
|
||||
break;
|
||||
}
|
||||
|
||||
const document = await Document.findByPk(event.documentId);
|
||||
if (!document) return;
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Handle re-writing of titles into CRDT
|
||||
const team = await Team.findByPk(document.teamId);
|
||||
|
||||
@@ -21,12 +21,16 @@ export default class DebounceProcessor {
|
||||
});
|
||||
|
||||
// If the document has been deleted then prevent further processing
|
||||
if (!document) return;
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the document has been updated since we initially queued the delayed
|
||||
// event then abort, there must be another updated event in the queue –
|
||||
// this functions as a simple distributed debounce.
|
||||
if (document.updatedAt > new Date(event.createdAt)) return;
|
||||
if (document.updatedAt > new Date(event.createdAt)) {
|
||||
return;
|
||||
}
|
||||
|
||||
globalEventQueue.add({ ...event, name: "documents.update.debounced" });
|
||||
break;
|
||||
|
||||
@@ -33,12 +33,16 @@ export default class NotificationsProcessor {
|
||||
async documentUpdated(event: DocumentEvent | RevisionEvent) {
|
||||
// never send notifications when batch importing documents
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'data' does not exist on type 'DocumentEv... Remove this comment to see the full error message
|
||||
if (event.data?.source === "import") return;
|
||||
if (event.data?.source === "import") {
|
||||
return;
|
||||
}
|
||||
const [document, team] = await Promise.all([
|
||||
Document.findByPk(event.documentId),
|
||||
Team.findByPk(event.teamId),
|
||||
]);
|
||||
if (!document || !team || !document.collection) return;
|
||||
if (!document || !team || !document.collection) {
|
||||
return;
|
||||
}
|
||||
const { collection } = document;
|
||||
const notificationSettings = await NotificationSetting.findAll({
|
||||
where: {
|
||||
@@ -132,8 +136,12 @@ export default class NotificationsProcessor {
|
||||
},
|
||||
],
|
||||
});
|
||||
if (!collection) return;
|
||||
if (!collection.permission) return;
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
if (!collection.permission) {
|
||||
return;
|
||||
}
|
||||
const notificationSettings = await NotificationSetting.findAll({
|
||||
where: {
|
||||
userId: {
|
||||
|
||||
@@ -38,10 +38,14 @@ export default class SlackProcessor {
|
||||
},
|
||||
],
|
||||
});
|
||||
if (!integration) return;
|
||||
if (!integration) {
|
||||
return;
|
||||
}
|
||||
|
||||
const collection = integration.collection;
|
||||
if (!collection) return;
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
await fetch(integration.settings.url, {
|
||||
method: "POST",
|
||||
@@ -65,15 +69,21 @@ export default class SlackProcessor {
|
||||
async documentUpdated(event: DocumentEvent | RevisionEvent) {
|
||||
// never send notifications when batch importing documents
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'data' does not exist on type 'DocumentEv... Remove this comment to see the full error message
|
||||
if (event.data && event.data.source === "import") return;
|
||||
if (event.data && event.data.source === "import") {
|
||||
return;
|
||||
}
|
||||
const [document, team] = await Promise.all([
|
||||
Document.findByPk(event.documentId),
|
||||
Team.findByPk(event.teamId),
|
||||
]);
|
||||
if (!document || !team) return;
|
||||
if (!document || !team) {
|
||||
return;
|
||||
}
|
||||
|
||||
// never send notifications for draft documents
|
||||
if (!document.publishedAt) return;
|
||||
if (!document.publishedAt) {
|
||||
return;
|
||||
}
|
||||
|
||||
const integration = await Integration.findOne({
|
||||
where: {
|
||||
@@ -88,7 +98,9 @@ export default class SlackProcessor {
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!integration) return;
|
||||
if (!integration) {
|
||||
return;
|
||||
}
|
||||
let text = `${document.updatedBy.name} updated a document`;
|
||||
|
||||
if (event.name === "documents.publish") {
|
||||
|
||||
@@ -652,7 +652,9 @@ router.post("collections.delete", auth(), async (ctx) => {
|
||||
authorize(user, "delete", collection);
|
||||
|
||||
const total = await Collection.count();
|
||||
if (total === 1) throw ValidationError("Cannot delete last collection");
|
||||
if (total === 1) {
|
||||
throw ValidationError("Cannot delete last collection");
|
||||
}
|
||||
|
||||
await collection.destroy();
|
||||
await Event.create({
|
||||
|
||||
@@ -50,7 +50,9 @@ router.post("documents.list", auth(), pagination(), async (ctx) => {
|
||||
const collectionId = ctx.body.collectionId || ctx.body.collection;
|
||||
const createdById = ctx.body.userId || ctx.body.user;
|
||||
let direction = ctx.body.direction;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
// always filter by the current team
|
||||
const { user } = ctx.state;
|
||||
let where: WhereOptions<Document> = {
|
||||
@@ -162,7 +164,9 @@ router.post("documents.archived", auth(), pagination(), async (ctx) => {
|
||||
|
||||
assertSort(sort, Document);
|
||||
let direction = ctx.body.direction;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
const collectionIds = await user.collectionIds();
|
||||
const collectionScope: Readonly<ScopeOptions> = {
|
||||
@@ -204,7 +208,9 @@ router.post("documents.deleted", auth(), pagination(), async (ctx) => {
|
||||
|
||||
assertSort(sort, Document);
|
||||
let direction = ctx.body.direction;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
const collectionIds = await user.collectionIds({
|
||||
paranoid: false,
|
||||
@@ -257,7 +263,9 @@ router.post("documents.viewed", auth(), pagination(), async (ctx) => {
|
||||
const { sort = "updatedAt" } = ctx.body;
|
||||
|
||||
assertSort(sort, Document);
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
const collectionIds = await user.collectionIds();
|
||||
const userId = user.id;
|
||||
@@ -318,7 +326,9 @@ router.post("documents.starred", auth(), pagination(), async (ctx) => {
|
||||
const { sort = "updatedAt" } = ctx.body;
|
||||
|
||||
assertSort(sort, Document);
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
const collectionIds = await user.collectionIds();
|
||||
const stars = await Star.findAll({
|
||||
@@ -371,7 +381,9 @@ router.post("documents.drafts", auth(), pagination(), async (ctx) => {
|
||||
const { collectionId, dateFilter, sort = "updatedAt" } = ctx.body;
|
||||
|
||||
assertSort(sort, Document);
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
|
||||
if (collectionId) {
|
||||
@@ -997,7 +1009,9 @@ router.post("documents.update", auth(), async (ctx) => {
|
||||
const editorVersion = ctx.headers["x-editor-version"] as string | undefined;
|
||||
assertPresent(id, "id is required");
|
||||
assertPresent(title || text, "title or text is required");
|
||||
if (append) assertPresent(text, "Text is required while appending");
|
||||
if (append) {
|
||||
assertPresent(text, "Text is required while appending");
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
|
||||
const document = await Document.findByPk(id, {
|
||||
@@ -1012,10 +1026,18 @@ router.post("documents.update", auth(), async (ctx) => {
|
||||
const previousTitle = document.title;
|
||||
|
||||
// Update document
|
||||
if (title) document.title = title;
|
||||
if (editorVersion) document.editorVersion = editorVersion;
|
||||
if (templateId) document.templateId = templateId;
|
||||
if (fullWidth !== undefined) document.fullWidth = fullWidth;
|
||||
if (title) {
|
||||
document.title = title;
|
||||
}
|
||||
if (editorVersion) {
|
||||
document.editorVersion = editorVersion;
|
||||
}
|
||||
if (templateId) {
|
||||
document.templateId = templateId;
|
||||
}
|
||||
if (fullWidth !== undefined) {
|
||||
document.fullWidth = fullWidth;
|
||||
}
|
||||
|
||||
if (!user.team?.collaborativeEditing) {
|
||||
if (append) {
|
||||
@@ -1303,7 +1325,9 @@ router.post("documents.import", auth(), async (ctx) => {
|
||||
assertUuid(parentDocumentId, "parentDocumentId must be an uuid");
|
||||
}
|
||||
|
||||
if (index) assertPositiveInteger(index, "index must be an integer (>=0)");
|
||||
if (index) {
|
||||
assertPositiveInteger(index, "index must be an integer (>=0)");
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
authorize(user, "createDocument", user.team);
|
||||
|
||||
@@ -1372,7 +1396,9 @@ router.post("documents.create", auth(), async (ctx) => {
|
||||
assertUuid(parentDocumentId, "parentDocumentId must be an uuid");
|
||||
}
|
||||
|
||||
if (index) assertPositiveInteger(index, "index must be an integer (>=0)");
|
||||
if (index) {
|
||||
assertPositiveInteger(index, "index must be an integer (>=0)");
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
authorize(user, "createDocument", user.team);
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@ router.post("events.list", auth(), pagination(), async (ctx) => {
|
||||
name,
|
||||
auditLog = false,
|
||||
} = ctx.body;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
assertSort(sort, Event);
|
||||
|
||||
let where: WhereOptions<Event> = {
|
||||
|
||||
@@ -42,7 +42,9 @@ router.post("fileOperations.list", auth(), pagination(), async (ctx) => {
|
||||
"type must be one of 'import' or 'export'"
|
||||
);
|
||||
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
const { user } = ctx.state;
|
||||
const where: WhereOptions<FileOperation> = {
|
||||
teamId: user.teamId,
|
||||
|
||||
@@ -19,7 +19,9 @@ const router = new Router();
|
||||
router.post("groups.list", auth(), pagination(), async (ctx) => {
|
||||
let { direction } = ctx.body;
|
||||
const { sort = "updatedAt" } = ctx.body;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
|
||||
assertSort(sort, Group);
|
||||
const { user } = ctx.state;
|
||||
|
||||
@@ -21,7 +21,9 @@ const router = new Router();
|
||||
// triggered by a user posting a getoutline.com link in Slack
|
||||
router.post("hooks.unfurl", async (ctx) => {
|
||||
const { challenge, token, event } = ctx.body;
|
||||
if (challenge) return (ctx.body = ctx.body.challenge);
|
||||
if (challenge) {
|
||||
return (ctx.body = ctx.body.challenge);
|
||||
}
|
||||
|
||||
if (token !== process.env.SLACK_VERIFICATION_TOKEN) {
|
||||
throw AuthenticationError("Invalid token");
|
||||
@@ -39,21 +41,27 @@ router.post("hooks.unfurl", async (ctx) => {
|
||||
},
|
||||
],
|
||||
});
|
||||
if (!user) return;
|
||||
if (!user) {
|
||||
return;
|
||||
}
|
||||
const auth = await IntegrationAuthentication.findOne({
|
||||
where: {
|
||||
service: "slack",
|
||||
teamId: user.teamId,
|
||||
},
|
||||
});
|
||||
if (!auth) return;
|
||||
if (!auth) {
|
||||
return;
|
||||
}
|
||||
// get content for unfurled links
|
||||
const unfurls = {};
|
||||
|
||||
for (const link of event.links) {
|
||||
const id = link.url.substr(link.url.lastIndexOf("/") + 1);
|
||||
const doc = await Document.findByPk(id);
|
||||
if (!doc || doc.teamId !== user.teamId) continue;
|
||||
if (!doc || doc.teamId !== user.teamId) {
|
||||
continue;
|
||||
}
|
||||
unfurls[link.url] = {
|
||||
title: doc.title,
|
||||
text: doc.getSummary(),
|
||||
|
||||
@@ -12,7 +12,9 @@ const router = new Router();
|
||||
router.post("integrations.list", auth(), pagination(), async (ctx) => {
|
||||
let { direction } = ctx.body;
|
||||
const { sort = "updatedAt" } = ctx.body;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
assertSort(sort, Integration);
|
||||
|
||||
const { user } = ctx.state;
|
||||
|
||||
@@ -33,7 +33,9 @@ router.post("revisions.info", auth(), async (ctx) => {
|
||||
router.post("revisions.list", auth(), pagination(), async (ctx) => {
|
||||
let { direction } = ctx.body;
|
||||
const { documentId, sort = "updatedAt" } = ctx.body;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
assertSort(sort, Revision);
|
||||
assertPresent(documentId, "documentId is required");
|
||||
|
||||
|
||||
@@ -100,7 +100,9 @@ router.post("shares.info", auth(), async (ctx) => {
|
||||
router.post("shares.list", auth(), pagination(), async (ctx) => {
|
||||
let { direction } = ctx.body;
|
||||
const { sort = "updatedAt" } = ctx.body;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
assertSort(sort, Share);
|
||||
|
||||
const { user } = ctx.state;
|
||||
|
||||
@@ -25,11 +25,21 @@ router.post("team.update", auth(), async (ctx) => {
|
||||
team.subdomain = subdomain === "" ? null : subdomain;
|
||||
}
|
||||
|
||||
if (name) team.name = name;
|
||||
if (sharing !== undefined) team.sharing = sharing;
|
||||
if (documentEmbeds !== undefined) team.documentEmbeds = documentEmbeds;
|
||||
if (guestSignin !== undefined) team.guestSignin = guestSignin;
|
||||
if (avatarUrl !== undefined) team.avatarUrl = avatarUrl;
|
||||
if (name) {
|
||||
team.name = name;
|
||||
}
|
||||
if (sharing !== undefined) {
|
||||
team.sharing = sharing;
|
||||
}
|
||||
if (documentEmbeds !== undefined) {
|
||||
team.documentEmbeds = documentEmbeds;
|
||||
}
|
||||
if (guestSignin !== undefined) {
|
||||
team.guestSignin = guestSignin;
|
||||
}
|
||||
if (avatarUrl !== undefined) {
|
||||
team.avatarUrl = avatarUrl;
|
||||
}
|
||||
|
||||
if (collaborativeEditing !== undefined) {
|
||||
team.collaborativeEditing = collaborativeEditing;
|
||||
|
||||
@@ -20,7 +20,9 @@ const router = new Router();
|
||||
router.post("users.list", auth(), pagination(), async (ctx) => {
|
||||
let { direction } = ctx.body;
|
||||
const { sort = "createdAt", query, filter } = ctx.body;
|
||||
if (direction !== "ASC") direction = "DESC";
|
||||
if (direction !== "ASC") {
|
||||
direction = "DESC";
|
||||
}
|
||||
assertSort(sort, User);
|
||||
|
||||
if (filter) {
|
||||
@@ -138,9 +140,15 @@ router.post("users.info", auth(), async (ctx) => {
|
||||
router.post("users.update", auth(), async (ctx) => {
|
||||
const { user } = ctx.state;
|
||||
const { name, avatarUrl, language } = ctx.body;
|
||||
if (name) user.name = name;
|
||||
if (avatarUrl) user.avatarUrl = avatarUrl;
|
||||
if (language) user.language = language;
|
||||
if (name) {
|
||||
user.name = name;
|
||||
}
|
||||
if (avatarUrl) {
|
||||
user.avatarUrl = avatarUrl;
|
||||
}
|
||||
if (language) {
|
||||
user.language = language;
|
||||
}
|
||||
await user.save();
|
||||
await Event.create({
|
||||
name: "users.update",
|
||||
|
||||
@@ -30,8 +30,12 @@ try {
|
||||
|
||||
let index = 0;
|
||||
Object.values(manifestData).forEach((filename) => {
|
||||
if (typeof filename !== "string") return;
|
||||
if (!env.CDN_URL) return;
|
||||
if (typeof filename !== "string") {
|
||||
return;
|
||||
}
|
||||
if (!env.CDN_URL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filename.endsWith(".js")) {
|
||||
// Preload resources you have high-confidence will be used in the current
|
||||
|
||||
@@ -71,7 +71,9 @@ async function archiveToPath(zip: JSZip) {
|
||||
postfix: ".zip",
|
||||
},
|
||||
(err, path) => {
|
||||
if (err) return reject(err);
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
zip
|
||||
.generateNodeStream({
|
||||
type: "nodebuffer",
|
||||
|
||||
Reference in New Issue
Block a user