mirror of
https://github.com/outline/outline.git
synced 2026-06-13 11:25:03 +03:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e92500dd85 | |||
| 1acec2502e | |||
| c42ce87309 | |||
| cab5dcef6a |
@@ -66,6 +66,6 @@ export class NotionImportsProcessor extends ImportsProcessor<IntegrationService.
|
||||
protected async scheduleTask(
|
||||
importTask: ImportTask<IntegrationService.Notion>
|
||||
): Promise<void> {
|
||||
await NotionAPIImportTask.schedule({ importTaskId: importTask.id });
|
||||
await new NotionAPIImportTask().schedule({ importTaskId: importTask.id });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export default class NotionAPIImportTask extends APIImportTask<IntegrationServic
|
||||
protected async scheduleNextTask(
|
||||
importTask: ImportTask<IntegrationService.Notion>
|
||||
) {
|
||||
await NotionAPIImportTask.schedule({ importTaskId: importTask.id });
|
||||
await new NotionAPIImportTask().schedule({ importTaskId: importTask.id });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,12 @@ describe("WebhookProcessor", () => {
|
||||
|
||||
await processor.perform(event);
|
||||
|
||||
expect(DeliverWebhookTask.schedule).toHaveBeenCalled();
|
||||
expect(DeliverWebhookTask.schedule).toHaveBeenCalledWith({
|
||||
expect(
|
||||
jest.mocked(DeliverWebhookTask.prototype.schedule)
|
||||
).toHaveBeenCalled();
|
||||
expect(
|
||||
jest.mocked(DeliverWebhookTask.prototype.schedule)
|
||||
).toHaveBeenCalledWith({
|
||||
event,
|
||||
subscriptionId: subscription.id,
|
||||
});
|
||||
@@ -53,7 +57,9 @@ describe("WebhookProcessor", () => {
|
||||
|
||||
await processor.perform(event);
|
||||
|
||||
expect(DeliverWebhookTask.schedule).toHaveBeenCalledTimes(0);
|
||||
expect(
|
||||
jest.mocked(DeliverWebhookTask.prototype.schedule)
|
||||
).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it("it schedules a delivery for the event for each subscription", async () => {
|
||||
@@ -79,13 +85,21 @@ describe("WebhookProcessor", () => {
|
||||
|
||||
await processor.perform(event);
|
||||
|
||||
expect(DeliverWebhookTask.schedule).toHaveBeenCalled();
|
||||
expect(DeliverWebhookTask.schedule).toHaveBeenCalledTimes(2);
|
||||
expect(DeliverWebhookTask.schedule).toHaveBeenCalledWith({
|
||||
expect(
|
||||
jest.mocked(DeliverWebhookTask.prototype.schedule)
|
||||
).toHaveBeenCalled();
|
||||
expect(
|
||||
jest.mocked(DeliverWebhookTask.prototype.schedule)
|
||||
).toHaveBeenCalledTimes(2);
|
||||
expect(
|
||||
jest.mocked(DeliverWebhookTask.prototype.schedule)
|
||||
).toHaveBeenCalledWith({
|
||||
event,
|
||||
subscriptionId: subscription.id,
|
||||
});
|
||||
expect(DeliverWebhookTask.schedule).toHaveBeenCalledWith({
|
||||
expect(
|
||||
jest.mocked(DeliverWebhookTask.prototype.schedule)
|
||||
).toHaveBeenCalledWith({
|
||||
event,
|
||||
subscriptionId: subscriptionTwo.id,
|
||||
});
|
||||
|
||||
@@ -24,7 +24,10 @@ export default class WebhookProcessor extends BaseProcessor {
|
||||
|
||||
await Promise.all(
|
||||
applicableSubscriptions.map((subscription) =>
|
||||
DeliverWebhookTask.schedule({ event, subscriptionId: subscription.id })
|
||||
new DeliverWebhookTask().schedule({
|
||||
event,
|
||||
subscriptionId: subscription.id,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type Props = {
|
||||
/** Position of moved document within document structure */
|
||||
index?: number;
|
||||
/** The IP address of the user moving the document */
|
||||
ip: string;
|
||||
ip: string | null;
|
||||
/** The database transaction to run within */
|
||||
transaction?: Transaction;
|
||||
};
|
||||
|
||||
@@ -4,9 +4,11 @@ import DeleteAttachmentTask from "@server/queues/tasks/DeleteAttachmentTask";
|
||||
import { buildAttachment, buildDocument } from "@server/test/factories";
|
||||
import documentPermanentDeleter from "./documentPermanentDeleter";
|
||||
|
||||
jest.mock("@server/queues/tasks/DeleteAttachmentTask", () => ({
|
||||
schedule: jest.fn(),
|
||||
}));
|
||||
jest.mock("@server/queues/tasks/DeleteAttachmentTask");
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe("documentPermanentDeleter", () => {
|
||||
it("should destroy documents", async () => {
|
||||
@@ -60,7 +62,9 @@ describe("documentPermanentDeleter", () => {
|
||||
await document.save();
|
||||
const countDeletedDoc = await documentPermanentDeleter([document]);
|
||||
expect(countDeletedDoc).toEqual(1);
|
||||
expect(DeleteAttachmentTask.schedule).toHaveBeenCalledTimes(2);
|
||||
expect(
|
||||
jest.mocked(DeleteAttachmentTask.prototype.schedule)
|
||||
).toHaveBeenCalledTimes(2);
|
||||
expect(
|
||||
await Document.unscoped().count({
|
||||
where: {
|
||||
|
||||
@@ -67,7 +67,7 @@ export default async function documentPermanentDeleter(documents: Document[]) {
|
||||
"commands",
|
||||
`Attachment ${attachmentId} scheduled for deletion`
|
||||
);
|
||||
await DeleteAttachmentTask.schedule({
|
||||
await new DeleteAttachmentTask().schedule({
|
||||
attachmentId,
|
||||
teamId: document.teamId,
|
||||
});
|
||||
|
||||
@@ -56,5 +56,5 @@ export default async function userSuspender({
|
||||
}
|
||||
);
|
||||
|
||||
await CleanupDemotedUserTask.schedule({ userId: user.id });
|
||||
await new CleanupDemotedUserTask().schedule({ userId: user.id });
|
||||
}
|
||||
|
||||
@@ -408,7 +408,7 @@ class Team extends ParanoidModel<
|
||||
});
|
||||
|
||||
if (attachment) {
|
||||
await DeleteAttachmentTask.schedule({
|
||||
await new DeleteAttachmentTask().schedule({
|
||||
attachmentId: attachment.id,
|
||||
teamId: model.id,
|
||||
});
|
||||
|
||||
@@ -717,7 +717,7 @@ class User extends ParanoidModel<
|
||||
});
|
||||
|
||||
if (attachment) {
|
||||
await DeleteAttachmentTask.schedule({
|
||||
await new DeleteAttachmentTask().schedule({
|
||||
attachmentId: attachment.id,
|
||||
teamId: model.teamId,
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@ export default class AvatarProcessor extends BaseProcessor {
|
||||
});
|
||||
|
||||
if (user.avatarUrl) {
|
||||
await UploadUserAvatarTask.schedule({
|
||||
await new UploadUserAvatarTask().schedule({
|
||||
userId: event.userId,
|
||||
avatarUrl: user.avatarUrl,
|
||||
});
|
||||
@@ -30,7 +30,7 @@ export default class AvatarProcessor extends BaseProcessor {
|
||||
});
|
||||
|
||||
if (team.avatarUrl) {
|
||||
await UploadTeamAvatarTask.schedule({
|
||||
await new UploadTeamAvatarTask().schedule({
|
||||
teamId: event.teamId,
|
||||
avatarUrl: team.avatarUrl,
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ export default class CollectionsProcessor extends BaseProcessor {
|
||||
];
|
||||
|
||||
async perform(event: CollectionEvent) {
|
||||
await DetachDraftsFromCollectionTask.schedule({
|
||||
await new DetachDraftsFromCollectionTask().schedule({
|
||||
collectionId: event.collectionId,
|
||||
actorId: event.actorId,
|
||||
ip: event.ip,
|
||||
|
||||
@@ -27,7 +27,7 @@ export default class DocumentSubscriptionProcessor extends BaseProcessor {
|
||||
async perform(event: ReceivedEvent) {
|
||||
switch (event.name) {
|
||||
case "collections.remove_user": {
|
||||
await CollectionSubscriptionRemoveUserTask.schedule(event);
|
||||
await new CollectionSubscriptionRemoveUserTask().schedule(event);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export default class DocumentSubscriptionProcessor extends BaseProcessor {
|
||||
return this.handleRemoveGroupFromCollection(event);
|
||||
|
||||
case "documents.remove_user": {
|
||||
await DocumentSubscriptionRemoveUserTask.schedule(event);
|
||||
await new DocumentSubscriptionRemoveUserTask().schedule(event);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -57,11 +57,11 @@ export default class DocumentSubscriptionProcessor extends BaseProcessor {
|
||||
async (groupUsers) => {
|
||||
await Promise.all(
|
||||
groupUsers.map((groupUser) =>
|
||||
CollectionSubscriptionRemoveUserTask.schedule({
|
||||
new CollectionSubscriptionRemoveUserTask().schedule({
|
||||
...event,
|
||||
name: "collections.remove_user",
|
||||
userId: groupUser.userId,
|
||||
})
|
||||
} as CollectionUserEvent)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -79,11 +79,11 @@ export default class DocumentSubscriptionProcessor extends BaseProcessor {
|
||||
async (groupUsers) => {
|
||||
await Promise.all(
|
||||
groupUsers.map((groupUser) =>
|
||||
DocumentSubscriptionRemoveUserTask.schedule({
|
||||
new DocumentSubscriptionRemoveUserTask().schedule({
|
||||
...event,
|
||||
name: "documents.remove_user",
|
||||
userId: groupUser.userId,
|
||||
})
|
||||
} as DocumentUserEvent)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ export default class FileOperationCreatedProcessor extends BaseProcessor {
|
||||
if (fileOperation.type === FileOperationType.Import) {
|
||||
switch (fileOperation.format) {
|
||||
case FileOperationFormat.MarkdownZip:
|
||||
await ImportMarkdownZipTask.schedule({
|
||||
await new ImportMarkdownZipTask().schedule({
|
||||
fileOperationId: event.modelId,
|
||||
});
|
||||
break;
|
||||
case FileOperationFormat.JSON:
|
||||
await ImportJSONTask.schedule({
|
||||
await new ImportJSONTask().schedule({
|
||||
fileOperationId: event.modelId,
|
||||
});
|
||||
break;
|
||||
@@ -36,17 +36,17 @@ export default class FileOperationCreatedProcessor extends BaseProcessor {
|
||||
if (fileOperation.type === FileOperationType.Export) {
|
||||
switch (fileOperation.format) {
|
||||
case FileOperationFormat.HTMLZip:
|
||||
await ExportHTMLZipTask.schedule({
|
||||
await new ExportHTMLZipTask().schedule({
|
||||
fileOperationId: event.modelId,
|
||||
});
|
||||
break;
|
||||
case FileOperationFormat.MarkdownZip:
|
||||
await ExportMarkdownZipTask.schedule({
|
||||
await new ExportMarkdownZipTask().schedule({
|
||||
fileOperationId: event.modelId,
|
||||
});
|
||||
break;
|
||||
case FileOperationFormat.JSON:
|
||||
await ExportJSONTask.schedule({
|
||||
await new ExportJSONTask().schedule({
|
||||
fileOperationId: event.modelId,
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -62,25 +62,25 @@ export default class NotificationsProcessor extends BaseProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
await DocumentPublishedNotificationsTask.schedule(event);
|
||||
await new DocumentPublishedNotificationsTask().schedule(event);
|
||||
}
|
||||
|
||||
async documentAddUser(event: DocumentUserEvent) {
|
||||
if (!event.data.isNew || event.userId === event.actorId) {
|
||||
return;
|
||||
}
|
||||
await DocumentAddUserNotificationsTask.schedule(event);
|
||||
await new DocumentAddUserNotificationsTask().schedule(event);
|
||||
}
|
||||
|
||||
async documentAddGroup(event: DocumentGroupEvent) {
|
||||
if (!event.data.isNew) {
|
||||
return;
|
||||
}
|
||||
await DocumentAddGroupNotificationsTask.schedule(event);
|
||||
await new DocumentAddGroupNotificationsTask().schedule(event);
|
||||
}
|
||||
|
||||
async revisionCreated(event: RevisionEvent) {
|
||||
await RevisionCreatedNotificationsTask.schedule(event);
|
||||
await new RevisionCreatedNotificationsTask().schedule(event);
|
||||
}
|
||||
|
||||
async collectionCreated(event: CollectionEvent) {
|
||||
@@ -93,7 +93,7 @@ export default class NotificationsProcessor extends BaseProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
await CollectionCreatedNotificationsTask.schedule(event);
|
||||
await new CollectionCreatedNotificationsTask().schedule(event);
|
||||
}
|
||||
|
||||
async collectionAddUser(event: CollectionUserEvent) {
|
||||
@@ -101,14 +101,14 @@ export default class NotificationsProcessor extends BaseProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
await CollectionAddUserNotificationsTask.schedule(event);
|
||||
await new CollectionAddUserNotificationsTask().schedule(event);
|
||||
}
|
||||
|
||||
async commentCreated(event: CommentEvent) {
|
||||
await CommentCreatedNotificationsTask.schedule(event);
|
||||
await new CommentCreatedNotificationsTask().schedule(event);
|
||||
}
|
||||
|
||||
async commentUpdated(event: CommentEvent) {
|
||||
await CommentUpdatedNotificationsTask.schedule(event);
|
||||
await new CommentUpdatedNotificationsTask().schedule(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ export default class RevisionsProcessor extends BaseProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
await DocumentUpdateTextTask.schedule(event);
|
||||
await new DocumentUpdateTextTask().schedule(event);
|
||||
|
||||
const user = await User.findByPk(event.actorId, {
|
||||
paranoid: false,
|
||||
|
||||
@@ -6,6 +6,6 @@ export default class UserDemotedProcessor extends BaseProcessor {
|
||||
static applicableEvents: TEvent["name"][] = ["users.demote"];
|
||||
|
||||
async perform(event: UserEvent) {
|
||||
await CleanupDemotedUserTask.schedule({ userId: event.userId });
|
||||
await new CleanupDemotedUserTask().schedule({ userId: event.userId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,9 @@ export default abstract class APIImportTask<
|
||||
([url, attachment]) => ({ attachmentId: attachment.id, url })
|
||||
);
|
||||
// publish task after attachments are persisted in DB.
|
||||
const job = await UploadAttachmentsForImportTask.schedule(uploadItems);
|
||||
const job = await new UploadAttachmentsForImportTask().schedule(
|
||||
uploadItems
|
||||
);
|
||||
await job.finished();
|
||||
} catch (err) {
|
||||
// upload attachments failure is not critical enough to fail the whole import.
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class CleanupDeletedTeamsTask extends BaseTask<Props> {
|
||||
});
|
||||
|
||||
for (const team of teams) {
|
||||
await CleanupDeletedTeamTask.schedule({
|
||||
await new CleanupDeletedTeamTask().schedule({
|
||||
teamId: team.id,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import BaseTask from "./BaseTask";
|
||||
type Props = {
|
||||
collectionId: string;
|
||||
actorId: string;
|
||||
ip: string;
|
||||
ip: string | null;
|
||||
};
|
||||
|
||||
export default class DetachDraftsFromCollectionTask extends BaseTask<Props> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Op } from "sequelize";
|
||||
import { GroupUser } from "@server/models";
|
||||
import { DocumentGroupEvent } from "@server/types";
|
||||
import { DocumentGroupEvent, DocumentUserEvent } from "@server/types";
|
||||
import BaseTask, { TaskPriority } from "./BaseTask";
|
||||
import DocumentAddUserNotificationsTask from "./DocumentAddUserNotificationsTask";
|
||||
|
||||
@@ -19,11 +19,12 @@ export default class DocumentAddGroupNotificationsTask extends BaseTask<Document
|
||||
async (groupUsers) => {
|
||||
await Promise.all(
|
||||
groupUsers.map(async (groupUser) => {
|
||||
await DocumentAddUserNotificationsTask.schedule({
|
||||
await new DocumentAddUserNotificationsTask().schedule({
|
||||
...event,
|
||||
name: "documents.add_user",
|
||||
modelId: event.data.membershipId,
|
||||
userId: groupUser.userId,
|
||||
});
|
||||
} as DocumentUserEvent);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ type Props = {
|
||||
sourceMetadata: Pick<Required<SourceMetadata>, "fileName" | "mimeType">;
|
||||
publish?: boolean;
|
||||
collectionId?: string;
|
||||
parentDocumentId?: string;
|
||||
parentDocumentId?: string | null;
|
||||
ip: string;
|
||||
key: string;
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ export default class UpdateTeamsAttachmentsSizeTask extends BaseTask<Props> {
|
||||
const teamIds = rows.map((row) => row.teamId);
|
||||
|
||||
for (const teamId of teamIds) {
|
||||
await UpdateTeamAttachmentsSizeTask.schedule({ teamId });
|
||||
await new UpdateTeamAttachmentsSizeTask().schedule({ teamId });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -166,7 +166,7 @@ router.post(
|
||||
)
|
||||
);
|
||||
|
||||
const job = await UploadAttachmentFromUrlTask.schedule({
|
||||
const job = await new UploadAttachmentFromUrlTask().schedule({
|
||||
attachmentId: attachment.id,
|
||||
url,
|
||||
});
|
||||
|
||||
@@ -135,7 +135,7 @@ router.post("auth.info", auth(), async (ctx: APIContext<T.AuthInfoReq>) => {
|
||||
// If the user did not _just_ sign in then we need to check if they continue
|
||||
// to have access to the workspace they are signed into.
|
||||
if (user.lastSignedInAt && user.lastSignedInAt < subHours(new Date(), 1)) {
|
||||
await ValidateSSOAccessTask.schedule({ userId: user.id });
|
||||
await new ValidateSSOAccessTask().schedule({ userId: user.id });
|
||||
}
|
||||
|
||||
ctx.body = {
|
||||
|
||||
@@ -29,7 +29,8 @@ const cronHandler = async (ctx: APIContext<T.CronSchemaReq>) => {
|
||||
for (const name in tasks) {
|
||||
const TaskClass = tasks[name];
|
||||
if (TaskClass.cron === period) {
|
||||
await TaskClass.schedule({ limit });
|
||||
// @ts-expect-error We won't instantiate an abstract class
|
||||
await new TaskClass().schedule({ limit });
|
||||
|
||||
// Backwards compatibility for installations that have not set up
|
||||
// cron jobs periods other than daily.
|
||||
@@ -38,13 +39,15 @@ const cronHandler = async (ctx: APIContext<T.CronSchemaReq>) => {
|
||||
!receivedPeriods.has(TaskSchedule.Minute) &&
|
||||
(period === TaskSchedule.Hour || period === TaskSchedule.Day)
|
||||
) {
|
||||
await TaskClass.schedule({ limit });
|
||||
// @ts-expect-error We won't instantiate an abstract class
|
||||
await new TaskClass().schedule({ limit });
|
||||
} else if (
|
||||
TaskClass.cron === TaskSchedule.Hour &&
|
||||
!receivedPeriods.has(TaskSchedule.Hour) &&
|
||||
period === TaskSchedule.Day
|
||||
) {
|
||||
await TaskClass.schedule({ limit });
|
||||
// @ts-expect-error We won't instantiate an abstract class
|
||||
await new TaskClass().schedule({ limit });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1539,7 +1539,7 @@ router.post(
|
||||
acl,
|
||||
});
|
||||
|
||||
const job = await DocumentImportTask.schedule({
|
||||
const job = await new DocumentImportTask().schedule({
|
||||
key,
|
||||
sourceMetadata: {
|
||||
fileName,
|
||||
@@ -1549,6 +1549,7 @@ router.post(
|
||||
collectionId,
|
||||
parentDocumentId,
|
||||
publish,
|
||||
ip: ctx.request.ip,
|
||||
});
|
||||
const response: DocumentImportTaskResponse = await job.finished();
|
||||
if ("error" in response) {
|
||||
@@ -2062,7 +2063,7 @@ router.post(
|
||||
});
|
||||
|
||||
if (documents.length) {
|
||||
await EmptyTrashTask.schedule({
|
||||
await new EmptyTrashTask().schedule({
|
||||
documentIds: documents.map((doc) => doc.id),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ export default function init() {
|
||||
for (const name in tasks) {
|
||||
const TaskClass = tasks[name];
|
||||
if (TaskClass.cron === schedule) {
|
||||
await TaskClass.schedule({ limit: 10000 });
|
||||
// @ts-expect-error We won't instantiate an abstract class
|
||||
await new TaskClass().schedule({ limit: 10000 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user