diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..bbe647a --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,55 @@ +name: CICD for EBS in node js +on: + push: + branches: + - main +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x] + steps: + - uses: actions/checkout@v2 + - name: Cache node modules + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Node ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + - name: Installing NPM + run: npm install + - name: Building application + run: npm run build + + - name: Generate deployment package + run: zip -r deploy.zip * -x "**node_modules**" + - name: Get timestamp + uses: gerred/actions/current-time@master + id: current-time + - name: Run string replace + uses: frabert/replace-string-action@master + id: format-time + with: + pattern: '[:\.]+' + string: "${{ steps.current-time.outputs.time }}" + replace-with: "-" + flags: "g" + - name: Beanstalk Deploy for app + uses: einaregilsson/beanstalk-deploy@v20 + with: + aws_access_key: ${{secrets.ACCESS_KEY_ID}} + aws_secret_key: ${{secrets.SECRET_ACCESS_KEY}} + application_name: loamic-server + environment_name: Environment name + region: Region + version_label: "my-app-${{ steps.format-time.outputs.replaced }}" + deployment_package: deploy.zip + - name: Deployed! + run: echo App deployed to EBS diff --git a/dist/app/modules/pdftoemail/pdftomail.controller.js b/dist/app/modules/pdftoemail/pdftomail.controller.js index 7a4b0f8..70df603 100644 --- a/dist/app/modules/pdftoemail/pdftomail.controller.js +++ b/dist/app/modules/pdftoemail/pdftomail.controller.js @@ -13,11 +13,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PdfController = void 0; -const fs_1 = __importDefault(require("fs")); -const path_1 = __importDefault(require("path")); -const handlebars_1 = __importDefault(require("handlebars")); const aws_sdk_1 = __importDefault(require("aws-sdk")); -const html_pdf_1 = __importDefault(require("html-pdf")); +const pdf_lib_1 = require("pdf-lib"); // Import pdf-lib for creating PDFs const config_1 = __importDefault(require("../../config")); // Configure AWS aws_sdk_1.default.config.update({ @@ -37,65 +34,41 @@ const generateAndUploadPdf = (req, res) => __awaiter(void 0, void 0, void 0, fun message: "Title and content are required.", }); } - // HTML template as a string - const templateContent = ` - - - - Document - - -

{{title}}

-

{{content}}

- - - `; - // Compile the template - const template = handlebars_1.default.compile(templateContent); - // Generate HTML from the template and data - const html = template({ title: pdfData.title, content: pdfData.content }); - // Use html-pdf to generate the PDF - html_pdf_1.default.create(html).toFile((err, fileInfo) => { - if (err) { - console.error("Error generating PDF:", err); + // Create a new PDF document + const pdfDoc = yield pdf_lib_1.PDFDocument.create(); + const page = pdfDoc.addPage(); + // Draw title and content on the page + page.drawText(pdfData.title, { x: 50, y: 750 }); + page.drawText(pdfData.content, { x: 50, y: 700 }); + // Serialize the PDFDocument to bytes + const pdfBytes = yield pdfDoc.save(); + // Upload the PDF to AWS S3 + const uploadParams = { + Bucket: "loamic-media", + Key: `pdfs/${Date.now()}-output.pdf`, + Body: pdfBytes, + ContentType: "application/pdf", + }; + s3.upload(uploadParams, (uploadErr, data) => __awaiter(void 0, void 0, void 0, function* () { + if (uploadErr) { + console.error("Error uploading to S3:", uploadErr); return res.status(500).json({ success: false, - message: "Failed to generate PDF", - error: err, + message: "Failed to upload PDF to S3", + error: uploadErr, }); } - // Upload the PDF to AWS S3 - const fileContent = fs_1.default.readFileSync(fileInfo.filename); - const uploadParams = { + // Generate a pre-signed URL for the uploaded PDF + const signedUrl = yield s3.getSignedUrlPromise("getObject", { Bucket: "loamic-media", - Key: `pdfs/${Date.now()}-${path_1.default.basename(fileInfo.filename)}`, - Body: fileContent, - ContentType: "application/pdf", - }; - s3.upload(uploadParams, (uploadErr, data) => __awaiter(void 0, void 0, void 0, function* () { - if (uploadErr) { - console.error("Error uploading to S3:", uploadErr); - fs_1.default.unlinkSync(fileInfo.filename); // Ensure temporary file is deleted even on upload failure - return res.status(500).json({ - success: false, - message: "Failed to upload PDF to S3", - error: uploadErr, - }); - } - // Generate a pre-signed URL for the uploaded PDF - const signedUrl = yield s3.getSignedUrlPromise("getObject", { - Bucket: "loamic-media", - Key: uploadParams.Key, - Expires: 60 * 5, // Link expires in 5 minutes - }); - // Delete temporary file - fs_1.default.unlinkSync(fileInfo.filename); - res.json({ - downloadUrl: signedUrl, - message: "Email sent successfully", - }); - })); - }); + Key: uploadParams.Key, + Expires: 60 * 5, // Link expires in 5 minutes + }); + res.json({ + downloadUrl: signedUrl, + message: "PDF generated and uploaded successfully", + }); + })); } catch (error) { console.error("Unexpected error:", error); diff --git a/package-lock.json b/package-lock.json index fbe522c..3620f6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "html-pdf": "^3.0.1", "http-status": "^1.7.4", "mongoose": "^8.4.1", + "pdf-lib": "^1.17.1", "phantomjs-prebuilt": "^2.1.16", "puppeteer-core": "^10.4.0" }, @@ -37,6 +38,22 @@ "sparse-bitfield": "^3.0.3" } }, + "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/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -1980,6 +1997,11 @@ "node": ">=6" } }, + "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/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2009,6 +2031,17 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "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/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -2644,6 +2677,11 @@ "node": ">=14" } }, + "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/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/package.json b/package.json index aa55275..9b2e778 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "html-pdf": "^3.0.1", "http-status": "^1.7.4", "mongoose": "^8.4.1", + "pdf-lib": "^1.17.1", "phantomjs-prebuilt": "^2.1.16", "puppeteer-core": "^10.4.0" }, diff --git a/src/app/modules/pdftoemail/pdftomail.controller.ts b/src/app/modules/pdftoemail/pdftomail.controller.ts index d0ba4de..08b715a 100644 --- a/src/app/modules/pdftoemail/pdftomail.controller.ts +++ b/src/app/modules/pdftoemail/pdftomail.controller.ts @@ -3,7 +3,7 @@ import fs from "fs"; import path from "path"; import handlebars from "handlebars"; import AWS from "aws-sdk"; -import pdf from "html-pdf"; +import { PDFDocument } from "pdf-lib"; // Import pdf-lib for creating PDFs import config from "../../config"; // Configure AWS @@ -27,71 +27,45 @@ const generateAndUploadPdf = async (req: Request, res: Response) => { }); } - // HTML template as a string - const templateContent = ` - - - - Document - - -

{{title}}

-

{{content}}

- - - `; + // Create a new PDF document + const pdfDoc = await PDFDocument.create(); + const page = pdfDoc.addPage(); - // Compile the template - const template = handlebars.compile(templateContent); + // Draw title and content on the page + page.drawText(pdfData.title, { x: 50, y: 750 }); + page.drawText(pdfData.content, { x: 50, y: 700 }); - // Generate HTML from the template and data - const html = template({ title: pdfData.title, content: pdfData.content }); + // Serialize the PDFDocument to bytes + const pdfBytes = await pdfDoc.save(); - // Use html-pdf to generate the PDF - pdf.create(html).toFile((err, fileInfo) => { - if (err) { - console.error("Error generating PDF:", err); + // Upload the PDF to AWS S3 + const uploadParams = { + Bucket: "loamic-media", + Key: `pdfs/${Date.now()}-output.pdf`, + Body: pdfBytes, + ContentType: "application/pdf", + }; + + s3.upload(uploadParams, async (uploadErr: any, data: any) => { + if (uploadErr) { + console.error("Error uploading to S3:", uploadErr); return res.status(500).json({ success: false, - message: "Failed to generate PDF", - error: err, + message: "Failed to upload PDF to S3", + error: uploadErr, }); } - // Upload the PDF to AWS S3 - const fileContent = fs.readFileSync(fileInfo.filename); - const uploadParams = { + // Generate a pre-signed URL for the uploaded PDF + const signedUrl = await s3.getSignedUrlPromise("getObject", { Bucket: "loamic-media", - Key: `pdfs/${Date.now()}-${path.basename(fileInfo.filename)}`, - Body: fileContent, - ContentType: "application/pdf", - }; - - s3.upload(uploadParams, async (uploadErr: any, data: any) => { - if (uploadErr) { - console.error("Error uploading to S3:", uploadErr); - fs.unlinkSync(fileInfo.filename); // Ensure temporary file is deleted even on upload failure - return res.status(500).json({ - success: false, - message: "Failed to upload PDF to S3", - error: uploadErr, - }); - } - - // Generate a pre-signed URL for the uploaded PDF - const signedUrl = await s3.getSignedUrlPromise("getObject", { - Bucket: "loamic-media", - Key: uploadParams.Key, - Expires: 60 * 5, // Link expires in 5 minutes - }); - - // Delete temporary file - fs.unlinkSync(fileInfo.filename); + Key: uploadParams.Key, + Expires: 60 * 5, // Link expires in 5 minutes + }); - res.json({ - downloadUrl: signedUrl, - message: "Email sent successfully", - }); + res.json({ + downloadUrl: signedUrl, + message: "PDF generated and uploaded successfully", }); }); } catch (error) {