From 39ea6dcafbf1f1769014eec719f985c92ad6ab5f Mon Sep 17 00:00:00 2001 From: Sharon Dcruz Date: Mon, 18 Aug 2025 13:42:26 +0000 Subject: [PATCH 1/3] notification-bug-fix (#87) Reviewed-on: https://git.cosqnet.com/cosqnet/fitlien-services/pulls/87 Reviewed-by: Allen T J Co-authored-by: Sharon Dcruz Co-committed-by: Sharon Dcruz --- firestore.indexes.json | 28 +++++++++++ .../membershipStatusNotifications.ts | 50 ++++++++++++++++--- 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/firestore.indexes.json b/firestore.indexes.json index 2016f51..0530c8b 100644 --- a/firestore.indexes.json +++ b/firestore.indexes.json @@ -28,6 +28,34 @@ } ] }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "userId", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "DESCENDING" + } + ] + }, + { + "collectionGroup": "gyms", + "queryScope": "COLLECTION_GROUP", + "fields": [ + { + "fieldPath": "isApproved", + "order": "ASCENDING" + }, + { + "fieldPath": "createdAt", + "order": "ASCENDING" + } + ] + }, { "collectionGroup": "gyms", "queryScope": "COLLECTION_GROUP", diff --git a/functions/src/notifications/membershipStatusNotifications.ts b/functions/src/notifications/membershipStatusNotifications.ts index 2ed768f..a26f9eb 100644 --- a/functions/src/notifications/membershipStatusNotifications.ts +++ b/functions/src/notifications/membershipStatusNotifications.ts @@ -4,7 +4,7 @@ import * as admin from "firebase-admin"; const app = getAdmin(); const logger = getLogger(); -const kTrainerRole = 'Trainer'; +const kTrainerRole = "Trainer"; interface MembershipData { id?: string; @@ -439,15 +439,33 @@ async function processExpiredMembership( membershipData: MembershipData ): Promise { try { - await app.firestore().collection("memberships").doc(membershipId).update({ - status: "EXPIRED", - updatedAt: admin.firestore.FieldValue.serverTimestamp(), - }); + const payments = await getPaymentsForMembership(membershipId); + if (payments.length > 0) { + const latestPayment = payments[0]; + const expiryDate = calculateExpiryDate( + latestPayment.dateTimestamp, + membershipData.subscription?.frequency || "monthly" + ); + + await app + .firestore() + .collection("memberships") + .doc(membershipId) + .update({ + expirationDate: admin.firestore.Timestamp.fromDate(expiryDate), + status: "EXPIRED", + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }); + } else { + await app.firestore().collection("memberships").doc(membershipId).update({ + status: "EXPIRED", + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }); + } logger.info(`Marked membership ${membershipId} as EXPIRED`); await sendPlanExpiredNotification(membershipId, membershipData); - await sendTrainerNotifications(membershipId, membershipData, "expired"); } catch (error) { logger.error(`Error processing membership ${membershipId}:`, error); @@ -461,8 +479,25 @@ async function processExpiringMembership( try { logger.info(`Processing expiring membership ${membershipId}`); - await sendPlanExpiringNotification(membershipId, membershipData); + const payments = await getPaymentsForMembership(membershipId); + if (payments.length > 0) { + const latestPayment = payments[0]; + const expiryDate = calculateExpiryDate( + latestPayment.dateTimestamp, + membershipData.subscription?.frequency || "monthly" + ); + await app + .firestore() + .collection("memberships") + .doc(membershipId) + .update({ + expirationDate: admin.firestore.Timestamp.fromDate(expiryDate), + updatedAt: admin.firestore.FieldValue.serverTimestamp(), + }); + } + + await sendPlanExpiringNotification(membershipId, membershipData); await sendTrainerNotifications(membershipId, membershipData, "expiring"); } catch (error) { logger.error( @@ -546,7 +581,6 @@ async function sendTrainerNotifications( try { const trainerName = await getTrainerName(assignment.trainerId); const trainerUserId = await getTrainerUserId(assignment.trainerId); - const notifType = notificationType === "expired" From 209354ec6b33b5b43ad9115fb982dd383cff270d Mon Sep 17 00:00:00 2001 From: Benoy Bose Date: Mon, 18 Aug 2025 19:16:18 +0530 Subject: [PATCH 2/3] UPDATED firebase-functions package --- functions/package-lock.json | 9 +- functions/package.json | 2 +- package-lock.json | 242 ------------------------------------ package.json | 7 -- 4 files changed, 6 insertions(+), 254 deletions(-) delete mode 100644 package-lock.json delete mode 100644 package.json diff --git a/functions/package-lock.json b/functions/package-lock.json index 1d81e0c..1ef4a3f 100644 --- a/functions/package-lock.json +++ b/functions/package-lock.json @@ -15,7 +15,7 @@ "cors": "^2.8.5", "date-fns": "^4.1.0", "firebase-admin": "^12.6.0", - "firebase-functions": "^6.0.1", + "firebase-functions": "^6.4.0", "form-data": "^4.0.1", "functions": "file:", "html-to-text": "^9.0.5", @@ -4897,9 +4897,10 @@ } }, "node_modules/firebase-functions": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-6.3.2.tgz", - "integrity": "sha512-FC3A1/nhqt1ZzxRnj5HZLScQaozAcFSD/vSR8khqSoFNOfxuXgwJS6ZABTB7+v+iMD5z6Mmxw6OfqITUBuI7OQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-6.4.0.tgz", + "integrity": "sha512-Q/LGhJrmJEhT0dbV60J4hCkVSeOM6/r7xJS/ccmkXzTWMjo+UPAYX9zlQmGlEjotstZ0U9GtQSJSgbB2Z+TJDg==", + "license": "MIT", "dependencies": { "@types/cors": "^2.8.5", "@types/express": "^4.17.21", diff --git a/functions/package.json b/functions/package.json index 334660d..099daf5 100644 --- a/functions/package.json +++ b/functions/package.json @@ -22,7 +22,7 @@ "cors": "^2.8.5", "date-fns": "^4.1.0", "firebase-admin": "^12.6.0", - "firebase-functions": "^6.0.1", + "firebase-functions": "^6.4.0", "form-data": "^4.0.1", "functions": "file:", "html-to-text": "^9.0.5", diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index b0bc379..0000000 --- a/package-lock.json +++ /dev/null @@ -1,242 +0,0 @@ -{ - "name": "fitlien-services", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@types/busboy": "^1.5.4", - "@types/nodemailer": "^6.4.17", - "@types/pdfkit": "^0.13.9", - "busboy": "^1.6.0", - "date-fns": "^4.1.0", - "nodemailer": "^7.0.3", - "pdfkit": "^0.17.1" - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", - "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@types/busboy": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.4.tgz", - "integrity": "sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/nodemailer": { - "version": "6.4.17", - "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.17.tgz", - "integrity": "sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/pdfkit": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/@types/pdfkit/-/pdfkit-0.13.9.tgz", - "integrity": "sha512-RDG8Yb1zT7I01FfpwK7nMSA433XWpblMqSCtA5vJlSyavWZb303HUYPCel6JTiDDFqwGLvtAnYbH8N/e0Cb89g==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/brotli": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", - "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", - "dependencies": { - "base64-js": "^1.1.2" - } - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crypto-js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" - }, - "node_modules/date-fns": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", - "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, - "node_modules/dfa": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", - "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fontkit": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz", - "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==", - "dependencies": { - "@swc/helpers": "^0.5.12", - "brotli": "^1.3.2", - "clone": "^2.1.2", - "dfa": "^1.2.0", - "fast-deep-equal": "^3.1.3", - "restructure": "^3.0.0", - "tiny-inflate": "^1.0.3", - "unicode-properties": "^1.4.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/jpeg-exif": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", - "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==" - }, - "node_modules/linebreak": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", - "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", - "dependencies": { - "base64-js": "0.0.8", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/linebreak/node_modules/base64-js": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", - "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/nodemailer": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.3.tgz", - "integrity": "sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" - }, - "node_modules/pdfkit": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.17.1.tgz", - "integrity": "sha512-Kkf1I9no14O/uo593DYph5u3QwiMfby7JsBSErN1WqeyTgCBNJE3K4pXBn3TgkdKUIVu+buSl4bYUNC+8Up4xg==", - "dependencies": { - "crypto-js": "^4.2.0", - "fontkit": "^2.0.4", - "jpeg-exif": "^1.1.4", - "linebreak": "^1.1.0", - "png-js": "^1.0.0" - } - }, - "node_modules/png-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", - "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" - }, - "node_modules/restructure": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz", - "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==" - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/tiny-inflate": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" - }, - "node_modules/unicode-properties": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", - "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", - "dependencies": { - "base64-js": "^1.3.0", - "unicode-trie": "^2.0.0" - } - }, - "node_modules/unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", - "dependencies": { - "pako": "^0.2.5", - "tiny-inflate": "^1.0.0" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index da0eb6c..0000000 --- a/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": { - "@types/busboy": "^1.5.4", - "busboy": "^1.6.0", - "date-fns": "^4.1.0" - } -} From 7259e67833fe976699608aad98b4b8c804de2932 Mon Sep 17 00:00:00 2001 From: Benoy Bose Date: Mon, 18 Aug 2025 19:20:36 +0530 Subject: [PATCH 3/3] REMOVED clean install from project root --- .gitea/workflows/deploy-dev.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitea/workflows/deploy-dev.yaml b/.gitea/workflows/deploy-dev.yaml index cbb62b4..05c02dc 100644 --- a/.gitea/workflows/deploy-dev.yaml +++ b/.gitea/workflows/deploy-dev.yaml @@ -19,9 +19,6 @@ jobs: with: node-version: 22 - - name: Clean install - run: npm clean-install - - name: Copy .env.example to .env run: cp functions/.env.example functions/.env