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
4 changes: 2 additions & 2 deletions db/tables/departments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { teamsTable } from "@db/tables/team";
import { relations } from "drizzle-orm";
import { serial } from "drizzle-orm/pg-core";

export const cities = mainSchema.enum("city", [
export const citiesEnum = mainSchema.enum("city", [
"Trondheim",
"Ås",
"Bergen",
Expand All @@ -13,7 +13,7 @@ export const cities = mainSchema.enum("city", [

export const departmentsTable = mainSchema.table("departments", {
id: serial("id").primaryKey(),
city: cities("city").notNull(),
city: citiesEnum("city").notNull(),
});

export const departmentsRelations = relations(departmentsTable, ({ many }) => ({
Expand Down
29 changes: 29 additions & 0 deletions db/tables/sponsors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { relations } from "drizzle-orm";
import { date, integer, serial, text } from "drizzle-orm/pg-core";
import { departmentsTable } from "./departments";
import mainSchema from "./schema";

export const sponsorSizeEnum = mainSchema.enum("size", [
"small",
"medium",
"large",
]);

export const sponsorsTable = mainSchema.table("sponsors", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
homePageURL: text("homePageURL").notNull(),
startDate: date("startDate", { mode: "date" }).notNull(),
endDate: date("endDate", { mode: "date" }),
size: sponsorSizeEnum("size").notNull(),
spesificDepartmentId: integer("spesificDepartmentId").references(
() => departmentsTable.id,
),
});

export const sponsorsRelations = relations(sponsorsTable, ({ one }) => ({
department: one(departmentsTable, {
fields: [sponsorsTable.spesificDepartmentId],
references: [departmentsTable.id],
}),
}));
42 changes: 42 additions & 0 deletions src/db-access/sponsors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { database } from "@db/setup/queryPostgres";
import { sponsorsTable } from "@db/tables/sponsors";
import {
type ORMResult,
handleDatabaseFullfillment,
handleDatabaseRejection,
ormError,
} from "@src/error/ormError";
import type { NewSponsor } from "@src/request-handling/sponsors";
import type { Sponsor, SponsorKey } from "@src/response-handling/sponsors";
import { inArray } from "drizzle-orm";

export async function insertSponsors(
sponsors: NewSponsor[],
): Promise<ORMResult<Sponsor[]>> {
return database
.transaction(async (tx) => {
const insertResult = await tx
.insert(sponsorsTable)
.values(sponsors)
.returning();
return insertResult;
})
.then(handleDatabaseFullfillment, handleDatabaseRejection);
}

export async function selectSponsorsById(
sponsorIds: SponsorKey[],
): Promise<ORMResult<Sponsor[]>> {
return database
.transaction(async (tx) => {
const selectResult = await tx
.select()
.from(sponsorsTable)
.where(inArray(sponsorsTable.id, sponsorIds));
if (selectResult.length !== sponsorIds.length) {
throw ormError("Couldn't select sponsors, id's didn's exist.");
}
return selectResult;
})
.then(handleDatabaseFullfillment, handleDatabaseRejection);
}
3 changes: 3 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { teamApplicationRouter } from "./routers/team_application";

import { openapiSpecification } from "@src/openapi/config";
import openapiExpressHandler from "swagger-ui-express";
import { sponsorsRouter } from "./routers/sponsors";
import { usersRouter } from "./routers/users";

const app = express();
Expand All @@ -33,6 +34,8 @@ app.use("/", logger);
app.use("/expense", expenseRouter);
app.use("/expenses", expensesRouter);

app.use("/sponsors", sponsorsRouter);

app.use("/users", usersRouter);

app.use("/teamapplications", teamApplicationRouter);
Expand Down
4 changes: 4 additions & 0 deletions src/openapi/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import {
sortParser,
} from "@src/request-handling/common";
import { expenseRequestParser } from "@src/request-handling/expenses";
import { sponsorRequestParser } from "@src/request-handling/sponsors";
import { teamApplicationParser } from "@src/request-handling/team_application";
import {
assistantUserRequestParser,
teamUserRequestParser,
userRequestParser,
} from "@src/request-handling/users";
import { expensesSelectSchema } from "@src/response-handling/expenses";
import { sponsorsSelectSchema } from "@src/response-handling/sponsors";
import { teamApplicationSelectSchema } from "@src/response-handling/team_application";
import {
assistantUserSelectSchema,
Expand Down Expand Up @@ -70,6 +72,8 @@ const openapiDocument = createDocument({
schemas: {
expenseRequest: expenseRequestParser,
expense: expensesSelectSchema,
sponsorRequest: sponsorRequestParser,
sponsor: sponsorsSelectSchema,
user: userSelectSchema,
teamUser: teamUserSelectSchema,
assistantUser: assistantUserSelectSchema,
Expand Down
5 changes: 2 additions & 3 deletions src/request-handling/expenses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { z } from "zod";
export const expenseRequestParser = z
.object({
userId: serialIdParser.describe("Id of user requesting expense"),
title: z.string().nonempty().describe("Title of expense"),
title: z.string().min(1).describe("Title of expense"),
moneyAmount: currencyParser.describe("Amount of money used"),
description: z.string().nonempty().describe("Description of expense"),
description: z.string().min(1).describe("Description of expense"),
bankAccountNumber: z
.string()
.length(11)
Expand All @@ -37,4 +37,3 @@ export const expenseRequestToInsertParser = expenseRequestParser
.pipe(createInsertSchema(expensesTable).strict().readonly());

export type NewExpense = z.infer<typeof expenseRequestToInsertParser>;
type foo = NewExpense["handlingDate"];
39 changes: 39 additions & 0 deletions src/request-handling/sponsors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { sponsorsTable } from "@db/tables/sponsors";
import { createInsertSchema } from "drizzle-zod";
import { z } from "zod";
import { serialIdParser } from "./common";

export const sponsorRequestParser = z
.object({
id: serialIdParser.describe("Id of sponsor"),
name: z.string().describe("Name of sponsor"),
homePageURL: z.string().url().describe("URL to homepage of sponsor"),
startDate: z
.string()
.date("Must be valid datestring (YYYY-MM-DD")
.describe("Date when sponsor started support"),
endDate: z
.string()
.date("Must be valid datestring (YYYY-MM-DD")
.nullable()
.describe("Date when sponsor ended support"),
size: z
.enum(["small", "medium", "large"])
.describe("Size of sponsor support"),
spesificDepartmentId: serialIdParser
.nullable()
.describe("Id of department that sponsor is connected to"),
})
.strict();

export const sponsorRequestToInsertParser = sponsorRequestParser
.extend({
name: sponsorRequestParser.shape.name.trim(),
startDate: sponsorRequestParser.shape.startDate.pipe(
z.coerce.date().max(new Date()),
),
endDate: sponsorRequestParser.shape.endDate.pipe(z.coerce.date()),
})
.pipe(createInsertSchema(sponsorsTable).strict().readonly());

export type NewSponsor = z.infer<typeof sponsorRequestToInsertParser>;
10 changes: 10 additions & 0 deletions src/response-handling/sponsors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { sponsorsTable } from "@db/tables/sponsors";
import { createSelectSchema } from "drizzle-zod";
import type { z } from "zod";

export const sponsorsSelectSchema = createSelectSchema(sponsorsTable)
.strict()
.readonly();

export type Sponsor = z.infer<typeof sponsorsSelectSchema>;
export type SponsorKey = Sponsor["id"];
76 changes: 76 additions & 0 deletions src/routers/sponsors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { insertSponsors, selectSponsorsById } from "@src/db-access/sponsors";
import { clientError } from "@src/error/httpErrors";
import { toSerialIdParser } from "@src/request-handling/common";
import { sponsorRequestToInsertParser } from "@src/request-handling/sponsors";
import { Router, json } from "express";

export const sponsorsRouter = Router();
sponsorsRouter.use(json());

/**
* @openapi
* /sponsors/:
* post:
* tags: [sponsors]
* summary: Add sponsor
* description: Add sponsor
* requestBody:
* required: true
* content:
* json:
* schema:
* $ref: "#/components/schemas/sponsorRequest"
* responses:
* 201:
* description: Successfull response
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/sponsor"
*/
sponsorsRouter.post("/", async (req, res, next) => {
const sponsorRequest = sponsorRequestToInsertParser.safeParse(req.body);
if (!sponsorRequest.success) {
const error = clientError(
400,
"Failed parsing sponsorrequest.",
sponsorRequest.error,
);
return next(error);
}
const databaseResult = await insertSponsors([sponsorRequest.data]);
if (!databaseResult.success) {
const error = clientError(400, "Database error", databaseResult.error);
return next(error);
}
res.status(201).json(databaseResult.data);
});

/**
* @openapi
* /sponsors/{id}/:
* get:
* tags: [sponsors]
* summary: Get sponsor with id
* description: Get sponsor with id
* parameters:
* - $ref: "#/components/parameters/id"
* responses:
* 200:
* description: Successfull response
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/sponsor"
*/
sponsorsRouter.get("/:sponsorId", async (req, res, next) => {
const sponsorIdResult = toSerialIdParser.safeParse(req.params.sponsorId);
if (!sponsorIdResult.success) {
return next(clientError(400, "", sponsorIdResult.error));
}
const databaseResult = await selectSponsorsById([sponsorIdResult.data]);
if (!databaseResult.success) {
return next(clientError(400, "Database error", databaseResult.error));
}
res.json(databaseResult.data);
});