Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
156 commits
Select commit Hold shift + click to select a range
3bab2c7
(Progress) Added Basic Pages with Nav Bar
keeryn04 Nov 2, 2025
9c647c2
(Progress) Added Basic Login / Signup Page
keeryn04 Nov 3, 2025
4c9490a
Update package-lock.json
jktieh Nov 5, 2025
2e43270
Create Navbar.tsx
jktieh Nov 5, 2025
bd888ab
Create Hero.tsx
jktieh Nov 5, 2025
5db1770
Create Footer.tsx
jktieh Nov 5, 2025
78de9da
Rename to QRCode.tsx
jktieh Nov 5, 2025
f877a3f
Create Home.tsx
jktieh Nov 5, 2025
fe3c303
Create Card.tsx
jktieh Nov 5, 2025
a35e3e8
Update App.tsx
jktieh Nov 5, 2025
aa42265
Update index.html
jktieh Nov 5, 2025
4004201
Update Footer.tsx
jktieh Nov 5, 2025
48f1658
Update Hero.tsx
jktieh Nov 5, 2025
c228e72
Update Navbar.tsx
jktieh Nov 5, 2025
5a4e276
Update main.tsx
jktieh Nov 5, 2025
0408e96
Update Home.tsx
jktieh Nov 6, 2025
2b56e52
(Progress) Added Info Spots for Logged In User
keeryn04 Nov 6, 2025
1509c7c
Update code structure for easy to maintain
lnqminh3003 Nov 7, 2025
cdf732c
Merge branch 'frontend/home-page' into frontend/qrcode
lnqminh3003 Nov 7, 2025
620232b
Updated homepage, added QR code component, about us section, redesign…
jktieh Nov 16, 2025
cf60e0f
Update Navbar.tsx
jktieh Nov 16, 2025
9fbcba0
Update Navbar.tsx
jktieh Nov 16, 2025
6b2ef6e
(Progress) QR Code Component Created, Backend Needed
keeryn04 Nov 16, 2025
e7bbbe0
(Progress) File Organization
keeryn04 Nov 16, 2025
56bae0c
Merge branch 'main' into mobile
lnqminh3003 Nov 16, 2025
49405ed
(Update) Added More Folder Formatting
keeryn04 Nov 18, 2025
e16bc01
(Update) User Auth Set Up
keeryn04 Nov 27, 2025
56be0f0
(Fix) Join Event Display Issue
keeryn04 Nov 27, 2025
d3bc9be
(Progress) Guest Profile Working
keeryn04 Nov 28, 2025
0afad34
Deleted unused components, updated Navbar
jktieh Dec 4, 2025
aa46da5
(Progress) Join Code Event Fetching
keeryn04 Dec 5, 2025
7af7feb
Merge pull request #33 from techstartucalgary/mobile-guest
keeryn04 Dec 7, 2025
ec3f34f
Merge pull request #32 from techstartucalgary/mobile-event
keeryn04 Dec 7, 2025
8405bbd
(Fix) Routes to Profile Page if not Logged In
keeryn04 Dec 7, 2025
430d64c
(Progress) Event Cards Showing, Needs Backend for Joining
keeryn04 Dec 18, 2025
aa1ee39
(Progress) Can Join Game, Swaps to Game Screen, Loads Game Data
keeryn04 Dec 18, 2025
7d674a0
(Progress) Displaying Correctly, Needs Styling
keeryn04 Dec 18, 2025
355108e
websocket hosting event
lnqminh3003 Jan 13, 2026
6c52d9a
(Progress) Camera Fix, Load User Events,
keeryn04 Jan 19, 2026
1dd3dc3
Merge branch 'frontend/qrcode' into frontend/home-page
lnqminh3003 Jan 19, 2026
91ac597
add vercel
lnqminh3003 Jan 19, 2026
9cb24a2
Merge branch 'backend' into frontend/home-page
lnqminh3003 Jan 20, 2026
6745299
Update the real time websocket for Frontend
lnqminh3003 Jan 20, 2026
55f30f2
(Update) Added Backend Routes
keeryn04 Jan 21, 2026
bfce025
"STR-100 LogIn and SignUp logic for a host"
jktieh Jan 23, 2026
580b4d6
Added .env file to run our Frontend
youssefibrahim3 Jan 23, 2026
56e07a4
Fixed env
Jan 23, 2026
fc2928f
Added CreateEventPage
Jan 23, 2026
7b23b62
Added service/CreateEvent
Jan 23, 2026
eec9a9e
Create Event Page has now been fully re-integrated after it was lost …
Jan 23, 2026
184d2f0
Merge branch 'main' into frontend/home-page
lnqminh3003 Jan 26, 2026
e8c8bf5
Merge branch 'main' into frontend/home-page
lnqminh3003 Jan 26, 2026
8bcbf2a
Merge branch 'frontend/home-page' of github.com:techstartucalgary/Net…
lnqminh3003 Jan 26, 2026
962bf04
(Update) Added More Backend Calls
keeryn04 Jan 26, 2026
9b68ec2
update gitignore file
lnqminh3003 Jan 26, 2026
b21f0c2
Merge pull request #42 from techstartucalgary/mobile-game-page
keeryn04 Jan 26, 2026
255ea2e
Merge remote-tracking branch 'origin/main' into mobile-and-backend
keeryn04 Jan 26, 2026
40e9e09
add vercel.json file
lnqminh3003 Jan 26, 2026
0acb123
fix vercel.json file
lnqminh3003 Jan 26, 2026
0cbf0ae
Merge remote-tracking branch 'origin/backend' into mobile-and-backend
keeryn04 Jan 26, 2026
697e9a0
(Update) Login and Signup Working on DB
keeryn04 Jan 26, 2026
30c537e
Add logo to login/sign up page
jktieh Jan 28, 2026
ded751c
Created the create-event page
Jan 29, 2026
9d1351a
Merge branch 'frontend/home-page' of https://github.com/techstartucal…
Jan 29, 2026
58ab852
Add user and event lookup endpoints
rxmox Jan 26, 2026
e429cd1
Add authentication for get user data from userId and get events from …
lnqminh3003 Jan 26, 2026
d8e24bf
Merge branch 'STR-101-Create-User-Connections-between-Users' of https…
rodolfo-gp Jan 29, 2026
b23b1a8
Merge branch 'STR-101-Create-User-Connections-between-Users' of https…
rodolfo-gp Jan 29, 2026
fba44f2
change joinCode example
lnqminh3003 Jan 30, 2026
9f64b44
Functionality
rodolfo-gp Jan 30, 2026
be97e2c
Added logo button interactivity, and reworked create event page
Jan 30, 2026
91e85f5
Merge branch 'frontend/home-page' of https://github.com/techstartucal…
Jan 30, 2026
052bc98
added event page, responsive NavBar
jktieh Jan 30, 2026
1a06709
(Update) Join Event and Display User Events Working
keeryn04 Jan 30, 2026
c3f504c
Update Hero.tsx
jktieh Jan 30, 2026
b591839
(Update) Guest Events Stored Locally, Displaying on Events
keeryn04 Jan 30, 2026
b6e2eb2
(Update) Name Bingo Route Added
keeryn04 Jan 30, 2026
1e4409d
Update Hero.tsx
jktieh Feb 2, 2026
0ecfefe
Adjust hero margin
jktieh Feb 2, 2026
ae5d5f4
update homepage
jktieh Feb 2, 2026
d16bea6
update create event
jktieh Feb 2, 2026
6f9a541
Merge branch 'main' into frontend/home-page
lnqminh3003 Feb 2, 2026
81ca8bb
Merge branch 'frontend/home-page' of github.com:techstartucalgary/Net…
lnqminh3003 Feb 2, 2026
1749f6e
fix data model in FE
lnqminh3003 Feb 2, 2026
36109d1
Fixed Controller logic. No duplicate creation
rodolfo-gp Feb 6, 2026
0ff7bc5
Merge branch 'main' of https://github.com/techstartucalgary/Networkin…
keeryn04 Feb 6, 2026
c239c2d
(Update) Added Bingo Routes
keeryn04 Feb 6, 2026
4bb7a36
(Progress) Added Basic Pages with Nav Bar
keeryn04 Nov 2, 2025
6924386
(Progress) Added Basic Login / Signup Page
keeryn04 Nov 3, 2025
63ca926
(Progress) Added Info Spots for Logged In User
keeryn04 Nov 6, 2025
493cbae
(Progress) QR Code Component Created, Backend Needed
keeryn04 Nov 16, 2025
67cb456
(Progress) File Organization
keeryn04 Nov 16, 2025
0b73644
(Update) Added More Folder Formatting
keeryn04 Nov 18, 2025
154503c
(Update) User Auth Set Up
keeryn04 Nov 27, 2025
7b8d22e
(Fix) Join Event Display Issue
keeryn04 Nov 27, 2025
693fac5
(Progress) Guest Profile Working
keeryn04 Nov 28, 2025
da00ac9
(Progress) Join Code Event Fetching
keeryn04 Dec 5, 2025
620f80a
(Fix) Routes to Profile Page if not Logged In
keeryn04 Dec 7, 2025
c62e798
(Progress) Event Cards Showing, Needs Backend for Joining
keeryn04 Dec 18, 2025
bda27e4
(Progress) Can Join Game, Swaps to Game Screen, Loads Game Data
keeryn04 Dec 18, 2025
9cde719
(Progress) Displaying Correctly, Needs Styling
keeryn04 Dec 18, 2025
bc39f55
(Progress) Camera Fix, Load User Events,
keeryn04 Jan 19, 2026
a69c46a
(Update) Added Backend Routes
keeryn04 Jan 21, 2026
c226e49
(Update) Added More Backend Calls
keeryn04 Jan 26, 2026
26f9163
(Update) Login and Signup Working on DB
keeryn04 Jan 26, 2026
d0e49a5
(Update) Join Event and Display User Events Working
keeryn04 Jan 30, 2026
8631119
(Update) Guest Events Stored Locally, Displaying on Events
keeryn04 Jan 30, 2026
2a77f74
(Update) Name Bingo Route Added
keeryn04 Jan 30, 2026
31ad27b
Add workflow_dispatch trigger to CI frontend workflow
lnqminh3003 Feb 2, 2026
87b583a
(Update) Added Bingo Routes
keeryn04 Feb 6, 2026
1f8bb6a
Merge branch 'mobile-and-backend' of https://github.com/techstartucal…
keeryn04 Feb 6, 2026
a0a4d4c
update loggined in NavBar, added authUtils
jktieh Feb 6, 2026
e7442ab
Added get cconnections by email route
rodolfo-gp Feb 6, 2026
a73a66c
Created BingoGame.ts to call the Bingo creation api
Feb 6, 2026
39ada11
update DashboardPage.tsx
jktieh Feb 6, 2026
979e5ff
(Update) Swapped Bingo Category Calling
keeryn04 Feb 6, 2026
e6f1879
(Progress) Added Basic Pages with Nav Bar
keeryn04 Nov 2, 2025
c90c348
(Progress) Added Basic Login / Signup Page
keeryn04 Nov 3, 2025
cd519fc
(Progress) Added Info Spots for Logged In User
keeryn04 Nov 6, 2025
6f1f5be
(Progress) QR Code Component Created, Backend Needed
keeryn04 Nov 16, 2025
e5dfb3f
(Progress) File Organization
keeryn04 Nov 16, 2025
d6854e1
(Update) Added More Folder Formatting
keeryn04 Nov 18, 2025
c455375
(Update) User Auth Set Up
keeryn04 Nov 27, 2025
e384beb
(Progress) Join Code Event Fetching
keeryn04 Dec 5, 2025
81fb797
(Progress) Event Cards Showing, Needs Backend for Joining
keeryn04 Dec 18, 2025
6187ba2
(Progress) Can Join Game, Swaps to Game Screen, Loads Game Data
keeryn04 Dec 18, 2025
7507ab9
(Progress) Displaying Correctly, Needs Styling
keeryn04 Dec 18, 2025
a8fce75
(Progress) Camera Fix, Load User Events,
keeryn04 Jan 19, 2026
1e50366
(Update) Added Backend Routes
keeryn04 Jan 21, 2026
268e54e
(Update) Added More Backend Calls
keeryn04 Jan 26, 2026
271e4da
(Update) Login and Signup Working on DB
keeryn04 Jan 26, 2026
bb8efc5
(Update) Guest Events Stored Locally, Displaying on Events
keeryn04 Jan 30, 2026
29a381a
(Update) Name Bingo Route Added
keeryn04 Jan 30, 2026
849e01c
(Update) Added Bingo Routes
keeryn04 Feb 6, 2026
02c9176
(Update) Swapped Bingo Category Calling
keeryn04 Feb 6, 2026
39b8bf3
Merge branch 'mobile-and-backend' of https://github.com/techstartucal…
keeryn04 Feb 6, 2026
958eb6a
(Update) Name Bingo API Calls Working
keeryn04 Feb 6, 2026
e3ec900
update navbar
jktieh Feb 6, 2026
cdc833f
update about us bug
jktieh Feb 6, 2026
9217681
(Update) Added Text Input Field
keeryn04 Feb 6, 2026
be17dca
Merge branch 'main' into STR-101-Create-User-Connections-between-Users
lnqminh3003 Feb 7, 2026
8730ab7
Update route for bingo game
lnqminh3003 Feb 7, 2026
f80f0b3
update dashboard
jktieh Feb 7, 2026
ea1ac89
Update HomePage.tsx
jktieh Feb 7, 2026
93fbf76
Revert "Update route for bingo game"
lnqminh3003 Feb 8, 2026
25fd441
added bingo game
jktieh Feb 8, 2026
10b3e35
Update EventPage.tsx
jktieh Feb 9, 2026
a4cab4b
update dashboard layout, fix bug
jktieh Feb 9, 2026
3447435
Update DashboardPage.tsx
jktieh Feb 9, 2026
4b17945
Fix broken logo
lnqminh3003 Feb 9, 2026
a8cbd4f
Merge branch 'frontend/home-page' of github.com:techstartucalgary/Net…
lnqminh3003 Feb 9, 2026
dff5657
Merge pull request #51 from techstartucalgary/frontend/home-page
lnqminh3003 Feb 17, 2026
2efc545
Merge pull request #55 from techstartucalgary/mobile-and-backend
lnqminh3003 Feb 17, 2026
cb0cda3
Merge pull request #61 from techstartucalgary/backend
lnqminh3003 Feb 17, 2026
c3c6fde
Merge branch 'main' into STR-101-Create-User-Connections-between-Users
lnqminh3003 Feb 17, 2026
07c68f5
Updating UserConnections to now be participant connenctions. Needs to…
rodolfo-gp Feb 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
Binary file added shatter-backend/src/.DS_Store
Binary file not shown.
6 changes: 4 additions & 2 deletions shatter-backend/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import express from "express";
import cors from "cors";

import userRoutes from './routes/user_route'; // these routes define how to handle requests to /api/users
import userRoutes from './routes/user_route';
import authRoutes from './routes/auth_routes';
import eventRoutes from './routes/event_routes';
import bingoRoutes from './routes/bingo_routes';
import participantConnectionRoutes from "./routes/participant_connections_routes";


const app = express();
Expand Down Expand Up @@ -43,5 +44,6 @@ app.use('/api/users', userRoutes);
app.use('/api/auth', authRoutes);
app.use('/api/events', eventRoutes);
app.use('/api/bingo', bingoRoutes);
app.use("/api/participantConnections", participantConnectionRoutes);

export default app;
export default app;
318 changes: 318 additions & 0 deletions shatter-backend/src/controllers/participant_connections_controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
// controllers/participant_connections_controller.ts

import { Request, Response } from "express";
import { Types } from "mongoose";

import { check_req_fields } from "../utils/requests_utils";
import { User } from "../models/user_model";
import { Participant } from "../models/participant_model";
import { ParticipantConnection } from "../models/participant_connection_model";

/**
* POST /api/participantConnections
* Create a new ParticipantConnection document.
* The server generates the ParticipantConnection `_id` automatically (pre-save hook).
*
* @param req.body._eventId - MongoDB ObjectId of the event (required)
* @param req.body.primaryParticipantId - MongoDB ObjectId of the primary participant (required)
* @param req.body.secondaryParticipantId - MongoDB ObjectId of the secondary participant (required)
* @param req.body.description - Optional description for the connection, can be the bingo question the participants connected with (optional)
*
* Behavior notes:
* - Validates ObjectId format before hitting the DB
* - Ensures BOTH participants exist AND belong to the given event
* - Prevents duplicates with exact same (_eventId, primaryParticipantId, secondaryParticipantId)
*
* @returns 201 - Created ParticipantConnection document
* @returns 400 - Missing required fields or invalid ObjectId format
* @returns 404 - Primary participant or secondary participant not found for this event
* @returns 409 - ParticipantConnection already exists for this event and participants
* @returns 500 - Internal server error
*/
export async function createParticipantConnection(req: Request, res: Response) {
try {
const requiredFields = ["_eventId", "primaryParticipantId", "secondaryParticipantId"];
if (!check_req_fields(req, requiredFields)) {
return res.status(400).json({ error: "Missing required fields" });
}

const { _eventId, primaryParticipantId, secondaryParticipantId, description } = req.body;

// Validate ObjectId format before hitting the DB
const idsToValidate = { _eventId, primaryParticipantId, secondaryParticipantId };
for (const [key, value] of Object.entries(idsToValidate)) {
if (!Types.ObjectId.isValid(value)) {
return res.status(400).json({ error: `Invalid ${key}` });
}
}

// Ensure both participants exist AND belong to the event
const [primaryParticipant, secondaryParticipant] = await Promise.all([
Participant.findOne({ _id: primaryParticipantId, eventId: _eventId }).select("_id"),
Participant.findOne({ _id: secondaryParticipantId, eventId: _eventId }).select("_id"),
]);

if (!primaryParticipant) {
return res.status(404).json({ error: "Primary participant not found for this event" });
}
if (!secondaryParticipant) {
return res.status(404).json({ error: "Secondary participant not found for this event" });
}

// Prevent duplicates with exact same (_eventId, primaryParticipantId, secondaryParticipantId)
const existing = await ParticipantConnection.findOne({
_eventId,
primaryParticipantId,
secondaryParticipantId,
});

if (existing) {
return res.status(409).json({
error: "ParticipantConnection already exists for this event and participants",
existingConnection: existing,
});
}

const newConnection = await ParticipantConnection.create({
_eventId,
primaryParticipantId,
secondaryParticipantId,
description,
});

return res.status(201).json(newConnection);
} catch (_error) {
return res.status(500).json({ error: "Internal server error" });
}
}

/**
* POST /api/participantConnections/by-emails
* Create a new ParticipantConnection by providing USER emails.
*
* Looks up users by email, then finds their Participant records for the given event,
* then saves the connection using the participants' MongoDB ObjectIds.
* The server generates the ParticipantConnection `_id` automatically (pre-save hook).
*
* @param req.body._eventId - MongoDB ObjectId of the event (required)
* @param req.body.primaryUserEmail - Email of the primary user (required)
* @param req.body.secondaryUserEmail - Email of the secondary user (required)
* @param req.body.description - Optional description for the connection (optional)
*
* Behavior notes:
* - Validates _eventId ObjectId format
* - Validates emails + prevents same email provided twice
* - Maps email -> User -> Participant (for that event)
* - Prevents duplicates with exact same (_eventId, primaryParticipantId, secondaryParticipantId)
*
* @returns 201 - Created ParticipantConnection document
* @returns 400 - Missing required fields, invalid ObjectId, invalid emails, or same email provided twice
* @returns 404 - Primary/secondary user not found OR participant not found for this event
* @returns 409 - ParticipantConnection already exists for this event and participants
* @returns 500 - Internal server error
*/
export async function createParticipantConnectionByEmails(req: Request, res: Response) {
try {
const requiredFields = ["_eventId", "primaryUserEmail", "secondaryUserEmail"];
if (!check_req_fields(req, requiredFields)) {
return res.status(400).json({ error: "Missing required fields" });
}

const { _eventId, primaryUserEmail, secondaryUserEmail, description } = req.body;

if (!Types.ObjectId.isValid(_eventId)) {
return res.status(400).json({ error: "Invalid _eventId" });
}

const primaryEmail = String(primaryUserEmail).trim().toLowerCase();
const secondaryEmail = String(secondaryUserEmail).trim().toLowerCase();

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
if (!emailRegex.test(primaryEmail)) {
return res.status(400).json({ error: "Invalid primaryUserEmail" });
}
if (!emailRegex.test(secondaryEmail)) {
return res.status(400).json({ error: "Invalid secondaryUserEmail" });
}

if (primaryEmail === secondaryEmail) {
return res.status(400).json({ error: "primaryUserEmail and secondaryUserEmail must be different" });
}

// Find users by email
const [primaryUser, secondaryUser] = await Promise.all([
User.findOne({ email: primaryEmail }).select("_id"),
User.findOne({ email: secondaryEmail }).select("_id"),
]);

if (!primaryUser) return res.status(404).json({ error: "Primary user not found" });
if (!secondaryUser) return res.status(404).json({ error: "Secondary user not found" });

// Map User -> Participant (for the event)
const [primaryParticipant, secondaryParticipant] = await Promise.all([
Participant.findOne({ eventId: _eventId, userId: primaryUser._id }).select("_id"),
Participant.findOne({ eventId: _eventId, userId: secondaryUser._id }).select("_id"),
]);

if (!primaryParticipant) {
return res.status(404).json({ error: "Primary participant not found for this event (by user email)" });
}
if (!secondaryParticipant) {
return res.status(404).json({ error: "Secondary participant not found for this event (by user email)" });
}

// Prevent duplicates with exact same (_eventId, primaryParticipantId, secondaryParticipantId)
const existing = await ParticipantConnection.findOne({
_eventId,
primaryParticipantId: primaryParticipant._id,
secondaryParticipantId: secondaryParticipant._id,
});

if (existing) {
return res.status(409).json({
error: "ParticipantConnection already exists for this event and participants",
existingConnection: existing,
});
}

const newConnection = await ParticipantConnection.create({
_eventId,
primaryParticipantId: primaryParticipant._id,
secondaryParticipantId: secondaryParticipant._id,
description,
});

return res.status(201).json(newConnection);
} catch (_error) {
return res.status(500).json({ error: "Internal server error" });
}
}

/**
* DELETE /api/participantConnections/delete
*
* Deletes a participant connection only if it belongs to the given event.
*
* @param req.body.eventId - MongoDB ObjectId of the event (required)
* @param req.body.connectionId - ParticipantConnection string _id (required)
*
* @returns 200 - Deleted connection
* @returns 400 - Missing/invalid body params
* @returns 404 - ParticipantConnection not found for this event
* @returns 500 - Internal server error
*/
export async function deleteParticipantConnection(req: Request, res: Response) {
try {
const { eventId, connectionId } = req.body;

if (!eventId || !Types.ObjectId.isValid(eventId)) {
return res.status(400).json({ error: "Invalid eventId" });
}

if (!connectionId || typeof connectionId !== "string") {
return res.status(400).json({ error: "Invalid connectionId" });
}

const deleted = await ParticipantConnection.findOneAndDelete({
_id: connectionId,
_eventId: eventId,
});

if (!deleted) {
return res.status(404).json({ error: "ParticipantConnection not found for this event" });
}

return res.status(200).json({
message: "ParticipantConnection deleted successfully",
deletedConnection: deleted,
});
} catch (_error) {
return res.status(500).json({ error: "Internal server error" });
}
}

/**
* PUT /api/participantConnections/getByParticipantAndEvent
*
* Returns all ParticipantConnections for an event where the given participant is either:
* - primaryParticipantId OR
* - secondaryParticipantId
*
* @param req.body.eventId - MongoDB ObjectId of the event (required)
* @param req.body.participantId - MongoDB ObjectId of the participant (required)
*
* @returns 200 - Array of matching ParticipantConnections
* @returns 400 - Missing/invalid body params
* @returns 500 - Internal server error
*/
export async function getConnectionsByParticipantAndEvent(req: Request, res: Response) {
try {
const { eventId, participantId } = req.body;

if (!eventId || !Types.ObjectId.isValid(eventId)) {
return res.status(400).json({ error: "Invalid eventId" });
}
if (!participantId || !Types.ObjectId.isValid(participantId)) {
return res.status(400).json({ error: "Invalid participantId" });
}

const connections = await ParticipantConnection.find({
_eventId: eventId,
$or: [{ primaryParticipantId: participantId }, { secondaryParticipantId: participantId }],
});

return res.status(200).json(connections);
} catch (_error) {
return res.status(500).json({ error: "Internal server error" });
}
}

/**
* PUT /api/participantConnections/getByUserEmailAndEvent
*
* Returns all ParticipantConnections for an event where the given user's PARTICIPANT is either:
* - primaryParticipantId OR
* - secondaryParticipantId
*
* @param req.body.eventId - MongoDB ObjectId of the event (required)
* @param req.body.userEmail - Email of the user (required)
*
* Behavior notes:
* - Maps userEmail -> User -> Participant (for that event)
* - Then returns ParticipantConnections where that participant appears
*
* @returns 200 - Array of matching ParticipantConnections
* @returns 400 - Missing/invalid body params or invalid userEmail (no matching user)
* @returns 404 - Participant not found for this event (even though user exists)
* @returns 500 - Internal server error
*/
export async function getConnectionsByUserEmailAndEvent(req: Request, res: Response) {
try {
const { eventId, userEmail } = req.body;

if (!eventId || !Types.ObjectId.isValid(eventId)) {
return res.status(400).json({ error: "Invalid eventId" });
}

const email = String(userEmail).trim().toLowerCase();
const user = await User.findOne({ email }).select("_id");

if (!user) {
return res.status(400).json({ error: "Invalid userEmail" });
}

const participant = await Participant.findOne({ eventId, userId: user._id }).select("_id");
if (!participant) {
return res.status(404).json({ error: "Participant not found for this event (by user email)" });
}

const connections = await ParticipantConnection.find({
_eventId: eventId,
$or: [{ primaryParticipantId: participant._id }, { secondaryParticipantId: participant._id }],
});

return res.status(200).json(connections);
} catch (_error) {
return res.status(500).json({ error: "Internal server error" });
}
}
46 changes: 46 additions & 0 deletions shatter-backend/src/models/participant_connection_model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Schema, model, Types, Document } from "mongoose";

export interface ParticipantConnection extends Document {
_id: string;
_eventId: Types.ObjectId;
primaryParticipantId: Types.ObjectId;
secondaryParticipantId: Types.ObjectId;
description?: string;
}

const participantConnectionSchema = new Schema<ParticipantConnection>(
{
_id: { type: String },
_eventId: {
type: Schema.Types.ObjectId,
ref: "Event",
required: true,
},
primaryParticipantId: {
type: Schema.Types.ObjectId,
ref: "Participant",
required: true,
},
secondaryParticipantId: {
type: Schema.Types.ObjectId,
ref: "Participant",
required: true,
},
description: { type: String },
},
{
versionKey: false,
}
);

participantConnectionSchema.pre("save", function (next) {
if (!this._id) {
this._id = `participantConnection_${Math.random().toString(36).slice(2, 10)}`;
}
next();
});

export const ParticipantConnection = model<ParticipantConnection>(
"ParticipantConnection",
participantConnectionSchema
);
Loading