Skip to content

Commit c2b76c4

Browse files
committed
basic API done
1 parent 782ba3f commit c2b76c4

File tree

4 files changed

+70
-13
lines changed

4 files changed

+70
-13
lines changed

generate_jwt.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import jwt from 'jsonwebtoken';
22

3+
const username = process.env.JWTGEN_USERNAME || '[email protected]'
34
const payload = {
45
aud: "custom_jwt",
56
iss: "custom_jwt",
@@ -11,7 +12,7 @@ const payload = {
1112
amr: ["pwd"],
1213
appid: "your-app-id",
1314
appidacr: "1",
14-
15+
email: username,
1516
groups: ["0"],
1617
idp: "https://login.microsoftonline.com",
1718
ipaddr: "192.168.1.1",
@@ -21,11 +22,13 @@ const payload = {
2122
scp: "user_impersonation",
2223
sub: "subject",
2324
tid: "tenant-id",
24-
unique_name: "[email protected]",
25+
unique_name: username,
2526
uti: "uti-value",
2627
ver: "1.0"
2728
};
2829

2930
const secretKey = process.env.JwtSigningKey;
3031
const token = jwt.sign(payload, secretKey, { algorithm: 'HS256' });
32+
console.log(`USERNAME=${username}`)
33+
console.log('=====================')
3134
console.log(token)

src/errors/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,15 @@ export class DatabaseInsertError extends BaseError<"DatabaseInsertError"> {
9292
});
9393
}
9494
}
95+
96+
97+
export class DatabaseFetchError extends BaseError<"DatabaseFetchError"> {
98+
constructor({ message }: { message: string }) {
99+
super({
100+
name: "DatabaseFetchError",
101+
id: 106,
102+
message,
103+
httpStatusCode: 500,
104+
});
105+
}
106+
}

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import protectedRoute from "./routes/protected.js";
77
import errorHandlerPlugin from "./plugins/errorHandler.js";
88
import { RunEnvironment, runEnvironments } from "./roles.js";
99
import { InternalServerError } from "./errors/index.js";
10-
import createEvent from "./routes/event.js";
10+
import eventsPlugin from "./routes/events.js";
1111

1212
const now = () => Date.now();
1313

@@ -58,7 +58,7 @@ async function init() {
5858
await app.register(
5959
async (api, _options) => {
6060
api.register(protectedRoute, { prefix: "/protected" });
61-
api.register(createEvent, { prefix: "/event" });
61+
api.register(eventsPlugin, { prefix: "/events" });
6262
},
6363
{ prefix: "/api/v1" },
6464
);

src/routes/event.ts renamed to src/routes/events.ts

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,30 @@ import { AppRoles } from "../roles.js";
33
import { z } from "zod";
44
import { zodToJsonSchema } from "zod-to-json-schema";
55
import { OrganizationList } from "../orgs.js";
6-
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";
7-
import { marshall } from "@aws-sdk/util-dynamodb";
6+
import {
7+
DynamoDBClient,
8+
PutItemCommand,
9+
ScanCommand,
10+
} from "@aws-sdk/client-dynamodb";
11+
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
812
import config from "../config.js";
9-
import { DatabaseInsertError } from "../errors/index.js";
13+
import { DatabaseFetchError, DatabaseInsertError } from "../errors/index.js";
1014
import { randomUUID } from "crypto";
1115

16+
// POST
17+
1218
const repeatOptions = ["weekly", "biweekly"] as const;
1319

1420
const requestBodySchema = z.object({
1521
title: z.string().min(1),
1622
description: z.string().min(1),
17-
start: z.string().datetime(),
18-
end: z.optional(z.string().datetime()),
23+
start: z.string(),
24+
end: z.optional(z.string()),
1925
location: z.string(),
2026
locationLink: z.optional(z.string().url()),
2127
repeats: z.optional(z.enum(repeatOptions)),
2228
host: z.enum(OrganizationList),
29+
featured: z.boolean().default(false)
2330
});
2431
const requestJsonSchema = zodToJsonSchema(requestBodySchema);
2532
type EventPostRequest = z.infer<typeof requestBodySchema>;
@@ -31,11 +38,15 @@ const responseJsonSchema = zodToJsonSchema(
3138
}),
3239
);
3340

41+
// GET
42+
const getResponseBodySchema = z.array(requestBodySchema);
43+
const getResponseJsonSchema = zodToJsonSchema(getResponseBodySchema);
44+
3445
const dynamoClient = new DynamoDBClient({
3546
region: process.env.AWS_REGION || "us-east-1",
3647
});
3748

38-
const createEvent: FastifyPluginAsync = async (fastify, _options) => {
49+
const eventsPlugin: FastifyPluginAsync = async (fastify, _options) => {
3950
fastify.post<{ Body: EventPostRequest }>(
4051
"/",
4152
{
@@ -50,10 +61,14 @@ const createEvent: FastifyPluginAsync = async (fastify, _options) => {
5061
async (request, reply) => {
5162
try {
5263
const entryUUID = randomUUID().toString();
53-
const dynamoResponse = await dynamoClient.send(
64+
await dynamoClient.send(
5465
new PutItemCommand({
5566
TableName: config.DYNAMO_TABLE_NAME,
56-
Item: marshall({ ...request.body, id: entryUUID }),
67+
Item: marshall({
68+
...request.body,
69+
id: entryUUID,
70+
createdBy: request.username,
71+
}),
5772
}),
5873
);
5974
reply.send({
@@ -70,6 +85,33 @@ const createEvent: FastifyPluginAsync = async (fastify, _options) => {
7085
}
7186
},
7287
);
88+
fastify.get<{ Body: undefined }>(
89+
"/",
90+
{
91+
schema: {
92+
response: { 200: getResponseJsonSchema },
93+
},
94+
onRequest: async (request, reply) => {
95+
await fastify.authorize(request, reply, [AppRoles.MANAGER]);
96+
},
97+
},
98+
async (request, reply) => {
99+
try {
100+
const response = await dynamoClient.send(
101+
new ScanCommand({ TableName: config.DYNAMO_TABLE_NAME }),
102+
);
103+
const items = response.Items?.map(item => unmarshall(item))
104+
reply.send(getResponseBodySchema.parse(items));
105+
} catch (e: unknown) {
106+
if (e instanceof Error) {
107+
request.log.error("Failed to get from DynamoDB: " + e.toString());
108+
}
109+
throw new DatabaseFetchError({
110+
message: "Failed to get events from Dynamo table.",
111+
});
112+
}
113+
},
114+
);
73115
};
74116

75-
export default createEvent;
117+
export default eventsPlugin;

0 commit comments

Comments
 (0)