import EmailRepository from "@Repositories/EmailRepository"; import BaseService from "@Services/BaseService"; import { Emails, Prisma } from "@prisma/client"; import { Service } from "typedi"; import MailchimpClient from "@mailchimp/mailchimp_transactional"; import { BackendVariables } from "@Common/config/variables/Variables"; @Service() export default class MailchimpService extends BaseService { private static readonly from = "no-reply@lecoffre.io"; // Construct the service constructor(private emailRepository: EmailRepository, protected variables: BackendVariables) { super(); } /** * @description : Get all emails * @throws {Error} If emails cannot be get */ public async get(query: Prisma.EmailsFindManyArgs): Promise { return this.emailRepository.findMany(query); } /** * @description : Create a new email * @throws {Error} If email cannot be created */ public async create(emailEntity: Emails): Promise { emailEntity.from = MailchimpService.from; return this.emailRepository.create(emailEntity); } /** * @description : Modify an email * @throws {Error} If email cannot be modified */ public async update(uid: string, emailEntity: Emails): Promise { return this.emailRepository.update(uid, emailEntity); } /** * @description : Get a email by uid * @throws {Error} If email cannot be get */ public async getByUid(uid: string, query?: any): Promise { return this.emailRepository.findOneByUid(uid); } /** * @description : Function called by cron to send emails * @throws {Error} If email cannot be sent */ public async sendEmails() { const emailsToSend = await this.get({ where: { sentAt: null } }); const currentDate = new Date(); let nextTrySendDate = null; for (const email of emailsToSend) { //If tries exceed 10, we stop trying to send the email if (email.nbTrySend && email.nbTrySend > 9) continue; //If email has never been sent, we send it if (email.nbTrySend == 0) { nextTrySendDate = currentDate; } //If email has already been sent, we send it again every nbTrySend^2 minutes else { nextTrySendDate = new Date(email.lastTrySendDate!); nextTrySendDate.setMinutes(nextTrySendDate.getMinutes() + Math.pow(email.nbTrySend!, 2)); } //If the next try send date is passed, we send the email if (currentDate >= nextTrySendDate) { try { await this.sendEmail(email); email.sentAt = currentDate; } catch (error) { email.lastTrySendDate = currentDate; email.nbTrySend = email.nbTrySend! + 1; } await this.update(email.uid, email); } } } private async sendEmail(email: Emails) { const apiKey = this.variables.MAILCHIMP_API_KEY; const mailchimpApiClient = MailchimpClient(apiKey!); await mailchimpApiClient.messages.sendTemplate({ template_name: email.templateName, template_content: [], message: { global_merge_vars: this.buildVariables(email.templateVariables), from_email: email.from!, from_name: "LeCoffre.io", subject: email.subject, to: [ { email: email.to, type: "to", }, ], }, }); } private buildVariables(templateVariables: any) { return Object.keys(templateVariables).map((key) => { return { name: key, content: templateVariables[key], }; }); } public async addToMailchimpList(email: string) { const MAILCHIMP_API_KEY = this.variables.MAILCHIMP_KEY; const data = { email_address: email, status: 'subscribed' }; const response = await fetch(`https://us17.api.mailchimp.com/3.0/lists/6ea48f811d/members`, { method: 'POST', headers: { 'Authorization': `apikey ${MAILCHIMP_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); return response.json(); } }