Skip to content

Commit 83a3c82

Browse files
committed
Full implementasjon av pdf-tjenester
1 parent 0308b2e commit 83a3c82

12 files changed

+307
-98
lines changed

package-lock.json

+80-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@navikt/ds-react": "5.17.4",
2626
"csp-header": "5.2.1",
2727
"js-cookie": "3.0.5",
28+
"jszip": "3.10.1",
2829
"lodash.debounce": "4.0.8",
2930
"puppeteer": "22.0.0",
3031
"react": "18.2.0",

server/src/cms/CmsArchiveCategoriesService.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ export class CmsArchiveCategoriesService {
2727
public async init() {
2828
const allCategories = await this.getAllCategories();
2929
if (!allCategories) {
30-
console.error(`Could not retrieve categories for ${this.config.name}`);
31-
return false;
30+
const msg = `Could not retrieve categories for ${this.config.name}`;
31+
console.error(msg);
32+
throw Error(msg);
3233
}
3334

3435
this.populateCategoriesMap(allCategories);

server/src/cms/CmsArchiveContentService.ts

+21-11
Original file line numberDiff line numberDiff line change
@@ -108,24 +108,34 @@ export class CmsArchiveContentService {
108108
}
109109

110110
public async getContentVersions(versionKeys: string[]): Promise<CmsContent[] | null> {
111-
const result = await this.client.getDocuments<CmsContentDocument>({
111+
const result = await this.client.search<CmsContentDocument>({
112112
index: this.index,
113113
_source_excludes: ['xmlAsString, versions'],
114+
size: versionKeys.length,
114115
body: {
115-
ids: versionKeys,
116+
sort: {
117+
'meta.timestamp': 'desc',
118+
},
119+
query: {
120+
ids: {
121+
values: versionKeys,
122+
},
123+
},
116124
},
117125
});
118126

119-
return (
120-
result?.reduce<CmsContent[]>((acc, content) => {
121-
const fixedContent = this.fixContent(content);
122-
if (fixedContent) {
123-
acc.push(fixedContent);
124-
}
127+
if (!result) {
128+
return null;
129+
}
130+
131+
return result.hits.reduce<CmsContent[]>((acc, content) => {
132+
const fixedContent = this.fixContent(content);
133+
if (fixedContent) {
134+
acc.push(fixedContent);
135+
}
125136

126-
return acc;
127-
}, []) || null
128-
);
137+
return acc;
138+
}, []);
129139
}
130140

131141
private fixContent(contentDocument: CmsContentDocument | null): CmsContent | null {

server/src/cms/CmsArchiveSite.ts

+57-15
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { CmsArchiveOpenSearchClient } from '../opensearch/CmsArchiveOpenSearchClient';
22
import express, { Express, Response, Router } from 'express';
33
import { CmsArchiveContentService } from './CmsArchiveContentService';
4-
import { parseQueryParamsList } from '../utils/queryParams';
4+
import { parseNumberParam, parseQueryParamsList } from '../utils/queryParams';
55
import mime from 'mime';
6-
import { HtmlRenderer } from '../site/ssr/htmlRenderer';
6+
import { HtmlRenderer } from '../ssr/htmlRenderer';
77
import { transformQueryToContentSearchParams } from '../opensearch/queries/contentSearch';
88
import { CmsArchiveCategoriesService } from './CmsArchiveCategoriesService';
99
import { cspMiddleware } from '../routing/csp';
1010
import { CmsArchiveBinariesService } from './CmsArchiveBinariesService';
11-
import { PdfGenerator } from '../site/pdf/PdfGenerator';
11+
import { PdfGenerator } from '../pdf/PdfGenerator';
1212
import { Browser } from 'puppeteer';
1313

1414
export type CmsArchiveSiteConfig = {
@@ -151,12 +151,53 @@ export class CmsArchiveSite {
151151
}
152152

153153
private setupFileRoutes(router: Router) {
154-
router.get('/pdf/:versionKeys', async (req, res, next) => {
155-
const versionKeys = req.params.versionKeys.split(',');
154+
router.get('/pdf/single/:versionKey', async (req, res, next) => {
155+
const result = await this.pdfGenerator.generatePdfFromVersion(
156+
req.params.versionKey,
157+
parseNumberParam(req.query.width)
158+
);
159+
160+
if (!result) {
161+
return next();
162+
}
163+
164+
const { filename, data } = result;
165+
166+
const contentType = mime.lookup(filename) || 'application/octet-stream';
167+
168+
return res
169+
.setHeader('Content-Disposition', `attachment; filename="${filename}"`)
170+
.setHeader('Content-Type', contentType)
171+
.send(data);
172+
});
173+
174+
router.get('/pdf/multi/:versionKeys', async (req, res, next) => {
175+
const result = await this.pdfGenerator.generatePdfFromVersions(
176+
req.params.versionKeys.split(','),
177+
parseNumberParam(req.query.width)
178+
);
179+
180+
if (!result) {
181+
return next();
182+
}
183+
184+
const { filename, dataStream } = result;
185+
186+
const contentType = mime.lookup(filename) || 'application/octet-stream';
187+
188+
res.setHeader('Content-Disposition', `attachment; filename="${filename}"`).setHeader(
189+
'Content-Type',
190+
contentType
191+
);
156192

157-
const pdfs = this.pdfGenerator.generatePdfFromVersions(versionKeys);
193+
dataStream.on('data', (chunk) => {
194+
res.write(chunk);
195+
});
158196

159-
// return this.fileResponse(`${contentVersion.displayName}-${con}`);
197+
dataStream.on('end', () => {
198+
console.log(`Finished streaming file ${filename}`);
199+
res.end();
200+
});
160201
});
161202

162203
router.get('/binary/file/:binaryKey', async (req, res, next) => {
@@ -167,7 +208,7 @@ export class CmsArchiveSite {
167208
return next();
168209
}
169210

170-
return this.fileResponse(
211+
return this.cmsBinaryResponse(
171212
binary.filename,
172213
binary.data,
173214
`attachment; filename="${binary.filename}"`,
@@ -181,7 +222,7 @@ export class CmsArchiveSite {
181222
return next();
182223
}
183224

184-
return this.fileResponse(file.filename, file.data, 'inline', res);
225+
return this.cmsBinaryResponse(file.filename, file.data, 'inline', res);
185226
});
186227

187228
router.use('/*/_image/:contentKey.:extension', async (req, res, next) => {
@@ -190,6 +231,7 @@ export class CmsArchiveSite {
190231
return next();
191232
}
192233

234+
// The last item in the binaries array of an image content is the source file
193235
const binaryKey = content.binaries?.slice(-1)?.[0].key;
194236
if (!binaryKey) {
195237
return next();
@@ -200,7 +242,7 @@ export class CmsArchiveSite {
200242
return next();
201243
}
202244

203-
return this.fileResponse(binary.filename, binary.data, 'inline', res);
245+
return this.cmsBinaryResponse(binary.filename, binary.data, 'inline', res);
204246
});
205247

206248
router.use('/*/_image/:contentKey/label/:label.:extension', async (req, res, next) => {
@@ -221,21 +263,21 @@ export class CmsArchiveSite {
221263
return next();
222264
}
223265

224-
return this.fileResponse(binary.filename, binary.data, 'inline', res);
266+
return this.cmsBinaryResponse(binary.filename, binary.data, 'inline', res);
225267
});
226268
}
227269

228-
private fileResponse(
270+
private cmsBinaryResponse(
229271
filename: string,
230-
data: string,
272+
base64Data: string,
231273
contentDisposition: string,
232274
res: Response
233275
) {
234276
const contentType = mime.lookup(filename) || 'application/octet-stream';
235277

236278
return res
237-
.setHeader('Content-Dispositon', contentDisposition)
279+
.setHeader('Content-Disposition', contentDisposition)
238280
.setHeader('Content-Type', contentType)
239-
.send(Buffer.from(data, 'base64'));
281+
.send(Buffer.from(base64Data, 'base64'));
240282
}
241283
}

0 commit comments

Comments
 (0)