const householdModel = require("../models/household.model"); const { sendError } = require("../utils/http"); const { inviteCodeLast4 } = require("../utils/redaction"); const { logError } = require("../utils/logger"); // Get all households user belongs to exports.getUserHouseholds = async (req, res) => { try { const households = await householdModel.getUserHouseholds(req.user.id); res.json(households); } catch (error) { logError(req, "households.getUserHouseholds", error); sendError(res, 500, "Failed to fetch households"); } }; // Get household details exports.getHousehold = async (req, res) => { try { const household = await householdModel.getHouseholdById( req.params.householdId, req.user.id ); if (!household) { return sendError(res, 404, "Household not found"); } res.json(household); } catch (error) { logError(req, "households.getHousehold", error); sendError(res, 500, "Failed to fetch household"); } }; // Create new household exports.createHousehold = async (req, res) => { try { const { name } = req.body; if (!name || name.trim().length === 0) { return sendError(res, 400, "Household name is required"); } if (name.length > 100) { return sendError(res, 400, "Household name must be 100 characters or less"); } const household = await householdModel.createHousehold( name.trim(), req.user.id ); res.status(201).json({ message: "Household created successfully", household }); } catch (error) { logError(req, "households.createHousehold", error); sendError(res, 500, "Failed to create household"); } }; // Update household exports.updateHousehold = async (req, res) => { try { const { name } = req.body; if (!name || name.trim().length === 0) { return sendError(res, 400, "Household name is required"); } if (name.length > 100) { return sendError(res, 400, "Household name must be 100 characters or less"); } const household = await householdModel.updateHousehold( req.params.householdId, { name: name.trim() } ); res.json({ message: "Household updated successfully", household }); } catch (error) { logError(req, "households.updateHousehold", error); sendError(res, 500, "Failed to update household"); } }; // Delete household exports.deleteHousehold = async (req, res) => { try { await householdModel.deleteHousehold(req.params.householdId); res.json({ message: "Household deleted successfully" }); } catch (error) { logError(req, "households.deleteHousehold", error); sendError(res, 500, "Failed to delete household"); } }; // Refresh invite code exports.refreshInviteCode = async (req, res) => { try { const household = await householdModel.refreshInviteCode(req.params.householdId); res.json({ message: "Invite code refreshed successfully", household }); } catch (error) { logError(req, "households.refreshInviteCode", error, { invite_last4: inviteCodeLast4(req.body?.inviteCode), }); sendError(res, 500, "Failed to refresh invite code"); } }; // Join household via invite code exports.joinHousehold = async (req, res) => { const inviteLast4 = inviteCodeLast4(req.params.inviteCode); try { const { inviteCode } = req.params; if (!inviteCode) return sendError(res, 400, "Invite code is required"); const result = await householdModel.joinHousehold( inviteCode.toUpperCase(), req.user.id ); if (!result) return sendError(res, 404, "Invalid or expired invite code"); if (result.alreadyMember) { return res.status(200).json({ message: "You are already a member of this household", household: { id: result.id, name: result.name } }); } res.status(200).json({ message: `Successfully joined ${result.name}`, household: { id: result.id, name: result.name } }); } catch (error) { logError(req, "households.joinHousehold", error, { invite_last4: inviteLast4 }); sendError(res, 500, "Failed to join household"); } }; // Get household members exports.getMembers = async (req, res) => { try { const members = await householdModel.getHouseholdMembers(req.params.householdId); res.json(members); } catch (error) { logError(req, "households.getMembers", error); sendError(res, 500, "Failed to fetch members"); } }; // Update member role exports.updateMemberRole = async (req, res) => { try { const { userId } = req.params; const { role } = req.body; if (!role || !['admin', 'user'].includes(role)) { return sendError(res, 400, "Invalid role. Must be 'admin' or 'user'"); } // Can't change own role if (parseInt(userId) === req.user.id) { return sendError(res, 400, "Cannot change your own role"); } const updated = await householdModel.updateMemberRole( req.params.householdId, userId, role ); res.json({ message: "Member role updated successfully", member: updated }); } catch (error) { logError(req, "households.updateMemberRole", error); sendError(res, 500, "Failed to update member role"); } }; // Remove member exports.removeMember = async (req, res) => { try { const { userId } = req.params; const targetUserId = parseInt(userId); // Allow users to remove themselves, or admins to remove others if (targetUserId !== req.user.id && req.household.role !== 'admin') { return sendError(res, 403, "Only admins can remove other members"); } await householdModel.removeMember(req.params.householdId, userId); res.json({ message: "Member removed successfully" }); } catch (error) { logError(req, "households.removeMember", error); sendError(res, 500, "Failed to remove member"); } };