From 5d434e789f3c1990c1534f776c699dcf0cf0baca Mon Sep 17 00:00:00 2001 From: soyou Date: Sun, 3 Oct 2021 16:21:19 +0900 Subject: [PATCH 1/2] [Server] feat: profile image upload by multer --- .env.example | 4 +++- package.json | 6 ++++++ scripts/start.sh | 4 ++++ src/controllers/dashboard.ts | 33 +++++++++++++++++++++++++++++---- src/controllers/user.ts | 16 ++++++++++++++++ src/routes/admin.ts | 1 + src/routes/user.ts | 4 ++++ src/utils/multer.ts | 26 ++++++++++++++++++++++++++ tsconfig.json | 3 ++- 9 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/utils/multer.ts diff --git a/.env.example b/.env.example index a450e42e..cf015a8e 100644 --- a/.env.example +++ b/.env.example @@ -16,4 +16,6 @@ DATABASE_HOST= DATABASE_NAME= DATABASE_PASSWORD= DATABASE_PORT= -DATABASE_USER= \ No newline at end of file +DATABASE_USER= +S3_ACCESS_ID= +S3_SECRET_KEY= \ No newline at end of file diff --git a/package.json b/package.json index 9ea91645..ae4e4e31 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ }, "homepage": "https://github.com/loverduck/Code-High#readme", "devDependencies": { + "@types/aws-sdk": "^2.7.0", "@types/axios": "^0.14.0", "@types/bcrypt": "^5.0.0", "@types/cookie-parser": "^1.4.2", @@ -27,6 +28,8 @@ "@types/dotenv": "^8.2.0", "@types/express": "^4.17.13", "@types/jsonwebtoken": "^8.5.5", + "@types/multer": "^1.4.7", + "@types/multer-s3": "^2.7.10", "@types/node": "^16.9.1", "@types/node-schedule": "^1.3.2", "@types/nodemailer": "^6.4.4", @@ -37,6 +40,7 @@ "typescript": "^4.4.3" }, "dependencies": { + "aws-sdk": "^2.999.0", "axios": "^0.21.4", "bcrypt": "^5.0.1", "cookie-parser": "^1.4.5", @@ -45,6 +49,8 @@ "express": "^4.17.1", "jsonwebtoken": "^8.5.1", "moment": "^2.29.1", + "multer": "^1.4.3", + "multer-s3": "^2.9.0", "mysql": "^2.18.1", "node-schedule": "^2.0.0", "nodemailer": "^6.6.3", diff --git a/scripts/start.sh b/scripts/start.sh index 6ca6017e..2b4eebb0 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -20,5 +20,9 @@ export GOOGLE_CLIENT_SECRET=$(aws ssm get-parameters --region ap-northeast-2 --n export KAKAO_CLIENT_ID=$(aws ssm get-parameters --region ap-northeast-2 --names KAKAO_CLIENT_ID --query Parameters[0].Value | sed 's/"//g') export KAKAO_CLIENT_SECRET=$(aws ssm get-parameters --region ap-northeast-2 --names KAKAO_CLIENT_SECRET --query Parameters[0].Value | sed 's/"//g') +export S3_ACCESS_ID=$(aws ssm get-parameters --region ap-northeast-2 --names S3_ACCESS_ID --query Parameters[0].Value | sed 's/"//g') +export S3_SECRET_KEY=$(aws ssm get-parameters --region ap-northeast-2 --names S3_SECRET_KEY --query Parameters[0].Value | sed 's/"//g') +export S3_REGION=$(aws ssm get-parameters --region ap-northeast-2 --names S3_REGION --query Parameters[0].Value | sed 's/"//g') + npm run build authbind --deep pm2 start dist/src/index.js \ No newline at end of file diff --git a/src/controllers/dashboard.ts b/src/controllers/dashboard.ts index 2de21a91..7e37332f 100644 --- a/src/controllers/dashboard.ts +++ b/src/controllers/dashboard.ts @@ -22,6 +22,10 @@ const userActiveStat = async (req: Request, res: Response) => { // 일별 코드 작성 현황 const dateStat = async (req: Request, res: Response) => { + if (req.body.userRole !== 1) { + return res.status(403).send({ message: 'forbidden user'}); + } + const today = dateFormat.today(); const fourDayAgo = dateFormat.calculateDate(-4); const day = await Stat.find({ date: Between(fourDayAgo, today)}); @@ -52,11 +56,31 @@ const dateStat = async (req: Request, res: Response) => { res.status(200).send({ stat }); } +const weekStat = async (req: Request, res: Response) => { + if (req.body.userRole !== 1) { + return res.status(403).send({ message: 'forbidden user'}); + } + + const week = await Stat.createQueryBuilder() + .select(['CONCAT(YEAR(date), \'-\', Month(date), \' \', WEEK(date)) AS date']) + .groupBy('CONCAT(YEAR(date), \'-\', Month(date), \' \', WEEK(date))') + .getRawMany() + + console.log(week) + + + res.status(200).send('test'); +} + const monthStat = async (req: Request, res: Response) => { + if (req.body.userRole !== 1) { + return res.status(403).send({ message: 'forbidden user'}); + } + const month = await Stat.createQueryBuilder() - .select(['date', 'SUM(postCount) AS postCount', 'SUM(commentCount) AS commentCount', 'SUM(joinCount) AS joinCount', 'SUM(visitCount) AS visitCount']) - .groupBy('MONTH(date)') - .orderBy('date', 'DESC') + .select(['CONCAT(YEAR(date), \'-\', Month(date)) AS date', 'SUM(postCount) AS postCount', 'SUM(commentCount) AS commentCount', 'SUM(joinCount) AS joinCount', 'SUM(visitCount) AS visitCount']) + .groupBy('CONCAT(YEAR(date), \'-\', Month(date))') + .orderBy('MONTH(date)', 'DESC') .limit(4) .getRawMany() @@ -71,7 +95,7 @@ const monthStat = async (req: Request, res: Response) => { } month.forEach((el) => { - stat.days.push(`${el.date.getMonth() + 1}월`); + stat.days.push(el.date); stat.postCount.push(el.postCount); stat.commentCount.push(el.commentCount); stat.joinCount.push(el.joinCount); @@ -84,5 +108,6 @@ const monthStat = async (req: Request, res: Response) => { export { userActiveStat, dateStat, + weekStat, monthStat } \ No newline at end of file diff --git a/src/controllers/user.ts b/src/controllers/user.ts index 1f6793bc..8093b111 100644 --- a/src/controllers/user.ts +++ b/src/controllers/user.ts @@ -64,6 +64,21 @@ const editUser = async (req: Request, res: Response) => { res.status(200).send({ userInfo: updateInfo, message: 'update success' }) } +const editImage = async (req: Request, res: Response) => { + if (req.body.userRole > 3 ) { + return res.status(403).send({ message: 'forbidden user'}) + } + + if (!req.file) { + return res.status(422).send('fail'); + } + + const file: any = req.file; + await User.update({ id: req.body.authUserId}, { image: file.location }) + + res.status(200).send({ message: 'upload success'}) +} + const resetPassword = async (req: Request, res: Response) => { let password = req.body.password; if (!req.body.code || !password) { @@ -112,5 +127,6 @@ export { userInfo, userInfoById, editUser, + editImage, deleteUser }; \ No newline at end of file diff --git a/src/routes/admin.ts b/src/routes/admin.ts index 8962ef97..5d73cada 100644 --- a/src/routes/admin.ts +++ b/src/routes/admin.ts @@ -8,6 +8,7 @@ adminRouter.use('/', checkAuth); adminRouter.use('/', checkRole); adminRouter.get('/stat/date', dashboardController.dateStat); +adminRouter.get('/stat/week', dashboardController.weekStat); adminRouter.get('/stat/month', dashboardController.monthStat); export default adminRouter; \ No newline at end of file diff --git a/src/routes/user.ts b/src/routes/user.ts index 08a17d84..2f648952 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -4,8 +4,12 @@ import * as postController from '../controllers/post'; import * as dashboardController from '../controllers/dashboard'; import { checkAuth } from '../middleware/checkAuth' import { checkRole } from '../middleware/checkRole'; +import { upload } from '../utils/multer'; + const userRouter = Router(); +userRouter.post('/image', upload.single('image'), checkAuth, checkRole, userController.editImage) + userRouter.use('/', checkAuth); userRouter.use('/', checkRole); diff --git a/src/utils/multer.ts b/src/utils/multer.ts new file mode 100644 index 00000000..511afe0e --- /dev/null +++ b/src/utils/multer.ts @@ -0,0 +1,26 @@ +import * as multer from 'multer'; +import * as multerS3 from 'multer-s3'; +import * as aws from 'aws-sdk'; +import { Request } from 'express'; +import 'dotenv/config'; + +aws.config.update({ + "accessKeyId": process.env.S3_ACCESS_ID, + "secretAccessKey": process.env.S3_SECRET_KEY, + "region": process.env.S3_REGION +}) + +const s3 = new aws.S3(); + +export const upload = multer({ + storage: multerS3({ + s3: s3, + contentType: multerS3.AUTO_CONTENT_TYPE, + bucket: 'code-high-image', + acl: 'public-read', + + key: (req: Request, file, cb) => { + cb(null, Date.now() + '.' + file.originalname.split('.').pop()); + } + }) +}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 32c19691..47a3dee7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,5 +13,6 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "sourceMap": true - } + }, + //"exclude": ["uploads/"] } \ No newline at end of file From 03a17807db46118e5274b1782e96c834b11aa7e3 Mon Sep 17 00:00:00 2001 From: soyou Date: Sun, 3 Oct 2021 16:49:35 +0900 Subject: [PATCH 2/2] [Server] feat: profile image upload by multer --- .env.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index cf015a8e..a8aaa37b 100644 --- a/.env.example +++ b/.env.example @@ -18,4 +18,5 @@ DATABASE_PASSWORD= DATABASE_PORT= DATABASE_USER= S3_ACCESS_ID= -S3_SECRET_KEY= \ No newline at end of file +S3_SECRET_KEY= +S3_REGION= \ No newline at end of file