Skip to content

Commit

Permalink
Merge pull request #1024 from academic-relations/dev
Browse files Browse the repository at this point in the history
merge dev into main
  • Loading branch information
pbc1017 authored Sep 4, 2024
2 parents 43f46ab + e74c7d9 commit d78784f
Show file tree
Hide file tree
Showing 38 changed files with 800 additions and 321 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Delete,
Get,
Param,
Patch,
Post,
Put,
Query,
Expand All @@ -30,6 +31,7 @@ import apiAct012 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct012";
import apiAct013 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct013";
import apiAct014 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct014";
import apiAct015 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct015";
import apiAct016 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct016";

import { ZodPipe } from "@sparcs-clubs/api/common/pipe/zod-pipe";

Expand All @@ -38,7 +40,10 @@ import {
Professor,
Student,
} from "@sparcs-clubs/api/common/util/decorators/method-decorator";
import { GetStudent } from "@sparcs-clubs/api/common/util/decorators/param-decorator";
import {
GetExecutive,
GetStudent,
} from "@sparcs-clubs/api/common/util/decorators/param-decorator";

import ActivityService from "../service/activity.service";

Expand Down Expand Up @@ -87,6 +92,10 @@ import type {
ApiAct015RequestParam,
ApiAct015ResponseOk,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct015";
import type {
ApiAct016RequestParam,
ApiAct016ResponseOk,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct016";

@Controller()
export default class ActivityController {
Expand Down Expand Up @@ -257,7 +266,7 @@ export default class ActivityController {
@Executive()
@Get("/executive/activities/activity/:activityId")
@UsePipes(new ZodPipe(apiAct014))
async getExcutiveActivity(
async getExecutiveActivity(
@Param() param: ApiAct014RequestParam,
): Promise<ApiAct014ResponseOk> {
const result = await this.activityService.getExecutiveActivity(
Expand All @@ -279,4 +288,18 @@ export default class ActivityController {

return result;
}

@Executive()
@Patch("/executive/activities/activity/:activityId/approval")
@UsePipes(new ZodPipe(apiAct016))
async patchExecutiveActivityApproval(
@GetExecutive() user: GetExecutive,
@Param() param: ApiAct016RequestParam,
): Promise<ApiAct016ResponseOk> {
const result = await this.activityService.patchExecutiveActivityApproval({
executiveId: user.executiveId,
param,
});
return result;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Inject, Injectable } from "@nestjs/common";
import { HttpException, HttpStatus, Inject, Injectable } from "@nestjs/common";
import {
ActivityStatusEnum,
ActivityTypeEnum,
} from "@sparcs-clubs/interface/common/enum/activity.enum";
import { and, asc, eq, gt, isNull, lte } from "drizzle-orm";
import { and, asc, eq, gt, isNull, lte, not } from "drizzle-orm";
import { MySql2Database } from "drizzle-orm/mysql2";

import logger from "@sparcs-clubs/api/common/util/logger";
Expand Down Expand Up @@ -498,4 +498,38 @@ export default class ActivityRepository {
.where(eq(Activity.id, id));
return result;
}

/**
* @param activityId 활동 Id
* @description 해당 활동의 승인 상태(ActivityStatusEnumId)를 변경합니다.
* 해당 활동의 상태가 이미 승인인 경우 예외(Bad Request)를 발생시킵니다.
* @returns update에 성공했는지 성공여부를 리턴합니다.
* 실패시 예외가 발생하여 항상 true를 리턴해야 합니다.
*/
async updateActivityStatusEnumId(param: {
activityId: number;
activityStatusEnumId: ActivityStatusEnum;
}): Promise<boolean> {
const isUpdateSucceed = await this.db.transaction(async tx => {
const [updateResult] = await tx
.update(Activity)
.set({
activityStatusEnumId: param.activityStatusEnumId,
})
.where(
and(
eq(Activity.id, param.activityId),
not(eq(Activity.activityStatusEnumId, ActivityStatusEnum.Approved)),
isNull(Activity.deletedAt),
),
);
if (updateResult.affectedRows !== 1)
throw new HttpException(
"failed to update activityStatusEnumId",
HttpStatus.BAD_REQUEST,
);
return true;
});
return isUpdateSucceed;
}
}
74 changes: 61 additions & 13 deletions packages/api/src/feature/activity/service/activity.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import {
ApiAct008RequestBody,
ApiAct008RequestParam,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct008";
import { ActivityDeadlineEnum } from "@sparcs-clubs/interface/common/enum/activity.enum";
import {
ActivityDeadlineEnum,
ActivityStatusEnum,
} from "@sparcs-clubs/interface/common/enum/activity.enum";

import { getKSTDate } from "@sparcs-clubs/api/common/util/util";
import ClubPublicService from "@sparcs-clubs/api/feature/club/service/club.public.service";
Expand Down Expand Up @@ -37,6 +40,10 @@ import type {
ApiAct013RequestQuery,
ApiAct013ResponseOk,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct013";
import type {
ApiAct016RequestParam,
ApiAct016ResponseOk,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct016";

@Injectable()
export default class ActivityService {
Expand Down Expand Up @@ -258,6 +265,16 @@ export default class ActivityService {
activity.id,
);

const evidenceFiles = await Promise.all(
evidence.map(async e => ({
fileId: e.fileId,
name: await this.filePublicService
.getFileInfoById(e.fileId)
.then(f => f.name),
url: await this.filePublicService.getFileUrl(e.fileId),
})),
);

return {
clubId: activity.clubId,
name: activity.name,
Expand All @@ -267,12 +284,10 @@ export default class ActivityService {
purpose: activity.purpose,
detail: activity.detail,
evidence: activity.evidence,
evidenceFiles: evidence.map(e => ({
fileId: e.fileId,
})),
evidenceFiles,
participants: participants.map(e => ({
studentId: e.studentId,
studnetNumber: e.studentNumber,
studentNumber: e.studentNumber,
name: e.name,
})),
durations: duration.map(e => ({
Expand Down Expand Up @@ -637,6 +652,16 @@ export default class ActivityService {
activity.id,
);

const evidenceFiles = await Promise.all(
evidence.map(async e => ({
fileId: e.fileId,
name: await this.filePublicService
.getFileInfoById(e.fileId)
.then(f => f.name),
url: await this.filePublicService.getFileUrl(e.fileId),
})),
);

return {
clubId: activity.clubId,
name: activity.name,
Expand All @@ -646,12 +671,10 @@ export default class ActivityService {
purpose: activity.purpose,
detail: activity.detail,
evidence: activity.evidence,
evidenceFiles: evidence.map(e => ({
fileId: e.fileId,
})),
evidenceFiles,
participants: participants.map(e => ({
studentId: e.studentId,
studnetNumber: e.studentNumber,
studentNumber: e.studentNumber,
name: e.name,
})),
durations: duration.map(e => ({
Expand All @@ -673,6 +696,16 @@ export default class ActivityService {
activity.id,
);

const evidenceFiles = await Promise.all(
evidence.map(async e => ({
fileId: e.fileId,
name: await this.filePublicService
.getFileInfoById(e.fileId)
.then(f => f.name),
url: await this.filePublicService.getFileUrl(e.fileId),
})),
);

return {
clubId: activity.clubId,
name: activity.name,
Expand All @@ -682,12 +715,10 @@ export default class ActivityService {
purpose: activity.purpose,
detail: activity.detail,
evidence: activity.evidence,
evidenceFiles: evidence.map(e => ({
fileId: e.fileId,
})),
evidenceFiles,
participants: participants.map(e => ({
studentId: e.studentId,
studnetNumber: e.studentNumber,
studentNumber: e.studentNumber,
name: e.name,
})),
durations: duration.map(e => ({
Expand All @@ -696,4 +727,21 @@ export default class ActivityService {
})),
};
}

/**
* @description patchExecutiveActivityApproval의 서비스 진입점입니다.
*/
async patchExecutiveActivityApproval(param: {
executiveId: number;
param: ApiAct016RequestParam;
}): Promise<ApiAct016ResponseOk> {
const isApprovalSucceed =
await this.activityRepository.updateActivityStatusEnumId({
activityId: param.param.activityId,
activityStatusEnumId: ActivityStatusEnum.Approved,
});
if (!isApprovalSucceed)
throw new HttpException("unreachable", HttpStatus.INTERNAL_SERVER_ERROR);
return {};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export class AuthRepository {
// professor_t에서 해당 professor_id이 있는지 확인 후 upsert
// type이 "Employee"를 포함하는 경우 Employee table에서 해당 email이 있는지 확인 후 upsert
// employee_t에서 해당 employee_id이 있는지 확인 후 upsert
if (type === "Teacher") {
if (type.includes("Teacher")) {
await this.db
.insert(Professor)
.values({ userId: user.id, name, email })
Expand Down
4 changes: 3 additions & 1 deletion packages/interface/src/api/activity/endpoint/apiAct002.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ const responseBodyMap = {
evidenceFiles: z.array(
z.object({
fileId: z.string().max(255),
name: z.string().max(255),
url: z.string().max(255),
}),
),
participants: z.array(
z.object({
studentId: z.coerce.number().int().min(1),
studnetNumber: z.coerce.number().int().min(20000000),
studentNumber: z.coerce.number().int().min(20000000),
name: z.string().max(255),
}),
),
Expand Down
49 changes: 49 additions & 0 deletions packages/interface/src/api/activity/endpoint/apiAct016.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { HttpStatusCode } from "axios";
import { z } from "zod";

/**
* @version v0.1
* @description 집행부원으로서 동아리 등록 신청을 수락(activityStatusEnumId.Approved)합니다.
*/

const url = (activityId: number) =>
`/executive/activities/activity/${activityId}/approval`;
const method = "PATCH";

const requestParam = z.object({
activityId: z.coerce.number().int().min(1),
});

const requestQuery = z.object({});

const requestBody = z.object({});

const responseBodyMap = {
[HttpStatusCode.Ok]: z.object({}),
};

const responseErrorMap = {};

const apiAct016 = {
url,
method,
requestParam,
requestQuery,
requestBody,
responseBodyMap,
responseErrorMap,
};

type ApiAct016RequestParam = z.infer<typeof apiAct016.requestParam>;
type ApiAct016RequestQuery = z.infer<typeof apiAct016.requestQuery>;
type ApiAct016RequestBody = z.infer<typeof apiAct016.requestBody>;
type ApiAct016ResponseOk = z.infer<(typeof apiAct016.responseBodyMap)[200]>;

export default apiAct016;

export type {
ApiAct016RequestParam,
ApiAct016RequestQuery,
ApiAct016RequestBody,
ApiAct016ResponseOk,
};
4 changes: 2 additions & 2 deletions packages/interface/src/api/club/endpoint/apiClb004.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const requestBody = z.object({});

const responseBodyMap = {
[HttpStatusCode.Ok]: z.object({
description: z.coerce.string(),
roomPassword: z.coerce.string().max(20),
description: z.string(),
roomPassword: z.string().max(20),
}),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const responseBodyMap = {
z.object({
clubId: z.coerce.number().int().min(1),
clubTypeEnumId: z.coerce.number().int().min(1),
isPermanent: z.boolean(),
division: z.object({
id: z.coerce.number().int().min(1),
name: zUserName,
Expand Down
Loading

0 comments on commit d78784f

Please sign in to comment.