const userDb = require("../db/user.db") const userNoteDb = require("../db/userNote.db") const refreshTokenDb = require("../db/refreshToken.db") const { queueUserUpdate, queueUserNoteCreate } = require("./redis/dbSync.service") const { getOrCacheUserModeration, setUserModerationInRedis, } = require("./redis/userModerationCache.service") const { sanitizeOptionalPlainText } = require("../utils/inputSanitizer") function assertUserId(userId) { const id = Number(userId) if (!Number.isInteger(id) || id <= 0) { const err = new Error("INVALID_USER_ID") err.statusCode = 400 throw err } return id } function computeUntil(durationDays = 7) { const days = Number(durationDays) const safeDays = Number.isFinite(days) && days > 0 ? days : 7 return new Date(Date.now() + safeDays * 24 * 60 * 60 * 1000) } async function ensureUserExists(userId) { const id = assertUserId(userId) const existing = await getOrCacheUserModeration(id) if (!existing) { const err = new Error("USER_NOT_FOUND") err.statusCode = 404 throw err } return { id, existing } } async function updateUserModeration(id, patch) { const updatedAt = new Date() const payload = { id, ...patch } await setUserModerationInRedis(payload, { ttlSeconds: 60 * 60 }) queueUserUpdate({ userId: id, data: patch, updatedAt: updatedAt.toISOString(), }).catch((err) => console.error("DB sync user update failed:", err?.message || err)) return { id, ...patch } } async function muteUser(userId, { durationDays = 7 } = {}) { const { id } = await ensureUserExists(userId) const mutedUntil = computeUntil(durationDays) return updateUserModeration(id, { mutedUntil }) } async function clearMute(userId) { const { id } = await ensureUserExists(userId) return updateUserModeration(id, { mutedUntil: null }) } async function suspendUser(userId, { durationDays = 7 } = {}) { const { id } = await ensureUserExists(userId) const suspendedUntil = computeUntil(durationDays) return updateUserModeration(id, { suspendedUntil }) } async function clearSuspend(userId) { const { id } = await ensureUserExists(userId) return updateUserModeration(id, { suspendedUntil: null }) } async function disableUser(userId) { const { id } = await ensureUserExists(userId) const disabledAt = new Date() await refreshTokenDb.revokeAllUserRefreshTokens(id) return updateUserModeration(id, { disabledAt }) } async function enableUser(userId) { const { id } = await ensureUserExists(userId) return updateUserModeration(id, { disabledAt: null }) } async function updateUserRole(userId, role) { const { id } = await ensureUserExists(userId) const normalized = String(role || "").toUpperCase() if (!["USER", "MOD"].includes(normalized)) { const err = new Error("INVALID_ROLE") err.statusCode = 400 throw err } return updateUserModeration(id, { role: normalized }) } async function addUserNote({ userId, createdById, note }) { const uid = assertUserId(userId) const cid = assertUserId(createdById) const text = sanitizeOptionalPlainText(note, { maxLength: 1000 }) if (!text) { const err = new Error("NOTE_REQUIRED") err.statusCode = 400 throw err } queueUserNoteCreate({ userId: uid, createdById: cid, note: text, createdAt: new Date().toISOString(), }).catch((err) => console.error("DB sync user note failed:", err?.message || err)) return { userId: uid, createdById: cid, note: text } } async function listUserNotes({ userId, page = 1, limit = 20 }) { const uid = assertUserId(userId) const safePage = Number.isInteger(Number(page)) && Number(page) > 0 ? Number(page) : 1 const safeLimit = Number.isInteger(Number(limit)) && Number(limit) > 0 ? Number(limit) : 20 const skip = (safePage - 1) * safeLimit const [notes, total, userExists] = await Promise.all([ userNoteDb.listUserNotes({ userId: uid, skip, take: safeLimit }), userNoteDb.countUserNotes({ userId: uid }), userDb.findUser({ id: uid }, { select: { id: true } }).then((u) => Boolean(u)), ]) if (!userExists) { const err = new Error("USER_NOT_FOUND") err.statusCode = 404 throw err } return { page: safePage, total, totalPages: total ? Math.ceil(total / safeLimit) : 0, results: notes, } } module.exports = { muteUser, clearMute, suspendUser, clearSuspend, disableUser, enableUser, updateUserRole, addUserNote, listUserNotes, }