@things-factory/pdf 10.1.228 → 10.1.231
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.
- package/dist-client/index.d.ts +2 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/issue-document.d.ts +44 -0
- package/dist-client/issue-document.js +162 -0
- package/dist-client/issue-document.js.map +1 -0
- package/dist-client/pages/issued-document/issued-document-list.d.ts +52 -0
- package/dist-client/pages/issued-document/issued-document-list.js +265 -0
- package/dist-client/pages/issued-document/issued-document-list.js.map +1 -0
- package/dist-client/pages/pdf-template/pdf-template-list-page.js +12 -0
- package/dist-client/pages/pdf-template/pdf-template-list-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +3 -2
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/controller/issued-document-kind.d.ts +60 -0
- package/dist-server/controller/issued-document-kind.js +48 -0
- package/dist-server/controller/issued-document-kind.js.map +1 -0
- package/dist-server/controller/pdf-release-reader.d.ts +1 -0
- package/dist-server/controller/pdf-release-reader.js +15 -0
- package/dist-server/controller/pdf-release-reader.js.map +1 -0
- package/dist-server/controller/pdf-release-service.d.ts +29 -4
- package/dist-server/controller/pdf-release-service.js +120 -9
- package/dist-server/controller/pdf-release-service.js.map +1 -1
- package/dist-server/index.d.ts +6 -1
- package/dist-server/index.js +13 -1
- package/dist-server/index.js.map +1 -1
- package/dist-server/role-tasks.js +3 -1
- package/dist-server/role-tasks.js.map +1 -1
- package/dist-server/service/index.d.ts +10 -1
- package/dist-server/service/index.js +1 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/pdf-generate/pdf-generate-resolver.d.ts +0 -2
- package/dist-server/service/pdf-generate/pdf-generate-resolver.js +8 -18
- package/dist-server/service/pdf-generate/pdf-generate-resolver.js.map +1 -1
- package/dist-server/service/pdf-release/index.d.ts +2 -2
- package/dist-server/service/pdf-release/index.js +4 -3
- package/dist-server/service/pdf-release/index.js.map +1 -1
- package/dist-server/service/pdf-release/pdf-release-query.d.ts +31 -5
- package/dist-server/service/pdf-release/pdf-release-query.js +213 -30
- package/dist-server/service/pdf-release/pdf-release-query.js.map +1 -1
- package/dist-server/service/pdf-release/pdf-release-type.d.ts +1 -16
- package/dist-server/service/pdf-release/pdf-release-type.js +4 -60
- package/dist-server/service/pdf-release/pdf-release-type.js.map +1 -1
- package/dist-server/service/pdf-release/pdf-release.d.ts +13 -1
- package/dist-server/service/pdf-release/pdf-release.js +67 -4
- package/dist-server/service/pdf-release/pdf-release.js.map +1 -1
- package/dist-server/service/pdf-template/pdf-template-type.d.ts +2 -0
- package/dist-server/service/pdf-template/pdf-template-type.js +8 -0
- package/dist-server/service/pdf-template/pdf-template-type.js.map +1 -1
- package/dist-server/service/pdf-template/pdf-template.d.ts +1 -0
- package/dist-server/service/pdf-template/pdf-template.js +5 -0
- package/dist-server/service/pdf-template/pdf-template.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -2
- package/things-factory.config.js +2 -1
- package/translations/en.json +30 -1
- package/translations/es.json +30 -1
- package/translations/ja.json +30 -1
- package/translations/ko.json +30 -1
- package/translations/ms.json +30 -1
- package/translations/zh.json +30 -1
- package/dist-client/pages/pdf-release/pdf-release-importer.d.ts +0 -23
- package/dist-client/pages/pdf-release/pdf-release-importer.js +0 -93
- package/dist-client/pages/pdf-release/pdf-release-importer.js.map +0 -1
- package/dist-client/pages/pdf-release/pdf-release-list-page.d.ts +0 -60
- package/dist-client/pages/pdf-release/pdf-release-list-page.js +0 -317
- package/dist-client/pages/pdf-release/pdf-release-list-page.js.map +0 -1
- package/dist-server/service/pdf-release/pdf-release-mutation.d.ts +0 -10
- package/dist-server/service/pdf-release/pdf-release-mutation.js +0 -156
- package/dist-server/service/pdf-release/pdf-release-mutation.js.map +0 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { PdfTemplateParts } from './pdf-document';
|
|
2
|
+
/** What a person gives when issuing: what the document is for, where it goes, and the day it speaks of. */
|
|
3
|
+
export interface IssueInput {
|
|
4
|
+
purpose?: string | null;
|
|
5
|
+
submittedTo?: string | null;
|
|
6
|
+
/** The day the document speaks of - a register's 기준일; today in the domain when none is given. */
|
|
7
|
+
asOf?: string | null;
|
|
8
|
+
}
|
|
9
|
+
/** What `dataOf` answers: the name the ledger shows for the subject, and the data the template is filled with. */
|
|
10
|
+
export interface IssuedDocumentData {
|
|
11
|
+
subjectName: string;
|
|
12
|
+
data: Record<string, any>;
|
|
13
|
+
}
|
|
14
|
+
/** A ledger row as a kind's `mayRead` sees it. */
|
|
15
|
+
export interface IssuedRow {
|
|
16
|
+
kind?: string | null;
|
|
17
|
+
refType?: string | null;
|
|
18
|
+
refId?: string | null;
|
|
19
|
+
creatorId?: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface IssuedDocumentKind {
|
|
22
|
+
/** `<module>.<document>`, e.g. `organization.employment-certificate`. */
|
|
23
|
+
kind: string;
|
|
24
|
+
/** The head of its number, e.g. `재직` - `재직-2026-0007`. */
|
|
25
|
+
prefix: string;
|
|
26
|
+
/** What `refId` names, e.g. `Employee`; `Domain` for a document about the company itself, whose subject is always the request's domain. */
|
|
27
|
+
refType: string;
|
|
28
|
+
/**
|
|
29
|
+
* The subject that is the caller's own, if the kind has one - one's own employee record for a 재직증명서. The ledger
|
|
30
|
+
* then offers the kind to issue for it, when `mayIssue` agrees.
|
|
31
|
+
*/
|
|
32
|
+
ownSubject?(context: ResolverContext): Promise<string | null>;
|
|
33
|
+
/** Whether the document speaks of a day the person picks (a register's 기준일) - the issue form then asks for it. */
|
|
34
|
+
asOf?: boolean;
|
|
35
|
+
/** The template in code; a domain's `PDFTemplate` of the same kind prints in its place. */
|
|
36
|
+
template: PdfTemplateParts;
|
|
37
|
+
/** The data to fill the template with, from the subject and what the person gave. Refuses what cannot be issued. */
|
|
38
|
+
dataOf(context: ResolverContext, refId: string, input: IssueInput): Promise<IssuedDocumentData>;
|
|
39
|
+
/** Whether the caller may issue this kind for this subject - the owning module's rule. */
|
|
40
|
+
mayIssue(context: ResolverContext, refId: string): Promise<boolean>;
|
|
41
|
+
/** Whether the caller may read a ledger row of this kind, and its file. */
|
|
42
|
+
mayRead(context: ResolverContext, row: IssuedRow): Promise<boolean>;
|
|
43
|
+
}
|
|
44
|
+
/** A module declares a kind it issues. The same `kind` again replaces it. */
|
|
45
|
+
export declare function registerIssuedDocumentKind(kind: IssuedDocumentKind): void;
|
|
46
|
+
export declare function issuedDocumentKindOf(kind: string | null | undefined): IssuedDocumentKind | undefined;
|
|
47
|
+
export declare function issuedDocumentKinds(): IssuedDocumentKind[];
|
|
48
|
+
/** The number a document of a kind gets: `<prefix>-<year>-<sequence>`, the sequence four digits at least. */
|
|
49
|
+
export declare function issueNumberOf(prefix: string, year: number, sequence: number): string;
|
|
50
|
+
/** What a person gave, kept as the ledger keeps it - trimmed words, nothing for a blank. */
|
|
51
|
+
export declare function issueInputOf(input: IssueInput | null | undefined): {
|
|
52
|
+
purpose: string | null;
|
|
53
|
+
submittedTo: string | null;
|
|
54
|
+
asOf: string | null;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The file name of an issued document - what a person sees in their downloads: `<kind>_<subject>_<number>.pdf`, e.g.
|
|
58
|
+
* `재직증명서_남종호_재직-2026-0001.pdf`. Characters a file system refuses go, and so does the ` · ` a subject name joins with.
|
|
59
|
+
*/
|
|
60
|
+
export declare function issuedFileNameOf(kindWord: string, subjectName: string | null | undefined, number: string): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerIssuedDocumentKind = registerIssuedDocumentKind;
|
|
4
|
+
exports.issuedDocumentKindOf = issuedDocumentKindOf;
|
|
5
|
+
exports.issuedDocumentKinds = issuedDocumentKinds;
|
|
6
|
+
exports.issueNumberOf = issueNumberOf;
|
|
7
|
+
exports.issueInputOf = issueInputOf;
|
|
8
|
+
exports.issuedFileNameOf = issuedFileNameOf;
|
|
9
|
+
const kinds = new Map();
|
|
10
|
+
/** A module declares a kind it issues. The same `kind` again replaces it. */
|
|
11
|
+
function registerIssuedDocumentKind(kind) {
|
|
12
|
+
if (!/^[a-z0-9-]+\.[a-z0-9.-]+$/.test(kind.kind))
|
|
13
|
+
throw new Error(`an issued document kind is <module>.<document>: ${kind.kind}`);
|
|
14
|
+
if (!kind.prefix?.trim())
|
|
15
|
+
throw new Error(`the issued document kind ${kind.kind} has no number prefix`);
|
|
16
|
+
kinds.set(kind.kind, kind);
|
|
17
|
+
}
|
|
18
|
+
function issuedDocumentKindOf(kind) {
|
|
19
|
+
return kind ? kinds.get(kind) : undefined;
|
|
20
|
+
}
|
|
21
|
+
function issuedDocumentKinds() {
|
|
22
|
+
return [...kinds.values()];
|
|
23
|
+
}
|
|
24
|
+
/** The number a document of a kind gets: `<prefix>-<year>-<sequence>`, the sequence four digits at least. */
|
|
25
|
+
function issueNumberOf(prefix, year, sequence) {
|
|
26
|
+
return `${prefix}-${year}-${String(sequence).padStart(4, '0')}`;
|
|
27
|
+
}
|
|
28
|
+
/** What a person gave, kept as the ledger keeps it - trimmed words, nothing for a blank. */
|
|
29
|
+
function issueInputOf(input) {
|
|
30
|
+
const text = (value) => (typeof value === 'string' && value.trim() ? value.trim() : null);
|
|
31
|
+
const asOf = text(input?.asOf);
|
|
32
|
+
if (asOf && !/^\d{4}-\d{2}-\d{2}$/.test(asOf))
|
|
33
|
+
throw new Error(`a day is YYYY-MM-DD: ${asOf}`);
|
|
34
|
+
return { purpose: text(input?.purpose), submittedTo: text(input?.submittedTo), asOf };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The file name of an issued document - what a person sees in their downloads: `<kind>_<subject>_<number>.pdf`, e.g.
|
|
38
|
+
* `재직증명서_남종호_재직-2026-0001.pdf`. Characters a file system refuses go, and so does the ` · ` a subject name joins with.
|
|
39
|
+
*/
|
|
40
|
+
function issuedFileNameOf(kindWord, subjectName, number) {
|
|
41
|
+
const clean = (text) => text
|
|
42
|
+
.replace(/\s*·\s*/g, '_')
|
|
43
|
+
.replace(/[\\/:*?"<>|\u0000-\u001f]+/g, '')
|
|
44
|
+
.replace(/\s+/g, ' ')
|
|
45
|
+
.trim();
|
|
46
|
+
return `${[kindWord, subjectName ?? '', number].map(clean).filter(Boolean).join('_')}.pdf`;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=issued-document-kind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issued-document-kind.js","sourceRoot":"","sources":["../../server/controller/issued-document-kind.ts"],"names":[],"mappings":";;AAyDA,gEAIC;AAED,oDAEC;AAED,kDAEC;AAGD,sCAEC;AAGD,oCAKC;AAMD,4CAQC;AA1CD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA8B,CAAA;AAEnD,6EAA6E;AAC7E,SAAgB,0BAA0B,CAAC,IAAwB;IACjE,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;IACjI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,CAAC,IAAI,uBAAuB,CAAC,CAAA;IACvG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;AAC5B,CAAC;AAED,SAAgB,oBAAoB,CAAC,IAA+B;IAClE,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAC3C,CAAC;AAED,SAAgB,mBAAmB;IACjC,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;AAC5B,CAAC;AAED,6GAA6G;AAC7G,SAAgB,aAAa,CAAC,MAAc,EAAE,IAAY,EAAE,QAAgB;IAC1E,OAAO,GAAG,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;AACjE,CAAC;AAED,4FAA4F;AAC5F,SAAgB,YAAY,CAAC,KAAoC;IAC/D,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IAClG,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IAC9B,IAAI,IAAI,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAA;IAC9F,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,CAAA;AACvF,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,QAAgB,EAAE,WAAsC,EAAE,MAAc;IACvG,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAE,CAC7B,IAAI;SACD,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC;SACxB,OAAO,CAAC,6BAA6B,EAAE,EAAE,CAAC;SAC1C,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAA;IACX,OAAO,GAAG,CAAC,QAAQ,EAAE,WAAW,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAA;AAC5F,CAAC","sourcesContent":["import type { PdfTemplateParts } from './pdf-document'\n\n/*\n * The kinds of document the ledger issues (ADR-0176 decision 3). The module that owns the fact a document certifies\n * declares its kind - organization the employment, Office the shareholdings - and with it who may issue and read it.\n * The pdf module keeps the templates, prints and numbers; it decides nothing about who.\n */\n\n/** What a person gives when issuing: what the document is for, where it goes, and the day it speaks of. */\nexport interface IssueInput {\n purpose?: string | null\n submittedTo?: string | null\n /** The day the document speaks of - a register's 기준일; today in the domain when none is given. */\n asOf?: string | null\n}\n\n/** What `dataOf` answers: the name the ledger shows for the subject, and the data the template is filled with. */\nexport interface IssuedDocumentData {\n subjectName: string\n data: Record<string, any>\n}\n\n/** A ledger row as a kind's `mayRead` sees it. */\nexport interface IssuedRow {\n kind?: string | null\n refType?: string | null\n refId?: string | null\n creatorId?: string | null\n}\n\nexport interface IssuedDocumentKind {\n /** `<module>.<document>`, e.g. `organization.employment-certificate`. */\n kind: string\n /** The head of its number, e.g. `재직` - `재직-2026-0007`. */\n prefix: string\n /** What `refId` names, e.g. `Employee`; `Domain` for a document about the company itself, whose subject is always the request's domain. */\n refType: string\n /**\n * The subject that is the caller's own, if the kind has one - one's own employee record for a 재직증명서. The ledger\n * then offers the kind to issue for it, when `mayIssue` agrees.\n */\n ownSubject?(context: ResolverContext): Promise<string | null>\n /** Whether the document speaks of a day the person picks (a register's 기준일) - the issue form then asks for it. */\n asOf?: boolean\n /** The template in code; a domain's `PDFTemplate` of the same kind prints in its place. */\n template: PdfTemplateParts\n /** The data to fill the template with, from the subject and what the person gave. Refuses what cannot be issued. */\n dataOf(context: ResolverContext, refId: string, input: IssueInput): Promise<IssuedDocumentData>\n /** Whether the caller may issue this kind for this subject - the owning module's rule. */\n mayIssue(context: ResolverContext, refId: string): Promise<boolean>\n /** Whether the caller may read a ledger row of this kind, and its file. */\n mayRead(context: ResolverContext, row: IssuedRow): Promise<boolean>\n}\n\nconst kinds = new Map<string, IssuedDocumentKind>()\n\n/** A module declares a kind it issues. The same `kind` again replaces it. */\nexport function registerIssuedDocumentKind(kind: IssuedDocumentKind): void {\n if (!/^[a-z0-9-]+\\.[a-z0-9.-]+$/.test(kind.kind)) throw new Error(`an issued document kind is <module>.<document>: ${kind.kind}`)\n if (!kind.prefix?.trim()) throw new Error(`the issued document kind ${kind.kind} has no number prefix`)\n kinds.set(kind.kind, kind)\n}\n\nexport function issuedDocumentKindOf(kind: string | null | undefined): IssuedDocumentKind | undefined {\n return kind ? kinds.get(kind) : undefined\n}\n\nexport function issuedDocumentKinds(): IssuedDocumentKind[] {\n return [...kinds.values()]\n}\n\n/** The number a document of a kind gets: `<prefix>-<year>-<sequence>`, the sequence four digits at least. */\nexport function issueNumberOf(prefix: string, year: number, sequence: number): string {\n return `${prefix}-${year}-${String(sequence).padStart(4, '0')}`\n}\n\n/** What a person gave, kept as the ledger keeps it - trimmed words, nothing for a blank. */\nexport function issueInputOf(input: IssueInput | null | undefined): { purpose: string | null; submittedTo: string | null; asOf: string | null } {\n const text = (value: unknown) => (typeof value === 'string' && value.trim() ? value.trim() : null)\n const asOf = text(input?.asOf)\n if (asOf && !/^\\d{4}-\\d{2}-\\d{2}$/.test(asOf)) throw new Error(`a day is YYYY-MM-DD: ${asOf}`)\n return { purpose: text(input?.purpose), submittedTo: text(input?.submittedTo), asOf }\n}\n\n/**\n * The file name of an issued document - what a person sees in their downloads: `<kind>_<subject>_<number>.pdf`, e.g.\n * `재직증명서_남종호_재직-2026-0001.pdf`. Characters a file system refuses go, and so does the ` · ` a subject name joins with.\n */\nexport function issuedFileNameOf(kindWord: string, subjectName: string | null | undefined, number: string): string {\n const clean = (text: string) =>\n text\n .replace(/\\s*·\\s*/g, '_')\n .replace(/[\\\\/:*?\"<>|\\u0000-\\u001f]+/g, '')\n .replace(/\\s+/g, ' ')\n .trim()\n return `${[kindWord, subjectName ?? '', number].map(clean).filter(Boolean).join('_')}.pdf`\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const attachment_base_1 = require("@things-factory/attachment-base");
|
|
4
|
+
const shell_1 = require("@things-factory/shell");
|
|
5
|
+
const pdf_release_1 = require("../service/pdf-release/pdf-release");
|
|
6
|
+
const pdf_release_service_1 = require("./pdf-release-service");
|
|
7
|
+
/**
|
|
8
|
+
* Who may open an issued document's file by its path: whoever may read its ledger row - its kind's module rule
|
|
9
|
+
* (ADR-0176 decision 2). attachment-base has already checked the file is of the request's domain.
|
|
10
|
+
*/
|
|
11
|
+
(0, attachment_base_1.registerAttachmentReader)('PDFRelease', async (attachment, context) => {
|
|
12
|
+
const row = attachment.refBy ? await (0, shell_1.getRepository)(pdf_release_1.PDFRelease, context.state.tx).findOne({ where: { id: attachment.refBy, domain: { id: context.state.domain.id } } }) : null;
|
|
13
|
+
return !!row && (await (0, pdf_release_service_1.mayReadRelease)(context, row));
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=pdf-release-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-release-reader.js","sourceRoot":"","sources":["../../server/controller/pdf-release-reader.ts"],"names":[],"mappings":";;AAAA,qEAA0E;AAC1E,iDAAqD;AAErD,oEAA+D;AAC/D,+DAAsD;AAEtD;;;GAGG;AACH,IAAA,0CAAwB,EAAC,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE;IACnE,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,IAAA,qBAAa,EAAC,wBAAU,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7K,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,IAAA,oCAAc,EAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;AACtD,CAAC,CAAC,CAAA","sourcesContent":["import { registerAttachmentReader } from '@things-factory/attachment-base'\nimport { getRepository } from '@things-factory/shell'\n\nimport { PDFRelease } from '../service/pdf-release/pdf-release'\nimport { mayReadRelease } from './pdf-release-service'\n\n/**\n * Who may open an issued document's file by its path: whoever may read its ledger row - its kind's module rule\n * (ADR-0176 decision 2). attachment-base has already checked the file is of the request's domain.\n */\nregisterAttachmentReader('PDFRelease', async (attachment, context) => {\n const row = attachment.refBy ? await getRepository(PDFRelease, context.state.tx).findOne({ where: { id: attachment.refBy, domain: { id: context.state.domain.id } } }) : null\n return !!row && (await mayReadRelease(context, row))\n})\n"]}
|
|
@@ -1,11 +1,36 @@
|
|
|
1
1
|
import { PDFRelease } from '../service/pdf-release/pdf-release';
|
|
2
2
|
import { PDFTemplate } from '../service/pdf-template/pdf-template';
|
|
3
|
+
import { IssueInput } from './issued-document-kind';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* privilege; this needs `context.state` (domain, user, tx).
|
|
5
|
+
* 「우리 회사」 as every template reads it - `{{company.name}}`, `{{company.seal}}` (ADR-0176 decision 4). The seal is a
|
|
6
|
+
* `data:` URL made here, on the server, for the print alone.
|
|
7
7
|
*/
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function companyForPrint(context: ResolverContext): Promise<Record<string, any>>;
|
|
9
|
+
/** The template a kind prints from in this domain: its own `PDFTemplate` of the kind, else the kind's template in code. */
|
|
10
|
+
export declare function templateOfKind(context: ResolverContext, kind: string): Promise<PDFTemplate | null>;
|
|
11
|
+
export interface IssueRequest {
|
|
12
|
+
/** A registered kind (`registerIssuedDocumentKind`): its number, its subject and its rules. */
|
|
13
|
+
kind: string;
|
|
14
|
+
/** What the document is about, as the kind's `refType` names it - none for a kind about the company itself (`Domain`). */
|
|
15
|
+
refId?: string | null;
|
|
16
|
+
input?: IssueInput | null;
|
|
17
|
+
/** A template the owning module picked for this subject (a product's own certificate) - before the domain's of the kind. */
|
|
18
|
+
template?: PDFTemplate | null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Issue a document - the one way a row reaches the ledger (ADR-0176 decision 2). The kind's module says whether the
|
|
22
|
+
* caller may issue it and what it prints; this numbers it per kind and year, fills the template with the kind's data,
|
|
23
|
+
* 「우리 회사」 and the issue (`{{issue.number}}`, `{{issue.issuedOn}}`, `{{issue.purpose}}`, `{{issue.submittedTo}}`),
|
|
24
|
+
* prints it, and keeps the row with its file. Runs in the request's transaction (`context.state`: domain, user, tx).
|
|
25
|
+
*/
|
|
26
|
+
export declare function releasePdf(context: ResolverContext, request: IssueRequest): Promise<{
|
|
9
27
|
release: PDFRelease;
|
|
10
28
|
contents: Buffer;
|
|
11
29
|
}>;
|
|
30
|
+
/** Whether the caller may read a ledger row: its kind's module says - a row of a kind no loaded module issues stays closed. */
|
|
31
|
+
export declare function mayReadRelease(context: ResolverContext, row: PDFRelease): Promise<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* Revoke an issued document (ADR-0176 decision 2): a reason is required; the row and its file stay. Whoever may issue
|
|
34
|
+
* the kind for its subject may revoke it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function revokeRelease(context: ResolverContext, id: string, reason: string): Promise<PDFRelease>;
|
|
@@ -1,23 +1,134 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.companyForPrint = companyForPrint;
|
|
4
|
+
exports.templateOfKind = templateOfKind;
|
|
3
5
|
exports.releasePdf = releasePdf;
|
|
6
|
+
exports.mayReadRelease = mayReadRelease;
|
|
7
|
+
exports.revokeRelease = revokeRelease;
|
|
4
8
|
const stream_1 = require("stream");
|
|
5
9
|
const attachment_base_1 = require("@things-factory/attachment-base");
|
|
10
|
+
const biz_base_1 = require("@things-factory/biz-base");
|
|
11
|
+
const shell_1 = require("@things-factory/shell");
|
|
6
12
|
const pdf_release_1 = require("../service/pdf-release/pdf-release");
|
|
13
|
+
const pdf_template_1 = require("../service/pdf-template/pdf-template");
|
|
14
|
+
const issued_document_kind_1 = require("./issued-document-kind");
|
|
7
15
|
const pdf_service_1 = require("./pdf-service");
|
|
8
16
|
const service = new pdf_service_1.PdfService();
|
|
9
|
-
/** A generated PDF handed to the attachment store as an upload would be. */
|
|
10
|
-
const upload = (filename, contents) => Promise.resolve({ filename, mimetype: 'application/pdf', encoding: '7bit', createReadStream: () => stream_1.Readable.from([contents]) });
|
|
11
17
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* privilege; this needs `context.state` (domain, user, tx).
|
|
18
|
+
* A generated PDF handed to the attachment store as an upload would be - its name spelled as the upload parser hands one
|
|
19
|
+
* over (latin1), which the store decodes back to UTF-8.
|
|
15
20
|
*/
|
|
16
|
-
|
|
21
|
+
const upload = (filename, contents) => Promise.resolve({ filename: Buffer.from(filename, 'utf8').toString('latin1'), mimetype: 'application/pdf', encoding: '7bit', createReadStream: () => stream_1.Readable.from([contents]) });
|
|
22
|
+
/**
|
|
23
|
+
* 「우리 회사」 as every template reads it - `{{company.name}}`, `{{company.seal}}` (ADR-0176 decision 4). The seal is a
|
|
24
|
+
* `data:` URL made here, on the server, for the print alone.
|
|
25
|
+
*/
|
|
26
|
+
async function companyForPrint(context) {
|
|
27
|
+
const { domain, tx } = context.state;
|
|
28
|
+
return (await (0, biz_base_1.printedCompanyOf)(domain, { seal: true, manager: tx }));
|
|
29
|
+
}
|
|
30
|
+
/** The template a kind prints from in this domain: its own `PDFTemplate` of the kind, else the kind's template in code. */
|
|
31
|
+
async function templateOfKind(context, kind) {
|
|
32
|
+
const { domain, tx } = context.state;
|
|
33
|
+
const rows = await tx.getRepository(pdf_template_1.PDFTemplate).find({ where: { domain: { id: domain.id }, kind }, order: { updatedAt: 'DESC' } });
|
|
34
|
+
return rows.find(one => one.active !== false) ?? null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The next sequence of a kind in a year - the last row of the kind and year locked in the request's transaction, so two
|
|
38
|
+
* issues at once cannot take one number (the unique index `ix_pdf_release_1` holds where there is no row to lock yet).
|
|
39
|
+
*/
|
|
40
|
+
async function nextSequence(context, kind, year) {
|
|
41
|
+
const { domain, tx } = context.state;
|
|
42
|
+
const query = tx
|
|
43
|
+
.getRepository(pdf_release_1.PDFRelease)
|
|
44
|
+
.createQueryBuilder('release')
|
|
45
|
+
.where('release.domain_id = :domain', { domain: domain.id })
|
|
46
|
+
.andWhere('release.kind = :kind', { kind })
|
|
47
|
+
.andWhere('release.year = :year', { year })
|
|
48
|
+
.orderBy('release.sequence', 'DESC')
|
|
49
|
+
.limit(1);
|
|
50
|
+
if (tx.connection.options.type === 'postgres')
|
|
51
|
+
query.setLock('pessimistic_write');
|
|
52
|
+
const last = await query.getOne();
|
|
53
|
+
return (last?.sequence ?? 0) + 1;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Issue a document - the one way a row reaches the ledger (ADR-0176 decision 2). The kind's module says whether the
|
|
57
|
+
* caller may issue it and what it prints; this numbers it per kind and year, fills the template with the kind's data,
|
|
58
|
+
* 「우리 회사」 and the issue (`{{issue.number}}`, `{{issue.issuedOn}}`, `{{issue.purpose}}`, `{{issue.submittedTo}}`),
|
|
59
|
+
* prints it, and keeps the row with its file. Runs in the request's transaction (`context.state`: domain, user, tx).
|
|
60
|
+
*/
|
|
61
|
+
async function releasePdf(context, request) {
|
|
17
62
|
const { domain, user, tx } = context.state;
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
63
|
+
const kind = (0, issued_document_kind_1.issuedDocumentKindOf)(request.kind);
|
|
64
|
+
if (!kind)
|
|
65
|
+
throw new shell_1.Refusal('issued-document-kind-unknown', { kind: request.kind }, `no module issues ${request.kind}`);
|
|
66
|
+
/* A document about the company itself is about the request's domain - whatever was named. */
|
|
67
|
+
const refId = kind.refType === 'Domain' ? domain.id : request.refId;
|
|
68
|
+
if (!refId || !(await kind.mayIssue(context, refId)))
|
|
69
|
+
throw new shell_1.Refusal('issued-document-not-permitted', { kind: request.kind }, `you may not issue ${request.kind} for this`);
|
|
70
|
+
const input = (0, issued_document_kind_1.issueInputOf)(request.input);
|
|
71
|
+
const issuedOn = (0, shell_1.calendarDay)(domain.timezone);
|
|
72
|
+
const { subjectName, data } = await kind.dataOf(context, refId, { ...input, asOf: input.asOf ?? issuedOn });
|
|
73
|
+
const template = request.template ?? (await templateOfKind(context, kind.kind));
|
|
74
|
+
const parts = template ?? kind.template;
|
|
75
|
+
const year = Number(issuedOn.slice(0, 4));
|
|
76
|
+
const sequence = await nextSequence(context, kind.kind, year);
|
|
77
|
+
const number = (0, issued_document_kind_1.issueNumberOf)(kind.prefix, year, sequence);
|
|
78
|
+
const issue = { number, issuedOn, purpose: input.purpose ?? '', submittedTo: input.submittedTo ?? '', asOf: input.asOf ?? issuedOn };
|
|
79
|
+
const contents = await service.generatePdf(parts, { ...data, company: await companyForPrint(context), issue });
|
|
80
|
+
const release = await tx.getRepository(pdf_release_1.PDFRelease).save({
|
|
81
|
+
domain,
|
|
82
|
+
name: number,
|
|
83
|
+
kind: kind.kind,
|
|
84
|
+
number,
|
|
85
|
+
year,
|
|
86
|
+
sequence,
|
|
87
|
+
refType: kind.refType,
|
|
88
|
+
refId,
|
|
89
|
+
subjectName,
|
|
90
|
+
purpose: input.purpose,
|
|
91
|
+
submittedTo: input.submittedTo,
|
|
92
|
+
template: template ?? null,
|
|
93
|
+
state: pdf_release_1.PDFReleaseStatus.published,
|
|
94
|
+
creator: user,
|
|
95
|
+
updater: user
|
|
96
|
+
});
|
|
97
|
+
const kindWord = String(context.t?.(`issued-document.${kind.kind}`) ?? '');
|
|
98
|
+
const fileName = (0, issued_document_kind_1.issuedFileNameOf)(kindWord && kindWord !== `issued-document.${kind.kind}` ? kindWord : kind.prefix, subjectName, number);
|
|
99
|
+
await (0, attachment_base_1.createAttachment)(null, { attachment: { file: upload(fileName, contents), refType: 'PDFRelease', refBy: release.id, category: 'document' } }, context);
|
|
21
100
|
return { release, contents };
|
|
22
101
|
}
|
|
102
|
+
/** Whether the caller may read a ledger row: its kind's module says - a row of a kind no loaded module issues stays closed. */
|
|
103
|
+
async function mayReadRelease(context, row) {
|
|
104
|
+
const kind = (0, issued_document_kind_1.issuedDocumentKindOf)(row.kind);
|
|
105
|
+
if (!kind)
|
|
106
|
+
return false;
|
|
107
|
+
try {
|
|
108
|
+
return (await kind.mayRead(context, row)) === true;
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Revoke an issued document (ADR-0176 decision 2): a reason is required; the row and its file stay. Whoever may issue
|
|
116
|
+
* the kind for its subject may revoke it.
|
|
117
|
+
*/
|
|
118
|
+
async function revokeRelease(context, id, reason) {
|
|
119
|
+
const { domain, user, tx } = context.state;
|
|
120
|
+
const repository = tx.getRepository(pdf_release_1.PDFRelease);
|
|
121
|
+
const row = await repository.findOne({ where: { domain: { id: domain.id }, id } });
|
|
122
|
+
if (!row)
|
|
123
|
+
throw new shell_1.Refusal('issued-document-not-found', {}, 'the issued document was not found');
|
|
124
|
+
const kind = (0, issued_document_kind_1.issuedDocumentKindOf)(row.kind);
|
|
125
|
+
if (!kind || !row.refId || !(await kind.mayIssue(context, row.refId)))
|
|
126
|
+
throw new shell_1.Refusal('issued-document-not-permitted', { kind: row.kind }, `you may not revoke ${row.kind}`);
|
|
127
|
+
const why = String(reason ?? '').trim();
|
|
128
|
+
if (!why)
|
|
129
|
+
throw new shell_1.Refusal('issued-document-revoke-reason-required', {}, 'say why it is revoked');
|
|
130
|
+
if (row.state === pdf_release_1.PDFReleaseStatus.revoked)
|
|
131
|
+
throw new shell_1.Refusal('issued-document-already-revoked', {}, 'it is revoked already');
|
|
132
|
+
return await repository.save({ ...row, state: pdf_release_1.PDFReleaseStatus.revoked, revokedAt: new Date(), revokeReason: why, updater: user });
|
|
133
|
+
}
|
|
23
134
|
//# sourceMappingURL=pdf-release-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf-release-service.js","sourceRoot":"","sources":["../../server/controller/pdf-release-service.ts"],"names":[],"mappings":";;AAmBA,gCAMC;AAzBD,mCAAiC;AAEjC,qEAAkE;AAElE,oEAAiF;AAEjF,+CAA0C;AAE1C,MAAM,OAAO,GAAG,IAAI,wBAAU,EAAE,CAAA;AAEhC,4EAA4E;AAC5E,MAAM,MAAM,GAAG,CAAC,QAAgB,EAAE,QAAgB,EAAE,EAAE,CACpD,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,iBAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAA;AAEjI;;;;GAIG;AACI,KAAK,UAAU,UAAU,CAAC,OAAwB,EAAE,QAAqB,EAAE,IAAS,EAAE,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE;IAClI,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAC1C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,wBAAU,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,8BAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IACpJ,MAAM,IAAA,kCAAgB,EAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IAChK,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAA;AAC9B,CAAC","sourcesContent":["import { Readable } from 'stream'\n\nimport { createAttachment } from '@things-factory/attachment-base'\n\nimport { PDFRelease, PDFReleaseStatus } from '../service/pdf-release/pdf-release'\nimport { PDFTemplate } from '../service/pdf-template/pdf-template'\nimport { PdfService } from './pdf-service'\n\nconst service = new PdfService()\n\n/** A generated PDF handed to the attachment store as an upload would be. */\nconst upload = (filename: string, contents: Buffer) =>\n Promise.resolve({ filename, mimetype: 'application/pdf', encoding: '7bit', createReadStream: () => Readable.from([contents]) })\n\n/**\n * Print a template with data and keep it — a PDFRelease whose file is an attachment of it. For a module that prints\n * its own documents (a certificate, a quotation) inside its own resolver: it holds the transaction and the\n * privilege; this needs `context.state` (domain, user, tx).\n */\nexport async function releasePdf(context: ResolverContext, template: PDFTemplate, data: any, name = `${template.name}-${Date.now()}`): Promise<{ release: PDFRelease; contents: Buffer }> {\n const { domain, user, tx } = context.state\n const contents = await service.generatePdf(template, data)\n const release = await tx.getRepository(PDFRelease).save({ domain, name, template, state: PDFReleaseStatus.published, creator: user, updater: user })\n await createAttachment(null, { attachment: { file: upload(`${name}.pdf`, contents), refType: 'PDFRelease', refBy: release.id, category: 'document' } }, context)\n return { release, contents }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pdf-release-service.js","sourceRoot":"","sources":["../../server/controller/pdf-release-service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Readable } from 'stream'\n\nimport { createAttachment } from '@things-factory/attachment-base'\nimport { printedCompanyOf } from '@things-factory/biz-base'\nimport { calendarDay, Refusal } from '@things-factory/shell'\n\nimport { PDFRelease, PDFReleaseStatus } from '../service/pdf-release/pdf-release'\nimport { PDFTemplate } from '../service/pdf-template/pdf-template'\nimport { IssueInput, issuedDocumentKindOf, issuedFileNameOf, issueInputOf, issueNumberOf } from './issued-document-kind'\nimport { PdfTemplateParts } from './pdf-document'\nimport { PdfService } from './pdf-service'\n\nconst service = new PdfService()\n\n/**\n * A generated PDF handed to the attachment store as an upload would be - its name spelled as the upload parser hands one\n * over (latin1), which the store decodes back to UTF-8.\n */\nconst upload = (filename: string, contents: Buffer) =>\n Promise.resolve({ filename: Buffer.from(filename, 'utf8').toString('latin1'), mimetype: 'application/pdf', encoding: '7bit', createReadStream: () => Readable.from([contents]) })\n\n/**\n * 「우리 회사」 as every template reads it - `{{company.name}}`, `{{company.seal}}` (ADR-0176 decision 4). The seal is a\n * `data:` URL made here, on the server, for the print alone.\n */\nexport async function companyForPrint(context: ResolverContext): Promise<Record<string, any>> {\n const { domain, tx } = context.state\n return (await printedCompanyOf(domain, { seal: true, manager: tx })) as any\n}\n\n/** The template a kind prints from in this domain: its own `PDFTemplate` of the kind, else the kind's template in code. */\nexport async function templateOfKind(context: ResolverContext, kind: string): Promise<PDFTemplate | null> {\n const { domain, tx } = context.state\n const rows = await tx.getRepository(PDFTemplate).find({ where: { domain: { id: domain.id }, kind }, order: { updatedAt: 'DESC' } })\n return rows.find(one => one.active !== false) ?? null\n}\n\n/**\n * The next sequence of a kind in a year - the last row of the kind and year locked in the request's transaction, so two\n * issues at once cannot take one number (the unique index `ix_pdf_release_1` holds where there is no row to lock yet).\n */\nasync function nextSequence(context: ResolverContext, kind: string, year: number): Promise<number> {\n const { domain, tx } = context.state\n const query = tx\n .getRepository(PDFRelease)\n .createQueryBuilder('release')\n .where('release.domain_id = :domain', { domain: domain.id })\n .andWhere('release.kind = :kind', { kind })\n .andWhere('release.year = :year', { year })\n .orderBy('release.sequence', 'DESC')\n .limit(1)\n if (tx.connection.options.type === 'postgres') query.setLock('pessimistic_write')\n const last = await query.getOne()\n return (last?.sequence ?? 0) + 1\n}\n\nexport interface IssueRequest {\n /** A registered kind (`registerIssuedDocumentKind`): its number, its subject and its rules. */\n kind: string\n /** What the document is about, as the kind's `refType` names it - none for a kind about the company itself (`Domain`). */\n refId?: string | null\n input?: IssueInput | null\n /** A template the owning module picked for this subject (a product's own certificate) - before the domain's of the kind. */\n template?: PDFTemplate | null\n}\n\n/**\n * Issue a document - the one way a row reaches the ledger (ADR-0176 decision 2). The kind's module says whether the\n * caller may issue it and what it prints; this numbers it per kind and year, fills the template with the kind's data,\n * 「우리 회사」 and the issue (`{{issue.number}}`, `{{issue.issuedOn}}`, `{{issue.purpose}}`, `{{issue.submittedTo}}`),\n * prints it, and keeps the row with its file. Runs in the request's transaction (`context.state`: domain, user, tx).\n */\nexport async function releasePdf(context: ResolverContext, request: IssueRequest): Promise<{ release: PDFRelease; contents: Buffer }> {\n const { domain, user, tx } = context.state\n const kind = issuedDocumentKindOf(request.kind)\n if (!kind) throw new Refusal('issued-document-kind-unknown', { kind: request.kind }, `no module issues ${request.kind}`)\n /* A document about the company itself is about the request's domain - whatever was named. */\n const refId = kind.refType === 'Domain' ? domain.id : request.refId\n if (!refId || !(await kind.mayIssue(context, refId))) throw new Refusal('issued-document-not-permitted', { kind: request.kind }, `you may not issue ${request.kind} for this`)\n\n const input = issueInputOf(request.input)\n const issuedOn = calendarDay(domain.timezone)\n const { subjectName, data } = await kind.dataOf(context, refId, { ...input, asOf: input.asOf ?? issuedOn })\n const template: PDFTemplate | null = request.template ?? (await templateOfKind(context, kind.kind))\n const parts: PdfTemplateParts = template ?? kind.template\n\n const year = Number(issuedOn.slice(0, 4))\n const sequence = await nextSequence(context, kind.kind, year)\n const number = issueNumberOf(kind.prefix, year, sequence)\n const issue = { number, issuedOn, purpose: input.purpose ?? '', submittedTo: input.submittedTo ?? '', asOf: input.asOf ?? issuedOn }\n const contents = await service.generatePdf(parts, { ...data, company: await companyForPrint(context), issue })\n\n const release = await tx.getRepository(PDFRelease).save({\n domain,\n name: number,\n kind: kind.kind,\n number,\n year,\n sequence,\n refType: kind.refType,\n refId,\n subjectName,\n purpose: input.purpose,\n submittedTo: input.submittedTo,\n template: template ?? null,\n state: PDFReleaseStatus.published,\n creator: user,\n updater: user\n } as any)\n const kindWord = String(context.t?.(`issued-document.${kind.kind}`) ?? '')\n const fileName = issuedFileNameOf(kindWord && kindWord !== `issued-document.${kind.kind}` ? kindWord : kind.prefix, subjectName, number)\n await createAttachment(null, { attachment: { file: upload(fileName, contents), refType: 'PDFRelease', refBy: release.id, category: 'document' } }, context)\n return { release, contents }\n}\n\n/** Whether the caller may read a ledger row: its kind's module says - a row of a kind no loaded module issues stays closed. */\nexport async function mayReadRelease(context: ResolverContext, row: PDFRelease): Promise<boolean> {\n const kind = issuedDocumentKindOf(row.kind)\n if (!kind) return false\n try {\n return (await kind.mayRead(context, row)) === true\n } catch {\n return false\n }\n}\n\n/**\n * Revoke an issued document (ADR-0176 decision 2): a reason is required; the row and its file stay. Whoever may issue\n * the kind for its subject may revoke it.\n */\nexport async function revokeRelease(context: ResolverContext, id: string, reason: string): Promise<PDFRelease> {\n const { domain, user, tx } = context.state\n const repository = tx.getRepository(PDFRelease)\n const row = await repository.findOne({ where: { domain: { id: domain.id }, id } })\n if (!row) throw new Refusal('issued-document-not-found', {}, 'the issued document was not found')\n const kind = issuedDocumentKindOf(row.kind)\n if (!kind || !row.refId || !(await kind.mayIssue(context, row.refId))) throw new Refusal('issued-document-not-permitted', { kind: row.kind }, `you may not revoke ${row.kind}`)\n const why = String(reason ?? '').trim()\n if (!why) throw new Refusal('issued-document-revoke-reason-required', {}, 'say why it is revoked')\n if (row.state === PDFReleaseStatus.revoked) throw new Refusal('issued-document-already-revoked', {}, 'it is revoked already')\n return await repository.save({ ...row, state: PDFReleaseStatus.revoked, revokedAt: new Date(), revokeReason: why, updater: user })\n}\n"]}
|
package/dist-server/index.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export * from './service';
|
|
2
2
|
export { composePdfDocument, PAGE_SIZES } from './controller/pdf-document';
|
|
3
|
+
export type { PdfTemplateParts } from './controller/pdf-document';
|
|
3
4
|
export { PdfService } from './controller/pdf-service';
|
|
4
|
-
export { releasePdf } from './controller/pdf-release-service';
|
|
5
|
+
export { companyForPrint, mayReadRelease, releasePdf, revokeRelease, templateOfKind } from './controller/pdf-release-service';
|
|
6
|
+
export type { IssueRequest } from './controller/pdf-release-service';
|
|
7
|
+
export { issuedDocumentKindOf, issuedDocumentKinds, issuedFileNameOf, issueInputOf, issueNumberOf, registerIssuedDocumentKind } from './controller/issued-document-kind';
|
|
8
|
+
export type { IssuedDocumentData, IssuedDocumentKind, IssuedRow, IssueInput } from './controller/issued-document-kind';
|
|
9
|
+
import './controller/pdf-release-reader';
|
package/dist-server/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.releasePdf = exports.PdfService = exports.PAGE_SIZES = exports.composePdfDocument = void 0;
|
|
3
|
+
exports.registerIssuedDocumentKind = exports.issueNumberOf = exports.issueInputOf = exports.issuedFileNameOf = exports.issuedDocumentKinds = exports.issuedDocumentKindOf = exports.templateOfKind = exports.revokeRelease = exports.releasePdf = exports.mayReadRelease = exports.companyForPrint = exports.PdfService = exports.PAGE_SIZES = exports.composePdfDocument = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
tslib_1.__exportStar(require("./service"), exports);
|
|
6
6
|
var pdf_document_1 = require("./controller/pdf-document");
|
|
@@ -9,7 +9,19 @@ Object.defineProperty(exports, "PAGE_SIZES", { enumerable: true, get: function (
|
|
|
9
9
|
var pdf_service_1 = require("./controller/pdf-service");
|
|
10
10
|
Object.defineProperty(exports, "PdfService", { enumerable: true, get: function () { return pdf_service_1.PdfService; } });
|
|
11
11
|
var pdf_release_service_1 = require("./controller/pdf-release-service");
|
|
12
|
+
Object.defineProperty(exports, "companyForPrint", { enumerable: true, get: function () { return pdf_release_service_1.companyForPrint; } });
|
|
13
|
+
Object.defineProperty(exports, "mayReadRelease", { enumerable: true, get: function () { return pdf_release_service_1.mayReadRelease; } });
|
|
12
14
|
Object.defineProperty(exports, "releasePdf", { enumerable: true, get: function () { return pdf_release_service_1.releasePdf; } });
|
|
15
|
+
Object.defineProperty(exports, "revokeRelease", { enumerable: true, get: function () { return pdf_release_service_1.revokeRelease; } });
|
|
16
|
+
Object.defineProperty(exports, "templateOfKind", { enumerable: true, get: function () { return pdf_release_service_1.templateOfKind; } });
|
|
17
|
+
var issued_document_kind_1 = require("./controller/issued-document-kind");
|
|
18
|
+
Object.defineProperty(exports, "issuedDocumentKindOf", { enumerable: true, get: function () { return issued_document_kind_1.issuedDocumentKindOf; } });
|
|
19
|
+
Object.defineProperty(exports, "issuedDocumentKinds", { enumerable: true, get: function () { return issued_document_kind_1.issuedDocumentKinds; } });
|
|
20
|
+
Object.defineProperty(exports, "issuedFileNameOf", { enumerable: true, get: function () { return issued_document_kind_1.issuedFileNameOf; } });
|
|
21
|
+
Object.defineProperty(exports, "issueInputOf", { enumerable: true, get: function () { return issued_document_kind_1.issueInputOf; } });
|
|
22
|
+
Object.defineProperty(exports, "issueNumberOf", { enumerable: true, get: function () { return issued_document_kind_1.issueNumberOf; } });
|
|
23
|
+
Object.defineProperty(exports, "registerIssuedDocumentKind", { enumerable: true, get: function () { return issued_document_kind_1.registerIssuedDocumentKind; } });
|
|
24
|
+
require("./controller/pdf-release-reader");
|
|
13
25
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
14
26
|
const role_tasks_1 = require("./role-tasks");
|
|
15
27
|
for (const task of role_tasks_1.ROLE_TASKS)
|
package/dist-server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,oDAAyB;AACzB,0DAA0E;AAAjE,kHAAA,kBAAkB,OAAA;AAAE,0GAAA,UAAU,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,oDAAyB;AACzB,0DAA0E;AAAjE,kHAAA,kBAAkB,OAAA;AAAE,0GAAA,UAAU,OAAA;AAEvC,wDAAqD;AAA5C,yGAAA,UAAU,OAAA;AACnB,wEAA6H;AAApH,sHAAA,eAAe,OAAA;AAAE,qHAAA,cAAc,OAAA;AAAE,iHAAA,UAAU,OAAA;AAAE,oHAAA,aAAa,OAAA;AAAE,qHAAA,cAAc,OAAA;AAEnF,0EAAwK;AAA/J,4HAAA,oBAAoB,OAAA;AAAE,2HAAA,mBAAmB,OAAA;AAAE,wHAAA,gBAAgB,OAAA;AAAE,oHAAA,YAAY,OAAA;AAAE,qHAAA,aAAa,OAAA;AAAE,kIAAA,0BAA0B,OAAA;AAG7H,2CAAwC;AAExC,yDAA4D;AAC5D,6CAAyC;AAEzC,KAAK,MAAM,IAAI,IAAI,uBAAU;IAAE,IAAA,4BAAgB,EAAC,IAAI,CAAC,CAAA","sourcesContent":["export * from './service'\nexport { composePdfDocument, PAGE_SIZES } from './controller/pdf-document'\nexport type { PdfTemplateParts } from './controller/pdf-document'\nexport { PdfService } from './controller/pdf-service'\nexport { companyForPrint, mayReadRelease, releasePdf, revokeRelease, templateOfKind } from './controller/pdf-release-service'\nexport type { IssueRequest } from './controller/pdf-release-service'\nexport { issuedDocumentKindOf, issuedDocumentKinds, issuedFileNameOf, issueInputOf, issueNumberOf, registerIssuedDocumentKind } from './controller/issued-document-kind'\nexport type { IssuedDocumentData, IssuedDocumentKind, IssuedRow, IssueInput } from './controller/issued-document-kind'\n\nimport './controller/pdf-release-reader'\n\nimport { registerRoleTask } from '@things-factory/auth-base'\nimport { ROLE_TASKS } from './role-tasks'\n\nfor (const task of ROLE_TASKS) registerRoleTask(task)\n"]}
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.ROLE_TASKS = void 0;
|
|
12
12
|
exports.ROLE_TASKS = [
|
|
13
|
-
{ id: 'pdf.templates', grants: [{ category: 'pdf', axes: ['query', 'mutation'] }] }
|
|
13
|
+
{ id: 'pdf.templates', grants: [{ category: 'pdf', axes: ['query', 'mutation'] }] },
|
|
14
|
+
/* The whole issuance ledger - every document issued, to find one by its number (ADR-0176); a file opens by its kind's rule. */
|
|
15
|
+
{ id: 'pdf.issuance-ledger', grants: [{ category: 'issued-document', axes: ['query'] }] }
|
|
14
16
|
];
|
|
15
17
|
//# sourceMappingURL=role-tasks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-tasks.js","sourceRoot":"","sources":["../server/role-tasks.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAIU,QAAA,UAAU,GAAe;IACpC,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"role-tasks.js","sourceRoot":"","sources":["../server/role-tasks.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAIU,QAAA,UAAU,GAAe;IACpC,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,CAAC,EAAE;IACnF,+HAA+H;IAC/H,EAAE,EAAE,EAAE,qBAAqB,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;CAC1F,CAAA","sourcesContent":["/*\n * The work this module names, for the seats applications build (ADR-0139 decision 11).\n *\n * A task holds whole privileges: each opens everything its doors open, and the words under `task.<id>` in this\n * module's translations say what that is. Seats are put together by applications (`RoleTemplate.tasks`).\n *\n * Data only - `server/index.ts` registers it - so an application's tests read it without starting the framework.\n */\n\nimport type { RoleTask } from '@things-factory/auth-base'\n\nexport const ROLE_TASKS: RoleTask[] = [\n { id: 'pdf.templates', grants: [{ category: 'pdf', axes: ['query', 'mutation'] }] },\n /* The whole issuance ledger - every document issued, to find one by its number (ADR-0176); a file opens by its kind's rule. */\n { id: 'pdf.issuance-ledger', grants: [{ category: 'issued-document', axes: ['query'] }] }\n]\n"]}
|
|
@@ -3,5 +3,14 @@ export * from './pdf-template/pdf-template';
|
|
|
3
3
|
export declare const entities: (typeof import("./pdf-template/pdf-template").PDFTemplate | typeof import("./pdf-release/pdf-release").PDFRelease)[];
|
|
4
4
|
export declare const subscribers: any[];
|
|
5
5
|
export declare const schema: {
|
|
6
|
-
|
|
6
|
+
openFields: {
|
|
7
|
+
byDesign: {
|
|
8
|
+
'Query.readableIssuedDocuments': string;
|
|
9
|
+
'Query.issuedDocument': string;
|
|
10
|
+
'Query.issuedDocumentKinds': string;
|
|
11
|
+
'Mutation.issueDocument': string;
|
|
12
|
+
'Mutation.revokeIssuedDocument': string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
resolverClasses: (typeof import("./pdf-release/pdf-release-query").PDFReleaseQuery | typeof import("./pdf-generate/pdf-generate-resolver").PDFGenerateResolver | typeof import("./pdf-template/pdf-template-query").PDFTemplateQuery | typeof import("./pdf-template/pdf-template-mutation").PDFTemplateMutation)[];
|
|
7
16
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yBAAyB;AACzB,oEAAyC;AACzC,sEAA2C;AAE3C,mCAAmC;AACnC,+
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yBAAyB;AACzB,oEAAyC;AACzC,sEAA2C;AAE3C,mCAAmC;AACnC,+CAKsB;AACtB,iDAAkE;AAClE,iDAIuB;AAEV,QAAA,QAAQ,GAAG;IACtB,cAAc;IACd,GAAG,sBAAkB;IACrB,GAAG,uBAAmB;CACvB,CAAA;AAEY,QAAA,WAAW,GAAG;IACzB,iBAAiB;IACjB,GAAG,yBAAqB;IACxB,GAAG,0BAAsB;CAC1B,CAAA;AAEY,QAAA,MAAM,GAAG;IACpB,UAAU,EAAE,EAAE,QAAQ,EAAE,yBAAoB,EAAE;IAC9C,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,uBAAmB;QACtB,GAAG,wBAAoB;QACvB,GAAG,wBAAoB;KACxB;CACF,CAAA","sourcesContent":["/* EXPORT ENTITY TYPES */\nexport * from './pdf-release/pdf-release'\nexport * from './pdf-template/pdf-template'\n\n/* IMPORT ENTITIES AND RESOLVERS */\nimport {\n OPEN_FIELDS as PdfReleaseOpenFields,\n entities as PdfReleaseEntities,\n resolvers as PdfReleaseResolvers,\n subscribers as PdfReleaseSubscribers\n} from './pdf-release'\nimport { resolvers as PDFGenerateResolvers } from './pdf-generate'\nimport {\n entities as PDFTemplateEntities,\n resolvers as PDFTemplateResolvers,\n subscribers as PDFTemplateSubscribers\n} from './pdf-template'\n\nexport const entities = [\n /* ENTITIES */\n ...PdfReleaseEntities,\n ...PDFTemplateEntities\n]\n\nexport const subscribers = [\n /* SUBSCRIBERS */\n ...PdfReleaseSubscribers,\n ...PDFTemplateSubscribers\n]\n\nexport const schema = {\n openFields: { byDesign: PdfReleaseOpenFields },\n resolverClasses: [\n /* RESOLVER CLASSES */\n ...PdfReleaseResolvers,\n ...PDFTemplateResolvers,\n ...PDFGenerateResolvers\n ]\n}\n"]}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { PDFRelease } from '../pdf-release/pdf-release';
|
|
2
1
|
export declare class PDFGenerateResolver {
|
|
3
2
|
private pdfService;
|
|
4
3
|
private templateOf;
|
|
5
4
|
renderPDF(templateId: string, data: any, context: ResolverContext): Promise<string>;
|
|
6
|
-
generatePDF(templateId: string, data: any, context: ResolverContext): Promise<PDFRelease>;
|
|
7
5
|
}
|
|
@@ -4,9 +4,8 @@ exports.PDFGenerateResolver = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const shell_1 = require("@things-factory/shell");
|
|
7
|
-
const pdf_service_1 = require("../../controller/pdf-service");
|
|
8
7
|
const pdf_release_service_1 = require("../../controller/pdf-release-service");
|
|
9
|
-
const
|
|
8
|
+
const pdf_service_1 = require("../../controller/pdf-service");
|
|
10
9
|
const pdf_template_1 = require("../pdf-template/pdf-template");
|
|
11
10
|
let PDFGenerateResolver = class PDFGenerateResolver {
|
|
12
11
|
constructor() {
|
|
@@ -19,18 +18,20 @@ let PDFGenerateResolver = class PDFGenerateResolver {
|
|
|
19
18
|
throw new Error(context.t('error.pdf-template-not-found'));
|
|
20
19
|
return template;
|
|
21
20
|
}
|
|
21
|
+
/*
|
|
22
|
+
* A preview for whoever keeps the templates: the sample data with 「우리 회사」 (`company`, its seal printed) as an issue
|
|
23
|
+
* would carry it. Nothing is kept - documents are issued through `issueDocument` (`releasePdf`) alone.
|
|
24
|
+
*/
|
|
22
25
|
async renderPDF(templateId, data, context) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
async generatePDF(templateId, data, context) {
|
|
26
|
-
return (await (0, pdf_release_service_1.releasePdf)(context, await this.templateOf(context, templateId), data)).release;
|
|
26
|
+
const template = await this.templateOf(context, templateId);
|
|
27
|
+
return (await this.pdfService.generatePdf(template, { ...(data ?? {}), company: await (0, pdf_release_service_1.companyForPrint)(context) })).toString('base64');
|
|
27
28
|
}
|
|
28
29
|
};
|
|
29
30
|
exports.PDFGenerateResolver = PDFGenerateResolver;
|
|
30
31
|
tslib_1.__decorate([
|
|
31
32
|
(0, type_graphql_1.Directive)('@privilege(category: "pdf", privilege: "query", domainOwnerGranted: true)'),
|
|
32
33
|
(0, type_graphql_1.Directive)('@transaction'),
|
|
33
|
-
(0, type_graphql_1.Query)(() => String, { description: 'To print a template with data to a PDF without keeping it
|
|
34
|
+
(0, type_graphql_1.Query)(() => String, { description: 'To print a template with sample data to a PDF without keeping it - base64, for a preview' }),
|
|
34
35
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('templateId')),
|
|
35
36
|
tslib_1.__param(1, (0, type_graphql_1.Arg)('data', type => shell_1.ScalarObject, { nullable: true })),
|
|
36
37
|
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
@@ -38,17 +39,6 @@ tslib_1.__decorate([
|
|
|
38
39
|
tslib_1.__metadata("design:paramtypes", [String, Object, Object]),
|
|
39
40
|
tslib_1.__metadata("design:returntype", Promise)
|
|
40
41
|
], PDFGenerateResolver.prototype, "renderPDF", null);
|
|
41
|
-
tslib_1.__decorate([
|
|
42
|
-
(0, type_graphql_1.Directive)('@privilege(category: "pdf", privilege: "mutation", domainOwnerGranted: true)'),
|
|
43
|
-
(0, type_graphql_1.Directive)('@transaction'),
|
|
44
|
-
(0, type_graphql_1.Mutation)(() => pdf_release_1.PDFRelease, { description: 'To print a template with data to a PDF and keep it as a release — its file is an attachment of the release' }),
|
|
45
|
-
tslib_1.__param(0, (0, type_graphql_1.Arg)('templateId')),
|
|
46
|
-
tslib_1.__param(1, (0, type_graphql_1.Arg)('data', type => shell_1.ScalarObject, { nullable: true })),
|
|
47
|
-
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
48
|
-
tslib_1.__metadata("design:type", Function),
|
|
49
|
-
tslib_1.__metadata("design:paramtypes", [String, Object, Object]),
|
|
50
|
-
tslib_1.__metadata("design:returntype", Promise)
|
|
51
|
-
], PDFGenerateResolver.prototype, "generatePDF", null);
|
|
52
42
|
exports.PDFGenerateResolver = PDFGenerateResolver = tslib_1.__decorate([
|
|
53
43
|
(0, type_graphql_1.Resolver)()
|
|
54
44
|
], PDFGenerateResolver);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf-generate-resolver.js","sourceRoot":"","sources":["../../../server/service/pdf-generate/pdf-generate-resolver.ts"],"names":[],"mappings":";;;;AAAA,+
|
|
1
|
+
{"version":3,"file":"pdf-generate-resolver.js","sourceRoot":"","sources":["../../../server/service/pdf-generate/pdf-generate-resolver.ts"],"names":[],"mappings":";;;;AAAA,+CAAmE;AAEnE,iDAAoD;AAEpD,8EAAsE;AACtE,8DAAyD;AACzD,+DAA0D;AAGnD,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAAzB;QACG,eAAU,GAAG,IAAI,wBAAU,EAAE,CAAA;IAoBvC,CAAC;IAlBS,KAAK,CAAC,UAAU,CAAC,OAAwB,EAAE,UAAkB;QACnE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QACpC,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,0BAAW,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QACtH,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAA;QACzE,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED;;;OAGG;IAIG,AAAN,KAAK,CAAC,SAAS,CAAoB,UAAkB,EAAyD,IAAS,EAAS,OAAwB;QACtJ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAC3D,OAAO,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,IAAA,qCAAe,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IACvI,CAAC;CACF,CAAA;AArBY,kDAAmB;AAiBxB;IAHL,IAAA,wBAAS,EAAC,2EAA2E,CAAC;IACtF,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,oBAAK,EAAC,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,0FAA0F,EAAE,CAAC;IAChH,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IAAsB,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAAa,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;oDAG9H;8BApBU,mBAAmB;IAD/B,IAAA,uBAAQ,GAAE;GACE,mBAAmB,CAqB/B","sourcesContent":["import { Arg, Ctx, Directive, Query, Resolver } from 'type-graphql'\n\nimport { ScalarObject } from '@things-factory/shell'\n\nimport { companyForPrint } from '../../controller/pdf-release-service'\nimport { PdfService } from '../../controller/pdf-service'\nimport { PDFTemplate } from '../pdf-template/pdf-template'\n\n@Resolver()\nexport class PDFGenerateResolver {\n private pdfService = new PdfService()\n\n private async templateOf(context: ResolverContext, templateId: string): Promise<PDFTemplate> {\n const { domain, tx } = context.state\n const template = await tx.getRepository(PDFTemplate).findOne({ where: { id: templateId, domain: { id: domain.id } } })\n if (!template) throw new Error(context.t('error.pdf-template-not-found'))\n return template\n }\n\n /*\n * A preview for whoever keeps the templates: the sample data with 「우리 회사」 (`company`, its seal printed) as an issue\n * would carry it. Nothing is kept - documents are issued through `issueDocument` (`releasePdf`) alone.\n */\n @Directive('@privilege(category: \"pdf\", privilege: \"query\", domainOwnerGranted: true)')\n @Directive('@transaction')\n @Query(() => String, { description: 'To print a template with sample data to a PDF without keeping it - base64, for a preview' })\n async renderPDF(@Arg('templateId') templateId: string, @Arg('data', type => ScalarObject, { nullable: true }) data: any, @Ctx() context: ResolverContext): Promise<string> {\n const template = await this.templateOf(context, templateId)\n return (await this.pdfService.generatePdf(template, { ...(data ?? {}), company: await companyForPrint(context) })).toString('base64')\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PDFRelease } from './pdf-release';
|
|
2
2
|
import { PDFReleaseQuery } from './pdf-release-query';
|
|
3
|
-
|
|
3
|
+
export { OPEN_FIELDS } from './pdf-release-query';
|
|
4
4
|
export declare const entities: (typeof PDFRelease)[];
|
|
5
|
-
export declare const resolvers: (typeof PDFReleaseQuery
|
|
5
|
+
export declare const resolvers: (typeof PDFReleaseQuery)[];
|
|
6
6
|
export declare const subscribers: any[];
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.subscribers = exports.resolvers = exports.entities = void 0;
|
|
3
|
+
exports.subscribers = exports.resolvers = exports.entities = exports.OPEN_FIELDS = void 0;
|
|
4
4
|
const pdf_release_1 = require("./pdf-release");
|
|
5
5
|
const pdf_release_query_1 = require("./pdf-release-query");
|
|
6
|
-
|
|
6
|
+
var pdf_release_query_2 = require("./pdf-release-query");
|
|
7
|
+
Object.defineProperty(exports, "OPEN_FIELDS", { enumerable: true, get: function () { return pdf_release_query_2.OPEN_FIELDS; } });
|
|
7
8
|
exports.entities = [pdf_release_1.PDFRelease];
|
|
8
|
-
exports.resolvers = [pdf_release_query_1.PDFReleaseQuery
|
|
9
|
+
exports.resolvers = [pdf_release_query_1.PDFReleaseQuery];
|
|
9
10
|
exports.subscribers = [];
|
|
10
11
|
//# sourceMappingURL=index.js.map
|