- Split 753-line jmap.service.js into modular structure: - jmap/config.js: JMAP configuration functions - jmap/client.js: Base JMAP requests (jmapRequest, getMailboxes, getIdentities) - jmap/discovery.js: Contact discovery from JMAP - jmap/search.js: Email search functionality - jmap/sync.js: Email synchronization - jmap/operations.js: Email operations (markAsRead, sendEmail) - jmap/index.js: Re-exports for backward compatibility - Update all imports across codebase to use new module structure - Translate remaining English error/log messages to Slovak: - email.service.js: JMAP validation messages - admin.service.js: Email account creation error - audit.service.js: Audit event logging error - timesheet.service.js: File deletion error - database.js: Database error message 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
333 lines
8.5 KiB
JavaScript
333 lines
8.5 KiB
JavaScript
import * as contactService from '../services/contact.service.js';
|
|
import { discoverContactsFromJMAP, getJmapConfigFromAccount } from '../services/jmap/index.js';
|
|
import * as emailAccountService from '../services/email-account.service.js';
|
|
|
|
/**
|
|
* Get all contacts for an email account
|
|
* GET /api/contacts?accountId=xxx (required)
|
|
*/
|
|
export const getContacts = async (req, res, next) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const { accountId } = req.query;
|
|
|
|
if (!accountId) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
message: 'accountId je povinný parameter',
|
|
statusCode: 400,
|
|
},
|
|
});
|
|
}
|
|
|
|
// Verify user has access to this email account
|
|
await emailAccountService.getEmailAccountById(accountId, userId);
|
|
|
|
// Get contacts for email account
|
|
const contacts = await contactService.getContactsForEmailAccount(accountId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
count: contacts.length,
|
|
data: contacts,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Discover potential contacts from JMAP (email senders)
|
|
* GET /api/contacts/discover?accountId=xxx&search=query&limit=50
|
|
*/
|
|
export const discoverContacts = async (req, res, next) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const { accountId, search = '', limit = 50 } = req.query;
|
|
|
|
// Get email account (or primary if not specified)
|
|
let emailAccount;
|
|
if (accountId) {
|
|
emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId);
|
|
} else {
|
|
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);
|
|
}
|
|
|
|
const jmapConfig = getJmapConfigFromAccount(emailAccount);
|
|
|
|
const potentialContacts = await discoverContactsFromJMAP(
|
|
jmapConfig,
|
|
emailAccount.id, // emailAccountId
|
|
search,
|
|
parseInt(limit)
|
|
);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
count: potentialContacts.length,
|
|
data: potentialContacts,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Add a new contact
|
|
* POST /api/contacts
|
|
* Body: { email, name, notes, accountId }
|
|
*/
|
|
export const addContact = async (req, res, next) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const { email, name = '', notes = '', accountId } = req.body;
|
|
|
|
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) {
|
|
emailAccount = await emailAccountService.getEmailAccountWithCredentials(accountId, userId);
|
|
} else {
|
|
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);
|
|
}
|
|
|
|
const jmapConfig = getJmapConfigFromAccount(emailAccount);
|
|
|
|
const contact = await contactService.addContact(
|
|
emailAccount.id,
|
|
jmapConfig,
|
|
email,
|
|
name,
|
|
notes,
|
|
userId // addedByUserId
|
|
);
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
data: contact,
|
|
message: 'Kontakt pridaný a emaily synchronizované',
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Remove a contact
|
|
* DELETE /api/contacts/:contactId?accountId=xxx
|
|
*/
|
|
export const removeContact = async (req, res, next) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const { contactId } = req.params;
|
|
const { accountId } = req.query;
|
|
|
|
if (!accountId) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
message: 'accountId je povinný parameter',
|
|
statusCode: 400,
|
|
},
|
|
});
|
|
}
|
|
|
|
// Verify user has access to this email account
|
|
await emailAccountService.getEmailAccountById(accountId, userId);
|
|
|
|
const result = await contactService.removeContact(contactId, accountId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
message: result.message,
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Update a contact
|
|
* PATCH /api/contacts/:contactId?accountId=xxx
|
|
*/
|
|
export const updateContact = async (req, res, next) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const { contactId } = req.params;
|
|
const { accountId } = req.query;
|
|
const { name, notes } = req.body;
|
|
|
|
if (!accountId) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
message: 'accountId je povinný parameter',
|
|
statusCode: 400,
|
|
},
|
|
});
|
|
}
|
|
|
|
// Verify user has access to this email account
|
|
await emailAccountService.getEmailAccountById(accountId, userId);
|
|
|
|
const updated = await contactService.updateContact(contactId, accountId, { name, notes });
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
data: updated,
|
|
message: 'Kontakt aktualizovaný',
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Link company to contact
|
|
* POST /api/contacts/:contactId/link-company?accountId=xxx
|
|
* Body: { companyId }
|
|
*/
|
|
export const linkCompanyToContact = async (req, res, next) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const { contactId } = req.params;
|
|
const { accountId } = req.query;
|
|
const { companyId } = req.body;
|
|
|
|
if (!accountId) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
message: 'accountId je povinný parameter',
|
|
statusCode: 400,
|
|
},
|
|
});
|
|
}
|
|
|
|
if (!companyId) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
message: 'companyId je povinný',
|
|
statusCode: 400,
|
|
},
|
|
});
|
|
}
|
|
|
|
// Verify user has access to this email account
|
|
await emailAccountService.getEmailAccountById(accountId, userId);
|
|
|
|
const updated = await contactService.linkCompanyToContact(contactId, accountId, companyId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
data: updated,
|
|
message: 'Firma bola linknutá ku kontaktu',
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Unlink company from contact
|
|
* POST /api/contacts/:contactId/unlink-company?accountId=xxx
|
|
*/
|
|
export const unlinkCompanyFromContact = async (req, res, next) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const { contactId } = req.params;
|
|
const { accountId } = req.query;
|
|
|
|
if (!accountId) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
message: 'accountId je povinný parameter',
|
|
statusCode: 400,
|
|
},
|
|
});
|
|
}
|
|
|
|
// Verify user has access to this email account
|
|
await emailAccountService.getEmailAccountById(accountId, userId);
|
|
|
|
const updated = await contactService.unlinkCompanyFromContact(contactId, accountId);
|
|
|
|
res.status(200).json({
|
|
success: true,
|
|
data: updated,
|
|
message: 'Firma bola odlinknutá od kontaktu',
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Create company from contact
|
|
* POST /api/contacts/:contactId/create-company?accountId=xxx
|
|
* Body: { name, email, phone, address, city, country, website, description } (all optional, uses contact data as defaults)
|
|
*/
|
|
export const createCompanyFromContact = async (req, res, next) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const { contactId } = req.params;
|
|
const { accountId } = req.query;
|
|
const companyData = req.body;
|
|
|
|
if (!accountId) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
message: 'accountId je povinný parameter',
|
|
statusCode: 400,
|
|
},
|
|
});
|
|
}
|
|
|
|
// Verify user has access to this email account
|
|
await emailAccountService.getEmailAccountById(accountId, userId);
|
|
|
|
const result = await contactService.createCompanyFromContact(contactId, accountId, userId, companyData);
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
data: result,
|
|
message: 'Firma bola vytvorená z kontaktu',
|
|
});
|
|
} catch (error) {
|
|
next(error);
|
|
}
|
|
};
|