fix: canceling workflow reminders (#21416)
* fix deleting reminders * schedule reminders if iffy is disabled * fix unit test * clean up code --------- Co-authored-by: CarinaWolli <wollencarina@gmail.com>
This commit is contained in:
co-authored by
CarinaWolli
parent
21a4711f07
commit
4ff366cd99
@@ -5,7 +5,7 @@ import { describe, expect, it, vi, beforeEach } from "vitest";
|
||||
import { lockUser, LockReason } from "@calcom/lib/autoLock";
|
||||
import { scheduleWorkflowNotifications } from "@calcom/trpc/server/routers/viewer/workflows/util";
|
||||
|
||||
import { scanWorkflowBody } from "./scanWorkflowBody";
|
||||
import { scanWorkflowBody, iffyScanBody } from "./scanWorkflowBody";
|
||||
|
||||
vi.mock("@calcom/lib/autoLock", async (importActual) => {
|
||||
const actual = await importActual<typeof import("@calcom/lib/autoLock")>();
|
||||
@@ -19,6 +19,14 @@ vi.mock("@calcom/trpc/server/routers/viewer/workflows/util", () => ({
|
||||
scheduleWorkflowNotifications: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("./scanWorkflowBody", async (importActual) => {
|
||||
const actual = await importActual<typeof import("./scanWorkflowBody")>();
|
||||
return {
|
||||
...actual,
|
||||
iffyScanBody: vi.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const mockWorkflowStep = {
|
||||
id: 1,
|
||||
reminderBody: "Test reminder body",
|
||||
@@ -58,7 +66,7 @@ describe("scanWorkflowBody", () => {
|
||||
|
||||
await scanWorkflowBody(payload);
|
||||
|
||||
expect(prismaMock.workflowStep.findMany).not.toHaveBeenCalled();
|
||||
expect(iffyScanBody).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should mark workflow step as safe if no reminder body", async () => {
|
||||
|
||||
@@ -19,21 +19,6 @@ const log = logger.getSubLogger({ prefix: ["[tasker] scanWorkflowBody"] });
|
||||
export async function scanWorkflowBody(payload: string) {
|
||||
const { workflowStepIds, userId } = scanWorkflowBodySchema.parse(JSON.parse(payload));
|
||||
|
||||
if (!process.env.IFFY_API_KEY) {
|
||||
log.info("IFFY_API_KEY not set, skipping scan");
|
||||
await prisma.workflowStep.updateMany({
|
||||
where: {
|
||||
id: {
|
||||
in: workflowStepIds,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
verifiedAt: new Date(),
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const workflowSteps = await prisma.workflowStep.findMany({
|
||||
where: {
|
||||
id: {
|
||||
@@ -55,68 +40,84 @@ export async function scanWorkflowBody(payload: string) {
|
||||
},
|
||||
});
|
||||
|
||||
for (const workflowStep of workflowSteps) {
|
||||
if (!workflowStep.reminderBody) {
|
||||
await prisma.workflowStep.update({
|
||||
where: {
|
||||
id: workflowStep.id,
|
||||
},
|
||||
data: {
|
||||
verifiedAt: new Date(),
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const timeFormat = getTimeFormatStringFromUserTimeFormat(workflowStep.workflow.user?.timeFormat);
|
||||
|
||||
// Determine if body is a template
|
||||
const defaultTemplate = getTemplateBodyForAction({
|
||||
action: workflowStep.action,
|
||||
locale: workflowStep.workflow.user?.locale ?? "en",
|
||||
t: await getTranslation(workflowStep.workflow.user?.locale ?? "en", "common"),
|
||||
template: workflowStep.template,
|
||||
timeFormat,
|
||||
});
|
||||
|
||||
if (!defaultTemplate) {
|
||||
log.error(`Template not found for action ${workflowStep.action}, template ${workflowStep.template}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
compareReminderBodyToTemplate({ reminderBody: workflowStep.reminderBody, template: defaultTemplate })
|
||||
) {
|
||||
await prisma.workflowStep.update({
|
||||
where: {
|
||||
id: workflowStep.id,
|
||||
},
|
||||
data: {
|
||||
verifiedAt: new Date(),
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const isSpam = await iffyScanBody(workflowStep.reminderBody, workflowStep.id);
|
||||
|
||||
if (isSpam) {
|
||||
if (!workflowStep.workflow.user?.whitelistWorkflows) {
|
||||
// We won't delete the workflow step incase it is flagged as a false positive
|
||||
log.warn(`Workflow step ${workflowStep.id} is spam with body ${workflowStep.reminderBody}`);
|
||||
await lockUser("userId", userId.toString(), LockReason.SPAM_WORKFLOW_BODY);
|
||||
|
||||
// Return early if spam is detected
|
||||
return;
|
||||
if (process.env.IFFY_API_KEY) {
|
||||
for (const workflowStep of workflowSteps) {
|
||||
if (!workflowStep.reminderBody) {
|
||||
await prisma.workflowStep.update({
|
||||
where: {
|
||||
id: workflowStep.id,
|
||||
},
|
||||
data: {
|
||||
verifiedAt: new Date(),
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
log.warn(
|
||||
`For whitelisted user, workflow step ${workflowStep.id} is spam with body ${workflowStep.reminderBody}`
|
||||
);
|
||||
}
|
||||
|
||||
await prisma.workflowStep.update({
|
||||
const timeFormat = getTimeFormatStringFromUserTimeFormat(workflowStep.workflow.user?.timeFormat);
|
||||
|
||||
// Determine if body is a template
|
||||
const defaultTemplate = getTemplateBodyForAction({
|
||||
action: workflowStep.action,
|
||||
locale: workflowStep.workflow.user?.locale ?? "en",
|
||||
t: await getTranslation(workflowStep.workflow.user?.locale ?? "en", "common"),
|
||||
template: workflowStep.template,
|
||||
timeFormat,
|
||||
});
|
||||
|
||||
if (!defaultTemplate) {
|
||||
log.error(`Template not found for action ${workflowStep.action}, template ${workflowStep.template}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
compareReminderBodyToTemplate({ reminderBody: workflowStep.reminderBody, template: defaultTemplate })
|
||||
) {
|
||||
await prisma.workflowStep.update({
|
||||
where: {
|
||||
id: workflowStep.id,
|
||||
},
|
||||
data: {
|
||||
verifiedAt: new Date(),
|
||||
},
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const isSpam = await iffyScanBody(workflowStep.reminderBody, workflowStep.id);
|
||||
|
||||
if (isSpam) {
|
||||
if (!workflowStep.workflow.user?.whitelistWorkflows) {
|
||||
// We won't delete the workflow step incase it is flagged as a false positive
|
||||
log.warn(`Workflow step ${workflowStep.id} is spam with body ${workflowStep.reminderBody}`);
|
||||
await lockUser("userId", userId.toString(), LockReason.SPAM_WORKFLOW_BODY);
|
||||
|
||||
// Return early if spam is detected
|
||||
return;
|
||||
}
|
||||
log.warn(
|
||||
`For whitelisted user, workflow step ${workflowStep.id} is spam with body ${workflowStep.reminderBody}`
|
||||
);
|
||||
}
|
||||
|
||||
await prisma.workflowStep.update({
|
||||
where: {
|
||||
id: workflowStep.id,
|
||||
},
|
||||
data: {
|
||||
verifiedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!process.env.IFFY_API_KEY) {
|
||||
log.info("IFFY_API_KEY not set, skipping scan");
|
||||
await prisma.workflowStep.updateMany({
|
||||
where: {
|
||||
id: workflowStep.id,
|
||||
id: {
|
||||
in: workflowStepIds,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
verifiedAt: new Date(),
|
||||
@@ -159,7 +160,7 @@ export async function scanWorkflowBody(payload: string) {
|
||||
});
|
||||
}
|
||||
|
||||
const iffyScanBody = async (body: string, workflowStepId: number) => {
|
||||
export const iffyScanBody = async (body: string, workflowStepId: number) => {
|
||||
try {
|
||||
const response = await fetch("https://api.iffy.com/api/v1/moderate", {
|
||||
method: "POST",
|
||||
|
||||
@@ -164,8 +164,9 @@ export const activateEventTypeHandler = async ({ ctx, input }: ActivateEventType
|
||||
const remindersToDelete = await prisma.workflowReminder.findMany({
|
||||
where: {
|
||||
booking: {
|
||||
eventTypeId: eventTypeId,
|
||||
userId: ctx.user.id,
|
||||
eventTypeId: {
|
||||
in: Array.from(activeOnEventTypes.keys()),
|
||||
},
|
||||
},
|
||||
workflowStepId: {
|
||||
in: eventTypeWorkflow.steps.map((step) => {
|
||||
|
||||
Reference in New Issue
Block a user