Skip to content

Commit

Permalink
Merge pull request #92 from sparcs-kaist/issue/91/share-timetable-image
Browse files Browse the repository at this point in the history
issue/91/share-timetable-image
  • Loading branch information
pbc1017 authored Mar 27, 2024
2 parents 18039e5 + 014b5e0 commit 1e31d6b
Show file tree
Hide file tree
Showing 24 changed files with 1,820 additions and 152 deletions.
1,280 changes: 1,134 additions & 146 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@
"@types/morgan": "^1.9.4",
"@types/passport-jwt": "^3.0.6",
"@types/passport-local": "^1.0.34",
"@types/sharp": "^0.32.0",
"axios": "^1.4.0",
"bcrypt": "^5.1.0",
"cached-prisma": "^1.2.1",
"canvas": "^2.11.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"cookie-parser": "^1.4.6",
Expand Down
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { TracksModule } from './modules/tracks/tracks.module';
import { UserModule } from './modules/user/user.module';
import { WishlistModule } from './modules/wishlist/wishlist.module';
import { PrismaModule } from './prisma/prisma.module';
import { ShareModule } from './modules/share/share.module';

@Module({
imports: [
Expand All @@ -42,6 +43,7 @@ import { PrismaModule } from './prisma/prisma.module';
DepartmentsModule,
PlannersModule,
TracksModule,
ShareModule,
],
controllers: [AppController],
providers: [
Expand Down
17 changes: 17 additions & 0 deletions src/common/entities/ETimetabls.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Prisma } from '@prisma/client';

export namespace ETimetable {
export const WithLectureClasstimes =
Prisma.validator<Prisma.timetable_timetable_lecturesArgs>()({
include: {
subject_lecture: {
include: {
subject_classtime: true,
},
},
},
});

export type WithLectureClasstimes =
Prisma.timetable_timetable_lecturesGetPayload<typeof WithLectureClasstimes>;
}
45 changes: 45 additions & 0 deletions src/common/interfaces/ILecture.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Type } from 'class-transformer';
import { IsInt, IsString } from 'class-validator';
import { ITimetable } from './ITimetable';

export namespace ILecture {
export class AutocompleteDto {
Expand All @@ -14,4 +15,48 @@ export namespace ILecture {
@IsString()
keyword!: string;
}
export interface Basic {
id: number;
code: string;
old_code: string;
year: number;
semester: number;
department_id: number;
class_no: string;
title: string;
title_en: string;
type: string;
type_en: string;
audience: number;
credit: number;
title_en_no_space: string;
title_no_space: string;
num_classes: number;
num_labs: number;
credit_au: number;
limit: number;
num_people: number | null; // Allow num_people to be null
is_english: boolean;
deleted: boolean;
course_id: number;
grade_sum: number;
load_sum: number;
speech_sum: number;
grade: number;
load: number;
speech: number;
review_total_weight: number;
class_title: string | null;
class_title_en: string | null;
common_title: string | null;
common_title_en: string | null;
subject_classtime: ITimetable.IClasstime[];
// professor_names: string[] | null; // 교수 이름 목록
// professor_names_en: string[] | null; // 교수 영문 이름 목록
// classroom_str: string | null; // 강의실 문자열
// classroom_str_en: string | null; // 강의실 영문 문자열
// classroom_short: string | null; // 강의실 축약 문자열
// classroom_short_en: string | null; // 강의실 영문 축약 문자열
// Additional properties as needed
}
}
47 changes: 47 additions & 0 deletions src/common/interfaces/IShare.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { CanvasRenderingContext2D } from 'canvas';
import { ILecture } from './ILecture';

export namespace IShare {
export interface RoundedRectangleOptions {
ctx: CanvasRenderingContext2D;
x: number;
y: number;
width: number;
height: number;
radius: number;
color: string;
}

export interface TextOptions {
ctx: CanvasRenderingContext2D;
x: number;
y: number;
text: string;
font: string;
fontSize: number;
color: string;
align?: 'right' | 'left' | 'center'; // Optional parameter
}

export interface DrawTileOptions {
ctx: CanvasRenderingContext2D;
x: number;
y: number;
width: number;
height: number;
title: string;
professor: string;
location: string;
font: string;
fontSize: number;
}

export interface drawTimetableDatas {
lectures: ILecture.Basic[];
timetableType: string;
semesterName: string;
isEnglish: boolean;
semesterFontSize: number;
tileFontSize: number;
}
}
17 changes: 17 additions & 0 deletions src/common/interfaces/ITimetable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export namespace ITimetable {
export interface IClasstime {
id: number;
day: number;
begin: Date;
end: Date;
type: string;
building_id: string | null;
building_full_name: string | null;
building_full_name_en: string | null;
room_name: string | null;
unit_time: number | null;
lecture_id: number | null;
// Additional properties as needed
}
// Other interfaces as needed...
}
20 changes: 20 additions & 0 deletions src/common/interfaces/dto/share/share.request.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Type } from 'class-transformer';
import { IsInt, IsNumber, IsOptional, IsString } from 'class-validator';

Check warning on line 2 in src/common/interfaces/dto/share/share.request.dto.ts

View workflow job for this annotation

GitHub Actions / Lint

'IsInt' is defined but never used

export class TimetableImageQueryDto {
@Type(() => Number)
@IsNumber()
timetable!: number;

@Type(() => Number)
@IsNumber()
year!: number;

@Type(() => Number)
@IsNumber()
semester!: number;

@IsString()
@IsOptional()
language?: string;
}
3 changes: 3 additions & 0 deletions src/common/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export * from './IAuth';
export * from './ICourse';
export * from './IFeed';
export * from './ITimetable';
export * from './ILecture';
export * from './IShare';
76 changes: 76 additions & 0 deletions src/modules/lectures/lectures.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import { toJsonReview } from 'src/common/interfaces/serializer/review.serializer
import { ReviewsRepository } from 'src/prisma/repositories/review.repository';
import { LectureDetails, ReviewDetails } from '../../common/schemaTypes/types';
import { LectureRepository } from './../../prisma/repositories/lecture.repository';
import { PrismaService } from 'src/prisma/prisma.service';

@Injectable()
export class LecturesService {
constructor(
private LectureRepository: LectureRepository,
private reviewsRepository: ReviewsRepository,
private prisma: PrismaService,
) {}

public async getLectureByFilter(
Expand Down Expand Up @@ -140,4 +142,78 @@ export class LecturesService {
return professor.professor.professor_name_en;
}
}

async getProfessorShortStr(
lectureId: number,
isEnglish: boolean = false,
): Promise<string> {
const lectureWithProfessors =
await this.LectureRepository.getProfessorsByLectureId(lectureId);

if (!lectureWithProfessors) {
throw new Error(`Lecture with ID ${lectureId} not found.`);
}

const profNameList = lectureWithProfessors.subject_lecture_professors.map(
(lp) =>
isEnglish
? lp.professor.professor_name_en
: lp.professor.professor_name,
);

if (profNameList.length <= 2) {
return profNameList.join(', ');
}
return isEnglish
? `${profNameList[0]} and ${profNameList.length - 1} others`
: `${profNameList[0]}${profNameList.length - 1} 명`;
}

async getClassroomShortStr(
lectureId: number,
isEnglish: boolean = false,
): Promise<string> {
const lectureWithClassTimes =
await this.LectureRepository.getClassroomByLectureId(lectureId);

if (
!lectureWithClassTimes ||
!lectureWithClassTimes.subject_classtime ||
lectureWithClassTimes.subject_classtime.length === 0
) {
throw new Error(`Lecture with ID ${lectureId} not found.`);
}

// 첫 번째 classtime 요소에서 정보를 가져옵니다.
const classtime = lectureWithClassTimes.subject_classtime[0];
const { building_full_name, building_full_name_en, room_name } = classtime;

if (!building_full_name) {
return isEnglish ? 'Unknown' : '정보 없음';
}

let classroomShort = '';
if (building_full_name.startsWith('(')) {
const buildingCode = building_full_name.substring(
1,
building_full_name.indexOf(')'),
);
classroomShort = `(${buildingCode}) ${room_name || ''}`;
} else {
classroomShort = `${building_full_name} ${room_name || ''}`;
}

let classroomShortEn = '';
if (building_full_name_en && building_full_name_en.startsWith('(')) {
const buildingCodeEn = building_full_name_en.substring(
1,
building_full_name_en.indexOf(')'),
);
classroomShortEn = `(${buildingCodeEn}) ${room_name || ''}`;
} else {
classroomShortEn = `${building_full_name_en} ${room_name || ''}`;
}

return isEnglish ? classroomShortEn : classroomShort;
}
}
1 change: 1 addition & 0 deletions src/modules/semesters/semesters.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ import { SemestersService } from './semesters.service';
imports: [PrismaModule],
controllers: [SemestersController],
providers: [SemestersService],
exports: [SemestersService],
})
export class SemestersModule {}
13 changes: 13 additions & 0 deletions src/modules/semesters/semesters.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
import { SemesterRepository } from 'src/prisma/repositories/semester.repository';
import { SemesterQueryDto } from '../../common/interfaces/dto/semester/semester.request.dto';
import { orderFilter } from '../../common/utils/search.utils';
import { subject_semester } from '@prisma/client';

@Injectable()
export class SemestersService {
Expand All @@ -14,4 +15,16 @@ export class SemestersService {
});
return semesters;
}

public getSemesterName(
semester: subject_semester,
language: string = 'kr',
): string {
const seasons = language.includes('en')
? ['spring', 'summer', 'fall', 'winter']
: ['봄', '여름', '가을', '겨울'];

const seasonName = seasons[semester.semester - 1];
return `${semester.year} ${seasonName}`;
}
}
35 changes: 32 additions & 3 deletions src/modules/share/share.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
import { Controller } from '@nestjs/common';
import {
Controller,
Get,
HttpException,
HttpStatus,
Query,
Res,
} from '@nestjs/common';
import { session_userprofile } from '@prisma/client';
import { GetUser } from '../../common/decorators/get-user.decorator';
import { ShareService } from './share.service';
import { TimetableRepository } from 'src/prisma/repositories/timetable.repository';
import { Response } from 'express';
import { TimetableImageQueryDto } from 'src/common/interfaces/dto/share/share.request.dto';

@Controller('share')
export class ShareController {}
@Controller('/api/share')
export class ShareController {
constructor(
private readonly shareService: ShareService,
private readonly timetableRepository: TimetableRepository,
) {}

@Get('timetable/image')
async getTimetableImage(
@Query() query: TimetableImageQueryDto,
@GetUser() user: session_userprofile,
@Res() res: Response,
) {
const imageBuffer = await this.shareService.createTimetableImage(query);
res.setHeader('Content-Type', 'image/png');
res.send(imageBuffer);
}
}
5 changes: 5 additions & 0 deletions src/modules/share/share.module.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { Module } from '@nestjs/common';
import { ShareController } from './share.controller';
import { ShareService } from './share.service';
import { TimetablesModule } from '../timetables/timetables.module';
import { PrismaModule } from 'src/prisma/prisma.module';
import { SemestersModule } from '../semesters/semesters.module';
import { LecturesModule } from '../lectures/lectures.module';

@Module({
imports: [PrismaModule, TimetablesModule, SemestersModule, LecturesModule],
controllers: [ShareController],
providers: [ShareService],
})
Expand Down
Loading

0 comments on commit 1e31d6b

Please sign in to comment.