Skip to content

Commit

Permalink
Merge pull request #1006 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 2, 2024
2 parents d69562d + 4d0b2fc commit 43f46ab
Show file tree
Hide file tree
Showing 137 changed files with 3,223 additions and 2,159 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sparcs-clubs",
"private": true,
"version": "1.0.0",
"version": "2.0.0",
"repository": "",
"license": "MIT",
"scripts": {
Expand Down
10 changes: 2 additions & 8 deletions packages/api/src/feature/activity/activity.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { S3Client } from "@aws-sdk/client-s3";
import { Module } from "@nestjs/common";

import { DrizzleModule } from "src/drizzle/drizzle.module";

import { ClubModule } from "../club/club.module";

import { FileRepository } from "../file/repository/file.repository";
import FilePublicService from "../file/service/file.public.service";
import { FileModule } from "../file/file.module";

import ActivityActivityTermController from "./controller/activity.activity-term.controller";
import ActivityController from "./controller/activity.controller";
Expand All @@ -17,17 +14,14 @@ import ActivityPublicService from "./service/activity.public.service";
import ActivityService from "./service/activity.service";

@Module({
imports: [ClubModule, DrizzleModule],
imports: [ClubModule, DrizzleModule, FileModule],
controllers: [ActivityController, ActivityActivityTermController],
providers: [
ActivityRepository,
ActivityActivityTermRepository,
ActivityService,
ActivityActivityTermService,
ActivityPublicService,
FilePublicService,
FileRepository,
S3Client,
],
exports: [ActivityPublicService],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import apiAct008, {
ApiAct008RequestParam,
ApiAct008ResponseOk,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct008";
import apiAct010 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct010";
import apiAct011 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct011";
import apiAct012 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct012";
import apiAct013 from "@sparcs-clubs/interface/api/activity/endpoint/apiAct013";
Expand Down Expand Up @@ -62,6 +63,10 @@ import type {
ApiAct005RequestBody,
ApiAct005ResponseOk,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct005";
import type {
ApiAct010RequestQuery,
ApiAct010ResponseOk,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct010";
import type {
ApiAct011RequestQuery,
ApiAct011ResponseOk,
Expand Down Expand Up @@ -189,6 +194,21 @@ export default class ActivityController {
return {};
}

@Student()
@Get("/student/activities/available-members")
@UsePipes(new ZodPipe(apiAct010))
async getStudentActivitiesAvailableMembers(
@GetStudent() user: GetStudent,
@Query() query: ApiAct010RequestQuery,
): Promise<ApiAct010ResponseOk> {
const result =
await this.activityService.getStudentActivitiesAvailableMembers({
studentId: user.studentId,
query,
});
return result;
}

@Student()
@Get("/student/provisional/activities")
@UsePipes(new ZodPipe(apiAct011))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
ActivityT,
ProfessorSignStatus,
} from "@sparcs-clubs/api/drizzle/schema/activity.schema";
import { Student } from "@sparcs-clubs/api/drizzle/schema/user.schema";

@Injectable()
export default class ActivityRepository {
Expand Down Expand Up @@ -316,8 +317,13 @@ export default class ActivityRepository {

async selectParticipantByActivityId(activityId: number) {
const result = await this.db
.select()
.select({
studentId: ActivityParticipant.studentId,
studentNumber: Student.number,
name: Student.name,
})
.from(ActivityParticipant)
.leftJoin(Student, eq(ActivityParticipant.studentId, Student.id))
.where(
and(
eq(ActivityParticipant.activityId, activityId),
Expand Down
55 changes: 50 additions & 5 deletions packages/api/src/feature/activity/service/activity.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import type {
ApiAct003RequestParam,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct003";
import type { ApiAct005ResponseOk } from "@sparcs-clubs/interface/api/activity/endpoint/apiAct005";
import type {
ApiAct010RequestQuery,
ApiAct010ResponseOk,
} from "@sparcs-clubs/interface/api/activity/endpoint/apiAct010";
import type {
ApiAct011RequestQuery,
ApiAct011ResponseOk,
Expand All @@ -46,7 +50,7 @@ export default class ActivityService {
/**
* @param activityId 활동 id
* @returns 해당id의 활동이 존재할 경우 그 정보를 리턴합니다.
* 존재하지 않을 경우 not found exception을 throw합니다.
* 존재하지 않을 경우 not found exception을 throw합니다.`
*/
private async getActivity(param: { activityId: number }) {
const activities = await this.activityRepository.selectActivityByActivityId(
Expand Down Expand Up @@ -201,6 +205,41 @@ export default class ActivityService {
}));
}

/**
* @description getStudentActivitiesAvailableMembers의 서비스 진입점입니다.
*/
async getStudentActivitiesAvailableMembers(param: {
studentId: number;
query: ApiAct010RequestQuery;
}): Promise<ApiAct010ResponseOk> {
if (
!(await this.clubPublicService.isStudentDelegate(
param.studentId,
param.query.clubId,
))
)
throw new HttpException(
"It seems that you are not a delegate of the club",
HttpStatus.BAD_REQUEST,
);

const result = await this.clubPublicService.getMemberFromDuration({
clubId: param.query.clubId,
duration: {
startTerm: param.query.startTerm,
endTerm: param.query.endTerm,
},
});

return {
students: result.map(e => ({
id: e.studentId,
name: e.name,
studentNumber: e.studentNumber,
})),
};
}

async getStudentActivity(
activityId: number,
studentId: number,
Expand Down Expand Up @@ -229,10 +268,12 @@ export default class ActivityService {
detail: activity.detail,
evidence: activity.evidence,
evidenceFiles: evidence.map(e => ({
uuid: e.fileId,
fileId: e.fileId,
})),
participants: participants.map(e => ({
studentId: e.studentId,
studnetNumber: e.studentNumber,
name: e.name,
})),
durations: duration.map(e => ({
startTerm: e.startTerm,
Expand Down Expand Up @@ -360,7 +401,7 @@ export default class ActivityService {
purpose: body.purpose,
detail: body.detail,
evidence: body.evidence,
evidenceFileIds: body.evidenceFiles.map(e => e.uuid),
evidenceFileIds: body.evidenceFiles.map(e => e.fileId),
participantIds: body.participants.map(e => e.studentId),
activityDId: activity.activityDId,
});
Expand Down Expand Up @@ -606,10 +647,12 @@ export default class ActivityService {
detail: activity.detail,
evidence: activity.evidence,
evidenceFiles: evidence.map(e => ({
uuid: e.fileId,
fileId: e.fileId,
})),
participants: participants.map(e => ({
studentId: e.studentId,
studnetNumber: e.studentNumber,
name: e.name,
})),
durations: duration.map(e => ({
startTerm: e.startTerm,
Expand Down Expand Up @@ -640,10 +683,12 @@ export default class ActivityService {
detail: activity.detail,
evidence: activity.evidence,
evidenceFiles: evidence.map(e => ({
uuid: e.fileId,
fileId: e.fileId,
})),
participants: participants.map(e => ({
studentId: e.studentId,
studnetNumber: e.studentNumber,
name: e.name,
})),
durations: duration.map(e => ({
startTerm: e.startTerm,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ export class ClubDelegateDRepository {
isNull(Club.deletedAt),
),
);
// logger.debug(result);
// logger.debug(result); // 로그가 너무 길어서 주석처리해 두었어요
return result;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { Inject, Injectable } from "@nestjs/common";
import { and, count, desc, eq, gte, isNull, lte, or } from "drizzle-orm";
import {
and,
count,
desc,
eq,
gte,
inArray,
isNotNull,
isNull,
lte,
not,
or,
} from "drizzle-orm";
import { MySql2Database } from "drizzle-orm/mysql2";

import logger from "@sparcs-clubs/api/common/util/logger";
import { getKSTDate, takeUnique } from "@sparcs-clubs/api/common/util/util";
import { DrizzleAsyncProvider } from "@sparcs-clubs/api/drizzle/drizzle.provider";

Expand Down Expand Up @@ -167,4 +180,45 @@ export default class ClubStudentTRepository {
)
.execute();
}

/**
* @param param
* @returns 어떤 동아리에 해당 기간동안 활동한 학생 목록을 가져옵니다.
* @description 동아리 회원이 변경되는 기간이 매우 한정적이기에 동시성을 지원하지 않습니다.
*/
async selectStudentByClubIdAndDuration(param: {
clubId: number;
duration: {
startTerm: Date;
endTerm: Date;
};
}) {
const studentIds = await this.db
.select()
.from(ClubStudentT)
.where(
and(
eq(ClubStudentT.clubId, param.clubId),
not(
or(
gte(ClubStudentT.startTerm, param.duration.endTerm),
and(
isNotNull(ClubStudentT.endTerm),
lte(ClubStudentT.endTerm, param.duration.startTerm),
),
),
),
isNull(ClubStudentT.deletedAt),
),
)
.then(arr => arr.map(e => e.studentId));
logger.debug(studentIds);
if (studentIds.length === 0) return [];
const result = await this.db
.select()
.from(Student)
.where(and(inArray(Student.id, studentIds), isNull(Student.deletedAt)));

return result;
}
}
32 changes: 31 additions & 1 deletion packages/api/src/feature/club/service/club.public.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,36 @@ export default class ClubPublicService {
return false;
}

/**
* @param param
* @returns 해당 동아리에서 해당 기간동안 활동했던 학생 목록을 리턴합니다.
*/
async getMemberFromDuration(param: {
clubId: number;
duration: {
startTerm: Date;
endTerm: Date;
};
}): Promise<
Array<{
studentId: number;
name: string;
studentNumber: number;
}>
> {
const result =
await this.clubStudentTRepository.selectStudentByClubIdAndDuration({
clubId: param.clubId,
duration: param.duration,
});

return result.map(e => ({
studentId: e.id,
name: e.name,
studentNumber: e.number,
}));
}

async getMemberFromSemester(param: { semesterId: number; clubId: number }) {
const result = await this.clubStudentTRepository.findByClubIdAndSemesterId(
param.clubId,
Expand Down Expand Up @@ -110,7 +140,7 @@ export default class ClubPublicService {
* @param semesterId 신청 학기 id
* @returns 특정 학기의 특정 상태(정동아리/가동아리/정동아리 or 가동아리)의 동아리(clubId) list
* 예를 들어, getClubIdByClubStatusEnumId([ClubTypeEnum.Regular], semesterId) 의 경우,
* semsterId 학기 당시 정동아리였던 동아리의 clubId list를 반환합니다.
* semesterId 학기 당시 정동아리였던 동아리의 clubId list를 반환합니다.
*/
async getClubIdByClubStatusEnumId(
studentId: number,
Expand Down
4 changes: 3 additions & 1 deletion packages/api/src/feature/file/service/file.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class FileService {
const uploadUrl = await getSignedUrl(this.s3Client, command, {
expiresIn: 600,
});
return { uploadUrl, fileId };
return { uploadUrl, fileId, name };
}

async getFilesDownloadLinks(param: {
Expand Down Expand Up @@ -93,6 +93,7 @@ export class FileService {
return {
id: e.id,
fileKey: `file/${e.userId}.${e.signedAt.valueOf()}.${e.name}`,
name: e.name,
};
});

Expand All @@ -101,6 +102,7 @@ export class FileService {
fileKeys.map(async e => ({
id: e.id,
url: await getFileUrls(e.fileKey),
name: e.name,
})),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ export class ClubRegistrationRepository {
await this.db
.select({ count: count(Registration.id) })
.from(Registration)
.where(isNull(Registration.deletedAt))
.then(takeUnique)
).count;

Expand Down
Loading

0 comments on commit 43f46ab

Please sign in to comment.