const db = require("../models"); const { ACCOUNT_TYPE_VALUES } = require("../constants/accountTypes"); const { revokeAllUserSessions } = require("../services/auth/session.service"); const { logActivity } = require("../services/activity.service"); const updateSecurityField = (field) => async (req, res, next) => { try { const value = req.body[field]; if (field === "accountType" && !ACCOUNT_TYPE_VALUES.includes(value)) return res.status(400).json({ success: false, error: { code: "INVALID_ACCOUNT_TYPE", message: "Invalid account type" } }); if (field === "accountStatus" && !["PENDING_VERIFICATION", "ACTIVE", "SUSPENDED", "DEACTIVATED"].includes(value)) return res.status(400).json({ success: false, error: { code: "INVALID_ACCOUNT_STATUS", message: "Invalid account status" } }); if (req.params.id === req.user.id) return res.status(400).json({ success: false, error: { code: "SELF_SECURITY_CHANGE_DENIED", message: "Security-sensitive self changes are not allowed" } }); let target; let previous; await db.sequelize.transaction(async (transaction) => { target = await db.User.findByPk(req.params.id, { transaction, lock: transaction.LOCK.UPDATE }); if (!target) throw Object.assign(new Error("User not found"), { status: 404, code: "USER_NOT_FOUND" }); previous = target[field]; target[field] = value; target.tokenVersion += 1; await target.save({ transaction }); await revokeAllUserSessions(target.id, `ADMIN_${field.toUpperCase()}_CHANGE`, transaction); }); await logActivity({ user: req.user, description: `${field} changed for ${target.id} from ${previous} to ${value}; reason: ${req.body.reason || "not supplied"}; request: ${req.id}`, type: field === "accountStatus" ? "ACCOUNT_STATUS_CHANGED" : "ACCOUNT_TYPE_CHANGED", module: "Identity Administration" }); res.json({ success: true, data: { id: target.id, [field]: target[field] } }); } catch (error) { next(error); } }; exports.updateStatus = updateSecurityField("accountStatus"); exports.updateAccountType = updateSecurityField("accountType");