Skip to content

Commit c606baf

Browse files
Merge pull request #44 from boostcampwm-2024/develop
v1.1.0 release 배포
2 parents 15781ae + 2b59850 commit c606baf

File tree

89 files changed

+1162
-1052
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+1162
-1052
lines changed

.github/workflows/cd-pipeline.yml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: auto Workflow
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
jobs:
9+
image-build-and-push:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: checkout
14+
uses: actions/checkout@v3
15+
16+
# root에 .env.local, .env.client, .env.server 복사
17+
- name: copy .env
18+
run: |
19+
echo "${{ secrets.LOCAL_ENV }}" > .env.local
20+
echo "${{ secrets.CLIENT_ENV }}" > .env.client
21+
echo "${{ secrets.SERVER_ENV }}" > .env.server
22+
23+
# Docker 로그인
24+
- name: docker hub login
25+
uses: docker/login-action@v2
26+
with:
27+
username: ${{ secrets.DOCKER_USERNAME }}
28+
password: ${{ secrets.DOCKER_PASSWORD }}
29+
30+
# Docker 이미지 빌드
31+
- name: docker image build
32+
run: |
33+
docker build -f ./services/module/Dockerfile -t summersummerwhy/octodocs-modules .
34+
docker build -f ./services/backend/Dockerfile.prod -t summersummerwhy/octodocs-backend .
35+
docker build -f ./services/nginx/Dockerfile.prod -t summersummerwhy/octodocs-nginx .
36+
docker build -f ./services/websocket/Dockerfile.prod -t summersummerwhy/octodocs-websocket .
37+
38+
# Docker 이미지 푸시
39+
- name: docker image push
40+
run: |
41+
docker push summersummerwhy/octodocs-modules
42+
docker push summersummerwhy/octodocs-backend
43+
docker push summersummerwhy/octodocs-nginx
44+
docker push summersummerwhy/octodocs-websocket
45+
46+
deploy:
47+
needs: image-build-and-push
48+
runs-on: ubuntu-latest
49+
50+
steps:
51+
- name: deploy
52+
env:
53+
REMOTE_HOST: ${{ secrets.REMOTE_SERVER_IP }}
54+
REMOTE_USER: ${{ secrets.REMOTE_SERVER_USER }}
55+
SSH_KEY: ${{ secrets.REMOTE_PRIVATE_KEY }}
56+
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
57+
run: |
58+
mkdir ~/.ssh
59+
echo "$SSH_KEY" > ~/.ssh/id_rsa
60+
chmod 600 ~/.ssh/id_rsa
61+
62+
ssh -o StrictHostKeyChecking=no $REMOTE_USER@$REMOTE_HOST << 'EOF'
63+
cd /root/octodocs
64+
docker-compose -f compose.prod.yml down
65+
docker-compose -f compose.prod.yml pull
66+
docker-compose -f compose.prod.yml up -d

.github/workflows/develop.yml

Lines changed: 0 additions & 105 deletions
This file was deleted.

Dockerfile.module

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# node_modules를 가지고 있는 이미지
2+
# 이 이미지를 기반으로 각 workspace 별 이미지를 만들면
3+
# yarn install 레이어를 공유하게 된다.
4+
FROM node:20-alpine
5+
6+
WORKDIR /app
7+
8+
# 호이스팅을 위해
9+
COPY package.json yarn.lock ./
10+
COPY apps/backend/package.json ./apps/backend/
11+
COPY apps/frontend/package.json ./apps/frontend/
12+
COPY apps/websocket/package.json ./apps/websocket/
13+
14+
# 의존성 설치
15+
RUN yarn install

apps/backend/src/app.module.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import { WorkspaceModule } from './workspace/workspace.module';
2020
import { RoleModule } from './role/role.module';
2121
import { TasksModule } from './tasks/tasks.module';
2222
import { ScheduleModule } from '@nestjs/schedule';
23-
import { RedLockModule } from './red-lock/red-lock.module';
2423

2524
@Module({
2625
imports: [
@@ -54,7 +53,6 @@ import { RedLockModule } from './red-lock/red-lock.module';
5453
WorkspaceModule,
5554
RoleModule,
5655
TasksModule,
57-
RedLockModule,
5856
],
5957
controllers: [AppController],
6058
providers: [AppService],

apps/backend/src/auth/auth.controller.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,22 @@ import { AuthService } from './auth.service';
1313
import { JwtAuthGuard } from './guards/jwt-auth.guard';
1414
import { Response } from 'express';
1515
import { MessageResponseDto } from './dtos/messageResponse.dto';
16+
import { LoginResponseDto } from './dtos/loginResponse.dto';
1617
import { ApiOperation, ApiResponse } from '@nestjs/swagger';
1718
import { TokenService } from './token/token.service';
1819
import { UpdateUserDto } from './dtos/UpdateUser.dto';
1920

2021
export enum AuthResponseMessage {
2122
AUTH_LOGGED_OUT = '로그아웃하였습니다.',
23+
AUTH_STATUS = '로그인 여부를 확인하였습니다',
2224
}
2325

2426
@Controller('auth')
2527
export class AuthController {
2628
constructor(
2729
private readonly authService: AuthService,
2830
private readonly tokenService: TokenService,
31+
private readonly jwtAuthGuard: JwtAuthGuard,
2932
) {}
3033

3134
@Get('naver')
@@ -94,6 +97,19 @@ export class AuthController {
9497
});
9598
}
9699

100+
// 클라이언트가 사용자가 로그인되어 있는지 확인할 수 있는 엔드포인트
101+
// auth/status
102+
@ApiResponse({ type: LoginResponseDto })
103+
@ApiOperation({ summary: '사용자가 로그인 여부를 체크합니다.' })
104+
@Get('status')
105+
async checkLogin(@Req() req, @Res() res: Response) {
106+
const isLoggedIn = await this.jwtAuthGuard.isLoggedIn(req, res);
107+
return res.status(200).json({
108+
message: AuthResponseMessage.AUTH_STATUS,
109+
loggedIn: isLoggedIn,
110+
});
111+
}
112+
97113
// 클라이언트가 사용자의 외부 id(snowflakeId) + 이름을 알 수 있는 엔드포인트
98114
// auth/profile
99115
@Get('profile')
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { IsString, IsBoolean } from 'class-validator';
3+
4+
export class LoginResponseDto {
5+
@ApiProperty({
6+
example: 'OO 생성에 성공했습니다.',
7+
description: 'api 요청 결과 메시지',
8+
})
9+
@IsString()
10+
message: string;
11+
12+
@ApiProperty({
13+
example: true,
14+
description: '로그인 여부',
15+
})
16+
@IsBoolean()
17+
loggedIn: string;
18+
}

apps/backend/src/auth/guards/jwt-auth.guard.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,48 @@ export class JwtAuthGuard implements CanActivate {
6767
}
6868
}
6969
}
70+
71+
// 제대로 로그인이 안되어있으면 exception 대신 false return
72+
// 쿠키 처리해줌
73+
async isLoggedIn(request, response): Promise<boolean> {
74+
const cookies = request.cookies;
75+
76+
// 쿠키가 없는 경우 false 반환
77+
if (!cookies || !cookies.accessToken || !cookies.refreshToken) {
78+
return false;
79+
}
80+
81+
const { accessToken, refreshToken } = cookies;
82+
83+
try {
84+
// JWT 검증
85+
this.jwtService.verify(accessToken, {
86+
secret: process.env.JWT_SECRET,
87+
});
88+
89+
return true;
90+
} catch (error) {
91+
// accessToken이 만료된 경우
92+
if (error instanceof TokenExpiredError) {
93+
try {
94+
// 새로운 accessToken 발급받기
95+
const newAccessToken =
96+
await this.tokenService.refreshAccessToken(refreshToken);
97+
98+
// 쿠키 업데이트
99+
this.tokenService.setAccessTokenCookie(response, newAccessToken);
100+
101+
return true;
102+
} catch (refreshError) {
103+
// refreshToken 디코딩 실패 시 처리 쿠키 비워줌
104+
this.tokenService.clearCookies(response);
105+
return false;
106+
}
107+
} else {
108+
// accessToken 디코딩(만료가 아닌 이유로) 실패 시 처리 쿠키 비워줌
109+
this.tokenService.clearCookies(response);
110+
return false;
111+
}
112+
}
113+
}
70114
}

apps/backend/src/page/page.module.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@ import { Page } from './page.entity';
66
import { PageRepository } from './page.repository';
77
import { NodeModule } from '../node/node.module';
88
import { WorkspaceModule } from '../workspace/workspace.module';
9-
import { RedLockModule } from '../red-lock/red-lock.module';
109

1110
@Module({
1211
imports: [
1312
TypeOrmModule.forFeature([Page]),
1413
forwardRef(() => NodeModule),
1514
WorkspaceModule,
16-
RedLockModule,
1715
],
1816
controllers: [PageController],
1917
providers: [PageService, PageRepository],

0 commit comments

Comments
 (0)