diff --git a/convex/crons.ts b/convex/crons.ts new file mode 100644 index 0000000..1964000 --- /dev/null +++ b/convex/crons.ts @@ -0,0 +1,12 @@ +import { cronJobs } from "convex/server"; +import { internal } from "./_generated/api"; + +const crons = cronJobs(); + +crons.daily( + "delete closed requests after a day", + { hourUTC: 1, minuteUTC: 0 }, + internal.requests.deleteOldClosedRequests +); + +export default crons; \ No newline at end of file diff --git a/convex/leaks.ts b/convex/leaks.ts index 92bb903..55bcebf 100644 --- a/convex/leaks.ts +++ b/convex/leaks.ts @@ -544,6 +544,7 @@ export const applyConsensusResult = internalMutation({ await ctx.db.patch(args.requestId, { closed: true, + closedBy: "verification", }); const submitter = await ctx.db.get(leak.submittedBy); diff --git a/convex/requests.ts b/convex/requests.ts index 47c581a..e314ddf 100644 --- a/convex/requests.ts +++ b/convex/requests.ts @@ -1,6 +1,6 @@ import { v } from "convex/values"; import { getAuthUserId } from "@convex-dev/auth/server"; -import { query, mutation } from "./_generated/server"; +import { query, mutation, internalMutation } from "./_generated/server"; import { Id } from "./_generated/dataModel"; // url validation helper @@ -8,8 +8,6 @@ function isValidUrl(url: string): boolean { return /^https?:\/\/.+/i.test(url); // only http and https } - - /** * Get all open (non-closed) requests from the database. * Returns requests with submitter names populated. @@ -279,6 +277,7 @@ export const closeRequest = mutation({ // Close the request await ctx.db.patch(args.requestId, { closed: true, + closedBy: "user", }); return { success: true as const }; @@ -454,3 +453,41 @@ export const getRequestsWithVerificationStatus = query({ return requestsWithStatus; }, }); + +/* + Delete closed requests after a day --> internal mutation called by a cron job +*/ + +export const deleteOldClosedRequests = internalMutation({ + args: {}, + returns: v.number(), + handler: async (ctx) => { + + //const daysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000; // 30 days in milliseconds + const daysAgo = Date.now() - 24 * 60 * 60 * 1000; // 1 day in milliseconds + + const oldClosedRequests = await ctx.db + .query("requests") + .withIndex("by_closed", (q) => q.eq("closed", true)) + .collect(); + + let deletedCount = 0; + + for (const request of oldClosedRequests) { + if (request._creationTime < daysAgo && request.closedBy === "user") { + // remove from users array of requests + if (request.submittedBy) { + const user = await ctx.db.get(request.submittedBy); + if (user && user.requests) { + await ctx.db.patch(request.submittedBy, { + requests: user.requests.filter((id) => id !== request._id), + }); + } + } + await ctx.db.delete(request._id); + deletedCount++; + } + } + return deletedCount; + }, +}); diff --git a/convex/schema.ts b/convex/schema.ts index dda21dd..d119a62 100644 --- a/convex/schema.ts +++ b/convex/schema.ts @@ -43,6 +43,7 @@ const requests = defineTable({ ), targetUrl: v.string(), closed: v.boolean(), + closedBy: v.optional(v.union(v.literal("user"), v.literal("verification"))), leaks: v.array(v.id("leaks")), submittedBy: v.id("users"), })