From 929ac81515b3b426ff06f1d6d913bab930421a92 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 09:51:52 +0100 Subject: [PATCH 01/28] Added cards api endpoint ref #14 --- src/controllers/PdfController.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/controllers/PdfController.ts b/src/controllers/PdfController.ts index affc7a4..49bb1a0 100644 --- a/src/controllers/PdfController.ts +++ b/src/controllers/PdfController.ts @@ -1,6 +1,7 @@ import { Body, JsonController, Post, QueryParam, Res } from 'routing-controllers'; import { OpenAPI } from 'routing-controllers-openapi'; import { Runner } from '../models/Runner'; +import { RunnerCard } from '../models/RunnerCard'; import { PdfCreator } from '../PdfCreator'; /** @@ -27,4 +28,19 @@ export class PdfController { res.setHeader('content-type', 'application/pdf'); return contracts; } + + @Post('/cards') + @OpenAPI({ description: "Generate runner card pdfs from runner card objects.
You can choose your prefered locale by passing the 'locale' query-param." }) + async generateCards(@Body({ validate: true, options: { limit: "500mb" } }) cards: RunnerCard | RunnerCard[], @Res() res: any, @QueryParam("locale") locale: string) { + if (!this.initialized) { + await this.pdf.init(); + this.initialized = true; + } + if (!Array.isArray(cards)) { + cards = [cards]; + } + const contracts = await this.pdf.generateRunnerCards(cards, locale); + res.setHeader('content-type', 'application/pdf'); + return contracts; + } } -- 2.47.2 From 8fc6c7176ee92f813db1e1d4b3e5ef1b2f4e1aef Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 09:55:29 +0100 Subject: [PATCH 02/28] Added basic card generation function ref #14 --- src/PdfCreator.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/PdfCreator.ts b/src/PdfCreator.ts index df60730..bc03f2d 100644 --- a/src/PdfCreator.ts +++ b/src/PdfCreator.ts @@ -9,6 +9,7 @@ import path from 'path'; import { PDFDocument } from 'pdf-lib'; import puppeteer from "puppeteer"; import { Runner } from './models/Runner'; +import { RunnerCard } from './models/RunnerCard'; import { RunnerGroup } from './models/RunnerGroup'; /** * This class is responsible for all things pdf creation. @@ -112,6 +113,30 @@ export class PdfCreator { return pdf } + /** + * Generate runner card pdfs. + * @param cards The runner cars you want to generate the cards for. + * @param locale The locale used for the cards (default:en) + */ + public async generateRunnerCards(cards: RunnerCard[], locale: string = "en"): Promise { + if (cards.length > 10) { + let pdf_promises = new Array>(); + let i, j; + for (i = 0, j = cards.length; i < j; i += 10) { + let chunk = cards.slice(i, i + 10); + pdf_promises.push(this.generateRunnerCards(chunk, locale)); + } + const pdfs = await Promise.all(pdf_promises); + return await this.mergePdfs(pdfs); + } + await i18next.changeLanguage(locale); + const template_source = fs.readFileSync(`${this.templateDir}/runner_card.html`, 'utf8'); + const template = Handlebars.compile(template_source); + const result = template({ cards }) + const pdf = await this.renderPdf(result, { format: "A4", landscape: false }); + return pdf + } + /** * Converts all images in html to base64. * Works with image files in the template directory or images from urls. -- 2.47.2 From d3a213ce3326aeb96d924e16a31fc87bf82eb5b3 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 10:07:58 +0100 Subject: [PATCH 03/28] Added basic logic to generate two-sided runnercards ref #14 --- src/templates/runner_card.html | 44 ++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/templates/runner_card.html diff --git a/src/templates/runner_card.html b/src/templates/runner_card.html new file mode 100644 index 0000000..fdf0dc9 --- /dev/null +++ b/src/templates/runner_card.html @@ -0,0 +1,44 @@ + + + + + Sponsoring contract + + + + + +
+
+ {{#each cards}} +
+

Front: {{this.code}}

+
+ {{/each}} +
+
+
+
+ {{#each cards}} +
+

Back: {{this.code}}

+
+ {{/each}} +
+
+ + + \ No newline at end of file -- 2.47.2 From b92a6f7b2b98fb0074d5a563d9918295e9ec0274 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 10:14:27 +0100 Subject: [PATCH 04/28] Added sizing for the real cards ref #14 --- src/templates/runner_card.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/templates/runner_card.html b/src/templates/runner_card.html index fdf0dc9..5f00ad6 100644 --- a/src/templates/runner_card.html +++ b/src/templates/runner_card.html @@ -11,12 +11,18 @@ position: relative; box-sizing: border-box; page-break-after: always; + padding: 1.2cm 2cm 1.2cm 2cm } body.A4 .sheet { width: 210mm; height: 296mm } + + .runnercard { + border: 1px solid; + height: 5.5cm; + } @@ -24,7 +30,7 @@
{{#each cards}} -
+

Front: {{this.code}}

{{/each}} @@ -33,7 +39,7 @@
{{#each cards}} -
+

Back: {{this.code}}

{{/each}} -- 2.47.2 From 016f746c7cec29ab391b3918c7589dea0cff9890 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 15:53:44 +0100 Subject: [PATCH 05/28] Styled front ref #14 --- src/PdfCreator.ts | 2 +- src/templates/runner_card.html | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/PdfCreator.ts b/src/PdfCreator.ts index bc03f2d..64286ad 100644 --- a/src/PdfCreator.ts +++ b/src/PdfCreator.ts @@ -132,7 +132,7 @@ export class PdfCreator { await i18next.changeLanguage(locale); const template_source = fs.readFileSync(`${this.templateDir}/runner_card.html`, 'utf8'); const template = Handlebars.compile(template_source); - const result = template({ cards }) + const result = template({ cards, eventname: "LfK! 2069" }) const pdf = await this.renderPdf(result, { format: "A4", landscape: false }); return pdf } diff --git a/src/templates/runner_card.html b/src/templates/runner_card.html index 5f00ad6..c1b0ef5 100644 --- a/src/templates/runner_card.html +++ b/src/templates/runner_card.html @@ -22,6 +22,7 @@ .runnercard { border: 1px solid; height: 5.5cm; + overflow: hidden; } @@ -31,7 +32,21 @@
{{#each cards}}
-

Front: {{this.code}}

+

{{../eventname}}

+

lauf-fuer-kaya.de - am 01.01.2021

+

Mit unterstützung von:

+
+
+ + +
+
+ + +
+
+

{{this.runner.lastname}}, {{this.runner.firstname}} {{this.runner.middlename}}

+

{{this.runner.group.name}}

{{/each}}
-- 2.47.2 From 68f46a45b5a51c8a8edafca852cb274af388fa76 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 15:57:09 +0100 Subject: [PATCH 06/28] Added **very** basic backside ref #14 --- src/templates/runner_card.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/templates/runner_card.html b/src/templates/runner_card.html index c1b0ef5..2a85229 100644 --- a/src/templates/runner_card.html +++ b/src/templates/runner_card.html @@ -55,7 +55,10 @@
{{#each cards}}
-

Back: {{this.code}}

+ + + +
{{/each}}
-- 2.47.2 From 7f58dd694b53152069c2095b2e18dd3a46cd04dd Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 16:14:10 +0100 Subject: [PATCH 07/28] Fixed double-sided printing ref #14 --- src/PdfCreator.ts | 21 ++++++++++++++++++++- src/templates/runner_card.html | 7 +++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/PdfCreator.ts b/src/PdfCreator.ts index 64286ad..707e003 100644 --- a/src/PdfCreator.ts +++ b/src/PdfCreator.ts @@ -129,10 +129,11 @@ export class PdfCreator { const pdfs = await Promise.all(pdf_promises); return await this.mergePdfs(pdfs); } + const cards_swapped = this.swapArrayPairs(cards); await i18next.changeLanguage(locale); const template_source = fs.readFileSync(`${this.templateDir}/runner_card.html`, 'utf8'); const template = Handlebars.compile(template_source); - const result = template({ cards, eventname: "LfK! 2069" }) + const result = template({ cards, cards_swapped, eventname: "LfK! 2069" }) const pdf = await this.renderPdf(result, { format: "A4", landscape: false }); return pdf } @@ -220,4 +221,22 @@ export class PdfCreator { runner.group = group; return runner; } + + /** + * Swaps pairs (0/1, 2/3, ...) of elements in an array recursively. + * If the last element has no partner it inserts an empty element at the end and swaps the two + * This is needed to generate pdfs with front- and backside that get printet on one paper. + * @param array The array which's pairs shall get switched. + * @returns Array with swapped pairs, + */ + private swapArrayPairs(array): Array { + if (array.length == 1) { + return [null, array[0]]; + } + if (array.length == 0) { + return null; + } + + return [array[1], array[0]].concat(this.swapArrayPairs(array.slice(2))); + } } \ No newline at end of file diff --git a/src/templates/runner_card.html b/src/templates/runner_card.html index 2a85229..987194e 100644 --- a/src/templates/runner_card.html +++ b/src/templates/runner_card.html @@ -46,19 +46,18 @@

{{this.runner.lastname}}, {{this.runner.firstname}} {{this.runner.middlename}}

-

{{this.runner.group.name}}

+

{{this.runner.group.name}} {{this.id}}

{{/each}}
- {{#each cards}} + {{#each cards_swapped}}
+

{{this.id}}

- -
{{/each}}
-- 2.47.2 From e3a45a61ac3b2d691c2f75d36155896b7ed301d8 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 17:32:02 +0100 Subject: [PATCH 08/28] Implemented first experimental speedtest ref #19 --- src/tests/speedtest.ts | 45 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/tests/speedtest.ts diff --git a/src/tests/speedtest.ts b/src/tests/speedtest.ts new file mode 100644 index 0000000..881340d --- /dev/null +++ b/src/tests/speedtest.ts @@ -0,0 +1,45 @@ +import axios from "axios" +import { Runner } from '../models/Runner' + +const baseurl = "http://localhost:4010" + +axios.interceptors.request.use((config) => { + config.headers['request-startTime'] = process.hrtime() + return config +}) + +axios.interceptors.response.use((response) => { + const start = response.config.headers['request-startTime'] + const end = process.hrtime(start) + const milliseconds = Math.round((end[0] * 1000) + (end[1] / 1000000)) + response.headers['request-duration'] = milliseconds + return response +}) + +async function postContracts(runners: Runner[]): Promise { + const res = await axios.post(`${baseurl}/contracts`, runners); + return new Measurement("contract", runners.length, parseInt(res.headers['request-duration'])) +} + +async function main() { + console.log((await axios.get("http://localhost:4010/version")).data) + console.log((await postContracts([])).toString()) +} + +main(); + +class Measurement { + public type: string; + public inputcount: number; + public responsetime: number; + + constructor(type: string, input: number, time: number) { + this.type = type; + this.inputcount = input; + this.responsetime = time; + } + + public toString(): string { + return `It took ${this.responsetime}ms to generate ${this.inputcount} pdfs for the type ${this.type}.` + } +} \ No newline at end of file -- 2.47.2 From 08944460854c78cd4368cf178b022c31b624c8d9 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 18:08:01 +0100 Subject: [PATCH 09/28] Implemented runner generation using fakerjs ref #19 --- package.json | 1 + src/tests/speedtest.ts | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 90132ef..65fb6ac 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@types/node": "^14.14.22", "@types/puppeteer": "^5.4.3", "cp-cli": "^2.0.0", + "faker": "^5.3.1", "nodemon": "^2.0.7", "release-it": "^14.2.2", "rimraf": "^3.0.2", diff --git a/src/tests/speedtest.ts b/src/tests/speedtest.ts index 881340d..1c67e8a 100644 --- a/src/tests/speedtest.ts +++ b/src/tests/speedtest.ts @@ -1,5 +1,7 @@ import axios from "axios" +import faker from "faker" import { Runner } from '../models/Runner' +import { RunnerGroup } from '../models/RunnerGroup' const baseurl = "http://localhost:4010" @@ -16,6 +18,21 @@ axios.interceptors.response.use((response) => { return response }) +function generateRunners(amount: number): Runner[] { + let runners: Runner[] = new Array(); + let group = new RunnerGroup(); + let runner = new Runner(); + for (var i = 0; i < amount; i++) { + group.name = faker.company.bsBuzz(); + group.id = Math.floor(Math.random() * (9999999 - 1) + 1); + runner.firstname = faker.name.firstName(); + runner.lastname = faker.name.lastName(); + runner.id = Math.floor(Math.random() * (9999999 - 1) + 1); + runners.push(runner); + } + return runners; +} + async function postContracts(runners: Runner[]): Promise { const res = await axios.post(`${baseurl}/contracts`, runners); return new Measurement("contract", runners.length, parseInt(res.headers['request-duration'])) @@ -23,7 +40,7 @@ async function postContracts(runners: Runner[]): Promise { async function main() { console.log((await axios.get("http://localhost:4010/version")).data) - console.log((await postContracts([])).toString()) + console.log((await postContracts(generateRunners(100))).toString()); } main(); -- 2.47.2 From 0d27916188114fa41e666170135de2b714ff113a Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Mon, 8 Feb 2021 18:12:35 +0100 Subject: [PATCH 10/28] tmp --- src/tests/speedtest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/speedtest.ts b/src/tests/speedtest.ts index 1c67e8a..d502b72 100644 --- a/src/tests/speedtest.ts +++ b/src/tests/speedtest.ts @@ -39,8 +39,8 @@ async function postContracts(runners: Runner[]): Promise { } async function main() { - console.log((await axios.get("http://localhost:4010/version")).data) - console.log((await postContracts(generateRunners(100))).toString()); + console.log(`version ${(await axios.get("http://localhost:4010/version")).data.version}`) + console.log("Starting tests"); } main(); -- 2.47.2 From a1b0a1918db552eb385fedcbaa576ad493a1d605 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 17:54:13 +0100 Subject: [PATCH 11/28] Implemented basic contracts tests in various sizes ref #19 --- src/tests/speedtest.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tests/speedtest.ts b/src/tests/speedtest.ts index d502b72..5448215 100644 --- a/src/tests/speedtest.ts +++ b/src/tests/speedtest.ts @@ -39,8 +39,12 @@ async function postContracts(runners: Runner[]): Promise { } async function main() { + const sizes = [0, 1, 10, 50, 100, 200, 500, 1000] console.log(`version ${(await axios.get("http://localhost:4010/version")).data.version}`) console.log("Starting tests"); + for (let size of sizes) { + console.log((await (await postContracts(generateRunners(size))).toString())) + } } main(); -- 2.47.2 From 75b8b281b87d9b173093f16beae12d707ec05052 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 18:02:43 +0100 Subject: [PATCH 12/28] Added speedtest script to package ref #19 --- package.json | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a60e379..4d84162 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "build": "rimraf ./dist && tsc && cp-cli ./src/templates ./dist/templates && cp-cli ./src/locales ./dist/locales", "licenses:export": "license-exporter --markdown", "release": "release-it --only-version", - "translations:sort": "node sort_translations.js" + "translations:sort": "node sort_translations.js", + "test:speed": "start-server-and-test dev http://localhost:4010/docs/openapi.json test:speed:run", + "test:speed:run": "ts-node src/tests/speedtest.ts" }, "repository": { "type": "git", @@ -70,6 +72,7 @@ "nodemon": "^2.0.7", "release-it": "^14.2.2", "rimraf": "^3.0.2", + "start-server-and-test": "^1.12.0", "ts-node": "^9.1.1", "typescript": "^4.1.3" }, @@ -86,4 +89,4 @@ "publish": false } } -} +} \ No newline at end of file -- 2.47.2 From aefe5493b06c04cc2b20029e1f7fc5f15ec9c04e Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 18:43:15 +0100 Subject: [PATCH 13/28] Beautified output a bit ref #19 --- src/tests/speedtest.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/tests/speedtest.ts b/src/tests/speedtest.ts index 5448215..c016204 100644 --- a/src/tests/speedtest.ts +++ b/src/tests/speedtest.ts @@ -38,13 +38,26 @@ async function postContracts(runners: Runner[]): Promise { return new Measurement("contract", runners.length, parseInt(res.headers['request-duration'])) } +async function testContracts(sizes): Promise { + let measurements = new Array(); + console.log("#### Testing contracts ####"); + + for (let size of sizes) { + const m = await postContracts(generateRunners(size)); + console.log(m.toString()); + measurements.push(m); + } + return measurements; +} + async function main() { const sizes = [0, 1, 10, 50, 100, 200, 500, 1000] - console.log(`version ${(await axios.get("http://localhost:4010/version")).data.version}`) - console.log("Starting tests"); - for (let size of sizes) { - console.log((await (await postContracts(generateRunners(size))).toString())) - } + console.log("########### Speedtest ###########"); + console.log(`Document server version (according to the api): ${(await axios.get("http://localhost:4010/version")).data.version}`); + console.log("####### Running tests #######"); + const contractResults = await testContracts(sizes); + console.log("####### Results #######"); + console.table(contractResults); } main(); -- 2.47.2 From 5c075bce8b94ff4482448c3cd56bdc28cbe0a7d9 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 19:15:08 +0100 Subject: [PATCH 14/28] Added barcode generatin ref #19 --- src/PdfCreator.ts | 5 +++-- src/asyncHelpers.ts | 3 ++- src/templates/runner_card.html | 13 +++++++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/PdfCreator.ts b/src/PdfCreator.ts index 025e7f8..ce3d430 100644 --- a/src/PdfCreator.ts +++ b/src/PdfCreator.ts @@ -123,7 +123,7 @@ export class PdfCreator { * @param cards The runner cars you want to generate the cards for. * @param locale The locale used for the cards (default:en) */ - public async generateRunnerCards(cards: RunnerCard[], locale: string = "en"): Promise { + public async generateRunnerCards(cards: RunnerCard[], locale: string = "en", codeformat: string = config.codeformat): Promise { if (cards.length > 10) { let pdf_promises = new Array>(); let i, j; @@ -138,7 +138,8 @@ export class PdfCreator { await i18next.changeLanguage(locale); const template_source = fs.readFileSync(`${this.templateDir}/runner_card.html`, 'utf8'); const template = Handlebars.compile(template_source); - const result = template({ cards, cards_swapped, eventname: "LfK! 2069" }) + let result = template({ cards, cards_swapped, eventname: "LfK! 2069", codeformat: "qrcode" }) + result = await awaitAsyncHandlebarHelpers(result); const pdf = await this.renderPdf(result, { format: "A4", landscape: false }); return pdf } diff --git a/src/asyncHelpers.ts b/src/asyncHelpers.ts index 881bbe6..53a9f16 100644 --- a/src/asyncHelpers.ts +++ b/src/asyncHelpers.ts @@ -3,6 +3,7 @@ import bwipjs from "bwip-js"; export const asyncHelpers = new AsyncHelpers(); async function generateBarcode(str, options, emtpy, cb) { + if (str == null) { cb(null, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg=="); return; } let res = await generateBase64Barcode(options.toString(), str.toString()); cb(null, res); } @@ -18,7 +19,7 @@ export async function generateBase64Barcode(type: string, content: string): Prom height: 10, width: 10, includetext: true, - textxalign: 'center', + textxalign: 'center' } if (type != "qrcode") { delete options.width; diff --git a/src/templates/runner_card.html b/src/templates/runner_card.html index 987194e..09f6eb8 100644 --- a/src/templates/runner_card.html +++ b/src/templates/runner_card.html @@ -38,15 +38,17 @@
- +
- +

{{this.runner.lastname}}, {{this.runner.firstname}} {{this.runner.middlename}}

-

{{this.runner.group.name}} {{this.id}}

+

{{this.runner.group.name}}

{{/each}}
@@ -55,9 +57,12 @@
{{#each cards_swapped}}
-

{{this.id}}

+ +
{{/each}}
-- 2.47.2 From 149bf1849db20b863ec998a72c77559ec401bc32 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 18:21:49 +0000 Subject: [PATCH 15/28] =?UTF-8?q?=F0=9F=A7=BENew=20changelog=20file=20vers?= =?UTF-8?q?ion=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 682f51e..b3704ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,30 +2,38 @@ All notable changes to this project will be documented in this file. Dates are displayed in UTC. -#### [v0.1.3](https://git.odit.services/lfk/document-server/compare/v0.1.2...v0.1.3) +#### [v0.1.3](https://git.odit.services/lfk/document-server/compare/v0.1.3...v0.1.3) -- Merge pull request 'Barcode generation feature/13-barcode_generation' (#21) from feature/13-barcode_generation into dev [`ff36b48`](https://git.odit.services/lfk/document-server/commit/ff36b4871f2d696c0b86883d529365ee8f1c6132) -- 🚀Bumped version to v0.1.3 [`6a14232`](https://git.odit.services/lfk/document-server/commit/6a142328898d5b89fa11eaf033372971d1093b0c) -- 🧾New changelog file version [CI SKIP] [skip ci] [`ad9a8a4`](https://git.odit.services/lfk/document-server/commit/ad9a8a4fe0649d48db924771be8ecb4cbf5c162a) +- Merge pull request 'Alpha Release 0.2.0 - The barcode release' (#22) from dev into main [`b952ac4`](https://git.odit.services/lfk/document-server/commit/b952ac4d728952e1fb6d26b0929e3f946748b85b) - Implemented async barcode generation using async helpers [`edc846a`](https://git.odit.services/lfk/document-server/commit/edc846ab05319a4e60422625678f204bc145884c) +- 📖New license file version [CI SKIP] [skip ci] [`fea0b1d`](https://git.odit.services/lfk/document-server/commit/fea0b1dc0582d2906bad22f2ff5e5aad90a1c885) - Reworked template layout for barcode [`1c06689`](https://git.odit.services/lfk/document-server/commit/1c066898009883f510fa204c66800e5f6228a15d) -- Added basic barcode generation [`8072d0b`](https://git.odit.services/lfk/document-server/commit/8072d0b1940ef6f316ce78dcbcb9e5af5bab04e7) -- 🧾New changelog file version [CI SKIP] [skip ci] [`03f63e3`](https://git.odit.services/lfk/document-server/commit/03f63e3777381a4475910e6fa4a3986f87b73f39) -- Merge pull request 'Alpha Release 0.1.3 - More env vars' (#20) from dev into main [`ecd02a1`](https://git.odit.services/lfk/document-server/commit/ecd02a1af7431d0bf615c4ec064f64e023946e49) +- 🧾New changelog file version [CI SKIP] [skip ci] [`7122fe7`](https://git.odit.services/lfk/document-server/commit/7122fe7dbe3fae64806492636255147078eb03c8) +- Merge pull request 'Barcode generation feature/13-barcode_generation' (#21) from feature/13-barcode_generation into dev [`ff36b48`](https://git.odit.services/lfk/document-server/commit/ff36b4871f2d696c0b86883d529365ee8f1c6132) - Now with working code scaleing [`4b79b29`](https://git.odit.services/lfk/document-server/commit/4b79b29ee6319559c9d68ddb11f831d25f12b3da) +- Added basic barcode generation [`8072d0b`](https://git.odit.services/lfk/document-server/commit/8072d0b1940ef6f316ce78dcbcb9e5af5bab04e7) - Now loading barcode format from env with overwrite via query param [`9a7c1d6`](https://git.odit.services/lfk/document-server/commit/9a7c1d64fdbdadbd104739133a87773e4d2bca01) - Added fallback error image [`5023457`](https://git.odit.services/lfk/document-server/commit/502345782f26895ccf3089d15c3817709b62dfcc) - First part of the handlebars barcode generation [`a35f8cf`](https://git.odit.services/lfk/document-server/commit/a35f8cfd3aa94923968fd77425c074844d28ec0d) -- 🧾New changelog file version [CI SKIP] [skip ci] [`b6296b8`](https://git.odit.services/lfk/document-server/commit/b6296b8d97cda943dfb5e11bc9dfbb2f363f5b81) - Added todo [`75d2ac3`](https://git.odit.services/lfk/document-server/commit/75d2ac3c5f80f8440b6d48c33b15ef17565559b3) - Removed promise [`e1ec193`](https://git.odit.services/lfk/document-server/commit/e1ec193a4ff1cd618da90f5f2d029ec848a6f669) -- Added new env vars to config [`3bb322e`](https://git.odit.services/lfk/document-server/commit/3bb322ede5db15a147c0d7a8db2a68ccb7fa2112) -- Now loading interpolation vars from config/env [`b4ebae2`](https://git.odit.services/lfk/document-server/commit/b4ebae283b472b2f0c6e28caed49b30edb119585) +- 🧾New changelog file version [CI SKIP] [skip ci] [`03f63e3`](https://git.odit.services/lfk/document-server/commit/03f63e3777381a4475910e6fa4a3986f87b73f39) - Fixed broken mime-type [`4187a8e`](https://git.odit.services/lfk/document-server/commit/4187a8e82015495c0e0362e957e236ed6935a908) -- Merge pull request 'Load more stuff from env feature/16-env_vars' (#17) from feature/16-env_vars into dev [`bc4d16e`](https://git.odit.services/lfk/document-server/commit/bc4d16e6f8959ed35d7e87647de84584cdfddd7b) -- Added new env vars to readme [`b77bb3a`](https://git.odit.services/lfk/document-server/commit/b77bb3ad9dba9d73c2c81215ba57936192155a9a) - Switched to using the current runner's id as the barcode text [`3e2b011`](https://git.odit.services/lfk/document-server/commit/3e2b011d2887d261fb9c36820982095d6dd6d847) - Added barcode field to template [`27d1d69`](https://git.odit.services/lfk/document-server/commit/27d1d69360c8513079abcfe3a6fc2a50309a2b61) + +#### [v0.1.3](https://git.odit.services/lfk/document-server/compare/v0.1.2...v0.1.3) + +> 9 February 2021 + +- Merge pull request 'Alpha Release 0.1.3 - More env vars' (#20) from dev into main [`ecd02a1`](https://git.odit.services/lfk/document-server/commit/ecd02a1af7431d0bf615c4ec064f64e023946e49) +- 🚀Bumped version to v0.1.3 [`6a14232`](https://git.odit.services/lfk/document-server/commit/6a142328898d5b89fa11eaf033372971d1093b0c) +- 🧾New changelog file version [CI SKIP] [skip ci] [`ad9a8a4`](https://git.odit.services/lfk/document-server/commit/ad9a8a4fe0649d48db924771be8ecb4cbf5c162a) +- 🧾New changelog file version [CI SKIP] [skip ci] [`b6296b8`](https://git.odit.services/lfk/document-server/commit/b6296b8d97cda943dfb5e11bc9dfbb2f363f5b81) +- Merge pull request 'Load more stuff from env feature/16-env_vars' (#17) from feature/16-env_vars into dev [`bc4d16e`](https://git.odit.services/lfk/document-server/commit/bc4d16e6f8959ed35d7e87647de84584cdfddd7b) +- Added new env vars to config [`3bb322e`](https://git.odit.services/lfk/document-server/commit/3bb322ede5db15a147c0d7a8db2a68ccb7fa2112) +- Added new env vars to readme [`b77bb3a`](https://git.odit.services/lfk/document-server/commit/b77bb3ad9dba9d73c2c81215ba57936192155a9a) +- Now loading interpolation vars from config/env [`b4ebae2`](https://git.odit.services/lfk/document-server/commit/b4ebae283b472b2f0c6e28caed49b30edb119585) - 🧾New changelog file version [CI SKIP] [skip ci] [`a306009`](https://git.odit.services/lfk/document-server/commit/a30600943d01116b99e946cb705a16d0372b5095) #### [v0.1.2](https://git.odit.services/lfk/document-server/compare/v0.1.1...v0.1.2) -- 2.47.2 From 96204d809e852c1bcea808a9c8f5ca0f8475c87f Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 18:24:56 +0000 Subject: [PATCH 16/28] =?UTF-8?q?=F0=9F=A7=BENew=20changelog=20file=20vers?= =?UTF-8?q?ion=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3704ad..53e6a92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,20 @@ All notable changes to this project will be documented in this file. Dates are displayed in UTC. -#### [v0.1.3](https://git.odit.services/lfk/document-server/compare/v0.1.3...v0.1.3) +#### [v0.1.3](https://git.odit.services/lfk/document-server/compare/v0.2.0...v0.1.3) + +- Merge pull request 'Added speedtest feature/19-speed_test' (#23) from feature/19-speed_test into dev [`7ac8edb`](https://git.odit.services/lfk/document-server/commit/7ac8edb5cf4b7317a703faa32ded482a8c2b9b91) +- Implemented first experimental speedtest [`e3a45a6`](https://git.odit.services/lfk/document-server/commit/e3a45a61ac3b2d691c2f75d36155896b7ed301d8) +- 🧾New changelog file version [CI SKIP] [skip ci] [`149bf18`](https://git.odit.services/lfk/document-server/commit/149bf1849db20b863ec998a72c77559ec401bc32) +- Beautified output a bit [`aefe549`](https://git.odit.services/lfk/document-server/commit/aefe5493b06c04cc2b20029e1f7fc5f15ec9c04e) +- Implemented runner generation using fakerjs [`0894446`](https://git.odit.services/lfk/document-server/commit/08944460854c78cd4368cf178b022c31b624c8d9) +- Added speedtest script to package [`75b8b28`](https://git.odit.services/lfk/document-server/commit/75b8b281b87d9b173093f16beae12d707ec05052) +- Implemented basic contracts tests in various sizes [`a1b0a19`](https://git.odit.services/lfk/document-server/commit/a1b0a1918db552eb385fedcbaa576ad493a1d605) +- tmp [`0d27916`](https://git.odit.services/lfk/document-server/commit/0d27916188114fa41e666170135de2b714ff113a) + +#### [v0.2.0](https://git.odit.services/lfk/document-server/compare/v0.1.3...v0.2.0) + +> 9 February 2021 - Merge pull request 'Alpha Release 0.2.0 - The barcode release' (#22) from dev into main [`b952ac4`](https://git.odit.services/lfk/document-server/commit/b952ac4d728952e1fb6d26b0929e3f946748b85b) - Implemented async barcode generation using async helpers [`edc846a`](https://git.odit.services/lfk/document-server/commit/edc846ab05319a4e60422625678f204bc145884c) -- 2.47.2 From dbccbf68f4e22470b4fc93c894527cc78973e324 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 18:26:21 +0000 Subject: [PATCH 17/28] =?UTF-8?q?=F0=9F=93=96New=20license=20file=20versio?= =?UTF-8?q?n=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- licenses.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/licenses.md b/licenses.md index ed35937..00f9823 100644 --- a/licenses.md +++ b/licenses.md @@ -877,6 +877,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# faker +**Author**: undefined +**Repo**: [object Object] +**License**: MIT +**Description**: Generate massive amounts of fake contextual data +## License Text + + # nodemon **Author**: [object Object] **Repo**: [object Object] @@ -958,6 +966,14 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# start-server-and-test +**Author**: Gleb Bahmutov +**Repo**: [object Object] +**License**: MIT +**Description**: Starts server, waits for URL, then runs test command; when the tests end, shuts down server +## License Text + + # ts-node **Author**: [object Object] **Repo**: [object Object] -- 2.47.2 From 68572b194eb740238be8101efed6fdb2a207f65b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 19:37:32 +0100 Subject: [PATCH 18/28] Added card generation speed tests (part 1) ref #14 --- src/tests/speedtest.ts | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/tests/speedtest.ts b/src/tests/speedtest.ts index c016204..aefb2a1 100644 --- a/src/tests/speedtest.ts +++ b/src/tests/speedtest.ts @@ -1,6 +1,7 @@ import axios from "axios" import faker from "faker" import { Runner } from '../models/Runner' +import { RunnerCard } from '../models/RunnerCard' import { RunnerGroup } from '../models/RunnerGroup' const baseurl = "http://localhost:4010" @@ -33,11 +34,45 @@ function generateRunners(amount: number): Runner[] { return runners; } +function generateCards(amount: number): RunnerCard[] { + let cards: RunnerCard[] = new Array(); + let card = new RunnerCard(); + for (let runner of generateRunners(amount)) { + card.id = runner.id; + card.code = idToEan13(card.id); + card.runner = runner; + cards.push(card); + } + return cards; +} + +function idToEan13(id): string { + const multiply = [1, 3]; + id = id.toString(); + + if (id.length > 12) { + throw new Error("id too long"); + } + while (id.length < 12) { id = '0' + id; } + + let total = 0; + this.id.split('').forEach((letter, index) => { + total += parseInt(letter, 10) * multiply[index % 2]; + }); + const checkSum = (Math.ceil(total / 10) * 10) - total; + return this.id + checkSum.toString(); +} + async function postContracts(runners: Runner[]): Promise { const res = await axios.post(`${baseurl}/contracts`, runners); return new Measurement("contract", runners.length, parseInt(res.headers['request-duration'])) } +async function postCards(cards: RunnerCard[]): Promise { + const res = await axios.post(`${baseurl}/cards`, cards); + return new Measurement("card", cards.length, parseInt(res.headers['request-duration'])) +} + async function testContracts(sizes): Promise { let measurements = new Array(); console.log("#### Testing contracts ####"); @@ -50,14 +85,28 @@ async function testContracts(sizes): Promise { return measurements; } +async function testCards(sizes): Promise { + let measurements = new Array(); + console.log("#### Testing Cards ####"); + + for (let size of sizes) { + const m = await postCards(generateCards(size)); + console.log(m.toString()); + measurements.push(m); + } + return measurements; +} + async function main() { const sizes = [0, 1, 10, 50, 100, 200, 500, 1000] console.log("########### Speedtest ###########"); console.log(`Document server version (according to the api): ${(await axios.get("http://localhost:4010/version")).data.version}`); console.log("####### Running tests #######"); const contractResults = await testContracts(sizes); + const cardResults = await testCards(sizes); console.log("####### Results #######"); console.table(contractResults); + console.table(cardResults); } main(); -- 2.47.2 From 491cdb8d71a80ea196d16334c0c80b8f7cc859c5 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 19:37:46 +0100 Subject: [PATCH 19/28] =?UTF-8?q?=F0=9F=9A=80Bumped=20version=20to=20v0.2.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +- src/PdfCreator.ts | 410 +++++++++++++++---------------- src/asyncHelpers.ts | 86 +++---- src/controllers/PdfController.ts | 60 ++--- src/tests/speedtest.ts | 156 ++++++------ 5 files changed, 358 insertions(+), 358 deletions(-) diff --git a/package.json b/package.json index 4d84162..e2fa293 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@odit/lfk-document-server", - "version": "0.1.3", + "version": "0.2.0", "description": "The document generation server for the LfK! runner system. This generates certificates, sponsoring aggreements and more", "main": "src/app.ts", "scripts": { @@ -89,4 +89,4 @@ "publish": false } } -} \ No newline at end of file +} diff --git a/src/PdfCreator.ts b/src/PdfCreator.ts index b824ac4..6b9c6b6 100644 --- a/src/PdfCreator.ts +++ b/src/PdfCreator.ts @@ -1,206 +1,206 @@ -import axios from 'axios'; -import cheerio from "cheerio"; -import fs from "fs"; -import Handlebars from 'handlebars'; -import i18next from "i18next"; -import Backend from 'i18next-fs-backend'; -import mime from "mime-types"; -import path from 'path'; -import { PDFDocument } from 'pdf-lib'; -import puppeteer from "puppeteer"; -import { awaitAsyncHandlebarHelpers, helpers } from './asyncHelpers'; -import { config } from './config'; -import { Runner } from './models/Runner'; -import { RunnerGroup } from './models/RunnerGroup'; - -/** - * This class is responsible for all things pdf creation. - * This uses the html templates from src/templates. - */ -export class PdfCreator { - private templateDir = path.join(__dirname, '/templates'); - private browser; - private static interpolations = { eventname: config.eventname, sponsoring_receipt_minimum_amount: config.sponsoring_receipt_minimum_amount, currency_symbol: config.currency_symbol } - - /** - * Main constructor. - * Initializes i18n(ext), Handlebars and puppeteer. - */ - constructor() { - this.init(); - } - - /** - * Main constructor. - * Initializes i18n(ext), Handlebars and puppeteer. - */ - public async init() { - const minimal_args = [ - '--autoplay-policy=user-gesture-required', - '--disable-background-networking', - '--disable-background-timer-throttling', - '--disable-backgrounding-occluded-windows', - '--disable-breakpad', - '--disable-client-side-phishing-detection', - '--disable-component-update', - '--disable-default-apps', - '--disable-dev-shm-usage', - '--disable-domain-reliability', - '--disable-extensions', - '--disable-features=AudioServiceOutOfProcess', - '--disable-hang-monitor', - '--disable-ipc-flooding-protection', - '--disable-notifications', - '--disable-offer-store-unmasked-wallet-cards', - '--disable-popup-blocking', - '--disable-print-preview', - '--disable-prompt-on-repost', - '--disable-renderer-backgrounding', - '--disable-speech-api', - '--disable-sync', - '--hide-scrollbars', - '--ignore-gpu-blacklist', - '--metrics-recording-only', - '--mute-audio', - '--no-default-browser-check', - '--no-first-run', - '--no-pings', - '--no-zygote', - '--password-store=basic', - '--use-gl=swiftshader', - '--no-sandbox' - ]; - await i18next - .use(Backend) - .init({ - fallbackLng: 'en', - lng: 'en', - backend: { - loadPath: path.join(__dirname, '/locales/{{lng}}.json') - } - }); - - await Handlebars.registerHelper(helpers); - await Handlebars.registerHelper('__', - function (str) { - return i18next.t(str, PdfCreator.interpolations).toString(); - } - ); - this.browser = await puppeteer.launch({ headless: true, args: minimal_args }); - } - - /** - * Generate sponsoring contract pdfs. - * @param runner The runner you want to generate the contracts for. - * @param locale The locale used for the contracts (default:en) - */ - public async generateSponsoringContract(runners: Runner[], locale: string = "en", codeformat: string = config.codeformat): Promise { - if (runners.length == 1 && Object.keys(runners[0]).length == 0) { - runners[0] = this.generateEmptyRunner(); - } - if (runners.length > 50) { - let pdf_promises = new Array>(); - let i, j; - for (i = 0, j = runners.length; i < j; i += 50) { - let chunk = runners.slice(i, i + 50); - pdf_promises.push(this.generateSponsoringContract(chunk, locale)); - } - const pdfs = await Promise.all(pdf_promises); - return await this.mergePdfs(pdfs); - } - await i18next.changeLanguage(locale); - const template_source = fs.readFileSync(`${this.templateDir}/sponsoring_contract.html`, 'utf8'); - const template = Handlebars.compile(template_source); - let result = template({ runners, codeformat }); - result = await awaitAsyncHandlebarHelpers(result); - const pdf = await this.renderPdf(result, { format: "A5", landscape: true }); - return pdf - } - - /** - * Converts all images in html to base64. - * Works with image files in the template directory or images from urls. - * @param html The html string whoms images shall get replaced. - */ - public async imgToBase64(html): Promise { - const $ = cheerio.load(html) - $('img').each(async (index, element) => { - let imgsrc = $(element).attr("src"); - if (imgsrc.startsWith("data:image")) { - return; - } - const img_type = mime.lookup(imgsrc); - - if (!(img_type.includes("image"))) { - throw new Error("File is not image mime type"); - } - - let image; - if (imgsrc.startsWith("http")) { - image = (await axios.get(imgsrc)).data; - image = Buffer.from(image).toString('base64'); - } - else { - if (imgsrc.startsWith("./")) { - imgsrc = imgsrc.replace("./", ""); - } - image = fs.readFileSync(`${this.templateDir}/${imgsrc}`, { encoding: "base64" }); - } - - image = `data:${img_type};base64,${image}` - $(element).attr("src", image) - }) - - return $.html(); - } - - /** - * This method manages the creation of pdfs via puppeteer. - * @param html The HTML that should get rendered. - * @param options Puppeteer PDF option (eg: {format: "A4"}) - */ - public async renderPdf(html: string, options): Promise { - html = await this.imgToBase64(html); - let page = await this.browser.newPage(); - await page.setContent(html); - const pdf = await page.pdf(options); - await page.close(); - return pdf; - } - - /** - * Merges multiple pdfs into one. - * @param pdfs The pdfs you want to merge as an buffer array. - * @returns The merged pdf as a buffer. - */ - private async mergePdfs(pdfs: Buffer[]): Promise { - const mergedPdf = await PDFDocument.create(); - - for (const pdfBuffer of pdfs) { - const pdf = await PDFDocument.load(pdfBuffer); - const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices()); - copiedPages.forEach((page) => { - mergedPdf.addPage(page); - }); - } - - return (await mergedPdf.save()); - } - - /** - * Generates a new dummy runner with halfspaces for all strings. - * Can be used to generate empty sponsoring contracts. - * @returns A new runner object that apears to be empty. - */ - private generateEmptyRunner(): Runner { - let group = new RunnerGroup(); - group.id = 0; - group.name = " "; - let runner = new Runner(); - runner.id = 0; - runner.firstname = " "; - runner.lastname = " "; - runner.group = group; - return runner; - } +import axios from 'axios'; +import cheerio from "cheerio"; +import fs from "fs"; +import Handlebars from 'handlebars'; +import i18next from "i18next"; +import Backend from 'i18next-fs-backend'; +import mime from "mime-types"; +import path from 'path'; +import { PDFDocument } from 'pdf-lib'; +import puppeteer from "puppeteer"; +import { awaitAsyncHandlebarHelpers, helpers } from './asyncHelpers'; +import { config } from './config'; +import { Runner } from './models/Runner'; +import { RunnerGroup } from './models/RunnerGroup'; + +/** + * This class is responsible for all things pdf creation. + * This uses the html templates from src/templates. + */ +export class PdfCreator { + private templateDir = path.join(__dirname, '/templates'); + private browser; + private static interpolations = { eventname: config.eventname, sponsoring_receipt_minimum_amount: config.sponsoring_receipt_minimum_amount, currency_symbol: config.currency_symbol } + + /** + * Main constructor. + * Initializes i18n(ext), Handlebars and puppeteer. + */ + constructor() { + this.init(); + } + + /** + * Main constructor. + * Initializes i18n(ext), Handlebars and puppeteer. + */ + public async init() { + const minimal_args = [ + '--autoplay-policy=user-gesture-required', + '--disable-background-networking', + '--disable-background-timer-throttling', + '--disable-backgrounding-occluded-windows', + '--disable-breakpad', + '--disable-client-side-phishing-detection', + '--disable-component-update', + '--disable-default-apps', + '--disable-dev-shm-usage', + '--disable-domain-reliability', + '--disable-extensions', + '--disable-features=AudioServiceOutOfProcess', + '--disable-hang-monitor', + '--disable-ipc-flooding-protection', + '--disable-notifications', + '--disable-offer-store-unmasked-wallet-cards', + '--disable-popup-blocking', + '--disable-print-preview', + '--disable-prompt-on-repost', + '--disable-renderer-backgrounding', + '--disable-speech-api', + '--disable-sync', + '--hide-scrollbars', + '--ignore-gpu-blacklist', + '--metrics-recording-only', + '--mute-audio', + '--no-default-browser-check', + '--no-first-run', + '--no-pings', + '--no-zygote', + '--password-store=basic', + '--use-gl=swiftshader', + '--no-sandbox' + ]; + await i18next + .use(Backend) + .init({ + fallbackLng: 'en', + lng: 'en', + backend: { + loadPath: path.join(__dirname, '/locales/{{lng}}.json') + } + }); + + await Handlebars.registerHelper(helpers); + await Handlebars.registerHelper('__', + function (str) { + return i18next.t(str, PdfCreator.interpolations).toString(); + } + ); + this.browser = await puppeteer.launch({ headless: true, args: minimal_args }); + } + + /** + * Generate sponsoring contract pdfs. + * @param runner The runner you want to generate the contracts for. + * @param locale The locale used for the contracts (default:en) + */ + public async generateSponsoringContract(runners: Runner[], locale: string = "en", codeformat: string = config.codeformat): Promise { + if (runners.length == 1 && Object.keys(runners[0]).length == 0) { + runners[0] = this.generateEmptyRunner(); + } + if (runners.length > 50) { + let pdf_promises = new Array>(); + let i, j; + for (i = 0, j = runners.length; i < j; i += 50) { + let chunk = runners.slice(i, i + 50); + pdf_promises.push(this.generateSponsoringContract(chunk, locale)); + } + const pdfs = await Promise.all(pdf_promises); + return await this.mergePdfs(pdfs); + } + await i18next.changeLanguage(locale); + const template_source = fs.readFileSync(`${this.templateDir}/sponsoring_contract.html`, 'utf8'); + const template = Handlebars.compile(template_source); + let result = template({ runners, codeformat }); + result = await awaitAsyncHandlebarHelpers(result); + const pdf = await this.renderPdf(result, { format: "A5", landscape: true }); + return pdf + } + + /** + * Converts all images in html to base64. + * Works with image files in the template directory or images from urls. + * @param html The html string whoms images shall get replaced. + */ + public async imgToBase64(html): Promise { + const $ = cheerio.load(html) + $('img').each(async (index, element) => { + let imgsrc = $(element).attr("src"); + if (imgsrc.startsWith("data:image")) { + return; + } + const img_type = mime.lookup(imgsrc); + + if (!(img_type.includes("image"))) { + throw new Error("File is not image mime type"); + } + + let image; + if (imgsrc.startsWith("http")) { + image = (await axios.get(imgsrc)).data; + image = Buffer.from(image).toString('base64'); + } + else { + if (imgsrc.startsWith("./")) { + imgsrc = imgsrc.replace("./", ""); + } + image = fs.readFileSync(`${this.templateDir}/${imgsrc}`, { encoding: "base64" }); + } + + image = `data:${img_type};base64,${image}` + $(element).attr("src", image) + }) + + return $.html(); + } + + /** + * This method manages the creation of pdfs via puppeteer. + * @param html The HTML that should get rendered. + * @param options Puppeteer PDF option (eg: {format: "A4"}) + */ + public async renderPdf(html: string, options): Promise { + html = await this.imgToBase64(html); + let page = await this.browser.newPage(); + await page.setContent(html); + const pdf = await page.pdf(options); + await page.close(); + return pdf; + } + + /** + * Merges multiple pdfs into one. + * @param pdfs The pdfs you want to merge as an buffer array. + * @returns The merged pdf as a buffer. + */ + private async mergePdfs(pdfs: Buffer[]): Promise { + const mergedPdf = await PDFDocument.create(); + + for (const pdfBuffer of pdfs) { + const pdf = await PDFDocument.load(pdfBuffer); + const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices()); + copiedPages.forEach((page) => { + mergedPdf.addPage(page); + }); + } + + return (await mergedPdf.save()); + } + + /** + * Generates a new dummy runner with halfspaces for all strings. + * Can be used to generate empty sponsoring contracts. + * @returns A new runner object that apears to be empty. + */ + private generateEmptyRunner(): Runner { + let group = new RunnerGroup(); + group.id = 0; + group.name = " "; + let runner = new Runner(); + runner.id = 0; + runner.firstname = " "; + runner.lastname = " "; + runner.group = group; + return runner; + } } \ No newline at end of file diff --git a/src/asyncHelpers.ts b/src/asyncHelpers.ts index 881bbe6..f435de1 100644 --- a/src/asyncHelpers.ts +++ b/src/asyncHelpers.ts @@ -1,44 +1,44 @@ -import AsyncHelpers from "async-helpers"; -import bwipjs from "bwip-js"; - -export const asyncHelpers = new AsyncHelpers(); -async function generateBarcode(str, options, emtpy, cb) { - let res = await generateBase64Barcode(options.toString(), str.toString()); - cb(null, res); -} -generateBarcode.async = true; -asyncHelpers.set('--bc', generateBarcode); -export const helpers = asyncHelpers.get({ wrap: true }); - -export async function generateBase64Barcode(type: string, content: string): Promise { - let options = { - bcid: type, - text: content, - scale: 4, - height: 10, - width: 10, - includetext: true, - textxalign: 'center', - } - if (type != "qrcode") { - delete options.width; - } - try { - const barcode: Buffer = await bwipjs.toBuffer(options); - return `data:image/png;base64,${barcode.toString('base64')}`; - } - catch { - return errorimage; - } -} - -export async function awaitAsyncHandlebarHelpers(input: string): Promise { - return await new Promise((resolve, reject) => { - asyncHelpers.resolveIds(input, (err, data) => { - if (err) { reject(err) } - resolve(data) - }); - }); -} - +import AsyncHelpers from "async-helpers"; +import bwipjs from "bwip-js"; + +export const asyncHelpers = new AsyncHelpers(); +async function generateBarcode(str, options, emtpy, cb) { + let res = await generateBase64Barcode(options.toString(), str.toString()); + cb(null, res); +} +generateBarcode.async = true; +asyncHelpers.set('--bc', generateBarcode); +export const helpers = asyncHelpers.get({ wrap: true }); + +export async function generateBase64Barcode(type: string, content: string): Promise { + let options = { + bcid: type, + text: content, + scale: 4, + height: 10, + width: 10, + includetext: true, + textxalign: 'center', + } + if (type != "qrcode") { + delete options.width; + } + try { + const barcode: Buffer = await bwipjs.toBuffer(options); + return `data:image/png;base64,${barcode.toString('base64')}`; + } + catch { + return errorimage; + } +} + +export async function awaitAsyncHandlebarHelpers(input: string): Promise { + return await new Promise((resolve, reject) => { + asyncHelpers.resolveIds(input, (err, data) => { + if (err) { reject(err) } + resolve(data) + }); + }); +} + const errorimage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXkAAAFRCAMAAACmIi1UAAABS2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+nhxg7wAAAARnQU1BAACxjwv8YQUAAAABc1JHQgCuzhzpAAADAFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/1CoAAAD/3ywkHQb+0yr/0yr/0ir/+DH/9zH/1Sr/1ir/9TD/9jH/+TH/8TD/6S7/7y//9DD/8C//3iz/3Cv/7S//2Cv/8zD/4Sz/2Sv/4i3/8jD/2iv/7C//3Sz/2yv/5S3/6C7/1yr/4Cz/6y7/0Sn/4y3/5C3/5i3/5y7/7i//6i4CAQAGBAAKBwEQDAJBNwo9NAoTDgNLQg0NCQI3LgkvJgdSRw4gGQX41SoaFQQyKQgsJAcXEgNHPgxYTg81Kwh5ZBTGryMoIAaSfRhVSw9DOgslHgYdFwS/qSH/+zI7MQnewybz1SqsjhyAbRXlvSWjiRtwYBPwxye1nh+OeBjNqSGkjBtoVhFsXhK7pSDDrCLMsyPv0ClnWxKqkx1eTQ9bUA/OtiQ5MAkqIQZYRw68nB5sWhH91iqPehiHdBZHOgxiVxGCcBZ6ahXixyfoyyiWfhh3aBRLPgyXgRl+aRX70inyyijhuiWbgxq/nx90YRPVsSMiHAXTuyWmjhzZvyatlh1ORQ3JsiO5oyDQuCXszSj72CtfVBD92yuynB63oB/40Cl9bRVsVxGvkh3cuCTpwibQrSKdhhqNchb1zyny0irbwSZzZBSvmR6ihBqgiBtjURBaSg+FbxaojBvEoiDZsyOKdheLeBjtxSf0zSiokBzWvSW4mB7HpSHlySjkxSf//jKzkx20lR7iwCb/+DLCoSD22yv12Sv+4CzjumPYAAAAS3RSTlMAEe5E3Wa7npl3IswzqlWISdr21VBNpAgWxrbRDfIb+rHlA8lwXKFr6Sb9j3tBMIC+4Cw+dDbtrR87isJGpyqTVpa4XziDZIZZAZxImYyrAAAdeklEQVR42u2dd2AbRd6GI1s2ltwglIQSOhy9k4Te60phV5IlWbIl2XKRe7dTLz0BEggkkEJCOgdHKIEjgYQSeu+9hHZHPXo7OLj77nPkIml/s7uzuzOr4nn/glia3Xl2tDszu/vMsGHpmRG7F4856PisLPOeZ1yQfeAwFoNy9B6jbHEZnXcyY2JEdt7FBpJ/CuNCOyPPtSFzxj6MDdWcd4RNIsN3Z3Qo5kibTI5ifKjlUJtsTmWEKGUnm42hT0YsNsUcwihRiHW4MvnjRzBO5LOHDSPHMk7EcwoOeNtwKyNFOrlY5G2HMlKEU2TDzPmMFdnsikt+L8aKdo9y/ENPPjlpPPx3NotAMvuOAoA//66lrNK3fAact2S4COZSwPfDXyMVrpLa0l/XgT9dyHgRy/mA7kNlzQLXG6GxbQ4YTrEJY2KBc/Iv1kTB96J3vAH+eBEjRii7AbZ/dbq4/tR2/Vn81/0OZ8zIZG8x2on3+4QB8kLpVeDA7MGYEcnBgOw9Xp4bTInnNfABdluWREZmiblOD4TjyAstS0Cv/lyGjUDOAS36E4/Axcd7A/jIboyb7hQAqleEahPA8+2zZrLhFPnsBchfVZPY5Dne8Rn40J8YOZ3ZHTC911PCicgH2qeJP3WAibHTl3wx0qlbu0VNvvci617F7oYTzp8A0W/ie5QDqfK/IP5cz5mMno6YDhMDvbO+GkFeKH8RPu/H8OnIWYDnrU6BQ6TEeS/46ImMn+YcA2he213Po8gL3VsniD+bywBqzv6A/F9qkE1+R8/yPvDhIkZQY3YGLG8DPcpB8m2vjhN/em+GUGMOEqOcsCQi0eR70TvXggN1MGOoKRcCkvd5OcnwdR2LxZ8/jA2ntGSfA8QgF77axkujF8peAofqSIZRQ04FHJ91CJxMKkrhgwgnMI6qcwKgOMkX5OXIC+W3g+8UMpCqMwZQvK5StslznMv5V/CloxlJlTkdMLyyrEkePCf4fpko/tZxDKXK7AlmwJ6LKDT53v6N9xtwwM5mLFXlPEDwbS+nGL769avF39uVwVTVozxeDHDmrAZeGb3gfJYNp3TlIsBvrUPgMBp9sHOy+JtZIxlP7BwO3vSe3FmH0eR7G33lTeCgncWAYqcQ0LupDKfJ7xhO1cDh1DGMKGaOBuyuqazAA88J/pfBt8cwpJg5DbD7sQuzyfcOpxzrwdezGVOsXAzIPejgsMM33j9F/P3TGFScjDCLwS36uINXgf6Pe8Chu5hhxcixgNsHDhXgOT4cnCsuYRfmOlOOdT8xtjvaA2rI9w6nbgUHz8LAKgbqDV5yC2rA9w6nfJPEZYzal5FVyIkA/IzSCk5dhMrrQCl5DK1CjgPMXvYLKslzTZXXgGIKGFvZnA2I/cPhUgueE7qeAeXsz+DK5UDgorz8lk5eNfne4dQ/APqdGV6ZHAV4bfNqAM/xna9cLi5pT4ZXOmOBMGtetV0LeY53LGCSMxWBVsRVboHTRL45MB0Mp5jkTCpQmPVCeRWnLYLneaYSxQ4UZt1eLmgkz9W3XAskZ2MZY2SgMGu9hh7lYKOv+Qso71IGGRmgN5hyf6PmJt87nCq7EqBnonpUTgKcFjh47eA5IfRjDxtOYQQKs+bYm/WQ5zjHg0xyhhEozHrDI+gCz3fcMltc5kEMtDgnA/B/7qrl9IV3bAOlnsdQiwL1Bi+WCnrJ25vnMGe0QlDCrBJObwTPJ8wZrRCgN5j4i0/QTZ6rDV0BJGfMGR0fKMz61sHrB4+UnDFndFxGjhbjmVsXJkGeK/HcxiRnMoHCrOc9AgnwnBD5+3jmjJYMQpgVqecIxbuFDacks7+yMEt7z7Jh6SImOZMIFGa95ikh1eR7h1MfgPJzGHR0j3LC1haBHHl79TwgOWPO6B2BwqxNXo5gBDdzRiMDhVlXv17Nk0SPcEYfwZzRqEUYJYRZiecQrra5M1Re6m9psFfwSsOpF5kzGgZfmBWH3WXvcjY88t5dy9a++9XyppCzs4qXH04xZzTMGHxh1gD3Wr/7sv88vLn/UaaehV9se8znqeak4QstS5jkTByEMMstqzcQ6jyNa+4W3/GY/Okjzg4Z9t77mDNaFKA3GP93Ob2BUOtsWzYHtYzUxIe/9zZLfZNvn/U0G04lRKUwi/f7fxsntYTXhA/bK1281HCKOaMTAoVZ415tlzxnCPXe3yfLLZ+28H1vHbrZo5zRQ1pyVgyFWdI9ytaGsgeUlq77sLK9VUJy9iZzRseCEGY1SuoNWn2+DcqrBm6IdKDRI5zRtqHrjC5UIcxq9bVNwlmwcWNLm4CWnN3MnNEDyVYhzBLCvofw1spcX4keVqGc0UNVcoYQZoWkmrzL/SDuMqU/uKWc0VOZ5CyaQwCzLZI9Sr70OlzwtkUfoX2ivHcTc0bvyAgozFoqKcyq8v0Zm7xtdZmUM3ohc0b35gJAbIX0gx6d7/Xgk58WCKKvFQ7mjO7N4UBvsLhDWpjlvgcfvG388gZsZ/TooSc5O0ONMMvlnq+CvO0/LcwZLRl1wiyXUxX5n1uYM1oyUJj1jJwwy7NaDfmvOyUlZ0PeGX0xQm8gNytfukIF+AnftUm/lT/EndEjgN5gtrwwK/STCvJTPgqrcUYPKcmZamGWb40K8ldzduaMRscK9AbTFIRZDY+NV9Gfr6+TcUbX3jmEndFQmPWmgt6g+tGp+OQ3h+vlJGc/gC+cNFTAo4RZCnoD+yMz8clvbKySk5w1Dl1ndK56YVZd1Rx88uvKm1Q6o88ZGuCh3uBGRb1BfXgzPvn5Tpe8M/qaoemMvmRXIMx6pVHpOcoK3xf45Dc5mTMaFYQwS/lltJKaG/HJP16pJDmDhZ2e+eDHAr3BvDCGMMtxAz75ZeXMGY3ITlBvgCPMci/AJ39XRHEJniHojEYIs/w4wqzyf+KTX+NjzmiYcwGnm7GEWaG7sMH3vNehxRmd4ZIzlN4AS5jlex+b/NSV1RjO6GuHmDMaIczC0xu0L8eeuLn8rWYMydkQc0YfrFmYFf5+Ii75O10BbZKzDHZG75ulWZhlv2wcLvnFwSBzRouSByr7Ca7eoK5+Gi75h9qwXFBDyRmNEGaFcIVZtW0P4ZLf0I2zUgDfecvQcUbrEWZVtGzAJX93Kdar+7z3gaHijIZ6g3vxhVmusidxyT+Mt/gU32wHzmhzZkrOoDDrX934egPHl7jkv3Fqd0ZnpOQM6g2+VSP1L9uGS/6DGmxn9Oah4IxGCLOCavQG5ctwyb/r1+GM3inzyJ8FhVlONSqVyBO45J+I4JbZVHZb5jujoTBrc6RejdGj8Slc8u834jujn+vJeMnZ/qr1BuKJm+0T9D3DjX4rP+Od0fqFWeGPpmBOVT5ajV0o3/FxpjujD9ItzAq4rsZ8TeqRZvxSecfjoIALMwl8jn5hVjC4GI/89KaACvIoZ3QGSc5MB0BhVptKYVZtA+Y7apMDQRXFopzRF2QOeSjM+sGpVs7XFPocj/wLDaq09RntjEboDbqDah1x2K9KbWhRtagpyhmdMZKzMSr0BjITN5vwyN9Yqa7TlMHO6NPVCrPQqXwcj/wNDnXlopzR52YGeZXCLKn438Ujf49btTP67cyUnJ0HW6UmBWvLV3jkV9SoLJhvWDozEyVn+wC9wdOz2rUoWDu/xiP/7y7mjI4GIcxyaNI9t32HN3HzVYtq8oG2aZnnjD4TjnQ66zRZh5vfuhyL/FONqosW3KtAMcXpTr6QSI8yOnFTMhdrqnJ7u/qyq/wZ54zORugNmjSB54KByTjkJ34f1iBKRzij01xyBvQGPT+GNEr9qzpm4JCf+YhdQ+ElHig5OzGdwSOEWQ5OY5q61uGQn1NVp6HwTHNGjzCrEGYpTtzgmVYm2bWtypNZzmgozPpMx8pozm9wyM/o0LRmO8oZnb6SM4QwqyGgnXzNpzjkPw9pu4LzzhWZ44yGwqyXynSsmdP1bxzyT7q1LdrO1zXckSnOaCjMmlFToR081/0zDvkvtV7CUc7oNJWcHadOmKWYDixz4gNureVXlWeIMxohzPK6dIDnqlfimFb+Waq1fJQzOh0lZwdCYdYtnbqWiWp+azYG+Z9CmjfgcmaE5AzqDR7XudZuoGI6jjGxW/MGMsMZjRBmtdn1ka+34wjoJY2JWBP1GeCMVi/MUr4CNm7UZUzEII9wRqeb5AyhNyiv0geeKym/G8OYqGWqMm449Wy6O6OhMOt2v+6FRx0PK5NfeJldD/m6zsnp7YyGwqz1Dpde8FiK3Hm1dXo2gXJGn5VO5LUIs5SDo8iVNSbivP2JcEankeTMAkeWXgIrvuIocmWNiTiNHuGMTh/J2b5AmDWnuZkAeRxF7jp/k76NuBzrQaHZ6UJeozBLMTiK3PkendcT3nd/2jqjz4d6g65aAuCxFLmbHHq3wnu/TVfJGRRmvVhOZCl7HEXutkrd5FHO6EvSAbxmYZZicBS5SsZEnIsswhltSQfyQJg1EVOYpTxxg6HIvSukezN8sHFSOkrOoDDrHhI9ymhfG0ORq2hMxGn0ldeloTN6JBBmTQ+ECZEvqVlPwJiIc4grr0k/ydk5UG/gIXOu4XAUuVO/qyawHcH/TNoNp6Aw64pQLSnwGIpcHGMi1nAq7ZzRUJh1VSmxJo+hyMUyJmJcZBtfmZJekjNdwiyMiRtFRe4dwSCRLfHeBeklOQPCrKlbu8k1eQxFLqYxUZl8uG56OjmjoTDrG1I9ymiUFblf+CrIbErwpJMzeuRh4LRbX02SvLIiF9OYiNHo67vTyBkNhVm3Ogmea3AUuQ87SW0L5Yy+NEXBQ2HWtS31JJs8hiL3G2Lkkc7oFJWc6RZmKUZZkft4JbGNCaEf08QZvTPUG3hKiILHUORiGxOxhsxp4oyGwqwlLWSbPIYiF9+YiHGR7UgPZzQUZt3n5UhHUZH7vo/g1ngH9MKel3LgoTBr4attPGnyZQ8ovIb8WANJ8s32OanvjD6VgDALY+JmGTljItZw6pOUd0YjhFm+IPEmr6jInU1mqjJ2FywCJGfDU0xyRkaYpRglRa4qYyLWcAo6ow9NKfBQmHWlu4k8eK5BYeKG1FRlbDjlhpKz81OJPBRmPReh0OQVX5XS+1QlYjiV2s5oKMx628vRiNLEje5n+2C8W1LYGU1MmKWYKoWnD1Y7SW+Rb/h4Ueo6oy8CBNY6BCptnnPeQ9rnpDycSl1n9JlHkBJmKafjd7lL7OS2evLk7eF5qeqMhsKsm8ooNXmupPQ2OWFiGYUDLnjeSFFn9NEIYVYFJfAcH7pd5k0de4DGNmtDQHK2X0pIzoAwy/ZjF60mv+NM/7Yk+Zfo/NRS1RkNhVkPOuhx5/hwo9T7yDeQvh0weIrzvJaCzmgozFr0cQNPEX1ry9I70Uqhcjuln5oQWZKCzuhjiQqzsND7l85DgH/H395KbZsp6Iy2AmHWHXqEWXjoIx3vgNmKT93V9MDz7bNSzhkN9QYvuQWOclrbnGsSl3v5/DtHLc3N8o7PUswZfSIUZpVWcNQjlJRG1tzYf7qfsPjL5W4fT/WHxgfaU8wZDYVZL/sFzoAIVX53/fInlq149+eVbc7OEp729lLMGX02FGY5XJwx4V11DZHyUn83hRkD1FxdSjmjoTDrcp3CrNRNajmjoTBrmzdDwfcOp5yp44weC4RZ86rtGUte6N6aMs7oQ0EbWOUWuMxNyjijaQizUjl826vjUsMZjRBmlWdyk+8dTq1NCWc0HWFWSpOva1icCs5oIMya8kqj0U2+pKKqosS4zaEkZ8Y7o08C+7DAyB4l7wp2lDprWjq7a5ylHUGXMZuuKoXO6BMMBk9LmIXJvSLiDjy27Mu7N2zc8M6Xyx4LuENVRvzehPLbk+6MvhQKszxGnWuEisrQ1/PjF5eaO/+pSFmFAdtPvjP6ZFrCLIz2zofKv4I3BCd/VdrFU//RCd2/TEyuM3ovWsIs5brXerejX1PbvN1bS30fUM7osw0ET0+YpXhTpNqzQmrlhZ5PPRTvS/WTr3796mQ6o4HeYOIvPkOafGtH+TsyTzq94++gjV5IqjMaCrNW/8EbA75FXoS+saWBMno+mERn9MjR4FWNurAR5AV7+ecK7wZu8Nsp//iEypuS5oymKsySa24l3rcVDXJvO2jfGUyeMxrqDa6IGHJDTnC/ibHaxZu0Z6oF/8tJkpztT1WYJdPk22ctxCA/blYD5UafLGc0FGa95jFm1sqzBWcNNduDHtpNwHf/lGQ4o0GPcsLWFkOafOO/8FZgH/97I+VGz/+xOgnOaCjM2uQ1pMW7PA/b8LLFTXlUx1fXG++MNkFhVm21IX35wN+exiT/9N8ClPdFcN5quDP6SNrCLMl2Vr7KhptV5bRPN0Gf0c7oY6Awq7vekCbvcs/HJv8k7dMN0hmdR5X8GOrCLKkEA5Oxyd9RF6S9O0Y7oxHCLLdB90GVhYlx83ePhmnvjtD1jKGSMyDMGr8kYtCdqM6vbfh5qpP+DhnqjL7QCGGWRJTMNokLL0So7w/f+IpxkrN9DBFmSQRv+fX+/Oanv0NGOqOhMOtZp2FP2Ph/U0H+XSPINweMckYjhFmNQcMe9IjcpeZsEzJgjwTP8wY5owuNEWZJpPF9FeTX+IzYJYQzevhYCuCzoTCrrMkw8JgL3/cb/FZWG7FLKMkZDWc0EGb1PBcy8DnKutrp2OTnVtUZsk/GOKOhMGuLlzMwJaV3Y5MnJqFXavShH3uoD6dGAGHWTOr3fhK7EmXPYpNfW2bUnjkepO6MvgBafBzGvhJV/egUTPBTHq02qjl03DKbsuTscCDMWtxRZyz5ksp1mOTXVRr2TD19Z/QZBgqzpCoZuhmT/M0h4x4nb24GzujjSTqjDRVmSfYkKq/EAn9ljYGdXdrOaCjMeqbL8JfRhJYlOLfAya83IJvaEE1n9MXGCrPUnFRhtjkNvf5QdUaPAHqD2R93JOFdbz5Yo7w+7MbSoMFXforOaCjM+sCRlJfshc7/zVMAP+9/nQafBoXIc+MpOaOhMGtaeyA5eoPWLgl73ECuXtrVavheOWg5o/cw/qFRafT+/y6WAb/4//zGg0c5o4lIzpIkzJJCH2mUfmnkncZIaxL2iZYzOmnCLAn07c6fZqPXGPnJ054M8BxvrwaXnwP0v5UPhVk3JldvIDQ5X/8QTuFM+fB1Z1OSWoTgfoP8aySX7Jp6wiwh7Jj16bUJ87OTPp3lDSfvl1jbBSRntjOJv4y2zZF0bRPPh53d25fNnzFt7tNz75gxf9n2bmeYT+JuoZzROl8jgY8OzwunhDCLr2qvcfiCJZeVBH2OmvaqJO9TifM1ws89XZTKwixXVV3AHqirSgGrjtACndG63srfd/jQEmbpiPcGosMp+GzTzZktzNJ+9kM4o3WI0keOGmrCLD3Dqc8ISoeACXTK/T7W5CXIIyRn2teBAbPDqx08Yyx1kS27iZgEBCzDeGd9NSMvmQr43JPWl/LB22hrnQy8TKOHr5FofF/wQPHDTXPCAUZebnwBnNEaX1o7HDR5DwMve5HtEj+Xcty+RGYppwcCjK5sgs2ip2530XaiF7tAF1zPmrx8mspFj8GNPpHInM17jYy80ole9Lb0cG2Pt4rUTRM/amZsFeIQTd4coc0AItKwzn6LkVe6xF4vIt+j7WXBPNG9KEZeuc2LRDDDdycxkJr6fZihVRjFdr9A5AorfrTsqW52hZU/2TS8InqLbm9tN2PF9qbVvzLy8uR/FS8Pv7+2Zz/EYo+Z/w21MrzSaS3bOpHM+nZjxc9Tbqwp51izl2rwLg983PZsjY/agOn5zSuvr6m2syASLr3+MfCw7SgTqVli24S7n1h5GQsI53przboecm8wZCNfhlm0cOE4lsQsHIcUThVpvhu4q41FR3bRrrA8idHTEx3rq0GJEwt+dK0peAjjpz36BAh7MYBao/PVTOsohlBbdtX7Dv7pjKGmjNK/OvtujKKGDCex8AhDr6HFk1lA8+TRDKXKczwpIfqIPRhMNTmVoGXlxF0YT9wcdOYwotntNMYUJ3uSFsjtuFFiOW0/RlYuPflHWYfRyT6nHGI58tKdWGDOuSBnZ6PWbWRhYWFhYWFhYWFhSXrMieOwPAtqGGbKsiEeEswDo7g8C2ptYIsl+scsSw56FyyWrOgHii0m2Q2YLaL3Sy3osSRiH3JQnzMrVTAKp7+03N7/RO2//D7I1cAMvlRoQu94lkmRfG/yRavnFcQvDJMFX821JpSSm62wgWITFfLoChInn1ADM2KPQLPPjf57Dg55W1aB3GfyrQo7Hn/cURvIyqZBHl1BKuQHa2BG7ZLo4Fv7GyQW+fhvW/MVDkyu7JHLUwBLjLxEBemQH/ijOaFEqyXKCnE+3bHlAkg+4f3ynL4zy+D50tp3WPMt0S8WFYPD2n9g+i4ABX3bjkMv2oClvx4F8fuF94J7DoqrYgVxyUvvg1wNzOISd/wxK/H7vZef/CK4hTz4T9kJ58soSXOsCZqiR6Zw8P/7DlTcYS4yJxwbsIG+35CZOHmJChInn1ADQD56mU/4wRZFrwtZ4BKEIN/3sy6K+yHmmsAJKjv+s+YCeEUplN5Awk+SFHmpClIgH1cDQD766YR/KYzCzANnIRT5Hc2n/2PRQ5iPqEs/ApMZdTXPFZ0lRRvo+xJh8lIVpEJ+sAaQvEX0L6a+009RYm9Ainzu4D9abIgzZ/R0ZIo1eXA1tGbFIOH8qAiQl6wgFfKDNYDki22Jz9xb+i+a4CykQN6ccE6P/dgK+y640Z9doURnwSq9AXPsHwmRl6wgHfIDNYDkzYOtMvb/Bf1HpFCpWNPg2abAZpN9a8Iq8fdYCej9Lo71AAiRl6wgJfL9NUD2bfJE54f8QZQmhWItgzwt4o8jYGRJnXULpfe7KFYuGfLSFaREPloDMXlTtE+dZRV92TJ4erDIF1sU61UW2+SXHiiWgmEZPCTI/bbGLg9kyEtXkBJ5a4y83CAw+uOPXRLNMsVaLblxHfRcBSyFNok3dWNND7nfw2LjfPT4UYq8KBblCmofw8qSHyZFPnHOyxI7+UX3sUhx9iA/tqty7rp8qb9bB/tE6P3OIktepoK0yGdJkE+cUMyP25m8xN8smvxAD96sQN4sUZW+JpEtvd+xgomQl6kgLfJmybNN3LiyIP46mB3r8EmStyi26dQiL1dB+uTjSswpTpy0Kk44G5sT/g+SL7YkduyLFchrOtsknuf1XmHlKkjpCjsM1bcZmNMxx5+SRCcjE6rY6KHPsyI7h+jkyl5hrZL7bYqNA0iQl6sgJfImCfJ9bS5Hel47B1ls3yRcUeIuKfUqC+U7+sj9LohNShAgL1tBSuQLpMjHt9Zc6b6LuNjoTFAc+iL0SMo0cKPXIjWSil3mkPudQ3QkJVtBSuRzJMlbBk83VuTlowBdbHSuKzZFZkLPDuQMfMkqcftomMLsQV6MjX7y8hWkRL6/BgjysQGFBexwVlxR4mKLEm855SJrmzsIDv33vhZRID8xVEyKvHwF6ZAfqIFsm0dPIQ9cgkCxeQm3nJCzwNmxDl0O8kdhwpklLiBFXr6CFGeJCyTP8/kDjVh0m8Ya1xUGxfad6nPiGYrvjOTHFWkGN8Qx7oxkxZ2IdZNXqCCdOyMDNYDkCwbvYqM6hrmxPicsNvE2LOJuYG58vYrgswiKdwNz44+tbvIKFaRCfrAGsD9vHvg9I6+RceeQPPRN8Vhd+u72xkooyE+8EhSL74BnR7c9OFUK7x/nJjycoZe8UgVp3AGP1UBEPruPRqFkvy/6YymUvck4WJm+3o4tv68jaSkU9RwG+3SWor6pznzRBxI3YO0vIDaHrZe8UgVJk0+sgRn5nJgVMZSOb9aSQ8zE/k1BlsJzSIWyD5HlKTzDJvGUkQ2XvFIFxeRRT0rJ74NcDcySf8pG3cGO750gO6tRlqKRbfzeZiuMIQut8pOh8U+J6CSvWEE65AdqgCCfZxIPWUBLMUtPSmQlNuwcM3ImM/b5YjVPtCbOYOskr1hBGuRjNTCL/2CBd6IlbrWiJ+JyxI/wZfc/0yb5FHeOxYz1FHeh+BlxfeSVK0icfHwN/h87gK/3ae4GIwAAAABJRU5ErkJggg==" \ No newline at end of file diff --git a/src/controllers/PdfController.ts b/src/controllers/PdfController.ts index 2518692..16b391e 100644 --- a/src/controllers/PdfController.ts +++ b/src/controllers/PdfController.ts @@ -1,30 +1,30 @@ -import { Body, JsonController, Post, QueryParam, Res } from 'routing-controllers'; -import { OpenAPI } from 'routing-controllers-openapi'; -import { Runner } from '../models/Runner'; -import { PdfCreator } from '../PdfCreator'; - -/** - * The pdf controller handels all endpoints concerning pdf generation. - * It therefore is the hearth of the document-generation server's endpoints. - * All endpoints have to accept a locale query-param to support i18n. - */ -@JsonController() -export class PdfController { - private pdf: PdfCreator = new PdfCreator(); - private initialized: boolean = false; - - @Post('/contracts') - @OpenAPI({ description: "Generate Sponsoring contract pdfs from runner objects.
You can choose your prefered locale by passing the 'locale' query-param.
If you provide more than 100 runenrs this could take a moment or two (we tested up to 1000 runners in about 70sec so far)." }) - async generateContracts(@Body({ validate: true, options: { limit: "500mb" } }) runners: Runner | Runner[], @Res() res: any, @QueryParam("locale") locale: string, @QueryParam("codeformat") codeformat: string) { - if (!this.initialized) { - await this.pdf.init(); - this.initialized = true; - } - if (!Array.isArray(runners)) { - runners = [runners]; - } - const contracts = await this.pdf.generateSponsoringContract(runners, locale, codeformat); - res.setHeader('content-type', 'application/pdf'); - return contracts; - } -} +import { Body, JsonController, Post, QueryParam, Res } from 'routing-controllers'; +import { OpenAPI } from 'routing-controllers-openapi'; +import { Runner } from '../models/Runner'; +import { PdfCreator } from '../PdfCreator'; + +/** + * The pdf controller handels all endpoints concerning pdf generation. + * It therefore is the hearth of the document-generation server's endpoints. + * All endpoints have to accept a locale query-param to support i18n. + */ +@JsonController() +export class PdfController { + private pdf: PdfCreator = new PdfCreator(); + private initialized: boolean = false; + + @Post('/contracts') + @OpenAPI({ description: "Generate Sponsoring contract pdfs from runner objects.
You can choose your prefered locale by passing the 'locale' query-param.
If you provide more than 100 runenrs this could take a moment or two (we tested up to 1000 runners in about 70sec so far)." }) + async generateContracts(@Body({ validate: true, options: { limit: "500mb" } }) runners: Runner | Runner[], @Res() res: any, @QueryParam("locale") locale: string, @QueryParam("codeformat") codeformat: string) { + if (!this.initialized) { + await this.pdf.init(); + this.initialized = true; + } + if (!Array.isArray(runners)) { + runners = [runners]; + } + const contracts = await this.pdf.generateSponsoringContract(runners, locale, codeformat); + res.setHeader('content-type', 'application/pdf'); + return contracts; + } +} diff --git a/src/tests/speedtest.ts b/src/tests/speedtest.ts index c016204..8bad000 100644 --- a/src/tests/speedtest.ts +++ b/src/tests/speedtest.ts @@ -1,79 +1,79 @@ -import axios from "axios" -import faker from "faker" -import { Runner } from '../models/Runner' -import { RunnerGroup } from '../models/RunnerGroup' - -const baseurl = "http://localhost:4010" - -axios.interceptors.request.use((config) => { - config.headers['request-startTime'] = process.hrtime() - return config -}) - -axios.interceptors.response.use((response) => { - const start = response.config.headers['request-startTime'] - const end = process.hrtime(start) - const milliseconds = Math.round((end[0] * 1000) + (end[1] / 1000000)) - response.headers['request-duration'] = milliseconds - return response -}) - -function generateRunners(amount: number): Runner[] { - let runners: Runner[] = new Array(); - let group = new RunnerGroup(); - let runner = new Runner(); - for (var i = 0; i < amount; i++) { - group.name = faker.company.bsBuzz(); - group.id = Math.floor(Math.random() * (9999999 - 1) + 1); - runner.firstname = faker.name.firstName(); - runner.lastname = faker.name.lastName(); - runner.id = Math.floor(Math.random() * (9999999 - 1) + 1); - runners.push(runner); - } - return runners; -} - -async function postContracts(runners: Runner[]): Promise { - const res = await axios.post(`${baseurl}/contracts`, runners); - return new Measurement("contract", runners.length, parseInt(res.headers['request-duration'])) -} - -async function testContracts(sizes): Promise { - let measurements = new Array(); - console.log("#### Testing contracts ####"); - - for (let size of sizes) { - const m = await postContracts(generateRunners(size)); - console.log(m.toString()); - measurements.push(m); - } - return measurements; -} - -async function main() { - const sizes = [0, 1, 10, 50, 100, 200, 500, 1000] - console.log("########### Speedtest ###########"); - console.log(`Document server version (according to the api): ${(await axios.get("http://localhost:4010/version")).data.version}`); - console.log("####### Running tests #######"); - const contractResults = await testContracts(sizes); - console.log("####### Results #######"); - console.table(contractResults); -} - -main(); - -class Measurement { - public type: string; - public inputcount: number; - public responsetime: number; - - constructor(type: string, input: number, time: number) { - this.type = type; - this.inputcount = input; - this.responsetime = time; - } - - public toString(): string { - return `It took ${this.responsetime}ms to generate ${this.inputcount} pdfs for the type ${this.type}.` - } +import axios from "axios" +import faker from "faker" +import { Runner } from '../models/Runner' +import { RunnerGroup } from '../models/RunnerGroup' + +const baseurl = "http://localhost:4010" + +axios.interceptors.request.use((config) => { + config.headers['request-startTime'] = process.hrtime() + return config +}) + +axios.interceptors.response.use((response) => { + const start = response.config.headers['request-startTime'] + const end = process.hrtime(start) + const milliseconds = Math.round((end[0] * 1000) + (end[1] / 1000000)) + response.headers['request-duration'] = milliseconds + return response +}) + +function generateRunners(amount: number): Runner[] { + let runners: Runner[] = new Array(); + let group = new RunnerGroup(); + let runner = new Runner(); + for (var i = 0; i < amount; i++) { + group.name = faker.company.bsBuzz(); + group.id = Math.floor(Math.random() * (9999999 - 1) + 1); + runner.firstname = faker.name.firstName(); + runner.lastname = faker.name.lastName(); + runner.id = Math.floor(Math.random() * (9999999 - 1) + 1); + runners.push(runner); + } + return runners; +} + +async function postContracts(runners: Runner[]): Promise { + const res = await axios.post(`${baseurl}/contracts`, runners); + return new Measurement("contract", runners.length, parseInt(res.headers['request-duration'])) +} + +async function testContracts(sizes): Promise { + let measurements = new Array(); + console.log("#### Testing contracts ####"); + + for (let size of sizes) { + const m = await postContracts(generateRunners(size)); + console.log(m.toString()); + measurements.push(m); + } + return measurements; +} + +async function main() { + const sizes = [0, 1, 10, 50, 100, 200, 500, 1000] + console.log("########### Speedtest ###########"); + console.log(`Document server version (according to the api): ${(await axios.get("http://localhost:4010/version")).data.version}`); + console.log("####### Running tests #######"); + const contractResults = await testContracts(sizes); + console.log("####### Results #######"); + console.table(contractResults); +} + +main(); + +class Measurement { + public type: string; + public inputcount: number; + public responsetime: number; + + constructor(type: string, input: number, time: number) { + this.type = type; + this.inputcount = input; + this.responsetime = time; + } + + public toString(): string { + return `It took ${this.responsetime}ms to generate ${this.inputcount} pdfs for the type ${this.type}.` + } } \ No newline at end of file -- 2.47.2 From 8a90f63b0919376beefef6a52aae9a59337aea59 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 18:38:04 +0000 Subject: [PATCH 20/28] =?UTF-8?q?=F0=9F=A7=BENew=20changelog=20file=20vers?= =?UTF-8?q?ion=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53e6a92..60a47c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,13 @@ All notable changes to this project will be documented in this file. Dates are displayed in UTC. -#### [v0.1.3](https://git.odit.services/lfk/document-server/compare/v0.2.0...v0.1.3) +#### [v0.2.0](https://git.odit.services/lfk/document-server/compare/v0.2.0...v0.2.0) -- Merge pull request 'Added speedtest feature/19-speed_test' (#23) from feature/19-speed_test into dev [`7ac8edb`](https://git.odit.services/lfk/document-server/commit/7ac8edb5cf4b7317a703faa32ded482a8c2b9b91) +- 🚀Bumped version to v0.2.0 [`491cdb8`](https://git.odit.services/lfk/document-server/commit/491cdb8d71a80ea196d16334c0c80b8f7cc859c5) - Implemented first experimental speedtest [`e3a45a6`](https://git.odit.services/lfk/document-server/commit/e3a45a61ac3b2d691c2f75d36155896b7ed301d8) +- 📖New license file version [CI SKIP] [skip ci] [`dbccbf6`](https://git.odit.services/lfk/document-server/commit/dbccbf68f4e22470b4fc93c894527cc78973e324) +- 🧾New changelog file version [CI SKIP] [skip ci] [`96204d8`](https://git.odit.services/lfk/document-server/commit/96204d809e852c1bcea808a9c8f5ca0f8475c87f) +- Merge pull request 'Added speedtest feature/19-speed_test' (#23) from feature/19-speed_test into dev [`7ac8edb`](https://git.odit.services/lfk/document-server/commit/7ac8edb5cf4b7317a703faa32ded482a8c2b9b91) - 🧾New changelog file version [CI SKIP] [skip ci] [`149bf18`](https://git.odit.services/lfk/document-server/commit/149bf1849db20b863ec998a72c77559ec401bc32) - Beautified output a bit [`aefe549`](https://git.odit.services/lfk/document-server/commit/aefe5493b06c04cc2b20029e1f7fc5f15ec9c04e) - Implemented runner generation using fakerjs [`0894446`](https://git.odit.services/lfk/document-server/commit/08944460854c78cd4368cf178b022c31b624c8d9) -- 2.47.2 From d38923c4ad3a2cf8872e236dd42f078e2a0e1045 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 9 Feb 2021 19:40:02 +0100 Subject: [PATCH 21/28] Added card generation speed tests (part 2) ref #14 --- src/tests/speedtest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/speedtest.ts b/src/tests/speedtest.ts index aefb2a1..0ed4372 100644 --- a/src/tests/speedtest.ts +++ b/src/tests/speedtest.ts @@ -56,11 +56,11 @@ function idToEan13(id): string { while (id.length < 12) { id = '0' + id; } let total = 0; - this.id.split('').forEach((letter, index) => { + id.split('').forEach((letter, index) => { total += parseInt(letter, 10) * multiply[index % 2]; }); const checkSum = (Math.ceil(total / 10) * 10) - total; - return this.id + checkSum.toString(); + return id + checkSum.toString(); } async function postContracts(runners: Runner[]): Promise { -- 2.47.2 From 9697d53a1527854536f8ddf5426f7ca902772f51 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 12 Feb 2021 17:06:20 +0100 Subject: [PATCH 22/28] Fixed bug in array swapping function ref #14 --- src/PdfCreator.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/PdfCreator.ts b/src/PdfCreator.ts index ce3d430..3b21eab 100644 --- a/src/PdfCreator.ts +++ b/src/PdfCreator.ts @@ -246,6 +246,10 @@ export class PdfCreator { return null; } - return [array[1], array[0]].concat(this.swapArrayPairs(array.slice(2))); + const rest = this.swapArrayPairs(array.slice(2)) + if (!rest) { + return [array[1], array[0]] + } + return [array[1], array[0]].concat(rest); } } \ No newline at end of file -- 2.47.2 From 68a1b8f3e0515e56c7c6069f7f3ef8db24c92674 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 12 Feb 2021 17:19:57 +0100 Subject: [PATCH 23/28] Implmented sponsoring image selection from array ref #14 --- src/PdfCreator.ts | 12 ++++++++++++ src/templates/runner_card.html | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/PdfCreator.ts b/src/PdfCreator.ts index 3b21eab..83b5b5f 100644 --- a/src/PdfCreator.ts +++ b/src/PdfCreator.ts @@ -14,6 +14,8 @@ import { Runner } from './models/Runner'; import { RunnerCard } from './models/RunnerCard'; import { RunnerGroup } from './models/RunnerGroup'; +const sponsors: string[] = ["https://odit.services/assets/img/profile-pic-no_bg.hash.0c81702a.png", "./sponsoringheader.png"] + /** * This class is responsible for all things pdf creation. * This uses the html templates from src/templates. @@ -87,6 +89,15 @@ export class PdfCreator { return i18next.t(str, PdfCreator.interpolations).toString(); } ); + await Handlebars.registerHelper('--sponsor', + function (str) { + const index = (parseInt(str) % sponsors.length); + if (isNaN(index)) { + return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==" + } + return sponsors[index]; + } + ); this.browser = await puppeteer.launch({ headless: true, args: minimal_args }); } @@ -140,6 +151,7 @@ export class PdfCreator { const template = Handlebars.compile(template_source); let result = template({ cards, cards_swapped, eventname: "LfK! 2069", codeformat: "qrcode" }) result = await awaitAsyncHandlebarHelpers(result); + fs.writeFileSync("lelelelele.tmp", result); const pdf = await this.renderPdf(result, { format: "A4", landscape: false }); return pdf } diff --git a/src/templates/runner_card.html b/src/templates/runner_card.html index 09f6eb8..69066c8 100644 --- a/src/templates/runner_card.html +++ b/src/templates/runner_card.html @@ -39,7 +39,7 @@
+ src="{{--sponsor this.id}}" />
@@ -59,7 +59,7 @@
+ src="{{--sponsor this.id}}" /> -- 2.47.2 From 08e858726c1462b599ba9cb3f7fb057f35178b83 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 12 Feb 2021 17:45:52 +0100 Subject: [PATCH 24/28] Fixed runnercard backside padding ref #14 --- src/templates/runner_card.html | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/templates/runner_card.html b/src/templates/runner_card.html index 69066c8..c85218e 100644 --- a/src/templates/runner_card.html +++ b/src/templates/runner_card.html @@ -56,13 +56,12 @@
{{#each cards_swapped}} -
+
- - - +
+ +
+
{{/each}}
-- 2.47.2 From 29376a7782ce39f04f856ec78775e65aa11f0ed7 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 12 Feb 2021 17:55:37 +0100 Subject: [PATCH 25/28] Now loading sponsor logos from env ref #14 --- src/PdfCreator.ts | 6 ++---- src/config.ts | 12 +++++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/PdfCreator.ts b/src/PdfCreator.ts index 83b5b5f..b48889e 100644 --- a/src/PdfCreator.ts +++ b/src/PdfCreator.ts @@ -14,8 +14,6 @@ import { Runner } from './models/Runner'; import { RunnerCard } from './models/RunnerCard'; import { RunnerGroup } from './models/RunnerGroup'; -const sponsors: string[] = ["https://odit.services/assets/img/profile-pic-no_bg.hash.0c81702a.png", "./sponsoringheader.png"] - /** * This class is responsible for all things pdf creation. * This uses the html templates from src/templates. @@ -91,11 +89,11 @@ export class PdfCreator { ); await Handlebars.registerHelper('--sponsor', function (str) { - const index = (parseInt(str) % sponsors.length); + const index = (parseInt(str) % config.sponor_logos.length); if (isNaN(index)) { return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==" } - return sponsors[index]; + return config.sponor_logos[index]; } ); this.browser = await puppeteer.launch({ headless: true, args: minimal_args }); diff --git a/src/config.ts b/src/config.ts index 8422d8d..6815cc2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,7 +8,8 @@ export const config = { eventname: process.env.EVENT_NAME || "Please set the event name", currency_symbol: process.env.CURRENCY_SYMBOL || "€", sponsoring_receipt_minimum_amount: process.env.SPONSORING_RECEIPT_MINIMUM_AMOUNT || "10", - codeformat: process.env.CODEFORMAT || "qrcode" + codeformat: process.env.CODEFORMAT || "qrcode", + sponor_logos: getSponsorLogos() } let errors = 0 if (typeof config.internal_port !== "number") { @@ -17,4 +18,13 @@ if (typeof config.internal_port !== "number") { if (typeof config.development !== "boolean") { errors++ } +function getSponsorLogos(): string[] { + try { + const logos = JSON.parse(process.env.SPONOR_LOGOS); + if (!Array.isArray(logos)) { throw new Error("Not an array.") } + return logos; + } catch (error) { + return ["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg=="]; + } +} export let e = errors \ No newline at end of file -- 2.47.2 From cf0f5839ee1e1b87f7b5bd5a299a35574fd1bb3c Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 12 Feb 2021 17:55:48 +0100 Subject: [PATCH 26/28] Added new env vars to readme ref #14 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 91dea08..7e77e25 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ The basic generation mechanism makes the templates and routes interchangeable (i | EVENT_NAME | String | "Please set the event name" | The event's name - used to generate pdf text. | CURRENCY_SYMBOL | String | "€" | The your currency's symbol - used to generate pdf text. | SPONSORING_RECEIPT_MINIMUM_AMOUNT | String | "10" | The mimimum total donation amount a sponsor has to donate to be able to receive a donation receipt - used to generate pdf text. +| SPONOR_LOGOS | Array | Empty png | The sponsor images you want to loop through. You can provide them via http url, local file or base64-encoded image. ## Templates > The document server uses html templates to generate various pdf documents. -- 2.47.2 From 449a96b3027fe93d8042b30420245f66e92f14b8 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 12 Feb 2021 18:00:42 +0100 Subject: [PATCH 27/28] =?UTF-8?q?=F0=9F=9A=80Bumped=20version=20to=20v0.3.?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e2fa293..141154f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@odit/lfk-document-server", - "version": "0.2.0", + "version": "0.3.0", "description": "The document generation server for the LfK! runner system. This generates certificates, sponsoring aggreements and more", "main": "src/app.ts", "scripts": { -- 2.47.2 From e74b9a4c9d041780e0cfd8c4d68a5b63f916e091 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Fri, 12 Feb 2021 17:01:30 +0000 Subject: [PATCH 28/28] =?UTF-8?q?=F0=9F=A7=BENew=20changelog=20file=20vers?= =?UTF-8?q?ion=20[CI=20SKIP]=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60a47c1..00ef120 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,19 +2,37 @@ All notable changes to this project will be documented in this file. Dates are displayed in UTC. -#### [v0.2.0](https://git.odit.services/lfk/document-server/compare/v0.2.0...v0.2.0) +#### [v0.3.0](https://git.odit.services/lfk/document-server/compare/v0.2.0...v0.3.0) +- 🚀Bumped version to v0.3.0 [`449a96b`](https://git.odit.services/lfk/document-server/commit/449a96b3027fe93d8042b30420245f66e92f14b8) +- Merge pull request 'Card generation feature/14-card_generation' (#24) from feature/14-card_generation into dev [`703eaa0`](https://git.odit.services/lfk/document-server/commit/703eaa0e9d667b628eab4e8496689fe66238f896) - 🚀Bumped version to v0.2.0 [`491cdb8`](https://git.odit.services/lfk/document-server/commit/491cdb8d71a80ea196d16334c0c80b8f7cc859c5) +- Added card generation speed tests (part 1) [`68572b1`](https://git.odit.services/lfk/document-server/commit/68572b194eb740238be8101efed6fdb2a207f65b) - Implemented first experimental speedtest [`e3a45a6`](https://git.odit.services/lfk/document-server/commit/e3a45a61ac3b2d691c2f75d36155896b7ed301d8) -- 📖New license file version [CI SKIP] [skip ci] [`dbccbf6`](https://git.odit.services/lfk/document-server/commit/dbccbf68f4e22470b4fc93c894527cc78973e324) -- 🧾New changelog file version [CI SKIP] [skip ci] [`96204d8`](https://git.odit.services/lfk/document-server/commit/96204d809e852c1bcea808a9c8f5ca0f8475c87f) -- Merge pull request 'Added speedtest feature/19-speed_test' (#23) from feature/19-speed_test into dev [`7ac8edb`](https://git.odit.services/lfk/document-server/commit/7ac8edb5cf4b7317a703faa32ded482a8c2b9b91) +- Added basic logic to generate two-sided runnercards [`d3a213c`](https://git.odit.services/lfk/document-server/commit/d3a213ce3326aeb96d924e16a31fc87bf82eb5b3) - 🧾New changelog file version [CI SKIP] [skip ci] [`149bf18`](https://git.odit.services/lfk/document-server/commit/149bf1849db20b863ec998a72c77559ec401bc32) +- Fixed double-sided printing [`7f58dd6`](https://git.odit.services/lfk/document-server/commit/7f58dd694b53152069c2095b2e18dd3a46cd04dd) +- Added basic card generation function [`8fc6c71`](https://git.odit.services/lfk/document-server/commit/8fc6c7176ee92f813db1e1d4b3e5ef1b2f4e1aef) - Beautified output a bit [`aefe549`](https://git.odit.services/lfk/document-server/commit/aefe5493b06c04cc2b20029e1f7fc5f15ec9c04e) +- Added barcode generatin [`5c075bc`](https://git.odit.services/lfk/document-server/commit/5c075bce8b94ff4482448c3cd56bdc28cbe0a7d9) - Implemented runner generation using fakerjs [`0894446`](https://git.odit.services/lfk/document-server/commit/08944460854c78cd4368cf178b022c31b624c8d9) +- Styled front [`016f746`](https://git.odit.services/lfk/document-server/commit/016f746c7cec29ab391b3918c7589dea0cff9890) +- Now loading sponsor logos from env [`29376a7`](https://git.odit.services/lfk/document-server/commit/29376a7782ce39f04f856ec78775e65aa11f0ed7) +- Implmented sponsoring image selection from array [`68a1b8f`](https://git.odit.services/lfk/document-server/commit/68a1b8f3e0515e56c7c6069f7f3ef8db24c92674) +- 📖New license file version [CI SKIP] [skip ci] [`dbccbf6`](https://git.odit.services/lfk/document-server/commit/dbccbf68f4e22470b4fc93c894527cc78973e324) +- Added cards api endpoint [`929ac81`](https://git.odit.services/lfk/document-server/commit/929ac81515b3b426ff06f1d6d913bab930421a92) +- 🧾New changelog file version [CI SKIP] [skip ci] [`96204d8`](https://git.odit.services/lfk/document-server/commit/96204d809e852c1bcea808a9c8f5ca0f8475c87f) +- Fixed runnercard backside padding [`08e8587`](https://git.odit.services/lfk/document-server/commit/08e858726c1462b599ba9cb3f7fb057f35178b83) +- Added sizing for the real cards [`b92a6f7`](https://git.odit.services/lfk/document-server/commit/b92a6f7b2b98fb0074d5a563d9918295e9ec0274) +- 🧾New changelog file version [CI SKIP] [skip ci] [`8a90f63`](https://git.odit.services/lfk/document-server/commit/8a90f63b0919376beefef6a52aae9a59337aea59) - Added speedtest script to package [`75b8b28`](https://git.odit.services/lfk/document-server/commit/75b8b281b87d9b173093f16beae12d707ec05052) +- Fixed bug in array swapping function [`9697d53`](https://git.odit.services/lfk/document-server/commit/9697d53a1527854536f8ddf5426f7ca902772f51) +- Added **very** basic backside [`68f46a4`](https://git.odit.services/lfk/document-server/commit/68f46a45b5a51c8a8edafca852cb274af388fa76) +- Added card generation speed tests (part 2) [`d38923c`](https://git.odit.services/lfk/document-server/commit/d38923c4ad3a2cf8872e236dd42f078e2a0e1045) - Implemented basic contracts tests in various sizes [`a1b0a19`](https://git.odit.services/lfk/document-server/commit/a1b0a1918db552eb385fedcbaa576ad493a1d605) - tmp [`0d27916`](https://git.odit.services/lfk/document-server/commit/0d27916188114fa41e666170135de2b714ff113a) +- Added new env vars to readme [`cf0f583`](https://git.odit.services/lfk/document-server/commit/cf0f5839ee1e1b87f7b5bd5a299a35574fd1bb3c) +- Merge pull request 'Added speedtest feature/19-speed_test' (#23) from feature/19-speed_test into dev [`7ac8edb`](https://git.odit.services/lfk/document-server/commit/7ac8edb5cf4b7317a703faa32ded482a8c2b9b91) #### [v0.2.0](https://git.odit.services/lfk/document-server/compare/v0.1.3...v0.2.0) -- 2.47.2