Add API endpoint to export event session votes - #1675
Merged
Conversation
GET /events/:projectId/votes returns the per-session vote export, reusing the core transformation of scripts/exportAllEventVotes.ts (fetch the event's public sessions/speakers JSON, join each session with its sessionVotes doc, flatten votes into columns keyed by vote-item name). The CSV/file IO stays in the script; the API returns JSON rows. Auth accepts either key type, scoped to avoid cross-tenant access: - event API key (ofproj_): only its own event, - organization key (oforg_): any event in that organization. Mismatches return 404 (not 403) so event ids aren't enumerable. Tested: project key (match/mismatch), org key (in-org/other-org), missing key, and missing public data URL. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
open-feedback
|
||||||||||||||||||||||||||||||||||||||||
| Project |
open-feedback
|
| Branch Review |
main
|
| Run status |
|
| Run duration | 02m 13s |
| Commit |
|
| Committer | Hugo Gresse |
| View all properties for this run ↗︎ | |
| Test results | |
|---|---|
|
|
1
|
|
|
1
|
|
|
0
|
|
|
0
|
|
|
13
|
| View all changes introduced in this branch ↗︎ | |
Tests for review

cypress/e2e/feedback/talk.spec.js • 1 failed test
| Test | Artifacts | |
|---|---|---|
| Single talk > Check that boolean vote does work with multiples votes as the same time as text votes |
Test Replay
Screenshots
|
|

cypress/e2e/feedback/talk.spec.js • 1 flaky test
| Test | Artifacts | |
|---|---|---|
| Single talk > Check that text vote does work (post, edit and delete) |
Test Replay
Screenshots
|
|
|
Visit the preview URL for this PR (updated for commit 264e3b8): https://open-feedback-42--pr1675-feat-api-export-even-0sq33l8v.web.app (expires Sun, 21 Jun 2026 16:02:05 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: 08b588459ed3335bea4061fbe93b8b77635ad43a |
- Default a missing vote `plus` to 0 instead of emitting "(undefined)". - Convert fetch failures (network error, non-2xx, invalid JSON) into a 400 with a clear message instead of an opaque 500. - Fetch session vote docs concurrently (Promise.all) and pre-index vote items by id, avoiding sequential awaits and repeated .find() on large events. - Org-key path: a non-existent project and a wrong-org project now return the identical 404 "Event not found", so event ids stay non-enumerable. Tests cover the unified 404, the plus default, and the fetch-error 400. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
GET /events/:projectId/votesto the public API — exports every session's votes for an event as JSON.Reuses the core transformation of
scripts/exportAllEventVotes.ts, ported intofunctions/src/api/services/exportEventVotes.ts:config.jsonUrl),projects/{id}/sessionVotes/{sessionId}doc,"Quality": "Great talk (2)").The CSV/file IO stays in the script; the API returns
{ projectId, sessionsCount, sessions[] }.Auth — both key types, scoped
Accepts either key via the existing
authenticateRequest:ofproj_) → only its own event (request.project.idmust match the path).oforg_) → any event whoseorganizationIdmatches the org.Mismatches return 404 (not 403) so event ids stay non-enumerable.
Hardening vs the script
The script assumed well-formed data; the service guards: missing
config.jsonUrl→ 400, missing speakers, and vote items that don't map to a question are skipped instead of throwing.Tests
getVotes.spec.ts— 6 cases:Functions build ✓ · lint ✓ · API tests 20/20 ✓
Notes / possible follow-ups
?format=csvlater (the row shape is already CSV-ready).🤖 Generated with Claude Code