Skip to content

Commit

Permalink
setup the redirect route
Browse files Browse the repository at this point in the history
  • Loading branch information
devksingh4 committed Jan 13, 2025
1 parent 7b66f40 commit 04bc57d
Show file tree
Hide file tree
Showing 8 changed files with 539 additions and 16 deletions.
6 changes: 6 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off"
}
},
{
"files": ["src/api/*", "src/api/**/*"],
"rules": {
"import/no-nodejs-modules": "off"
}
}
]
}
11 changes: 10 additions & 1 deletion src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint import/no-nodejs-modules: ["error", {"allow": ["crypto"]}] */
import { randomUUID } from "crypto";
import fastify, { FastifyInstance } from "fastify";
import FastifyAuthProvider from "@fastify/auth";
Expand All @@ -18,6 +17,9 @@ import * as dotenv from "dotenv";
import iamRoutes from "./routes/iam.js";
import ticketsPlugin from "./routes/tickets.js";
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
import linkryRoutes from "./routes/linkry.js";
import path from "node:path";
import { fileURLToPath } from "node:url";

dotenv.config();

Expand Down Expand Up @@ -53,6 +55,12 @@ async function init() {
return event.requestContext.requestId;
},
});
const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
const __dirname = path.dirname(__filename);
await app.register(import("@fastify/static"), {
root: path.join(__dirname, "public"),
});

await app.register(fastifyAuthPlugin);
await app.register(fastifyZodValidationPlugin);
await app.register(FastifyAuthProvider);
Expand Down Expand Up @@ -97,6 +105,7 @@ async function init() {
api.register(icalPlugin, { prefix: "/ical" });
api.register(iamRoutes, { prefix: "/iam" });
api.register(ticketsPlugin, { prefix: "/tickets" });
api.register(linkryRoutes, { prefix: "/linkry" });
if (app.runEnvironment === "dev") {
api.register(vendingPlugin, { prefix: "/vending" });
}
Expand Down
6 changes: 5 additions & 1 deletion src/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
"prettier:write": "prettier --write *.ts **/*.ts"
},
"dependencies": {
"@aws-sdk/client-sts": "^3.726.0"
"@aws-sdk/client-sts": "^3.726.0",
"@fastify/static": "^8.0.4"
},
"devDependencies": {
"@types/ejs": "^3.1.5"
}
}
65 changes: 65 additions & 0 deletions src/api/public/404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Not Found | ACM @ UIUC</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #1a1a1a;
color: #ffffff;
font-family: Arial, sans-serif;
text-align: center;
}

.container {
max-width: 600px;
}

h1 {
font-size: 10rem;
margin: 0;
color: #ffffff;
}

h1 span {
color: #ffa500;
}

p {
margin-top: 1rem;
font-size: 1.5rem;
color: #aaaaaa;
}

footer {
margin-top: 2rem;
font-size: 0.9rem;
color: #666666;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', () => {
const yearElement = document.getElementById('year');
const currentYear = new Date().getFullYear();
yearElement.textContent = currentYear;
});
</script>
</head>

<body>
<div class="container">
<h1>4<span>0</span>4</h1>
<p>The page you are looking for could not be found.</p>
<footer>&copy; <span id="year"></span> ACM @ UIUC</footer>
</div>
</body>

</html>
Binary file added src/api/public/favicon.ico
Binary file not shown.
52 changes: 48 additions & 4 deletions src/api/routes/linkry.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { FastifyPluginAsync } from "fastify";
import { z } from "zod";
import { AppRoles } from "../../common/roles.js";
import { NotImplementedError } from "../../common/errors/index.js";
import {
BaseError,
DatabaseFetchError,
NotFoundError,

Check warning on line 7 in src/api/routes/linkry.ts

View workflow job for this annotation

GitHub Actions / Run Unit Tests

'NotFoundError' is defined but never used. Allowed unused vars must match /^_/u
NotImplementedError,
} from "../../common/errors/index.js";
import { intersection } from "../plugins/auth.js";

Check warning on line 10 in src/api/routes/linkry.ts

View workflow job for this annotation

GitHub Actions / Run Unit Tests

'intersection' is defined but never used. Allowed unused vars must match /^_/u
import { NoDataRequest } from "../types.js";
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
import { environmentConfig, genericConfig } from "common/config.js";

Check warning on line 13 in src/api/routes/linkry.ts

View workflow job for this annotation

GitHub Actions / Run Unit Tests

'environmentConfig' is defined but never used. Allowed unused vars must match /^_/u
import { unmarshall } from "@aws-sdk/util-dynamodb";

type LinkrySlugOnlyRequest = {
Params: { id: string };
Expand All @@ -13,12 +21,12 @@ type LinkrySlugOnlyRequest = {

const rawRequest = {
slug: z.string().min(1),
full: z.string().url().min(1),
redirect: z.string().url().min(1),
groups: z.optional(z.array(z.string()).min(1)),
};

const createRequest = z.object(rawRequest);
const patchRequest = z.object({ ...rawRequest, slug: z.undefined() });
const patchRequest = z.object({ redirect: z.string().url().min(1) });

type LinkyCreateRequest = {
Params: undefined;
Expand All @@ -32,9 +40,44 @@ type LinkryPatchRequest = {
Body: z.infer<typeof patchRequest>;
};

const dynamoClient = new DynamoDBClient({
region: genericConfig.AwsRegion,
});

const linkryRoutes: FastifyPluginAsync = async (fastify, _options) => {
fastify.get<LinkrySlugOnlyRequest>("/redir/:id", async (request, reply) => {
throw new NotImplementedError({});
const id = request.params.id;
const command = new QueryCommand({
TableName: genericConfig.LinkryDynamoTableName,
KeyConditionExpression:
"#slug = :slugVal AND begins_with(#access, :accessVal)",
ExpressionAttributeNames: {
"#slug": "slug",
"#access": "access",
},
ExpressionAttributeValues: {
":slugVal": { S: id },
":accessVal": { S: "OWNER#" },
},
});
try {
const result = await dynamoClient.send(command);
if (!result || !result.Items || result.Items.length === 0) {
return reply
.headers({ "content-type": "text/html" })
.status(404)
.sendFile("404.html");
}
return reply.redirect(unmarshall(result.Items[0]).redirect);
} catch (e) {
if (e instanceof BaseError) {
throw e;
}
request.log.error(e);
throw new DatabaseFetchError({
message: "Could not retrieve mapping, please try again later.",
});
}
});
fastify.post<LinkyCreateRequest>(
"/redir",
Expand Down Expand Up @@ -68,6 +111,7 @@ const linkryRoutes: FastifyPluginAsync = async (fastify, _options) => {
},
async (request, reply) => {

Check warning on line 112 in src/api/routes/linkry.ts

View workflow job for this annotation

GitHub Actions / Run Unit Tests

'request' is defined but never used. Allowed unused args must match /^_/u
// make sure that a user can manage this link, either via owning or being in a group that has access to it, or is a LINKS_ADMIN.
// you can only change the URL it redirects to
throw new NotImplementedError({});
},
);
Expand Down
2 changes: 2 additions & 0 deletions src/common/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type ConfigType = {
type GenericConfigType = {
EventsDynamoTableName: string;
CacheDynamoTableName: string;
LinkryDynamoTableName: string;
ConfigSecretName: string;
UpcomingEventThresholdSeconds: number;
AwsRegion: string;
Expand All @@ -46,6 +47,7 @@ export const execCouncilTestingGroupId = "dbe18eb2-9675-46c4-b1ef-749a6db4fedd";
const genericConfig: GenericConfigType = {
EventsDynamoTableName: "infra-core-api-events",
CacheDynamoTableName: "infra-core-api-cache",
LinkryDynamoTableName: "infra-core-api-linkry",
ConfigSecretName: "infra-core-api-config",
UpcomingEventThresholdSeconds: 1800, // 30 mins
AwsRegion: process.env.AWS_REGION || "us-east-1",
Expand Down
Loading

0 comments on commit 04bc57d

Please sign in to comment.