From 5aca24a3003210d743170a8aaad2196821476002 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Fri, 7 Mar 2025 17:27:34 +0000 Subject: [PATCH 1/4] feat: delete due and dandling notifications every day --- config/cron-tasks.ts | 56 ++++++++++++++++++++++++++++++++++++++++++++ config/server.ts | 14 +++++++---- 2 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 config/cron-tasks.ts diff --git a/config/cron-tasks.ts b/config/cron-tasks.ts new file mode 100644 index 0000000..d0dceb6 --- /dev/null +++ b/config/cron-tasks.ts @@ -0,0 +1,56 @@ +export default { + /** + * Delete notifications that are over a week past their due date and orphaned notifications daily at midnight + */ + cleanupExpiredNotifications: { + task: async ({ strapi }) => { + console.log("Running cleanupExpiredNotifications task"); + try { + // Calculate date 1 week ago + const oneWeekAgo = new Date(); + oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); + + // Find all notifications with templates due over a week ago + const expiredNotifications = await strapi.db + .query("api::notification.notification") + .findMany({ + where: { + $or: [ + { + notification_template: { + dueDate: { + $lt: oneWeekAgo, + }, + }, + }, + { + notification_template: null, + }, + ], + }, + }); + + // Delete the expired and orphaned notifications + if (expiredNotifications.length > 0) { + await strapi.db.query("api::notification.notification").deleteMany({ + where: { + id: { + $in: expiredNotifications.map((n) => n.id), + }, + }, + }); + console.log( + `Deleted ${expiredNotifications.length} notifications that were over a week past due or orphaned` + ); + } + } catch (error) { + console.error("Error cleaning up notifications:", error); + } + console.log("Finished cleanupExpiredNotifications task"); + }, + options: { + rule: "0 0 * * *", // Runs daily at midnight + tz: "UTC", + }, + }, +}; diff --git a/config/server.ts b/config/server.ts index eabd9ae..b3624ba 100644 --- a/config/server.ts +++ b/config/server.ts @@ -1,8 +1,10 @@ +import cronTasks from "./cron-tasks"; + export default ({ env }) => ({ - host: env('HOST', '0.0.0.0'), - port: env.int('PORT', 1337), + host: env("HOST", "0.0.0.0"), + port: env.int("PORT", 1337), app: { - keys: env.array('APP_KEYS'), + keys: env.array("APP_KEYS"), }, http: { serverOptions: { @@ -10,6 +12,10 @@ export default ({ env }) => ({ }, }, webhooks: { - populateRelations: env.bool('WEBHOOKS_POPULATE_RELATIONS', false), + populateRelations: env.bool("WEBHOOKS_POPULATE_RELATIONS", false), + }, + cron: { + enabled: true, + tasks: cronTasks, }, }); From 55219ab819e75392b77daffc2ad270b788ec75fa Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Fri, 7 Mar 2025 17:27:54 +0000 Subject: [PATCH 2/4] feat: delete notifications when associated notification-template is deleted --- .../notification-template/lifecycles.ts | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/api/notification-template/content-types/notification-template/lifecycles.ts diff --git a/src/api/notification-template/content-types/notification-template/lifecycles.ts b/src/api/notification-template/content-types/notification-template/lifecycles.ts new file mode 100644 index 0000000..40e06f9 --- /dev/null +++ b/src/api/notification-template/content-types/notification-template/lifecycles.ts @@ -0,0 +1,67 @@ +export default { + async beforeDelete(event) { + const { where } = event.params; + const { id } = where; + + try { + await deleteAssociatedNotifications([id]); + } catch (error) { + console.error(`Error in beforeDelete for template ${id}:`, error); + } + }, + + async beforeDeleteMany(event) { + const { where } = event.params; + const { id } = where; + + try { + // First get all template IDs that will be deleted + const templatesForDeletion = await strapi.db + .query("api::notification-template.notification-template") + .findMany({ + where, + select: ["id"], + }); + + const templateIds = templatesForDeletion.map((template) => template.id); + + if (templateIds.length > 0) { + await deleteAssociatedNotifications(templateIds); + } + } catch (error) { + console.error(`Error in beforeDeleteMany for templates:`, error); + } + }, +}; + +// Helper function to delete notifications for given template IDs +async function deleteAssociatedNotifications(templateIds: number[]) { + // Find all notifications associated with these templates + const notifications = await strapi.db + .query("api::notification.notification") + .findMany({ + where: { + notification_template: { + id: { + $in: templateIds, + }, + }, + }, + }); + + if (notifications.length > 0) { + // Delete all associated notifications + await strapi.db.query("api::notification.notification").deleteMany({ + where: { + id: { + $in: notifications.map((n) => n.id), + }, + }, + }); + console.log( + `Deleted ${ + notifications.length + } notifications associated with template(s) ${templateIds.join(", ")}` + ); + } +} From c85ca2e19c2f8e68c22b438adc37f6873634771d Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Fri, 7 Mar 2025 17:28:33 +0000 Subject: [PATCH 3/4] chore: add .vscode to .gitignore --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 53768e4..c04df4c 100644 --- a/.gitignore +++ b/.gitignore @@ -118,4 +118,9 @@ build ############################ data/* -!data/.gitkeep \ No newline at end of file +!data/.gitkeep + +############################ +# IDE +############################ +.vscode From cb2aa8ba2c68effa612b39465d3f5758ba8a4893 Mon Sep 17 00:00:00 2001 From: Alfetopito Date: Fri, 7 Mar 2025 17:29:52 +0000 Subject: [PATCH 4/4] chore: regenerate types --- .../1.0.0/full_documentation.json | 25 +++- src/gen/types.ts | 110 ++++++++++++++---- 2 files changed, 114 insertions(+), 21 deletions(-) diff --git a/src/extensions/documentation/documentation/1.0.0/full_documentation.json b/src/extensions/documentation/documentation/1.0.0/full_documentation.json index 7f1b195..360fcb2 100644 --- a/src/extensions/documentation/documentation/1.0.0/full_documentation.json +++ b/src/extensions/documentation/documentation/1.0.0/full_documentation.json @@ -14,7 +14,7 @@ "name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html" }, - "x-generation-date": "2025-02-13T15:53:59.140Z" + "x-generation-date": "2025-03-07T17:29:38.606Z" }, "x-strapi-config": { "path": "/documentation", @@ -10516,6 +10516,9 @@ } } }, + "isReducedBondingPool": { + "type": "boolean" + }, "createdAt": { "type": "string", "format": "date-time" @@ -10565,6 +10568,17 @@ } } }, + "isServiceFeeEnabled": { + "type": "boolean" + }, + "isColocated": { + "type": "string", + "enum": [ + "Yes", + "No", + "Partial" + ] + }, "createdAt": { "type": "string", "format": "date-time" @@ -10702,6 +10716,15 @@ } } }, + "isWhiteListed": { + "type": "boolean" + }, + "isVouched": { + "type": "boolean" + }, + "isColocated": { + "type": "boolean" + }, "createdAt": { "type": "string", "format": "date-time" diff --git a/src/gen/types.ts b/src/gen/types.ts index 640c119..96e3d7c 100644 --- a/src/gen/types.ts +++ b/src/gen/types.ts @@ -969,13 +969,13 @@ export interface components { Announcement: { text: string; networks?: { - data?: { + data?: ({ id?: number; attributes?: { name?: string; chainId?: number; solver_networks?: { - data?: { + data?: ({ id?: number; attributes?: { solver?: { @@ -1263,6 +1263,7 @@ export interface components { attributes?: Record; }[]; }; + isReducedBondingPool?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -1282,6 +1283,9 @@ export interface components { }; }[]; }; + isServiceFeeEnabled?: boolean; + /** @enum {string} */ + isColocated?: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -1334,6 +1338,9 @@ export interface components { }; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -1351,7 +1358,7 @@ export interface components { }; }; }; - }[]; + })[]; }; /** Format: date-time */ createdAt?: string; @@ -1370,7 +1377,7 @@ export interface components { }; }; }; - }[]; + })[]; }; environments?: { data?: { @@ -3116,7 +3123,7 @@ export interface components { BondingPool: { name: string; solver_bonding_pools?: { - data?: { + data?: ({ id?: number; attributes?: { address?: string; @@ -3245,7 +3252,7 @@ export interface components { }; }; solvers?: { - data?: { + data?: ({ id?: number; attributes?: { displayName?: string; @@ -3456,6 +3463,9 @@ export interface components { }; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -3481,6 +3491,9 @@ export interface components { attributes?: Record; }[]; }; + isServiceFeeEnabled?: boolean; + /** @enum {string} */ + isColocated?: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -3498,8 +3511,9 @@ export interface components { }; }; }; - }[]; + })[]; }; + isReducedBondingPool?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -3517,7 +3531,7 @@ export interface components { }; }; }; - }[]; + })[]; }; /** Format: date-time */ createdAt?: string; @@ -4320,7 +4334,7 @@ export interface components { name?: string; chainId?: number; solver_networks?: { - data?: { + data?: ({ id?: number; attributes?: { solver?: { @@ -4608,6 +4622,7 @@ export interface components { attributes?: Record; }[]; }; + isReducedBondingPool?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -4627,6 +4642,9 @@ export interface components { }; }[]; }; + isServiceFeeEnabled?: boolean; + /** @enum {string} */ + isColocated?: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -4679,6 +4697,9 @@ export interface components { }; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -4696,7 +4717,7 @@ export interface components { }; }; }; - }[]; + })[]; }; /** Format: date-time */ createdAt?: string; @@ -6583,7 +6604,7 @@ export interface components { name: string; chainId?: number; solver_networks?: { - data?: { + data?: ({ id?: number; attributes?: { solver?: { @@ -6871,6 +6892,7 @@ export interface components { attributes?: Record; }[]; }; + isReducedBondingPool?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -6890,6 +6912,9 @@ export interface components { }; }[]; }; + isServiceFeeEnabled?: boolean; + /** @enum {string} */ + isColocated?: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -6967,6 +6992,9 @@ export interface components { }; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -6984,7 +7012,7 @@ export interface components { }; }; }; - }[]; + })[]; }; /** Format: date-time */ createdAt?: string; @@ -8673,6 +8701,9 @@ export interface components { solverId: string; solver_networks?: (number | string)[]; solver_bonding_pools?: (number | string)[]; + isServiceFeeEnabled: boolean; + /** @enum {string} */ + isColocated: "Yes" | "No" | "Partial"; }; }; SolverListResponseDataItem: { @@ -8924,7 +8955,7 @@ export interface components { description?: string; solverId: string; solver_networks?: { - data?: { + data?: ({ id?: number; attributes?: { solver?: { @@ -9037,6 +9068,7 @@ export interface components { attributes?: Record; }[]; }; + isReducedBondingPool?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -9056,6 +9088,9 @@ export interface components { }; }[]; }; + isServiceFeeEnabled?: boolean; + /** @enum {string} */ + isColocated?: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -9133,6 +9168,9 @@ export interface components { }; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -9150,7 +9188,7 @@ export interface components { }; }; }; - }[]; + })[]; }; solver_bonding_pools?: { data?: { @@ -9158,6 +9196,9 @@ export interface components { attributes?: Record; }[]; }; + isServiceFeeEnabled: boolean; + /** @enum {string} */ + isColocated: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -9191,6 +9232,7 @@ export interface components { /** @example string or id */ bonding_pool?: number | string; solvers?: (number | string)[]; + isReducedBondingPool: boolean; }; }; SolverBondingPoolListResponseDataItem: { @@ -9218,7 +9260,7 @@ export interface components { attributes?: { name?: string; solver_bonding_pools?: { - data?: { + data?: ({ id?: number; attributes?: { address?: string; @@ -9231,7 +9273,7 @@ export interface components { }; }; solvers?: { - data?: { + data?: ({ id?: number; attributes?: { displayName?: string; @@ -9534,6 +9576,9 @@ export interface components { }; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -9559,6 +9604,9 @@ export interface components { attributes?: Record; }[]; }; + isServiceFeeEnabled?: boolean; + /** @enum {string} */ + isColocated?: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -9576,8 +9624,9 @@ export interface components { }; }; }; - }[]; + })[]; }; + isReducedBondingPool?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -9595,7 +9644,7 @@ export interface components { }; }; }; - }[]; + })[]; }; /** Format: date-time */ createdAt?: string; @@ -9622,6 +9671,7 @@ export interface components { attributes?: Record; }[]; }; + isReducedBondingPool: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -9658,6 +9708,9 @@ export interface components { active: boolean; /** @example string or id */ environment?: number | string; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated: boolean; }; }; SolverNetworkListResponseDataItem: { @@ -9980,6 +10033,9 @@ export interface components { }; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -10042,6 +10098,7 @@ export interface components { attributes?: Record; }[]; }; + isReducedBondingPool?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -10061,6 +10118,9 @@ export interface components { }; }[]; }; + isServiceFeeEnabled?: boolean; + /** @enum {string} */ + isColocated?: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -10095,6 +10155,9 @@ export interface components { attributes?: Record; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -10835,7 +10898,7 @@ export interface components { name?: string; chainId?: number; solver_networks?: { - data?: { + data?: ({ id?: number; attributes?: { solver?: { @@ -11123,6 +11186,7 @@ export interface components { attributes?: Record; }[]; }; + isReducedBondingPool?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -11142,6 +11206,9 @@ export interface components { }; }[]; }; + isServiceFeeEnabled?: boolean; + /** @enum {string} */ + isColocated?: "Yes" | "No" | "Partial"; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -11194,6 +11261,9 @@ export interface components { }; }; }; + isWhiteListed?: boolean; + isVouched?: boolean; + isColocated?: boolean; /** Format: date-time */ createdAt?: string; /** Format: date-time */ @@ -11211,7 +11281,7 @@ export interface components { }; }; }; - }[]; + })[]; }; /** Format: date-time */ createdAt?: string;