Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/sparcs-kaist/taxi-back into #…
Browse files Browse the repository at this point in the history
…273-안-읽은-메세지-확인
  • Loading branch information
chlehdwon committed Aug 9, 2023
2 parents 76844ff + f8ba37f commit 9186492
Show file tree
Hide file tree
Showing 17 changed files with 5,283 additions and 4,679 deletions.
3 changes: 3 additions & 0 deletions loadenv.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ module.exports = {
JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS),
testAccounts:
process.env.TEST_ACCOUNTS && JSON.parse(process.env.TEST_ACCOUNTS),
slackWebhookUrl: {
report: process.env.SLACK_REPORT_WEBHOOK_URL || "", // optional
},
};
9,627 changes: 5,017 additions & 4,610 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"ajv": "^8.12.0",
"ajv-errors": "^3.0.0",
"ajv-formats": "^2.1.1",
"aws-sdk": "^2.1182.0",
"aws-sdk": "^2.1386.0",
"axios": "^0.27.2",
"ci": "^2.2.0",
"connect-mongo": "^4.6.0",
Expand All @@ -27,7 +27,7 @@
"express-validator": "^6.14.0",
"firebase-admin": "^11.4.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.5.2",
"mongoose": "^6.11.3",
"node-mocks-http": "^1.12.1",
"querystring": "^0.2.1",
"redis": "^4.2.0",
Expand Down
28 changes: 28 additions & 0 deletions src/modules/slackNotification.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const { slackWebhookUrl: slackUrl } = require("../../loadenv");
const axios = require("axios");
const logger = require("../modules/logger");

module.exports.notifyToReportChannel = (reportUser, report) => {
if (!slackUrl.report) return;

const data = {
text: `${reportUser}님으로부터 신고가 접수되었습니다.
신고자 ID: ${report.creatorId}
신고 ID: ${report.reportedId}
방 ID: ${report.roomId ?? ""}
사유: ${report.type}
기타: ${report.etcDetail}
`,
};
const config = { "Content-Type": "application/json" };

axios
.post(slackUrl.report, data, config)
.then((res) => {
logger.info("Slack webhook sent successfully");
})
.catch((err) => {
logger.error("Fail to send slack webhook", err);
});
};
18 changes: 14 additions & 4 deletions src/modules/socket.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const sessionMiddleware = require("../middlewares/session");
const logger = require("./logger");
const { getLoginInfo } = require("./auths/login");
const { roomModel, userModel, chatModel } = require("./stores/mongo");
const { getS3Url } = require("./stores/awsS3");
const { getS3Url } = require("./stores/aws");
const { getTokensOfUsers, sendMessageByTokens } = require("./fcm");

const { frontUrl } = require("../../loadenv");
Expand Down Expand Up @@ -42,6 +42,7 @@ const transformChatsForRoom = async (chats) => {
);
}
chatsToSend.push({
roomId: chat.roomId,
type: chat.type,
authorId: chat.authorId._id,
authorName: chat.authorId.nickname,
Expand All @@ -52,11 +53,14 @@ const transformChatsForRoom = async (chats) => {
inOutNames: chat.inOutNames,
});
}

return chatsToSend;
};

// FCM 알림으로 보내는 content는 채팅 type에 따라 달라집니다.
// type이 text인 경우 `${nickname}: ${content}`를, 아닌 경우 `${nickname}`를 보냅니다.
/**
* FCM 알림으로 보내는 content는 채팅 type에 따라 달라집니다.
* 예를 들어, type이 "text"인 경우 `${nickname}: ${content}`를 보냅니다.
*/
const getMessageBody = (type, nickname, content) => {
// TODO: 채팅 메시지 유형에 따라 Body를 다르게 표시합니다.
if (type === "text") {
Expand All @@ -65,7 +69,7 @@ const getMessageBody = (type, nickname, content) => {
} else if (type === "s3img") {
// 채팅 유형이 이미지인 경우 본문은 "${nickname} 님이 이미지를 전송하였습니다"가 됩니다.
// TODO: 사용자 언어를 가져올 수 있으면 개선할 수 있다고 생각합니다.
const suffix = " 님이 이미지를 전송하였습니다.";
const suffix = " 님이 이미지를 전송하였습니다";
return `${nickname} ${suffix}`;
} else if (type === "in" || type === "out") {
// 채팅 메시지 type이 "in"이거나 "out"인 경우 본문은 "${nickname} 님이 입장하였습니다" 또는 "${nickname} 님이 퇴장하였습니다"가 됩니다.
Expand All @@ -81,6 +85,12 @@ const getMessageBody = (type, nickname, content) => {
? " 님이 결제를 완료하였습니다"
: " 님이 정산을 완료하였습니다";
return `${nickname} ${suffix}`;
} else if (type === "account") {
const suffix = " 님이 계좌번호를 전송하였습니다";
return `${nickname} ${suffix}`;
} else {
// 정의되지 않은 type의 경우에는 nickname만 반환합니다.
return nickname;
}
};

Expand Down
37 changes: 37 additions & 0 deletions src/modules/stores/awsS3.js → src/modules/stores/aws.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
const { aws: awsEnv } = require("../../../loadenv");

const logger = require("../logger");
// Load the AWS-SDK and s3
const AWS = require("aws-sdk");
AWS.config.update({
region: "ap-northeast-2",
signatureVersion: "v4",
});

const s3 = new AWS.S3({ apiVersion: "2006-03-01" });
const ses = new AWS.SES({ apiVersion: "2010-12-01" });

// function to list Object
module.exports.getList = (directoryPath, cb) => {
Expand Down Expand Up @@ -80,3 +83,37 @@ module.exports.foundObject = (filePath, cb) => {
module.exports.getS3Url = (filePath) => {
return `${awsEnv.s3Url}${filePath}`;
};

module.exports.sendReportEmail = (reportedEmail, report, html) => {
const reportTypeMap = {
"no-settlement": "정산을 하지 않음",
"no-show": "택시에 동승하지 않음",
"etc-reason": "기타 사유",
};

const params = {
Destination: {
ToAddresses: [reportedEmail],
},
Message: {
Body: {
Html: {
Data: html,
},
},
Subject: {
Charset: "UTF-8",
Data: `[SPARCS TAXI] 신고가 접수되었습니다 (사유: ${reportTypeMap[report.type]})`,
},
},
Source: "taxi.sparcs@gmail.com",
};

ses.sendEmail(params, (err, data) => {
if (err) {
logger.error("Fail to send email", err);
} else {
logger.info("Email sent successfully");
}
});
};
1 change: 1 addition & 0 deletions src/modules/stores/mongo.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ const reportSchema = Schema({
},
etcDetail: { type: String, default: "" }, // 기타 세부 사유
time: { type: Date, required: true },
roomId: { type: Schema.Types.ObjectId, ref: "Room" }, // 신고한 방 id
});

const adminIPWhitelistSchema = Schema({
Expand Down
7 changes: 6 additions & 1 deletion src/routes/docs/reportsSchema.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const reportsSchema = {
createHandler: {
type: "object",
required: ["reportedId", "type", "time"],
required: ["reportedId", "type", "time", "roomId"],
properties: {
reportedId: {
type: "string",
Expand All @@ -14,11 +14,16 @@ const reportsSchema = {
etcDetail: {
type: "string",
maxLength: 30,
default: "",
},
time: {
type: "string",
format: "date-time",
},
roomId: {
type: "string",
pattern: "^[a-fA-F\\d]{24}$",
},
},
errorMessage: "validation: bad request",
},
Expand Down
51 changes: 2 additions & 49 deletions src/services/auth.replace.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,7 @@ const logger = require("../modules/logger");
const jwt = require("../modules/auths/jwt");

const { registerDeviceTokenHandler } = require("../services/auth");

const loginHtmlBuilder = (redirectPath) => `
<!DOCTYPE html>
<html lang="ko">
<head>
<title>replace Login</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,minium-scale=1.0,maxinum-scale=1.0,user-scalable=no" />
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function(){
const post = (path, params) => {
var form = document.createElement("form");
form.setAttribute("method", "post");
form.setAttribute("action", path);
for(var key in params) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
document.body.appendChild(form);
form.submit();
}
const submitHandler = () => {
const value = document.getElementById("input-id").value;
if(value) post('/auth/login/replace', {
id: value,
redirect: "${encodeURIComponent(redirectPath)}",
});
}
const enterHandler = (e) => {
if (e.keyCode === 13) submitHandler();
}
$('#btn').click(submitHandler);
$('#input-id').on("keyup", enterHandler);
$('#input-id').focus();
});
</script>
</head>
<body>
<div>아이디 입력</div>
<input id="input-id">
<div id="btn">로그인</div>
</body>
</html>
`;
const loginReplacePage = require("../views/loginReplacePage");

const makeInfo = (id) => {
const info = {
Expand Down Expand Up @@ -144,7 +97,7 @@ const sparcsssoHandler = (req, res) => {
const isApp = !!req.query.isApp;

req.session.isApp = isApp;
res.end(loginHtmlBuilder(redirectPath));
res.end(loginReplacePage(redirectPath));
};

const logoutHandler = async (req, res) => {
Expand Down
6 changes: 3 additions & 3 deletions src/services/chats.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { chatModel, userModel, roomModel } = require("../modules/stores/mongo");
const { chatPopulateOption } = require("../modules/populates/chats");
const awsS3 = require("../modules/stores/awsS3");
const aws = require("../modules/stores/aws");
const {
transformChatsForRoom,
emitChatEvent,
Expand Down Expand Up @@ -248,7 +248,7 @@ const uploadChatImgGetPUrlHandler = async (req, res) => {
});
const chat = await chatDocument.save();
const key = `chat-img/${chat._id}`;
awsS3.getUploadPUrlPost(key, type, (err, data) => {
aws.getUploadPUrlPost(key, type, (err, data) => {
if (err) {
return res
.status(500)
Expand Down Expand Up @@ -294,7 +294,7 @@ const uploadChatImgDoneHandler = async (req, res) => {
});
}
const key = `chat-img/${chat._id}`;
awsS3.foundObject(key, async (err, data) => {
aws.foundObject(key, async (err, data) => {
if (err) {
return res
.status(500)
Expand Down
35 changes: 33 additions & 2 deletions src/services/reports.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
const { userModel, reportModel } = require("../modules/stores/mongo");
const {
userModel,
reportModel,
roomModel,
} = require("../modules/stores/mongo");
const { reportPopulateOption } = require("../modules/populates/reports");
const { sendReportEmail } = require("../modules/stores/aws");
const logger = require("../modules/logger");
const emailPage = require("../views/emailNoSettlementPage");
const { notifyToReportChannel } = require("../modules/slackNotification");

const createHandler = async (req, res) => {
try {
const { reportedId, type, etcDetail, time } = req.body;
const { reportedId, type, etcDetail, time, roomId } = req.body;
const user = await userModel.findOne({ id: req.userId });
const creatorId = user._id;

Expand All @@ -15,15 +22,39 @@ const createHandler = async (req, res) => {
});
}

const room = await roomModel.findById(roomId);
if (!room) {
return res.status(400).json({
error: "User/report: no corresponding room",
});
}

const report = new reportModel({
creatorId,
reportedId,
type,
etcDetail,
time,
roomId
});

await report.save();

notifyToReportChannel(user.nickname, report);

if (report.type === "no-settlement") {
const emailRoomName = room ? room.name : "";
const emailRoomId = room ? room._id : "";
const emailHtml = emailPage(
reported.name,
reported.nickname,
emailRoomName,
user.nickname,
emailRoomId
);
sendReportEmail(reported.email, report, emailHtml);
}

res.status(200).send("User/report : report successful");
} catch (err) {
logger.error(err);
Expand Down
6 changes: 3 additions & 3 deletions src/services/users.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { userModel } = require("../modules/stores/mongo");
const logger = require("../modules/logger");
const awsS3 = require("../modules/stores/awsS3");
const aws = require("../modules/stores/aws");

const agreeOnTermsOfServiceHandler = async (req, res) => {
try {
Expand Down Expand Up @@ -83,7 +83,7 @@ const editProfileImgGetPUrlHandler = async (req, res) => {
.send("User/editProfileImg/getPUrl : internal server error");
}
const key = `profile-img/${user._id}`;
awsS3.getUploadPUrlPost(key, type, (err, data) => {
aws.getUploadPUrlPost(key, type, (err, data) => {
if (err) {
return res
.status(500)
Expand All @@ -110,7 +110,7 @@ const editProfileImgDoneHandler = async (req, res) => {
.send("User/editProfileImg/done : internal server error");
}
const key = `profile-img/${user._id}`;
awsS3.foundObject(key, async (err) => {
aws.foundObject(key, async (err) => {
if (err) {
logger.error(err);
return res
Expand Down
Loading

0 comments on commit 9186492

Please sign in to comment.