@things-factory/inquiry 0.0.0-stage → 10.1.252

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.
Files changed (106) hide show
  1. package/client/bootstrap.ts +27 -0
  2. package/client/components/inquiry-thread.ts +277 -0
  3. package/client/components/inquiry-todo.ts +36 -0
  4. package/client/components/inquiry-writer.ts +212 -0
  5. package/client/index.ts +2 -0
  6. package/client/inquiry-watch.ts +45 -0
  7. package/client/pages/inquiry-list.ts +218 -0
  8. package/client/route.ts +8 -0
  9. package/client/tsconfig.json +13 -0
  10. package/client/utils/inquiry-api.ts +103 -0
  11. package/client/utils/inquiry-badge.ts +46 -0
  12. package/client/utils/inquiry-words.ts +26 -0
  13. package/dist-client/bootstrap.d.ts +2 -0
  14. package/dist-client/bootstrap.js +25 -0
  15. package/dist-client/bootstrap.js.map +1 -0
  16. package/dist-client/components/inquiry-thread.d.ts +28 -0
  17. package/dist-client/components/inquiry-thread.js +303 -0
  18. package/dist-client/components/inquiry-thread.js.map +1 -0
  19. package/dist-client/components/inquiry-todo.d.ts +9 -0
  20. package/dist-client/components/inquiry-todo.js +43 -0
  21. package/dist-client/components/inquiry-todo.js.map +1 -0
  22. package/dist-client/components/inquiry-writer.d.ts +25 -0
  23. package/dist-client/components/inquiry-writer.js +233 -0
  24. package/dist-client/components/inquiry-writer.js.map +1 -0
  25. package/dist-client/index.d.ts +2 -0
  26. package/dist-client/index.js +3 -0
  27. package/dist-client/index.js.map +1 -0
  28. package/dist-client/inquiry-watch.d.ts +2 -0
  29. package/dist-client/inquiry-watch.js +41 -0
  30. package/dist-client/inquiry-watch.js.map +1 -0
  31. package/dist-client/pages/inquiry-list.d.ts +56 -0
  32. package/dist-client/pages/inquiry-list.js +241 -0
  33. package/dist-client/pages/inquiry-list.js.map +1 -0
  34. package/dist-client/route.d.ts +1 -0
  35. package/dist-client/route.js +9 -0
  36. package/dist-client/route.js.map +1 -0
  37. package/dist-client/tsconfig.tsbuildinfo +1 -0
  38. package/dist-client/utils/inquiry-api.d.ts +73 -0
  39. package/dist-client/utils/inquiry-api.js +34 -0
  40. package/dist-client/utils/inquiry-api.js.map +1 -0
  41. package/dist-client/utils/inquiry-badge.d.ts +4 -0
  42. package/dist-client/utils/inquiry-badge.js +47 -0
  43. package/dist-client/utils/inquiry-badge.js.map +1 -0
  44. package/dist-client/utils/inquiry-words.d.ts +13 -0
  45. package/dist-client/utils/inquiry-words.js +22 -0
  46. package/dist-client/utils/inquiry-words.js.map +1 -0
  47. package/dist-server/attachment-reader.d.ts +1 -0
  48. package/dist-server/attachment-reader.js +21 -0
  49. package/dist-server/attachment-reader.js.map +1 -0
  50. package/dist-server/index.d.ts +2 -0
  51. package/dist-server/index.js +22 -0
  52. package/dist-server/index.js.map +1 -0
  53. package/dist-server/inquiry-activity.d.ts +38 -0
  54. package/dist-server/inquiry-activity.js +38 -0
  55. package/dist-server/inquiry-activity.js.map +1 -0
  56. package/dist-server/role-tasks.d.ts +2 -0
  57. package/dist-server/role-tasks.js +14 -0
  58. package/dist-server/role-tasks.js.map +1 -0
  59. package/dist-server/service/index.d.ts +7 -0
  60. package/dist-server/service/index.js +24 -0
  61. package/dist-server/service/index.js.map +1 -0
  62. package/dist-server/service/inquiry/index.d.ts +4 -0
  63. package/dist-server/service/inquiry/index.js +8 -0
  64. package/dist-server/service/inquiry/index.js.map +1 -0
  65. package/dist-server/service/inquiry/inquiry-resolver.d.ts +29 -0
  66. package/dist-server/service/inquiry/inquiry-resolver.js +407 -0
  67. package/dist-server/service/inquiry/inquiry-resolver.js.map +1 -0
  68. package/dist-server/service/inquiry/inquiry-rules.d.ts +88 -0
  69. package/dist-server/service/inquiry/inquiry-rules.js +157 -0
  70. package/dist-server/service/inquiry/inquiry-rules.js.map +1 -0
  71. package/dist-server/service/inquiry/inquiry-service.d.ts +35 -0
  72. package/dist-server/service/inquiry/inquiry-service.js +143 -0
  73. package/dist-server/service/inquiry/inquiry-service.js.map +1 -0
  74. package/dist-server/service/inquiry/inquiry-types.d.ts +18 -0
  75. package/dist-server/service/inquiry/inquiry-types.js +69 -0
  76. package/dist-server/service/inquiry/inquiry-types.js.map +1 -0
  77. package/dist-server/service/inquiry/inquiry.d.ts +48 -0
  78. package/dist-server/service/inquiry/inquiry.js +232 -0
  79. package/dist-server/service/inquiry/inquiry.js.map +1 -0
  80. package/dist-server/tsconfig.tsbuildinfo +1 -0
  81. package/package.json +51 -4
  82. package/server/attachment-reader.ts +18 -0
  83. package/server/index.ts +18 -0
  84. package/server/inquiry-activity.ts +35 -0
  85. package/server/role-tasks.ts +13 -0
  86. package/server/service/index.ts +19 -0
  87. package/server/service/inquiry/index.ts +5 -0
  88. package/server/service/inquiry/inquiry-resolver.ts +321 -0
  89. package/server/service/inquiry/inquiry-rules.ts +173 -0
  90. package/server/service/inquiry/inquiry-service.ts +143 -0
  91. package/server/service/inquiry/inquiry-types.ts +45 -0
  92. package/server/service/inquiry/inquiry.ts +180 -0
  93. package/server/tsconfig.json +11 -0
  94. package/test/inquiry-persistence.test.ts +218 -0
  95. package/test/inquiry-rules.test.ts +121 -0
  96. package/test/open-doors.test.ts +44 -0
  97. package/test/translations.test.ts +53 -0
  98. package/test/writer-popup-standard.test.ts +40 -0
  99. package/things-factory.config.js +8 -0
  100. package/translations/en.json +93 -0
  101. package/translations/es.json +93 -0
  102. package/translations/ja.json +93 -0
  103. package/translations/ko.json +93 -0
  104. package/translations/ms.json +93 -0
  105. package/translations/zh.json +93 -0
  106. package/README.md +0 -3
@@ -0,0 +1,407 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InquiryReplyResolver = exports.InquiryResolver = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const GraphQLUpload_js_1 = tslib_1.__importDefault(require("graphql-upload/GraphQLUpload.js"));
6
+ const type_graphql_1 = require("type-graphql");
7
+ const typeorm_1 = require("typeorm");
8
+ const attachment_base_1 = require("@things-factory/attachment-base");
9
+ const auth_base_1 = require("@things-factory/auth-base");
10
+ const env_1 = require("@things-factory/env");
11
+ const shell_1 = require("@things-factory/shell");
12
+ const inquiry_1 = require("./inquiry");
13
+ const inquiry_rules_1 = require("./inquiry-rules");
14
+ const inquiry_service_1 = require("./inquiry-service");
15
+ const inquiry_types_1 = require("./inquiry-types");
16
+ const HANDLE = '@privilege(category: "inquiry", privilege: "mutation", domainOwnerGranted: true)';
17
+ /** The ways the list is narrowed: every one the person may read, their own, or those waiting on the handlers. */
18
+ const SCOPES = ['all', 'mine', 'handlers-turn'];
19
+ /** A refusal said in the reader's words, with a code the screen may read. */
20
+ function refuse(context, code, fallback) {
21
+ const message = context.t ? String(context.t(`inquiry.refusal.${code}`, { defaultValue: fallback })) : fallback;
22
+ const error = new Error(message);
23
+ error.extensions = { code: `inquiry.${code}` };
24
+ throw error;
25
+ }
26
+ const NOT_FOUND = 'there is no such inquiry.';
27
+ async function visibleOrRefuse(id, context, tx) {
28
+ const visible = await (0, inquiry_service_1.visibleInquiry)(id, context, tx);
29
+ if (!visible)
30
+ refuse(context, 'unknown-inquiry', NOT_FOUND);
31
+ return visible;
32
+ }
33
+ async function attachFiles(refType, refBy, files, context) {
34
+ for (const file of files ?? []) {
35
+ await (0, attachment_base_1.createAttachment)(null, { attachment: { file, refType, refBy } }, context);
36
+ }
37
+ }
38
+ /** The fields that change with a move to `status`. */
39
+ function stampsOf(status, now) {
40
+ return {
41
+ status,
42
+ ...(status === 'ANSWERED' ? { answeredAt: now } : {}),
43
+ ...(status === 'CLOSED' ? { closedAt: now } : {})
44
+ };
45
+ }
46
+ /** Keeps the handlers' to-do in line with whose turn it is: open while it waits on them, closed otherwise. */
47
+ async function alignTodo(inquiry, context) {
48
+ if ((0, inquiry_rules_1.handlersTurn)(inquiry.status))
49
+ await (0, inquiry_service_1.openTodo)(inquiry, context);
50
+ else
51
+ await (0, inquiry_service_1.closeTodo)(inquiry, context, inquiry.status);
52
+ }
53
+ let InquiryResolver = class InquiryResolver {
54
+ /* ---------------------------------------------------------------- reading */
55
+ async inquiries(params, scope, context) {
56
+ const { domain, user } = context.state;
57
+ const narrowing = scope || 'all';
58
+ if (!SCOPES.includes(narrowing))
59
+ refuse(context, 'unknown-scope', `the list cannot be narrowed so (${narrowing}).`);
60
+ const handler = await (0, inquiry_service_1.isHandler)(context);
61
+ const qb = (0, shell_1.getQueryBuilderFromListParams)({
62
+ domain,
63
+ params: { ...params, sortings: [] },
64
+ repository: (0, shell_1.getRepository)(inquiry_1.Inquiry),
65
+ alias: 'I',
66
+ searchables: ['title', 'body']
67
+ });
68
+ if (!handler)
69
+ qb.andWhere("(I.visibility <> 'PRIVATE' OR I.creator = :me)", { me: user.id });
70
+ if (narrowing === 'mine')
71
+ qb.andWhere('I.creator = :me', { me: user.id });
72
+ if (narrowing === 'handlers-turn')
73
+ qb.andWhere('I.status IN (:...turn)', { turn: [...inquiry_rules_1.HANDLERS_TURN] }).orderBy('I.createdAt', 'ASC');
74
+ else
75
+ qb.orderBy('I.createdAt', 'DESC');
76
+ const [items, total] = await qb.getManyAndCount();
77
+ return { items, total };
78
+ }
79
+ async inquiry(id, context) {
80
+ return (await (0, inquiry_service_1.visibleInquiry)(id, context))?.inquiry;
81
+ }
82
+ async inquirySummary(context) {
83
+ const { domain, user } = context.state;
84
+ const handler = await (0, inquiry_service_1.isHandler)(context);
85
+ const own = await (0, shell_1.getRepository)(inquiry_1.Inquiry).find({ where: { domain: { id: domain.id }, creator: { id: user.id }, handlerActivityAt: (0, typeorm_1.Not)((0, typeorm_1.IsNull)()) } });
86
+ const newAnswers = own.filter(one => (0, inquiry_rules_1.newForAsker)(one)).length;
87
+ const unhandled = handler ? await (0, shell_1.getRepository)(inquiry_1.Inquiry).count({ where: { domain: { id: domain.id }, status: (0, typeorm_1.In)([...inquiry_rules_1.HANDLERS_TURN]) } }) : 0;
88
+ return { newAnswers, unhandled, handler, badge: (0, inquiry_rules_1.badgeOf)({ newAnswers, unhandled, handler }) };
89
+ }
90
+ /* ---------------------------------------------------------------- writing and replying */
91
+ async createInquiry(input, attachments, context) {
92
+ const { domain, user, tx } = context.state;
93
+ const refusal = (0, inquiry_rules_1.inputRefusal)(input);
94
+ if (refusal)
95
+ refuse(context, refusal, `the inquiry cannot be kept (${refusal}).`);
96
+ const { name, version } = env_1.appPackage ?? {};
97
+ const saved = await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).save({
98
+ domain,
99
+ kind: input.kind,
100
+ title: input.title.trim(),
101
+ body: input.body ?? null,
102
+ status: 'RECEIVED',
103
+ visibility: input.visibility || 'DOMAIN',
104
+ pageUrl: input.pageUrl?.trim() || null,
105
+ appName: name ?? null,
106
+ appVersion: version ?? null,
107
+ replyCount: 0,
108
+ creator: user,
109
+ updater: user
110
+ });
111
+ await attachFiles(inquiry_service_1.INQUIRY_REF_TYPE, saved.id, attachments, context);
112
+ const inquiry = await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).findOneBy({ id: saved.id });
113
+ await (0, inquiry_service_1.openTodo)(inquiry, context);
114
+ await (0, inquiry_service_1.tellWhenCommitted)(context, inquiry, 'received', await (0, inquiry_service_1.handlerUserIds)(domain, tx), { body: inquiry.body });
115
+ return inquiry;
116
+ }
117
+ async replyInquiry(id, body, answer, attachments, context) {
118
+ const { domain, user, tx } = context.state;
119
+ const { inquiry, viewer } = await visibleOrRefuse(id, context, tx);
120
+ const refusal = (0, inquiry_rules_1.replyRefusalFor)(inquiry, viewer) ?? (0, inquiry_rules_1.replyRefusal)(body, attachments?.length ?? 0);
121
+ if (refusal)
122
+ refuse(context, refusal, `the reply cannot be kept (${refusal}).`);
123
+ const side = (0, inquiry_rules_1.sideOf)(inquiry, viewer);
124
+ const asAnswer = !!answer;
125
+ const answerRefused = (0, inquiry_rules_1.answerRefusal)(side, asAnswer);
126
+ if (answerRefused)
127
+ refuse(context, answerRefused, 'only a handler sends the answer.');
128
+ const status = (0, inquiry_rules_1.statusAfterReply)(inquiry, side, asAnswer);
129
+ const now = new Date();
130
+ const reply = await (0, shell_1.getRepository)(inquiry_1.InquiryReply, tx).save({
131
+ domain,
132
+ inquiry: { id },
133
+ body: body?.trim() || null,
134
+ byHandler: side === 'handler',
135
+ answer: asAnswer,
136
+ status: status !== inquiry.status ? status : null,
137
+ creator: user,
138
+ updater: user
139
+ });
140
+ await attachFiles(inquiry_service_1.INQUIRY_REPLY_REF_TYPE, reply.id, attachments, context);
141
+ await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).update(id, {
142
+ ...stampsOf(status, now),
143
+ replyCount: inquiry.replyCount + 1,
144
+ ...(side === 'handler' ? { handlerActivityAt: now, ...(inquiry.assigneeId ? {} : { assignee: user }) } : { askerSeenAt: now }),
145
+ updater: user
146
+ });
147
+ const fresh = (await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).findOneBy({ id }));
148
+ await alignTodo(fresh, context);
149
+ if (side === 'handler')
150
+ await (0, inquiry_service_1.tellWhenCommitted)(context, fresh, asAnswer ? 'answered' : 'replied', [fresh.creatorId], { body });
151
+ else
152
+ await (0, inquiry_service_1.tellWhenCommitted)(context, fresh, 'asker-replied', fresh.assigneeId ? [fresh.assigneeId] : await (0, inquiry_service_1.handlerUserIds)(domain, tx), { body });
153
+ return fresh;
154
+ }
155
+ async moveInquiry(id, status, reason, context) {
156
+ const { domain, user, tx } = context.state;
157
+ const { inquiry, viewer } = await visibleOrRefuse(id, context, tx);
158
+ const refusal = (0, inquiry_rules_1.moveRefusal)(inquiry, status, viewer);
159
+ if (refusal)
160
+ refuse(context, refusal, `the inquiry cannot be moved so (${refusal}).`);
161
+ const side = (0, inquiry_rules_1.sideOf)(inquiry, viewer);
162
+ const now = new Date();
163
+ await (0, shell_1.getRepository)(inquiry_1.InquiryReply, tx).save({ domain, inquiry: { id }, body: reason?.trim() || null, byHandler: side === 'handler', answer: false, status, creator: user, updater: user });
164
+ await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).update(id, {
165
+ ...stampsOf(status, now),
166
+ replyCount: inquiry.replyCount + 1,
167
+ ...(side === 'handler' ? { handlerActivityAt: now, ...(inquiry.assigneeId ? {} : { assignee: user }) } : { askerSeenAt: now }),
168
+ updater: user
169
+ });
170
+ const fresh = (await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).findOneBy({ id }));
171
+ await alignTodo(fresh, context);
172
+ if (side === 'handler')
173
+ await (0, inquiry_service_1.tellWhenCommitted)(context, fresh, 'moved', [fresh.creatorId], { body: reason, status });
174
+ return fresh;
175
+ }
176
+ async takeInquiry(id, context) {
177
+ const { user, tx } = context.state;
178
+ const { inquiry } = await visibleOrRefuse(id, context, tx);
179
+ if (inquiry.status === 'CLOSED')
180
+ refuse(context, 'closed', 'a closed inquiry is not taken.');
181
+ await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).update(id, { assignee: user, ...(inquiry.status === 'RECEIVED' ? { status: 'IN_PROGRESS' } : {}), updater: user });
182
+ return (await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).findOneBy({ id }));
183
+ }
184
+ async readInquiry(id, context) {
185
+ const { user, tx } = context.state;
186
+ const { inquiry } = await visibleOrRefuse(id, context, tx);
187
+ if (inquiry.creatorId !== user.id)
188
+ return inquiry;
189
+ await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).update(id, { askerSeenAt: new Date() });
190
+ return (await (0, shell_1.getRepository)(inquiry_1.Inquiry, tx).findOneBy({ id }));
191
+ }
192
+ /* ---------------------------------------------------------------- fields */
193
+ async replies(one) {
194
+ return await (0, shell_1.getRepository)(inquiry_1.InquiryReply).find({ where: { inquiry: { id: one.id } }, order: { createdAt: 'ASC' } });
195
+ }
196
+ async attachments(one, context) {
197
+ return await (0, shell_1.getRepository)(attachment_base_1.Attachment).find({ where: { domain: { id: context.state.domain.id }, refType: inquiry_service_1.INQUIRY_REF_TYPE, refBy: one.id }, order: { createdAt: 'ASC' } });
198
+ }
199
+ mine(one, context) {
200
+ return one.creatorId === context.state.user.id;
201
+ }
202
+ isNew(one, context) {
203
+ return one.creatorId === context.state.user.id && (0, inquiry_rules_1.newForAsker)(one);
204
+ }
205
+ async canReply(one, context) {
206
+ return !(0, inquiry_rules_1.replyRefusalFor)(one, await (0, inquiry_service_1.viewerOf)(context));
207
+ }
208
+ async asHandler(one, context) {
209
+ const viewer = await (0, inquiry_service_1.viewerOf)(context);
210
+ return viewer.handler && (0, inquiry_rules_1.sideOf)(one, viewer) === 'handler';
211
+ }
212
+ async moves(one, context) {
213
+ const viewer = await (0, inquiry_service_1.viewerOf)(context);
214
+ return inquiry_rules_1.INQUIRY_STATUSES.filter(status => !(0, inquiry_rules_1.moveRefusal)(one, status, viewer));
215
+ }
216
+ async creator(one) {
217
+ return one.creatorId ? await (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: one.creatorId }) : null;
218
+ }
219
+ async assignee(one) {
220
+ return one.assigneeId ? await (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: one.assigneeId }) : null;
221
+ }
222
+ };
223
+ exports.InquiryResolver = InquiryResolver;
224
+ tslib_1.__decorate([
225
+ (0, type_graphql_1.Query)(returns => inquiry_types_1.InquiryList, {
226
+ description: "The inquiries the request's person may read - every open one of the domain, their own, and for a handler the private ones too - the newest first. `scope` narrows it: all (the default), mine, or handlers-turn (received or in progress, the oldest first)."
227
+ }),
228
+ tslib_1.__param(0, (0, type_graphql_1.Args)(type => shell_1.ListParam)),
229
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('scope', { nullable: true })),
230
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
231
+ tslib_1.__metadata("design:type", Function),
232
+ tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, String, Object]),
233
+ tslib_1.__metadata("design:returntype", Promise)
234
+ ], InquiryResolver.prototype, "inquiries", null);
235
+ tslib_1.__decorate([
236
+ (0, type_graphql_1.Query)(returns => inquiry_1.Inquiry, { nullable: true, description: 'One inquiry, when the request may read it.' }),
237
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
238
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
239
+ tslib_1.__metadata("design:type", Function),
240
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
241
+ tslib_1.__metadata("design:returntype", Promise)
242
+ ], InquiryResolver.prototype, "inquiry", null);
243
+ tslib_1.__decorate([
244
+ (0, type_graphql_1.Query)(returns => inquiry_types_1.InquirySummary, { description: 'What the menu counts: new words on the person\'s own inquiries, and for a handler those waiting on the handlers.' }),
245
+ tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
246
+ tslib_1.__metadata("design:type", Function),
247
+ tslib_1.__metadata("design:paramtypes", [Object]),
248
+ tslib_1.__metadata("design:returntype", Promise)
249
+ ], InquiryResolver.prototype, "inquirySummary", null);
250
+ tslib_1.__decorate([
251
+ (0, type_graphql_1.Directive)('@transaction'),
252
+ (0, type_graphql_1.Mutation)(returns => inquiry_1.Inquiry, {
253
+ description: 'Writes an inquiry. The application and its version, the writer and the domain are taken from the request; the screen it was written from is sent by the browser. The handlers are told.'
254
+ }),
255
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('input', type => inquiry_types_1.InquiryInput)),
256
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('attachments', type => [GraphQLUpload_js_1.default], { nullable: true })),
257
+ tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
258
+ tslib_1.__metadata("design:type", Function),
259
+ tslib_1.__metadata("design:paramtypes", [inquiry_types_1.InquiryInput, Array, Object]),
260
+ tslib_1.__metadata("design:returntype", Promise)
261
+ ], InquiryResolver.prototype, "createInquiry", null);
262
+ tslib_1.__decorate([
263
+ (0, type_graphql_1.Directive)('@transaction'),
264
+ (0, type_graphql_1.Mutation)(returns => inquiry_1.Inquiry, {
265
+ description: "Replies on an inquiry - its writer or a handler. A handler may send the reply as the answer; the writer replying to an answer or a decision hands it back to the handlers. The other side is told."
266
+ }),
267
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
268
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('body', { nullable: true })),
269
+ tslib_1.__param(2, (0, type_graphql_1.Arg)('answer', { nullable: true })),
270
+ tslib_1.__param(3, (0, type_graphql_1.Arg)('attachments', type => [GraphQLUpload_js_1.default], { nullable: true })),
271
+ tslib_1.__param(4, (0, type_graphql_1.Ctx)()),
272
+ tslib_1.__metadata("design:type", Function),
273
+ tslib_1.__metadata("design:paramtypes", [String, String, Boolean, Array, Object]),
274
+ tslib_1.__metadata("design:returntype", Promise)
275
+ ], InquiryResolver.prototype, "replyInquiry", null);
276
+ tslib_1.__decorate([
277
+ (0, type_graphql_1.Directive)('@transaction'),
278
+ (0, type_graphql_1.Mutation)(returns => inquiry_1.Inquiry, {
279
+ description: 'Moves an inquiry - its writer closes it; a handler puts it in progress, answered, planned or declined (a proposal only) or closed. The reason, when given, stays on the thread. The writer is told of a handler\'s move.'
280
+ }),
281
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
282
+ tslib_1.__param(1, (0, type_graphql_1.Arg)('status')),
283
+ tslib_1.__param(2, (0, type_graphql_1.Arg)('reason', { nullable: true })),
284
+ tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
285
+ tslib_1.__metadata("design:type", Function),
286
+ tslib_1.__metadata("design:paramtypes", [String, String, String, Object]),
287
+ tslib_1.__metadata("design:returntype", Promise)
288
+ ], InquiryResolver.prototype, "moveInquiry", null);
289
+ tslib_1.__decorate([
290
+ (0, type_graphql_1.Directive)(HANDLE),
291
+ (0, type_graphql_1.Directive)('@transaction'),
292
+ (0, type_graphql_1.Mutation)(returns => inquiry_1.Inquiry, { description: 'A handler takes an inquiry - it is theirs to answer, and in progress when it was received.' }),
293
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
294
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
295
+ tslib_1.__metadata("design:type", Function),
296
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
297
+ tslib_1.__metadata("design:returntype", Promise)
298
+ ], InquiryResolver.prototype, "takeInquiry", null);
299
+ tslib_1.__decorate([
300
+ (0, type_graphql_1.Directive)('@transaction'),
301
+ (0, type_graphql_1.Mutation)(returns => inquiry_1.Inquiry, { description: "Records that its writer opened it - the handlers' words on it are no longer new. Anyone else opening it leaves no trace." }),
302
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('id')),
303
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
304
+ tslib_1.__metadata("design:type", Function),
305
+ tslib_1.__metadata("design:paramtypes", [String, Object]),
306
+ tslib_1.__metadata("design:returntype", Promise)
307
+ ], InquiryResolver.prototype, "readInquiry", null);
308
+ tslib_1.__decorate([
309
+ (0, type_graphql_1.FieldResolver)(type => [inquiry_1.InquiryReply], { description: 'Its replies, the oldest first.' }),
310
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
311
+ tslib_1.__metadata("design:type", Function),
312
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry]),
313
+ tslib_1.__metadata("design:returntype", Promise)
314
+ ], InquiryResolver.prototype, "replies", null);
315
+ tslib_1.__decorate([
316
+ (0, type_graphql_1.FieldResolver)(type => [attachment_base_1.Attachment], { description: 'Its files.' }),
317
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
318
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
319
+ tslib_1.__metadata("design:type", Function),
320
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry, Object]),
321
+ tslib_1.__metadata("design:returntype", Promise)
322
+ ], InquiryResolver.prototype, "attachments", null);
323
+ tslib_1.__decorate([
324
+ (0, type_graphql_1.FieldResolver)(type => Boolean, { description: "Whether the request's person wrote it." }),
325
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
326
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
327
+ tslib_1.__metadata("design:type", Function),
328
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry, Object]),
329
+ tslib_1.__metadata("design:returntype", Boolean)
330
+ ], InquiryResolver.prototype, "mine", null);
331
+ tslib_1.__decorate([
332
+ (0, type_graphql_1.FieldResolver)(type => Boolean, { description: "Whether it has a handler's word its writer has not seen - for its writer." }),
333
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
334
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
335
+ tslib_1.__metadata("design:type", Function),
336
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry, Object]),
337
+ tslib_1.__metadata("design:returntype", Boolean)
338
+ ], InquiryResolver.prototype, "isNew", null);
339
+ tslib_1.__decorate([
340
+ (0, type_graphql_1.FieldResolver)(type => Boolean, { description: 'Whether the request may reply on it.' }),
341
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
342
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
343
+ tslib_1.__metadata("design:type", Function),
344
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry, Object]),
345
+ tslib_1.__metadata("design:returntype", Promise)
346
+ ], InquiryResolver.prototype, "canReply", null);
347
+ tslib_1.__decorate([
348
+ (0, type_graphql_1.FieldResolver)(type => Boolean, { description: 'Whether the request replies on it as a handler - and so may send the answer.' }),
349
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
350
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
351
+ tslib_1.__metadata("design:type", Function),
352
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry, Object]),
353
+ tslib_1.__metadata("design:returntype", Promise)
354
+ ], InquiryResolver.prototype, "asHandler", null);
355
+ tslib_1.__decorate([
356
+ (0, type_graphql_1.FieldResolver)(type => [String], { description: 'Where the request may move it.' }),
357
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
358
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
359
+ tslib_1.__metadata("design:type", Function),
360
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry, Object]),
361
+ tslib_1.__metadata("design:returntype", Promise)
362
+ ], InquiryResolver.prototype, "moves", null);
363
+ tslib_1.__decorate([
364
+ (0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true, description: 'Who wrote it.' }),
365
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
366
+ tslib_1.__metadata("design:type", Function),
367
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry]),
368
+ tslib_1.__metadata("design:returntype", Promise)
369
+ ], InquiryResolver.prototype, "creator", null);
370
+ tslib_1.__decorate([
371
+ (0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true, description: 'The handler who took it.' }),
372
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
373
+ tslib_1.__metadata("design:type", Function),
374
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.Inquiry]),
375
+ tslib_1.__metadata("design:returntype", Promise)
376
+ ], InquiryResolver.prototype, "assignee", null);
377
+ exports.InquiryResolver = InquiryResolver = tslib_1.__decorate([
378
+ (0, type_graphql_1.Resolver)(inquiry_1.Inquiry)
379
+ ], InquiryResolver);
380
+ let InquiryReplyResolver = class InquiryReplyResolver {
381
+ async attachments(one, context) {
382
+ return await (0, shell_1.getRepository)(attachment_base_1.Attachment).find({ where: { domain: { id: context.state.domain.id }, refType: inquiry_service_1.INQUIRY_REPLY_REF_TYPE, refBy: one.id }, order: { createdAt: 'ASC' } });
383
+ }
384
+ async creator(one) {
385
+ return one.creatorId ? await (0, shell_1.getRepository)(auth_base_1.User).findOneBy({ id: one.creatorId }) : null;
386
+ }
387
+ };
388
+ exports.InquiryReplyResolver = InquiryReplyResolver;
389
+ tslib_1.__decorate([
390
+ (0, type_graphql_1.FieldResolver)(type => [attachment_base_1.Attachment], { description: 'Its files.' }),
391
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
392
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
393
+ tslib_1.__metadata("design:type", Function),
394
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.InquiryReply, Object]),
395
+ tslib_1.__metadata("design:returntype", Promise)
396
+ ], InquiryReplyResolver.prototype, "attachments", null);
397
+ tslib_1.__decorate([
398
+ (0, type_graphql_1.FieldResolver)(type => auth_base_1.User, { nullable: true, description: 'Who wrote it.' }),
399
+ tslib_1.__param(0, (0, type_graphql_1.Root)()),
400
+ tslib_1.__metadata("design:type", Function),
401
+ tslib_1.__metadata("design:paramtypes", [inquiry_1.InquiryReply]),
402
+ tslib_1.__metadata("design:returntype", Promise)
403
+ ], InquiryReplyResolver.prototype, "creator", null);
404
+ exports.InquiryReplyResolver = InquiryReplyResolver = tslib_1.__decorate([
405
+ (0, type_graphql_1.Resolver)(inquiry_1.InquiryReply)
406
+ ], InquiryReplyResolver);
407
+ //# sourceMappingURL=inquiry-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inquiry-resolver.js","sourceRoot":"","sources":["../../../server/service/inquiry/inquiry-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The doors of inquiries (ADR-0184 decisions 2-8).\n *\n * Writing, reading and replying is not a privilege: anyone signed in to the domain asks, reads the open inquiries and\n * their own, and replies on their own - each door asks the inquiry itself (inquiry-rules.ts). Taking one is the\n * handlers' alone - `inquiry:mutation`, the module's task `inquiry.answering`; the handlers' other moves go through the\n * same doors as the writer's, which ask the rules who may.\n */\nimport type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\nimport { Arg, Args, Ctx, Directive, FieldResolver, Mutation, Query, Resolver, Root } from 'type-graphql'\nimport { In, IsNull, Not } from 'typeorm'\n\nimport { Attachment, createAttachment } from '@things-factory/attachment-base'\nimport { User } from '@things-factory/auth-base'\nimport { appPackage } from '@things-factory/env'\nimport { getQueryBuilderFromListParams, getRepository, ListParam } from '@things-factory/shell'\n\nimport { Inquiry, InquiryReply } from './inquiry'\nimport {\n answerRefusal,\n badgeOf,\n handlersTurn,\n HANDLERS_TURN,\n INQUIRY_STATUSES,\n inputRefusal,\n moveRefusal,\n newForAsker,\n replyRefusal,\n replyRefusalFor,\n sideOf,\n statusAfterReply\n} from './inquiry-rules'\nimport {\n closeTodo,\n handlerUserIds,\n INQUIRY_REF_TYPE,\n INQUIRY_REPLY_REF_TYPE,\n isHandler,\n openTodo,\n tellWhenCommitted,\n viewerOf,\n visibleInquiry\n} from './inquiry-service'\nimport { InquiryInput, InquiryList, InquirySummary } from './inquiry-types'\n\nconst HANDLE = '@privilege(category: \"inquiry\", privilege: \"mutation\", domainOwnerGranted: true)'\n\n/** The ways the list is narrowed: every one the person may read, their own, or those waiting on the handlers. */\nconst SCOPES = ['all', 'mine', 'handlers-turn']\n\n/** A refusal said in the reader's words, with a code the screen may read. */\nfunction refuse(context: ResolverContext, code: string, fallback: string): never {\n const message = context.t ? String(context.t(`inquiry.refusal.${code}`, { defaultValue: fallback })) : fallback\n const error: any = new Error(message)\n error.extensions = { code: `inquiry.${code}` }\n throw error\n}\n\nconst NOT_FOUND = 'there is no such inquiry.'\n\nasync function visibleOrRefuse(id: string, context: ResolverContext, tx?: any) {\n const visible = await visibleInquiry(id, context, tx)\n if (!visible) refuse(context, 'unknown-inquiry', NOT_FOUND)\n return visible\n}\n\nasync function attachFiles(refType: string, refBy: string, files: FileUpload[] | undefined, context: ResolverContext) {\n for (const file of files ?? []) {\n await createAttachment(null, { attachment: { file, refType, refBy } } as any, context)\n }\n}\n\n/** The fields that change with a move to `status`. */\nfunction stampsOf(status: string, now: Date) {\n return {\n status,\n ...(status === 'ANSWERED' ? { answeredAt: now } : {}),\n ...(status === 'CLOSED' ? { closedAt: now } : {})\n }\n}\n\n/** Keeps the handlers' to-do in line with whose turn it is: open while it waits on them, closed otherwise. */\nasync function alignTodo(inquiry: Inquiry, context: ResolverContext) {\n if (handlersTurn(inquiry.status)) await openTodo(inquiry, context)\n else await closeTodo(inquiry, context, inquiry.status)\n}\n\n@Resolver(Inquiry)\nexport class InquiryResolver {\n /* ---------------------------------------------------------------- reading */\n\n @Query(returns => InquiryList, {\n description:\n \"The inquiries the request's person may read - every open one of the domain, their own, and for a handler the private ones too - the newest first. `scope` narrows it: all (the default), mine, or handlers-turn (received or in progress, the oldest first).\"\n })\n async inquiries(@Args(type => ListParam) params: ListParam, @Arg('scope', { nullable: true }) scope: string, @Ctx() context: ResolverContext): Promise<InquiryList> {\n const { domain, user } = context.state\n const narrowing = scope || 'all'\n if (!SCOPES.includes(narrowing)) refuse(context, 'unknown-scope', `the list cannot be narrowed so (${narrowing}).`)\n const handler = await isHandler(context)\n const qb = getQueryBuilderFromListParams({\n domain,\n params: { ...params, sortings: [] },\n repository: getRepository(Inquiry),\n alias: 'I',\n searchables: ['title', 'body']\n })\n if (!handler) qb.andWhere(\"(I.visibility <> 'PRIVATE' OR I.creator = :me)\", { me: user.id })\n if (narrowing === 'mine') qb.andWhere('I.creator = :me', { me: user.id })\n if (narrowing === 'handlers-turn') qb.andWhere('I.status IN (:...turn)', { turn: [...HANDLERS_TURN] }).orderBy('I.createdAt', 'ASC')\n else qb.orderBy('I.createdAt', 'DESC')\n const [items, total] = await qb.getManyAndCount()\n return { items, total }\n }\n\n @Query(returns => Inquiry, { nullable: true, description: 'One inquiry, when the request may read it.' })\n async inquiry(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Inquiry | undefined> {\n return (await visibleInquiry(id, context))?.inquiry\n }\n\n @Query(returns => InquirySummary, { description: 'What the menu counts: new words on the person\\'s own inquiries, and for a handler those waiting on the handlers.' })\n async inquirySummary(@Ctx() context: ResolverContext): Promise<InquirySummary> {\n const { domain, user } = context.state\n const handler = await isHandler(context)\n const own = await getRepository(Inquiry).find({ where: { domain: { id: domain.id }, creator: { id: user.id }, handlerActivityAt: Not(IsNull()) } as any })\n const newAnswers = own.filter(one => newForAsker(one)).length\n const unhandled = handler ? await getRepository(Inquiry).count({ where: { domain: { id: domain.id }, status: In([...HANDLERS_TURN]) } as any }) : 0\n return { newAnswers, unhandled, handler, badge: badgeOf({ newAnswers, unhandled, handler }) }\n }\n\n /* ---------------------------------------------------------------- writing and replying */\n\n @Directive('@transaction')\n @Mutation(returns => Inquiry, {\n description: 'Writes an inquiry. The application and its version, the writer and the domain are taken from the request; the screen it was written from is sent by the browser. The handlers are told.'\n })\n async createInquiry(\n @Arg('input', type => InquiryInput) input: InquiryInput,\n @Arg('attachments', type => [GraphQLUpload], { nullable: true }) attachments: FileUpload[],\n @Ctx() context: ResolverContext\n ): Promise<Inquiry> {\n const { domain, user, tx } = context.state as any\n const refusal = inputRefusal(input)\n if (refusal) refuse(context, refusal, `the inquiry cannot be kept (${refusal}).`)\n const { name, version } = (appPackage as any) ?? {}\n const saved = await getRepository(Inquiry, tx).save({\n domain,\n kind: input.kind,\n title: input.title.trim(),\n body: input.body ?? null,\n status: 'RECEIVED',\n visibility: input.visibility || 'DOMAIN',\n pageUrl: input.pageUrl?.trim() || null,\n appName: name ?? null,\n appVersion: version ?? null,\n replyCount: 0,\n creator: user,\n updater: user\n } as any)\n await attachFiles(INQUIRY_REF_TYPE, saved.id, attachments, context)\n const inquiry = await getRepository(Inquiry, tx).findOneBy({ id: saved.id })\n await openTodo(inquiry!, context)\n await tellWhenCommitted(context, inquiry!, 'received', await handlerUserIds(domain, tx), { body: inquiry!.body })\n return inquiry!\n }\n\n @Directive('@transaction')\n @Mutation(returns => Inquiry, {\n description:\n \"Replies on an inquiry - its writer or a handler. A handler may send the reply as the answer; the writer replying to an answer or a decision hands it back to the handlers. The other side is told.\"\n })\n async replyInquiry(\n @Arg('id') id: string,\n @Arg('body', { nullable: true }) body: string,\n @Arg('answer', { nullable: true }) answer: boolean,\n @Arg('attachments', type => [GraphQLUpload], { nullable: true }) attachments: FileUpload[],\n @Ctx() context: ResolverContext\n ): Promise<Inquiry> {\n const { domain, user, tx } = context.state as any\n const { inquiry, viewer } = await visibleOrRefuse(id, context, tx)\n const refusal = replyRefusalFor(inquiry, viewer) ?? replyRefusal(body, attachments?.length ?? 0)\n if (refusal) refuse(context, refusal, `the reply cannot be kept (${refusal}).`)\n const side = sideOf(inquiry, viewer)\n const asAnswer = !!answer\n const answerRefused = answerRefusal(side, asAnswer)\n if (answerRefused) refuse(context, answerRefused, 'only a handler sends the answer.')\n const status = statusAfterReply(inquiry, side, asAnswer)\n const now = new Date()\n const reply = await getRepository(InquiryReply, tx).save({\n domain,\n inquiry: { id },\n body: body?.trim() || null,\n byHandler: side === 'handler',\n answer: asAnswer,\n status: status !== inquiry.status ? status : null,\n creator: user,\n updater: user\n } as any)\n await attachFiles(INQUIRY_REPLY_REF_TYPE, reply.id, attachments, context)\n await getRepository(Inquiry, tx).update(id, {\n ...stampsOf(status, now),\n replyCount: inquiry.replyCount + 1,\n ...(side === 'handler' ? { handlerActivityAt: now, ...(inquiry.assigneeId ? {} : { assignee: user }) } : { askerSeenAt: now }),\n updater: user\n } as any)\n const fresh = (await getRepository(Inquiry, tx).findOneBy({ id }))!\n await alignTodo(fresh, context)\n if (side === 'handler') await tellWhenCommitted(context, fresh, asAnswer ? 'answered' : 'replied', [fresh.creatorId!], { body })\n else await tellWhenCommitted(context, fresh, 'asker-replied', fresh.assigneeId ? [fresh.assigneeId] : await handlerUserIds(domain, tx), { body })\n return fresh\n }\n\n @Directive('@transaction')\n @Mutation(returns => Inquiry, {\n description:\n 'Moves an inquiry - its writer closes it; a handler puts it in progress, answered, planned or declined (a proposal only) or closed. The reason, when given, stays on the thread. The writer is told of a handler\\'s move.'\n })\n async moveInquiry(@Arg('id') id: string, @Arg('status') status: string, @Arg('reason', { nullable: true }) reason: string, @Ctx() context: ResolverContext): Promise<Inquiry> {\n const { domain, user, tx } = context.state as any\n const { inquiry, viewer } = await visibleOrRefuse(id, context, tx)\n const refusal = moveRefusal(inquiry, status, viewer)\n if (refusal) refuse(context, refusal, `the inquiry cannot be moved so (${refusal}).`)\n const side = sideOf(inquiry, viewer)\n const now = new Date()\n await getRepository(InquiryReply, tx).save({ domain, inquiry: { id }, body: reason?.trim() || null, byHandler: side === 'handler', answer: false, status, creator: user, updater: user } as any)\n await getRepository(Inquiry, tx).update(id, {\n ...stampsOf(status, now),\n replyCount: inquiry.replyCount + 1,\n ...(side === 'handler' ? { handlerActivityAt: now, ...(inquiry.assigneeId ? {} : { assignee: user }) } : { askerSeenAt: now }),\n updater: user\n } as any)\n const fresh = (await getRepository(Inquiry, tx).findOneBy({ id }))!\n await alignTodo(fresh, context)\n if (side === 'handler') await tellWhenCommitted(context, fresh, 'moved', [fresh.creatorId!], { body: reason, status })\n return fresh\n }\n\n @Directive(HANDLE)\n @Directive('@transaction')\n @Mutation(returns => Inquiry, { description: 'A handler takes an inquiry - it is theirs to answer, and in progress when it was received.' })\n async takeInquiry(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Inquiry> {\n const { user, tx } = context.state as any\n const { inquiry } = await visibleOrRefuse(id, context, tx)\n if (inquiry.status === 'CLOSED') refuse(context, 'closed', 'a closed inquiry is not taken.')\n await getRepository(Inquiry, tx).update(id, { assignee: user, ...(inquiry.status === 'RECEIVED' ? { status: 'IN_PROGRESS' } : {}), updater: user } as any)\n return (await getRepository(Inquiry, tx).findOneBy({ id }))!\n }\n\n @Directive('@transaction')\n @Mutation(returns => Inquiry, { description: \"Records that its writer opened it - the handlers' words on it are no longer new. Anyone else opening it leaves no trace.\" })\n async readInquiry(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Inquiry> {\n const { user, tx } = context.state as any\n const { inquiry } = await visibleOrRefuse(id, context, tx)\n if (inquiry.creatorId !== user.id) return inquiry\n await getRepository(Inquiry, tx).update(id, { askerSeenAt: new Date() } as any)\n return (await getRepository(Inquiry, tx).findOneBy({ id }))!\n }\n\n /* ---------------------------------------------------------------- fields */\n\n @FieldResolver(type => [InquiryReply], { description: 'Its replies, the oldest first.' })\n async replies(@Root() one: Inquiry): Promise<InquiryReply[]> {\n return await getRepository(InquiryReply).find({ where: { inquiry: { id: one.id } } as any, order: { createdAt: 'ASC' } as any })\n }\n\n @FieldResolver(type => [Attachment], { description: 'Its files.' })\n async attachments(@Root() one: Inquiry, @Ctx() context: ResolverContext): Promise<Attachment[]> {\n return await getRepository(Attachment).find({ where: { domain: { id: context.state.domain.id }, refType: INQUIRY_REF_TYPE, refBy: one.id } as any, order: { createdAt: 'ASC' } as any })\n }\n\n @FieldResolver(type => Boolean, { description: \"Whether the request's person wrote it.\" })\n mine(@Root() one: Inquiry, @Ctx() context: ResolverContext): boolean {\n return one.creatorId === context.state.user.id\n }\n\n @FieldResolver(type => Boolean, { description: \"Whether it has a handler's word its writer has not seen - for its writer.\" })\n isNew(@Root() one: Inquiry, @Ctx() context: ResolverContext): boolean {\n return one.creatorId === context.state.user.id && newForAsker(one)\n }\n\n @FieldResolver(type => Boolean, { description: 'Whether the request may reply on it.' })\n async canReply(@Root() one: Inquiry, @Ctx() context: ResolverContext): Promise<boolean> {\n return !replyRefusalFor(one, await viewerOf(context))\n }\n\n @FieldResolver(type => Boolean, { description: 'Whether the request replies on it as a handler - and so may send the answer.' })\n async asHandler(@Root() one: Inquiry, @Ctx() context: ResolverContext): Promise<boolean> {\n const viewer = await viewerOf(context)\n return viewer.handler && sideOf(one, viewer) === 'handler'\n }\n\n @FieldResolver(type => [String], { description: 'Where the request may move it.' })\n async moves(@Root() one: Inquiry, @Ctx() context: ResolverContext): Promise<string[]> {\n const viewer = await viewerOf(context)\n return INQUIRY_STATUSES.filter(status => !moveRefusal(one, status, viewer))\n }\n\n @FieldResolver(type => User, { nullable: true, description: 'Who wrote it.' })\n async creator(@Root() one: Inquiry): Promise<User | null> {\n return one.creatorId ? await getRepository(User).findOneBy({ id: one.creatorId }) : null\n }\n\n @FieldResolver(type => User, { nullable: true, description: 'The handler who took it.' })\n async assignee(@Root() one: Inquiry): Promise<User | null> {\n return one.assigneeId ? await getRepository(User).findOneBy({ id: one.assigneeId }) : null\n }\n}\n\n@Resolver(InquiryReply)\nexport class InquiryReplyResolver {\n @FieldResolver(type => [Attachment], { description: 'Its files.' })\n async attachments(@Root() one: InquiryReply, @Ctx() context: ResolverContext): Promise<Attachment[]> {\n return await getRepository(Attachment).find({ where: { domain: { id: context.state.domain.id }, refType: INQUIRY_REPLY_REF_TYPE, refBy: one.id } as any, order: { createdAt: 'ASC' } as any })\n }\n\n @FieldResolver(type => User, { nullable: true, description: 'Who wrote it.' })\n async creator(@Root() one: InquiryReply): Promise<User | null> {\n return one.creatorId ? await getRepository(User).findOneBy({ id: one.creatorId }) : null\n }\n}\n"]}
@@ -0,0 +1,88 @@
1
+ /** The kinds of inquiry - a question, a bug report, a feature proposal (`inquiry.kind.<code>`). */
2
+ export declare const INQUIRY_KINDS: readonly ["QUESTION", "BUG", "PROPOSAL"];
3
+ /** Where an inquiry stands (`inquiry.status.<code>`). PLANNED and DECLINED are a proposal's only. */
4
+ export declare const INQUIRY_STATUSES: readonly ["RECEIVED", "IN_PROGRESS", "ANSWERED", "PLANNED", "DECLINED", "CLOSED"];
5
+ /** Who reads it: everyone of the domain, or its writer and the handlers (`inquiry.visibility.<code>`). */
6
+ export declare const INQUIRY_VISIBILITIES: readonly ["DOMAIN", "PRIVATE"];
7
+ export type InquiryKind = (typeof INQUIRY_KINDS)[number];
8
+ export type InquiryStatus = (typeof INQUIRY_STATUSES)[number];
9
+ export declare const MAX_TITLE = 200;
10
+ export declare const MAX_BODY = 20000;
11
+ export declare const MAX_PAGE_URL = 2000;
12
+ /** The states that wait on the handlers - a to-do is open for them, and the handlers' badge counts them. */
13
+ export declare const HANDLERS_TURN: readonly string[];
14
+ export interface InquiryFacts {
15
+ kind: string;
16
+ status: string;
17
+ visibility: string;
18
+ creatorId?: string | null;
19
+ handlerActivityAt?: Date | string | null;
20
+ askerSeenAt?: Date | string | null;
21
+ }
22
+ /** The request's person as an inquiry sees them. */
23
+ export interface Viewer {
24
+ userId: string;
25
+ /** Holds `inquiry:mutation` (the task `inquiry.answering`), or owns the domain. */
26
+ handler: boolean;
27
+ }
28
+ export interface InquiryInputFacts {
29
+ kind?: string | null;
30
+ title?: string | null;
31
+ body?: string | null;
32
+ visibility?: string | null;
33
+ pageUrl?: string | null;
34
+ }
35
+ /** Why what was written cannot be kept, or nothing. */
36
+ export declare function inputRefusal(input: InquiryInputFacts): string | undefined;
37
+ /** Whether a reply says something - words, or files. */
38
+ export declare function replyRefusal(body: string | null | undefined, files: number): string | undefined;
39
+ /** An open inquiry is read by everyone of the domain; a private one by its writer and the handlers (decision 5). */
40
+ export declare function mayRead(one: InquiryFacts, viewer: Viewer): boolean;
41
+ /** Replies go back and forth between the writer and the handlers, until it is closed (decision 3). */
42
+ export declare function replyRefusalFor(one: InquiryFacts, viewer: Viewer): string | undefined;
43
+ /** Which side a reply is from - the writer's own reply is the asker's, even when the writer is a handler. */
44
+ export declare function sideOf(one: InquiryFacts, viewer: Viewer): 'asker' | 'handler';
45
+ /**
46
+ * Where it stands after a reply (decision 2). A handler's reply marked as the answer answers it; any other handler's
47
+ * reply puts a received one in progress. The asker replying to an answer or a decision hands it back to the handlers.
48
+ */
49
+ export declare function statusAfterReply(one: InquiryFacts, side: 'asker' | 'handler', asAnswer: boolean): string;
50
+ /** Whether `side` may mark a reply as the answer - the handlers' only. */
51
+ export declare function answerRefusal(side: 'asker' | 'handler', asAnswer: boolean): string | undefined;
52
+ /**
53
+ * Why the request may not move it to `to`, or nothing (decision 2). The writer closes their own; everything else is the
54
+ * handlers'. A closed one stays closed; PLANNED and DECLINED are a proposal's; nothing goes back to RECEIVED.
55
+ */
56
+ export declare function moveRefusal(one: InquiryFacts, to: string, viewer: Viewer): string | undefined;
57
+ /** Whether it waits on the handlers. */
58
+ export declare const handlersTurn: (status: string) => boolean;
59
+ /** Whether the writer has a handler's word they have not seen - a reply or a move since they last opened it. */
60
+ export declare function newForAsker(one: InquiryFacts): boolean;
61
+ /** The count on the menu entry (decision 8): new words on one's own inquiries, and for a handler those waiting on them. */
62
+ export declare function badgeOf(summary: {
63
+ newAnswers: number;
64
+ unhandled: number;
65
+ handler: boolean;
66
+ }): number;
67
+ /** The screen an inquiry opens on. */
68
+ export declare const viewAddressOf: (id: string) => string;
69
+ /** Why the people are told. */
70
+ export type NoticeKind = 'received' | 'replied' | 'answered' | 'moved' | 'asker-replied';
71
+ /** A sentence in one language, with the English one when that language has none. */
72
+ export type Say = (key: string, english: string, params?: Record<string, unknown>) => string;
73
+ /** The body as one line of plain words - the notice's summary. */
74
+ export declare function plainSummary(body: string | null | undefined, max?: number): string;
75
+ /** Who is told of what (decision 7): the handlers of a new one, the writer of a handler's word, the handler of the writer's. */
76
+ export declare function noticeWordsOf(one: {
77
+ title: string;
78
+ kind: string;
79
+ }, kind: NoticeKind, said: {
80
+ body?: string | null;
81
+ status?: string;
82
+ }, say: Say): {
83
+ subject: string;
84
+ summary: string;
85
+ body: string;
86
+ action: string;
87
+ note: string;
88
+ };