diff --git a/package-lock.json b/package-lock.json index e57a031ed661282b5013e8031521738cadaf45f1..2fe18e317f551d7d1061d8b63ae8566743790f5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,11 +22,14 @@ "eslint-import-resolver-typescript": "^3.5.2", "fastify": "^4.9.2", "mailgun-js": "^0.22.0", + "moment": "^2.29.4", "mongoose": "^6.7.2", "multer": "^1.4.5-lts.1", + "node-fetch": "^2.6.9", "passport": "^0.6.0", "passport-jwt": "^4.0.0", "passport-local": "^1.0.0", + "pdf-lib": "^1.17.1", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0" @@ -3005,6 +3008,22 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@pdf-lib/standard-fonts": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz", + "integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==", + "dependencies": { + "pako": "^1.0.6" + } + }, + "node_modules/@pdf-lib/upng": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz", + "integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==", + "dependencies": { + "pako": "^1.0.10" + } + }, "node_modules/@pkgr/utils": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", @@ -10555,6 +10574,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, "node_modules/mongodb": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.11.0.tgz", @@ -10748,9 +10775,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -11119,6 +11146,11 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "node_modules/param-case": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", @@ -11307,6 +11339,22 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "node_modules/pdf-lib": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz", + "integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==", + "dependencies": { + "@pdf-lib/standard-fonts": "^1.0.0", + "@pdf-lib/upng": "^1.0.1", + "pako": "^1.0.11", + "tslib": "^1.11.1" + } + }, + "node_modules/pdf-lib/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/peberminta": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.8.0.tgz", @@ -16409,6 +16457,22 @@ } } }, + "@pdf-lib/standard-fonts": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz", + "integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==", + "requires": { + "pako": "^1.0.6" + } + }, + "@pdf-lib/upng": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz", + "integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==", + "requires": { + "pako": "^1.0.10" + } + }, "@pkgr/utils": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", @@ -22343,6 +22407,11 @@ "minimist": "^1.2.6" } }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, "mongodb": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.11.0.tgz", @@ -22504,9 +22573,9 @@ } }, "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", "requires": { "whatwg-url": "^5.0.0" } @@ -22766,6 +22835,11 @@ } } }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "param-case": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", @@ -22907,6 +22981,24 @@ "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, + "pdf-lib": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz", + "integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==", + "requires": { + "@pdf-lib/standard-fonts": "^1.0.0", + "@pdf-lib/upng": "^1.0.1", + "pako": "^1.0.11", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, "peberminta": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.8.0.tgz", diff --git a/package.json b/package.json index 4ef62fccd396ad6178c0a1effde2214f469d93e8..8767b4080704c7838b841752a8453941c46621fc 100644 --- a/package.json +++ b/package.json @@ -38,11 +38,14 @@ "eslint-import-resolver-typescript": "^3.5.2", "fastify": "^4.9.2", "mailgun-js": "^0.22.0", + "moment": "^2.29.4", "mongoose": "^6.7.2", "multer": "^1.4.5-lts.1", + "node-fetch": "^2.6.9", "passport": "^0.6.0", "passport-jwt": "^4.0.0", "passport-local": "^1.0.0", + "pdf-lib": "^1.17.1", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0" diff --git a/src/internships/internships.controller.ts b/src/internships/internships.controller.ts index 58a18914f0cee611d391c4452336ef293d970a64..28d69a2e88bc786c6295ff348d2bf841e8f15995 100644 --- a/src/internships/internships.controller.ts +++ b/src/internships/internships.controller.ts @@ -49,6 +49,11 @@ export class InternshipsController { return this._internshipsService.create(internshipDto); } + @Post("/:id/generate") + generatePDF(@Param() params: { id: string }): Promise<InternshipEntity | void> { + return this._internshipsService.generatePDF(params.id); + } + @Put(':studentId') update( @Param() params: { studentId: string }, @@ -109,4 +114,5 @@ export class InternshipsController { ): Promise<InternshipEntity | void> { return this._internshipsService.delete(params.studentId); } + } diff --git a/src/internships/internships.service.ts b/src/internships/internships.service.ts index 9d3af2080dcac5cd1119734812c3638d8a54f3f1..f153e715f6cce31de9a7c7eeb9585c9c890f9979 100644 --- a/src/internships/internships.service.ts +++ b/src/internships/internships.service.ts @@ -2,6 +2,16 @@ import { Injectable } from '@nestjs/common'; import { InternshipDao } from './dao/internships.dao'; import { CreateInternshipDto } from './dto/create-internship.dto'; import { InternshipEntity } from './entities/internship.entity'; +import { PDFDocument, StandardFonts, rgb, degrees } from 'pdf-lib'; +import { readFileSync, writeFileSync } from 'fs'; +import { join } from 'path'; +import { v4 } from 'uuid'; +import { timeStamp } from 'console'; +import { STATE_SECRETARY_ESTABLISHES_INTERNSHIP_AGREEMENT } from 'src/shared/InternshipState'; +import config from 'src/config'; + + + @Injectable() export class InternshipService { @@ -16,6 +26,291 @@ export class InternshipService { create = (internship: CreateInternshipDto): Promise<InternshipEntity> => this._internshipsDao.save(internship); + async generatePDF (id: string): Promise<InternshipEntity>{ + var information = await this.findOne(id).then( (data: InternshipEntity) => + data.information); + + //on recupere les informations de l'entreprise + var nomEntreprise = information.company.companyName; + + var adresse = information.company.address; + var adresseString = adresse.street + ', ' + adresse.postalCode + ', ' + + adresse.city + ', ' + adresse.country; + + var telOrganisme = 'NULL'; + + var melOrganisme = information.company.hrContactEmail; + + var reprsentePar = information.company.ceoName; + + var qualiteRepresentant = 'NULL'; + + var nomService = information.affectation.service; + + var lieuStage = information.company.address; + var lieuStageString = lieuStage.street + ', ' + lieuStage.postalCode + ', ' + lieuStage.city + ', ' + lieuStage.country; + + //on recupere les informations de l'etudiant + var etudiant = information.student; + + var nomEtudiant = etudiant.completeName; + + var dateNaissanceEtudiant = etudiant.birthDate.toDateString(); + + var adresseEtudiant = etudiant.address.street + ', ' + etudiant.address.postalCode + ', ' + etudiant.address.city + ', ' + etudiant.address.country; + + var telEtudiant = etudiant.phone; + + var melEtudiant = etudiant.email; + + //on recupere les informations du stage + var sujetStage = 'NULL'; + + var dateDebutStage = information.affectation.dateStart.toDateString(); + + var dateFinStage = information.affectation.dateEnd.toDateString(); + + const diffInMs = information.affectation.dateEnd.getTime() - information.affectation.dateStart.getTime(); + const diffInWeeks = diffInMs / 1000 / 60 / 60 / 24 / 7; + var dureeStageEnSemaines = Math.ceil(diffInWeeks); + + var dureeStageEnJours = dureeStageEnSemaines * 5; + + //on recupere les informations du tuteur du stage + var nomCompletTuteur = information.affectation.responsibleName; + + var fonctionTuteur = information.affectation.responsibleFunction; + + var telTuteur = information.affectation.responsiblePhone; + + var melTuteur = information.affectation.responsibleEmail; + + const filePath = join(__dirname, '..', '..', 'src', 'shared', 'conventions', 'convention_a_modifier.pdf'); + const existingPdfBytes = readFileSync(filePath); + + const pdfDoc = await PDFDocument.load(existingPdfBytes); + + // Embed the Helvetica font + const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica); + + // Get the first page of the document + const pages = pdfDoc.getPages(); + const firstPage = pages[0]; + + // on remplit les informations de l'entreprise + firstPage.drawText(nomEntreprise, { + x: 61, + y: 564, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(adresseString, { + x: 73, + y: 542, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(telOrganisme, { + x: 52, + y: 522, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(melOrganisme, { + x: 149, + y: 522, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(reprsentePar, { + x: 98, + y: 501, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(qualiteRepresentant, { + x: 130, + y: 480, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(nomService, { + x: 230, + y: 459, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(lieuStageString, { + x: 98, + y: 438, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + // on remplit les informations de l'entreprise + firstPage.drawText(nomEtudiant, { + x: 98, + y: 396, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(dateNaissanceEtudiant, { + x: 137, + y: 374, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(adresseEtudiant, { + x: 73, + y: 353, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(telEtudiant, { + x: 52, + y: 331, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(melEtudiant, { + x: 149, + y: 331, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(sujetStage, { + x: 102, + y: 231, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(dateDebutStage, { + x: 119, + y: 214, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(dateFinStage, { + x: 221, + y: 214, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(dureeStageEnSemaines.toString(), { + x: 200, + y: 197, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(dureeStageEnJours.toString(), { + x: 276, + y: 197, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(nomCompletTuteur, { + x: 380, + y: 131, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(fonctionTuteur, { + x: 360, + y: 110, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(telTuteur, { + x: 345, + y: 89, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + firstPage.drawText(melTuteur, { + x: 345, + y: 69, + size: 9, + font: helveticaFont, + color: rgb(0, 0, 0), + rotate: degrees(0), + }); + + + + + + // Serialize the PDFDocument to bytes (a Uint8Array) + const pdfBytes = await pdfDoc.save(); + const newFileName = v4(); + const newFilePath = join(__dirname, '..', '..', 'src', 'shared','conventions', newFileName + '.pdf'); + writeFileSync(newFilePath, pdfBytes); + const resourceURI = `${config.server.uri}:${config.server.port}/resources/agreements/${newFileName}.pdf`; + this._internshipsDao.findByStudentIdAndUpdateTracking(id,STATE_SECRETARY_ESTABLISHES_INTERNSHIP_AGREEMENT,resourceURI); + return null; + } + + update = ( studentId: string, internship: CreateInternshipDto, diff --git a/src/shared/conventions/a71ab39d-8cb0-4285-a43f-66149c183c4a.pdf b/src/shared/conventions/a71ab39d-8cb0-4285-a43f-66149c183c4a.pdf new file mode 100644 index 0000000000000000000000000000000000000000..329661723c858e96892caddbe358f3f823a4b62f Binary files /dev/null and b/src/shared/conventions/a71ab39d-8cb0-4285-a43f-66149c183c4a.pdf differ diff --git a/src/shared/conventions/convention_a_modifier.pdf b/src/shared/conventions/convention_a_modifier.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fecbaf098a2f0239a22db9b9dcc40619d45f63f9 Binary files /dev/null and b/src/shared/conventions/convention_a_modifier.pdf differ