initial implementation
This commit is contained in:
		
							
								
								
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | .nogit/ | ||||||
|  | node_modules/ | ||||||
|  | assets/pdfdir/ | ||||||
|  | coverage/ | ||||||
|  | public/ | ||||||
|  | pages/ | ||||||
|  | .yarn/ | ||||||
							
								
								
									
										147
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | |||||||
|  | # gitzone standard | ||||||
|  | image: hosttoday/ht-docker-node:npmci | ||||||
|  |  | ||||||
|  | cache: | ||||||
|  |   paths: | ||||||
|  |   - .npmci_cache/ | ||||||
|  |   key: "$CI_BUILD_STAGE" | ||||||
|  |  | ||||||
|  | stages: | ||||||
|  | - security | ||||||
|  | - test | ||||||
|  | - release | ||||||
|  | - metadata | ||||||
|  |  | ||||||
|  | # ==================== | ||||||
|  | # security stage | ||||||
|  | # ==================== | ||||||
|  | mirror: | ||||||
|  |   stage: security | ||||||
|  |   script: | ||||||
|  |   - npmci git mirror | ||||||
|  |   tags: | ||||||
|  |   - docker | ||||||
|  |   - notpriv | ||||||
|  |  | ||||||
|  | snyk: | ||||||
|  |   stage: security | ||||||
|  |   script: | ||||||
|  |     - npmci npm prepare | ||||||
|  |     - npmci command npm install -g snyk | ||||||
|  |     - npmci command npm install --ignore-scripts | ||||||
|  |     - npmci command snyk test | ||||||
|  |   tags: | ||||||
|  |   - docker | ||||||
|  |   - notpriv | ||||||
|  |  | ||||||
|  | # ==================== | ||||||
|  | # test stage | ||||||
|  | # ==================== | ||||||
|  | testLEGACY: | ||||||
|  |   stage: test | ||||||
|  |   script: | ||||||
|  |   - npmci npm prepare | ||||||
|  |   - npmci node install legacy | ||||||
|  |   - npmci npm install | ||||||
|  |   - npmci npm test | ||||||
|  |   coverage: /\d+.?\d+?\%\s*coverage/ | ||||||
|  |   tags: | ||||||
|  |   - docker | ||||||
|  |   - notpriv | ||||||
|  |   allow_failure: true | ||||||
|  |  | ||||||
|  | testLTS: | ||||||
|  |   stage: test | ||||||
|  |   script: | ||||||
|  |   - npmci npm prepare | ||||||
|  |   - npmci node install lts | ||||||
|  |   - npmci npm install | ||||||
|  |   - npmci npm test | ||||||
|  |   coverage: /\d+.?\d+?\%\s*coverage/ | ||||||
|  |   tags: | ||||||
|  |   - docker | ||||||
|  |   - notpriv | ||||||
|  |      | ||||||
|  | testSTABLE: | ||||||
|  |   stage: test | ||||||
|  |   script: | ||||||
|  |   - npmci npm prepare | ||||||
|  |   - npmci node install stable | ||||||
|  |   - npmci npm install | ||||||
|  |   - npmci npm test | ||||||
|  |   coverage: /\d+.?\d+?\%\s*coverage/ | ||||||
|  |   tags: | ||||||
|  |   - docker | ||||||
|  |   - notpriv | ||||||
|  |  | ||||||
|  | release: | ||||||
|  |   stage: release | ||||||
|  |   script: | ||||||
|  |   - npmci node install stable | ||||||
|  |   - npmci npm publish | ||||||
|  |   only: | ||||||
|  |   - tags | ||||||
|  |   tags: | ||||||
|  |   - docker | ||||||
|  |   - notpriv | ||||||
|  |  | ||||||
|  | # ==================== | ||||||
|  | # metadata stage | ||||||
|  | # ==================== | ||||||
|  | codequality: | ||||||
|  |   stage: metadata | ||||||
|  |   image: docker:stable | ||||||
|  |   allow_failure: true | ||||||
|  |   services: | ||||||
|  |     - docker:stable-dind | ||||||
|  |   script: | ||||||
|  |     - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') | ||||||
|  |     - docker run | ||||||
|  |         --env SOURCE_CODE="$PWD" | ||||||
|  |         --volume "$PWD":/code | ||||||
|  |         --volume /var/run/docker.sock:/var/run/docker.sock | ||||||
|  |         "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code | ||||||
|  |   artifacts: | ||||||
|  |     paths: [codeclimate.json] | ||||||
|  |   tags: | ||||||
|  |   - docker | ||||||
|  |   - priv | ||||||
|  |  | ||||||
|  | trigger: | ||||||
|  |   stage: metadata | ||||||
|  |   script: | ||||||
|  |   - npmci trigger | ||||||
|  |   only: | ||||||
|  |   - tags | ||||||
|  |   tags: | ||||||
|  |   - docker | ||||||
|  |   - notpriv | ||||||
|  |  | ||||||
|  | pages: | ||||||
|  |   image: hosttoday/ht-docker-node:npmci | ||||||
|  |   stage: metadata | ||||||
|  |   script: | ||||||
|  |     - npmci command npm install -g typedoc typescript | ||||||
|  |     - npmci npm prepare | ||||||
|  |     - npmci npm install | ||||||
|  |     - npmci command typedoc --module "commonjs" --target "ES2016" --out public/ ts/ | ||||||
|  |   tags: | ||||||
|  |     - docker | ||||||
|  |     - notpriv | ||||||
|  |   only: | ||||||
|  |     - tags | ||||||
|  |   artifacts: | ||||||
|  |     expire_in: 1 week | ||||||
|  |     paths: | ||||||
|  |     - public | ||||||
|  |   allow_failure: true | ||||||
|  |  | ||||||
|  | windowsCompatibility: | ||||||
|  |   image: stefanscherer/node-windows:10-build-tools | ||||||
|  |   stage: metadata | ||||||
|  |   script: | ||||||
|  |   - npm install & npm test | ||||||
|  |   coverage: /\d+.?\d+?\%\s*coverage/ | ||||||
|  |   tags: | ||||||
|  |   - windows | ||||||
|  |   allow_failure: true | ||||||
							
								
								
									
										8
									
								
								npmextra.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								npmextra.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | { | ||||||
|  |   "npmci": { | ||||||
|  |     "npmGlobalTools": [ | ||||||
|  |       "@gitzone/npmts", | ||||||
|  |       "ts-node" | ||||||
|  |     ] | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										1578
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1578
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										30
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | { | ||||||
|  |   "name": "smartpdf", | ||||||
|  |   "version": "1.0.1", | ||||||
|  |   "description": "create pdfs on the fly", | ||||||
|  |   "main": "dist/index.js", | ||||||
|  |   "typings": "dist/index.d.ts", | ||||||
|  |   "author": "Lossless GmbH", | ||||||
|  |   "license": "MIT", | ||||||
|  |   "scripts": { | ||||||
|  |     "test": "tstest test/", | ||||||
|  |     "format": "(gitzone format)" | ||||||
|  |   }, | ||||||
|  |   "devDependencies": { | ||||||
|  |     "@gitzone/tsbuild": "^2.0.22", | ||||||
|  |     "@gitzone/tsrun": "^1.1.12", | ||||||
|  |     "@gitzone/tstest": "^1.0.15", | ||||||
|  |     "@pushrocks/tapbundle": "^3.0.7", | ||||||
|  |     "@types/node": "^10.11.4" | ||||||
|  |   }, | ||||||
|  |   "dependencies": { | ||||||
|  |     "@pushrocks/smartfile": "^6.0.8", | ||||||
|  |     "@pushrocks/smartnetwork": "^1.1.0", | ||||||
|  |     "@pushrocks/smartpromise": "^2.0.5", | ||||||
|  |     "@types/express": "^4.16.0", | ||||||
|  |     "@types/puppeteer": "^1.8.0", | ||||||
|  |     "express": "^4.16.3", | ||||||
|  |     "puppeteer": "^1.8.0", | ||||||
|  |     "smartunique": "^2.0.0" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										19
									
								
								test/test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								test/test.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | import { expect, tap } from '@pushrocks/tapbundle'; | ||||||
|  | import * as smartpdf from '../ts/index' | ||||||
|  |  | ||||||
|  | let testSmartPdf: smartpdf.SmartPdf; | ||||||
|  |  | ||||||
|  | tap.test('should create a valid instance of smartpdf', async () => { | ||||||
|  |   testSmartPdf = new smartpdf.SmartPdf(); | ||||||
|  |   expect(testSmartPdf).to.be.instanceof(smartpdf.SmartPdf); | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | tap.test('should create a pdf from html string', async () => { | ||||||
|  |   await testSmartPdf.getPdfForHtmlString('hi'); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | tap.test('should create a pdf from website', async () => { | ||||||
|  |   await testSmartPdf.getPdfForWebsite('https://wikipedia.org'); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | tap.start() | ||||||
							
								
								
									
										1
									
								
								ts/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ts/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | export * from './smartpdf.classes.smartpdf'; | ||||||
							
								
								
									
										8
									
								
								ts/smartpdf.classes.pdfcandidate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								ts/smartpdf.classes.pdfcandidate.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | import * as plugins from './smartpdf.plugins'; | ||||||
|  |  | ||||||
|  | export class PdfCandidate { | ||||||
|  |   pdfId = plugins.smartunique.shortId(); | ||||||
|  |   doneDeferred = plugins.smartpromise.defer(); | ||||||
|  |  | ||||||
|  |   constructor(public htmlString) {} | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								ts/smartpdf.classes.pdfresult.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ts/smartpdf.classes.pdfresult.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | import * as plugins from './smartpdf.plugins'; | ||||||
							
								
								
									
										74
									
								
								ts/smartpdf.classes.smartpdf.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								ts/smartpdf.classes.smartpdf.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | import * as plugins from './smartpdf.plugins'; | ||||||
|  | import * as paths from './smartpdf.paths'; | ||||||
|  | import { Server } from 'http'; | ||||||
|  | import { PdfCandidate } from './smartpdf.classes.pdfcandidate'; | ||||||
|  |  | ||||||
|  | export class SmartPdf { | ||||||
|  |   htmlServerInstance: Server; | ||||||
|  |   serverPort: number; | ||||||
|  |   headlessBrowser: plugins.puppeteer.Browser; | ||||||
|  |   private _readyDeferred: plugins.smartpromise.Deferred<void>; | ||||||
|  |   private _candidates: {[key: string]: PdfCandidate} = {}; | ||||||
|  |  | ||||||
|  |   constructor() { | ||||||
|  |     this._readyDeferred = new plugins.smartpromise.Deferred(); | ||||||
|  |     this.init(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async init() { | ||||||
|  |     // setup puppeteer | ||||||
|  |     this.headlessBrowser = await plugins.puppeteer.launch(); | ||||||
|  |  | ||||||
|  |     // setup server | ||||||
|  |     const app = plugins.express(); | ||||||
|  |     app.get('/:pdfId', (req, res) => { | ||||||
|  |       res.setHeader('PDF-ID', this._candidates[req.params.pdfId].pdfId); | ||||||
|  |       res.send(this._candidates[req.params.pdfId].htmlString); | ||||||
|  |     }); | ||||||
|  |     this.htmlServerInstance = plugins.http.createServer(app); | ||||||
|  |     const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork(); | ||||||
|  |     const portAvailable = smartnetworkInstance.isLocalPortAvailable(3210); | ||||||
|  |     this.htmlServerInstance.listen(3210, 'localhost'); | ||||||
|  |     this.htmlServerInstance.on('listening', () => { | ||||||
|  |       this._readyDeferred.resolve(); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * returns a pdf for a given html string; | ||||||
|  |    */ | ||||||
|  |   async getPdfForHtmlString(htmlStringArg: string) { | ||||||
|  |     await this._readyDeferred.promise; | ||||||
|  |     const pdfCandidate = new PdfCandidate(htmlStringArg); | ||||||
|  |     this._candidates[pdfCandidate.pdfId] = pdfCandidate; | ||||||
|  |     const page = await this.headlessBrowser.newPage(); | ||||||
|  |     const response = await page.goto(`http://localhost:3210/${pdfCandidate.pdfId}`, { waitUntil: 'networkidle2' }); | ||||||
|  |     const headers = response.headers(); | ||||||
|  |     if(headers['pdf-id'] !== pdfCandidate.pdfId) { | ||||||
|  |       console.log('Error! Headers do not match. For security reasons no pdf is being emitted!'); | ||||||
|  |       return | ||||||
|  |     } else { | ||||||
|  |       console.log(`id security check passed for ${pdfCandidate.pdfId}`); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     await page.pdf({ | ||||||
|  |       path: plugins.path.join(paths.pdfDir, `${pdfCandidate.pdfId}.pdf`), | ||||||
|  |       format: 'A4' | ||||||
|  |     }); | ||||||
|  |     await page.close(); | ||||||
|  |     delete this._candidates[pdfCandidate.pdfId]; | ||||||
|  |     pdfCandidate.doneDeferred.resolve(); | ||||||
|  |     await pdfCandidate.doneDeferred.promise; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   async getPdfForWebsite(websiteUrl: string) { | ||||||
|  |     const page = await this.headlessBrowser.newPage(); | ||||||
|  |     const response = await page.goto(websiteUrl, { waitUntil: 'networkidle2' }); | ||||||
|  |     const pdfId = plugins.smartunique.shortId(); | ||||||
|  |     await page.pdf({ | ||||||
|  |       path: plugins.path.join(paths.pdfDir, `${pdfId}.pdf`), | ||||||
|  |       format: 'A4' | ||||||
|  |     }); | ||||||
|  |     await page.close(); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										6
									
								
								ts/smartpdf.paths.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								ts/smartpdf.paths.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | import * as plugins from './smartpdf.plugins'; | ||||||
|  |  | ||||||
|  | export const packageDir = plugins.path.join(__dirname, '../'); | ||||||
|  | export const pdfDir = plugins.path.join(packageDir, 'assets/pdfdir'); | ||||||
|  |  | ||||||
|  | plugins.smartfile.fs.ensureDirSync(pdfDir); | ||||||
							
								
								
									
										30
									
								
								ts/smartpdf.plugins.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								ts/smartpdf.plugins.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | // native | ||||||
|  | import * as http from 'http'; | ||||||
|  | import * as path from 'path'; | ||||||
|  |  | ||||||
|  | export { | ||||||
|  |   http, | ||||||
|  |   path | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // @pushrocks | ||||||
|  | import * as smartfile from '@pushrocks/smartfile'; | ||||||
|  | import * as smartpromise from '@pushrocks/smartpromise'; | ||||||
|  | import * as smartnetwork from '@pushrocks/smartnetwork'; | ||||||
|  | import * as smartunique from 'smartunique'; | ||||||
|  |  | ||||||
|  | export { | ||||||
|  |   smartfile, | ||||||
|  |   smartpromise, | ||||||
|  |   smartunique, | ||||||
|  |   smartnetwork | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // thirdparty | ||||||
|  | import * as express from 'express'; | ||||||
|  | import * as puppeteer from 'puppeteer'; | ||||||
|  |  | ||||||
|  | export { | ||||||
|  |   express, | ||||||
|  |   puppeteer | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								tslint.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tslint.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | { | ||||||
|  |     "extends": ["tslint:latest", "tslint-config-prettier"], | ||||||
|  |     "rules": { | ||||||
|  |       "semicolon": [true, "always"] | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
		Reference in New Issue
	
	Block a user