import * as contactService from '../services/contact.service.js'; import { discoverContactsFromJMAP, getJmapConfigFromAccount } from '../services/jmap.service.js'; import { formatErrorResponse } from '../utils/errors.js'; import * as emailAccountService from '../services/email-account.service.js'; import { logger } from '../utils/logger.js'; /** * Get all contacts for authenticated user * GET /api/contacts?accountId=xxx (optional) */ export const getContacts = async (req, res) => { try { const userId = req.userId; const { accountId } = req.query; const contacts = await contactService.getUserContacts(userId, accountId || null); res.status(200).json({ success: true, count: contacts.length, data: contacts, }); } catch (error) { const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development'); res.status(error.statusCode || 500).json(errorResponse); } }; /** * Discover potential contacts from JMAP (email senders) * GET /api/contacts/discover?accountId=xxx&search=query&limit=50 */ export const discoverContacts = async (req, res) => { try { const userId = req.userId; const { accountId, search = '', limit = 50 } = req.query; logger.debug('discoverContacts called', { userId, accountId, search, limit }); // Get email account (or primary if not specified) let emailAccount; if (accountId) { logger.debug('Getting email account by ID', { accountId }); emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId); logger.debug('Email account retrieved', { id: emailAccount.id, email: emailAccount.email }); } else { logger.debug('No accountId provided, getting primary account', { userId }); const primaryAccount = await emailAccountService.getPrimaryEmailAccount(userId); logger.debug('Primary account', primaryAccount ? { id: primaryAccount.id, email: primaryAccount.email } : { found: false }); if (!primaryAccount) { return res.status(400).json({ success: false, error: { message: 'Najprv musíš pripojiť email účet v Profile', statusCode: 400, }, }); } emailAccount = await emailAccountService.getEmailAccountWithCredentials(primaryAccount.id, userId); logger.debug('Email account retrieved from primary', { id: emailAccount.id, email: emailAccount.email }); } const jmapConfig = getJmapConfigFromAccount(emailAccount); logger.debug('JMAP Config created', { server: jmapConfig.server, username: jmapConfig.username, accountId: jmapConfig.accountId, hasPassword: !!jmapConfig.password }); const potentialContacts = await discoverContactsFromJMAP( jmapConfig, userId, search, parseInt(limit) ); res.status(200).json({ success: true, count: potentialContacts.length, data: potentialContacts, }); } catch (error) { logger.error('ERROR in discoverContacts', { error: error.message, stack: error.stack }); const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development'); res.status(error.statusCode || 500).json(errorResponse); } }; /** * Add a new contact * POST /api/contacts * Body: { email, name, notes, accountId } */ export const addContact = async (req, res) => { try { const userId = req.userId; logger.debug('Full req.body', { body: req.body }); const { email, name = '', notes = '', accountId } = req.body; logger.debug('addContact called', { userId, email, name, accountId }); if (!email) { return res.status(400).json({ success: false, error: { message: 'Email je povinný', statusCode: 400, }, }); } // Get email account (or primary if not specified) let emailAccount; if (accountId) { logger.debug('Using provided accountId', { accountId }); emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId); } else { logger.debug('No accountId provided, using primary account'); const primaryAccount = await emailAccountService.getPrimaryEmailAccount(userId); if (!primaryAccount) { return res.status(400).json({ success: false, error: { message: 'Najprv musíš pripojiť email účet v Profile', statusCode: 400, }, }); } emailAccount = await emailAccountService.getEmailAccountWithCredentials(primaryAccount.id, userId); logger.debug('Using primary account', { accountId: primaryAccount.id }); } const jmapConfig = getJmapConfigFromAccount(emailAccount); const contact = await contactService.addContact( userId, emailAccount.id, jmapConfig, email, name, notes ); res.status(201).json({ success: true, data: contact, message: 'Kontakt pridaný a emaily synchronizované', }); } catch (error) { const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development'); res.status(error.statusCode || 500).json(errorResponse); } }; /** * Remove a contact * DELETE /api/contacts/:contactId */ export const removeContact = async (req, res) => { try { const userId = req.userId; const { contactId } = req.params; const result = await contactService.removeContact(userId, contactId); res.status(200).json({ success: true, message: result.message, }); } catch (error) { const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development'); res.status(error.statusCode || 500).json(errorResponse); } }; /** * Update a contact * PATCH /api/contacts/:contactId */ export const updateContact = async (req, res) => { try { const userId = req.userId; const { contactId } = req.params; const { name, notes } = req.body; const updated = await contactService.updateContact(userId, contactId, { name, notes }); res.status(200).json({ success: true, data: updated, message: 'Kontakt aktualizovaný', }); } catch (error) { const errorResponse = formatErrorResponse(error, process.env.NODE_ENV === 'development'); res.status(error.statusCode || 500).json(errorResponse); } };