Added mailchimp feature + cron services
This commit is contained in:
parent
399ed9ac3c
commit
8fd59a13d8
46
Dockerfile-Cron
Normal file
46
Dockerfile-Cron
Normal file
@ -0,0 +1,46 @@
|
||||
# Install dependencies only when needed
|
||||
FROM node:19-alpine AS deps
|
||||
|
||||
WORKDIR leCoffre
|
||||
|
||||
RUN npm install -D prisma@4.11.0
|
||||
COPY package.json ./
|
||||
|
||||
RUN apk update && apk add openssh-client git
|
||||
|
||||
COPY id_rsa /root/.ssh/id_rsa
|
||||
RUN chmod 600 ~/.ssh/id_rsa
|
||||
RUN eval "$(ssh-agent -s)" && ssh-add /root/.ssh/id_rsa
|
||||
RUN ssh-keyscan github.com smart-chain-fr/leCoffre-resources.git >> /root/.ssh/known_hosts
|
||||
|
||||
RUN npm install --frozen-lockfile
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM node:19-alpine AS builder
|
||||
|
||||
WORKDIR leCoffre
|
||||
|
||||
COPY --from=deps leCoffre/node_modules ./node_modules
|
||||
COPY --from=deps leCoffre/package.json package.json
|
||||
COPY tsconfig.json tsconfig.json
|
||||
COPY src src
|
||||
|
||||
RUN npx prisma generate
|
||||
RUN npm run build
|
||||
|
||||
# Production image, copy all the files and run next
|
||||
FROM node:19-alpine AS production
|
||||
|
||||
WORKDIR leCoffre
|
||||
|
||||
RUN adduser -D lecoffreuser --uid 10000 && chown -R lecoffreuser .
|
||||
|
||||
COPY --from=builder --chown=lecoffreuser leCoffre/node_modules ./node_modules
|
||||
COPY --from=builder --chown=lecoffreuser leCoffre/dist dist
|
||||
COPY --from=builder --chown=lecoffreuser leCoffre/package.json ./package.json
|
||||
COPY --from=builder --chown=lecoffreuser leCoffre/src/common/databases ./src/common/databases
|
||||
|
||||
USER lecoffreuser
|
||||
|
||||
CMD ["npm", "run", "cron"]
|
||||
EXPOSE 3001
|
61
package-lock.json
generated
61
package-lock.json
generated
@ -9,12 +9,14 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mailchimp/mailchimp_transactional": "^1.0.50",
|
||||
"@pinata/sdk": "^2.1.0",
|
||||
"@prisma/client": "^4.11.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"classnames": "^2.3.2",
|
||||
"cors": "^2.8.5",
|
||||
"cron": "^2.3.1",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.57",
|
||||
@ -35,9 +37,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/cron": "^2.0.1",
|
||||
"@types/express": "^4.17.16",
|
||||
"@types/jest": "^29.5.0",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/mailchimp__mailchimp_transactional": "^1.0.5",
|
||||
"@types/module-alias": "^2.0.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/node-fetch": "^2.6.3",
|
||||
@ -1044,6 +1049,17 @@
|
||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@mailchimp/mailchimp_transactional": {
|
||||
"version": "1.0.50",
|
||||
"resolved": "https://registry.npmjs.org/@mailchimp/mailchimp_transactional/-/mailchimp_transactional-1.0.50.tgz",
|
||||
"integrity": "sha512-SaNFseFPSDQlOYM9JTyYY6wauMu6qJ8eExo+jssFyb20ZaVvxKX1eTb3Gm5aW/4aWuxn6nofU+02sCk51//wdw==",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "13.4.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.10.tgz",
|
||||
@ -1348,6 +1364,16 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cron": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cron/-/cron-2.0.1.tgz",
|
||||
"integrity": "sha512-WHa/1rtNtD2Q/H0+YTTZoty+/5rcE66iAFX2IY+JuUoOACsevYyFkSYu/2vdw+G5LrmO7Lxowrqm0av4k3qWNQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/luxon": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express": {
|
||||
"version": "4.17.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
|
||||
@ -1430,12 +1456,33 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.1.tgz",
|
||||
"integrity": "sha512-XOS5nBcgEeP2PpcqJHjCWhUCAzGfXIU8ILOSLpx2FhxqMW9KdxgCGXNOEKGVBfveKtIpztHzKK5vSRVLyW/NqA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mailchimp__mailchimp_transactional": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/mailchimp__mailchimp_transactional/-/mailchimp__mailchimp_transactional-1.0.5.tgz",
|
||||
"integrity": "sha512-5LYI3dZcyVBtg+lNxhKBHrHnNeAVvlpPM0kO6FZcjrrMALK7wistwvqI8PAns2mnveC67OSN43y6wQkK6KeTNQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mime": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
|
||||
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/module-alias": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/module-alias/-/module-alias-2.0.1.tgz",
|
||||
"integrity": "sha512-DN/CCT1HQG6HquBNJdLkvV+4v5l/oEuwOHUPLxI+Eub0NED+lk0YUfba04WGH90EINiUrNgClkNnwGmbICeWMQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/multer": {
|
||||
"version": "1.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz",
|
||||
@ -1446,9 +1493,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.16.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.19.tgz",
|
||||
"integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA=="
|
||||
"version": "18.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.0.tgz",
|
||||
"integrity": "sha512-GXZxEtOxYGFchyUzxvKI14iff9KZ2DI+A6a37o6EQevtg6uO9t+aUZKcaC1Te5Ng1OnLM7K9NVVj+FbecD9cJg=="
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.6.4",
|
||||
@ -2287,6 +2334,14 @@
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
|
||||
},
|
||||
"node_modules/cron": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/cron/-/cron-2.3.1.tgz",
|
||||
"integrity": "sha512-1eRRlIT0UfIqauwbG9pkg3J6CX9A6My2ytJWqAXoK0T9oJnUZTzGBNPxao0zjodIbPgf8UQWjE62BMb9eVllSQ==",
|
||||
"dependencies": {
|
||||
"luxon": "^3.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/cron-parser": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.8.1.tgz",
|
||||
|
@ -20,6 +20,7 @@
|
||||
"build-db": "npx prisma migrate dev",
|
||||
"build": "tsc",
|
||||
"start": "node ./dist/entries/App.js",
|
||||
"cron": "node ./dist/entries/Cron.js",
|
||||
"api:start": "npm run migrate && npm run start",
|
||||
"dev": "nodemon -V",
|
||||
"format": "prettier --write src",
|
||||
@ -41,12 +42,14 @@
|
||||
},
|
||||
"homepage": "https://github.com/smart-chain-fr/leCoffre-back#readme",
|
||||
"dependencies": {
|
||||
"@mailchimp/mailchimp_transactional": "^1.0.50",
|
||||
"@pinata/sdk": "^2.1.0",
|
||||
"@prisma/client": "^4.11.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.0",
|
||||
"classnames": "^2.3.2",
|
||||
"cors": "^2.8.5",
|
||||
"cron": "^2.3.1",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.58",
|
||||
@ -67,9 +70,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/cron": "^2.0.1",
|
||||
"@types/express": "^4.17.16",
|
||||
"@types/jest": "^29.5.0",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/mailchimp__mailchimp_transactional": "^1.0.5",
|
||||
"@types/module-alias": "^2.0.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^18.11.18",
|
||||
"@types/node-fetch": "^2.6.3",
|
||||
@ -84,6 +90,6 @@
|
||||
},
|
||||
"prisma": {
|
||||
"schema": "src/common/databases/schema.prisma",
|
||||
"seed": "ts-node src/common/databases/seeders/seeder2.ts"
|
||||
"seed": "ts-node src/common/databases/seeders/seeder.ts"
|
||||
}
|
||||
}
|
||||
|
@ -9,11 +9,12 @@ import { validateOrReject } from "class-validator";
|
||||
import authHandler from "@App/middlewares/AuthHandler";
|
||||
import ruleHandler from "@App/middlewares/RulesHandler";
|
||||
import documentHandler from "@App/middlewares/OfficeMembershipHandlers/DocumentHandler";
|
||||
import EmailBuilder from "@Common/emails/EmailBuilder";
|
||||
|
||||
@Controller()
|
||||
@Service()
|
||||
export default class DocumentsController extends ApiController {
|
||||
constructor(private documentsService: DocumentsService) {
|
||||
constructor(private documentsService: DocumentsService, private emailBuilder: EmailBuilder) {
|
||||
super();
|
||||
}
|
||||
|
||||
@ -64,6 +65,9 @@ export default class DocumentsController extends ApiController {
|
||||
//call service to get prisma entity
|
||||
const documentEntityCreated = await this.documentsService.create(documentEntity);
|
||||
|
||||
//create email for asked document
|
||||
this.emailBuilder.sendDocumentEmails(documentEntityCreated);
|
||||
|
||||
//Hydrate ressource with prisma entity
|
||||
const document = Document.hydrate<Document>(documentEntityCreated, {
|
||||
strategy: "excludeAll",
|
||||
@ -105,6 +109,9 @@ export default class DocumentsController extends ApiController {
|
||||
//call service to get prisma entity
|
||||
const documentEntityUpdated: Documents = await this.documentsService.update(uid, documentEntity, req.body.refused_reason);
|
||||
|
||||
//create email for asked document
|
||||
this.emailBuilder.sendDocumentEmails(documentEntityUpdated);
|
||||
|
||||
//Hydrate ressource with prisma entity
|
||||
const document = Document.hydrate<Document>(documentEntityUpdated, { strategy: "excludeAll" });
|
||||
|
||||
|
@ -0,0 +1,43 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_contact_uid_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_office_role_uid_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_office_uid_fkey";
|
||||
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "users" DROP CONSTRAINT "users_roles_uid_fkey";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "email" (
|
||||
"uid" TEXT NOT NULL,
|
||||
"templateName" VARCHAR(255) NOT NULL,
|
||||
"from" VARCHAR(255),
|
||||
"to" VARCHAR(255) NOT NULL,
|
||||
"subject" VARCHAR(255) NOT NULL,
|
||||
"templateVariables" JSON NOT NULL DEFAULT '{}',
|
||||
"cc" VARCHAR(255)[],
|
||||
"cci" VARCHAR(255)[],
|
||||
"sentAt" TIMESTAMP(3),
|
||||
"nbTrySend" INTEGER DEFAULT 0,
|
||||
"lastTrySendDate" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "email_pkey" PRIMARY KEY ("uid")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "email_uid_key" ON "email"("uid");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_contact_uid_fkey" FOREIGN KEY ("contact_uid") REFERENCES "contacts"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_roles_uid_fkey" FOREIGN KEY ("roles_uid") REFERENCES "roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_office_role_uid_fkey" FOREIGN KEY ("office_role_uid") REFERENCES "office_roles"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "users" ADD CONSTRAINT "users_office_uid_fkey" FOREIGN KEY ("office_uid") REFERENCES "offices"("uid") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -270,6 +270,22 @@ model Rules {
|
||||
@@map("rules")
|
||||
}
|
||||
|
||||
model Emails {
|
||||
uid String @id @unique @default(uuid())
|
||||
templateName String @db.VarChar(255)
|
||||
from String? @db.VarChar(255)
|
||||
to String @db.VarChar(255)
|
||||
subject String @db.VarChar(255)
|
||||
templateVariables Json @default("{}") @db.Json
|
||||
cc String[] @db.VarChar(255)
|
||||
cci String[] @db.VarChar(255)
|
||||
sentAt DateTime?
|
||||
nbTrySend Int? @default(0)
|
||||
lastTrySendDate DateTime?
|
||||
|
||||
@@map("email")
|
||||
}
|
||||
|
||||
enum ECivility {
|
||||
MALE
|
||||
FEMALE
|
||||
|
50
src/common/emails/EmailBuilder.ts
Normal file
50
src/common/emails/EmailBuilder.ts
Normal file
@ -0,0 +1,50 @@
|
||||
|
||||
import DocumentsService from "@Services/super-admin/DocumentsService/DocumentsService";
|
||||
import { Documents } from "@prisma/client";
|
||||
import { Document } from "le-coffre-resources/dist/SuperAdmin";
|
||||
import { Service } from "typedi";
|
||||
import { ETemplates } from "./Templates/EmailTemplates";
|
||||
import MailchimpService from "@Services/common/MailchimpService/MailchimpService";
|
||||
|
||||
@Service()
|
||||
export default class EmailBuilder {
|
||||
public constructor(private mailchimpService: MailchimpService ,private documentsService: DocumentsService){}
|
||||
|
||||
public async sendDocumentEmails(documentEntity: Documents){
|
||||
if(documentEntity.document_status !== "ASKED" && documentEntity.document_status !== "REFUSED") return;
|
||||
|
||||
const documentPrisma = await this.documentsService.getByUid(documentEntity.uid, { depositor: {include: {contact: true}}, folder:{include:{ office: true}} });
|
||||
if(!documentPrisma) throw new Error("Document not found");
|
||||
const document = Document.hydrate<Document>(documentPrisma);
|
||||
const to = document.depositor!.contact!.email;
|
||||
|
||||
const templateVariables = {
|
||||
civility: document.depositor!.contact!.civility,
|
||||
last_name: document.depositor!.contact!.last_name,
|
||||
office_name: document.folder!.office!.name,
|
||||
link: "http://localhost:3000"
|
||||
};
|
||||
|
||||
let templateName = ETemplates.DOCUMENT_ASKED;
|
||||
let subject = "Document Asked";
|
||||
if(documentEntity.document_status === "REFUSED"){
|
||||
templateName = ETemplates.DOCUMENT_REFUSED;
|
||||
subject = "Document Refused";
|
||||
}
|
||||
|
||||
this.mailchimpService.create({
|
||||
templateName,
|
||||
to,
|
||||
subject,
|
||||
templateVariables,
|
||||
uid: "",
|
||||
from: null,
|
||||
cc: [],
|
||||
cci: [],
|
||||
sentAt: null,
|
||||
nbTrySend: null,
|
||||
lastTrySendDate: null,
|
||||
});
|
||||
|
||||
}
|
||||
}
|
4
src/common/emails/Templates/EmailTemplates.ts
Normal file
4
src/common/emails/Templates/EmailTemplates.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const ETemplates = {
|
||||
DOCUMENT_ASKED: "DOCUMENT_ASKED",
|
||||
DOCUMENT_REFUSED: "DOCUMENT_REFUSED",
|
||||
};
|
75
src/common/repositories/EmailRepository.ts
Normal file
75
src/common/repositories/EmailRepository.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import Database from "@Common/databases/database";
|
||||
import BaseRepository from "@Repositories/BaseRepository";
|
||||
import { Service } from "typedi";
|
||||
import { Emails, Prisma } from "prisma/prisma-client";
|
||||
|
||||
@Service()
|
||||
export default class EmailRepository extends BaseRepository {
|
||||
constructor(private database: Database) {
|
||||
super();
|
||||
}
|
||||
protected get model() {
|
||||
return this.database.getClient().emails;
|
||||
}
|
||||
protected get instanceDb() {
|
||||
return this.database.getClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Find many emails
|
||||
*/
|
||||
public async findMany(query: Prisma.EmailsFindManyArgs) {
|
||||
query.take = Math.min(query.take || this.defaultFetchRows, this.maxFetchRows);
|
||||
return this.model.findMany(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Create an email
|
||||
*/
|
||||
public async create(email: Emails): Promise<Emails> {
|
||||
const createArgs: Prisma.EmailsCreateArgs = {
|
||||
data: {
|
||||
templateName: email.templateName,
|
||||
from: email.from,
|
||||
to: email.to,
|
||||
subject: email.subject,
|
||||
templateVariables: email.templateVariables!,
|
||||
cc: email.cc,
|
||||
cci: email.cci,
|
||||
},
|
||||
};
|
||||
return this.model.create(createArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : update given email
|
||||
*/
|
||||
public async update(uid: string, email: Emails): Promise<Emails> {
|
||||
const updateArgs: Prisma.EmailsUpdateArgs = {
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
data: {
|
||||
sentAt: email.sentAt,
|
||||
nbTrySend: email.nbTrySend,
|
||||
lastTrySendDate: email.lastTrySendDate,
|
||||
},
|
||||
};
|
||||
|
||||
return this.model.update(updateArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : find unique email
|
||||
*/
|
||||
public async findOneByUid(uid: string) {
|
||||
return this.model.findUnique({
|
||||
where: {
|
||||
uid: uid,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
14
src/entries/Cron.ts
Normal file
14
src/entries/Cron.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import "module-alias/register";
|
||||
import "reflect-metadata";
|
||||
import { Container } from "typedi";
|
||||
import CronService from "@Services/common/CronService/CronService";
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
if(process.env["MAILCHIMP_API_KEY"] === "ppd"){
|
||||
Container.get(CronService).sendMails();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
})();
|
24
src/services/common/CronService/CronService.ts
Normal file
24
src/services/common/CronService/CronService.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Service } from "typedi";
|
||||
import { CronJob } from "cron";
|
||||
import MailchimpService from "../MailchimpService/MailchimpService";
|
||||
|
||||
|
||||
@Service()
|
||||
export default class CronService {
|
||||
constructor(private mailchimpService: MailchimpService) {}
|
||||
|
||||
public async sendMails() {
|
||||
const cronJob = new CronJob("*/15 * * * * *", async () => {
|
||||
try {
|
||||
await this.mailchimpService.sendEmails();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
// Start job
|
||||
if (!cronJob.running) {
|
||||
cronJob.start();
|
||||
}
|
||||
}
|
||||
}
|
116
src/services/common/MailchimpService/MailchimpService.ts
Normal file
116
src/services/common/MailchimpService/MailchimpService.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import EmailRepository from "@Repositories/EmailRepository";
|
||||
import BaseService from "@Services/BaseService";
|
||||
import { Emails } from "@prisma/client";
|
||||
import { Service } from "typedi";
|
||||
import MailchimpClient from "@mailchimp/mailchimp_transactional";
|
||||
|
||||
@Service()
|
||||
export default class MailchimpService extends BaseService {
|
||||
// private static readonly mailchimp = new Mailchimp(process.env.MAILCHIMP_API_KEY);
|
||||
private static readonly from = "vincent.alamelle@smart-chain.fr";
|
||||
|
||||
constructor(private emailRepository: EmailRepository) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Get all emails
|
||||
* @throws {Error} If emails cannot be get
|
||||
*/
|
||||
public async get(query: any): Promise<Emails[]> {
|
||||
return this.emailRepository.findMany(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Create a new email
|
||||
* @throws {Error} If email cannot be created
|
||||
*/
|
||||
public async create(emailEntity: Emails): Promise<Emails> {
|
||||
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<Emails> {
|
||||
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<Emails | null> {
|
||||
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 = process.env["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],
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
@ -90,11 +90,11 @@
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowJs": true,
|
||||
"isolatedModules": true
|
||||
"isolatedModules": true,
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.tsx", "src/services/common/TestService",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
|
Loading…
x
Reference in New Issue
Block a user