Skip to content

Commit

Permalink
Add: Check Read Emails
Browse files Browse the repository at this point in the history
  • Loading branch information
MinjaeKimmm committed Oct 24, 2024
1 parent a526443 commit 92fd170
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 6 deletions.
3 changes: 3 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ eventConfig &&
require("./src/lottery").lotteryRouter
);

// 이메일 수신 확인은 origin 검사 거치지 않기
app.use("/email", require("./src/routes/emails"));

// [Middleware] 모든 API 요청에 대하여 origin 검증
app.use(require("./src/middlewares/originValidator"));

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"response-time": "^2.3.2",
"socket.io": "^4.6.1",
"swagger-ui-express": "^4.6.0",
"uuid": "^10.0.0",
"validator": "^13.7.0",
"winston": "^3.8.1",
"winston-daily-rotate-file": "^4.7.1",
Expand Down
10 changes: 10 additions & 0 deletions src/modules/stores/mongo.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,15 @@ const reportSchema = Schema({
roomId: { type: Schema.Types.ObjectId, ref: "Room" }, // 신고한 방 id
});

const emailSchema = Schema({
emailAddress: { type: String, required: true }, // 전송된 이메일 주소
reportId: { type: Schema.Types.ObjectId, ref: "User" },
trackingId: { type: String, required: true }, // 이메일 id
sentAt: { type: Date, required: true }, // 이메일 전송 시간
isOpened: { type: Boolean, required: true }, // 이메일 수신 여부
openedAt: { type: Date }, // 이메일 수신 시간
});

const adminIPWhitelistSchema = Schema({
ip: { type: String, required: true }, // IP 주소
description: { type: String, default: "" }, // 설명
Expand Down Expand Up @@ -267,6 +276,7 @@ module.exports = {
locationModel: mongoose.model("Location", locationSchema),
chatModel: mongoose.model("Chat", chatSchema),
reportModel: mongoose.model("Report", reportSchema),
emailModel: mongoose.model("Email", emailSchema),
adminIPWhitelistModel: mongoose.model(
"AdminIPWhitelist",
adminIPWhitelistSchema
Expand Down
2 changes: 2 additions & 0 deletions src/routes/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
locationModel,
chatModel,
reportModel,
emailModel,
adminIPWhitelistModel,
adminLogModel,
deviceTokenModel,
Expand All @@ -33,6 +34,7 @@ const resources = [
locationModel,
chatModel,
reportModel,
emailModel,
adminIPWhitelistModel,
adminLogModel,
deviceTokenModel,
Expand Down
31 changes: 31 additions & 0 deletions src/routes/emails.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const express = require('express');
const router = express.Router();
const { emailModel } = require('../modules/stores/mongo');
const logger = require("../modules/logger");

router.get('/open-tracking', async (req, res) => {
const { trackingId } = req.query;

if (!trackingId) {
return res.status(400).send('Tracking ID missing');
}

try {
const trackingRecord = await emailModel.findOne({ trackingId });
if (!trackingRecord) {
return res.status(404).send('Tracking ID not found');
}

trackingRecord.isOpened = true;
trackingRecord.openedAt = new Date();
await trackingRecord.save();

res.set('Content-Type', 'image/gif');
res.send(Buffer.from('R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==', 'base64'));
} catch (err) {
logger.error(err)
res.status(500).send('Internal Server Error')
}
})

module.exports = router;
25 changes: 24 additions & 1 deletion src/services/reports.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ const {
userModel,
reportModel,
roomModel,
emailModel,
} = require("../modules/stores/mongo");
const { reportPopulateOption } = require("../modules/populates/reports");
const { sendReportEmail } = require("../modules/email");
const logger = require("../modules/logger");
const reportEmailPage = require("../views/reportEmailPage");
const { notifyReportToReportChannel } = require("../modules/slackNotification");
const { v4: uuidv4 } = require("uuid");

const createHandler = async (req, res) => {
try {
Expand Down Expand Up @@ -40,6 +42,26 @@ const createHandler = async (req, res) => {

await report.save();

const generateUniqueTrackingId = async () => {
let trackingId;
let existingTracking;
do {
trackingId = uuidv4();
existingTracking = await emailModel.findOne({ trackingId });
} while (existingTracking)
return trackingId;
};

const trackingId = await generateUniqueTrackingId();

await emailModel.create({
emailAddress: reported.email,
reportId: report,
trackingId,
sentAt: new Date(),
isOpened: false
});

notifyReportToReportChannel(user.nickname, report);

if (report.type === "no-settlement" || report.type === "no-show") {
Expand All @@ -51,7 +73,8 @@ const createHandler = async (req, res) => {
reported.nickname,
emailRoomName,
user.nickname,
emailRoomId
emailRoomId,
trackingId
);
sendReportEmail(reported.email, report, emailHtml);
}
Expand Down
6 changes: 5 additions & 1 deletion src/views/emailPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ const { getS3Url } = require("../modules/stores/aws");

module.exports = (
title,
content
content,
trackingId,
origin
) => `<div style="font-family: system-ui; position: relative; background: #ffffff; margin: 0; padding: 72px;">
<div style="width: max(min(100%, 800px), 320px); margin: 0 auto; padding 0;">
<div style="height: 102px; background: #6E3678; margin: 0 0 48px; padding: 0;">
Expand All @@ -27,5 +29,7 @@ module.exports = (
</a>
<div style="font-family: system-ui; font-size: 12px; font-weight: lighter; color: #999999; margin: 0; padding: 0;">[email protected]</div>
</div>
<!-- Tracking pixel to detect email opens -->
<img src="${new URL(`/email?trackingId=${trackingId}`, origin).href}" width="1" height="1" alt="pixel" />
</div>
</div>`;
14 changes: 10 additions & 4 deletions src/views/reportEmailPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ reportEmailPage["no-settlement"] = (
nickname,
roomName,
payer,
roomId
roomId,
trackingId
) =>
emailPage(
"미정산 내역 관련 안내",
Expand Down Expand Up @@ -40,7 +41,9 @@ reportEmailPage["no-settlement"] = (
}" target="_blank">채널톡 문의하기</a>를 통해 채팅을 남겨주시거나, 또는 이 메일에 회신해 주셔도 됩니다.<br /><br />
감사합니다.<br />
SPARCS Taxi팀 드림.
`
`,
trackingId,
origin
);

/* 미탑승 알림 메일을 위한 템플릿 */
Expand All @@ -50,7 +53,8 @@ reportEmailPage["no-show"] = (
nickname,
roomName,
payer,
roomId
roomId,
trackingId
) =>
emailPage(
"미탑승 내역 관련 안내",
Expand Down Expand Up @@ -80,7 +84,9 @@ reportEmailPage["no-show"] = (
}" target="_blank">채널톡 문의하기</a>를 통해 채팅을 남겨주시거나, 또는 이 메일에 회신해 주셔도 됩니다.<br /><br />
감사합니다.<br />
SPARCS Taxi팀 드림.
`
`,
trackingId,
origin
);

module.exports = reportEmailPage;

0 comments on commit 92fd170

Please sign in to comment.