diff --git a/.gitignore b/.gitignore index dd3f26e42..e3909401d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -congifKey.ts + # Logs @@ -43,3 +43,4 @@ firebase-debug.log firebase-debug.log* ./firestore.indexes.json firestore.rules + diff --git a/firebas.json b/firebas.json deleted file mode 100644 index 970fdcf22..000000000 --- a/firebas.json +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - - - - - - -{ - "firestore": { - "rules": "firestore.rules", - "indexes": "firestore.indexes.json" - }, - "functions": [{ - "runtime": "nodejs20", - "source": "functions", - "codebase": "default", - "ignore": [ - "node_modules", - ".git", - "firebase-debug.log", - "firebase-debug.*.log" - ], - "predeploy": [ - "npm --prefix \"$RESOURCE_DIR\" run build" - ] - }], - "hosting": { - "site": "delib-5", - "public": "dist", - "ignore": [ - "firebase.json", - "**/.*", - "**/node_modules/**" - ], - "rewrites": [{ - "source": "/getRandomStatements2", - "function": { - "functionId": "getRandomStatements2", - "region": "us-central1" - } - }, - { - "source": "**", - "destination": "/index.html" - } - ] - }, - "emulators": { - "auth": { - "port": 9099 - }, - "functions": { - "port": 5001 - }, - "firestore": { - "port": 8080 - }, - "storage": { - "port": 9199 - }, - "ui": { - "enabled": true, - "port": 5002 - }, - "singleProjectMode": true, - "hosting": { - "port": 5000 - } - }, - "storage": { - "rules": "storage.rules" - } - } - diff --git a/firestore.rules b/firestore.rules index 6e311281e..e28a558d0 100644 --- a/firestore.rules +++ b/firestore.rules @@ -81,7 +81,19 @@ service cloud.firestore { allow read: if request.auth.uid != null; allow write: if request.auth.uid != null; } - + match /rooms/{roomId=**}{ + allow read: if request.auth.uid != null; + allow write: if request.auth.uid != null; + } + match /participants/{participantId=**}{ + allow read: if request.auth.uid != null; + allow write: if request.auth.uid != null; + } + match /roomsSettings/{roomSettingsId=**}{ + allow read: if request.auth.uid != null; + allow write: if request.auth.uid != null; + } + match /timers-rooms/{timerIdx=**}{ allow read: if request.auth.uid != null; allow write: if request.auth.uid != null; diff --git a/functions/package-lock.json b/functions/package-lock.json index 6e7b4cbe9..ef729789f 100644 --- a/functions/package-lock.json +++ b/functions/package-lock.json @@ -7,7 +7,7 @@ "name": "functions", "dependencies": { "@google/generative-ai": "^0.15.0", - "delib-npm": "^1.3.33", + "delib-npm": "^1.3.44", "dotenv": "^16.4.5", "firebase-admin": "^11.8.0", "firebase-functions": "^5.1.0", @@ -3288,9 +3288,9 @@ } }, "node_modules/delib-npm": { - "version": "1.3.33", - "resolved": "https://registry.npmjs.org/delib-npm/-/delib-npm-1.3.33.tgz", - "integrity": "sha512-jrj08L+dGy80PGyMymi6rDXWNKcHtOepcdVxdDZv3to/Qc9zp5PSf/C77MXokFq8aiuryqvT9Gpl+gI2/y9Tbg==", + "version": "1.3.44", + "resolved": "https://registry.npmjs.org/delib-npm/-/delib-npm-1.3.44.tgz", + "integrity": "sha512-6/5LMhuJ4lekGRVc4sChA6SRgEOxaXUySdswrkENlBMi1htrL8+6aM9zlX/ExJgjfzpOo8cgpibKKyKpENipOQ==", "dependencies": { "react": "^18.3.1", "sass": "^1.77.6", diff --git a/functions/package.json b/functions/package.json index f8cee3009..b3da16abc 100644 --- a/functions/package.json +++ b/functions/package.json @@ -16,7 +16,7 @@ "main": "lib/index.js", "dependencies": { "@google/generative-ai": "^0.15.0", - "delib-npm": "^1.3.33", + "delib-npm": "^1.3.44", "dotenv": "^16.4.5", "firebase-admin": "^11.8.0", "firebase-functions": "^5.1.0", diff --git a/functions/src/fn_agree.ts b/functions/src/fn_agree.ts index 88bd7ad9b..74bfef5e2 100644 --- a/functions/src/fn_agree.ts +++ b/functions/src/fn_agree.ts @@ -1,7 +1,7 @@ import { AgreeDisagree, AgreeDisagreeEnum, AgreeDocument, Collections } from "delib-npm"; import { logger } from "firebase-functions/v1"; import { db } from "."; -import { getAction } from "./fn_approval"; +import { Action, getAction } from "./fn_approval"; export async function updateAgrees(event: any) { @@ -14,17 +14,17 @@ export async function updateAgrees(event: any) { const action = getAction(event); let results: AgreeDocument = { agree: 0, disagree: 0 }; - if (action === "create") { + if (action === Action.create) { if (!agreeAfterData) throw new Error("No agreement data found"); const { agree } = agreeAfterData; results = getUpdateCreateAgree(combinedAgreement.statementId, agree); - } else if (action === "delete") { + } else if (action === Action.delete) { if (!agreeBeforeData) throw new Error("No agreement data found"); const { agree } = agreeBeforeData; results = getUpdateDeleteAgree(combinedAgreement.statementId, agree); - } else if (action === "update") { + } else if (action === Action.update) { if (!agreeAfterData) throw new Error("No agreement data found"); const { agree: agreeAfter } = agreeAfterData; const { agree: agreeBefore } = agreeBeforeData || { agree: undefined }; @@ -44,7 +44,7 @@ export async function updateAgrees(event: any) { const { agree, disagree } = statement.data()?.documentAgree || { agree: 0, disagree: 0 } as AgreeDocument; const { agree: updateAgree, disagree: updateDisagree } = results; - + const newAgree = agree + updateAgree; const newDisagree = disagree + updateDisagree; @@ -52,7 +52,7 @@ export async function updateAgrees(event: any) { const updateAgrees: AgreeDocument = { agree: newAgree, - disagree:newDisagree, + disagree: newDisagree, avgAgree: totalAgree !== 0 ? (newAgree - newDisagree) / totalAgree : 0, } @@ -90,7 +90,7 @@ function getUpdateDeleteAgree(statementId: string, agree: AgreeDisagreeEnum): Ag function getUpdateUpdateAgree(statementId: string, agreeAfter: AgreeDisagreeEnum, agreeBefore: AgreeDisagreeEnum): AgreeDocument { try { - + const { Agree, Disagree, NoOpinion } = AgreeDisagreeEnum; diff --git a/functions/src/fn_approval.ts b/functions/src/fn_approval.ts index 9e42069e0..6ff0a0e3e 100644 --- a/functions/src/fn_approval.ts +++ b/functions/src/fn_approval.ts @@ -5,101 +5,124 @@ import { db } from "."; export async function updateApprovalResults(event: any) { try { - const action = getAction(event); + const action: Action = getAction(event); const eventData = event.data.after.data() as Approval || event.data.before.data() as Approval; const { statementId, documentId, userId } = eventData; const approveAfterData = event.data.after.data() as Approval; const approveBeforeData = event.data.before.data() as Approval; - + let approvedDiff = 0; let approvingUserDiff = 0; - if (action === "create") { - // await newApproval(eventData); + if (action === Action.create) { + const { approval } = approveAfterData; approvingUserDiff = 1; approvedDiff = approval ? 1 : 0; - } else if (action === "delete") { + } else if (action === Action.delete) { const { approval } = approveBeforeData; approvingUserDiff = -1; approvedDiff = approval ? -1 : 0; - } else if (action === "update") { - const { approval } = approveAfterData; - approvedDiff = approval ? 1 : -1; + } else if (action === Action.update) { + const { approval: approvalAfter } = approveAfterData; + const { approval: approvalBefore } = approveBeforeData; + approvedDiff = (() => { + if (approvalAfter && !approvalBefore) { + return 1; + } else if (approvalBefore && !approvalAfter) { + return -1; + } + return 0; + + })() } - //update paragraph db.runTransaction(async (transaction) => { - const statementRef = db.collection(Collections.statements).doc(statementId); - const statementDB = await transaction.get(statementRef); - const { documentApproval } = statementDB.data() as Statement; + try { + const statementRef = db.collection(Collections.statements).doc(statementId); + const statementDB = await transaction.get(statementRef); + const { documentApproval } = statementDB.data() as Statement; + + - let newApprovalResults: DocumentApproval = { - approved: approvedDiff, - totalVoters: approvingUserDiff, - averageApproval: approvedDiff - }; + if (!documentApproval) { + const newApprovalResults = { + approved: approvedDiff, + totalVoters: approvingUserDiff, + averageApproval: approvingUserDiff !== 0 ? approvedDiff / approvingUserDiff : 0 + }; + + transaction.set(statementRef, { documentApproval: newApprovalResults }, { merge: true }); + return; + } - if (documentApproval) { const newApproved = documentApproval.approved + approvedDiff; - const totalVoters = documentApproval.totalVoters + approvingUserDiff; + const totalVoters = documentApproval.totalVoters + approvingUserDiff; - newApprovalResults = { + const newApprovalResults = { approved: newApproved, totalVoters, - averageApproval: newApproved / totalVoters + averageApproval: totalVoters !== 0 ? newApproved / totalVoters:0 }; - } else { - + + transaction.set(statementRef, { documentApproval: newApprovalResults }, { merge: true }); + return; + } catch (error) { + logger.error(error); + return; } - transaction.set(statementRef, { documentApproval: newApprovalResults }, { merge: true }); }); //update document db.runTransaction(async (transaction) => { - const statementRef = db.collection(Collections.statements).doc(documentId); - const statementDB = await transaction.get(statementRef); - const { documentApproval } = statementDB.data() as Statement; + try { + const statementRef = db.collection(Collections.statements).doc(documentId); + const statementDB = await transaction.get(statementRef); + const { documentApproval } = statementDB.data() as Statement; + + const userApprovalsDB = await db.collection(Collections.approval).where("documentId", "==", documentId).where("userId", "==", userId).get(); + const numberOfUserApprovals = userApprovalsDB.size; + const addUser = (numberOfUserApprovals === 1 && action === "create") ? 1 : 0; + + /** + * Represents the results of a document approval. + */ + let newApprovalResults: DocumentApproval = { + approved: approvedDiff, + totalVoters: addUser, + averageApproval: approvedDiff + }; - const userApprovalsDB = await db.collection(Collections.approval).where("documentId", "==", documentId).where("userId", "==", userId).get(); - const numberOfUserApprovals = userApprovalsDB.size; - const addUser = (numberOfUserApprovals === 1 && action === "create") ? 1 : 0; - /** - * Represents the results of a document approval. - */ - let newApprovalResults: DocumentApproval = { - approved: approvedDiff, - totalVoters: addUser, - averageApproval: approvedDiff - }; + if (documentApproval) { + const newApproved = documentApproval.approved + approvedDiff; + const newTotalVoters = documentApproval.totalVoters + addUser; - if (documentApproval) { - const newApproved = documentApproval.approved + approvedDiff; - const newTotalVoters = documentApproval.totalVoters + addUser; + newApprovalResults = { + approved: newApproved, + totalVoters: newTotalVoters, + averageApproval: newTotalVoters !== 0 ?newApproved / newTotalVoters:0 + }; + } - - newApprovalResults = { - approved: newApproved, - totalVoters: newTotalVoters, - averageApproval: newApproved / newTotalVoters - }; + transaction.update(statementRef, { documentApproval: newApprovalResults }); + return; + } catch (error) { + logger.error(error); } - - transaction.update(statementRef, { documentApproval: newApprovalResults }); }); @@ -108,16 +131,24 @@ export async function updateApprovalResults(event: any) { } } -export function getAction(event: any): "create" | "delete" | "update" { + +export enum Action { + create = "create", + delete = "delete", + update = "update", +} + + +export function getAction(event: any): Action { if (event.data.after.data() && event.data.before.data()) { - return "update"; + return Action.update; } else if (event.data.after.data() && event.data.before.data() === undefined) { - return "create"; + return Action.create; } else if (event.data.after.data() === undefined && event.data.before.data()) { - return "delete"; + return Action.delete; } - return "update"; + return Action.update; } diff --git a/functions/src/fn_rooms.ts b/functions/src/fn_rooms.ts deleted file mode 100644 index 238acf055..000000000 --- a/functions/src/fn_rooms.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Collections, Participant } from "delib-npm"; -import { logger } from "firebase-functions/v1"; -import { db } from "./index"; -import { FieldValue } from "firebase-admin/firestore"; - -//count room joiners -export async function countRoomJoiners(ev: any) { - try { - //on change of room joiners, update the room with the new count - //get the room id - const previouseRequest = ev.data.before.data() as Participant; - const newRequest = ev.data.after.data() as Participant; - - if (previouseRequest === undefined) - return; - if (newRequest === undefined) - throw new Error("New Request is undefined"); - - if (!newRequest.statementId || !previouseRequest.statementId) - return; - - //if new request - if (previouseRequest === undefined) { - //get the room - const lobbyRoomRef = db - .collection(Collections.statementLobbyRooms) - .doc(newRequest.statementId); - - //update the room with the new count - const lobbyRoom = await lobbyRoomRef.get(); - if (lobbyRoom.exists) { - return lobbyRoomRef.update({ - joinersCount: FieldValue.increment(1), - }); - } else { - return lobbyRoomRef.set({ - joinersCount: 1, - parentId: newRequest.parentId, - statementId: newRequest.statementId, - }); - } - } else if (newRequest === undefined) { - logger.info("request deleted"); - const previousLoobyRoomRef = db - .collection(Collections.statementLobbyRooms) - .doc(previouseRequest.statementId); - await previousLoobyRoomRef.update({ - joinersCount: FieldValue.increment(-1), - }); - } else { - //if request uppdated - - const newLobbyRoomRef = db - .collection(Collections.statementLobbyRooms) - .doc(newRequest.statementId); - const previousLoobyRoomRef = db - .collection(Collections.statementLobbyRooms) - .doc(previouseRequest.statementId); - - //update the room with the new count - - const newLobbyRoom = await newLobbyRoomRef.get(); - const previousLoobyRoom = await previousLoobyRoomRef.get(); - - await updateNewRoom( - newLobbyRoom, - newLobbyRoomRef, - newRequest.parentId, - newRequest.statementId, - ); - - await updatePreviuosRoom( - previousLoobyRoom, - previousLoobyRoomRef, - previouseRequest.parentId, - previouseRequest.statementId, - ); - } - } catch (error) { - logger.error(error); - } - - async function updatePreviuosRoom( - previousLoobyRoom: any, - previousLoobyRoomRef: any, - parentId: string, - statementId: string | undefined, - ) { - try { - if (previousLoobyRoom.exists) { - await previousLoobyRoomRef.update({ - joinersCount: FieldValue.increment(-1), - }); - } else { - await previousLoobyRoomRef.set({ - joinersCount: 0, - parentId, - statementId, - }); - } - } catch (error) { - logger.error(error); - } - } - - async function updateNewRoom( - newLobbyRoom: any, - newLobbyRoomRef: any, - parentId: string, - statementId: string | undefined, - ) { - try { - if (newLobbyRoom.exists) { - await newLobbyRoomRef.update({ - joinersCount: FieldValue.increment(1), - }); - } else { - await newLobbyRoomRef.set({ - joinersCount: 1, - parentId, - statementId, - }); - } - } catch (error) { - logger.error(error); - } - } - - return; -} diff --git a/functions/src/fn_signatures.ts b/functions/src/fn_signatures.ts index f806d83ae..c9e3260f1 100644 --- a/functions/src/fn_signatures.ts +++ b/functions/src/fn_signatures.ts @@ -1,48 +1,8 @@ -import { FieldValue } from "firebase-admin/firestore"; import { db } from "./index"; import { logger } from "firebase-functions/v1"; import { getAction } from "./fn_approval"; import { Collections, DocumentSigns, Signature } from "delib-npm"; -export enum SignatureStatus { - signed = "signed", - unsigned = "unsigned", - rejected = "rejected", -} - -export async function addSignature(event: any) { - try { - const signature = event.data.data(); - if (!signature) throw new Error("signature is not defined"); - if (signature.statementId === undefined) - throw new Error("statementId is not defined"); - - const statementRef = db - .collection("statements") - .doc(signature.statementId); - await statementRef.update({ signaturesCount: FieldValue.increment(1) }); - } catch (error) { - logger.error(error); - } -} - -export async function removeSignature(event: any) { - try { - const signature = event.data.data(); - if (!signature) throw new Error("signature is not defined"); - if (signature.statementId === undefined) - throw new Error("statementId is not defined"); - - const statementRef = db - .collection("statements") - .doc(signature.statementId); - await statementRef.update({ - signaturesCount: FieldValue.increment(-1), - }); - } catch (error) { - logger.error(error); - } -} //functions for FreeDi Sign @@ -85,12 +45,14 @@ async function onCreateSignature(signature: Signature) { const documentSignatureDB = await transaction.get(documentSignatureRef); if (!documentSignatureDB.exists) { + //in case the document signature do not exists yet const documentSignature: DocumentSigns = { - documentId, viewed: 1, + documentId, + viewed: 1, signed: signed ? 1 : 0, rejected: signed ? 0 : 1, avgSignatures: signed ? levelOfSignature : 0, - totalSignaturesLevel:signed ? levelOfSignature : 0 + totalSignaturesLevel: signed ? levelOfSignature : 0 }; transaction.set(documentSignatureRef, documentSignature); } else { @@ -99,7 +61,7 @@ async function onCreateSignature(signature: Signature) { documentSignature.signed += signed ? 1 : 0; documentSignature.rejected += signed ? 0 : 1; documentSignature.totalSignaturesLevel += signed ? levelOfSignature : 0; - documentSignature.avgSignatures = documentSignature.totalSignaturesLevel/documentSignature.viewed; + documentSignature.avgSignatures = documentSignature.totalSignaturesLevel / documentSignature.viewed; transaction.update(documentSignatureRef, documentSignature); } @@ -125,7 +87,7 @@ async function onDeleteSignature(signature: Signature) { documentSignature.signed -= signed ? 1 : 0; documentSignature.rejected -= signed ? 0 : 1; documentSignature.totalSignaturesLevel -= signed ? levelOfSignature : 0; - documentSignature.avgSignatures = documentSignature.totalSignaturesLevel/documentSignature.viewed; + documentSignature.avgSignatures = documentSignature.totalSignaturesLevel / documentSignature.viewed; transaction.update(documentSignatureRef, documentSignature); } }); @@ -137,9 +99,13 @@ async function onDeleteSignature(signature: Signature) { async function onUpdateSignature(signatureBeforeData: Signature, signatureAfterData: Signature) { try { - const { levelOfSignature: levelOfSignatureBefore } = signatureBeforeData; - const { documentId, signed, levelOfSignature: levelOfSignatureAfter } = signatureAfterData; - + const { signed: signedBefore, levelOfSignature: levelOfSignatureBefore } = signatureBeforeData; + const { documentId, signed: signedAfter, levelOfSignature: levelOfSignatureAfter } = signatureAfterData; + + const diffSigned = (signedAfter ? 1 : 0) - (signedBefore ? 1 : 0); + const diffRejected = (signedAfter ? 0 : 1) - (signedBefore ? 0 : 1); + const diffSignatureLevel = levelOfSignatureAfter - levelOfSignatureBefore; + await db.runTransaction(async (transaction) => { @@ -147,24 +113,15 @@ async function onUpdateSignature(signatureBeforeData: Signature, signatureAfterD .doc(documentId) const documentSignatureDB = await transaction.get(documentSignatureRef); - if (documentSignatureDB.exists) { - const documentSignature = documentSignatureDB.data() as DocumentSigns; - documentSignature.signed += signed ? 1 : -1; - documentSignature.rejected += signed ? -1 : 1; - documentSignature.totalSignaturesLevel += signed ? levelOfSignatureAfter : -levelOfSignatureBefore; - documentSignature.avgSignatures = documentSignature.totalSignaturesLevel/documentSignature.viewed; - transaction.update(documentSignatureRef, documentSignature); - } else { + if (!documentSignatureDB.exists) throw new Error("Document signature not found"); + + const documentSignature = documentSignatureDB.data() as DocumentSigns; + documentSignature.signed += diffSigned; + documentSignature.rejected += diffRejected; + documentSignature.totalSignaturesLevel += diffSignatureLevel; + documentSignature.avgSignatures = documentSignature.totalSignaturesLevel / documentSignature.viewed; + transaction.update(documentSignatureRef, documentSignature); - const documentSignature: DocumentSigns = { - documentId, viewed: 1, - signed: signed ? 1 : 0, - rejected: signed ? 0 : 1, - avgSignatures: signed ? levelOfSignatureAfter : 0, - totalSignaturesLevel:signed ? levelOfSignatureAfter : 0 - }; - transaction.set(documentSignatureRef, documentSignature); - } }); } catch (error) { diff --git a/functions/src/index.ts b/functions/src/index.ts index 4d752bacc..d181b08e0 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -5,8 +5,7 @@ import { updateEvaluation, } from './fn_evaluation'; import { updateResultsSettings } from './fn_results'; -import { countRoomJoiners } from './fn_rooms'; -import { addSignature, removeSignature, updateDocumentSignatures } from './fn_signatures'; +import { updateDocumentSignatures } from './fn_signatures'; import { updateParentWithNewMessageCB, @@ -101,21 +100,9 @@ exports.addVote = onDocumentWritten('/votes/{voteId}', updateVote); // exports.removeVote = onDocumentDeleted('/votes/{voteId}', removeVote); -//signatures (part of delib-signatures) -exports.changeSignature = onDocumentCreated( - '/statementsSignatures/{signatureId}', - addSignature -); -exports.deleteSignature = onDocumentDeleted( - '/statementsSignatures/{signatureId}', - removeSignature -); -//rooms -exports.countRoomJoiners = onDocumentWritten( - `${Collections.statementRoomsAsked}/{requestId}`, - countRoomJoiners -); + + //timers exports.cleanTimers = onSchedule('every day 00:00', cleanOldTimers); diff --git a/index.html b/index.html index 2bbf1d33d..e62f82d9f 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@
- +