Skip to content

Commit fc02848

Browse files
Merge pull request #68 from se-gam/dev
feat: 공지사항 기능 및 어드민 API 추가
2 parents 1ea401d + a9cf104 commit fc02848

15 files changed

Lines changed: 458 additions & 9 deletions

File tree

‎.github/workflows/dev.yml‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ jobs:
1717
- name: Checkout
1818
uses: actions/checkout@v3
1919

20-
- name: Create .env file
21-
run: |
22-
jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' <<< "$SECRETS_CONTEXT" > .dev.env
23-
env:
24-
SECRETS_CONTEXT: ${{ toJson(secrets) }}
20+
# - name: Create .env file
21+
# run: |
22+
# jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' <<< "$SECRETS_CONTEXT" > .dev.env
23+
# env:
24+
# SECRETS_CONTEXT: ${{ toJson(secrets) }}
2525

2626
- name: Install dependencies and build
2727
run: |
@@ -41,5 +41,6 @@ jobs:
4141
cd /home/${{ secrets.DEV_SERVER_USER }}/segam-backend
4242
git pull origin dev
4343
yarn install
44+
yarn db:save:dev
4445
yarn build
4546
dotenv -e .dev.env -- pm2 restart main
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- CreateTable
2+
CREATE TABLE "notice" (
3+
"id" INTEGER NOT NULL,
4+
"title" TEXT NOT NULL,
5+
"content" TEXT NOT NULL,
6+
"is_popup" BOOLEAN NOT NULL DEFAULT false,
7+
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
8+
"deleted_at" TIMESTAMP(3),
9+
10+
CONSTRAINT "notice_pkey" PRIMARY KEY ("id")
11+
);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- AlterTable
2+
CREATE SEQUENCE notice_id_seq;
3+
ALTER TABLE "notice" ALTER COLUMN "id" SET DEFAULT nextval('notice_id_seq');
4+
ALTER SEQUENCE notice_id_seq OWNED BY "notice"."id";

‎prisma/schema/notice/notice.prisma‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
model Notice {
2+
id Int @id @default(autoincrement())
3+
title String
4+
content String
5+
isPopup Boolean @default(false) @map("is_popup")
6+
createdAt DateTime @default(now()) @map("created_at")
7+
deletedAt DateTime? @map("deleted_at")
8+
9+
@@map("notice")
10+
}

‎src/app/app.module.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ import { AttendanceModule } from 'src/attendance/attendance.module';
33
import { AuthModule } from 'src/auth/auth.module';
44
import { CommonModule } from 'src/common/common.module';
55
import { LoggerMiddleware } from 'src/common/middlewares/logger.middleware';
6+
import { GodokModule } from 'src/godok/godok.module';
7+
import { NoticeModule } from 'src/notice/notice.module';
68
import { RestaurantModule } from 'src/restaurant/restaurant.module';
79
import { StudyroomModule } from 'src/studyroom/studyroom.module';
810
import { UserModule } from 'src/user/user.module';
911
import { AppController } from './app.controller';
1012
import { AppService } from './app.service';
1113
import { configModule } from './modules/config.module';
12-
import { GodokModule } from 'src/godok/godok.module';
1314

1415
@Module({
1516
imports: [
@@ -21,6 +22,7 @@ import { GodokModule } from 'src/godok/godok.module';
2122
UserModule,
2223
RestaurantModule,
2324
GodokModule,
25+
NoticeModule,
2426
],
2527
controllers: [AppController],
2628
providers: [AppService],

‎src/auth/pipes/signup-validation.pipe.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ export class PasswordValidationPipe implements PipeTransform {
1818
value: PasswordPayload,
1919
metadata: ArgumentMetadata,
2020
): PasswordPayload {
21-
if (this.configService.get('NODE_ENV') === 'local') {
22-
return value;
23-
}
21+
// if (this.configService.get('NODE_ENV') === 'local') {
22+
// return value;
23+
// }
2424

2525
const pattern =
2626
/^[0-9a-fA-F]{32}:(?:[0-9a-fA-F]{32}|[0-9a-fA-F]{64}|[0-9a-fA-F]{96})$/;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { Notice } from '@prisma/client';
3+
4+
export class NoticePreviewDto {
5+
@ApiProperty({
6+
description: '공지사항 id',
7+
example: 1,
8+
type: Number,
9+
})
10+
id!: number;
11+
12+
@ApiProperty({
13+
description: '공지사항 제목',
14+
example: '공지사항 제목',
15+
type: String,
16+
})
17+
title!: string;
18+
19+
@ApiProperty({
20+
description: '공지사항 생성 일자',
21+
type: Date,
22+
})
23+
createdAt!: Date;
24+
25+
static from(notice: Notice): NoticePreviewDto {
26+
return {
27+
id: notice.id,
28+
title: notice.title,
29+
createdAt: notice.createdAt,
30+
};
31+
}
32+
}

‎src/notice/dto/notice.dto.ts‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { Notice } from '@prisma/client';
3+
4+
export class NoticeDto {
5+
@ApiProperty({
6+
description: '공지사항 id',
7+
example: 1,
8+
type: Number,
9+
})
10+
id!: number;
11+
12+
@ApiProperty({
13+
description: '공지사항 제목',
14+
example: '공지사항 제목',
15+
type: String,
16+
})
17+
title!: string;
18+
19+
@ApiProperty({
20+
description: '공지사항 내용',
21+
example: '공지사항 내용',
22+
type: String,
23+
})
24+
content!: string;
25+
26+
@ApiProperty({
27+
description: '팝업 공지사항 여부',
28+
example: false,
29+
type: Boolean,
30+
})
31+
isPopup!: boolean;
32+
33+
@ApiProperty({
34+
description: '공지사항 생성 일자',
35+
type: Date,
36+
})
37+
createdAt!: Date;
38+
39+
@ApiProperty({
40+
description: '공지사항 삭제 일자',
41+
type: Date,
42+
})
43+
deletedAt?: Date;
44+
45+
static from(notice: Notice): NoticeDto {
46+
return {
47+
id: notice.id,
48+
title: notice.title,
49+
content: notice.content,
50+
isPopup: notice.isPopup,
51+
createdAt: notice.createdAt,
52+
deletedAt: notice.deletedAt,
53+
};
54+
}
55+
}

‎src/notice/notice.controller.ts‎

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import {
2+
Body,
3+
Controller,
4+
Delete,
5+
Get,
6+
Param,
7+
ParseIntPipe,
8+
Post,
9+
Put,
10+
Version,
11+
} from '@nestjs/common';
12+
import { ApiOkResponse, ApiOperation, ApiTags } from '@nestjs/swagger';
13+
import { NoticeDto } from './dto/notice.dto';
14+
import { NoticeService } from './notice.service';
15+
import { CreateUpdateNoticePayload } from './payload/create-update-notice.payload';
16+
import { NoticePreviewDto } from './dto/notice-preview.dto';
17+
18+
@ApiTags('공지사항 API')
19+
@Controller('notice')
20+
export class NoticeController {
21+
constructor(private readonly noticeService: NoticeService) {}
22+
23+
@Version('1')
24+
@ApiOperation({
25+
summary: '팝업 공지사항 조회 API',
26+
description: '팝업 공지사항을 조회합니다.',
27+
})
28+
@Get('popup')
29+
async getPopupNotice(): Promise<NoticeDto> {
30+
return this.noticeService.getPopupNotice();
31+
}
32+
33+
@Version('1')
34+
@ApiOperation({
35+
summary: '팝업 공지사항 등록 API',
36+
description: '팝업 공지사항을 등록합니다.',
37+
})
38+
@Post('popup/:id')
39+
async createPopupNotice(@Param('id') id: number): Promise<void> {
40+
return this.noticeService.createPopupNotice(id);
41+
}
42+
43+
@Version('1')
44+
@ApiOperation({
45+
summary: '공지사항 생성 API',
46+
description: '공지사항을 생성합니다.',
47+
})
48+
@Post('')
49+
async createNotice(
50+
@Body() payload: CreateUpdateNoticePayload,
51+
): Promise<void> {
52+
return this.noticeService.createNotice(payload);
53+
}
54+
55+
@Version('1')
56+
@ApiOperation({
57+
summary: '공지사항 수정 API',
58+
description: '공지사항을 수정합니다.',
59+
})
60+
@Put(':id')
61+
async updateNotice(
62+
@Param('id') id: number,
63+
@Body() payload: CreateUpdateNoticePayload,
64+
): Promise<void> {
65+
return this.noticeService.updateNotice(id, payload);
66+
}
67+
68+
@Version('1')
69+
@ApiOperation({
70+
summary: '공지사항 삭제 API',
71+
description: '공지사항을 삭제합니다.',
72+
})
73+
@Delete(':id')
74+
async deleteNotice(@Param('id') id: number): Promise<void> {
75+
return this.noticeService.deleteNotice(id);
76+
}
77+
78+
@Version('1')
79+
@ApiOperation({
80+
summary: '공지사항 조회 api',
81+
description: '공지사항을 조회합니다.',
82+
})
83+
@ApiOkResponse({
84+
description: '전체 공지사항의 id, title, createdAt 필드를 조회합니다.',
85+
type: [NoticePreviewDto],
86+
})
87+
@Get()
88+
async getNotice(): Promise<NoticePreviewDto[]> {
89+
return this.noticeService.getNotice();
90+
}
91+
92+
@Version('1')
93+
@ApiOperation({
94+
summary: '공지사항 단일조회 api',
95+
description: '특정 공지사항을 조회합니다.',
96+
})
97+
@ApiOkResponse({
98+
type: NoticeDto,
99+
})
100+
@Get('/:id')
101+
async getNoticeById(
102+
@Param('id', ParseIntPipe) id: number,
103+
): Promise<NoticeDto> {
104+
return this.noticeService.getNoticeById(id);
105+
}
106+
}

‎src/notice/notice.module.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Module } from '@nestjs/common';
2+
import { NoticeController } from './notice.controller';
3+
import { NoticeRepository } from './notice.repository';
4+
import { NoticeService } from './notice.service';
5+
6+
@Module({
7+
controllers: [NoticeController],
8+
providers: [NoticeService, NoticeRepository],
9+
})
10+
export class NoticeModule {}

0 commit comments

Comments
 (0)