Merge pull request 'Release 0.5.0' (#42) from dev into main
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details

Reviewed-on: #42
Reviewed-by: Philipp Dormann <philipp@philippdormann.de>
This commit is contained in:
Nicolai Ort 2021-03-31 18:15:32 +00:00
commit a81db03ba3
14 changed files with 379 additions and 82 deletions

View File

@ -2,9 +2,46 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [v0.5.0](https://git.odit.services/lfk/document-server/compare/v0.4.3...v0.5.0)
- Added translations [`ac572f1`](https://git.odit.services/lfk/document-server/commit/ac572f1ea31cb66985e04cb5d56cc67f521e990d)
- Added translations [`7fea1ca`](https://git.odit.services/lfk/document-server/commit/7fea1ca78ff6fdbb38dee0edd9918eaeb1264d18)
- Sorted translations 🌍 [`2278e4a`](https://git.odit.services/lfk/document-server/commit/2278e4ad06947b540323856ea1e71022562ea719)
- Added front certificate design [`8b71608`](https://git.odit.services/lfk/document-server/commit/8b71608792f00084df1e71956e503f102cea290d)
- 📖New license file version [CI SKIP] [skip ci] [`3fc6124`](https://git.odit.services/lfk/document-server/commit/3fc612488d1f231d83d6a5823a13dc4817e6a588)
- Addest first coupple of test improvements [`a580841`](https://git.odit.services/lfk/document-server/commit/a5808419738563fec3a7d8d35f4ce20d76c017fb)
- Pinned depencencies (and bumped some) [`479e28c`](https://git.odit.services/lfk/document-server/commit/479e28c46c6b3b8ba1622bcf5712695a94c2ae89)
- Added new basic certificate endpoint [`0af9b81`](https://git.odit.services/lfk/document-server/commit/0af9b81b38e1c28261c012375af2c91808e65621)
- Added function for generateing runner certificates [`955e118`](https://git.odit.services/lfk/document-server/commit/955e11846b5385c1a0b6f0b54b9951f0768ff414)
- 🧾New changelog file version [CI SKIP] [skip ci] [`f220e70`](https://git.odit.services/lfk/document-server/commit/f220e70743534c1fc66ff6f50e3693182d35990a)
- Now formatting currency ans distance [`e0add84`](https://git.odit.services/lfk/document-server/commit/e0add846bb37b435da9807bdc76c70793002896e)
- Fixed bg image opacity overlay [`8d6ea4d`](https://git.odit.services/lfk/document-server/commit/8d6ea4dbf9763994f0f44c4ad9b32a7b1d16f11a)
- Pinned dev dependencies [`82159be`](https://git.odit.services/lfk/document-server/commit/82159bed536bbafd20746927f5a7f61f76959637)
- Now calculateing total donations (perdistance) [`6b23dea`](https://git.odit.services/lfk/document-server/commit/6b23dea47745e98371a65a4f577f2e20cfdfe597)
- Added backside table [`3ca2237`](https://git.odit.services/lfk/document-server/commit/3ca22379535bba72d05e0b3fafe22d3a4b2f549d)
- Added template strings [`6767c3b`](https://git.odit.services/lfk/document-server/commit/6767c3b2d1e991e2f4f74b8d423a72e240ffcb8c)
- Added template strings [`2b21957`](https://git.odit.services/lfk/document-server/commit/2b2195727b15b8666edf0d925f2e68a98030153d)
- Fixed background opacity [`2a4cfdb`](https://git.odit.services/lfk/document-server/commit/2a4cfdb2f88ad3ac1ebc925199a440756e9e9d3a)
- Now with embedded background [`64fce5b`](https://git.odit.services/lfk/document-server/commit/64fce5bd019a00bf34c1ebd133c1904bb577b67b)
- Made footer text configureable [`63c7beb`](https://git.odit.services/lfk/document-server/commit/63c7beb8b9cdc564186c5b86a4f305c8575f5b9f)
- 🚀Bumped version to v0.5.0 [`f623c0a`](https://git.odit.services/lfk/document-server/commit/f623c0a7cd06f707ac488456c9e8a051d3ceae46)
- Merge pull request 'Generate runner certificates feature/36-runner_certificates' (#41) from feature/36-runner_certificates into dev [`d3f7d1a`](https://git.odit.services/lfk/document-server/commit/d3f7d1a6c9858d7fdf09c696622962e6f8471e78)
- disabled testing for now [`cec8930`](https://git.odit.services/lfk/document-server/commit/cec893032dea9f312e37841232a9434e19b79003)
- Added missing interpolations [`b43aeec`](https://git.odit.services/lfk/document-server/commit/b43aeec0cf40a9c37a10072062ab5d93102f6c81)
- 🧾New changelog file version [CI SKIP] [skip ci] [`f1084b5`](https://git.odit.services/lfk/document-server/commit/f1084b59a74dcc5981fd314721c36726706f386c)
- disabled testing for now [`e75f151`](https://git.odit.services/lfk/document-server/commit/e75f15142e293349a071a7cdcc53cc10780304f6)
- Removed temporary background-image fix [`5ba26c4`](https://git.odit.services/lfk/document-server/commit/5ba26c4cbfae7d3f31d3709aaeb372c14de78fa9)
- Fixed page size+background image [`b82a32a`](https://git.odit.services/lfk/document-server/commit/b82a32ae3ee3256402be5dde0ada903f2c19a8cc)
- Fixed typo [`1d12de7`](https://git.odit.services/lfk/document-server/commit/1d12de7045b5e8324dc0ddc421944e70ffc2ec73)
- Documented new env var [`5a98688`](https://git.odit.services/lfk/document-server/commit/5a98688d60eed34644391ecde638949fe5a46c65)
#### [v0.4.3](https://git.odit.services/lfk/document-server/compare/v0.4.2...v0.4.3)
> 30 March 2021
- Merge pull request 'Release 0.4.3' (#40) from dev into main [`c8dc998`](https://git.odit.services/lfk/document-server/commit/c8dc998ecdccc7fc4348ecc0db552a3d7bc2eb52)
- 🧾New changelog file version [CI SKIP] [skip ci] [`289a0d8`](https://git.odit.services/lfk/document-server/commit/289a0d8671575dda911c64f79d24726d3bbee071)
- 🧾New changelog file version [CI SKIP] [skip ci] [`3df3d26`](https://git.odit.services/lfk/document-server/commit/3df3d26708aab12590cd9c1f697cfdea8017ace4)
- 🧾New changelog file version [CI SKIP] [skip ci] [`457ea26`](https://git.odit.services/lfk/document-server/commit/457ea26cf8124009084415d12c7a0e31912a3eb1)
- 🚀Bumped version to v0.4.3 [`c3beb3e`](https://git.odit.services/lfk/document-server/commit/c3beb3e1032492f9a8304c4b099a700ad0d1d2cf)
- Pipeline mtu fix [`c2d2b66`](https://git.odit.services/lfk/document-server/commit/c2d2b66f2f6fbd30c2027fd3dab393db5219eb44)

View File

@ -37,6 +37,7 @@ The basic generation mechanism makes the templates and routes interchangeable (i
| SPONOR_LOGOS | Array<String> | Empty png | The sponsor images you want to loop through. You can provide them via http url, local file or base64-encoded image.
| API_KEY | String(min length: 64) | Random generated string | The api key you want to use for auth (query-param `key`), has to be at least 64 chars long.
| DISCLAIMER_TEXT | String | N/A | A disclaimer that will get displayed on the bottom of each sponsoring contract. R/N You can only provide the disclaimer for one language.
| DONATIONS_FOOTER_TEXT | String | N/A | A text that will get displayed on the bottom of each runner certificate's second page. R/N You can only provide the text for one language.
| CONTRACTS_PER_RUNNER | Number | 1 | The amount of contracts that get created per runner (per request).
## Templates

View File

@ -1,6 +1,6 @@
# @odit/class-validator-jsonschema
**Author**: Aleksi Pekkala <aleksipekkala@gmail.com>
**Repo**: git@github.com:epiphone/class-validator-jsonschema.git
**Repo**: git@github.com:epiphone/class-validator-jsonschema
**License**: MIT
**Description**: Convert class-validator-decorated classes into JSON schema
## License Text
@ -29,7 +29,7 @@ SOFTWARE.
# async-helpers
**Author**: Brian Woodward (https://github.com/doowb)
**Repo**: doowb/async-helpers
**Repo**: https://github.com/doowb/async-helpers
**License**: MIT
**Description**: Use async helpers in templates with engines that typically only handle sync helpers. Handlebars and Lodash have been tested.
## License Text
@ -58,7 +58,7 @@ THE SOFTWARE.
# axios
**Author**: Matt Zabriskie
**Repo**: https://github.com/axios/axios.git
**Repo**: https://github.com/axios/axios
**License**: MIT
**Description**: Promise based HTTP client for the browser and node.js
## License Text
@ -85,7 +85,7 @@ THE SOFTWARE.
# bwip-js
**Author**: Mark Warren <mwarren@metafloor.com>
**Repo**: https://github.com/metafloor/bwip-js.git
**Repo**: https://github.com/metafloor/bwip-js
**License**: MIT
**Description**: JavaScript barcode generator supporting over 100 types and standards.
## License Text
@ -117,7 +117,7 @@ THE SOFTWARE.
# cheerio
**Author**: Matt Mueller <mattmuelle@gmail.com> (mat.io)
**Repo**: git://github.com/cheeriojs/cheerio.git
**Repo**: https://github.comcheeriojs/cheerio
**License**: MIT
**Description**: Tiny, fast, and elegant implementation of core jQuery designed specifically for the server
## License Text
@ -144,8 +144,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# class-transformer
**Author**: [object Object]
**Repo**: https://github.com/typestack/class-transformer.git
**Author**: Umed Khudoiberdiev
**Repo**: https://github.com/typestack/class-transformer
**License**: MIT
**Description**: Proper decorator-based transformation / serialization / deserialization of plain javascript objects to class constructors
## License Text
@ -173,7 +173,7 @@ THE SOFTWARE.
# class-validator
**Author**: TypeStack contributors
**Repo**: https://github.com/typestack/class-validator.git
**Repo**: https://github.com/typestack/class-validator
**License**: MIT
**Description**: Decorator-based property validation for classes.
## License Text
@ -201,7 +201,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# consola
**Author**: undefined
**Author**: ?
**Repo**: nuxt/consola
**License**: MIT
**Description**: Elegant Console Logger for Node.js and Browser
@ -239,8 +239,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# dotenv
**Author**: undefined
**Repo**: git://github.com/motdotla/dotenv.git
**Author**: ?
**Repo**: https://github.commotdotla/dotenv
**License**: BSD-2-Clause
**Description**: Loads environment variables from .env file
## License Text
@ -303,7 +303,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# handlebars
**Author**: Yehuda Katz
**Repo**: https://github.com/wycats/handlebars.js.git
**Repo**: https://github.com/wycats/handlebars.js
**License**: MIT
**Description**: Handlebars provides the power necessary to let you build semantic templates effectively with no frustration
## License Text
@ -330,7 +330,7 @@ THE SOFTWARE.
# i18next
**Author**: Jan Mühlemann <jan.muehlemann@gmail.com> (https://github.com/jamuhl)
**Repo**: https://github.com/i18next/i18next.git
**Repo**: https://github.com/i18next/i18next
**License**: MIT
**Description**: i18next internationalization framework
## License Text
@ -358,15 +358,15 @@ SOFTWARE.
# i18next-fs-backend
**Author**: undefined
**Repo**: git@github.com:i18next/i18next-fs-backend.git
**Author**: ?
**Repo**: git@github.com:i18next/i18next-fs-backend
**License**: undefined
**Description**: i18next-fs-backend is a backend layer for i18next using in Node.js and for Deno to load translations from the filesystem.
## License Text
# mime-types
**Author**: undefined
**Author**: ?
**Repo**: jshttp/mime-types
**License**: MIT
**Description**: The ultimate javascript content-type utility.
@ -398,7 +398,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# pdf-lib
**Author**: Andrew Dillon <andrew.dillon.j@gmail.com>
**Repo**: git+https://github.com/Hopding/pdf-lib.git
**Repo**: git+https://github.com/Hopding/pdf-lib
**License**: MIT
**Description**: Create and modify PDF files with JavaScript
## License Text
@ -427,7 +427,7 @@ SOFTWARE.
# puppeteer
**Author**: The Chromium Authors
**Repo**: github:puppeteer/puppeteer
**Repo**: https://github.com/puppeteer/puppeteer
**License**: Apache-2.0
**Description**: A high-level API to control headless Chrome over the DevTools Protocol
## License Text
@ -636,8 +636,8 @@ SOFTWARE.
# reflect-metadata
**Author**: [object Object]
**Repo**: https://github.com/rbuckton/reflect-metadata.git
**Author**: Ron Buckton
**Repo**: https://github.com/rbuckton/reflect-metadata
**License**: Apache-2.0
**Description**: Polyfill for Metadata Reflection API
## License Text
@ -698,8 +698,8 @@ If the Work includes a "NOTICE" text file as part of its distribution, then any
END OF TERMS AND CONDITIONS
# routing-controllers
**Author**: [object Object]
**Repo**: https://github.com/typestack/routing-controllers.git
**Author**: Umed Khudoiberdiev
**Repo**: https://github.com/typestack/routing-controllers
**License**: MIT
**Description**: Create structured, declarative and beautifully organized class-based controllers with heavy decorators usage for Express / Koa using TypeScript.
## License Text
@ -762,8 +762,8 @@ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# @types/express
**Author**: undefined
**Repo**: https://github.com/DefinitelyTyped/DefinitelyTyped.git
**Author**: ?
**Repo**: https://github.com/DefinitelyTyped/DefinitelyTyped
**License**: MIT
**Description**: TypeScript definitions for Express
## License Text
@ -791,8 +791,8 @@ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# @types/node
**Author**: undefined
**Repo**: https://github.com/DefinitelyTyped/DefinitelyTyped.git
**Author**: ?
**Repo**: https://github.com/DefinitelyTyped/DefinitelyTyped
**License**: MIT
**Description**: TypeScript definitions for Node.js
## License Text
@ -820,8 +820,8 @@ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# @types/puppeteer
**Author**: undefined
**Repo**: https://github.com/DefinitelyTyped/DefinitelyTyped.git
**Author**: ?
**Repo**: https://github.com/DefinitelyTyped/DefinitelyTyped
**License**: MIT
**Description**: TypeScript definitions for puppeteer
## License Text
@ -849,8 +849,8 @@ OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# cp-cli
**Author**: undefined
**Repo**: git+https://github.com/screendriver/cp-cli.git
**Author**: ?
**Repo**: https://github.com/screendriver/cp-cli
**License**: MIT
**Description**: A 'cp' CLI util for Node.js
## License Text
@ -878,16 +878,16 @@ SOFTWARE.
# faker
**Author**: undefined
**Repo**: http://github.com/Marak/Faker.js.git
**Author**: ?
**Repo**: http://github.com/Marak/Faker.js
**License**: MIT
**Description**: Generate massive amounts of fake contextual data
## License Text
# nodemon
**Author**: [object Object]
**Repo**: https://github.com/remy/nodemon.git
**Author**: Remy Sharp
**Repo**: https://github.com/remy/nodemon
**License**: MIT
**Description**: Simple monitor script for use during development of a node.js app.
## License Text
@ -915,8 +915,8 @@ SOFTWARE.
# release-it
**Author**: [object Object]
**Repo**: https://github.com/release-it/release-it.git
**Author**: Lars Kappert
**Repo**: https://github.com/release-it/release-it
**License**: MIT
**Description**: Generic CLI tool to automate versioning and package publishing related tasks.
## License Text
@ -945,7 +945,7 @@ SOFTWARE.
# rimraf
**Author**: Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)
**Repo**: git://github.com/isaacs/rimraf.git
**Repo**: git://github.com/isaacs/rimraf
**License**: ISC
**Description**: A deep deletion module for node (like `rm -rf`)
## License Text
@ -968,15 +968,15 @@ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# start-server-and-test
**Author**: Gleb Bahmutov <gleb.bahmutov@gmail.com>
**Repo**: https://github.com/bahmutov/start-server-and-test.git
**Repo**: https://github.com/bahmutov/start-server-and-test
**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**: git://github.com/TypeStrong/ts-node.git
**Author**: Blake Embrey
**Repo**: https://github.comTypeStrong/ts-node
**License**: MIT
**Description**: TypeScript execution environment and REPL for node.js, with source map support
## License Text
@ -1005,7 +1005,7 @@ THE SOFTWARE.
# typescript
**Author**: Microsoft Corp.
**Repo**: https://github.com/Microsoft/TypeScript.git
**Repo**: https://github.com/Microsoft/TypeScript
**License**: Apache-2.0
**Description**: TypeScript is a language for application scale JavaScript development
## License Text

View File

@ -1,6 +1,6 @@
{
"name": "@odit/lfk-document-server",
"version": "0.4.3",
"version": "0.5.0",
"description": "The document generation server for the LfK! runner system. This generates certificates, sponsoring aggreements and more",
"main": "src/app.ts",
"scripts": {
@ -8,9 +8,7 @@
"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",
"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"
"translations:sort": "node sort_translations.js"
},
"repository": {
"type": "git",
@ -41,40 +39,40 @@
],
"license": "CC-BY-NC-SA-4.0",
"dependencies": {
"@odit/class-validator-jsonschema": "^2.1.1",
"async-helpers": "^0.3.17",
"axios": "^0.21.1",
"bwip-js": "^2.0.12",
"cheerio": "^1.0.0-rc.5",
"@odit/class-validator-jsonschema": "2.1.1",
"async-helpers": "0.3.17",
"axios": "0.21.1",
"bwip-js": "2.1.1",
"cheerio": "1.0.0-rc.5",
"class-transformer": "0.3.1",
"class-validator": "^0.13.1",
"consola": "^2.15.0",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"handlebars": "^4.7.6",
"i18next": "^19.8.7",
"i18next-fs-backend": "^1.0.8",
"mime-types": "^2.1.28",
"pdf-lib": "^1.16.0",
"puppeteer": "^7.0.1",
"reflect-metadata": "^0.1.13",
"class-validator": "0.13.1",
"consola": "2.15.3",
"cors": "2.8.5",
"dotenv": "8.2.0",
"express": "4.17.1",
"handlebars": "4.7.7",
"i18next": "20.1.0",
"i18next-fs-backend": "1.1.1",
"mime-types": "2.1.29",
"pdf-lib": "1.16.0",
"puppeteer": "8.0.0",
"reflect-metadata": "0.1.13",
"routing-controllers": "0.9.0-alpha.6",
"routing-controllers-openapi": "2.2.0"
},
"devDependencies": {
"@odit/license-exporter": "^0.0.10",
"@types/express": "^4.17.11",
"@types/node": "^14.14.22",
"@types/puppeteer": "^5.4.3",
"cp-cli": "^2.0.0",
"faker": "^5.3.1",
"nodemon": "^2.0.7",
"@odit/license-exporter": "0.0.11",
"@types/express": "4.17.11",
"@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",
"start-server-and-test": "^1.12.0",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
"rimraf": "3.0.2",
"start-server-and-test": "1.12.0",
"ts-node": "9.1.1",
"typescript": "4.1.3"
},
"release-it": {
"git": {

View File

@ -10,6 +10,7 @@ import { PDFDocument } from 'pdf-lib';
import puppeteer from "puppeteer";
import { awaitAsyncHandlebarHelpers, helpers } from './asyncHelpers';
import { config } from './config';
import { CertificateRunner } from './models/CertificateRunner';
import { Runner } from './models/Runner';
import { RunnerCard } from './models/RunnerCard';
import { RunnerGroup } from './models/RunnerGroup';
@ -97,6 +98,18 @@ export class PdfCreator {
return config.sponor_logos[index];
}
);
await Handlebars.registerHelper('--format_kilometers',
function (str) {
let meters = parseInt(str);
return ((meters / 1000).toFixed(3).toString())
}
);
await Handlebars.registerHelper('--format_currency',
function (str) {
let meters = parseInt(str);
return ((meters / 100).toFixed(2).toString())
}
);
this.browser = await puppeteer.launch({ headless: true, args: minimal_args });
}
@ -153,13 +166,37 @@ export class PdfCreator {
await i18next.changeLanguage(locale);
const template_source = fs.readFileSync(`${this.templateDir}/runner_card.html`, 'utf8');
const template = Handlebars.compile(template_source);
let result = template({ cards, cards_swapped, eventname: "LfK! 2069", codeformat: "qrcode" })
let result = template({ cards, cards_swapped, eventname: config.eventname, codeformat: codeformat })
result = await awaitAsyncHandlebarHelpers(result);
fs.writeFileSync("lelelelele.tmp", result);
const pdf = await this.renderPdf(result, { format: "A4", landscape: false });
return pdf
}
/**
* 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 generateRunnerCertficates(runners: CertificateRunner[], locale: string = "en"): Promise<Buffer> {
if (runners.length > 50) {
let pdf_promises = new Array<Promise<Buffer>>();
let i, j;
for (i = 0, j = runners.length; i < j; i += 50) {
let chunk = runners.slice(i, i + 50);
pdf_promises.push(this.generateRunnerCertficates(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_certificate.html`, 'utf8');
const template = Handlebars.compile(template_source);
let result = template({ runners, eventname: config.eventname, currency_symbol: config.currency_symbol, donations_footer_text: config.donations_footer_text });
result = await awaitAsyncHandlebarHelpers(result);
const pdf = await this.renderPdf(result, { format: "A4", landscape: false, printBackground: true });
return pdf;
}
/**
* Converts all images in html to base64.
* Works with image files in the template directory or images from urls.
@ -167,6 +204,7 @@ export class PdfCreator {
*/
public async imgToBase64(html): Promise<string> {
const $ = cheerio.load(html)
$('img').each(async (index, element) => {
let imgsrc = $(element).attr("src");
if (imgsrc.startsWith("data:image")) {
@ -192,7 +230,7 @@ export class PdfCreator {
image = `data:${img_type};base64,${image}`
$(element).attr("src", image)
})
});
return $.html();
}

View File

@ -13,6 +13,7 @@ export const config = {
sponor_logos: getSponsorLogos(),
api_key: getApiKey(),
disclaimer_text: process.env.DISCLAIMER_TEXT || "",
donations_footer_text: process.env.DONATIONS_FOOTER_TEXT || "",
contracts_per_runner: parseInt(process.env.CONTRACTS_PER_RUNNER) || 1,
}
let errors = 0

View File

@ -1,5 +1,6 @@
import { Authorized, Body, JsonController, Post, QueryParam, Res } from 'routing-controllers';
import { OpenAPI } from 'routing-controllers-openapi';
import { CertificateRunner } from '../models/CertificateRunner';
import { Runner } from '../models/Runner';
import { RunnerCard } from '../models/RunnerCard';
import { PdfCreator } from '../PdfCreator';
@ -54,6 +55,25 @@ export class PdfController {
return contracts;
}
@Post('/certificates')
@OpenAPI({ description: "Generate runner certificate pdfs from certificate runner objects.<br>You can choose your prefered locale by passing the 'locale' query-param.<br> 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 generateCertificates(@Body({ validate: true, options: { limit: "500mb" } }) runners: CertificateRunner[], @Res() res: any, @QueryParam("locale") locale: string, @QueryParam("download") download: boolean) {
if (!this.initialized) {
await this.pdf.init();
this.initialized = true;
}
if (!Array.isArray(runners)) {
runners = [runners];
}
runners = this.mapCertificatRunnersGroupNames(runners)
const certificates = await this.pdf.generateRunnerCertficates(runners, locale);
res.setHeader('content-type', 'application/pdf');
if (download) {
res.setHeader('Content-Disposition', 'attachment; filename="certificates.pdf"')
}
return certificates;
}
private mapRunnerGroupNames(runners: Runner[]): Runner[] {
let response = new Array<Runner>();
for (let runner of runners) {
@ -68,6 +88,26 @@ export class PdfController {
return response;
}
private mapCertificatRunnersGroupNames(runners: CertificateRunner[]): CertificateRunner[] {
let response = new Array<CertificateRunner>();
for (let runner of runners) {
if (!runner.group.parentGroup) {
runner.group.fullName = runner.group.name;
}
else {
runner.group.fullName = `${runner.group.parentGroup.name}/${runner.group.name}`;
}
runner.donationPerDistanceTotal = runner.distanceDonations.reduce(function (sum, current) {
return sum + current.amountPerDistance;
}, 0);
runner.donationTotal = runner.distanceDonations.reduce(function (sum, current) {
return sum + current.amount;
}, 0);
response.push(runner)
}
return response;
}
private mapCardGroupNames(cards: RunnerCard[]): RunnerCard[] {
let response = new Array<RunnerCard>();
for (let card of cards) {

View File

@ -1,9 +1,14 @@
{
"address": "Adresse",
"betrag-km": "Betrag/KM",
"city": "Stadt",
"date": "Datum",
"firstname": "Vorname",
"fuer-den-guten-zweck-zurueckgelegt": "für den guten Zweck zurückgelegt",
"gesamt": "Gesamt",
"gesamtbetrag": "Gesamtbetrag",
"group": "Team/Klasse",
"hat-beim-eventname": "Hat beim {{eventname}}",
"house_number": "Hausnummer",
"id": "ID",
"lastname": "Nachname",
@ -12,9 +17,12 @@
"postalcode": "Postleitzahl",
"signature": "Unterschrift",
"sponsor": "Sponsor",
"sponsor-in": "Sponsor:in",
"sponsoring_address_condition": "Muss ausgefüllt werden, wenn Sie eine Spendenquittung benötigen - Spendenquittungen können erst ab einem Gesamtbetrag von {{sponsoring_receipt_minimum_amount}}{{currency_symbol}} ausgestellt werden",
"sponsoring_amount_per_distance": "mit einem Betrag von _____{{currency_symbol}} pro gelaufenem Kilometer zu unterstützen.",
"sponsoring_subtitle": "Ich/Wir sind bereit anlässlich des {{eventname}}",
"sponsoring_title": "Sponsoringerklärung",
"street": "Straße"
"sponsorings": "Sponsorings",
"street": "Straße",
"urkunde": "Urkunde"
}

View File

@ -1,19 +1,28 @@
{
"address": "Address",
"betrag-km": "Amount/KM",
"city": "City",
"date": "date",
"firstname": "First name",
"fuer-den-guten-zweck-zurueckgelegt": "for our good cuse at the {{eventname}}",
"gesamt": "Combined",
"gesamtbetrag": "Total",
"group": "Team/class",
"hat-beim-eventname": "Ran",
"house_number": "House number",
"id": "ID",
"lastname": "Last name",
"location": "Location",
"please_use_blockletters": "Please write in BLOCK LETTERS.",
"postalcode": "Postal code",
"signature": "Signature",
"sponsor": "sponsor",
"sponsor-in": "Donor",
"sponsoring_address_condition": "You have to provide an address if you want a donation receipt - Donation receipts can't be issued for total donation amounts under {{sponsoring_receipt_minimum_amount}}{{currency_symbol}}",
"sponsoring_amount_per_distance": "with the amount of _____{{currency_symbol}} per kilometer run.",
"sponsoring_subtitle": "On the ocation of the {{eventname}} I/We want to support",
"sponsoring_title": "Sponsoring contract",
"street": "Street"
"sponsorings": "Donations",
"street": "Street",
"urkunde": "Certifcate"
}

View File

@ -1,5 +1,5 @@
import {
IsArray
IsArray, IsNumber, IsOptional
} from "class-validator";
import { DistanceDonation } from './DistanceDonation';
import { Runner } from './Runner';
@ -13,4 +13,13 @@ export class CertificateRunner extends Runner {
*/
@IsArray()
distanceDonations: DistanceDonation[];
@IsNumber()
@IsOptional()
donationPerDistanceTotal?: number = 0;
@IsNumber()
@IsOptional()
donationTotal?: number = 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

View File

@ -1,10 +1,15 @@
import axios from "axios"
import faker from "faker"
import { config } from '../config'
import { CertificateRunner } from '../models/CertificateRunner'
import { DistanceDonation } from '../models/DistanceDonation'
import { Donor } from '../models/Donor'
import { Runner } from '../models/Runner'
import { RunnerCard } from '../models/RunnerCard'
import { RunnerGroup } from '../models/RunnerGroup'
const baseurl = "http://localhost:4010"
const key = config.api_key;
axios.interceptors.request.use((config) => {
config.headers['request-startTime'] = process.hrtime()
@ -46,6 +51,36 @@ function generateCards(amount: number): RunnerCard[] {
return cards;
}
function generateCertificateRunners(amount: number): CertificateRunner[] {
let runners: CertificateRunner[] = new Array<CertificateRunner>();
let group = new RunnerGroup();
let runner = new CertificateRunner();
let donor = new Donor();
let donation = new DistanceDonation();
for (var i = 0; i < amount; i++) {
group.name = faker.company.bsBuzz();
group.id = Math.floor(Math.random() * (9999999 - 1) + 1);
donor.firstname = faker.name.firstName();
donor.lastname = faker.name.lastName();
donor.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);
runner.distance = Math.floor(Math.random() * (9999999 - 1) + 1);
donation.id = Math.floor(Math.random() * (9999999 - 1) + 1);
donation.donor = donor;
donation.runner = runner;
donation.amountPerDistance = Math.floor(Math.random() * (10000 - 1) + 1);
runner.distanceDonations = [donation, donation]
runners.push(runner);
}
return runners;
}
function idToEan13(id): string {
const multiply = [1, 3];
id = id.toString();
@ -64,15 +99,20 @@ function idToEan13(id): string {
}
async function postContracts(runners: Runner[]): Promise<Measurement> {
const res = await axios.post(`${baseurl}/contracts`, runners);
const res = await axios.post(`${baseurl}/contracts?key=${key}`, runners);
return new Measurement("contract", runners.length, parseInt(res.headers['request-duration']))
}
async function postCards(cards: RunnerCard[]): Promise<Measurement> {
const res = await axios.post(`${baseurl}/cards`, cards);
const res = await axios.post(`${baseurl}/cards?key=${key}`, cards);
return new Measurement("card", cards.length, parseInt(res.headers['request-duration']))
}
async function postCertificates(runners: CertificateRunner[]): Promise<Measurement> {
const res = await axios.post(`${baseurl}/certificates?key=${key}`, runners);
return new Measurement("certificate", runners.length, parseInt(res.headers['request-duration']))
}
async function testContracts(sizes): Promise<Measurement[]> {
let measurements = new Array<Measurement>();
console.log("#### Testing contracts ####");
@ -97,16 +137,30 @@ async function testCards(sizes): Promise<Measurement[]> {
return measurements;
}
async function testCertificates(sizes): Promise<Measurement[]> {
let measurements = new Array<Measurement>();
console.log("#### Testing Certificates ####");
for (let size of sizes) {
const m = await postCertificates(generateCertificateRunners(size));
console.log(m.toString());
measurements.push(m);
}
return measurements;
}
async function main() {
const sizes = [0, 1, 10, 50, 100, 200, 500, 1000]
const sizes = [1, 10, 50, 100]
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);
const certificateResults = await testCertificates(sizes);
console.log("####### Results #######");
console.table(contractResults);
console.table(cardResults);
console.table(certificateResults);
}
main();