Type server models (#6326)
* fix: type server models * fix: make ParanoidModel generic * fix: ApiKey * fix: Attachment * fix: AuthenticationProvider * fix: Backlink * fix: Collection * fix: Comment * fix: Document * fix: FileOperation * fix: Group * fix: GroupPermission * fix: GroupUser * fix: Integration * fix: IntegrationAuthentication * fix: Notification * fix: Pin * fix: Revision * fix: SearchQuery * fix: Share * fix: Star * fix: Subscription * fix: TypeError * fix: Imports * fix: Team * fix: TeamDomain * fix: User * fix: UserAuthentication * fix: UserPermission * fix: View * fix: WebhookDelivery * fix: WebhookSubscription * Remove type duplication --------- Co-authored-by: Tom Moor <tom.moor@gmail.com>
This commit is contained in:
@@ -200,7 +200,8 @@ if (env.SLACK_CLIENT_ID && env.SLACK_CLIENT_SECRET) {
|
||||
const { user } = ctx.state.auth;
|
||||
assertPresent(code || error, "code is required");
|
||||
|
||||
const collectionId = state;
|
||||
// FIX ME! What about having zod like schema in place here?
|
||||
const collectionId = state as string;
|
||||
assertUuid(collectionId, "collectionId must be an uuid");
|
||||
|
||||
if (error) {
|
||||
|
||||
@@ -60,6 +60,7 @@ import {
|
||||
TeamEvent,
|
||||
UserEvent,
|
||||
ViewEvent,
|
||||
WebhookDeliveryStatus,
|
||||
WebhookSubscriptionEvent,
|
||||
} from "@server/types";
|
||||
import fetch from "@server/utils/fetch";
|
||||
@@ -572,7 +573,8 @@ export default class DeliverWebhookTask extends BaseTask<Props> {
|
||||
status: "pending",
|
||||
});
|
||||
|
||||
let response, requestBody, requestHeaders, status;
|
||||
let response, requestBody, requestHeaders;
|
||||
let status: WebhookDeliveryStatus;
|
||||
try {
|
||||
requestBody = presentWebhook({
|
||||
event,
|
||||
|
||||
@@ -43,7 +43,7 @@ export class ViewsExtension implements Extension {
|
||||
);
|
||||
await Promise.all([
|
||||
View.touch(documentId, context.user.id, true),
|
||||
context.user.update({ lastViewedAt: new Date() }),
|
||||
context.user.update({ lastActiveAt: new Date() }),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Comment, Event } from "@server/models";
|
||||
import { buildDocument, buildUser } from "@server/test/factories";
|
||||
import { buildComment, buildDocument, buildUser } from "@server/test/factories";
|
||||
import commentDestroyer from "./commentDestroyer";
|
||||
|
||||
describe("commentDestroyer", () => {
|
||||
@@ -12,24 +12,9 @@ describe("commentDestroyer", () => {
|
||||
teamId: user.teamId,
|
||||
});
|
||||
|
||||
const comment = await Comment.create({
|
||||
teamId: document.teamId,
|
||||
const comment = await buildComment({
|
||||
userId: user.id,
|
||||
documentId: document.id,
|
||||
data: {
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: "test",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
createdById: user.id,
|
||||
});
|
||||
|
||||
await commentDestroyer({
|
||||
|
||||
@@ -78,7 +78,6 @@ export default async function documentCreator({
|
||||
editorVersion,
|
||||
collectionId,
|
||||
teamId: user.teamId,
|
||||
userId: user.id,
|
||||
createdAt,
|
||||
updatedAt: updatedAt ?? createdAt,
|
||||
lastModifiedById: user.id,
|
||||
|
||||
@@ -40,10 +40,8 @@ describe("starCreator", () => {
|
||||
});
|
||||
|
||||
await Star.create({
|
||||
teamId: document.teamId,
|
||||
documentId: document.id,
|
||||
userId: user.id,
|
||||
createdById: user.id,
|
||||
index: "P",
|
||||
});
|
||||
|
||||
|
||||
@@ -13,10 +13,8 @@ describe("starDestroyer", () => {
|
||||
});
|
||||
|
||||
const star = await Star.create({
|
||||
teamId: document.teamId,
|
||||
documentId: document.id,
|
||||
userId: user.id,
|
||||
createdById: user.id,
|
||||
index: "P",
|
||||
});
|
||||
|
||||
|
||||
@@ -13,10 +13,8 @@ describe("starUpdater", () => {
|
||||
});
|
||||
|
||||
let star = await Star.create({
|
||||
teamId: document.teamId,
|
||||
documentId: document.id,
|
||||
userId: user.id,
|
||||
createdById: user.id,
|
||||
index: "P",
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Transaction } from "sequelize";
|
||||
import { InferCreationAttributes, Transaction } from "sequelize";
|
||||
import slugify from "slugify";
|
||||
import { RESERVED_SUBDOMAINS } from "@shared/utils/domains";
|
||||
import { traceFunction } from "@server/logging/tracing";
|
||||
@@ -50,7 +50,7 @@ async function teamCreator({
|
||||
name,
|
||||
avatarUrl,
|
||||
authenticationProviders,
|
||||
},
|
||||
} as Partial<InferCreationAttributes<Team>>,
|
||||
{
|
||||
include: ["authenticationProviders"],
|
||||
transaction,
|
||||
|
||||
@@ -70,7 +70,8 @@ describe("teamPermanentDeleter", () => {
|
||||
expect(
|
||||
await Collection.unscoped().count({
|
||||
where: {
|
||||
id: document.collectionId,
|
||||
// buildDocument() above guarantees this to be non-null
|
||||
id: document.collectionId!,
|
||||
},
|
||||
paranoid: false,
|
||||
})
|
||||
|
||||
@@ -58,7 +58,6 @@ export default async function userInviter({
|
||||
teamId: user.teamId,
|
||||
name: invite.name,
|
||||
email: invite.email,
|
||||
service: null,
|
||||
isAdmin: invite.role === UserRole.Admin,
|
||||
isViewer: invite.role === UserRole.Viewer,
|
||||
invitedById: user.id,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferCreationAttributes } from "sequelize";
|
||||
import InviteAcceptedEmail from "@server/emails/templates/InviteAcceptedEmail";
|
||||
import {
|
||||
DomainNotAllowedError,
|
||||
@@ -236,9 +237,8 @@ export default async function userProvisioner({
|
||||
isViewer: isAdmin === true ? false : defaultUserRole === "viewer",
|
||||
teamId,
|
||||
avatarUrl,
|
||||
service: null,
|
||||
authentications: authentication ? [authentication] : [],
|
||||
},
|
||||
} as Partial<InferCreationAttributes<User>>,
|
||||
{
|
||||
include: "authentications",
|
||||
transaction,
|
||||
|
||||
@@ -101,7 +101,7 @@ export default function auth(options: AuthenticationOptions = {}) {
|
||||
if (user.isSuspended) {
|
||||
const suspendingAdmin = await User.findOne({
|
||||
where: {
|
||||
id: user.suspendedById,
|
||||
id: user.suspendedById!,
|
||||
},
|
||||
paranoid: false,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import randomstring from "randomstring";
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
Column,
|
||||
Table,
|
||||
@@ -14,7 +15,10 @@ import Length from "./validators/Length";
|
||||
|
||||
@Table({ tableName: "apiKeys", modelName: "apiKey" })
|
||||
@Fix
|
||||
class ApiKey extends ParanoidModel {
|
||||
class ApiKey extends ParanoidModel<
|
||||
InferAttributes<ApiKey>,
|
||||
Partial<InferCreationAttributes<ApiKey>>
|
||||
> {
|
||||
static prefix = "ol_api_";
|
||||
|
||||
@Length({
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { createReadStream } from "fs";
|
||||
import path from "path";
|
||||
import { File } from "formidable";
|
||||
import { QueryTypes } from "sequelize";
|
||||
import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
QueryTypes,
|
||||
} from "sequelize";
|
||||
import {
|
||||
BeforeDestroy,
|
||||
BelongsTo,
|
||||
@@ -25,7 +29,10 @@ import Length from "./validators/Length";
|
||||
|
||||
@Table({ tableName: "attachments", modelName: "attachment" })
|
||||
@Fix
|
||||
class Attachment extends IdModel {
|
||||
class Attachment extends IdModel<
|
||||
InferAttributes<Attachment>,
|
||||
Partial<InferCreationAttributes<Attachment>>
|
||||
> {
|
||||
@Length({
|
||||
max: 4096,
|
||||
msg: "key must be 4096 characters or less",
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Op, SaveOptions } from "sequelize";
|
||||
import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
InstanceUpdateOptions,
|
||||
Op,
|
||||
} from "sequelize";
|
||||
import {
|
||||
BelongsTo,
|
||||
Column,
|
||||
@@ -8,11 +13,11 @@ import {
|
||||
ForeignKey,
|
||||
HasMany,
|
||||
Table,
|
||||
Model,
|
||||
IsUUID,
|
||||
PrimaryKey,
|
||||
} from "sequelize-typescript";
|
||||
import env from "@server/env";
|
||||
import Model from "@server/models/base/Model";
|
||||
import AzureClient from "@server/utils/azure";
|
||||
import GoogleClient from "@server/utils/google";
|
||||
import OIDCClient from "@server/utils/oidc";
|
||||
@@ -28,7 +33,10 @@ import Length from "./validators/Length";
|
||||
updatedAt: false,
|
||||
})
|
||||
@Fix
|
||||
class AuthenticationProvider extends Model {
|
||||
class AuthenticationProvider extends Model<
|
||||
InferAttributes<AuthenticationProvider>,
|
||||
Partial<InferCreationAttributes<AuthenticationProvider>>
|
||||
> {
|
||||
@IsUUID(4)
|
||||
@PrimaryKey
|
||||
@Default(DataType.UUIDV4)
|
||||
@@ -97,7 +105,9 @@ class AuthenticationProvider extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
disable = async (options?: SaveOptions<AuthenticationProvider>) => {
|
||||
disable: (
|
||||
options?: InstanceUpdateOptions<InferAttributes<AuthenticationProvider>>
|
||||
) => Promise<AuthenticationProvider> = async (options) => {
|
||||
const res = await (
|
||||
this.constructor as typeof AuthenticationProvider
|
||||
).findAndCountAll({
|
||||
@@ -124,7 +134,9 @@ class AuthenticationProvider extends Model {
|
||||
}
|
||||
};
|
||||
|
||||
enable = (options?: SaveOptions<AuthenticationProvider>) =>
|
||||
enable: (
|
||||
options?: InstanceUpdateOptions<InferAttributes<AuthenticationProvider>>
|
||||
) => Promise<AuthenticationProvider> = (options) =>
|
||||
this.update(
|
||||
{
|
||||
enabled: true,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
DataType,
|
||||
BelongsTo,
|
||||
@@ -12,7 +13,10 @@ import Fix from "./decorators/Fix";
|
||||
|
||||
@Table({ tableName: "backlinks", modelName: "backlink" })
|
||||
@Fix
|
||||
class Backlink extends IdModel {
|
||||
class Backlink extends IdModel<
|
||||
InferAttributes<Backlink>,
|
||||
Partial<InferCreationAttributes<Backlink>>
|
||||
> {
|
||||
@BelongsTo(() => User, "userId")
|
||||
user: User;
|
||||
|
||||
|
||||
@@ -223,11 +223,10 @@ describe("#updateDocument", () => {
|
||||
const document = await buildDocument({ collectionId: collection.id });
|
||||
await collection.reload();
|
||||
|
||||
const newDocument = await Document.create({
|
||||
const newDocument = await buildDocument({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
teamId: collection.teamId,
|
||||
userId: collection.createdById,
|
||||
lastModifiedById: collection.createdById,
|
||||
createdById: collection.createdById,
|
||||
title: "Child document",
|
||||
@@ -277,11 +276,10 @@ describe("#removeDocument", () => {
|
||||
await collection.reload();
|
||||
|
||||
// Add a child for testing
|
||||
const newDocument = await Document.create({
|
||||
const newDocument = await buildDocument({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
teamId: collection.teamId,
|
||||
userId: collection.createdById,
|
||||
lastModifiedById: collection.createdById,
|
||||
createdById: collection.createdById,
|
||||
title: "Child document",
|
||||
@@ -306,11 +304,10 @@ describe("#removeDocument", () => {
|
||||
await collection.reload();
|
||||
|
||||
// Add a child for testing
|
||||
const newDocument = await Document.create({
|
||||
const newDocument = await buildDocument({
|
||||
parentDocumentId: document.id,
|
||||
collectionId: collection.id,
|
||||
teamId: collection.teamId,
|
||||
userId: collection.createdById,
|
||||
lastModifiedById: collection.createdById,
|
||||
createdById: collection.createdById,
|
||||
publishedAt: new Date(),
|
||||
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
Op,
|
||||
FindOptions,
|
||||
NonNullFindOptions,
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
} from "sequelize";
|
||||
import {
|
||||
Sequelize,
|
||||
@@ -159,7 +161,10 @@ import NotContainsUrl from "./validators/NotContainsUrl";
|
||||
}))
|
||||
@Table({ tableName: "collections", modelName: "collection" })
|
||||
@Fix
|
||||
class Collection extends ParanoidModel {
|
||||
class Collection extends ParanoidModel<
|
||||
InferAttributes<Collection>,
|
||||
Partial<InferCreationAttributes<Collection>>
|
||||
> {
|
||||
@SimpleLength({
|
||||
min: 10,
|
||||
max: 10,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
DataType,
|
||||
BelongsTo,
|
||||
@@ -38,7 +39,10 @@ import TextLength from "./validators/TextLength";
|
||||
}))
|
||||
@Table({ tableName: "comments", modelName: "comment" })
|
||||
@Fix
|
||||
class Comment extends ParanoidModel {
|
||||
class Comment extends ParanoidModel<
|
||||
InferAttributes<Comment>,
|
||||
Partial<InferCreationAttributes<Comment>>
|
||||
> {
|
||||
@TextLength({
|
||||
max: CommentValidation.maxLength,
|
||||
msg: `Comment must be less than ${CommentValidation.maxLength} characters`,
|
||||
|
||||
@@ -3,7 +3,13 @@ import compact from "lodash/compact";
|
||||
import isNil from "lodash/isNil";
|
||||
import uniq from "lodash/uniq";
|
||||
import randomstring from "randomstring";
|
||||
import type { Identifier, NonNullFindOptions, SaveOptions } from "sequelize";
|
||||
import type {
|
||||
Identifier,
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
NonNullFindOptions,
|
||||
SaveOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
Sequelize,
|
||||
Transaction,
|
||||
@@ -186,7 +192,10 @@ type AdditionalFindOptions = {
|
||||
}))
|
||||
@Table({ tableName: "documents", modelName: "document" })
|
||||
@Fix
|
||||
class Document extends ParanoidModel {
|
||||
class Document extends ParanoidModel<
|
||||
InferAttributes<Document>,
|
||||
Partial<InferCreationAttributes<Document>>
|
||||
> {
|
||||
@SimpleLength({
|
||||
min: 10,
|
||||
max: 10,
|
||||
@@ -208,7 +217,7 @@ class Document extends ParanoidModel {
|
||||
|
||||
@IsNumeric
|
||||
@Column(DataType.SMALLINT)
|
||||
version: number;
|
||||
version?: number | null;
|
||||
|
||||
@Default(false)
|
||||
@Column
|
||||
@@ -261,7 +270,7 @@ class Document extends ParanoidModel {
|
||||
msg: `Document collaborative state is too large, you must create a new document`,
|
||||
})
|
||||
@Column(DataType.BLOB)
|
||||
state: Uint8Array;
|
||||
state?: Uint8Array | null;
|
||||
|
||||
/** Whether this document is part of onboarding. */
|
||||
@Default(false)
|
||||
@@ -387,14 +396,13 @@ class Document extends ParanoidModel {
|
||||
// ensure documents have a title
|
||||
model.title = model.title || "";
|
||||
|
||||
if (model.previous("title") && model.previous("title") !== model.title) {
|
||||
const previousTitle = model.previous("title");
|
||||
if (previousTitle && previousTitle !== model.title) {
|
||||
if (!model.previousTitles) {
|
||||
model.previousTitles = [];
|
||||
}
|
||||
|
||||
model.previousTitles = uniq(
|
||||
model.previousTitles.concat(model.previous("title"))
|
||||
);
|
||||
model.previousTitles = uniq(model.previousTitles.concat(previousTitle));
|
||||
}
|
||||
|
||||
// add the current user as a collaborator on this doc
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import type { SaveOptions, WhereOptions } from "sequelize";
|
||||
import type {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
SaveOptions,
|
||||
WhereOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
ForeignKey,
|
||||
AfterSave,
|
||||
@@ -22,7 +27,10 @@ import Fix from "./decorators/Fix";
|
||||
|
||||
@Table({ tableName: "events", modelName: "event", updatedAt: false })
|
||||
@Fix
|
||||
class Event extends IdModel {
|
||||
class Event extends IdModel<
|
||||
InferAttributes<Event>,
|
||||
Partial<InferCreationAttributes<Event>>
|
||||
> {
|
||||
@IsUUID(4)
|
||||
@Column(DataType.UUID)
|
||||
modelId: string | null;
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Op, WhereOptions } from "sequelize";
|
||||
import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
Op,
|
||||
WhereOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
ForeignKey,
|
||||
DefaultScope,
|
||||
@@ -36,7 +41,10 @@ import Fix from "./decorators/Fix";
|
||||
}))
|
||||
@Table({ tableName: "file_operations", modelName: "file_operation" })
|
||||
@Fix
|
||||
class FileOperation extends ParanoidModel {
|
||||
class FileOperation extends ParanoidModel<
|
||||
InferAttributes<FileOperation>,
|
||||
Partial<InferCreationAttributes<FileOperation>>
|
||||
> {
|
||||
@Column(DataType.ENUM(...Object.values(FileOperationType)))
|
||||
type: FileOperationType;
|
||||
|
||||
@@ -50,7 +58,7 @@ class FileOperation extends ParanoidModel {
|
||||
key: string;
|
||||
|
||||
@Column
|
||||
url: string;
|
||||
url?: string | null;
|
||||
|
||||
@Column
|
||||
error: string | null;
|
||||
@@ -118,7 +126,7 @@ class FileOperation extends ParanoidModel {
|
||||
|
||||
@ForeignKey(() => Collection)
|
||||
@Column(DataType.UUID)
|
||||
collectionId: string;
|
||||
collectionId?: string | null;
|
||||
|
||||
/**
|
||||
* Count the number of export file operations for a given team after a point
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Op } from "sequelize";
|
||||
import { InferAttributes, InferCreationAttributes, Op } from "sequelize";
|
||||
import {
|
||||
AfterDestroy,
|
||||
BelongsTo,
|
||||
@@ -69,7 +69,10 @@ import NotContainsUrl from "./validators/NotContainsUrl";
|
||||
},
|
||||
})
|
||||
@Fix
|
||||
class Group extends ParanoidModel {
|
||||
class Group extends ParanoidModel<
|
||||
InferAttributes<Group>,
|
||||
Partial<InferCreationAttributes<Group>>
|
||||
> {
|
||||
@Length({ min: 0, max: 255, msg: "name must be be 255 characters or less" })
|
||||
@NotContainsUrl
|
||||
@Column
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Op } from "sequelize";
|
||||
import { InferAttributes, InferCreationAttributes, Op } from "sequelize";
|
||||
import {
|
||||
BelongsTo,
|
||||
Column,
|
||||
@@ -40,7 +40,10 @@ import Fix from "./decorators/Fix";
|
||||
}))
|
||||
@Table({ tableName: "group_permissions", modelName: "group_permission" })
|
||||
@Fix
|
||||
class GroupPermission extends ParanoidModel {
|
||||
class GroupPermission extends ParanoidModel<
|
||||
InferAttributes<GroupPermission>,
|
||||
Partial<InferCreationAttributes<GroupPermission>>
|
||||
> {
|
||||
@Default(CollectionPermission.ReadWrite)
|
||||
@IsIn([Object.values(CollectionPermission)])
|
||||
@Column(DataType.STRING)
|
||||
@@ -71,6 +74,10 @@ class GroupPermission extends ParanoidModel {
|
||||
|
||||
@BelongsTo(() => User, "createdById")
|
||||
createdBy: User;
|
||||
|
||||
@ForeignKey(() => User)
|
||||
@Column(DataType.UUID)
|
||||
createdById: string;
|
||||
}
|
||||
|
||||
export default GroupPermission;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
DefaultScope,
|
||||
BelongsTo,
|
||||
@@ -37,7 +38,10 @@ import Fix from "./decorators/Fix";
|
||||
}))
|
||||
@Table({ tableName: "group_users", modelName: "group_user", paranoid: true })
|
||||
@Fix
|
||||
class GroupUser extends Model {
|
||||
class GroupUser extends Model<
|
||||
InferAttributes<GroupUser>,
|
||||
Partial<InferCreationAttributes<GroupUser>>
|
||||
> {
|
||||
@BelongsTo(() => User, "userId")
|
||||
user: User;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
ForeignKey,
|
||||
BelongsTo,
|
||||
@@ -8,7 +9,10 @@ import {
|
||||
IsIn,
|
||||
} from "sequelize-typescript";
|
||||
import { IntegrationType, IntegrationService } from "@shared/types";
|
||||
import type { IntegrationSettings } from "@shared/types";
|
||||
import type {
|
||||
IntegrationSettings,
|
||||
UserCreatableIntegrationService,
|
||||
} from "@shared/types";
|
||||
import Collection from "./Collection";
|
||||
import IntegrationAuthentication from "./IntegrationAuthentication";
|
||||
import Team from "./Team";
|
||||
@@ -16,12 +20,6 @@ import User from "./User";
|
||||
import IdModel from "./base/IdModel";
|
||||
import Fix from "./decorators/Fix";
|
||||
|
||||
export enum UserCreatableIntegrationService {
|
||||
Diagrams = "diagrams",
|
||||
Grist = "grist",
|
||||
GoogleAnalytics = "google-analytics",
|
||||
}
|
||||
|
||||
@Scopes(() => ({
|
||||
withAuthentication: {
|
||||
include: [
|
||||
@@ -35,14 +33,17 @@ export enum UserCreatableIntegrationService {
|
||||
}))
|
||||
@Table({ tableName: "integrations", modelName: "integration" })
|
||||
@Fix
|
||||
class Integration<T = unknown> extends IdModel {
|
||||
class Integration<T = unknown> extends IdModel<
|
||||
InferAttributes<Integration<T>>,
|
||||
Partial<InferCreationAttributes<Integration<T>>>
|
||||
> {
|
||||
@IsIn([Object.values(IntegrationType)])
|
||||
@Column(DataType.STRING)
|
||||
type: IntegrationType;
|
||||
|
||||
@IsIn([Object.values(IntegrationService)])
|
||||
@Column(DataType.STRING)
|
||||
service: IntegrationService;
|
||||
service: IntegrationService | UserCreatableIntegrationService;
|
||||
|
||||
@Column(DataType.JSONB)
|
||||
settings: IntegrationSettings<T>;
|
||||
@@ -67,11 +68,11 @@ class Integration<T = unknown> extends IdModel {
|
||||
teamId: string;
|
||||
|
||||
@BelongsTo(() => Collection, "collectionId")
|
||||
collection: Collection;
|
||||
collection?: Collection | null;
|
||||
|
||||
@ForeignKey(() => Collection)
|
||||
@Column(DataType.UUID)
|
||||
collectionId: string;
|
||||
collectionId?: string | null;
|
||||
|
||||
@BelongsTo(() => IntegrationAuthentication, "authenticationId")
|
||||
authentication: IntegrationAuthentication;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
DataType,
|
||||
Table,
|
||||
@@ -17,7 +18,10 @@ import Fix from "./decorators/Fix";
|
||||
|
||||
@Table({ tableName: "authentications", modelName: "authentication" })
|
||||
@Fix
|
||||
class IntegrationAuthentication extends IdModel {
|
||||
class IntegrationAuthentication extends IdModel<
|
||||
InferAttributes<IntegrationAuthentication>,
|
||||
Partial<InferCreationAttributes<IntegrationAuthentication>>
|
||||
> {
|
||||
@Column(DataType.STRING)
|
||||
service: IntegrationService;
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import crypto from "crypto";
|
||||
import type { SaveOptions } from "sequelize";
|
||||
import type {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
SaveOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
Table,
|
||||
ForeignKey,
|
||||
Model,
|
||||
Column,
|
||||
PrimaryKey,
|
||||
IsUUID,
|
||||
@@ -18,6 +21,7 @@ import {
|
||||
} from "sequelize-typescript";
|
||||
import { NotificationEventType } from "@shared/types";
|
||||
import env from "@server/env";
|
||||
import Model from "@server/models/base/Model";
|
||||
import Collection from "./Collection";
|
||||
import Comment from "./Comment";
|
||||
import Document from "./Document";
|
||||
@@ -83,7 +87,10 @@ import Fix from "./decorators/Fix";
|
||||
updatedAt: false,
|
||||
})
|
||||
@Fix
|
||||
class Notification extends Model {
|
||||
class Notification extends Model<
|
||||
InferAttributes<Notification>,
|
||||
Partial<InferCreationAttributes<Notification>>
|
||||
> {
|
||||
@IsUUID(4)
|
||||
@PrimaryKey
|
||||
@Default(DataType.UUIDV4)
|
||||
@@ -92,7 +99,7 @@ class Notification extends Model {
|
||||
|
||||
@AllowNull
|
||||
@Column
|
||||
emailedAt: Date;
|
||||
emailedAt?: Date | null;
|
||||
|
||||
@AllowNull
|
||||
@Column
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
DataType,
|
||||
Column,
|
||||
@@ -14,7 +15,10 @@ import Fix from "./decorators/Fix";
|
||||
|
||||
@Table({ tableName: "pins", modelName: "pin" })
|
||||
@Fix
|
||||
class Pin extends IdModel {
|
||||
class Pin extends IdModel<
|
||||
InferAttributes<Pin>,
|
||||
Partial<InferCreationAttributes<Pin>>
|
||||
> {
|
||||
@Column
|
||||
index: string | null;
|
||||
|
||||
@@ -28,11 +32,11 @@ class Pin extends IdModel {
|
||||
createdById: string;
|
||||
|
||||
@BelongsTo(() => Collection, "collectionId")
|
||||
collection: Collection;
|
||||
collection?: Collection | null;
|
||||
|
||||
@ForeignKey(() => Collection)
|
||||
@Column(DataType.UUID)
|
||||
collectionId: string;
|
||||
collectionId?: string | null;
|
||||
|
||||
@BelongsTo(() => Document, "documentId")
|
||||
document: Document;
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { Op, SaveOptions } from "sequelize";
|
||||
import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
Op,
|
||||
SaveOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
DataType,
|
||||
BelongsTo,
|
||||
@@ -28,10 +33,13 @@ import Length from "./validators/Length";
|
||||
}))
|
||||
@Table({ tableName: "revisions", modelName: "revision" })
|
||||
@Fix
|
||||
class Revision extends IdModel {
|
||||
class Revision extends IdModel<
|
||||
InferAttributes<Revision>,
|
||||
Partial<InferCreationAttributes<Revision>>
|
||||
> {
|
||||
@IsNumeric
|
||||
@Column(DataType.SMALLINT)
|
||||
version: number;
|
||||
version?: number | null;
|
||||
|
||||
@SimpleLength({
|
||||
max: 255,
|
||||
@@ -133,7 +141,7 @@ class Revision extends IdModel {
|
||||
*/
|
||||
static createFromDocument(
|
||||
document: Document,
|
||||
options?: SaveOptions<Revision>
|
||||
options?: SaveOptions<InferAttributes<Revision>>
|
||||
) {
|
||||
const revision = this.buildFromDocument(document);
|
||||
return revision.save(options);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
Table,
|
||||
ForeignKey,
|
||||
Model,
|
||||
Column,
|
||||
PrimaryKey,
|
||||
IsUUID,
|
||||
@@ -10,8 +10,10 @@ import {
|
||||
DataType,
|
||||
Default,
|
||||
} from "sequelize-typescript";
|
||||
import Team from "./Team";
|
||||
import User from "./User";
|
||||
import Share from "@server/models/Share";
|
||||
import Team from "@server/models/Team";
|
||||
import User from "@server/models/User";
|
||||
import Model from "@server/models/base/Model";
|
||||
import Fix from "./decorators/Fix";
|
||||
|
||||
@Table({
|
||||
@@ -20,7 +22,10 @@ import Fix from "./decorators/Fix";
|
||||
updatedAt: false,
|
||||
})
|
||||
@Fix
|
||||
class SearchQuery extends Model {
|
||||
class SearchQuery extends Model<
|
||||
InferAttributes<SearchQuery>,
|
||||
Partial<InferCreationAttributes<SearchQuery>>
|
||||
> {
|
||||
@IsUUID(4)
|
||||
@PrimaryKey
|
||||
@Default(DataType.UUIDV4)
|
||||
@@ -69,11 +74,18 @@ class SearchQuery extends Model {
|
||||
// associations
|
||||
|
||||
@BelongsTo(() => User, "userId")
|
||||
user: User;
|
||||
user?: User | null;
|
||||
|
||||
@ForeignKey(() => User)
|
||||
@Column(DataType.UUID)
|
||||
userId: string;
|
||||
userId?: string | null;
|
||||
|
||||
@BelongsTo(() => Share, "shareId")
|
||||
share?: Share | null;
|
||||
|
||||
@ForeignKey(() => Share)
|
||||
@Column(DataType.UUID)
|
||||
shareId?: string | null;
|
||||
|
||||
@BelongsTo(() => Team, "teamId")
|
||||
team: Team;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { type SaveOptions } from "sequelize";
|
||||
import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
type SaveOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
ForeignKey,
|
||||
BelongsTo,
|
||||
@@ -69,7 +73,10 @@ import Length from "./validators/Length";
|
||||
}))
|
||||
@Table({ tableName: "shares", modelName: "share" })
|
||||
@Fix
|
||||
class Share extends IdModel {
|
||||
class Share extends IdModel<
|
||||
InferAttributes<Share>,
|
||||
Partial<InferCreationAttributes<Share>>
|
||||
> {
|
||||
@Column
|
||||
published: boolean;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
Column,
|
||||
DataType,
|
||||
@@ -13,7 +14,10 @@ import Fix from "./decorators/Fix";
|
||||
|
||||
@Table({ tableName: "stars", modelName: "star" })
|
||||
@Fix
|
||||
class Star extends IdModel {
|
||||
class Star extends IdModel<
|
||||
InferAttributes<Star>,
|
||||
Partial<InferCreationAttributes<Star>>
|
||||
> {
|
||||
@Column
|
||||
index: string | null;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
Column,
|
||||
DataType,
|
||||
@@ -23,7 +24,10 @@ import Fix from "./decorators/Fix";
|
||||
}))
|
||||
@Table({ tableName: "subscriptions", modelName: "subscription" })
|
||||
@Fix
|
||||
class Subscription extends ParanoidModel {
|
||||
class Subscription extends ParanoidModel<
|
||||
InferAttributes<Subscription>,
|
||||
Partial<InferCreationAttributes<Subscription>>
|
||||
> {
|
||||
@BelongsTo(() => User, "userId")
|
||||
user: User;
|
||||
|
||||
|
||||
@@ -3,7 +3,11 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import { URL } from "url";
|
||||
import util from "util";
|
||||
import { type SaveOptions } from "sequelize";
|
||||
import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
type SaveOptions,
|
||||
} from "sequelize";
|
||||
import { Op } from "sequelize";
|
||||
import {
|
||||
Column,
|
||||
@@ -65,7 +69,10 @@ const readFile = util.promisify(fs.readFile);
|
||||
}))
|
||||
@Table({ tableName: "teams", modelName: "team" })
|
||||
@Fix
|
||||
class Team extends ParanoidModel {
|
||||
class Team extends ParanoidModel<
|
||||
InferAttributes<Team>,
|
||||
Partial<InferCreationAttributes<Team>>
|
||||
> {
|
||||
@NotContainsUrl
|
||||
@Length({ min: 2, max: 255, msg: "name must be between 2 to 255 characters" })
|
||||
@Column
|
||||
@@ -275,7 +282,6 @@ class Team extends ParanoidModel {
|
||||
parentDocumentId: null,
|
||||
collectionId: collection.id,
|
||||
teamId: collection.teamId,
|
||||
userId: collection.createdById,
|
||||
lastModifiedById: collection.createdById,
|
||||
createdById: collection.createdById,
|
||||
title,
|
||||
@@ -366,14 +372,9 @@ class Team extends ParanoidModel {
|
||||
|
||||
@AfterUpdate
|
||||
static deletePreviousAvatar = async (model: Team) => {
|
||||
if (
|
||||
model.previous("avatarUrl") &&
|
||||
model.previous("avatarUrl") !== model.avatarUrl
|
||||
) {
|
||||
const attachmentIds = parseAttachmentIds(
|
||||
model.previous("avatarUrl"),
|
||||
true
|
||||
);
|
||||
const previousAvatarUrl = model.previous("avatarUrl");
|
||||
if (previousAvatarUrl && previousAvatarUrl !== model.avatarUrl) {
|
||||
const attachmentIds = parseAttachmentIds(previousAvatarUrl, true);
|
||||
if (!attachmentIds.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import emailProviders from "email-providers";
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
Column,
|
||||
Table,
|
||||
@@ -21,7 +22,10 @@ import Length from "./validators/Length";
|
||||
|
||||
@Table({ tableName: "team_domains", modelName: "team_domain" })
|
||||
@Fix
|
||||
class TeamDomain extends IdModel {
|
||||
class TeamDomain extends IdModel<
|
||||
InferAttributes<TeamDomain>,
|
||||
Partial<InferCreationAttributes<TeamDomain>>
|
||||
> {
|
||||
@NotIn({
|
||||
args: env.isCloudHosted ? [emailProviders] : [],
|
||||
msg: "You chose a restricted domain, please try another.",
|
||||
|
||||
@@ -8,6 +8,9 @@ import {
|
||||
SaveOptions,
|
||||
Op,
|
||||
FindOptions,
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
InstanceUpdateOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
Table,
|
||||
@@ -40,6 +43,7 @@ import {
|
||||
} from "@shared/types";
|
||||
import { stringToColor } from "@shared/utils/color";
|
||||
import env from "@server/env";
|
||||
import Model from "@server/models/base/Model";
|
||||
import DeleteAttachmentTask from "@server/queues/tasks/DeleteAttachmentTask";
|
||||
import parseAttachmentIds from "@server/utils/parseAttachmentIds";
|
||||
import { ValidationError } from "../errors";
|
||||
@@ -117,7 +121,10 @@ export enum UserFlag {
|
||||
}))
|
||||
@Table({ tableName: "users", modelName: "user" })
|
||||
@Fix
|
||||
class User extends ParanoidModel {
|
||||
class User extends ParanoidModel<
|
||||
InferAttributes<User>,
|
||||
Partial<InferCreationAttributes<User>>
|
||||
> {
|
||||
@IsEmail
|
||||
@Length({ max: 255, msg: "User email must be 255 characters or less" })
|
||||
@Column
|
||||
@@ -519,7 +526,10 @@ class User extends ParanoidModel {
|
||||
],
|
||||
});
|
||||
|
||||
demote = async (to: UserRole, options?: SaveOptions<User>) => {
|
||||
demote: (
|
||||
to: UserRole,
|
||||
options?: InstanceUpdateOptions<InferAttributes<Model>>
|
||||
) => Promise<void> = async (to, options) => {
|
||||
const res = await (this.constructor as typeof User).findAndCountAll({
|
||||
where: {
|
||||
teamId: this.teamId,
|
||||
@@ -568,7 +578,9 @@ class User extends ParanoidModel {
|
||||
}
|
||||
};
|
||||
|
||||
promote = (options?: SaveOptions<User>) =>
|
||||
promote: (
|
||||
options?: InstanceUpdateOptions<InferAttributes<User>>
|
||||
) => Promise<User> = (options) =>
|
||||
this.update(
|
||||
{
|
||||
isAdmin: true,
|
||||
@@ -605,14 +617,9 @@ class User extends ParanoidModel {
|
||||
|
||||
@AfterUpdate
|
||||
static deletePreviousAvatar = async (model: User) => {
|
||||
if (
|
||||
model.previous("avatarUrl") &&
|
||||
model.previous("avatarUrl") !== model.avatarUrl
|
||||
) {
|
||||
const attachmentIds = parseAttachmentIds(
|
||||
model.previous("avatarUrl"),
|
||||
true
|
||||
);
|
||||
const previousAvatarUrl = model.previous("avatarUrl");
|
||||
if (previousAvatarUrl && previousAvatarUrl !== model.avatarUrl) {
|
||||
const attachmentIds = parseAttachmentIds(previousAvatarUrl, true);
|
||||
if (!attachmentIds.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { addMinutes, subMinutes } from "date-fns";
|
||||
import invariant from "invariant";
|
||||
import { SaveOptions } from "sequelize";
|
||||
import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
SaveOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
BeforeCreate,
|
||||
BelongsTo,
|
||||
@@ -22,7 +26,10 @@ import Fix from "./decorators/Fix";
|
||||
|
||||
@Table({ tableName: "user_authentications", modelName: "user_authentication" })
|
||||
@Fix
|
||||
class UserAuthentication extends IdModel {
|
||||
class UserAuthentication extends IdModel<
|
||||
InferAttributes<UserAuthentication>,
|
||||
Partial<InferCreationAttributes<UserAuthentication>>
|
||||
> {
|
||||
@Column(DataType.ARRAY(DataType.STRING))
|
||||
scopes: string[];
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Op } from "sequelize";
|
||||
import { InferAttributes, InferCreationAttributes, Op } from "sequelize";
|
||||
import {
|
||||
Column,
|
||||
ForeignKey,
|
||||
@@ -39,7 +39,10 @@ import Fix from "./decorators/Fix";
|
||||
}))
|
||||
@Table({ tableName: "user_permissions", modelName: "user_permission" })
|
||||
@Fix
|
||||
class UserPermission extends IdModel {
|
||||
class UserPermission extends IdModel<
|
||||
InferAttributes<UserPermission>,
|
||||
Partial<InferCreationAttributes<UserPermission>>
|
||||
> {
|
||||
@Default(CollectionPermission.ReadWrite)
|
||||
@IsIn([Object.values(CollectionPermission)])
|
||||
@Column(DataType.STRING)
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { FindOrCreateOptions, Op } from "sequelize";
|
||||
import {
|
||||
FindOrCreateOptions,
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
Op,
|
||||
} from "sequelize";
|
||||
import {
|
||||
BelongsTo,
|
||||
Column,
|
||||
@@ -26,7 +31,10 @@ import Fix from "./decorators/Fix";
|
||||
}))
|
||||
@Table({ tableName: "views", modelName: "view" })
|
||||
@Fix
|
||||
class View extends IdModel {
|
||||
class View extends IdModel<
|
||||
InferAttributes<View>,
|
||||
Partial<InferCreationAttributes<View>>
|
||||
> {
|
||||
@Column
|
||||
lastEditingAt: Date | null;
|
||||
|
||||
@@ -55,7 +63,7 @@ class View extends IdModel {
|
||||
userId: string;
|
||||
documentId: string;
|
||||
},
|
||||
options?: FindOrCreateOptions
|
||||
options?: FindOrCreateOptions<InferAttributes<View>>
|
||||
) {
|
||||
const [model, created] = await this.findOrCreate({
|
||||
...options,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import {
|
||||
Column,
|
||||
Table,
|
||||
@@ -7,6 +8,7 @@ import {
|
||||
DataType,
|
||||
IsIn,
|
||||
} from "sequelize-typescript";
|
||||
import { type WebhookDeliveryStatus } from "@server/types";
|
||||
import WebhookSubscription from "./WebhookSubscription";
|
||||
import IdModel from "./base/IdModel";
|
||||
import Fix from "./decorators/Fix";
|
||||
@@ -16,14 +18,17 @@ import Fix from "./decorators/Fix";
|
||||
modelName: "webhook_delivery",
|
||||
})
|
||||
@Fix
|
||||
class WebhookDelivery extends IdModel {
|
||||
class WebhookDelivery extends IdModel<
|
||||
InferAttributes<WebhookDelivery>,
|
||||
Partial<InferCreationAttributes<WebhookDelivery>>
|
||||
> {
|
||||
@NotEmpty
|
||||
@IsIn([["pending", "success", "failed"]])
|
||||
@Column(DataType.STRING)
|
||||
status: "pending" | "success" | "failed";
|
||||
status: WebhookDeliveryStatus;
|
||||
|
||||
@Column(DataType.INTEGER)
|
||||
statusCode: number;
|
||||
statusCode?: number | null;
|
||||
|
||||
@Column(DataType.JSONB)
|
||||
requestBody: unknown;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import crypto from "crypto";
|
||||
import isEmpty from "lodash/isEmpty";
|
||||
import { SaveOptions } from "sequelize";
|
||||
import {
|
||||
InferAttributes,
|
||||
InferCreationAttributes,
|
||||
InstanceUpdateOptions,
|
||||
} from "sequelize";
|
||||
import {
|
||||
Column,
|
||||
Table,
|
||||
@@ -39,7 +43,10 @@ import Length from "./validators/Length";
|
||||
modelName: "webhook_subscription",
|
||||
})
|
||||
@Fix
|
||||
class WebhookSubscription extends ParanoidModel {
|
||||
class WebhookSubscription extends ParanoidModel<
|
||||
InferAttributes<WebhookSubscription>,
|
||||
Partial<InferCreationAttributes<WebhookSubscription>>
|
||||
> {
|
||||
@NotEmpty
|
||||
@Length({ max: 255, msg: "Webhook name be less than 255 characters" })
|
||||
@Column
|
||||
@@ -110,7 +117,9 @@ class WebhookSubscription extends ParanoidModel {
|
||||
* @param options Save options
|
||||
* @returns Promise<WebhookSubscription>
|
||||
*/
|
||||
public async disable(options?: SaveOptions<WebhookSubscription>) {
|
||||
public async disable(
|
||||
options?: InstanceUpdateOptions<InferAttributes<WebhookSubscription>>
|
||||
) {
|
||||
return this.update({ enabled: false }, options);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import {
|
||||
CreatedAt,
|
||||
UpdatedAt,
|
||||
@@ -9,7 +10,10 @@ import {
|
||||
} from "sequelize-typescript";
|
||||
import Model from "./Model";
|
||||
|
||||
class IdModel extends Model {
|
||||
class IdModel<
|
||||
TModelAttributes extends {} = any,
|
||||
TCreationAttributes extends {} = TModelAttributes
|
||||
> extends Model<TModelAttributes, TCreationAttributes> {
|
||||
@IsUUID(4)
|
||||
@PrimaryKey
|
||||
@Default(DataType.UUIDV4)
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import { FindOptions } from "sequelize";
|
||||
import { Model as SequelizeModel } from "sequelize-typescript";
|
||||
|
||||
class Model extends SequelizeModel {
|
||||
class Model<
|
||||
TModelAttributes extends {} = any,
|
||||
TCreationAttributes extends {} = TModelAttributes
|
||||
> extends SequelizeModel<TModelAttributes, TCreationAttributes> {
|
||||
/**
|
||||
* Find all models in batches, calling the callback function for each batch.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import { DeletedAt } from "sequelize-typescript";
|
||||
import IdModel from "./IdModel";
|
||||
|
||||
class ParanoidModel extends IdModel {
|
||||
class ParanoidModel<
|
||||
TModelAttributes extends {} = any,
|
||||
TCreationAttributes extends {} = TModelAttributes
|
||||
> extends IdModel<TModelAttributes, TCreationAttributes> {
|
||||
@DeletedAt
|
||||
deletedAt: Date | null;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,6 @@ describe("revisions.create", () => {
|
||||
userId: subscriber.id,
|
||||
documentId: document.id,
|
||||
event: "documents.update",
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const task = new RevisionCreatedNotificationsTask();
|
||||
@@ -303,7 +302,6 @@ describe("revisions.create", () => {
|
||||
userId: subscriber.id,
|
||||
documentId: document.id,
|
||||
event: "documents.update",
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const task = new RevisionCreatedNotificationsTask();
|
||||
@@ -343,7 +341,6 @@ describe("revisions.create", () => {
|
||||
userId: subscriber.id,
|
||||
documentId: document.id,
|
||||
event: "documents.update",
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
await subscription.destroy();
|
||||
@@ -391,7 +388,6 @@ describe("revisions.create", () => {
|
||||
userId: subscriber.id,
|
||||
documentId: document.id,
|
||||
event: "documents.update",
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
const task = new RevisionCreatedNotificationsTask();
|
||||
|
||||
@@ -26,7 +26,6 @@ describe("#comments.list", () => {
|
||||
});
|
||||
const comment = await buildComment({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
documentId: document.id,
|
||||
});
|
||||
const res = await server.post("/api/comments.list", {
|
||||
@@ -58,7 +57,6 @@ describe("#comments.list", () => {
|
||||
});
|
||||
const comment = await buildComment({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
documentId: document.id,
|
||||
});
|
||||
const res = await server.post("/api/comments.list", {
|
||||
@@ -99,12 +97,10 @@ describe("#comments.list", () => {
|
||||
});
|
||||
const comment1 = await buildComment({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
documentId: document1.id,
|
||||
});
|
||||
const comment2 = await buildComment({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
documentId: document2.id,
|
||||
});
|
||||
const res = await server.post("/api/comments.list", {
|
||||
@@ -143,7 +139,6 @@ describe("#comments.create", () => {
|
||||
|
||||
const comment = await buildComment({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
documentId: document.id,
|
||||
});
|
||||
|
||||
@@ -222,7 +217,6 @@ describe("#comments.info", () => {
|
||||
});
|
||||
const comment = await buildComment({
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
documentId: document.id,
|
||||
});
|
||||
const res = await server.post("/api/comments.info", {
|
||||
|
||||
@@ -906,7 +906,6 @@ router.post(
|
||||
editorVersion: original.editorVersion,
|
||||
collectionId: original.collectionId,
|
||||
teamId: original.teamId,
|
||||
userId: user.id,
|
||||
publishedAt: new Date(),
|
||||
lastModifiedById: user.id,
|
||||
createdById: user.id,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { IntegrationService, IntegrationType } from "@shared/types";
|
||||
import { IntegrationAuthentication, User } from "@server/models";
|
||||
import Integration, {
|
||||
import {
|
||||
IntegrationService,
|
||||
UserCreatableIntegrationService,
|
||||
} from "@server/models/Integration";
|
||||
IntegrationType,
|
||||
} from "@shared/types";
|
||||
import { IntegrationAuthentication, User } from "@server/models";
|
||||
import Integration from "@server/models/Integration";
|
||||
import {
|
||||
buildAdmin,
|
||||
buildTeam,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { z } from "zod";
|
||||
import { IntegrationType } from "@shared/types";
|
||||
import {
|
||||
IntegrationType,
|
||||
UserCreatableIntegrationService,
|
||||
} from "@shared/types";
|
||||
import { Integration } from "@server/models";
|
||||
import { UserCreatableIntegrationService } from "@server/models/Integration";
|
||||
import { BaseSchema } from "../schema";
|
||||
|
||||
export const IntegrationsListSchema = BaseSchema.extend({
|
||||
|
||||
@@ -37,7 +37,8 @@ export default async function main(exit = false) {
|
||||
|
||||
for (const document of documents) {
|
||||
const ydoc = new Y.Doc();
|
||||
Y.applyUpdate(ydoc, document.state);
|
||||
// The where clause above ensures that state is non-null
|
||||
Y.applyUpdate(ydoc, document.state!);
|
||||
const node = Node.fromJSON(
|
||||
schema,
|
||||
yDocToProsemirrorJSON(ydoc, "default")
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import path from "path";
|
||||
import { Model, Sequelize } from "sequelize-typescript";
|
||||
import { InferAttributes, InferCreationAttributes } from "sequelize";
|
||||
import { Sequelize } from "sequelize-typescript";
|
||||
import { Umzug, SequelizeStorage, MigrationError } from "umzug";
|
||||
import env from "@server/env";
|
||||
import Model from "@server/models/base/Model";
|
||||
import Logger from "../logging/Logger";
|
||||
import * as models from "../models";
|
||||
|
||||
@@ -12,7 +14,12 @@ const url = env.DATABASE_CONNECTION_POOL_URL || env.DATABASE_URL;
|
||||
|
||||
export function createDatabaseInstance(
|
||||
url: string,
|
||||
models: { [key: string]: typeof Model }
|
||||
models: {
|
||||
[key: string]: typeof Model<
|
||||
InferAttributes<Model>,
|
||||
InferCreationAttributes<Model>
|
||||
>;
|
||||
}
|
||||
) {
|
||||
return new Sequelize(url, {
|
||||
logging: (msg) =>
|
||||
@@ -28,7 +35,7 @@ export function createDatabaseInstance(
|
||||
}
|
||||
: false,
|
||||
},
|
||||
models: Object.values(models) as any,
|
||||
models: Object.values(models),
|
||||
pool: {
|
||||
max: poolMax,
|
||||
min: poolMin,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { faker } from "@faker-js/faker";
|
||||
import isNil from "lodash/isNil";
|
||||
import isNull from "lodash/isNull";
|
||||
import randomstring from "randomstring";
|
||||
import { InferCreationAttributes } from "sequelize";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import {
|
||||
CollectionPermission,
|
||||
@@ -122,7 +123,6 @@ export async function buildSubscription(overrides: Partial<Subscription> = {}) {
|
||||
}
|
||||
|
||||
return Subscription.create({
|
||||
enabled: true,
|
||||
event: "documents.update",
|
||||
...overrides,
|
||||
});
|
||||
@@ -139,7 +139,7 @@ export function buildTeam(overrides: Record<string, any> = {}) {
|
||||
},
|
||||
],
|
||||
...overrides,
|
||||
},
|
||||
} as Partial<InferCreationAttributes<Team>>,
|
||||
{
|
||||
include: "authenticationProviders",
|
||||
}
|
||||
@@ -200,7 +200,7 @@ export async function buildUser(overrides: Partial<User> = {}) {
|
||||
]
|
||||
: [],
|
||||
...overrides,
|
||||
},
|
||||
} as Partial<InferCreationAttributes<User>>,
|
||||
{
|
||||
include: "authentications",
|
||||
}
|
||||
@@ -377,7 +377,7 @@ export async function buildDocument(
|
||||
publishedAt: isNull(overrides.collectionId) ? null : new Date(),
|
||||
lastModifiedById: overrides.userId,
|
||||
createdById: overrides.userId,
|
||||
editorVersion: 2,
|
||||
editorVersion: "12.0.0",
|
||||
...overrides,
|
||||
},
|
||||
{
|
||||
@@ -398,11 +398,9 @@ export async function buildDocument(
|
||||
|
||||
export async function buildComment(overrides: {
|
||||
userId: string;
|
||||
teamId: string;
|
||||
documentId: string;
|
||||
}) {
|
||||
const comment = await Comment.create({
|
||||
teamId: overrides.teamId,
|
||||
documentId: overrides.documentId,
|
||||
data: {
|
||||
type: "doc",
|
||||
|
||||
@@ -343,6 +343,8 @@ export type ViewEvent = BaseEvent & {
|
||||
};
|
||||
};
|
||||
|
||||
export type WebhookDeliveryStatus = "pending" | "success" | "failed";
|
||||
|
||||
export type WebhookSubscriptionEvent = BaseEvent & {
|
||||
name:
|
||||
| "webhookSubscriptions.create"
|
||||
|
||||
@@ -62,7 +62,7 @@ export type PublicEnv = {
|
||||
APP_NAME: string;
|
||||
ROOT_SHARE_ID?: string;
|
||||
analytics: {
|
||||
service?: IntegrationService;
|
||||
service?: IntegrationService | UserCreatableIntegrationService;
|
||||
settings?: IntegrationSettings<IntegrationType.Analytics>;
|
||||
};
|
||||
};
|
||||
@@ -87,6 +87,12 @@ export enum IntegrationService {
|
||||
GoogleAnalytics = "google-analytics",
|
||||
}
|
||||
|
||||
export enum UserCreatableIntegrationService {
|
||||
Diagrams = "diagrams",
|
||||
Grist = "grist",
|
||||
GoogleAnalytics = "google-analytics",
|
||||
}
|
||||
|
||||
export enum CollectionPermission {
|
||||
Read = "read",
|
||||
ReadWrite = "read_write",
|
||||
|
||||
Reference in New Issue
Block a user