UNPKG

@accounter/server

Version:
141 lines (124 loc) 4.48 kB
import { GraphQLError } from 'graphql'; import type { BusinessEmailConfig } from '../../../__generated__/types.js'; import { hashStringToInt } from '../../../shared/helpers/index.js'; import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js'; import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js'; import { ChargesProvider } from '../../charges/providers/charges.provider.js'; import { getDocumentFromFile } from '../../documents/helpers/upload.helper.js'; import { DocumentsProvider } from '../../documents/providers/documents.provider.js'; import { IInsertDocumentsParams } from '../../documents/types.js'; import { suggestionDataSchema } from '../../financial-entities/helpers/business-suggestion-data-schema.helper.js'; import { BusinessesProvider } from '../../financial-entities/providers/businesses.provider.js'; import { EmailListenerConfig } from '../../financial-entities/types.js'; import type { EmailIngestionModule } from '../types.js'; const businessEmailConfig: EmailIngestionModule.QueryResolvers['businessEmailConfig'] = async ( _, { email }, { injector }, ) => { const business = await injector.get(BusinessesProvider).getBusinessByEmail(email); if (!business) { return null; } let listenerConfig: EmailListenerConfig = {}; if (business?.suggestion_data) { const { data, success, error } = suggestionDataSchema.safeParse(business.suggestion_data); if (success) { if (data.emailListener) { listenerConfig = data.emailListener; } } else { console.error( `Invalid suggestion_data schema for business "${business.name}" [${business.id}]: ${JSON.stringify(error.issues)}`, ); } } const listenerConfigRes: Omit<BusinessEmailConfig, 'businessId'> = { internalEmailLinks: listenerConfig.internalEmailLinks, emailBody: listenerConfig.emailBody, attachments: listenerConfig.attachments, }; return { ...listenerConfigRes, businessId: business.id, }; }; const insertEmailDocuments: EmailIngestionModule.MutationResolvers['insertEmailDocuments'] = async ( _, { documents, userDescription, messageId, businessId }, { injector }, ) => { if (documents.length === 0) { return true; } try { const { ownerId } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); const newDocuments: Array<IInsertDocumentsParams['documents'][number]> = []; await Promise.all( documents.map(async doc => { const hash = hashStringToInt(await doc.text()); const existingDocument = await injector.get(DocumentsProvider).getDocumentByHash.load(hash); if (existingDocument) { console.log( `Document ${'name' in doc ? doc.name : 'unknown'} already exists in the database with id=${existingDocument.id}, skipping upload.`, ); return; } const newDocument = await getDocumentFromFile( injector, doc, null, false, businessId ?? undefined, hash, ); newDocuments.push({ ...newDocument, remarks: userDescription }); }), ); if (newDocuments.length > 0) { await injector.get(TenantAwareDBClient).transaction(async client => { const charge = await injector .get(ChargesProvider) .generateCharge( { ownerId, userDescription, }, client, ) .catch(e => { throw new Error(`Error generating charge for email id=${messageId}: ${e}`); }); if (!charge?.id) { throw new Error(`Charge creation failed for email id=${messageId}`); } const documentsWithChargeId = newDocuments.map(doc => ({ ...doc, chargeId: charge.id, })); return await injector .get(DocumentsProvider) .insertDocuments({ documents: documentsWithChargeId }, client); }); } return true; } catch (error) { console.error('Failed to insert email documents:', error); if (error instanceof GraphQLError) { throw error; } throw new GraphQLError(`Failed to insert email documents`, { extensions: { code: 'INTERNAL_SERVER_ERROR', }, }); } }; export const emailIngestionResolvers = { Query: { businessEmailConfig, }, Mutation: { insertEmailDocuments, }, };