orator-conversion 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
2
+
3
+ class EndpointPdfPageToPng extends libFableServiceProviderBase
4
+ {
5
+ constructor(pFable, pOptions, pServiceHash)
6
+ {
7
+ super(pFable, pOptions, pServiceHash);
8
+
9
+ this.serviceType = 'OratorFileTranslationEndpoint-PdfPageToPng';
10
+
11
+ this._FileTranslation = (pOptions && pOptions.FileTranslation) ? pOptions.FileTranslation : null;
12
+
13
+ this.converterPath = 'pdf-to-page-png/:Page';
14
+ }
15
+
16
+ convert(pInputBuffer, pRequest, fCallback)
17
+ {
18
+ let tmpPage = parseInt(pRequest.params.Page, 10);
19
+ if (isNaN(tmpPage) || tmpPage < 1)
20
+ {
21
+ return fCallback(new Error('Invalid page number. Must be a positive integer.'));
22
+ }
23
+
24
+ this._FileTranslation.renderPdfPageToImage(pInputBuffer, tmpPage, 'png',
25
+ (pRenderError, pImageBuffer) =>
26
+ {
27
+ if (pRenderError)
28
+ {
29
+ return fCallback(pRenderError);
30
+ }
31
+ return fCallback(null, pImageBuffer, 'image/png');
32
+ });
33
+ }
34
+ }
35
+
36
+ module.exports = EndpointPdfPageToPng;
@@ -0,0 +1,371 @@
1
+ /**
2
+ * Unit tests for Orator File Translation - Basic Sanity
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ */
8
+
9
+ const Chai = require("chai");
10
+ const Expect = Chai.expect;
11
+
12
+ const libFable = require('fable');
13
+ const libOrator = require('orator');
14
+ const libOratorFileTranslation = require('../source/Orator-File-Translation.js');
15
+
16
+ const defaultFableSettings = (
17
+ {
18
+ Product: 'OratorFileTranslation-Tests',
19
+ ProductVersion: '0.0.0',
20
+ APIServerPort: 0
21
+ });
22
+
23
+ suite
24
+ (
25
+ 'Orator File Translation',
26
+ () =>
27
+ {
28
+ suite
29
+ (
30
+ 'Object Sanity',
31
+ () =>
32
+ {
33
+ test
34
+ (
35
+ 'the class should initialize itself into a happy little object',
36
+ (fDone) =>
37
+ {
38
+ let tmpFable = new libFable(defaultFableSettings);
39
+
40
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
41
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
42
+
43
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
44
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation', {});
45
+
46
+ Expect(tmpFileTranslation).to.be.an('object', 'OratorFileTranslation should initialize as an object.');
47
+ Expect(tmpFileTranslation.serviceType).to.equal('OratorFileTranslation');
48
+ Expect(tmpFileTranslation).to.have.a.property('connectRoutes');
49
+ Expect(tmpFileTranslation.connectRoutes).to.be.a('function');
50
+ Expect(tmpFileTranslation).to.have.a.property('converters');
51
+ Expect(tmpFileTranslation.converters).to.be.an('object');
52
+ Expect(tmpFileTranslation).to.have.a.property('addConverter');
53
+ Expect(tmpFileTranslation.addConverter).to.be.a('function');
54
+ Expect(tmpFileTranslation).to.have.a.property('collectRequestBody');
55
+ Expect(tmpFileTranslation.collectRequestBody).to.be.a('function');
56
+ Expect(tmpFileTranslation).to.have.a.property('extractPdfPage');
57
+ Expect(tmpFileTranslation.extractPdfPage).to.be.a('function');
58
+ Expect(tmpFileTranslation).to.have.a.property('renderPdfPageToImage');
59
+ Expect(tmpFileTranslation.renderPdfPageToImage).to.be.a('function');
60
+
61
+ return fDone();
62
+ }
63
+ );
64
+
65
+ test
66
+ (
67
+ 'the service should have default converters registered',
68
+ (fDone) =>
69
+ {
70
+ let tmpFable = new libFable(defaultFableSettings);
71
+
72
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
73
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
74
+
75
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
76
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation', {});
77
+
78
+ Expect(tmpFileTranslation.converters).to.have.a.property('image/jpg-to-png');
79
+ Expect(tmpFileTranslation.converters['image/jpg-to-png']).to.be.a('function');
80
+ Expect(tmpFileTranslation.converters).to.have.a.property('image/png-to-jpg');
81
+ Expect(tmpFileTranslation.converters['image/png-to-jpg']).to.be.a('function');
82
+ Expect(tmpFileTranslation.converters).to.have.a.property('pdf-to-page-png/:Page');
83
+ Expect(tmpFileTranslation.converters['pdf-to-page-png/:Page']).to.be.a('function');
84
+ Expect(tmpFileTranslation.converters).to.have.a.property('pdf-to-page-jpg/:Page');
85
+ Expect(tmpFileTranslation.converters['pdf-to-page-jpg/:Page']).to.be.a('function');
86
+ Expect(tmpFileTranslation.converters).to.have.a.property('pdf-to-page-png/:Page/:LongSidePixels');
87
+ Expect(tmpFileTranslation.converters['pdf-to-page-png/:Page/:LongSidePixels']).to.be.a('function');
88
+ Expect(tmpFileTranslation.converters).to.have.a.property('pdf-to-page-jpg/:Page/:LongSidePixels');
89
+ Expect(tmpFileTranslation.converters['pdf-to-page-jpg/:Page/:LongSidePixels']).to.be.a('function');
90
+
91
+ return fDone();
92
+ }
93
+ );
94
+ }
95
+ );
96
+
97
+ suite
98
+ (
99
+ 'Configuration',
100
+ () =>
101
+ {
102
+ test
103
+ (
104
+ 'the service should have default configuration values when no options are provided',
105
+ (fDone) =>
106
+ {
107
+ let tmpFable = new libFable(defaultFableSettings);
108
+
109
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
110
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
111
+
112
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
113
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation', {});
114
+
115
+ Expect(tmpFileTranslation.RoutePrefix).to.equal('/conversion');
116
+ Expect(tmpFileTranslation.Version).to.equal('1.0');
117
+ Expect(tmpFileTranslation.LogLevel).to.equal(0);
118
+ Expect(tmpFileTranslation.MaxFileSize).to.equal(10 * 1024 * 1024);
119
+ Expect(tmpFileTranslation.PdftkPath).to.equal('pdftk');
120
+ Expect(tmpFileTranslation.PdftoppmPath).to.equal('pdftoppm');
121
+
122
+ return fDone();
123
+ }
124
+ );
125
+
126
+ test
127
+ (
128
+ 'the service should accept configuration via options',
129
+ (fDone) =>
130
+ {
131
+ let tmpFable = new libFable(defaultFableSettings);
132
+
133
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
134
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
135
+
136
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
137
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation',
138
+ {
139
+ RoutePrefix: '/convert',
140
+ Version: '2.0',
141
+ LogLevel: 3,
142
+ MaxFileSize: 5 * 1024 * 1024,
143
+ PdftkPath: '/usr/local/bin/pdftk',
144
+ PdftoppmPath: '/usr/local/bin/pdftoppm'
145
+ });
146
+
147
+ Expect(tmpFileTranslation.RoutePrefix).to.equal('/convert');
148
+ Expect(tmpFileTranslation.Version).to.equal('2.0');
149
+ Expect(tmpFileTranslation.LogLevel).to.equal(3);
150
+ Expect(tmpFileTranslation.MaxFileSize).to.equal(5 * 1024 * 1024);
151
+ Expect(tmpFileTranslation.PdftkPath).to.equal('/usr/local/bin/pdftk');
152
+ Expect(tmpFileTranslation.PdftoppmPath).to.equal('/usr/local/bin/pdftoppm');
153
+
154
+ return fDone();
155
+ }
156
+ );
157
+
158
+ test
159
+ (
160
+ 'the service should accept configuration via fable settings fallback',
161
+ (fDone) =>
162
+ {
163
+ let tmpFableSettings = Object.assign({}, defaultFableSettings,
164
+ {
165
+ OratorFileTranslationRoutePrefix: '/api/convert',
166
+ OratorFileTranslationVersion: '3.0',
167
+ OratorFileTranslationLogLevel: 2,
168
+ OratorFileTranslationMaxFileSize: 20 * 1024 * 1024,
169
+ OratorFileTranslationPdftkPath: '/opt/pdftk/bin/pdftk',
170
+ OratorFileTranslationPdftoppmPath: '/opt/poppler/bin/pdftoppm'
171
+ });
172
+ let tmpFable = new libFable(tmpFableSettings);
173
+
174
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
175
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
176
+
177
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
178
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation', {});
179
+
180
+ Expect(tmpFileTranslation.RoutePrefix).to.equal('/api/convert');
181
+ Expect(tmpFileTranslation.Version).to.equal('3.0');
182
+ Expect(tmpFileTranslation.LogLevel).to.equal(2);
183
+ Expect(tmpFileTranslation.MaxFileSize).to.equal(20 * 1024 * 1024);
184
+ Expect(tmpFileTranslation.PdftkPath).to.equal('/opt/pdftk/bin/pdftk');
185
+ Expect(tmpFileTranslation.PdftoppmPath).to.equal('/opt/poppler/bin/pdftoppm');
186
+
187
+ return fDone();
188
+ }
189
+ );
190
+
191
+ test
192
+ (
193
+ 'options should take precedence over fable settings',
194
+ (fDone) =>
195
+ {
196
+ let tmpFableSettings = Object.assign({}, defaultFableSettings,
197
+ {
198
+ OratorFileTranslationRoutePrefix: '/fallback',
199
+ OratorFileTranslationVersion: '0.1',
200
+ OratorFileTranslationLogLevel: 1,
201
+ OratorFileTranslationMaxFileSize: 1024
202
+ });
203
+ let tmpFable = new libFable(tmpFableSettings);
204
+
205
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
206
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
207
+
208
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
209
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation',
210
+ {
211
+ RoutePrefix: '/primary',
212
+ Version: '9.0',
213
+ LogLevel: 5,
214
+ MaxFileSize: 2048
215
+ });
216
+
217
+ Expect(tmpFileTranslation.RoutePrefix).to.equal('/primary');
218
+ Expect(tmpFileTranslation.Version).to.equal('9.0');
219
+ Expect(tmpFileTranslation.LogLevel).to.equal(5);
220
+ Expect(tmpFileTranslation.MaxFileSize).to.equal(2048);
221
+
222
+ return fDone();
223
+ }
224
+ );
225
+ }
226
+ );
227
+
228
+ suite
229
+ (
230
+ 'Converter Registry',
231
+ () =>
232
+ {
233
+ test
234
+ (
235
+ 'a custom converter can be added via addConverter',
236
+ (fDone) =>
237
+ {
238
+ let tmpFable = new libFable(defaultFableSettings);
239
+
240
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
241
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
242
+
243
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
244
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation', {});
245
+
246
+ let tmpCustomConverter = (pInputBuffer, pRequest, fCallback) =>
247
+ {
248
+ return fCallback(null, pInputBuffer, 'text/plain');
249
+ };
250
+
251
+ tmpFileTranslation.addConverter('custom/echo', tmpCustomConverter);
252
+
253
+ Expect(tmpFileTranslation.converters).to.have.a.property('custom/echo');
254
+ Expect(tmpFileTranslation.converters['custom/echo']).to.be.a('function');
255
+
256
+ return fDone();
257
+ }
258
+ );
259
+
260
+ test
261
+ (
262
+ 'the converter count should reflect defaults plus custom additions',
263
+ (fDone) =>
264
+ {
265
+ let tmpFable = new libFable(defaultFableSettings);
266
+
267
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
268
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
269
+
270
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
271
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation', {});
272
+
273
+ // Should have 6 default converters (jpg-to-png, png-to-jpg, pdf-to-page-png, pdf-to-page-jpg, pdf-to-page-png sized, pdf-to-page-jpg sized)
274
+ Expect(Object.keys(tmpFileTranslation.converters).length).to.equal(6);
275
+
276
+ tmpFileTranslation.addConverter('document/txt-to-html', (pInput, pReq, fCb) => { fCb(null, pInput, 'text/html'); });
277
+
278
+ // Should now have 7
279
+ Expect(Object.keys(tmpFileTranslation.converters).length).to.equal(7);
280
+
281
+ return fDone();
282
+ }
283
+ );
284
+ }
285
+ );
286
+
287
+ suite
288
+ (
289
+ 'Route Registration',
290
+ () =>
291
+ {
292
+ test
293
+ (
294
+ 'connectRoutes should register versioned routes on the orator service server',
295
+ (fDone) =>
296
+ {
297
+ let tmpFable = new libFable(defaultFableSettings);
298
+
299
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
300
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
301
+
302
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
303
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation', {});
304
+
305
+ tmpOrator.startService(
306
+ () =>
307
+ {
308
+ let tmpResult = tmpFileTranslation.connectRoutes();
309
+ Expect(tmpResult).to.equal(true);
310
+
311
+ // Verify versioned routes are registered via the IPC router
312
+ let tmpJpgToPng = tmpOrator.serviceServer.router.find('POST', '/conversion/1.0/image/jpg-to-png');
313
+ Expect(tmpJpgToPng).to.be.an('object');
314
+ Expect(tmpJpgToPng).to.have.a.property('handler');
315
+
316
+ let tmpPngToJpg = tmpOrator.serviceServer.router.find('POST', '/conversion/1.0/image/png-to-jpg');
317
+ Expect(tmpPngToJpg).to.be.an('object');
318
+ Expect(tmpPngToJpg).to.have.a.property('handler');
319
+
320
+ // Verify PDF page extraction routes with parameterized path
321
+ let tmpPdfToPng = tmpOrator.serviceServer.router.find('POST', '/conversion/1.0/pdf-to-page-png/1');
322
+ Expect(tmpPdfToPng).to.be.an('object');
323
+ Expect(tmpPdfToPng).to.have.a.property('handler');
324
+
325
+ let tmpPdfToJpg = tmpOrator.serviceServer.router.find('POST', '/conversion/1.0/pdf-to-page-jpg/5');
326
+ Expect(tmpPdfToJpg).to.be.an('object');
327
+ Expect(tmpPdfToJpg).to.have.a.property('handler');
328
+
329
+ return fDone();
330
+ });
331
+ }
332
+ );
333
+
334
+ test
335
+ (
336
+ 'connectRoutes should use a custom version and route prefix',
337
+ (fDone) =>
338
+ {
339
+ let tmpFable = new libFable(defaultFableSettings);
340
+
341
+ tmpFable.serviceManager.addServiceType('Orator', libOrator);
342
+ tmpFable.serviceManager.addServiceType('OratorFileTranslation', libOratorFileTranslation);
343
+
344
+ let tmpOrator = tmpFable.serviceManager.instantiateServiceProvider('Orator', {});
345
+ let tmpFileTranslation = tmpFable.serviceManager.instantiateServiceProvider('OratorFileTranslation',
346
+ {
347
+ RoutePrefix: '/api/convert',
348
+ Version: '2.0'
349
+ });
350
+
351
+ tmpOrator.startService(
352
+ () =>
353
+ {
354
+ tmpFileTranslation.connectRoutes();
355
+
356
+ let tmpHandler = tmpOrator.serviceServer.router.find('POST', '/api/convert/2.0/image/jpg-to-png');
357
+ Expect(tmpHandler).to.be.an('object');
358
+ Expect(tmpHandler).to.have.a.property('handler');
359
+
360
+ let tmpPdfHandler = tmpOrator.serviceServer.router.find('POST', '/api/convert/2.0/pdf-to-page-png/3');
361
+ Expect(tmpPdfHandler).to.be.an('object');
362
+ Expect(tmpPdfHandler).to.have.a.property('handler');
363
+
364
+ return fDone();
365
+ });
366
+ }
367
+ );
368
+ }
369
+ );
370
+ }
371
+ );