Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions src/api/functions/auditLog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ import {
} from "@aws-sdk/client-dynamodb";
import { marshall } from "@aws-sdk/util-dynamodb";
import { genericConfig } from "common/config.js";
import { AUDIT_LOG_RETENTION_DAYS } from "common/constants.js";
import { AuditLogEntry } from "common/types/logs.js";

type AuditLogParams = {
dynamoClient?: DynamoDBClient;
entry: AuditLogEntry;
};

const RETENTION_DAYS = 365;

function buildMarshalledAuditLogItem(entry: AuditLogEntry) {
const baseNow = Date.now();
const timestamp = Math.floor(baseNow / 1000);
const expireAt =
timestamp + Math.floor((RETENTION_DAYS * 24 * 60 * 60 * 1000) / 1000);
timestamp +
Math.floor((AUDIT_LOG_RETENTION_DAYS * 24 * 60 * 60 * 1000) / 1000);

return marshall(
{
Expand Down
10 changes: 10 additions & 0 deletions src/api/routes/roomRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
getDefaultFilteringQuerystring,
nonEmptyCommaSeparatedStringSchema,
} from "common/utils.js";
import { ROOM_RESERVATION_RETENTION_DAYS } from "common/constants.js";

const roomRequestRoutes: FastifyPluginAsync = async (fastify, _options) => {
await fastify.register(rateLimiter, {
Expand Down Expand Up @@ -104,6 +105,9 @@ const roomRequestRoutes: FastifyPluginAsync = async (fastify, _options) => {
semesterId,
"createdAt#status": `${createdAt}#${request.body.status}`,
createdBy: request.username,
expiresAt:
Math.floor(Date.now() / 1000) +
86400 * ROOM_RESERVATION_RETENTION_DAYS,
...request.body,
},
{ removeUndefinedValues: true },
Expand Down Expand Up @@ -315,6 +319,9 @@ const roomRequestRoutes: FastifyPluginAsync = async (fastify, _options) => {
userId: request.username,
"userId#requestId": `${request.username}#${requestId}`,
semesterId: request.body.semester,
expiresAt:
Math.floor(Date.now() / 1000) +
86400 * ROOM_RESERVATION_RETENTION_DAYS,
};
const logStatement = buildAuditLogTransactPut({
entry: {
Expand Down Expand Up @@ -344,6 +351,9 @@ const roomRequestRoutes: FastifyPluginAsync = async (fastify, _options) => {
"createdAt#status": `${createdAt}#${RoomRequestStatus.CREATED}`,
createdBy: request.username,
status: RoomRequestStatus.CREATED,
expiresAt:
Math.floor(Date.now() / 1000) +
86400 * ROOM_RESERVATION_RETENTION_DAYS,
notes: "This request was created by the user.",
}),
},
Expand Down
16 changes: 14 additions & 2 deletions src/api/routes/stripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import { AvailableSQSFunctions, SQSPayload } from "common/types/sqsMessage.js";
import { SendMessageCommand, SQSClient } from "@aws-sdk/client-sqs";
import * as z from "zod/v4";
import { getAllUserEmails } from "common/utils.js";
import { STRIPE_LINK_RETENTION_DAYS } from "common/constants.js";

const stripeRoutes: FastifyPluginAsync = async (fastify, _options) => {
await fastify.register(rawbody, {
Expand Down Expand Up @@ -249,6 +250,9 @@ const stripeRoutes: FastifyPluginAsync = async (fastify, _options) => {
message: "Deactivated Stripe payment link",
},
});
// expire deleted links at 90 days
const expiresAt =
Math.floor(Date.now() / 1000) + 86400 * STRIPE_LINK_RETENTION_DAYS;
const dynamoCommand = new TransactWriteItemsCommand({
TransactItems: [
...(logStatement ? [logStatement] : []),
Expand All @@ -259,11 +263,12 @@ const stripeRoutes: FastifyPluginAsync = async (fastify, _options) => {
userId: { S: unmarshalledEntry.userId },
linkId: { S: linkId },
},
UpdateExpression: "SET active = :new_val",
UpdateExpression: "SET active = :new_val, expiresAt = :ttl",
ConditionExpression: "active = :old_val",
ExpressionAttributeValues: {
":new_val": { BOOL: false },
":old_val": { BOOL: true },
":ttl": { N: expiresAt.toString() },
},
},
},
Expand Down Expand Up @@ -666,11 +671,18 @@ Please contact Officer Board with any questions.`,
userId: { S: unmarshalledEntry.userId },
linkId: { S: paymentLinkId },
},
UpdateExpression: "SET active = :new_val",
UpdateExpression:
"SET active = :new_val, expiresAt = :ttl",
ConditionExpression: "active = :old_val",
ExpressionAttributeValues: {
":new_val": { BOOL: false },
":old_val": { BOOL: true },
":ttl": {
N: (
Math.floor(Date.now() / 1000) +
86400 * STRIPE_LINK_RETENTION_DAYS
).toString(),
},
},
},
},
Expand Down
10 changes: 8 additions & 2 deletions src/api/routes/tickets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { createAuditLogEntry } from "api/functions/auditLog.js";
import { Modules } from "common/modules.js";
import { FastifyZodOpenApiTypeProvider } from "fastify-zod-openapi";
import { withRoles, withTags } from "api/components/index.js";
import { FULFILLED_PURCHASES_RETENTION_DAYS } from "common/constants.js";

const postMerchSchema = z.object({
type: z.literal("merch"),
Expand Down Expand Up @@ -355,6 +356,9 @@ const ticketsPlugin: FastifyPluginAsync = async (fastify, _options) => {
message: "Could not find username.",
});
}
const expiresAt =
Math.floor(Date.now() / 1000) +
86400 * FULFILLED_PURCHASES_RETENTION_DAYS;
switch (request.body.type) {
case "merch":
ticketId = request.body.stripePi;
Expand All @@ -363,7 +367,7 @@ const ticketsPlugin: FastifyPluginAsync = async (fastify, _options) => {
Key: {
stripe_pi: { S: ticketId },
},
UpdateExpression: "SET fulfilled = :true_val",
UpdateExpression: "SET fulfilled = :true_val, expiresAt = :ttl",
ConditionExpression:
"#email = :email_val AND (attribute_not_exists(fulfilled) OR fulfilled = :false_val) AND (attribute_not_exists(refunded) OR refunded = :false_val)",
ExpressionAttributeNames: {
Expand All @@ -373,6 +377,7 @@ const ticketsPlugin: FastifyPluginAsync = async (fastify, _options) => {
":true_val": { BOOL: true },
":false_val": { BOOL: false },
":email_val": { S: request.body.email },
":ttl": { N: expiresAt.toString() },
},
ReturnValuesOnConditionCheckFailure: "ALL_OLD",
ReturnValues: "ALL_OLD",
Expand All @@ -385,7 +390,7 @@ const ticketsPlugin: FastifyPluginAsync = async (fastify, _options) => {
Key: {
ticket_id: { S: ticketId },
},
UpdateExpression: "SET #used = :trueValue",
UpdateExpression: "SET #used = :trueValue, expiresAt = :ttl",
ConditionExpression:
"(attribute_not_exists(#used) OR #used = :falseValue) AND (attribute_not_exists(refunded) OR refunded = :falseValue)",
ExpressionAttributeNames: {
Expand All @@ -394,6 +399,7 @@ const ticketsPlugin: FastifyPluginAsync = async (fastify, _options) => {
ExpressionAttributeValues: {
":trueValue": { BOOL: true },
":falseValue": { BOOL: false },
":ttl": { N: expiresAt.toString() },
},
ReturnValuesOnConditionCheckFailure: "ALL_OLD",
ReturnValues: "ALL_OLD",
Expand Down
4 changes: 4 additions & 0 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const STRIPE_LINK_RETENTION_DAYS = 90; // this number of days after the link is deactivated.
export const AUDIT_LOG_RETENTION_DAYS = 365;
export const ROOM_RESERVATION_RETENTION_DAYS = 730;
export const FULFILLED_PURCHASES_RETENTION_DAYS = 365; // ticketing/merch: after the purchase is marked as fulfilled.
4 changes: 3 additions & 1 deletion src/ui/pages/stripe/CurrentLinks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { notifications } from "@mantine/notifications";
import { useAuth } from "@ui/components/AuthContext";
import pluralize from "pluralize";
import dayjs from "dayjs";
import { STRIPE_LINK_RETENTION_DAYS } from "@common/constants";

const HumanFriendlyDate = ({ date }: { date: string | Date }) => {
return <Text size="sm">{dayjs(date).format("MMMM D, YYYY")}</Text>;
Expand Down Expand Up @@ -146,7 +147,8 @@ export const StripeCurrentLinksPanel: React.FC<
}
if (result.success > 0) {
notifications.show({
message: `Deactivated ${pluralize("link", result.success, true)}!`,
title: `Deactivated ${pluralize("link", result.success, true)}!`,
message: `Links will be permanently removed from this page after ${STRIPE_LINK_RETENTION_DAYS} days.`,
color: "green",
});
}
Expand Down
14 changes: 13 additions & 1 deletion terraform/modules/dynamo/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ resource "aws_dynamodb_table" "app_audit_log" {
}
ttl {
attribute_name = "expiresAt"
enabled = true
enabled = false
}
}

Expand Down Expand Up @@ -80,6 +80,10 @@ resource "aws_dynamodb_table" "room_requests" {
hash_key = "requestId"
projection_type = "ALL"
}
ttl {
attribute_name = "expiresAt"
enabled = true
}
}


Expand Down Expand Up @@ -110,6 +114,10 @@ resource "aws_dynamodb_table" "room_requests_status" {
range_key = "requestId"
projection_type = "ALL"
}
ttl {
attribute_name = "expiresAt"
enabled = true
}
}


Expand Down Expand Up @@ -224,6 +232,10 @@ resource "aws_dynamodb_table" "stripe_links" {
hash_key = "linkId"
projection_type = "ALL"
}
ttl {
attribute_name = "expiresAt"
enabled = true
}
}

resource "aws_dynamodb_table" "linkry_records" {
Expand Down
Loading