From 315734c143b037838855ef697cd2cf417e6aacad Mon Sep 17 00:00:00 2001 From: solvhold Date: Mon, 16 Mar 2026 17:26:38 +0100 Subject: [PATCH 1/3] feat: :sparkles: add teams parser issue: #127 --- openapi/config.ts | 2 ++ src/request-handling/teams.ts | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/request-handling/teams.ts diff --git a/openapi/config.ts b/openapi/config.ts index 3ee5199..a32675b 100644 --- a/openapi/config.ts +++ b/openapi/config.ts @@ -27,6 +27,7 @@ import { } from "@/src/response-handling/users"; import openapiFromJsdoc from "swagger-jsdoc"; import { createDocument } from "zod-openapi"; +import { teamsRequestParser } from "@/src/request-handling/teams"; const openapiDocument = createDocument({ openapi: "3.1.0", @@ -84,6 +85,7 @@ const openapiDocument = createDocument({ datePeriod: datePeriodParser, teamApplication: teamApplicationSelectSchema, teamApplicationRequest: teamApplicationParser, + teams: teamsRequestParser }, parameters: { id: serialIdParser.openapi({ param: { in: "path", name: "id" } }), diff --git a/src/request-handling/teams.ts b/src/request-handling/teams.ts new file mode 100644 index 0000000..f023a08 --- /dev/null +++ b/src/request-handling/teams.ts @@ -0,0 +1,36 @@ +import { expensesTable } from "@/db/tables/expenses"; +import { timeStringParser } from "@/lib/time-parsers"; +import { serialIdParser } from "@/src/request-handling/common"; +import { createInsertSchema } from "drizzle-zod"; +import { z } from "zod"; + +export const teamsRequestParser = z + .object({ + departmentId: serialIdParser.describe("Id of corresponding department"), + name: z.string().min(1).describe("Name of team"), + email: z.string().email().describe("Email of team"), + description: z.string().min(1).describe("Description of team"), + shortDescription: z + .string() + .min(1) + .describe("Short description of team"), + acceptApplication: z + .boolean() + .describe("Whether the team is accepting applications or not"), + active: z.boolean().describe("Whether the team is active or not"), + deadline: timeStringParser.describe( + "Deadline for applying to the team", + ), + }) + .strict(); + +export const teamsRequestToInsertParser = teamsRequestParser + .extend({ + name: teamsRequestParser.shape.name.trim(), + email: teamsRequestParser.shape.email.trim().toLowerCase(), + description: teamsRequestParser.shape.description.trim(), + shortDescription: teamsRequestParser.shape.shortDescription.trim(), + }) + .pipe(createInsertSchema(expensesTable).strict().readonly()); + +export type NewTeam = z.infer; \ No newline at end of file From f3e27f47ab23451c87f5b04b8487c2991036b585 Mon Sep 17 00:00:00 2001 From: solvhold Date: Mon, 16 Mar 2026 17:37:32 +0100 Subject: [PATCH 2/3] feat: :sparkles: add call for returning all inactive teams issue: #127 --- src/db-access/teams.ts | 14 ++++++++++++++ src/routers/teams.ts | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/db-access/teams.ts b/src/db-access/teams.ts index 8990d1c..3ce46a8 100644 --- a/src/db-access/teams.ts +++ b/src/db-access/teams.ts @@ -35,3 +35,17 @@ export const selectActiveTeams = async ( return teams; }); }; +export const selectInActiveTeams = async ( + parameters: QueryParameters, +): Promise> => { + return await newDatabaseTransaction(database, async (tx) => { + const teams = await tx + .select() + .from(teamsTable) + .where(eq(teamsTable.active, false)) + .limit(parameters.limit) + .offset(parameters.offset); + + return teams; + }); +}; diff --git a/src/routers/teams.ts b/src/routers/teams.ts index e1ca51f..b991df7 100644 --- a/src/routers/teams.ts +++ b/src/routers/teams.ts @@ -1,4 +1,4 @@ -import { selectActiveTeams, selectTeamsById } from "@/src/db-access/teams"; +import { selectActiveTeams, selectInActiveTeams, selectTeamsById } from "@/src/db-access/teams"; import { clientError } from "@/src/error/http-errors"; import { listQueryParser, @@ -48,6 +48,42 @@ teamsRouter.get("/active", async (req, res, next) => { } res.json(results.data); }); + +/** + * @openapi + * /teams/inactive/: + * get: + * tags: [teams] + * summary: Get all inactive teams + * description: Return all inactive teams + * parameters: + * - $ref: "#/components/parameters/offset" + * - $ref: "#/components/parameters/limit" + * responses: + * 200: + * description: Successfull response + * content: + * application/json: + * schema: + * $ref: "#/components/schemas/teams" + */ +teamsRouter.get("/inactive", async (req, res, next) => { + const queryParametersResult = toListQueryParser.safeParse(req.query); + if (!queryParametersResult.success) { + return next( + clientError(400, "Invalid request format", queryParametersResult.error), + ); + } + + const results = await selectInActiveTeams(queryParametersResult.data); + if (!results.success) { + return next( + clientError(400, "Invalid request format", queryParametersResult.error), + ); + } + res.json(results.data); +}); + /** * @openapi * /teams/{teamId}/: From ff5da2c82e3a60ecfc8316fd26487c9a03c3193f Mon Sep 17 00:00:00 2001 From: solvhold Date: Mon, 16 Mar 2026 17:52:12 +0100 Subject: [PATCH 3/3] refactor: pnpm check issue: #127 --- openapi/config.ts | 4 +-- src/request-handling/teams.ts | 47 ++++++++++++++++------------------- src/routers/teams.ts | 6 ++++- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/openapi/config.ts b/openapi/config.ts index a32675b..e78bdea 100644 --- a/openapi/config.ts +++ b/openapi/config.ts @@ -20,6 +20,7 @@ import { teamApplicationSelectSchema } from "@/src/response-handling/application import { expensesSelectSchema } from "@/src/response-handling/expenses"; import { sponsorsSelectSchema } from "@/src/response-handling/sponsors"; +import { teamsRequestParser } from "@/src/request-handling/teams"; import { assistantUserSelectSchema, teamUserSelectSchema, @@ -27,7 +28,6 @@ import { } from "@/src/response-handling/users"; import openapiFromJsdoc from "swagger-jsdoc"; import { createDocument } from "zod-openapi"; -import { teamsRequestParser } from "@/src/request-handling/teams"; const openapiDocument = createDocument({ openapi: "3.1.0", @@ -85,7 +85,7 @@ const openapiDocument = createDocument({ datePeriod: datePeriodParser, teamApplication: teamApplicationSelectSchema, teamApplicationRequest: teamApplicationParser, - teams: teamsRequestParser + teams: teamsRequestParser, }, parameters: { id: serialIdParser.openapi({ param: { in: "path", name: "id" } }), diff --git a/src/request-handling/teams.ts b/src/request-handling/teams.ts index f023a08..2406a94 100644 --- a/src/request-handling/teams.ts +++ b/src/request-handling/teams.ts @@ -5,32 +5,27 @@ import { createInsertSchema } from "drizzle-zod"; import { z } from "zod"; export const teamsRequestParser = z - .object({ - departmentId: serialIdParser.describe("Id of corresponding department"), - name: z.string().min(1).describe("Name of team"), - email: z.string().email().describe("Email of team"), - description: z.string().min(1).describe("Description of team"), - shortDescription: z - .string() - .min(1) - .describe("Short description of team"), - acceptApplication: z - .boolean() - .describe("Whether the team is accepting applications or not"), - active: z.boolean().describe("Whether the team is active or not"), - deadline: timeStringParser.describe( - "Deadline for applying to the team", - ), - }) - .strict(); + .object({ + departmentId: serialIdParser.describe("Id of corresponding department"), + name: z.string().min(1).describe("Name of team"), + email: z.string().email().describe("Email of team"), + description: z.string().min(1).describe("Description of team"), + shortDescription: z.string().min(1).describe("Short description of team"), + acceptApplication: z + .boolean() + .describe("Whether the team is accepting applications or not"), + active: z.boolean().describe("Whether the team is active or not"), + deadline: timeStringParser.describe("Deadline for applying to the team"), + }) + .strict(); export const teamsRequestToInsertParser = teamsRequestParser - .extend({ - name: teamsRequestParser.shape.name.trim(), - email: teamsRequestParser.shape.email.trim().toLowerCase(), - description: teamsRequestParser.shape.description.trim(), - shortDescription: teamsRequestParser.shape.shortDescription.trim(), - }) - .pipe(createInsertSchema(expensesTable).strict().readonly()); + .extend({ + name: teamsRequestParser.shape.name.trim(), + email: teamsRequestParser.shape.email.trim().toLowerCase(), + description: teamsRequestParser.shape.description.trim(), + shortDescription: teamsRequestParser.shape.shortDescription.trim(), + }) + .pipe(createInsertSchema(expensesTable).strict().readonly()); -export type NewTeam = z.infer; \ No newline at end of file +export type NewTeam = z.infer; diff --git a/src/routers/teams.ts b/src/routers/teams.ts index b991df7..6f3127c 100644 --- a/src/routers/teams.ts +++ b/src/routers/teams.ts @@ -1,4 +1,8 @@ -import { selectActiveTeams, selectInActiveTeams, selectTeamsById } from "@/src/db-access/teams"; +import { + selectActiveTeams, + selectInActiveTeams, + selectTeamsById, +} from "@/src/db-access/teams"; import { clientError } from "@/src/error/http-errors"; import { listQueryParser,