Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: 2023-01-21 비정기 배포 #815

Merged
merged 24 commits into from
Jan 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fa9559c
ci: 타입오류 메시지 상대경로 명시적으로 해소 (#643)
scarf005 Sep 7, 2023
93fc7b4
feat: v2 book api (#746)
JeongJiHwan Sep 7, 2023
8b7c07f
style: prettier 적용 (#761)
scarf005 Sep 7, 2023
c88ca8d
[fix] backend dockerfile error (#764)
weg901127 Sep 8, 2023
1565441
fix: `positiveInt` -> `nonNegativeInt` (#766)
scarf005 Sep 11, 2023
6cbb823
refactor: v2 라우트 정리 적용 (#771)
scarf005 Sep 14, 2023
1ac5b23
feat: add mydata service
jimin52 Sep 21, 2023
7094331
feat: 유저 search 할 때 id 가 undefined 인 경우 핸들링
jimin52 Sep 21, 2023
1c8b49b
feat: add swagger && /me endpoint && apply authValidate
jimin52 Sep 21, 2023
71c1216
Merge branch 'develop' into 778-auth-관련-api-무조건-200-리턴-버그
jimin52 Sep 21, 2023
5754bef
fix: searchUsersById 타입을 이전과 같이 리턴하도록 변경
jimin52 Sep 21, 2023
7fbfa10
Merge branch '778-auth-관련-api-무조건-200-리턴-버그' of https://github.com/ji…
jimin52 Sep 21, 2023
1449028
fix: add librarian validate in search endpoint
jimin52 Sep 21, 2023
cda9990
feat: 로그인한 유저만 본인 정보를 찾을 수 있도록 middleware 에서 권한 체크
jimin52 Sep 26, 2023
7b7ad82
chore: console.log 제거
jimin52 Sep 26, 2023
c5bd7ae
Merge pull request #779 from jiphyeonjeon-42/778-auth-관련-api-무조건-200-…
jimin52 Oct 1, 2023
cf970dd
User API 경로 정리 (#777)
nyj001012 Oct 23, 2023
d7bca34
fix(cursus): Access-Control-Allow-Origin 설정 (#790)
nyj001012 Oct 25, 2023
53da6fd
chore: dependencies 업데이트 (#796)
nyj001012 Nov 6, 2023
6878ceb
fix: users/me 유저권한 all 로 변경
jimin52 Nov 27, 2023
f943af5
fix: 반납 3일 전 알림이 여러 번 전송됨 (#801)
nyj001012 Jan 13, 2024
8bee80b
fix: `dev/v2` 경로 복구 (#808)
scarf005 Jan 27, 2024
35a8192
security: 보안 취약점 해결 (#818)
nyj001012 Jan 27, 2024
59c4eec
fix(auth): /get/me시, id가 null이면 400 status code 반환 (#816)
nyj001012 Jan 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"jest": true
},
"root": true,
"extends": ["airbnb-base", "plugin:@typescript-eslint/recommended"],
"extends": ["airbnb-base", "plugin:@typescript-eslint/recommended", "prettier"],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "import"],
"parserOptions": {
Expand Down
19 changes: 10 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ name: Test
on:
pull_request:

defaults:
run:
shell: bash

jobs:
test:
name: Test PR
runs-on: ubuntu-latest
environment: development

steps:
- uses: reviewdog/action-setup@v1

- name: Checkout
uses: actions/checkout@v3

Expand Down Expand Up @@ -40,12 +46,7 @@ jobs:
pnpm install --frozen-lockfile
pnpm --filter='@jiphyeonjeon-42/contracts' build

- if: always()
name: check types (backend)
working-directory: backend
run: pnpm check

- if: always()
name: check types (contracts)
working-directory: contracts
run: pnpm check
- name: check types
if: always()
run: |
pnpm -r --no-bail --parallel run check | sed -r 's|(.*)( check: )(.*)|\1/\3|'
7 changes: 7 additions & 0 deletions .prettierrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
semi: true
singleQuote: true
useTabs: false
tabWidth: 2
trailingComma: all
printWidth: 100
arrowParens: always
6 changes: 6 additions & 0 deletions Dockerfile
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

도커에 추가된 파이썬은 어느 부분에 쓰이게 되나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재는 사용 중인 부분이 없네요. 컨테이너 내부에서 뭔가 하려고 하셨던 거 같은데. 일단 지금은 쓰지 않고 있습니다.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ FROM node:18-alpine as pnpm-installed
# https://github.com/pnpm/pnpm/issues/4495#issuecomment-1317831712
ENV PNPM_HOME="/root/.local/share/pnpm"
ENV PATH="${PATH}:${PNPM_HOME}"
ENV PYTHONUNBUFFERED=1
RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
RUN python3 -m ensurepip
RUN pip3 install --no-cache --upgrade pip setuptools
RUN apk add --no-cache make
RUN apk add build-base
RUN npm install --global pnpm
RUN pnpm config set store-dir .pnpm-store
RUN pnpm install --global node-pre-gyp
Expand Down
5 changes: 5 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
"@types/cookie-parser": "^1.4.3",
"@types/cors": "^2.8.13",
"@types/express": "^4.17.17",
"@types/express-session": "^1.17.10",
"@types/http-errors": "^2.0.1",
"@types/jest": "^29.5.2",
"@types/jsonwebtoken": "^9.0.2",
"@types/lusca": "^1.7.4",
"@types/morgan": "^1.9.4",
"@types/node-schedule": "^2.1.0",
"@types/passport": "^1.0.12",
Expand All @@ -49,6 +51,7 @@
},
"dependencies": {
"@jiphyeonjeon-42/contracts": "workspace:*",
"@mapbox/node-pre-gyp": "^1.0.11",
"@slack/web-api": "^6.7.1",
"@ts-rest/express": "^3.28.0",
"@ts-rest/open-api": "^3.28.0",
Expand All @@ -60,13 +63,15 @@
"dotenv": "^16.0.0",
"express": "^4.17.2",
"express-rate-limit": "^6.9.0",
"express-session": "^1.17.3",
"hangul-js": "^0.2.6",
"http-errors": "^2.0.0",
"http-status": "^1.5.0",
"http-terminator": "^3.2.0",
"jsonwebtoken": "^8.5.1",
"kysely": "^0.26.1",
"kysely-paginate": "^0.2.0",
"lusca": "^1.7.0",
"morgan": "^1.10.0",
"mysql2": "^2.3.3",
"node-schedule": "^2.1.0",
Expand Down
19 changes: 18 additions & 1 deletion backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,29 @@ import { createExpressEndpoints } from '@ts-rest/express';

import router from '~/v1/routes';
import routerV2 from '~/v2/routes';
import lusca from "lusca";
import session from 'express-session';
import * as crypto from "crypto";
import { morganMiddleware } from './logger';

const app: express.Application = express();
const secret = crypto.randomBytes(42).toString('hex');

app.use(session({
secret,
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
sameSite: 'strict',
secure: true,
}
}));
app.use(morganMiddleware);
app.use(cookieParser());
app.use(cookieParser(
secret,
));
app.use(lusca.csrf());
app.use(passport.initialize());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
Expand Down
24 changes: 13 additions & 11 deletions backend/src/config/JwtOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@ import { Mode } from './modeOption';
import { match } from 'ts-pattern';

type getJwtOption = (mode: Mode) => (option: OauthUrlOption) => JwtOption;
export const getJwtOption: getJwtOption = (mode) => ({ redirectURL, clientURL }) => {
const redirectDomain = new URL(redirectURL).hostname;
const clientDomain = new URL(clientURL).hostname;
const secure = mode === 'prod' || mode === 'https';
export const getJwtOption: getJwtOption =
(mode) =>
({ redirectURL, clientURL }) => {
const redirectDomain = new URL(redirectURL).hostname;
const clientDomain = new URL(clientURL).hostname;
const secure = mode === 'prod' || mode === 'https';

const issuer = secure ? redirectDomain : 'localhost';
const domain = match(mode)
.with('prod', () => clientDomain)
.with('https', () => undefined)
.otherwise(() => 'localhost');
const issuer = secure ? redirectDomain : 'localhost';
const domain = match(mode)
.with('prod', () => clientDomain)
.with('https', () => undefined)
.otherwise(() => 'localhost');

return { issuer, domain, secure };
};
return { issuer, domain, secure };
};

export const jwtSecretSchema = z.object({ JWT_SECRET: nonempty }).transform((v) => v.JWT_SECRET);

Expand Down
10 changes: 5 additions & 5 deletions backend/src/config/config.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export type NaverBookApiOption = {

/** 네이버 도서 검색 API 시크릿 */
secret: string;
}
};

/** DB 연결 옵션 */
export type ConnectOption = {
Expand All @@ -34,7 +34,7 @@ export type ConnectOption = {

/** DB 이름 */
database: string;
}
};

/** OAuth URL 옵션 */
export type OauthUrlOption = {
Expand All @@ -43,7 +43,7 @@ export type OauthUrlOption = {

/** 집현전 프론트엔드 URL */
clientURL: string;
}
};

/** 42 API OAuth 클라이언트 인증 정보 */
export type Oauth42ApiOption = {
Expand All @@ -52,7 +52,7 @@ export type Oauth42ApiOption = {

/** 42 API OAuth 클라이언트 시크릿 */
secret: string;
}
};

/** npm 로깅 레벨 */
export type LogLevel = keyof typeof levels;
Expand All @@ -64,4 +64,4 @@ export type LogLevelOption = {

/** 콘솔 로깅 레벨 */
readonly consoleLogLevel: 'error' | 'debug';
}
};
18 changes: 11 additions & 7 deletions backend/src/config/dbSchema.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { envObject, nonempty } from './envObject';

/** RDS 연결 옵션 파싱을 위한 스키마 */
export const rdsSchema = envObject('RDS_HOSTNAME', 'RDS_USERNAME', 'RDS_PASSWORD', 'RDS_DB_NAME')
.transform((v) => ({
host: v.RDS_HOSTNAME,
username: v.RDS_USERNAME,
password: v.RDS_PASSWORD,
database: v.RDS_DB_NAME,
}));
export const rdsSchema = envObject(
'RDS_HOSTNAME',
'RDS_USERNAME',
'RDS_PASSWORD',
'RDS_DB_NAME',
).transform((v) => ({
host: v.RDS_HOSTNAME,
username: v.RDS_USERNAME,
password: v.RDS_PASSWORD,
database: v.RDS_DB_NAME,
}));

/** MYSQL 연결 옵션 파싱을 위한 스키마 */
const mysqlSchema = envObject('MYSQL_USER', 'MYSQL_PASSWORD', 'MYSQL_DATABASE')
Expand Down
2 changes: 1 addition & 1 deletion backend/src/config/envObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const url = z.string().trim().url();
* @param keys 환경변수 키 목록
*/
export const envObject = <T extends readonly string[]>(...keys: T) => {
type Keys = T[ number ];
type Keys = T[number];
const env = Object.fromEntries(keys.map((key) => [key, nonempty]));

return z.object(env as Record<Keys, typeof nonempty>);
Expand Down
10 changes: 6 additions & 4 deletions backend/src/config/getConnectOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ const getConnectOptionSchema = (mode: Mode) => {
/**
* 환경변수에서 DB 연결 옵션을 파싱하는 함수
*/
export const getConnectOption = (mode: Mode) => (processEnv: NodeJS.ProcessEnv): ConnectOption => {
const connectOptionSchema = getConnectOptionSchema(mode);
export const getConnectOption =
(mode: Mode) =>
(processEnv: NodeJS.ProcessEnv): ConnectOption => {
const connectOptionSchema = getConnectOptionSchema(mode);

return connectOptionSchema.parse(processEnv);
};
return connectOptionSchema.parse(processEnv);
};
4 changes: 2 additions & 2 deletions backend/src/config/logOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export const colors: Record<LogLevel, string> = {
} as const;

export const getLogLevelOption = (mode: RuntimeMode): LogLevelOption => {
const logLevel = (mode === 'production' ? 'http' : 'debug');
const consoleLogLevel = (mode === 'production' ? 'error' : 'debug');
const logLevel = mode === 'production' ? 'http' : 'debug';
const consoleLogLevel = mode === 'production' ? 'error' : 'debug';

return { logLevel, consoleLogLevel } as const;
};
12 changes: 7 additions & 5 deletions backend/src/config/naverBookApiOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
import { NaverBookApiOption } from './config.type';
import { envObject } from './envObject';

const naverBookApiSchema = envObject('NAVER_BOOK_SEARCH_CLIENT_ID', 'NAVER_BOOK_SEARCH_SECRET')
.transform((v) => ({
client: v.NAVER_BOOK_SEARCH_CLIENT_ID,
secret: v.NAVER_BOOK_SEARCH_SECRET,
}));
const naverBookApiSchema = envObject(
'NAVER_BOOK_SEARCH_CLIENT_ID',
'NAVER_BOOK_SEARCH_SECRET',
).transform((v) => ({
client: v.NAVER_BOOK_SEARCH_CLIENT_ID,
secret: v.NAVER_BOOK_SEARCH_SECRET,
}));

export const getNaverBookApiOption = (processEnv: NodeJS.ProcessEnv): NaverBookApiOption => {
const option = naverBookApiSchema.parse(processEnv);
Expand Down
24 changes: 14 additions & 10 deletions backend/src/config/oauthOption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ export const oauth42Schema = z.object({
CLIENT_SECRET: nonempty,
});

export const getOauthUrlOption = (processEnv: NodeJS.ProcessEnv): OauthUrlOption => oauthUrlSchema
.transform((v) => ({
redirectURL: v.REDIRECT_URL,
clientURL: v.CLIENT_URL,
})).parse(processEnv);
export const getOauthUrlOption = (processEnv: NodeJS.ProcessEnv): OauthUrlOption =>
oauthUrlSchema
.transform((v) => ({
redirectURL: v.REDIRECT_URL,
clientURL: v.CLIENT_URL,
}))
.parse(processEnv);

// eslint-disable-next-line max-len
export const getOauth42ApiOption = (processEnv: NodeJS.ProcessEnv): Oauth42ApiOption => oauth42Schema
.transform((v) => ({
id: v.CLIENT_ID,
secret: v.CLIENT_SECRET,
})).parse(processEnv);
export const getOauth42ApiOption = (processEnv: NodeJS.ProcessEnv): Oauth42ApiOption =>
oauth42Schema
.transform((v) => ({
id: v.CLIENT_ID,
secret: v.CLIENT_SECRET,
}))
.parse(processEnv);
33 changes: 19 additions & 14 deletions backend/src/entity/entities/Book.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import {
Column, Entity, Index, JoinColumn, ManyToOne, OneToMany, PrimaryGeneratedColumn,
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
import { BookInfo } from './BookInfo';
import { User } from './User';
Expand All @@ -8,55 +14,54 @@ import { Reservation } from './Reservation';

@Index('FK_donator_id_from_user', ['donatorId'], {})
@Entity('book')

export class Book {
@PrimaryGeneratedColumn({ type: 'int', name: 'id' })
id?: number;
id?: number;

@Column('varchar', { name: 'donator', nullable: true, length: 255 })
donator: string | null;
donator: string | null;

@Column('varchar', { name: 'callSign', length: 255 })
callSign: string;
callSign: string;

@Column('int', { name: 'status' })
status: number;
status: number;

@Column('datetime', {
name: 'createdAt',
default: () => "'CURRENT_TIMESTAMP(6)'",
})
createdAt?: Date;
createdAt?: Date;

@Column('int')
infoId: number;
infoId: number;

@Column('datetime', {
name: 'updatedAt',
default: () => "'CURRENT_TIMESTAMP(6)'",
})
updatedAt?: Date;
updatedAt?: Date;

@Column('int', { name: 'donatorId', nullable: true })
donatorId: number | null;
donatorId: number | null;

@ManyToOne(() => BookInfo, (bookInfo) => bookInfo.books, {
onDelete: 'NO ACTION',
onUpdate: 'NO ACTION',
})
@JoinColumn([{ name: 'infoId', referencedColumnName: 'id' }])
info?: BookInfo;
info?: BookInfo;

@ManyToOne(() => User, (user) => user.books, {
onDelete: 'NO ACTION',
onUpdate: 'NO ACTION',
})
@JoinColumn([{ name: 'donatorId', referencedColumnName: 'id' }])
donator2?: User;
donator2?: User;

@OneToMany(() => Lending, (lending) => lending.book)
lendings?: Lending[];
lendings?: Lending[];

@OneToMany(() => Reservation, (reservation) => reservation.book)
reservations?: Reservation[];
reservations?: Reservation[];
}
Loading
Loading