Skip to content

Commit

Permalink
commit working repository
Browse files Browse the repository at this point in the history
  • Loading branch information
Ratchet7x5 committed Jan 23, 2025
1 parent 5fb25bf commit fb1f185
Show file tree
Hide file tree
Showing 17 changed files with 1,524 additions and 35 deletions.
1 change: 1 addition & 0 deletions api/controller/stripeController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const createCheckout = asyncHandler(
res.send({ clientSecret: session.client_secret });
} catch (error) {
res.send({ error }).status(404);
return;
}
}
);
Expand Down
8 changes: 4 additions & 4 deletions api/controller/userController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ export const updateUserTicketInfo = asyncHandler(
return res.status(400).json({ message: "All fields are required" });
}

let updateUserInfoOrNewUser = await insertUserTicket(req.body);
let userTicketId = await insertUserTicket(req.body);

res.status(200).json({
updateUserInfoOrNewUser,
updateUserInfoOrNewUser: userTicketId,
});
} catch (error) {
console.log(error);
res.status(500).json({
message:
"Error occured while trying to update/insert a user ticket: " + error,
message: error,
});
}
}
Expand Down
12 changes: 10 additions & 2 deletions api/gateway/eventsGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ export async function isTicketAvailableByPriceId(
return isTicketAvailable;
}

// @Ratchet7x5: Reserve one ticket
/**
* Decrements an event ticket from the tickets (numberTicketsLeft) and events (eventRemainingCapacity) table.
* @param priceId The stripe price ID
* @returns
*/
export async function reserveTicket(priceId: string) {
let canReserveTicket = await isTicketAvailableByPriceId(priceId);
let reservedTicket;
Expand Down Expand Up @@ -112,7 +116,11 @@ export async function reserveTicket(priceId: string) {
return reservedTicket;
}

// @Ratchet7x5: Release one reserved ticket
/**
* Increments an event ticket from the tickets (numberTicketsLeft) and events (eventRemainingCapacity) table.
* @param priceId The stripe price ID
* @returns
*/
export async function releaseReservedTicket(priceId: string) {
let releasedTicket;

Expand Down
114 changes: 110 additions & 4 deletions api/gateway/userGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
peoples,
purchasableMemberships,
questions,
tickets,
ticketsEventIdLinks,
userTickets,
userTicketsPeopleIdLinks,
userTicketsTicketIdLinks,
} from "../schemas/schema";
import { db } from "../db/config/db";
import { User, UpdateUserInfoBody } from "../types/types";
import { eq } from "drizzle-orm";
import { eq, and, gte } from "drizzle-orm";
import { stripe } from "../stripe/stripe";
import { getUserEmail, getUserIdByEmail } from "./authGateway";
import { updateUserMetadata } from "supertokens-node/recipe/usermetadata";
Expand Down Expand Up @@ -54,6 +56,7 @@ export async function getUserMembershipExpiryDate(
return returnDate;
}

// refactor the logic: If the current date is past the expiry, they are no longer a member.
export async function isMembershipActive(userEmail: string): Promise<boolean> {
let isActive = false;

Expand Down Expand Up @@ -83,7 +86,7 @@ export async function isMembershipActive(userEmail: string): Promise<boolean> {

/**
* Inserts an unpaid ticket into the userTickets (People_Ticket) table
* @param data The payload containing name, email, phoneNumber, answers (q&a). ticketId isn't currently used.
* @param data The payload containing name, email, phoneNumber, answers (q&a). ticketId is tickets.id
* @returns
*/
export async function insertUserTicket(data: {
Expand All @@ -96,9 +99,60 @@ export async function insertUserTicket(data: {
answer: string;
}[];
}): Promise<{ userTicketId: number }> {
/**
* Three secnarios can occur in this function:
* 1. Paid ticket: Throw error [DONE]
* 2. Unpaid ticket: return the ticketId (or update info on the existing ticket?) [DONE]
* 3. Uninserted ticket: Insert a new ticket. [PARTIALLY DONE]
*
* A potential refactor of this function may be needed.
*
* Another issue is, a user can purchase different tickets for the same event.
* The caveat is that the second ticket will always be unpaid, but gets inserted into user tickets.
* Since Tickets are linked to the Event, probably use this to prevent the user from buying
*/
// return the userTicketId
let newUserTicket: { userTicketId: number }[];

// if the user already has a paid ticket, then we send an error back.
// You will have to use the ticketsEventIdLinks to detect if the ticket belongs to an event.
let prepaidTicket = await db
.select()
.from(userTickets)
.innerJoin(
userTicketsTicketIdLinks,
eq(userTickets.id, userTicketsTicketIdLinks.userTicketId)
)
.innerJoin(
ticketsEventIdLinks,
eq(userTicketsTicketIdLinks.ticketId, ticketsEventIdLinks.ticketId)
)
.where(
and(
eq(userTickets.email, data.email),
eq(userTickets.paid, true),
eq(ticketsEventIdLinks.ticketId, data.ticketId) // Ensure ticket ID matches
)
);
if (prepaidTicket.length > 0) {
console.log(
"insertUserTicket: prepaidTicket: " +
JSON.stringify(prepaidTicket[0], null, 2)
);
//if paid, throw error
if (prepaidTicket[0].user_tickets.paid) {
throw new Error(
`You have already purchased a ticket. Contact admin if issue persists.`
);
}
//NOTE: THIS ELSE IF BLOCK HAS BEEN DISABLED
//if unpaid, return ticketId
/*else if (!prepaidTicket[0].user_tickets.paid) {
return { userTicketId: prepaidTicket[0].user_tickets.id };
}*/
}

//insert a new ticket
newUserTicket = await db
.insert(userTickets)
.values({
Expand Down Expand Up @@ -141,11 +195,13 @@ export async function insertUserTicket(data: {
throw new Error("insertUserTicket: Unable to insert userTicketIdLink: ");
}

console.log("insertUserTicket: userTicketIdLink: " + userTicketIdLink[0]);
console.log(
"insertUserTicket: userTicketIdLink: " + JSON.stringify(userTicketIdLink)
);

const ticketId = newUserTicket[0].userTicketId;

console.dir("insertUserTicket: ticketId: " + ticketId);
console.log("insertUserTicket: ticketId: " + JSON.stringify(ticketId));

if (data.answers.length > 0) {
const answerRecords = data.answers.map((answerData) => ({
Expand All @@ -160,6 +216,56 @@ export async function insertUserTicket(data: {
);

for (let index = 0; index < data.answers.length; index++) {
//TODO: if questions.checkForMemberEmail == true, check for email. If the email is not a member, throw an error.
let question = await db
.select()
.from(questions)
.where(eq(questions.id, answerRecords[index].questionId));

console.log(
"insertUserTicket: question: " + JSON.stringify(question, null, 2)
);

// if specified email is a member email, then create a new ticket for this user as well
if (question[0].checkForMemberEmail) {
let isMemberEmail = await db
.select()
.from(peoples)
.where(
and(
eq(peoples.email, answerRecords[index].answer),
gte(peoples.memberExpiryDate, new Date().toISOString())
)
)
.catch((error) => {
throw new Error(
`insertUserTicket: isMemberEmail: Error while trying to retrieve ${answerRecords[index].answer} from database: ${error}`
);
});

console.log(
"insertUserTicket: isMemberEmail: " +
JSON.stringify(isMemberEmail, null, 2)
);

// member is either not a paid member, or doesn't exist.
if (isMemberEmail.length == 0) {
throw new Error(
`insertUserTicket: ${answerRecords[index].answer} is not a paid member of AUIS. Contact admin if they are. Use ticketId ${ticketId} as reference.`
);
} else if (
isMemberEmail.length > 0 &&
isMemberEmail[0].memberExpiryDate !== undefined &&
isMemberEmail[0].memberExpiryDate !== null
) {
console.log(
"insertUserTicket: isMember date comparison: " +
new Date().toISOString() >=
isMemberEmail[0].memberExpiryDate
);
}
}

let answer = await db
.insert(answers)
.values(answerRecords[index])
Expand Down
5 changes: 0 additions & 5 deletions api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,4 @@ const port = Number.parseInt(process.env.PORT || "3000");
// Specify the host parameter as '0.0.0.0' to listen on all network interfaces
app.listen(port, "0.0.0.0", () => {
console.log(`Backend is now listening on port :${port}`);
console.log(`Backend env vars :
DOMAIN_API=${process.env.DOMAIN_API},
DOMAIN_FRONTEND=${process.env.DOMAIN_FRONTEND},
STRIPE_WEBHOOK_ENDPOINT=${process.env.STRIPE_WEBHOOK_ENDPOINT},
GOOGLE_CLIENT_ID=${process.env.GOOGLE_CLIENT_ID},`);
});
1 change: 0 additions & 1 deletion api/routes/userRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Router } from "express";
import { verifySession } from "supertokens-node/recipe/session/framework/express";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import {
getUserMetadata,
updateUserInfo,
Expand Down
46 changes: 45 additions & 1 deletion api/scripts/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
purchasableMemberships,
tickets,
ticketsEventIdLinks,
questions,
questionsTicketIdLinks,
} from "../schemas/schema";

const main = async () => {
Expand All @@ -18,6 +20,8 @@ const main = async () => {
await db.delete(tickets);
await db.delete(ticketsEventIdLinks);
await db.delete(purchasableMemberships);
await db.delete(questions);
await db.delete(questionsTicketIdLinks);

// Add data
console.log("Seeding database");
Expand Down Expand Up @@ -234,7 +238,47 @@ const main = async () => {
]);

//Questions
await db.insert(questions).values([
{
id: 1,
question: "What is your dance partners' email?",
checkForMemberEmail: true,
publishedAt: new Date().toLocaleString(),
},
{
id: 2,
question: "What is your dance partners' name?",
checkForMemberEmail: false,
publishedAt: new Date().toLocaleString(),
},
{
id: 3,
question:
"Do you have any food allergies? Examples: Peanuts, Gluten, Milk",
checkForMemberEmail: false,
publishedAt: new Date().toLocaleString(),
},
]);

//QuestionTicketIdLink
await db.insert(questionsTicketIdLinks).values([
// Dance Series: Shawn Thomas
{
id: 1,
questionId: 1,
ticketId: 3,
},
{
id: 2,
questionId: 2,
ticketId: 3,
},
{
id: 3,
questionId: 3,
ticketId: 3,
},
]);

await db.insert(purchasableMemberships).values([
{
Expand All @@ -260,7 +304,7 @@ const main = async () => {
expiry: new Date(
new Date().setFullYear(new Date().getFullYear() + 1)
).toLocaleDateString(),
price: "15.00",
price: "16.00",
publishedAt: new Date().toISOString(),
},
]);
Expand Down
4 changes: 4 additions & 0 deletions web/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ coverage/
*.njsproj
*.sln
*.sw?
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"zod": "^3.23.8"
},
"devDependencies": {
"@playwright/test": "^1.49.1",
"@testing-library/dom": "^10.1.0",
"@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^16.0.0",
Expand Down
Loading

0 comments on commit fb1f185

Please sign in to comment.