Skip to content

feat(functions): add request validation using zod#522

Open
snehamathad604 wants to merge 6 commits into
roshankumar0036singh:mainfrom
snehamathad604:feature/request-validation-middleware
Open

feat(functions): add request validation using zod#522
snehamathad604 wants to merge 6 commits into
roshankumar0036singh:mainfrom
snehamathad604:feature/request-validation-middleware

Conversation

@snehamathad604
Copy link
Copy Markdown
Contributor

@snehamathad604 snehamathad604 commented Jun 2, 2026

Description

Adds request validation for Firebase callable Cloud Functions using Zod.

This PR introduces a reusable validation utility and centralized schemas to validate incoming request payloads before processing. Invalid requests now return structured HttpsError responses with validation details, helping the frontend provide clearer error messages to users.

Changes Made

  • Added Zod as a validation dependency
  • Created src/validation/validate.ts for reusable schema validation
  • Created src/validation/schemas.ts for centralized request schemas
  • Added request validation to:
    • setRole
    • getTopContributors
  • Returns structured validation errors using functions.https.HttpsError

Fixes #330

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

  • Successfully installed and configured Zod
  • TypeScript compilation passes with npm run build

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • My changes generate no new warnings
  • New and existing code compiles locally with my changes

Summary by CodeRabbit

  • New Features

    • Added input validation for callable functions and an exported reputation scoring helper.
    • Added Jest tests and a test script.
  • Improvements

    • Refined certificate generation and delivery to be idempotent and more robust.
    • Strengthened reputation and contributor request handling and pagination.
    • Improved scheduled reminder logging.
  • Removals

    • Removed daily digest and scheduled event-notification handlers.
  • Chores

    • Updated build/tooling and added a validation library.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Babel/Jest/TS tooling, Zod-based request validation and schemas, extracts reputation scoring into an exported helper with tests, replaces inline setRole validation with schema validation, refactors certificate generation/email/storage into an idempotent pipeline, updates small imports/ignores, and removes compiled source-map footers.

Changes

Cloud Functions Build, Validation, and Refactoring

Layer / File(s) Summary
Build and test configuration setup
cloud-functions/babel.config.js, cloud-functions/jest.config.js, cloud-functions/tsconfig.json, cloud-functions/package.json
Babel presets for Node/TS, Jest setup for .ts, trimmed TS options, adds test script and Zod/Jest/Babel/TS dev deps.
Request validation framework and schemas
cloud-functions/src/validation/validate.ts, cloud-functions/src/validation/schemas.ts
Adds validateSchema that runs Zod safeParse and throws functions.https.HttpsError('invalid-argument') on failure; introduces setRoleSchema and getTopContributorsSchema.
Reputation helper, guarded init, and tests
cloud-functions/src/reputation.ts, cloud-functions/src/reputation.test.ts
Guards Firebase Admin init, exports calculatePoints, uses it in reputation updates, validates getTopContributors payload with schema, and adds Jest tests for weighted-point cases.
SetRole input validation
cloud-functions/src/setRole.ts
Replaces manual payload checks with validateSchema(setRoleSchema, data) while preserving auth and claims update behavior.
Certificate generation and email pipeline refactoring
cloud-functions/lib/certificateService.js, cloud-functions/src/certificateService.ts
Initializes Resend once, consolidates PDF generation/upload, signed-URL creation, Firestore persistence, idempotent per-participant handling (attach vs link email), structured per-participant outcomes, fetches participants directly from events/${eventId}/participants, and only marks event flags when all succeed; return shape is { total, results }.
DailyDigest import & misc ignores
cloud-functions/src/dailyDigest.ts, cloud-functions/.gitignore
Switches expo-server-sdk import to { Expo } and adds lib/ to .gitignore.
Source map cleanup and compiled file tweaks
cloud-functions/lib/analyzeAttendance.js, cloud-functions/lib/lib/participants.js, cloud-functions/lib/onEventCreate.js, cloud-functions/lib/reminders.js, cloud-functions/lib/server.js
Removes trailing //# sourceMappingURL=... comments from compiled outputs and adds small log improvements (e.g., reminders processed).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

level:intermediate, type:refactor, quality:clean

Suggested reviewers

  • roshankumar0036singh

Poem

I hopped through code with jittery feet,
Zod gates lined the validation street.
Points now measured neat and clear,
Certificates mailed with a cheerful cheer.
Tests pass — nibble your carrot, dear. 🐇✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several changes appear unrelated to request validation: removing dailyDigest.ts and eventNotifications.js, refactoring certificateService with idempotent participant processing, removing source map comments across multiple files, and updating TypeScript config are beyond the validation middleware scope. Isolate validation-specific changes into a focused PR. Move unrelated refactoring (certificateService, dailyDigest removal, eventNotifications removal) and build configuration updates to separate PRs to maintain clear change scope.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(functions): add request validation using zod' directly matches the main change of the PR, which introduces Zod-based request validation for Cloud Functions.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #330: Zod schemas defined in schemas.ts [#330], validation utility created in validate.ts [#330], schemas applied to setRole and getTopContributors [#330], and HttpsError responses with validation details [#330].

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (3)
cloud-functions/src/reputation.test.ts (2)

1-27: 💤 Low value

These two tests don't exercise production code.

Both blocks recompute the scoring formula inline and assert the result against that same locally-computed expression, so they pass regardless of what calculatePoints actually does. The meaningful coverage is in the calculatePoints suite below (Lines 31-43); these duplicates can be dropped.

♻️ Proposed removal
-describe("calculateReputation logic", () => {
-  test("calculates reputation points correctly", () => {
-    const attendanceCount = 2;
-    const registrationCount = 3;
-    const remindersSet = 1;
-
-    const points =
-      attendanceCount * 10 +
-      registrationCount * 2 +
-      remindersSet;
-
-    expect(points).toBe(27);
-  });
-});
-
-test("calculates zero points correctly", () => {
-  const attendanceCount = 0;
-  const registrationCount = 0;
-  const remindersSet = 0;
-
-  const points =
-    attendanceCount * 10 +
-    registrationCount * 2 +
-    remindersSet;
-
-  expect(points).toBe(0);
-});
-
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cloud-functions/src/reputation.test.ts` around lines 1 - 27, The two
top-level tests in reputation.test.ts are redundant because they compute the
scoring formula inline instead of calling the production function; remove the
duplicate test blocks (the describe("calculateReputation logic" suite and the
following standalone test) and ensure tests call the real function
calculatePoints (used in the existing calculatePoints suite) so coverage
exercises production code rather than re-implementing the formula locally.

29-29: 💤 Low value

Move the import to the top and use ESM import.

A mid-file require("./reputation") is unusual in a .ts test and also triggers the module's top-level admin.initializeApp() / admin.firestore() at load time. Hoisting it as a top-level import { calculatePoints } from "./reputation"; keeps load behavior predictable and consistent with the rest of the suite.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cloud-functions/src/reputation.test.ts` at line 29, Replace the mid-file
CommonJS require with a top-level ESM import to avoid triggering reputation
module side-effects unpredictably: remove the in-function/near-line
require("./reputation") and add a top-level statement import { calculatePoints }
from "./reputation"; at the top of the test file so the reputation module (and
its admin.initializeApp()/admin.firestore() calls) is loaded consistently with
the rest of the suite.
cloud-functions/tsconfig.json (1)

2-10: ⚡ Quick win

Restore the dropped TypeScript safety checks.

This config keeps strict, but it no longer enforces noImplicitReturns and noUnusedLocals, so missing return paths and dead validation branches can now pass npm run build. Please re-enable equivalent checks here or confirm they moved to another enforced CI step.

Suggested config change
   "compilerOptions": {
     "module": "commonjs",
     "target": "es2017",
     "outDir": "lib",
     "rootDir": "src",
     "strict": true,
+    "noImplicitReturns": true,
+    "noUnusedLocals": true,
     "esModuleInterop": true,
     "skipLibCheck": true
   },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cloud-functions/tsconfig.json` around lines 2 - 10, The tsconfig
compilerOptions dropped important safety flags; re-enable noImplicitReturns and
noUnusedLocals under compilerOptions (alongside existing strict/esModuleInterop)
so TypeScript will catch missing return paths and dead/unused local variables
during local builds; update the tsconfig.json "compilerOptions" block to include
"noImplicitReturns": true and "noUnusedLocals": true (or confirm and document
that an equivalent CI TypeScript/tsc step enforces them if you intentionally
moved enforcement).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cloud-functions/lib/certificateService.js`:
- Around line 211-228: The logs in the upload/send flow currently print raw
participant.email (seen in the console.error and console.log calls around the
send/upload block), which exposes PII; change those log statements to avoid raw
emails by logging participant.id or a deterministic redacted/hash of the email
(e.g., a hashEmail(participant.email) or redactEmail(participant.email))
instead, and update the error return object to omit the raw email (use the id or
hashed value for the email field) so getErrorMessage, signedUrl and returned
status remain but no raw email is written to logs or returned.
- Around line 109-123: The code currently creates a nearly permanent signed URL
in uploadPdfAndGetUrl and persists it in persistCertificateUrl; instead, stop
generating long-lived signed URLs and persist the storage object path (e.g.,
storagePath or file.name) and a issued timestamp. Update uploadPdfAndGetUrl to
only save the PDF and return its object path (not a signed URL), and change
persistCertificateUrl to store certificateObjectPath (or storagePath) and
certificateIssuedAt; when you need to send or download a PDF, generate a
short-lived signed URL on demand (use file.getSignedUrl with a short expires)
rather than saving one permanently.

In `@cloud-functions/lib/dailyDigest.js`:
- Around line 42-43: The compiled import uses a default export which breaks
runtime; change the import in dailyDigest.ts to use the named Expo export
(import { Expo } from 'expo-server-sdk';), keep the existing instantiation const
expo = new Expo(); and calls like Expo.isExpoPushToken(pushToken), then rebuild
the project so the generated lib/dailyDigest.js reflects the named-export shape
and restores the static isExpoPushToken method.

In `@cloud-functions/lib/eventNotifications.js`:
- Around line 78-120: sendPushNotifications currently throws on any chunk-level
ticket error which causes checkUpcomingEvents to retry the whole event and
resend already-delivered messages; instead make delivery idempotent by handling
errors per-ticket and persisting per-recipient or per-chunk success before
committing the event as notified. Update sendPushNotifications to return
detailed results (accepted indices, rejected tokens/reasons) instead of
throwing; in checkUpcomingEvents call sendPushNotifications and: 1) for accepted
tickets, immediately persist a per-recipient delivery mark (or update a
per-event deliveredTokens list) so retries skip them, 2) for unrecoverable token
errors remove or flag those tokens, and 3) only set eventDoc.ref.notified10Min
when all recipients are either marked delivered or permanently invalid;
reference functions/sendPushNotifications, checkUpcomingEvents,
buildMessagesForEvent and the notified10Min field to locate where to add
per-recipient persistence and change the control flow to avoid full-event
retries on partial success.

In `@cloud-functions/src/validation/schemas.ts`:
- Around line 3-13: The current z.object schemas (setRoleSchema and
getTopContributorsSchema) silently allow unknown fields; update both definitions
to use Zod's strict mode by appending .strict() to each z.object(...) so unknown
payload fields are rejected (e.g., setRoleSchema = z.object({...}).strict() and
getTopContributorsSchema = z.object({...}).strict()).

---

Nitpick comments:
In `@cloud-functions/src/reputation.test.ts`:
- Around line 1-27: The two top-level tests in reputation.test.ts are redundant
because they compute the scoring formula inline instead of calling the
production function; remove the duplicate test blocks (the
describe("calculateReputation logic" suite and the following standalone test)
and ensure tests call the real function calculatePoints (used in the existing
calculatePoints suite) so coverage exercises production code rather than
re-implementing the formula locally.
- Line 29: Replace the mid-file CommonJS require with a top-level ESM import to
avoid triggering reputation module side-effects unpredictably: remove the
in-function/near-line require("./reputation") and add a top-level statement
import { calculatePoints } from "./reputation"; at the top of the test file so
the reputation module (and its admin.initializeApp()/admin.firestore() calls) is
loaded consistently with the rest of the suite.

In `@cloud-functions/tsconfig.json`:
- Around line 2-10: The tsconfig compilerOptions dropped important safety flags;
re-enable noImplicitReturns and noUnusedLocals under compilerOptions (alongside
existing strict/esModuleInterop) so TypeScript will catch missing return paths
and dead/unused local variables during local builds; update the tsconfig.json
"compilerOptions" block to include "noImplicitReturns": true and
"noUnusedLocals": true (or confirm and document that an equivalent CI
TypeScript/tsc step enforces them if you intentionally moved enforcement).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cd2e6958-0ead-4667-bf86-b594018d680a

📥 Commits

Reviewing files that changed from the base of the PR and between 3110e76 and aa6f4a7.

⛔ Files ignored due to path filters (1)
  • cloud-functions/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (22)
  • cloud-functions/babel.config.js
  • cloud-functions/jest.config.js
  • cloud-functions/lib/analyzeAttendance.js
  • cloud-functions/lib/certificateService.js
  • cloud-functions/lib/dailyDigest.js
  • cloud-functions/lib/eventNotifications.js
  • cloud-functions/lib/index.js
  • cloud-functions/lib/lib/participants.js
  • cloud-functions/lib/onEventCreate.js
  • cloud-functions/lib/reminders.js
  • cloud-functions/lib/reputation.js
  • cloud-functions/lib/server.js
  • cloud-functions/lib/setRole.js
  • cloud-functions/lib/utils/distance.js
  • cloud-functions/lib/utils/fraudScore.js
  • cloud-functions/package.json
  • cloud-functions/src/reputation.test.ts
  • cloud-functions/src/reputation.ts
  • cloud-functions/src/setRole.ts
  • cloud-functions/src/validation/schemas.ts
  • cloud-functions/src/validation/validate.ts
  • cloud-functions/tsconfig.json
💤 Files with no reviewable changes (7)
  • cloud-functions/lib/utils/distance.js
  • cloud-functions/lib/lib/participants.js
  • cloud-functions/lib/reminders.js
  • cloud-functions/lib/onEventCreate.js
  • cloud-functions/lib/utils/fraudScore.js
  • cloud-functions/lib/server.js
  • cloud-functions/lib/analyzeAttendance.js

Comment thread cloud-functions/lib/certificateService.js Outdated
Comment thread cloud-functions/lib/certificateService.js Outdated
Comment thread cloud-functions/lib/dailyDigest.js Outdated
Comment thread cloud-functions/lib/eventNotifications.js Outdated
Comment on lines +3 to +13
export const setRoleSchema = z.object({
uid: z.string().min(1, "uid is required"),
role: z.enum(["admin", "club", "student"]),
});

export const getTopContributorsSchema = z.object({
limit: z.number().int().min(1).max(25).optional(),
lastPoints: z.number().optional(),
lastUserId: z.string().optional(),
startRank: z.number().int().min(1).optional(),
}); No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and print the relevant schema file with line numbers
sed -n '1,120p' cloud-functions/src/validation/schemas.ts | nl -ba

# Check Zod import style/version signals
rg -n "from ['\"]zod['\"]|require\\(['\"]zod['\"]\\)|zod" -S cloud-functions/src/validation/schemas.ts cloud-functions/src/validation || true
rg -n "@?types/zod|zod\\b" package.json cloud-functions/package.json pnpm-lock.yaml yarn.lock package-lock.json 2>/dev/null || true

# Find any existing strict/unknown handling patterns used elsewhere in the repo
rg -n "strictObject\\(|.strict\\(|\\.passthrough\\(|\\.strip\\(|\\.unknown\\(|.catchall\\(" cloud-functions/src || true
rg -n "unknownKeys|strip|passthrough" cloud-functions/src || true

# Print the part of schemas.ts around the two schemas (in case there is more)
rg -n "setRoleSchema|getTopContributorsSchema" cloud-functions/src/validation/schemas.ts

Repository: roshankumar0036singh/Uni-Event

Length of output: 117


🌐 Web query:

Zod strictObject unknown keys default behavior z.object extra keys accepted stripped vs rejected

💡 Result:

In Zod, the default behavior for z.object schemas is to strip unknown keys (keys not explicitly defined in the schema) during parsing [1][2]. This means that if an input object contains extra properties, they are excluded from the final parsed output [1][3]. To control this behavior, Zod provides the following methods: 1..strip: This explicitly enforces the default behavior of removing unknown keys [1][3]. 2..passthrough: This instructs Zod to include unknown keys in the parsed output instead of stripping them [1][3]. 3..strict: This causes Zod to throw an error if the input object contains any keys that are not explicitly defined in the schema [1][3]. For convenience, you can also use z.strictObject(...), which is functionally equivalent to z.object(...).strict() and is often preferred for data exploration or scenarios where you want to ensure the input strictly matches the defined schema [2][4]. Conversely, z.looseObject(...) acts similarly to using .passthrough() [2]. Note that these methods are not recursive; if you use .strict() on a parent object, it does not automatically enforce strictness on nested child objects [5]. Each object schema must be configured individually to control how unknown keys are handled [5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Print the relevant part of schemas.ts with line numbers (without nl)
python3 - <<'PY'
from pathlib import Path
p = Path("cloud-functions/src/validation/schemas.ts")
lines = p.read_text().splitlines()
for i in range(1, min(len(lines), 40)+1):
    print(f"{i:4d}\t{lines[i-1]}")
PY

# 2) Check Zod dependency/version
# Prefer cloud-functions/package.json if present
if [ -f cloud-functions/package.json ]; then
  echo "---- cloud-functions/package.json ----"
  rg -n "\"zod\"|zod@" cloud-functions/package.json || true
fi
# Also scan root package.json
if [ -f package.json ]; then
  echo "---- root package.json ----"
  rg -n "\"zod\"|zod@" package.json || true
fi

# 3) Search for existing strict/unknown-handling patterns used elsewhere
rg -n "strictObject\\(|\\.strict\\(|\\.passthrough\\(|\\.strip\\(|\\.unknown\\(|catchall\\(" cloud-functions/src || true
rg -n "unknownKeys|strip|passthrough" cloud-functions/src || true

Repository: roshankumar0036singh/Uni-Event

Length of output: 622


🌐 Web query:

z.strictObject(z.object) is functionally equivalent to z.object(...).strict() unknown keys handling default strip

💡 Result:

Yes, z.strictObject(shape) is functionally equivalent to z.object(shape).strict [1][2]. Both create an object schema that disallows unknown keys, causing Zod to throw an error if any keys not defined in the schema are present during parsing [2][3]. By default, z.object behavior is to "strip" unknown keys, meaning they are silently removed from the output and do not cause validation errors [1][3]. Using.strict (or z.strictObject) explicitly changes this behavior to "strict" mode [2]. While z.strictObject serves as a convenient shorthand, it is essentially a wrapper that applies the strict constraint upon initialization [1][2]. In newer versions of Zod (including the move toward Zod 4), maintainers have increasingly encouraged the use of z.strictObject and z.looseObject as preferred, explicit ways to define strictness [4]. Note that this strictness is not recursive; it only applies to the object level at which it is defined [5].

Citations:


Reject unknown payload fields (switch these Zod schemas to strict mode)

cloud-functions/src/validation/schemas.ts defines setRoleSchema and getTopContributorsSchema with z.object(...). With Zod v4 (zod ^4.4.3), z.object strips unknown keys by default, so extra fields won’t cause validation to fail—undermining the “reject invalid payloads at function entry” contract. Use strict object schemas for both.

Suggested schema change
-export const setRoleSchema = z.object({
+export const setRoleSchema = z.strictObject({
   uid: z.string().min(1, "uid is required"),
   role: z.enum(["admin", "club", "student"]),
 });
 
-export const getTopContributorsSchema = z.object({
+export const getTopContributorsSchema = z.strictObject({
   limit: z.number().int().min(1).max(25).optional(),
   lastPoints: z.number().optional(),
   lastUserId: z.string().optional(),
   startRank: z.number().int().min(1).optional(),
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cloud-functions/src/validation/schemas.ts` around lines 3 - 13, The current
z.object schemas (setRoleSchema and getTopContributorsSchema) silently allow
unknown fields; update both definitions to use Zod's strict mode by appending
.strict() to each z.object(...) so unknown payload fields are rejected (e.g.,
setRoleSchema = z.object({...}).strict() and getTopContributorsSchema =
z.object({...}).strict()).

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cloud-functions/src/certificateService.ts`:
- Around line 277-280: The failed outcome object currently returned when email
sending fails is missing certificateUrl; update the object returned in the
email-failure catch block (the one setting email: participant.email || null,
status: 'failed', error: getErrorMessage(error)) to also include certificateUrl:
signedUrl so it matches handleExistingCertificateParticipant and reflects that
the cert was uploaded/persisted; locate this in certificateService.ts around the
email send error handling and add certificateUrl: signedUrl to the outcome.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 88264534-100d-4334-a21f-61adf15869b4

📥 Commits

Reviewing files that changed from the base of the PR and between edd53b8 and 743ceb5.

⛔ Files ignored due to path filters (14)
  • cloud-functions/lib/analyzeAttendance.js.map is excluded by !**/*.map
  • cloud-functions/lib/certificateService.js.map is excluded by !**/*.map
  • cloud-functions/lib/dailyDigest.js.map is excluded by !**/*.map
  • cloud-functions/lib/eventNotifications.js.map is excluded by !**/*.map
  • cloud-functions/lib/inactiveUsers.js.map is excluded by !**/*.map
  • cloud-functions/lib/index.js.map is excluded by !**/*.map
  • cloud-functions/lib/lib/participants.js.map is excluded by !**/*.map
  • cloud-functions/lib/onEventCreate.js.map is excluded by !**/*.map
  • cloud-functions/lib/reminders.js.map is excluded by !**/*.map
  • cloud-functions/lib/reputation.js.map is excluded by !**/*.map
  • cloud-functions/lib/server.js.map is excluded by !**/*.map
  • cloud-functions/lib/setRole.js.map is excluded by !**/*.map
  • cloud-functions/lib/utils/distance.js.map is excluded by !**/*.map
  • cloud-functions/lib/utils/fraudScore.js.map is excluded by !**/*.map
📒 Files selected for processing (15)
  • cloud-functions/.gitignore
  • cloud-functions/lib/analyzeAttendance.js
  • cloud-functions/lib/certificateService.js
  • cloud-functions/lib/dailyDigest.js
  • cloud-functions/lib/eventNotifications.js
  • cloud-functions/lib/index.js
  • cloud-functions/lib/lib/participants.js
  • cloud-functions/lib/onEventCreate.js
  • cloud-functions/lib/reminders.js
  • cloud-functions/lib/reputation.js
  • cloud-functions/lib/server.js
  • cloud-functions/lib/setRole.js
  • cloud-functions/lib/utils/distance.js
  • cloud-functions/lib/utils/fraudScore.js
  • cloud-functions/src/certificateService.ts
💤 Files with no reviewable changes (13)
  • cloud-functions/lib/lib/participants.js
  • cloud-functions/lib/utils/fraudScore.js
  • cloud-functions/lib/server.js
  • cloud-functions/lib/setRole.js
  • cloud-functions/lib/analyzeAttendance.js
  • cloud-functions/lib/eventNotifications.js
  • cloud-functions/lib/dailyDigest.js
  • cloud-functions/lib/index.js
  • cloud-functions/lib/utils/distance.js
  • cloud-functions/lib/onEventCreate.js
  • cloud-functions/lib/certificateService.js
  • cloud-functions/lib/reminders.js
  • cloud-functions/lib/reputation.js
✅ Files skipped from review due to trivial changes (1)
  • cloud-functions/.gitignore

Comment on lines +277 to +280
email: participant.email || null,
status: 'failed',
error: getErrorMessage(error),
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Include certificateUrl in the failed outcome for consistency and completeness.

At this point, the certificate has been successfully uploaded to storage (line 251) and persisted to Firestore (line 254). When email sending fails, the outcome should include certificateUrl: signedUrl to:

  • Maintain consistency with handleExistingCertificateParticipant (line 208), which includes certificateUrl in failed outcomes
  • Provide complete information about the partial success (cert generated/stored, email failed)
  • Aid debugging and enable manual email delivery if needed
✨ Proposed fix to include certificateUrl
 return {
     email: participant.email || null,
     status: 'failed',
     error: getErrorMessage(error),
+    certificateUrl: signedUrl,
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
email: participant.email || null,
status: 'failed',
error: getErrorMessage(error),
};
email: participant.email || null,
status: 'failed',
error: getErrorMessage(error),
certificateUrl: signedUrl,
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cloud-functions/src/certificateService.ts` around lines 277 - 280, The failed
outcome object currently returned when email sending fails is missing
certificateUrl; update the object returned in the email-failure catch block (the
one setting email: participant.email || null, status: 'failed', error:
getErrorMessage(error)) to also include certificateUrl: signedUrl so it matches
handleExistingCertificateParticipant and reflects that the cert was
uploaded/persisted; locate this in certificateService.ts around the email send
error handling and add certificateUrl: signedUrl to the outcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add request validation middleware to cloud functions

1 participant