From 72fb934d4f07c2254ae3980c2d07507636c6d9bd Mon Sep 17 00:00:00 2001 From: Tiago Ribeiro Date: Tue, 7 May 2024 23:53:15 +0100 Subject: [PATCH] Updated the propagated changes to also affect expiry date changes for corporates --- src/pages/api/users/update.ts | 7 +- src/utils/propagate.user.changes.ts | 188 ++++++++++++++++------------ 2 files changed, 115 insertions(+), 80 deletions(-) diff --git a/src/pages/api/users/update.ts b/src/pages/api/users/update.ts index 3a79045f..bbd1b75c 100644 --- a/src/pages/api/users/update.ts +++ b/src/pages/api/users/update.ts @@ -12,7 +12,7 @@ import moment from "moment"; import ShortUniqueId from "short-unique-id"; import {Payment} from "@/interfaces/paypal"; import {toFixedNumber} from "@/utils/number"; -import {propagateStatusChange} from "@/utils/propagate.user.changes"; +import {propagateExpiryDateChanges, propagateStatusChange} from "@/utils/propagate.user.changes"; const db = getFirestore(app); const auth = getAuth(app); @@ -79,15 +79,18 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { const queryId = req.query.id as string; const userRef = doc(db, "users", queryId ? (queryId as string) : req.session.user.id); + const userSnapshot = await getDoc(userRef); const updatedUser = req.body as User & {password?: string; newPassword?: string}; if (!!queryId) { - const user = await setDoc(userRef, updatedUser, {merge: true}); + await setDoc(userRef, updatedUser, {merge: true}); await managePaymentRecords(updatedUser, updatedUser.id); + const user = {...userSnapshot.data(), id: userSnapshot.id} as User; if (updatedUser.status || updatedUser.type === "corporate") { // there's no await as this does not affect the user propagateStatusChange(queryId, updatedUser.status); + propagateExpiryDateChanges(queryId, user.subscriptionExpirationDate || null, updatedUser.subscriptionExpirationDate || null); } res.status(200).json({ok: true}); diff --git a/src/utils/propagate.user.changes.ts b/src/utils/propagate.user.changes.ts index d168c178..48e896bf 100644 --- a/src/utils/propagate.user.changes.ts +++ b/src/utils/propagate.user.changes.ts @@ -1,92 +1,124 @@ // updating specific user changes other users // for example, updating the status of a corporate user should update the status of all users in the same corporate group -import { UserStatus, User } from "../interfaces/user"; -import { - getFirestore, - collection, - getDocs, - getDoc, - doc, - setDoc, - query, - where, -} from "firebase/firestore"; -import { app } from "@/firebase"; +import {UserStatus, User} from "../interfaces/user"; +import {getFirestore, collection, getDocs, getDoc, doc, setDoc, query, where} from "firebase/firestore"; +import {app} from "@/firebase"; const db = getFirestore(app); export const propagateStatusChange = (userId: string, status: UserStatus) => - new Promise((resolve, reject) => { - getDoc(doc(db, "users", userId)) - .then((docUser) => { - const user = docUser.data() as User; + new Promise((resolve, reject) => { + getDoc(doc(db, "users", userId)) + .then((docUser) => { + const user = docUser.data() as User; - // only update the status of the user's groups if the user is a corporate user - if (user.type === "corporate") { - getDocs( - query(collection(db, "groups"), where("admin", "==", userId)) - ).then(async (userGroupsRef) => { - const userGroups = userGroupsRef.docs.map((x) => x.data()); + // only update the status of the user's groups if the user is a corporate user + if (user.type === "corporate") { + getDocs(query(collection(db, "groups"), where("admin", "==", userId))).then(async (userGroupsRef) => { + const userGroups = userGroupsRef.docs.map((x) => x.data()); - const targetUsers = [ - ...new Set( - userGroups.flatMap((g) => g.participants).filter((u) => u) - ), - ]; + const targetUsers = [...new Set(userGroups.flatMap((g) => g.participants).filter((u) => u))]; - Promise.all( - targetUsers.map(async (targetUserId) => { - const ref = await getDoc(doc(db, "users", targetUserId)); + Promise.all( + targetUsers.map(async (targetUserId) => { + const ref = await getDoc(doc(db, "users", targetUserId)); - if (!ref.exists()) return null; + if (!ref.exists()) return null; - const data = ref.data() as User; - return { ...data, id: targetUserId }; - }) - ) - .then((data) => { - const filtered = data.filter((x) => { - if (x === null) return false; - if (x.status === status) return false; - if (x.type !== "student") return false; - return true; - }) as User[]; + const data = ref.data() as User; + return {...data, id: targetUserId}; + }), + ) + .then((data) => { + const filtered = data.filter((x) => { + if (x === null) return false; + if (x.status === status) return false; + return true; + }) as User[]; - if (filtered.length === 0) { - return; - } + if (filtered.length === 0) { + return; + } - Promise.all( - filtered.map((user: User) => - setDoc( - doc(db, "users", user.id), - { status }, - { merge: true } - ) - ) - ) - .then(() => { - resolve(true); - }) - .catch((err) => { - console.error(err); - reject(err); - }); - }) - .catch((err) => { - console.error(err); - reject(err); - }); - }); - return; - } + Promise.all(filtered.map((user: User) => setDoc(doc(db, "users", user.id), {status}, {merge: true}))) + .then(() => { + resolve(true); + }) + .catch((err) => { + console.error(err); + reject(err); + }); + }) + .catch((err) => { + console.error(err); + reject(err); + }); + }); + return; + } - const error = new Error("User is not a corporate user"); - console.error(error); - reject(error); - }) - .catch((err) => { - console.error(err); - reject(err); - }); - }); + const error = new Error("User is not a corporate user"); + console.error(error); + reject(error); + }) + .catch((err) => { + console.error(err); + reject(err); + }); + }); + +export const propagateExpiryDateChanges = (userId: string, initialExpiryDate: Date | null, subscriptionExpirationDate: Date | null) => + new Promise((resolve, reject) => { + getDoc(doc(db, "users", userId)) + .then((docUser) => { + const user = docUser.data() as User; + + // only update the status of the user's groups if the user is a corporate user + if (user.type === "corporate") { + getDocs(query(collection(db, "groups"), where("admin", "==", userId))).then(async (userGroupsRef) => { + const userGroups = userGroupsRef.docs.map((x) => x.data()); + + const targetUsers = [...new Set(userGroups.flatMap((g) => g.participants).filter((u) => u))]; + + Promise.all( + targetUsers.map(async (targetUserId) => { + const ref = await getDoc(doc(db, "users", targetUserId)); + + if (!ref.exists()) return null; + + const data = ref.data() as User; + return {...data, id: ref.id}; + }), + ) + .then(async (data) => { + const filtered = data.filter((x) => { + if (x === null) return false; + if (x.subscriptionExpirationDate !== initialExpiryDate) return false; + return true; + }) as User[]; + + if (filtered.length === 0) return; + + for (const user of filtered) { + await setDoc(doc(db, "users", user.id), {subscriptionExpirationDate}, {merge: true}); + } + + resolve(true); + }) + .catch((err) => { + console.error(err); + reject(err); + }); + }); + return; + } + + const error = new Error("User is not a corporate user"); + console.error(error); + reject(error); + }) + .catch((err) => { + console.error(err); + reject(err); + }); + });