Skip to content

Commit

Permalink
Merge branch 'develop' into feat/team-dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
mroihn authored Dec 16, 2024
2 parents 25dc074 + 186a25a commit d88b177
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/controllers/competition.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,38 @@ import { roleMiddleware } from '~/middlewares/role-access.middleware';
import {
getAnnouncementsByCompetitionId,
getCompetition,
getCompetitionParticipant,
postAnnouncement,
} from '~/repositories/competition.repository';
import {
getAdminCompAnnouncementRoute,
getCompetitionParticipantRoute,
postAdminCompAnnouncementRoute,
} from '~/routes/competition.route';
import { createAuthRouter } from '~/utils/router-factory';

export const competitionProtectedRouter = createAuthRouter();

competitionProtectedRouter.get(
getCompetitionParticipantRoute.getRoutingPath(),
roleMiddleware('admin'),
);

competitionProtectedRouter.openapi(
getCompetitionParticipantRoute,
async (c) => {
const { page, limit } = c.req.valid('query');
const { competitionId } = c.req.valid('param');

const competitionParticipant = await getCompetitionParticipant(
db,
competitionId,
{ page: Number(page), limit: Number(limit) },
);
return c.json(competitionParticipant, 200);
},
);

competitionProtectedRouter.get(
getAdminCompAnnouncementRoute.getRoutingPath(),
roleMiddleware('admin'),
Expand Down
19 changes: 18 additions & 1 deletion src/controllers/team.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import {
deleteTeam,
deleteTeamMember,
getTeamById,
getTeamsByCompetitionId,
insertUserToTeam,
updateTeamDocument,
updateTeamVerification,
} from '~/repositories/team.repository';
import {
deleteTeamMemberRoute,
postCreateTeamRoute,
postQuitTeamRoute,
getTeamCompetitionRoute,
getTeamDetailRoute,
postCreateTeamRoute,
postTeamDocumentRoute,
postTeamVerificationRoute,
putChangeTeamNameRoute,
Expand Down Expand Up @@ -171,3 +174,17 @@ teamProtectedRouter.openapi(postTeamDocumentRoute, async (c) => {

return c.json(updatedTeam, 200);
});

teamProtectedRouter.openapi(getTeamCompetitionRoute, async (c) => {
const { competitionId } = c.req.valid('param');
const teams = await getTeamsByCompetitionId(db, competitionId);
if(!teams) return c.json({ error: "Competition doesn't exist!" }, 400);
return c.json(teams, 200);
});

teamProtectedRouter.openapi(getTeamDetailRoute, async (c) => {
const { competitionId, teamId } = c.req.valid('param');
const team = await getTeamById(db, teamId, { teamMember: true });
if (!team) return c.json({ error: "Team doesn't exist!" }, 400);
return c.json(team, 200);
});
36 changes: 36 additions & 0 deletions src/repositories/competition.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,42 @@ export const getCompetitionParticipantNumber = async (
return { participantCount: result.length };
};

export const getCompetitionParticipant = async (
db: Database,
competitionId: string,
options: { page: number; limit: number },
) => {
const { page, limit } = options;
const offset = (page - 1) * limit;

const result = await db.query.team.findMany({
where: eq(team.competitionId, competitionId),
limit,
offset,
});

const totalItems = (
await db.query.team.findMany({
where: eq(team.competitionId, competitionId),
})
).length;

const totalPages = Math.ceil(totalItems / limit);
const next = page < totalPages ? `?page=${page + 1}&limit=${limit}` : null;
const prev = page > 1 ? `?page=${page - 1}&limit=${limit}` : null;

return {
pagination: {
currentPage: page,
totalItems,
totalPages,
next,
prev,
},
result,
};
};

export const getCompetitionById = async (
db: Database,
competitionId: string,
Expand Down
12 changes: 12 additions & 0 deletions src/repositories/team.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,15 @@ export const updateTeamVerification = async (
.returning()
.then(first);
};

export const getTeamsByCompetitionId = async (
db: Database,
competitionId: string
) => {
return await db.query.team.findMany({
where: eq(team.competitionId, competitionId),
with: {
teamMembers: true,
}
});
}
25 changes: 25 additions & 0 deletions src/routes/competition.route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { createRoute } from '@hono/zod-openapi';
import {
AnnouncementSchema,
CompetitionParticipantSchema,
GetCompetitionTimeQuerySchema,
PostCompAnnouncementBodySchema,
} from '~/types/competition.type';
import { AllAnnouncementSchema } from '~/types/competition.type';
Expand Down Expand Up @@ -29,6 +31,29 @@ export const getAdminCompAnnouncementRoute = createRoute({
},
});

export const getCompetitionParticipantRoute = createRoute({
operationId: 'getCompetitionParticipant',
tags: ['team', 'admin', 'competition'],
method: 'get',
path: '/admin/{competitionId}/team',
request: {
params: CompetitionIdParam,
query: GetCompetitionTimeQuerySchema,
},
responses: {
200: {
description: "Fetched competition's participant.",
content: {
'application/json': {
schema: CompetitionParticipantSchema,
},
},
},
400: createErrorResponse('UNION', 'Bad request error'),
500: createErrorResponse('GENERIC', 'Internal server error'),
},
});

export const postAdminCompAnnouncementRoute = createRoute({
operationId: 'postAdminCompAnnouncement',
tags: ['admin', 'competition'],
Expand Down
47 changes: 47 additions & 0 deletions src/routes/team.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { createRoute } from '@hono/zod-openapi';
import { TeamMemberSchema } from '~/types/team-member.type';
import {
CompetitionAndTeamIdParam,
CompetitionIdParam,
PostTeamBodySchema,
PostTeamDocumentBodySchema,
PostTeamVerificationBodySchema,
TeamCompetitionDetailSchema,
TeamCompetitionSchema,
TeamIdParam,
TeamMemberIdSchema,
TeamSchema,
Expand Down Expand Up @@ -225,3 +228,47 @@ export const postTeamVerificationRoute = createRoute({
500: createErrorResponse('GENERIC', 'Internal server error'),
},
});

export const getTeamCompetitionRoute = createRoute({
operationId: "getTeamCompetition",
tags: ["team", "admin"],
method: "get",
path: "/admin/{competitionId}/team",
request: {
params: CompetitionIdParam,
},
responses: {
200: {
description: "Successfully get team competition",
content: {
"application/json": {
schema: TeamCompetitionSchema,
},
},
},
400: createErrorResponse("UNION", "Bad request error"),
500: createErrorResponse("GENERIC", "Internal server error"),
},
});

export const getTeamDetailRoute = createRoute({
operationId: "getTeamDetail",
tags: ["team", "admin"],
method: "get",
path: "/admin/{competitionId}/team/{teamId}",
request: {
params: CompetitionAndTeamIdParam,
},
responses: {
200: {
description: "Successfully get team detail",
content: {
"application/json": {
schema: TeamCompetitionDetailSchema,
},
},
},
400: createErrorResponse("UNION", "Bad request error"),
500: createErrorResponse("GENERIC", "Internal server error"),
},
})
35 changes: 35 additions & 0 deletions src/types/competition.type.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createInsertSchema, createSelectSchema } from 'drizzle-zod';
import { z } from 'zod';
import { competitionAnnouncement } from '~/db/schema';
import { TeamSchema } from './team.type';

export const AnnouncementSchema = createSelectSchema(competitionAnnouncement, {
createdAt: z.union([z.string(), z.date()]),
Expand All @@ -21,3 +22,37 @@ export const PostCompAnnouncementBodySchema = z.object({
title: z.string().min(1),
description: z.string().min(1),
});

export const CompetitionParticipantSchema = z
.object({
pagination: z.object({
currentPage: z.number(),
totalItems: z.number(),
totalPages: z.number(),
next: z.string().url().nullable(),
prev: z.string().url().nullable(),
}),
result: z.array(TeamSchema),
})
.openapi('CompetitionParticipant');

export const GetCompetitionTimeQuerySchema = z.object({
page: z
.string()
.default('1')
.openapi({
param: {
in: 'query',
required: false,
},
}),
limit: z
.string()
.default('10')
.openapi({
param: {
in: 'query',
required: false,
},
}),
});
20 changes: 20 additions & 0 deletions src/types/team.type.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createInsertSchema, createSelectSchema } from 'drizzle-zod';
import { z } from 'zod';
import { team } from '~/db/schema';
import { TeamMemberSchema } from './team-member.type';

export const PostTeamDocumentBodySchema = createInsertSchema(team).pick({
paymentProofMediaId: true,
Expand Down Expand Up @@ -42,3 +43,22 @@ export const PostTeamBodySchema = createInsertSchema(team).pick({
competitionId: true,
name: true,
});

export const CompetitionIdParam = z.object({
competitionId: z.string().openapi({
param: {
in: "path",
required: true,
},
}),
});

export const TeamCompetitionSchema = z.array(
TeamSchema.extend({
members: z.array(TeamMemberSchema),
})
);

export const TeamCompetitionDetailSchema = TeamSchema.extend({
members: z.array(TeamMemberSchema),
});

0 comments on commit d88b177

Please sign in to comment.