/*********************************************************************************************************************************************************************** * File Name: profile.controller.js (admin) * Type of Program: Controller * Description: Self-service profile management for admin users. * All routes require: authenticate → requireAdmin() * * Endpoints: * GET /api/admin/profile → view own profile * PUT /api/admin/profile → update personal_info * POST /api/admin/profile/avatar → upload / replace avatar * DELETE /api/admin/profile/avatar → remove avatar * * Author: Kenneth Obsequio (@lash0000) * Date Created: Jun. 18, 2026 ***********************************************************************************************************************************************************************/ 'use strict'; const mdl_Users = require('../../models/users/users.mdl'); const R = require('../../utils/response.util'); const { uploadFile, deleteFile } = require('../../services/s3.service'); const { resolveUserAvatar } = require('../../utils/resolveAvatar.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.', await resolveUserAvatar(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; 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.', await resolveUserAvatar(updated)); } catch (err) { console.error('[ADMIN] updateProfile error:', err); return R.error(res, 'Profile update failed.', 500); } }; // ─── POST upload own avatar ──────────────────────────────────────────────────── exports.uploadAvatar = async (req, res) => { try { if (!req.file) return R.error(res, 'No file provided.', 400); const user = await mdl_Users.findByPk(req.user.user_id); // Remove old avatar from S3 before replacing const oldKey = user.personal_info?.avatar?.uuid; if (oldKey) await deleteFile(oldKey).catch(() => {}); const { url, uuid } = await uploadFile({ buffer: req.file.buffer, originalname: req.file.originalname, mimetype: req.file.mimetype, ownerType: 'avatar', }); const merged = { ...(user.personal_info || {}), avatar: { url, uuid, name: req.file.originalname, mime_type: req.file.mimetype, size: req.file.size, }, }; 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, 'Avatar updated.', await resolveUserAvatar(updated)); } catch (err) { console.error('[ADMIN] uploadAvatar error:', err); return R.error(res, 'Avatar upload failed.', 500); } }; // ─── DELETE remove own avatar ────────────────────────────────────────────────── exports.deleteAvatar = async (req, res) => { try { const user = await mdl_Users.findByPk(req.user.user_id); const key = user.personal_info?.avatar?.uuid; if (!key) return R.error(res, 'No avatar to remove.', 404); await deleteFile(key).catch(() => {}); const merged = { ...(user.personal_info || {}), avatar: null }; await user.update({ personal_info: merged }); return R.success(res, 'Avatar removed.'); } catch (err) { console.error('[ADMIN] deleteAvatar error:', err); return R.error(res, 'Could not remove avatar.', 500); } };