Skip to content

Commit

Permalink
add the ability to get the metadata for events
Browse files Browse the repository at this point in the history
  • Loading branch information
devksingh4 committed Nov 14, 2024
1 parent 36f1e00 commit a179462
Show file tree
Hide file tree
Showing 6 changed files with 400 additions and 1 deletion.
5 changes: 5 additions & 0 deletions cloudformation/iam.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ Resources:
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-purchase-history
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-tickets
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-tickets/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-ticketing-metadata/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-events-ticketing-metadata
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-metadata/*
- !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/infra-merchstore-metadata

PolicyName: lambda-dynamo
Outputs:
MainFunctionRoleArn:
Expand Down
4 changes: 4 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type GenericConfigType = {
EntraTenantId: string;
MerchStorePurchasesTableName: string;
TicketPurchasesTableName: string;
TicketMetadataTableName: string;
MerchStoreMetadataTableName: string;
};

type EnvironmentConfigType = {
Expand All @@ -41,7 +43,9 @@ const genericConfig: GenericConfigType = {
AwsRegion: process.env.AWS_REGION || "us-east-1",
EntraTenantId: "c8d9148f-9a59-4db3-827d-42ea0c2b6e2e",
MerchStorePurchasesTableName: "infra-merchstore-purchase-history",
MerchStoreMetadataTableName: "infra-merchstore-metadata",
TicketPurchasesTableName: "infra-events-tickets",
TicketMetadataTableName: "infra-events-ticketing-metadata",
} as const;

const environmentConfig: EnvironmentConfigType = {
Expand Down
99 changes: 99 additions & 0 deletions src/routes/tickets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { z } from "zod";
import {
DynamoDBClient,
QueryCommand,
ScanCommand,
UpdateItemCommand,
} from "@aws-sdk/client-dynamodb";
import { genericConfig } from "../config.js";
Expand Down Expand Up @@ -64,6 +65,31 @@ const getTicketsResponseJsonSchema = zodToJsonSchema(
}),
);

const baseItemMetadata = z.object({
itemId: z.string().min(1),
itemName: z.string().min(1),
itemSalesActive: z.union([z.date(), z.literal(false)]),
priceDollars: z.object({
member: z.number().min(0),
nonMember: z.number().min(0),
}),
});

const ticketingItemMetadata = baseItemMetadata.extend({
eventCapacity: z.number(),
ticketsSold: z.number(),
});

type ItemMetadata = z.infer<typeof baseItemMetadata>;
type TicketItemMetadata = z.infer<typeof ticketingItemMetadata>;

const listMerchItemsResponseJsonSchema = zodToJsonSchema(
z.object({
merch: z.array(baseItemMetadata),
tickets: z.array(ticketingItemMetadata),
}),
);

const postSchema = z.union([postMerchSchema, postTicketSchema]);

type VerifyPostRequest = z.infer<typeof postSchema>;
Expand All @@ -78,7 +104,80 @@ type TicketsGetRequest = {
Body: undefined;
};

type TicketsListRequest = {
Params: undefined;
Querystring: undefined;
Body: undefined;
};

const ticketsPlugin: FastifyPluginAsync = async (fastify, _options) => {
fastify.get<TicketsListRequest>(
"/",
{
schema: {
response: {
200: listMerchItemsResponseJsonSchema,
},
},
onRequest: async (request, reply) => {
await fastify.authorize(request, reply, [AppRoles.TICKETS_MANAGER]);
},
},
async (request, reply) => {
const merchCommand = new ScanCommand({
TableName: genericConfig.MerchStoreMetadataTableName,
ProjectionExpression: "item_id, item_name, item_sales_active_utc",
});
const merchItems: ItemMetadata[] = [];
const response = await dynamoClient.send(merchCommand);
if (response.Items) {
for (const item of response.Items.map((x) => unmarshall(x))) {
const memberPrice = parseInt(item.item_price?.paid, 10) || 0;
const nonMemberPrice = parseInt(item.item_price?.others, 10) || 0;
merchItems.push({
itemId: item.item_id,
itemName: item.item_name,
itemSalesActive:
item.item_sales_active_utc === -1
? false
: new Date(parseInt(item.item_sales_active_utc, 10)),
priceDollars: {
member: memberPrice,
nonMember: nonMemberPrice,
},
});
}
}
const ticketCommand = new ScanCommand({
TableName: genericConfig.TicketMetadataTableName,
ProjectionExpression:
"event_id, event_name, event_sales_active_utc, event_capacity, tickets_sold",
});
const ticketItems: TicketItemMetadata[] = [];
const ticketResponse = await dynamoClient.send(ticketCommand);
if (ticketResponse.Items) {
for (const item of ticketResponse.Items.map((x) => unmarshall(x))) {
const memberPrice = parseInt(item.eventCost?.paid, 10) || 0;
const nonMemberPrice = parseInt(item.eventCost?.others, 10) || 0;
ticketItems.push({
itemId: item.event_id,
itemName: item.event_name,
itemSalesActive:
item.event_sales_active_utc === -1
? false
: new Date(parseInt(item.event_sales_active_utc, 10)),
eventCapacity: item.event_capacity,
ticketsSold: item.tickets_sold,
priceDollars: {
member: memberPrice,
nonMember: nonMemberPrice,
},
});
}
}
reply.send({ merch: merchItems, tickets: ticketItems });
},
);
fastify.get<TicketsGetRequest>(
"/:eventId",
{
Expand Down
230 changes: 230 additions & 0 deletions tests/unit/data/mockTIcketsMerchMetadata.testdata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
const merchMetadata = [
{
item_id: {
S: "2024_spr_tshirt",
},
item_email_desc: {
S: "Please pick up your item in the ACM room on Wednesdays between 6pm and 6:30pm.",
},
item_image: {
S: "img/tshirt.png",
},
item_name: {
S: "ACM T-Shirt: Spring 2024 Series",
},
item_price: {
M: {
others: {
N: "26",
},
paid: {
N: "22",
},
},
},
item_sales_active_utc: {
N: "0",
},
member_price: {
S: "price_1OchTUDiGOXU9RuSQXnpbSHS",
},
nonmember_price: {
S: "price_1OchTrDiGOXU9RuStYC6XgXp",
},
sizes: {
L: [
{
S: "S",
},
{
S: "M",
},
{
S: "L",
},
{
S: "XL",
},
],
},
total_avail: {
M: {
L: {
N: "10",
},
M: {
N: "22",
},
S: {
N: "23",
},
XL: {
N: "9",
},
},
},
},
{
item_id: {
S: "2024_fa_barcrawl",
},
item_email_desc: {
S: "Shirts will be availiable for pickup one week before the event. Check your email near then for more details. Make sure to join the ACM Discord for updates!",
},
item_image: {
S: "img/barcrawl_fa24_design.png",
},
item_name: {
S: "ACM Bar Crawl: Fall 2024 (Nov 14)",
},
item_price: {
M: {
others: {
N: "18",
},
paid: {
N: "15",
},
},
},
item_sales_active_utc: {
N: "0",
},
member_price: {
S: "price_1QFSCiDiGOXU9RuSNJ90SblG",
},
nonmember_price: {
S: "price_1QFSDVDiGOXU9RuSEUH0DQtx",
},
ready_for_pickup: {
BOOL: false,
},
sizes: {
L: [
{
S: "S",
},
{
S: "M",
},
{
S: "L",
},
{
S: "XL",
},
{
S: "2XL",
},
],
},
total_avail: {
M: {
"2XL": {
N: "2",
},
L: {
N: "22",
},
M: {
N: "0",
},
S: {
N: "7",
},
XL: {
N: "1",
},
},
},
},
];

const ticketsMetadata = [
{
event_id: {
S: "fa23_barcrawl",
},
eventCost: {
M: {
others: {
N: "18",
},
paid: {
N: "15",
},
},
},
eventDetails: {
S: "Join ACM and meet your fellow members as we visit KAMS, Joe's, and Legends on our semesterly bar crawl! Get a free t-shirt with sign-up! Alcohol will be provided by ACM to members over 21 wearing bar crawl t-shirts. We will also be hosting an official pregame (details released closer to the event)! This ticket does not pay for cover at the bars.",
},
eventImage: {
S: "img/bar_crawl_fa23.png",
},
event_capacity: {
N: "130",
},
event_name: {
S: "ACM Fall 2023 Bar Crawl",
},
event_sales_active_utc: {
N: "-1",
},
event_time: {
N: "1699578000",
},
member_price: {
S: "price_1O6mXBDiGOXU9RuS2ZfBXaEc",
},
nonmember_price: {
S: "price_1O6mXBDiGOXU9RuSq7PUcC1C",
},
tickets_sold: {
N: "55",
},
},
{
event_id: {
S: "fa22_barcrawl",
},
eventCost: {
M: {
others: {
N: "18",
},
paid: {
N: "15",
},
},
},
eventDetails: {
S: "Join ACM and meet your fellow members as we visit KAMS, Joe's, and Legends on our semesterly bar crawl! Get a free t-shirt with sign-up! Alcohol will be provided by ACM to members over 21 wearing bar crawl t-shirts. We will also be hosting an official pregame (details released closer to the event)! This ticket does not pay for cover at the bars.",
},
eventImage: {
S: "img/bar_crawl_fa23.png",
},
event_capacity: {
N: "130",
},
event_name: {
S: "ACM Fall 2023 Bar Crawl",
},
event_sales_active_utc: {
N: "-1",
},
event_time: {
N: "1699578000",
},
member_price: {
S: "price_1O6mXBDiGOXU9RuS2ZfBXaEc",
},
nonmember_price: {
S: "price_1O6mXBDiGOXU9RuSq7PUcC1C",
},
tickets_sold: {
N: "55",
},
},
];

export { merchMetadata, ticketsMetadata };
1 change: 0 additions & 1 deletion tests/unit/entraInviteUser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ vi.mock("../../src/functions/entraId.js", () => {
return "ey.test.token";
}),
addToTenant: vi.fn().mockImplementation(async (email) => {

Check warning on line 19 in tests/unit/entraInviteUser.test.ts

View workflow job for this annotation

GitHub Actions / Run Unit Tests

'email' is defined but never used. Allowed unused args must match /^_/u
console.log("FUCK", email);
return { success: true, email: "[email protected]" };
}),
};
Expand Down
Loading

0 comments on commit a179462

Please sign in to comment.