initialize git, basic setup for crm
This commit is contained in:
120
src/services/crm-email.service.js
Normal file
120
src/services/crm-email.service.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import { db } from '../config/database.js';
|
||||
import { emails, contacts } from '../db/schema.js';
|
||||
import { eq, and, or, desc, like, sql } from 'drizzle-orm';
|
||||
import { NotFoundError } from '../utils/errors.js';
|
||||
|
||||
/**
|
||||
* Get all emails for a user (only from added contacts)
|
||||
*/
|
||||
export const getUserEmails = async (userId) => {
|
||||
const userEmails = await db
|
||||
.select({
|
||||
id: emails.id,
|
||||
jmapId: emails.jmapId,
|
||||
messageId: emails.messageId,
|
||||
threadId: emails.threadId,
|
||||
inReplyTo: emails.inReplyTo,
|
||||
from: emails.from,
|
||||
to: emails.to,
|
||||
subject: emails.subject,
|
||||
body: emails.body,
|
||||
isRead: emails.isRead,
|
||||
date: emails.date,
|
||||
createdAt: emails.createdAt,
|
||||
contact: {
|
||||
id: contacts.id,
|
||||
email: contacts.email,
|
||||
name: contacts.name,
|
||||
},
|
||||
})
|
||||
.from(emails)
|
||||
.leftJoin(contacts, eq(emails.contactId, contacts.id))
|
||||
.where(eq(emails.userId, userId))
|
||||
.orderBy(desc(emails.date));
|
||||
|
||||
return userEmails;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get emails by thread ID
|
||||
*/
|
||||
export const getEmailThread = async (userId, threadId) => {
|
||||
const thread = await db
|
||||
.select()
|
||||
.from(emails)
|
||||
.where(and(eq(emails.userId, userId), eq(emails.threadId, threadId)))
|
||||
.orderBy(emails.date);
|
||||
|
||||
if (thread.length === 0) {
|
||||
throw new NotFoundError('Thread nenájdený');
|
||||
}
|
||||
|
||||
return thread;
|
||||
};
|
||||
|
||||
/**
|
||||
* Search emails (from, to, subject)
|
||||
*/
|
||||
export const searchEmails = async (userId, query) => {
|
||||
if (!query || query.trim().length < 2) {
|
||||
throw new Error('Search term must be at least 2 characters');
|
||||
}
|
||||
|
||||
const searchPattern = `%${query}%`;
|
||||
|
||||
const results = await db
|
||||
.select()
|
||||
.from(emails)
|
||||
.where(
|
||||
and(
|
||||
eq(emails.userId, userId),
|
||||
or(
|
||||
like(emails.from, searchPattern),
|
||||
like(emails.to, searchPattern),
|
||||
like(emails.subject, searchPattern)
|
||||
)
|
||||
)
|
||||
)
|
||||
.orderBy(desc(emails.date))
|
||||
.limit(50);
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get unread email count
|
||||
*/
|
||||
export const getUnreadCount = async (userId) => {
|
||||
const result = await db
|
||||
.select({ count: sql`count(*)::int` })
|
||||
.from(emails)
|
||||
.where(and(eq(emails.userId, userId), eq(emails.isRead, false)));
|
||||
|
||||
return result[0]?.count || 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark thread as read
|
||||
*/
|
||||
export const markThreadAsRead = async (userId, threadId) => {
|
||||
const result = await db
|
||||
.update(emails)
|
||||
.set({ isRead: true, updatedAt: new Date() })
|
||||
.where(and(eq(emails.userId, userId), eq(emails.threadId, threadId), eq(emails.isRead, false)))
|
||||
.returning();
|
||||
|
||||
return { success: true, count: result.length };
|
||||
};
|
||||
|
||||
/**
|
||||
* Get emails for a specific contact
|
||||
*/
|
||||
export const getContactEmails = async (userId, contactId) => {
|
||||
const contactEmails = await db
|
||||
.select()
|
||||
.from(emails)
|
||||
.where(and(eq(emails.userId, userId), eq(emails.contactId, contactId)))
|
||||
.orderBy(desc(emails.date));
|
||||
|
||||
return contactEmails;
|
||||
};
|
||||
Reference in New Issue
Block a user