/*********************************************************************************************************************************************************************** * File Name: profile.controller.js (client) * Type of Program: Controller * Description: Self-service profile management for CLIENT users. * All routes require: authenticate → requireClient() * * Endpoints: * GET /api/client/profile → view own profile * PUT /api/client/profile → update personal_info * GET /api/client/sessions → view own active sessions * DELETE /api/client/sessions/:id → revoke a specific session * * Author: rgrgogu * Date Created: Oct. 6, 2025 ***********************************************************************************************************************************************************************/ const mdl_Users = require('../../models/users/users.mdl'); const mdl_UserSessions = require('../../models/users/user_sessions.mdl'); const R = require('../../utils/response.util'); // ─── GET own profile ─────────────────────────────────────────────────────────── exports.getProfile = async (req, res) => { try { const user = await mdl_Users.findByPk(req.user.user_id, { attributes: { exclude: ['password', 'otp_code', 'otp_expires_at'] }, }); return R.success(res, 'Profile retrieved.', user); } catch (err) { return R.error(res, 'Could not retrieve profile.', 500); } }; // ─── PUT update own profile ──────────────────────────────────────────────────── exports.updateProfile = async (req, res) => { try { const user = await mdl_Users.findByPk(req.user.user_id); const { personal_info } = req.body; // Deep-merge personal_info so partial updates don't wipe existing data const merged = { ...(user.personal_info || {}), ...(personal_info || {}), name: { ...((user.personal_info?.name) || {}), ...((personal_info?.name) || {}), }, }; await user.update({ personal_info: merged }); const updated = await mdl_Users.findByPk(req.user.user_id, { attributes: { exclude: ['password', 'otp_code', 'otp_expires_at'] }, }); return R.success(res, 'Profile updated.', updated); } catch (err) { console.error('[CLIENT] updateProfile error:', err); return R.error(res, 'Profile update failed.', 500); } }; // ─── GET own sessions ────────────────────────────────────────────────────────── exports.getSessions = async (req, res) => { try { const sessions = await mdl_UserSessions.findAll({ where: { user_id: req.user.user_id, is_active: true }, order: [['createdAt', 'DESC']], attributes: { exclude: ['refresh_token_hash'] }, }); return R.success(res, 'Sessions retrieved.', sessions); } catch (err) { return R.error(res, 'Could not retrieve sessions.', 500); } }; // ─── DELETE revoke a session ─────────────────────────────────────────────────── exports.revokeSession = async (req, res) => { try { const session = await mdl_UserSessions.findOne({ where: { session_id: req.params.id, user_id: req.user.user_id }, }); if (!session) return R.error(res, 'Session not found.', 404); await session.update({ is_active: false, logout_info: { date: new Date().toISOString(), ip_address: req.ip }, }); return R.success(res, 'Session revoked.'); } catch (err) { return R.error(res, 'Could not revoke session.', 500); } };