diff --git a/src/controllers/competition.controller.ts b/src/controllers/competition.controller.ts index 441422a..aebcd83 100644 --- a/src/controllers/competition.controller.ts +++ b/src/controllers/competition.controller.ts @@ -4,11 +4,15 @@ import { getAnnouncementsByCompetitionId, getCompetition, getCompetitionParticipant, + getCompetitionTimelines, + getCompetitionTimelinesByCompetitionId, postAnnouncement, } from '~/repositories/competition.repository'; import { getAdminCompAnnouncementRoute, getCompetitionParticipantRoute, + getCompetitionTimeLineByCompetitionIdRoute, + getCompetitionTimelineRoute, postAdminCompAnnouncementRoute, } from '~/routes/competition.route'; import { createAuthRouter } from '~/utils/router-factory'; @@ -79,3 +83,22 @@ competitionProtectedRouter.openapi( return c.json(announcement, 200); }, ); + +competitionProtectedRouter.openapi(getCompetitionTimelineRoute, async (c) => { + const user = c.get('user'); + const userId = user.id; + const timelines = await getCompetitionTimelines(db, userId); + return c.json(timelines, 200); +}); + +competitionProtectedRouter.openapi( + getCompetitionTimeLineByCompetitionIdRoute, + async (c) => { + const { competitionId } = c.req.valid('param'); + const timelines = await getCompetitionTimelinesByCompetitionId( + db, + competitionId, + ); + return c.json(timelines, 200); + }, +); diff --git a/src/controllers/team.controller.ts b/src/controllers/team.controller.ts index 685ab48..eed5207 100644 --- a/src/controllers/team.controller.ts +++ b/src/controllers/team.controller.ts @@ -175,6 +175,11 @@ teamProtectedRouter.openapi(postTeamDocumentRoute, async (c) => { return c.json(updatedTeam, 200); }); +teamProtectedRouter.get( + getTeamCompetitionRoute.getRoutingPath(), + roleMiddleware('admin'), +); + teamProtectedRouter.openapi(getTeamCompetitionRoute, async (c) => { const { competitionId } = c.req.valid('param'); const teams = await getTeamsByCompetitionId(db, competitionId); @@ -182,6 +187,11 @@ teamProtectedRouter.openapi(getTeamCompetitionRoute, async (c) => { return c.json(teams, 200); }); +teamProtectedRouter.get( + getTeamDetailRoute.getRoutingPath(), + roleMiddleware('admin'), +); + teamProtectedRouter.openapi(getTeamDetailRoute, async (c) => { const { teamId } = c.req.valid('param'); const team = await getTeamById(db, teamId, { teamMember: true }); diff --git a/src/repositories/competition.repository.ts b/src/repositories/competition.repository.ts index 3ac77a5..e339596 100644 --- a/src/repositories/competition.repository.ts +++ b/src/repositories/competition.repository.ts @@ -4,7 +4,13 @@ import { first } from '~/db/helper'; import type { PostCompAnnouncementBodySchema } from '~/types/competition.type'; import type { Database } from '../db/drizzle'; -import { competition, competitionAnnouncement, team } from '../db/schema'; +import { + competition, + competitionAnnouncement, + competitionTimeline, + team, + teamMember, +} from '../db/schema'; export const getCompetitionParticipantNumber = async ( db: Database, @@ -97,3 +103,29 @@ export const postAnnouncement = async ( .returning() .then(first); }; + +export const getCompetitionTimelines = async (db: Database, userId: string) => { + // Get user's competitions + const userTeams = await db.query.team.findMany({ + where: eq(teamMember.userId, userId), + with: { + competition: { + with: { + timeline: true, + }, + }, + }, + }); + + return userTeams.flatMap((team) => team.competition.timeline); +}; + +export const getCompetitionTimelinesByCompetitionId = async ( + db: Database, + competitionId: string, +) => { + const result = await db.query.competitionTimeline.findMany({ + where: eq(competitionTimeline.competitionId, competitionId), + }); + return result; +}; diff --git a/src/routes/competition.route.ts b/src/routes/competition.route.ts index 36bb1ed..c9cd33c 100644 --- a/src/routes/competition.route.ts +++ b/src/routes/competition.route.ts @@ -2,6 +2,7 @@ import { createRoute } from '@hono/zod-openapi'; import { AnnouncementSchema, CompetitionParticipantSchema, + CompetitionTimelineSchema, GetCompetitionTimeQuerySchema, PostCompAnnouncementBodySchema, } from '~/types/competition.type'; @@ -83,3 +84,44 @@ export const postAdminCompAnnouncementRoute = createRoute({ 500: createErrorResponse('GENERIC', 'Internal server error'), }, }); + +export const getCompetitionTimelineRoute = createRoute({ + operationId: 'getCompetitionTimeline', + tags: ['competition'], + method: 'get', + path: '/competition/timeline', + responses: { + 200: { + content: { + 'application/json': { + schema: CompetitionTimelineSchema, + }, + }, + description: 'Successfully fetched competition timelines', + }, + 400: createErrorResponse('UNION', 'Bad request error'), + 500: createErrorResponse('GENERIC', 'Internal server error'), + }, +}); + +export const getCompetitionTimeLineByCompetitionIdRoute = createRoute({ + operationId: 'getCompetitionTimelineWithCompetitionId', + tags: ['competition'], + method: 'get', + path: '/competition/{competitionId}/timeline', + request: { + params: CompetitionIdParam, + }, + responses: { + 200: { + content: { + 'application/json': { + schema: CompetitionTimelineSchema, + }, + }, + description: 'Successfully fetched competition timelines', + }, + 400: createErrorResponse('UNION', 'Bad request error'), + 500: createErrorResponse('GENERIC', 'Internal server error'), + }, +}); diff --git a/src/types/competition.type.ts b/src/types/competition.type.ts index 25d142a..86d0066 100644 --- a/src/types/competition.type.ts +++ b/src/types/competition.type.ts @@ -1,6 +1,6 @@ import { createSelectSchema } from 'drizzle-zod'; import { z } from 'zod'; -import { competitionAnnouncement } from '~/db/schema'; +import { competitionAnnouncement, competitionTimeline } from '~/db/schema'; import { TeamSchema } from './team.type'; @@ -57,3 +57,7 @@ export const GetCompetitionTimeQuerySchema = z.object({ }, }), }); + +export const CompetitionTimelineSchema = z.array( + createSelectSchema(competitionTimeline).openapi('CompetitionTimeline'), +);