Skip to content

Commit

Permalink
Merge pull request #140 from TeamBookTez/feat/withdrawal-logic
Browse files Browse the repository at this point in the history
[feat] Implement membership withdrawal logic
  • Loading branch information
holmir97 authored Apr 25, 2022
2 parents 264acda + b0775a8 commit e674770
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 10 deletions.
52 changes: 45 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"mongoose-validator": "^2.1.0",
"multer": "^1.4.2",
"multer-s3": "^2.9.0",
"node-schedule": "^2.1.0",
"pg": "^8.7.1",
"pg-hstore": "^2.3.4",
"reflect-metadata": "^0.1.13",
Expand Down
38 changes: 38 additions & 0 deletions src/controller/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,50 @@ const getLoginFlagController = async (req: Request, res: Response) => {
}
};

/**
* @회원탈퇴
* @route Patch /auth/withdraw
* @access private
* @err
*/
const patchWithdrawController = async (req: Request, res: Response) => {
try {
const resData = await authService.patchWithdrawService(req.user.id);

if (resData === constant.NON_EXISTENT_USER) {
return response.basicResponse(
res,
returnCode.BAD_REQUEST,
false,
"이미 삭제된 유저입니다."
);
}

return response.basicResponse(
res,
returnCode.OK,
true,
"삭제가 완료되었습니다."
);
} catch (err) {
slack.slackWebhook(req, err.message);
console.error(err.message);
return response.basicResponse(
res,
returnCode.INTERNAL_SERVER_ERROR,
false,
"서버 오류"
);
}
};

const authController = {
getEmailController,
getNicknameController,
postLoginController,
postSignupController,
getLoginFlagController,
patchWithdrawController,
};

export default authController;
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import router from "./router";
import connectDB from "./loader/db";
import config from "./config";

// scheduler
import { userScan } from "./scheduler/userScheduler";

const app = express();

// Connect Database
Expand Down Expand Up @@ -40,6 +43,9 @@ app.use(function (err, req, res, next) {
// render the error page
res.status(err.status || 500);
res.json({ error: err });

// scheduler
userScan;
});

const server = app
Expand Down
1 change: 1 addition & 0 deletions src/interface/IUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface IUser {
img: string;
refresh_token: string;
email_code: string;
expired_at: Date;
created_at: Date;
updated_at: Date;
is_deleted: boolean;
Expand Down
7 changes: 6 additions & 1 deletion src/loader/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ const connectDB = async () => {
console.log("Review Collection is created!");
});

console.log("Mongoose Connected ...");
const uri = config.mongoURI;
console.log(
"\nMongoose Connected... [" +
uri.substring(uri.lastIndexOf("/") + 1, uri.length) +
"]\n"
);
} catch (err) {
console.error(err.message);
process.exit(1);
Expand Down
7 changes: 7 additions & 0 deletions src/models/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ const UserSchema = new mongoose.Schema({
type: String,
required: false,
},

// 만료 일자
expired_at: {
type: Date,
required: false,
},

// 생성 일자
created_at: {
type: Date,
Expand Down
3 changes: 2 additions & 1 deletion src/router/auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express from "express";

// Middleware
import { isLogin } from "../middleware/authMiddleware";
import { auth, isLogin } from "../middleware/authMiddleware";

// Controller
import authController from "../controller/auth";
Expand All @@ -13,5 +13,6 @@ router.get("/nickname", authController.getNicknameController);
router.post("/login", authController.postLoginController);
router.post("/signup", authController.postSignupController);
router.get("/check", isLogin, authController.getLoginFlagController);
router.patch("/withdraw", auth, authController.patchWithdrawController);

module.exports = router;
28 changes: 28 additions & 0 deletions src/scheduler/userScheduler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import schedule from "node-schedule";

// models
import Review from "../models/Review";
import User from "../models/User";

// library
import { keysToSnake, keysToCamel } from "../library/convertSnakeToCamel";

export const userScan = schedule.scheduleJob("0 0 0 * * *", async () => {
// 현재 시간
const current = new Date(new Date(Date.now()).setUTCMinutes(0, 0, 0));
console.log("Scanning users...[" + current + "]");

// 삭제 예정 유저
const deletedUsers = await User.find(keysToSnake({ isDeleted: true }));

deletedUsers.forEach(async (user) => {
// 현재 날짜가 만료 날짜 이후
if (current.getTime() >= user.expired_at.getTime()) {
// 해당 유저가 가진 리뷰 모두 삭제
await Review.deleteMany(keysToSnake({ userID: user._id }));
// 해당 유저 삭제
await user.deleteOne(keysToSnake({ _id: user._id }));
}
});
console.log("Complete scanning...");
});
32 changes: 31 additions & 1 deletion src/service/auth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import config from "../config";
import mongoose from "mongoose";

// library
import jwt from "jsonwebtoken";
Expand All @@ -9,7 +10,7 @@ import {
checkNicknameValid,
checkPasswordValid,
} from "../library/checkValidation";
import { keysToSnake } from "../library/convertSnakeToCamel";
import { keysToSnake, keysToCamel } from "../library/convertSnakeToCamel";

// model
import User from "../models/User";
Expand Down Expand Up @@ -208,12 +209,41 @@ const getLoginFlagService = async (isLogin: Boolean) => {
return { isLogin };
};

/**
* @회원탈퇴
* @route Patch /auth/withdraw
* @access private
* @err
*/
const patchWithdrawService = async (userId: string) => {
const user = await User.findById(new mongoose.Types.ObjectId(userId));

// snake to camel
const originUser = keysToCamel(user);
const camelUser = keysToCamel(originUser.Doc);

if (camelUser.isDeleted) {
return constant.NON_EXISTENT_USER;
}

// 삭제
await user.updateOne({ $set: keysToSnake({ isDeleted: true }) });

// 만료 날짜
const date = new Date(Date.now() + 30 * 24 * 3600 * 1000);

// 시간 아래는 0 으로 초기화
const expiredAt = date.setUTCMinutes(0, 0, 0);
await user.updateOne({ $set: keysToSnake({ expiredAt }) });
};

const authService = {
getEmailService,
getNicknameService,
postLoginService,
postSignupService,
getLoginFlagService,
patchWithdrawService,
};

export default authService;

0 comments on commit e674770

Please sign in to comment.