126 lines
3.6 KiB
JavaScript
126 lines
3.6 KiB
JavaScript
const express = require("express")
|
|
const multer = require("multer")
|
|
const requireAuth = require("../middleware/requireAuth.js")
|
|
const {
|
|
getUserProfile,
|
|
markAllNotificationsRead,
|
|
getUserNotificationsPage,
|
|
changePassword,
|
|
} = require("../services/profile.service")
|
|
const { endpoints } = require("@shared/contracts")
|
|
|
|
const router = express.Router()
|
|
const upload = multer({ dest: "uploads/" })
|
|
|
|
const { updateUserAvatar } = require("../services/avatar.service")
|
|
const { enqueueAuditFromRequest, buildAuditMeta } = require("../services/audit.service")
|
|
const { AUDIT_ACTIONS } = require("../services/auditActions")
|
|
|
|
const { account } = endpoints
|
|
|
|
function attachNotificationExtras(validatedList = [], sourceList = []) {
|
|
const extrasById = new Map(
|
|
(Array.isArray(sourceList) ? sourceList : []).map((item) => [
|
|
Number(item?.id),
|
|
item?.extras ?? null,
|
|
])
|
|
)
|
|
|
|
return (Array.isArray(validatedList) ? validatedList : []).map((item) => ({
|
|
...item,
|
|
extras: extrasById.get(Number(item?.id)) ?? null,
|
|
}))
|
|
}
|
|
|
|
router.post(
|
|
"/avatar",
|
|
requireAuth,
|
|
upload.single("file"),
|
|
async (req, res) => {
|
|
try {
|
|
const updatedUser = await updateUserAvatar(req.auth.userId, req.file)
|
|
enqueueAuditFromRequest(
|
|
req,
|
|
AUDIT_ACTIONS.ACCOUNT.AVATAR_UPDATE,
|
|
buildAuditMeta({
|
|
entityType: "USER",
|
|
entityId: req.auth.userId,
|
|
after: { avatarUrl: updatedUser.avatarUrl ?? null },
|
|
})
|
|
)
|
|
|
|
res.json(
|
|
account.avatarUploadResponseSchema.parse({
|
|
message: "Avatar updated",
|
|
user: updatedUser,
|
|
})
|
|
)
|
|
} catch (err) {
|
|
console.error(err)
|
|
res.status(400).json({ error: err.message })
|
|
}
|
|
}
|
|
)
|
|
|
|
router.get("/me", requireAuth, async (req, res) => {
|
|
try {
|
|
const user = await getUserProfile(req.auth.userId)
|
|
const payload = account.accountMeResponseSchema.parse(user)
|
|
payload.notifications = attachNotificationExtras(payload.notifications, user?.notifications)
|
|
res.json(payload)
|
|
} catch (err) {
|
|
res.status(400).json({ error: err.message })
|
|
}
|
|
})
|
|
|
|
router.get("/notifications/read", requireAuth, async (req, res) => {
|
|
try {
|
|
await markAllNotificationsRead(req.auth.userId)
|
|
enqueueAuditFromRequest(
|
|
req,
|
|
AUDIT_ACTIONS.ACCOUNT.NOTIFICATIONS_READ,
|
|
buildAuditMeta({
|
|
entityType: "USER",
|
|
entityId: req.auth.userId,
|
|
extra: { action: "mark_all_read" },
|
|
})
|
|
)
|
|
res.sendStatus(200)
|
|
} catch (err) {
|
|
res.status(400).json({ error: err.message })
|
|
}
|
|
})
|
|
|
|
router.get("/notifications", requireAuth, async (req, res) => {
|
|
try {
|
|
const input = account.accountNotificationsListRequestSchema.parse(req.query)
|
|
const payload = await getUserNotificationsPage(req.auth.userId, input.page, 10)
|
|
const validated = account.accountNotificationsListResponseSchema.parse(payload)
|
|
validated.results = attachNotificationExtras(validated.results, payload?.results)
|
|
res.json(validated)
|
|
} catch (err) {
|
|
res.status(400).json({ error: err.message })
|
|
}
|
|
})
|
|
|
|
router.post("/password", requireAuth, async (req, res) => {
|
|
try {
|
|
const input = account.accountPasswordChangeRequestSchema.parse(req.body)
|
|
const payload = await changePassword(req.auth.userId, input)
|
|
enqueueAuditFromRequest(
|
|
req,
|
|
AUDIT_ACTIONS.ACCOUNT.PASSWORD_CHANGE,
|
|
buildAuditMeta({
|
|
entityType: "USER",
|
|
entityId: req.auth.userId,
|
|
})
|
|
)
|
|
res.json(account.accountPasswordChangeResponseSchema.parse(payload))
|
|
} catch (err) {
|
|
res.status(400).json({ error: err.message })
|
|
}
|
|
})
|
|
|
|
module.exports = router
|
|
|