Skip to content

Commit

Permalink
Merge pull request #311 from boostcampwm-2021/dev
Browse files Browse the repository at this point in the history
version 1.0.0 release
  • Loading branch information
9b2n authored Dec 2, 2021
2 parents d50d8c5 + 7c481b2 commit d181a0a
Show file tree
Hide file tree
Showing 161 changed files with 6,503 additions and 21,102 deletions.
6 changes: 5 additions & 1 deletion back/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ FROM node:16-alpine

WORKDIR /app
COPY . .

RUN yarn install
RUN yarn global add pm2
RUN yarn build

EXPOSE 3000
CMD ["yarn","run","start"]
CMD ["yarn","start:prod"]
4 changes: 4 additions & 0 deletions back/common/constants/nums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const PAGE_LIMIT = 10;
const UPLOAD_LIMIT = 8;

export { PAGE_LIMIT, UPLOAD_LIMIT };
8 changes: 5 additions & 3 deletions back/common/dto/cursor-pagination.dto.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty } from 'class-validator';
import { IsInt, IsNotEmpty, IsNumberString, IsOptional, IsPositive } from 'class-validator';
export class CursorPaginationDto {
@IsOptional()
@ApiProperty({ required: false })
lastId?: number;

@ApiProperty()
@IsNotEmpty()
limit: number;
@IsOptional()
@IsNumberString()
limit?: number;
}
10 changes: 5 additions & 5 deletions back/common/dto/pagination-query.dto.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty } from 'class-validator';
import { IsOptional } from 'class-validator';

export class PaginationQueryDto {
@IsNotEmpty()
@IsOptional()
@ApiProperty()
skip: number;
skip?: number;

@IsNotEmpty()
@IsOptional()
@ApiProperty()
take: number;
take?: number;
}
40 changes: 40 additions & 0 deletions back/common/error/AllExceptionsFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpStatus,
NotFoundException,
BadRequestException,
UnauthorizedException,
} from '@nestjs/common';
import { TypeORMError } from 'typeorm';
import * as dotenv from 'dotenv';
dotenv.config();
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: any, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
let message = '';
let status = 200;
process.env.NODE_ENV === 'dev' && console.log(exception);
if (exception instanceof HttpException) {
status = exception.getStatus();
message = (exception as any).response.message;
} else if (exception instanceof TypeORMError) {
message = 'DB ์• ๋Ÿฌ์ž…๋‹ˆ๋‹ค.';
status = HttpStatus.SERVICE_UNAVAILABLE;
} else {
status = HttpStatus.INTERNAL_SERVER_ERROR;
message = 'internal server error';
}
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message,
});
}
}
9 changes: 9 additions & 0 deletions back/common/pipes/parse-optional-string.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';

@Injectable()
export class ParseOptionalStringPipe implements PipeTransform<string | undefined> {
transform(value: string | undefined, metadata: ArgumentMetadata): string | undefined {
if (!['string', 'undefined'].includes(typeof value)) throw new BadRequestException();
return value;
}
}
12 changes: 9 additions & 3 deletions back/config/auth.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import * as dotenv from 'dotenv';

dotenv.config();

const EXPIRE_TIME = 60 * 60;
const ACCESS_EXPIRE_TIME = 2 * 60 * 60;
const REFRESH_EXPIRE_TIME = 2 * 7 * 24 * 60 * 60;

export const jwtOption = {
secret: process.env.AUTH_SECRET_KEY,
signOptions: { expiresIn: EXPIRE_TIME },
secret: process.env.AUTH_ACCESS_SECRET_KEY,
expiresIn: ACCESS_EXPIRE_TIME,
};

export const jwtRefeshOption = {
secret: process.env.AUTH_REFRESH_SECRET_KEY,
expiresIn: REFRESH_EXPIRE_TIME,
};
5 changes: 2 additions & 3 deletions back/config/database.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ const databaseConfig: TypeOrmModuleOptions = {
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
entities: [__dirname + '/../**/*.entity{.ts,.js}'],
// autoLoadEntities: true,
synchronize: false,
logging: true,
timezone: 'KST',
logging: process.env.NODE_ENV === 'db_dev',
timezone: '+00:00',
};

export default databaseConfig;
4 changes: 4 additions & 0 deletions back/config/logger.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import * as dotenv from 'dotenv';
dotenv.config();

export const loggerEnv = process.env.NODE_ENV === 'dev' ? 'dev' : 'combined';
47 changes: 41 additions & 6 deletions back/config/s3.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as AWS from 'aws-sdk';
import * as multerS3 from 'multer-s3-transform';
import * as dotenv from 'dotenv';
import * as sharp from 'sharp';

import { v1 as uuidv1 } from 'uuid';
dotenv.config();

const s3 = new AWS.S3({
Expand All @@ -18,11 +18,24 @@ export const multerUserOption = {
storage: multerS3({
s3,
shouldTransform: true,
key: function (req, file, cb) {
file.__uuid__ = uuidv1().toString(); // ***
cb(null, file.__uuid__);
},
transforms: [
{
id: 'resized',
id: 'origin',
key: function (request, file, cb) {
cb(null, `${file.__uuid__}.webp`);
},
transform: function (req, file, cb) {
cb(null, sharp({ animated: true }).webp({ quality: 90 }));
},
},
{
id: 'profile',
key: function (request, file, cb) {
cb(null, `${Date.now().toString()}.webp`);
cb(null, `${file.__uuid__}-profile.webp`);
},
transform: function (req, file, cb) {
cb(null, sharp().resize({ width: 100, height: 100 }).webp({ quality: 80 }));
Expand All @@ -31,25 +44,47 @@ export const multerUserOption = {
],
bucket: 'spongebob-bucket',
acl: 'public-read',
contentType: function (req, file, cb) {
cb(null, 'image/webp');
},
}),
};

export const multerTransFormOption = {
storage: multerS3({
s3,
shouldTransform: true,
key: function (req, file, cb) {
file.__uuid__ = uuidv1().toString(); // ***
cb(null, file.__uuid__);
},
transforms: [
{
id: 'transform',
id: 'origin',
key: function (request, file, cb) {
cb(null, `${file.__uuid__}.webp`);
},
transform: function (req, file, cb) {
cb(null, sharp({ animated: true }).webp({ quality: 90 }));
},
},
{
id: 'feed',
key: function (request, file, cb) {
cb(null, `${Date.now().toString()}.webp`);
cb(null, `${file.__uuid__}-feed.webp`);
},
transform: function (req, file, cb) {
cb(null, sharp().webp({ quality: 80 }));
cb(
null,
sharp({ animated: true }).resize({ width: 470, height: 500 }).webp({ quality: 80 })
);
},
},
],
bucket: 'spongebob-bucket',
acl: 'public-read',
contentType: function (req, file, cb) {
cb(null, 'image/webp');
},
}),
};
17 changes: 17 additions & 0 deletions back/config/swagger.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { DocumentBuilder } from '@nestjs/swagger';

export const SwaggerConfig = new DocumentBuilder()
.setTitle(`PingPing's Friends`)
.setDescription(`The PingPing's friends API description`)
.setVersion('0.1.0')
.addBearerAuth(
{ type: 'http', scheme: 'bearer', bearerFormat: 'JWT', in: 'Header' },
'access-token'
)
.addCookieAuth('auth-cookie', {
type: 'http',
in: 'Header',
scheme: 'Bearer',
})
.addTag('pingpings')
.build();
21 changes: 21 additions & 0 deletions back/db/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: "3"
services:
db:
image: mysql:5.7.36
restart: always
command: --lower_case_table_names=1 # ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ถ„
container_name: testdb-root
ports:
- "3308:3306" # (์ปจํ…Œ์ด๋„ˆ ์™ธ๋ถ€:์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€)
environment: # -e ์˜ต์…˜
- MYSQL_DATABASE=sns
- MYSQL_ROOT_PASSWORD=1234
- TZ=Asia/Seoul

command: # ๋ช…๋ น์–ด ์‹คํ–‰
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
volumes:
- testdb-root-volume:/var/lib/mysql
volumes:
testdb-root-volume:
106 changes: 106 additions & 0 deletions back/db/dummy_insert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import csv
from datetime import datetime
from numpy.core.numeric import False_
import pandas as pd
from faker import Faker
import data_config
fake = Faker('ko_kr')


def get_species_data():
sound = ['์™ˆ์™ˆ', '์บ‰์บ‰', '๋ƒฅ๋ƒฅ', '์ถ‰์ด™', '์–ดํฅ',
"Error!Error", "๊ตฌ๊ตฌ", "๋ฐฅ๋ฐฅ", "ํ•‘ํ•‘", "ํ—คํ—ค"]
data = [(sound[fake.pyint(min_value=0, max_value=9)], fake.unique.town())
for _ in range(100)]

df = pd.DataFrame(data)
df.to_csv("./db/data_csv/species_data.csv")


def get_habitat_data():

data = [(fake.unique.city(), data_config.color[fake.pyint(min_value=0, max_value=13)], i)
for i in range(50)]

df = pd.DataFrame(data)
df.to_csv("./db/data_csv/habitat_data.csv")


def get_user_data():

data = [(f"test{i}", data_config.pwd, fake.name(), 1, fake.pyint(min_value=1, max_value=1), i)
for i in range(1, 10000)]

df = pd.DataFrame(data)
df.to_csv("./db/data_csv/user_data.csv")


def get_contents_data():

data = [(data_config.img_url_arr[fake.pyint(min_value=0, max_value=317)], 'image/webp')
for _ in range(500000)]

df = pd.DataFrame(data)
df.to_csv("./db/data_csv/contents_data.csv")


def get_post_data():
# fake.date_time_between(start_date="-3y", end_date="now")
data = [(fake.bs(), fake.bs(), fake.pyint(min_value=1, max_value=9000), fake.pyint(min_value=1, max_value=49),
fake.date_time_between(start_date="-3y", end_date="now"))
for _ in range(50000)]
data += [(fake.bs(), fake.bs(), fake.pyint(min_value=1, max_value=9000), 1,
fake.date_time_between(start_date="-3y", end_date="now"))
for _ in range(50000)]
data += [(fake.bs(), fake.bs(), fake.pyint(min_value=1, max_value=9000), 1,
fake.date_time_between(start_date="-7d", end_date="now"))
for _ in range(50000)]
data += [(fake.bs(), fake.bs(), fake.pyint(min_value=1, max_value=9000), fake.pyint(min_value=1, max_value=49),
fake.date_time_between(start_date="-7d", end_date="now"))
for _ in range(50000)]
df = pd.DataFrame(data)
df.to_csv("./db/data_csv/post_data.csv")


def get_post_contents_data():
# fake.date_time_between(start_date="-3y", end_date="now")
# ๊ฒŒ์‹œ๊ธ€๋‹น ์ด๋ฏธ์ง€ ์ถ”๊ฐ€ ๋žœ๋ค
data = [(i, i)
for i in range(1, 200001)]
data += [(i-200000, i)
for i in range(200001, 400000)]
data += [(i-400000, i)
for i in range(400001, 500000)]
df = pd.DataFrame(data)
df.to_csv("./db/data_csv/post_contents_data.csv", index=False)


def get_comments_data():
# fake.date_time_between(start_date="-3y", end_date="now")
data = [(fake.date_time_between(start_date="-7d", end_date="now"), fake.bs(), fake.pyint(min_value=1, max_value=199999), fake.pyint(min_value=1, max_value=9998))
for i in range(1, 500000)]
data += [(fake.date_time_between(start_date="-3y", end_date="now"), fake.bs(), fake.pyint(min_value=1, max_value=199999), fake.pyint(min_value=1, max_value=9998))
for i in range(1, 500000)]
df = pd.DataFrame(data)
df.to_csv("./db/data_csv/comments_data.csv")


def get_heart_data():
# fake.date_time_between(start_date="-3y", end_date="now")
data = [(fake.pyint(min_value=1, max_value=9998), fake.pyint(min_value=1, max_value=199999))
for i in range(1, 2000000)]
data += [(fake.pyint(min_value=1, max_value=9998), fake.pyint(min_value=99999, max_value=149999))
for i in range(1, 1000000)]
df = pd.DataFrame(data)
df.to_csv("./db/data_csv/heart_data.csv", index=False)


# datetime.datetime(2020, 8, 16, 21, 3, 18)
# get_species_data()
# get_habitat_data()
# get_user_data()# 1~9998
# get_contents_data() # 1~499999 / 1~9999์€ ์œ ์ €์—์„œ์‚ฌ์šฉ
# get_post_data() # 1~199,999
# get_post_contents_data() # 1~499999
# get_comments_data() # 1~9,999,997
get_heart_data()
21 changes: 21 additions & 0 deletions back/logger/logger.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Injectable, NestMiddleware } from '@nestjs/common';

import { Request, Response } from 'express';
import { AppLoggingService } from './logger.service';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
constructor() {}

use(req: Request, res: Response, next: Function) {
const loggerService = new AppLoggingService(req.url.slice(1).split('/')[0]);
const tempUrl = req.method + ' ' + req.url.split('?')[0];
const _headers = JSON.stringify(req.headers ? req.headers : {});
const _query = JSON.stringify(req.query ? req.query : {});
const _body = JSON.stringify(req.body ? req.body : {});
const _url = JSON.stringify(tempUrl ? tempUrl : {});

loggerService.log(`${_url} ${_headers} ${_query} ${_body}`.replace(/\\/, ''));
next();
}
}
Loading

0 comments on commit d181a0a

Please sign in to comment.