@things-factory/announcement 10.1.246 → 10.1.248
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/package.json +9 -9
- package/dist-client/announcement-watch.d.ts +0 -6
- package/dist-client/announcement-watch.js +0 -105
- package/dist-client/announcement-watch.js.map +0 -1
- package/dist-client/bootstrap.d.ts +0 -1
- package/dist-client/bootstrap.js +0 -8
- package/dist-client/bootstrap.js.map +0 -1
- package/dist-client/components/announcement-popup.d.ts +0 -20
- package/dist-client/components/announcement-popup.js +0 -98
- package/dist-client/components/announcement-popup.js.map +0 -1
- package/dist-client/components/announcement-receipts.d.ts +0 -30
- package/dist-client/components/announcement-receipts.js +0 -220
- package/dist-client/components/announcement-receipts.js.map +0 -1
- package/dist-client/components/announcement-sheet.d.ts +0 -17
- package/dist-client/components/announcement-sheet.js +0 -224
- package/dist-client/components/announcement-sheet.js.map +0 -1
- package/dist-client/components/audience-picker.d.ts +0 -32
- package/dist-client/components/audience-picker.js +0 -229
- package/dist-client/components/audience-picker.js.map +0 -1
- package/dist-client/index.d.ts +0 -1
- package/dist-client/index.js +0 -2
- package/dist-client/index.js.map +0 -1
- package/dist-client/pages/announcement-editor.d.ts +0 -59
- package/dist-client/pages/announcement-editor.js +0 -523
- package/dist-client/pages/announcement-editor.js.map +0 -1
- package/dist-client/pages/announcement-list.d.ts +0 -54
- package/dist-client/pages/announcement-list.js +0 -209
- package/dist-client/pages/announcement-list.js.map +0 -1
- package/dist-client/pages/announcement-manage-list.d.ts +0 -46
- package/dist-client/pages/announcement-manage-list.js +0 -115
- package/dist-client/pages/announcement-manage-list.js.map +0 -1
- package/dist-client/pages/announcement-view.d.ts +0 -30
- package/dist-client/pages/announcement-view.js +0 -182
- package/dist-client/pages/announcement-view.js.map +0 -1
- package/dist-client/route.d.ts +0 -1
- package/dist-client/route.js +0 -18
- package/dist-client/route.js.map +0 -1
- package/dist-client/tsconfig.tsbuildinfo +0 -1
- package/dist-client/utils/announcement-api.d.ts +0 -149
- package/dist-client/utils/announcement-api.js +0 -52
- package/dist-client/utils/announcement-api.js.map +0 -1
- package/dist-client/utils/announcement-badge.d.ts +0 -4
- package/dist-client/utils/announcement-badge.js +0 -47
- package/dist-client/utils/announcement-badge.js.map +0 -1
- package/dist-client/utils/announcement-words.d.ts +0 -11
- package/dist-client/utils/announcement-words.js +0 -23
- package/dist-client/utils/announcement-words.js.map +0 -1
- package/dist-server/announcement-read.d.ts +0 -6
- package/dist-server/announcement-read.js +0 -45
- package/dist-server/announcement-read.js.map +0 -1
- package/dist-server/attachment-reader.d.ts +0 -1
- package/dist-server/attachment-reader.js +0 -13
- package/dist-server/attachment-reader.js.map +0 -1
- package/dist-server/index.d.ts +0 -2
- package/dist-server/index.js +0 -20
- package/dist-server/index.js.map +0 -1
- package/dist-server/role-tasks.d.ts +0 -2
- package/dist-server/role-tasks.js +0 -13
- package/dist-server/role-tasks.js.map +0 -1
- package/dist-server/service/announcement/announcement-resolver.d.ts +0 -38
- package/dist-server/service/announcement/announcement-resolver.js +0 -664
- package/dist-server/service/announcement/announcement-resolver.js.map +0 -1
- package/dist-server/service/announcement/announcement-rules.d.ts +0 -150
- package/dist-server/service/announcement/announcement-rules.js +0 -227
- package/dist-server/service/announcement/announcement-rules.js.map +0 -1
- package/dist-server/service/announcement/announcement-service.d.ts +0 -54
- package/dist-server/service/announcement/announcement-service.js +0 -248
- package/dist-server/service/announcement/announcement-service.js.map +0 -1
- package/dist-server/service/announcement/announcement-types.d.ts +0 -54
- package/dist-server/service/announcement/announcement-types.js +0 -203
- package/dist-server/service/announcement/announcement-types.js.map +0 -1
- package/dist-server/service/announcement/announcement.d.ts +0 -124
- package/dist-server/service/announcement/announcement.js +0 -462
- package/dist-server/service/announcement/announcement.js.map +0 -1
- package/dist-server/service/announcement/index.d.ts +0 -4
- package/dist-server/service/announcement/index.js +0 -8
- package/dist-server/service/announcement/index.js.map +0 -1
- package/dist-server/service/index.d.ts +0 -7
- package/dist-server/service/index.js +0 -23
- package/dist-server/service/index.js.map +0 -1
- package/dist-server/tsconfig.tsbuildinfo +0 -1
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ANNOUNCEMENT_REF_TYPE = void 0;
|
|
4
|
-
exports.isWriter = isWriter;
|
|
5
|
-
exports.memberOf = memberOf;
|
|
6
|
-
exports.reachingIds = reachingIds;
|
|
7
|
-
exports.audiencesOf = audiencesOf;
|
|
8
|
-
exports.visibleAnnouncement = visibleAnnouncement;
|
|
9
|
-
exports.alignRoster = alignRoster;
|
|
10
|
-
exports.keepRevision = keepRevision;
|
|
11
|
-
exports.sendOut = sendOut;
|
|
12
|
-
exports.tellWhenCommitted = tellWhenCommitted;
|
|
13
|
-
exports.publishDue = publishDue;
|
|
14
|
-
exports.schedulePublishing = schedulePublishing;
|
|
15
|
-
/*
|
|
16
|
-
* What the doors of announcements do with the database (ADR-0163 decisions 1-5): who may read one, who is on its roster,
|
|
17
|
-
* sending it out, telling people of it, and publishing the scheduled ones when their start comes.
|
|
18
|
-
*/
|
|
19
|
-
const typeorm_1 = require("typeorm");
|
|
20
|
-
const auth_base_1 = require("@things-factory/auth-base");
|
|
21
|
-
const env_1 = require("@things-factory/env");
|
|
22
|
-
const translator_1 = require("@things-factory/i18n-base/translator");
|
|
23
|
-
const notification_1 = require("@things-factory/notification");
|
|
24
|
-
const organization_1 = require("@things-factory/organization");
|
|
25
|
-
const shell_1 = require("@things-factory/shell");
|
|
26
|
-
const announcement_1 = require("./announcement");
|
|
27
|
-
const announcement_rules_1 = require("./announcement-rules");
|
|
28
|
-
/** The attachments of an announcement hang on it under this `refType` (attachment-base). */
|
|
29
|
-
exports.ANNOUNCEMENT_REF_TYPE = 'Announcement';
|
|
30
|
-
/** Whether the request writes announcements - the one privilege of the module (`announcement.writing`). */
|
|
31
|
-
async function isWriter(context) {
|
|
32
|
-
const state = context?.state ?? {};
|
|
33
|
-
const { domain, user, unsafeIP, prohibitedPrivileges } = state;
|
|
34
|
-
if (!domain || !user)
|
|
35
|
-
return false;
|
|
36
|
-
/* Asked once per request - a list asks it for each row. */
|
|
37
|
-
state.__announcementWriter ??= (0, auth_base_1.checkPermission)({ category: 'announcement', privilege: 'mutation', owner: true }, user, domain, unsafeIP, prohibitedPrivileges).then(Boolean);
|
|
38
|
-
return await state.__announcementWriter;
|
|
39
|
-
}
|
|
40
|
-
/** The request's person as an audience sees them - asked once per request. */
|
|
41
|
-
async function memberOf(context) {
|
|
42
|
-
const state = context.state;
|
|
43
|
-
if (!state.__announcementMember) {
|
|
44
|
-
const { ownDepartments, ...member } = await (0, organization_1.audienceMemberOf)(state.domain, state.user ?? {});
|
|
45
|
-
state.__announcementMember = member;
|
|
46
|
-
}
|
|
47
|
-
return state.__announcementMember;
|
|
48
|
-
}
|
|
49
|
-
/** The announcements of the domain whose audience names `member` - by their targets, whatever their status. */
|
|
50
|
-
async function reachingIds(member, tx) {
|
|
51
|
-
if (!member.userId || !member.domainId)
|
|
52
|
-
return [];
|
|
53
|
-
const domain = { id: member.domainId };
|
|
54
|
-
const rows = await (0, shell_1.getRepository)(announcement_1.AnnouncementAudience, tx).find({
|
|
55
|
-
where: [
|
|
56
|
-
{ domain, scope: 'DOMAIN', targetId: member.domainId },
|
|
57
|
-
{ domain, scope: 'USER', targetId: member.userId },
|
|
58
|
-
...(member.departmentIds.length ? [{ domain, scope: 'DEPARTMENT', targetId: (0, typeorm_1.In)([...member.departmentIds]) }] : []),
|
|
59
|
-
...(member.roleIds.length ? [{ domain, scope: 'ROLE', targetId: (0, typeorm_1.In)([...member.roleIds]) }] : [])
|
|
60
|
-
]
|
|
61
|
-
});
|
|
62
|
-
return [...new Set(rows.map(one => one.announcementId))];
|
|
63
|
-
}
|
|
64
|
-
async function audiencesOf(announcementId, tx) {
|
|
65
|
-
return await (0, shell_1.getRepository)(announcement_1.AnnouncementAudience, tx).find({ where: { announcement: { id: announcementId } }, order: { createdAt: 'ASC' } });
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* The announcement as the request may see it, or nothing - one answer for "none", "not yours" and "not out yet".
|
|
69
|
-
* Its audience reads it once it is out; a writer reads every one that is not somebody else's draft.
|
|
70
|
-
*/
|
|
71
|
-
async function visibleAnnouncement(id, context, tx) {
|
|
72
|
-
const { domain, user } = context?.state ?? {};
|
|
73
|
-
if (!id || !domain || !user || !/^[0-9a-f-]{36}$/i.test(id))
|
|
74
|
-
return undefined;
|
|
75
|
-
const announcement = await (0, shell_1.getRepository)(announcement_1.Announcement, tx).findOne({ where: { id, domain: { id: domain.id } } });
|
|
76
|
-
if (!announcement)
|
|
77
|
-
return undefined;
|
|
78
|
-
const reader = announcement.status === announcement_1.AnnouncementStatus.PUBLISHED && (await reachingIds(await memberOf(context), tx)).includes(id);
|
|
79
|
-
const writer = (announcement.status !== announcement_1.AnnouncementStatus.DRAFT || announcement.creatorId === user.id) && (await isWriter(context));
|
|
80
|
-
return reader || writer ? { announcement, reader, writer } : undefined;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Puts the roster in line with the audience as it stands: everyone it names now is listed, one it no longer names is
|
|
84
|
-
* not (their reading stays). Answers those newly listed - the ones not yet told.
|
|
85
|
-
*/
|
|
86
|
-
async function alignRoster(announcement, domain, by, tx) {
|
|
87
|
-
const named = await (0, organization_1.audienceUserIds)(domain, await audiencesOf(announcement.id, tx), tx);
|
|
88
|
-
const repository = (0, shell_1.getRepository)(announcement_1.AnnouncementReceipt, tx);
|
|
89
|
-
const receipts = await repository.find({ where: { announcement: { id: announcement.id } } });
|
|
90
|
-
const byUser = new Map(receipts.map(one => [one.userId, one]));
|
|
91
|
-
const now = new Date();
|
|
92
|
-
const added = [];
|
|
93
|
-
for (const userId of named) {
|
|
94
|
-
const receipt = byUser.get(userId);
|
|
95
|
-
if (receipt?.listed)
|
|
96
|
-
continue;
|
|
97
|
-
added.push(userId);
|
|
98
|
-
if (receipt)
|
|
99
|
-
await repository.update(receipt.id, { listed: true, notifiedAt: now, updater: by });
|
|
100
|
-
else
|
|
101
|
-
await repository.save({ domain, announcement: { id: announcement.id }, user: { id: userId }, listed: true, notifiedAt: now, creator: by, updater: by });
|
|
102
|
-
}
|
|
103
|
-
const gone = receipts.filter(one => one.listed && !named.includes(one.userId));
|
|
104
|
-
if (gone.length)
|
|
105
|
-
await repository.update({ id: (0, typeorm_1.In)(gone.map(one => one.id)) }, { listed: false, updater: by });
|
|
106
|
-
await (0, shell_1.getRepository)(announcement_1.Announcement, tx).update(announcement.id, { audienceSize: named.length });
|
|
107
|
-
return added;
|
|
108
|
-
}
|
|
109
|
-
/** The version as it stands, kept - the one that went out, and each change after. */
|
|
110
|
-
async function keepRevision(announcement, domain, by, tx) {
|
|
111
|
-
const audiences = await audiencesOf(announcement.id, tx);
|
|
112
|
-
const { title, body, category, importance, startsAt, endsAt, pinned, requiresAcknowledgement, acknowledgeBy, popup, links } = announcement;
|
|
113
|
-
await (0, shell_1.getRepository)(announcement_1.AnnouncementRevision, tx).save({
|
|
114
|
-
domain,
|
|
115
|
-
announcement: { id: announcement.id },
|
|
116
|
-
version: announcement.version,
|
|
117
|
-
title,
|
|
118
|
-
body,
|
|
119
|
-
rest: {
|
|
120
|
-
category,
|
|
121
|
-
importance,
|
|
122
|
-
startsAt,
|
|
123
|
-
endsAt,
|
|
124
|
-
pinned,
|
|
125
|
-
requiresAcknowledgement,
|
|
126
|
-
acknowledgeBy,
|
|
127
|
-
popup,
|
|
128
|
-
links,
|
|
129
|
-
audiences: audiences.map(({ scope, targetId, targetName }) => ({ scope, targetId, targetName }))
|
|
130
|
-
},
|
|
131
|
-
creator: by,
|
|
132
|
-
updater: by
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Sends it out: published now, the roster counted, this version kept. Answers the people to tell - the publisher is not
|
|
137
|
-
* told of their own announcement.
|
|
138
|
-
*/
|
|
139
|
-
async function sendOut(announcement, domain, by, tx) {
|
|
140
|
-
const now = new Date();
|
|
141
|
-
await (0, shell_1.getRepository)(announcement_1.Announcement, tx).update(announcement.id, {
|
|
142
|
-
status: announcement_1.AnnouncementStatus.PUBLISHED,
|
|
143
|
-
publishedAt: now,
|
|
144
|
-
startsAt: announcement.startsAt ?? now,
|
|
145
|
-
publisher: by,
|
|
146
|
-
updater: by
|
|
147
|
-
});
|
|
148
|
-
const fresh = await (0, shell_1.getRepository)(announcement_1.Announcement, tx).findOneBy({ id: announcement.id });
|
|
149
|
-
await keepRevision(fresh, domain, by, tx);
|
|
150
|
-
return (await alignRoster(fresh, domain, by, tx)).filter(id => id !== by.id);
|
|
151
|
-
}
|
|
152
|
-
/** The sentences in `lng` from this module's translations, the English one where `lng` has none. */
|
|
153
|
-
const sayIn = (lng) => (key, english, params = {}) => (0, translator_1.translatorFor)(lng)(key, { ...params, defaultValue: english.replace(/\{(\w+)\}/g, (_, name) => String(params[name] ?? '')) });
|
|
154
|
-
/** The people to tell, as notification takes them - only those who can sign in, each with their mail and language. */
|
|
155
|
-
async function receiversOf(userIds, tx) {
|
|
156
|
-
if (!userIds.length)
|
|
157
|
-
return [];
|
|
158
|
-
const people = await (0, shell_1.getRepository)(auth_base_1.User, tx).find({ where: { id: (0, typeorm_1.In)(userIds) } });
|
|
159
|
-
return people.filter(one => one.status === auth_base_1.UserStatus.ACTIVATED).map(one => ({ id: one.id, email: one.email, locale: one.locale }));
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* The notice of an announcement (notification ADR-0164): in the app and by web push always - the `announcement` type is
|
|
163
|
-
* what pops it up - and by mail when the announcement asks for it and the domain has mail on.
|
|
164
|
-
*/
|
|
165
|
-
function noticeOf(one, kind, receivers, broadcast, link) {
|
|
166
|
-
return {
|
|
167
|
-
type: 'announcement',
|
|
168
|
-
level: one.importance === 'URGENT' ? 'warn' : 'info',
|
|
169
|
-
receivers,
|
|
170
|
-
words: lng => (0, announcement_rules_1.noticeWordsOf)(one, kind, sayIn(lng)),
|
|
171
|
-
address: (0, announcement_rules_1.viewAddressOf)(one.id),
|
|
172
|
-
link,
|
|
173
|
-
label: `announcement ${kind} ${one.id}`,
|
|
174
|
-
/* The mail carries the whole body, drawn from its Markdown; the inbox and push show the summary. */
|
|
175
|
-
format: 'markdown',
|
|
176
|
-
channels: { email: !!one.sendEmail },
|
|
177
|
-
/* Said once to the domain's Teams channel too - only what is addressed to everyone, and only when it goes out or all are told again. */
|
|
178
|
-
...(broadcast ? { broadcast: true } : {})
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
/** Keeps what one telling sent on the announcement - in its own transaction, the request's being over. */
|
|
182
|
-
async function recordDelivery(id, kind, result, receivers) {
|
|
183
|
-
try {
|
|
184
|
-
const repository = (0, shell_1.getRepository)(announcement_1.Announcement);
|
|
185
|
-
const one = await repository.findOneBy({ id });
|
|
186
|
-
if (one)
|
|
187
|
-
await repository.update(id, { deliveries: (0, announcement_rules_1.withDelivery)(one.deliveries, (0, announcement_rules_1.deliveryOf)(kind, result, receivers)) });
|
|
188
|
-
}
|
|
189
|
-
catch (error) {
|
|
190
|
-
env_1.logger.error(`announcement ${id}: what was sent could not be kept`, error);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
/**
|
|
194
|
-
* Tells `userIds` of it once the request's transaction has committed - a reader told before it would not find it yet -
|
|
195
|
-
* and keeps what went out. A notice that does not arrive does not undo the announcement: its list, badge and popup
|
|
196
|
-
* still reach them.
|
|
197
|
-
*/
|
|
198
|
-
async function tellWhenCommitted(context, one, kind, userIds, toEveryone = false) {
|
|
199
|
-
const receivers = await receiversOf(userIds, context.state.tx);
|
|
200
|
-
if (!receivers.length)
|
|
201
|
-
return;
|
|
202
|
-
const broadcast = toEveryone && (0, announcement_rules_1.broadcastOf)(await audiencesOf(one.id, context.state.tx), context.state.domain?.id);
|
|
203
|
-
(0, notification_1.sendNoticeWhenCommitted)(context, noticeOf(one, kind, receivers, broadcast, (0, notification_1.noticeLinkOf)(context, (0, announcement_rules_1.viewAddressOf)(one.id))), result => recordDelivery(one.id, kind, result, receivers.length));
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Publishes the scheduled announcements whose start has come. Each is taken by one update from SCHEDULED, so a server
|
|
207
|
-
* among several that loses the race does not send it twice.
|
|
208
|
-
*/
|
|
209
|
-
async function publishDue(now = new Date()) {
|
|
210
|
-
const due = await (0, shell_1.getRepository)(announcement_1.Announcement).find({
|
|
211
|
-
where: { status: announcement_1.AnnouncementStatus.SCHEDULED, startsAt: (0, typeorm_1.LessThanOrEqual)(now), deletedAt: (0, typeorm_1.IsNull)() },
|
|
212
|
-
relations: ['domain', 'publisher', 'creator'],
|
|
213
|
-
take: 50
|
|
214
|
-
});
|
|
215
|
-
let published = 0;
|
|
216
|
-
for (const one of due) {
|
|
217
|
-
try {
|
|
218
|
-
const by = { id: one.publisherId ?? one.creatorId };
|
|
219
|
-
const receivers = await (0, shell_1.getDataSource)().transaction(async (tx) => {
|
|
220
|
-
const taken = await tx.getRepository(announcement_1.Announcement).update({ id: one.id, status: announcement_1.AnnouncementStatus.SCHEDULED }, { status: announcement_1.AnnouncementStatus.DRAFT });
|
|
221
|
-
if (!taken.affected)
|
|
222
|
-
return undefined;
|
|
223
|
-
return await sendOut({ ...one, status: announcement_1.AnnouncementStatus.DRAFT }, one.domain, by, tx);
|
|
224
|
-
});
|
|
225
|
-
if (!receivers)
|
|
226
|
-
continue;
|
|
227
|
-
published++;
|
|
228
|
-
/* No request, so no address to put on a mail button - the mail says where to find it instead. */
|
|
229
|
-
const people = await receiversOf(receivers);
|
|
230
|
-
const broadcast = (0, announcement_rules_1.broadcastOf)(await audiencesOf(one.id), one.domain?.id);
|
|
231
|
-
if (people.length)
|
|
232
|
-
await recordDelivery(one.id, 'published', await (0, notification_1.sendNotice)(one.domain, noticeOf(one, 'published', people, broadcast)), people.length);
|
|
233
|
-
}
|
|
234
|
-
catch (error) {
|
|
235
|
-
env_1.logger.error(`announcement ${one.id}: publishing at its start failed`, error);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
return published;
|
|
239
|
-
}
|
|
240
|
-
let timer;
|
|
241
|
-
/** Looks for scheduled announcements every minute. The timer never keeps the process alive. */
|
|
242
|
-
function schedulePublishing() {
|
|
243
|
-
if (timer)
|
|
244
|
-
return;
|
|
245
|
-
timer = setInterval(() => void publishDue().catch(error => env_1.logger.error('scheduled announcements', error)), 60 * 1000);
|
|
246
|
-
timer.unref?.();
|
|
247
|
-
}
|
|
248
|
-
//# sourceMappingURL=announcement-service.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"announcement-service.js","sourceRoot":"","sources":["../../../server/service/announcement/announcement-service.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * What the doors of announcements do with the database (ADR-0163 decisions 1-5): who may read one, who is on its roster,\n * sending it out, telling people of it, and publishing the scheduled ones when their start comes.\n */\nimport { EntityManager, In, IsNull, LessThanOrEqual } from 'typeorm'\n\nimport { checkPermission, User, UserStatus } from '@things-factory/auth-base'\nimport { logger } from '@things-factory/env'\nimport { translatorFor } from '@things-factory/i18n-base/translator'\nimport { noticeLinkOf, sendNotice, sendNoticeWhenCommitted, type Notice, type NoticeResult } from '@things-factory/notification'\nimport { audienceMemberOf, audienceUserIds, type AudienceMember } from '@things-factory/organization'\nimport { Domain, getDataSource, getRepository } from '@things-factory/shell'\n\nimport { Announcement, AnnouncementAudience, AnnouncementReceipt, AnnouncementRevision, AnnouncementStatus } from './announcement'\nimport { broadcastOf, deliveryOf, noticeWordsOf, viewAddressOf, withDelivery, type NoticeKind, type Say } from './announcement-rules'\n\n/** The attachments of an announcement hang on it under this `refType` (attachment-base). */\nexport const ANNOUNCEMENT_REF_TYPE = 'Announcement'\n\n/** Whether the request writes announcements - the one privilege of the module (`announcement.writing`). */\nexport async function isWriter(context: any): Promise<boolean> {\n const state = context?.state ?? {}\n const { domain, user, unsafeIP, prohibitedPrivileges } = state\n if (!domain || !user) return false\n /* Asked once per request - a list asks it for each row. */\n state.__announcementWriter ??= checkPermission({ category: 'announcement', privilege: 'mutation', owner: true } as any, user, domain, unsafeIP, prohibitedPrivileges).then(Boolean)\n return await state.__announcementWriter\n}\n\n/** The request's person as an audience sees them - asked once per request. */\nexport async function memberOf(context: any): Promise<AudienceMember> {\n const state = context.state\n if (!state.__announcementMember) {\n const { ownDepartments, ...member } = await audienceMemberOf(state.domain, state.user ?? {})\n state.__announcementMember = member\n }\n return state.__announcementMember\n}\n\n/** The announcements of the domain whose audience names `member` - by their targets, whatever their status. */\nexport async function reachingIds(member: AudienceMember, tx?: EntityManager): Promise<string[]> {\n if (!member.userId || !member.domainId) return []\n const domain = { id: member.domainId }\n const rows = await getRepository(AnnouncementAudience, tx).find({\n where: [\n { domain, scope: 'DOMAIN', targetId: member.domainId },\n { domain, scope: 'USER', targetId: member.userId },\n ...(member.departmentIds.length ? [{ domain, scope: 'DEPARTMENT', targetId: In([...member.departmentIds]) }] : []),\n ...(member.roleIds.length ? [{ domain, scope: 'ROLE', targetId: In([...member.roleIds]) }] : [])\n ] as any\n })\n return [...new Set(rows.map(one => one.announcementId!))]\n}\n\nexport async function audiencesOf(announcementId: string, tx?: EntityManager): Promise<AnnouncementAudience[]> {\n return await getRepository(AnnouncementAudience, tx).find({ where: { announcement: { id: announcementId } } as any, order: { createdAt: 'ASC' } as any })\n}\n\n/**\n * The announcement as the request may see it, or nothing - one answer for \"none\", \"not yours\" and \"not out yet\".\n * Its audience reads it once it is out; a writer reads every one that is not somebody else's draft.\n */\nexport async function visibleAnnouncement(id: string, context: any, tx?: EntityManager): Promise<{ announcement: Announcement; reader: boolean; writer: boolean } | undefined> {\n const { domain, user } = context?.state ?? {}\n if (!id || !domain || !user || !/^[0-9a-f-]{36}$/i.test(id)) return undefined\n const announcement = await getRepository(Announcement, tx).findOne({ where: { id, domain: { id: domain.id } } as any })\n if (!announcement) return undefined\n const reader = announcement.status === AnnouncementStatus.PUBLISHED && (await reachingIds(await memberOf(context), tx)).includes(id)\n const writer = (announcement.status !== AnnouncementStatus.DRAFT || announcement.creatorId === user.id) && (await isWriter(context))\n return reader || writer ? { announcement, reader, writer } : undefined\n}\n\n/**\n * Puts the roster in line with the audience as it stands: everyone it names now is listed, one it no longer names is\n * not (their reading stays). Answers those newly listed - the ones not yet told.\n */\nexport async function alignRoster(announcement: Announcement, domain: Domain, by: { id: string }, tx: EntityManager): Promise<string[]> {\n const named = await audienceUserIds(domain, await audiencesOf(announcement.id, tx), tx)\n const repository = getRepository(AnnouncementReceipt, tx)\n const receipts = await repository.find({ where: { announcement: { id: announcement.id } } as any })\n const byUser = new Map(receipts.map(one => [one.userId, one]))\n const now = new Date()\n const added: string[] = []\n for (const userId of named) {\n const receipt = byUser.get(userId)\n if (receipt?.listed) continue\n added.push(userId)\n if (receipt) await repository.update(receipt.id, { listed: true, notifiedAt: now, updater: by } as any)\n else await repository.save({ domain, announcement: { id: announcement.id }, user: { id: userId }, listed: true, notifiedAt: now, creator: by, updater: by } as any)\n }\n const gone = receipts.filter(one => one.listed && !named.includes(one.userId!))\n if (gone.length) await repository.update({ id: In(gone.map(one => one.id)) } as any, { listed: false, updater: by } as any)\n await getRepository(Announcement, tx).update(announcement.id, { audienceSize: named.length } as any)\n return added\n}\n\n/** The version as it stands, kept - the one that went out, and each change after. */\nexport async function keepRevision(announcement: Announcement, domain: Domain, by: { id: string }, tx: EntityManager): Promise<void> {\n const audiences = await audiencesOf(announcement.id, tx)\n const { title, body, category, importance, startsAt, endsAt, pinned, requiresAcknowledgement, acknowledgeBy, popup, links } = announcement\n await getRepository(AnnouncementRevision, tx).save({\n domain,\n announcement: { id: announcement.id },\n version: announcement.version,\n title,\n body,\n rest: {\n category,\n importance,\n startsAt,\n endsAt,\n pinned,\n requiresAcknowledgement,\n acknowledgeBy,\n popup,\n links,\n audiences: audiences.map(({ scope, targetId, targetName }) => ({ scope, targetId, targetName }))\n },\n creator: by,\n updater: by\n } as any)\n}\n\n/**\n * Sends it out: published now, the roster counted, this version kept. Answers the people to tell - the publisher is not\n * told of their own announcement.\n */\nexport async function sendOut(announcement: Announcement, domain: Domain, by: { id: string }, tx: EntityManager): Promise<string[]> {\n const now = new Date()\n await getRepository(Announcement, tx).update(announcement.id, {\n status: AnnouncementStatus.PUBLISHED,\n publishedAt: now,\n startsAt: announcement.startsAt ?? now,\n publisher: by,\n updater: by\n } as any)\n const fresh = await getRepository(Announcement, tx).findOneBy({ id: announcement.id })\n await keepRevision(fresh!, domain, by, tx)\n return (await alignRoster(fresh!, domain, by, tx)).filter(id => id !== by.id)\n}\n\n/** The sentences in `lng` from this module's translations, the English one where `lng` has none. */\nconst sayIn =\n (lng: string): Say =>\n (key, english, params = {}) =>\n translatorFor(lng)(key, { ...params, defaultValue: english.replace(/\\{(\\w+)\\}/g, (_, name) => String(params[name] ?? '')) })\n\n/** The people to tell, as notification takes them - only those who can sign in, each with their mail and language. */\nasync function receiversOf(userIds: string[], tx?: EntityManager) {\n if (!userIds.length) return []\n const people = await getRepository(User, tx).find({ where: { id: In(userIds) } as any })\n return people.filter(one => one.status === UserStatus.ACTIVATED).map(one => ({ id: one.id, email: one.email, locale: (one as any).locale }))\n}\n\n/**\n * The notice of an announcement (notification ADR-0164): in the app and by web push always - the `announcement` type is\n * what pops it up - and by mail when the announcement asks for it and the domain has mail on.\n */\nfunction noticeOf(one: Announcement, kind: NoticeKind, receivers: Notice['receivers'], broadcast: boolean, link?: string): Notice {\n return {\n type: 'announcement',\n level: one.importance === 'URGENT' ? 'warn' : 'info',\n receivers,\n words: lng => noticeWordsOf(one, kind, sayIn(lng)),\n address: viewAddressOf(one.id),\n link,\n label: `announcement ${kind} ${one.id}`,\n /* The mail carries the whole body, drawn from its Markdown; the inbox and push show the summary. */\n format: 'markdown',\n channels: { email: !!one.sendEmail },\n /* Said once to the domain's Teams channel too - only what is addressed to everyone, and only when it goes out or all are told again. */\n ...(broadcast ? { broadcast: true } : {})\n }\n}\n\n/** Keeps what one telling sent on the announcement - in its own transaction, the request's being over. */\nasync function recordDelivery(id: string, kind: NoticeKind, result: NoticeResult | undefined, receivers: number): Promise<void> {\n try {\n const repository = getRepository(Announcement)\n const one = await repository.findOneBy({ id })\n if (one) await repository.update(id, { deliveries: withDelivery(one.deliveries, deliveryOf(kind, result, receivers)) } as any)\n } catch (error) {\n logger.error(`announcement ${id}: what was sent could not be kept`, error)\n }\n}\n\n/**\n * Tells `userIds` of it once the request's transaction has committed - a reader told before it would not find it yet -\n * and keeps what went out. A notice that does not arrive does not undo the announcement: its list, badge and popup\n * still reach them.\n */\nexport async function tellWhenCommitted(context: any, one: Announcement, kind: NoticeKind, userIds: string[], toEveryone = false): Promise<void> {\n const receivers = await receiversOf(userIds, context.state.tx)\n if (!receivers.length) return\n const broadcast = toEveryone && broadcastOf(await audiencesOf(one.id, context.state.tx), context.state.domain?.id)\n sendNoticeWhenCommitted(context, noticeOf(one, kind, receivers, broadcast, noticeLinkOf(context, viewAddressOf(one.id))), result =>\n recordDelivery(one.id, kind, result, receivers.length)\n )\n}\n\n/**\n * Publishes the scheduled announcements whose start has come. Each is taken by one update from SCHEDULED, so a server\n * among several that loses the race does not send it twice.\n */\nexport async function publishDue(now = new Date()): Promise<number> {\n const due = await getRepository(Announcement).find({\n where: { status: AnnouncementStatus.SCHEDULED, startsAt: LessThanOrEqual(now), deletedAt: IsNull() } as any,\n relations: ['domain', 'publisher', 'creator'],\n take: 50\n })\n let published = 0\n for (const one of due) {\n try {\n const by = { id: one.publisherId ?? one.creatorId! }\n const receivers = await getDataSource().transaction(async tx => {\n const taken = await tx.getRepository(Announcement).update({ id: one.id, status: AnnouncementStatus.SCHEDULED } as any, { status: AnnouncementStatus.DRAFT } as any)\n if (!taken.affected) return undefined\n return await sendOut({ ...one, status: AnnouncementStatus.DRAFT } as Announcement, one.domain!, by, tx)\n })\n if (!receivers) continue\n published++\n /* No request, so no address to put on a mail button - the mail says where to find it instead. */\n const people = await receiversOf(receivers)\n const broadcast = broadcastOf(await audiencesOf(one.id), one.domain?.id)\n if (people.length) await recordDelivery(one.id, 'published', await sendNotice(one.domain, noticeOf(one, 'published', people, broadcast)), people.length)\n } catch (error) {\n logger.error(`announcement ${one.id}: publishing at its start failed`, error)\n }\n }\n return published\n}\n\nlet timer: ReturnType<typeof setInterval> | undefined\n\n/** Looks for scheduled announcements every minute. The timer never keeps the process alive. */\nexport function schedulePublishing(): void {\n if (timer) return\n timer = setInterval(() => void publishDue().catch(error => logger.error('scheduled announcements', error)), 60 * 1000)\n timer.unref?.()\n}\n"]}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { Announcement } from './announcement';
|
|
2
|
-
export declare class AnnouncementLinkInput {
|
|
3
|
-
label: string;
|
|
4
|
-
url: string;
|
|
5
|
-
}
|
|
6
|
-
export declare class AnnouncementAudienceInput {
|
|
7
|
-
scope: string;
|
|
8
|
-
targetId: string;
|
|
9
|
-
targetName?: string;
|
|
10
|
-
}
|
|
11
|
-
export declare class AnnouncementInput {
|
|
12
|
-
title: string;
|
|
13
|
-
body?: string;
|
|
14
|
-
category?: string;
|
|
15
|
-
importance?: string;
|
|
16
|
-
startsAt?: Date;
|
|
17
|
-
endsAt?: Date;
|
|
18
|
-
pinned?: boolean;
|
|
19
|
-
requiresAcknowledgement?: boolean;
|
|
20
|
-
acknowledgeBy?: Date;
|
|
21
|
-
popup?: boolean;
|
|
22
|
-
sendEmail?: boolean;
|
|
23
|
-
links?: AnnouncementLinkInput[];
|
|
24
|
-
audiences?: AnnouncementAudienceInput[];
|
|
25
|
-
}
|
|
26
|
-
export declare class AnnouncementList {
|
|
27
|
-
items: Announcement[];
|
|
28
|
-
total: number;
|
|
29
|
-
}
|
|
30
|
-
export declare class AnnouncementSummary {
|
|
31
|
-
unread: number;
|
|
32
|
-
toAcknowledge: number;
|
|
33
|
-
pending: number;
|
|
34
|
-
}
|
|
35
|
-
export declare class AnnouncementReceiptRow {
|
|
36
|
-
userId: string;
|
|
37
|
-
name?: string;
|
|
38
|
-
email?: string;
|
|
39
|
-
listed: boolean;
|
|
40
|
-
notifiedAt?: Date;
|
|
41
|
-
readAt?: Date;
|
|
42
|
-
acknowledgedAt?: Date;
|
|
43
|
-
}
|
|
44
|
-
export declare class AnnouncementChoice {
|
|
45
|
-
id: string;
|
|
46
|
-
name: string;
|
|
47
|
-
note?: string;
|
|
48
|
-
}
|
|
49
|
-
export declare class AnnouncementAudienceChoices {
|
|
50
|
-
domainId: string;
|
|
51
|
-
domainName: string;
|
|
52
|
-
departments: AnnouncementChoice[];
|
|
53
|
-
roles: AnnouncementChoice[];
|
|
54
|
-
}
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AnnouncementAudienceChoices = exports.AnnouncementChoice = exports.AnnouncementReceiptRow = exports.AnnouncementSummary = exports.AnnouncementList = exports.AnnouncementInput = exports.AnnouncementAudienceInput = exports.AnnouncementLinkInput = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const type_graphql_1 = require("type-graphql");
|
|
6
|
-
const announcement_1 = require("./announcement");
|
|
7
|
-
let AnnouncementLinkInput = class AnnouncementLinkInput {
|
|
8
|
-
};
|
|
9
|
-
exports.AnnouncementLinkInput = AnnouncementLinkInput;
|
|
10
|
-
tslib_1.__decorate([
|
|
11
|
-
(0, type_graphql_1.Field)({ description: 'What the link is called on the announcement.' }),
|
|
12
|
-
tslib_1.__metadata("design:type", String)
|
|
13
|
-
], AnnouncementLinkInput.prototype, "label", void 0);
|
|
14
|
-
tslib_1.__decorate([
|
|
15
|
-
(0, type_graphql_1.Field)({ description: "A screen of the application by its address (`contract-list?id=…`) or an https page." }),
|
|
16
|
-
tslib_1.__metadata("design:type", String)
|
|
17
|
-
], AnnouncementLinkInput.prototype, "url", void 0);
|
|
18
|
-
exports.AnnouncementLinkInput = AnnouncementLinkInput = tslib_1.__decorate([
|
|
19
|
-
(0, type_graphql_1.InputType)({ description: 'A screen an announcement points to.' })
|
|
20
|
-
], AnnouncementLinkInput);
|
|
21
|
-
let AnnouncementAudienceInput = class AnnouncementAudienceInput {
|
|
22
|
-
};
|
|
23
|
-
exports.AnnouncementAudienceInput = AnnouncementAudienceInput;
|
|
24
|
-
tslib_1.__decorate([
|
|
25
|
-
(0, type_graphql_1.Field)({ description: 'DOMAIN, DEPARTMENT (with the departments under it), ROLE or USER.' }),
|
|
26
|
-
tslib_1.__metadata("design:type", String)
|
|
27
|
-
], AnnouncementAudienceInput.prototype, "scope", void 0);
|
|
28
|
-
tslib_1.__decorate([
|
|
29
|
-
(0, type_graphql_1.Field)({ description: 'The domain, department, role or user id.' }),
|
|
30
|
-
tslib_1.__metadata("design:type", String)
|
|
31
|
-
], AnnouncementAudienceInput.prototype, "targetId", void 0);
|
|
32
|
-
tslib_1.__decorate([
|
|
33
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'Its name, shown to the writer.' }),
|
|
34
|
-
tslib_1.__metadata("design:type", String)
|
|
35
|
-
], AnnouncementAudienceInput.prototype, "targetName", void 0);
|
|
36
|
-
exports.AnnouncementAudienceInput = AnnouncementAudienceInput = tslib_1.__decorate([
|
|
37
|
-
(0, type_graphql_1.InputType)({ description: 'One target of an announcement.' })
|
|
38
|
-
], AnnouncementAudienceInput);
|
|
39
|
-
let AnnouncementInput = class AnnouncementInput {
|
|
40
|
-
};
|
|
41
|
-
exports.AnnouncementInput = AnnouncementInput;
|
|
42
|
-
tslib_1.__decorate([
|
|
43
|
-
(0, type_graphql_1.Field)({ description: 'The title.' }),
|
|
44
|
-
tslib_1.__metadata("design:type", String)
|
|
45
|
-
], AnnouncementInput.prototype, "title", void 0);
|
|
46
|
-
tslib_1.__decorate([
|
|
47
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'The body, in Markdown.' }),
|
|
48
|
-
tslib_1.__metadata("design:type", String)
|
|
49
|
-
], AnnouncementInput.prototype, "body", void 0);
|
|
50
|
-
tslib_1.__decorate([
|
|
51
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'The kind - one of the codes the module declares; GENERAL when empty.' }),
|
|
52
|
-
tslib_1.__metadata("design:type", String)
|
|
53
|
-
], AnnouncementInput.prototype, "category", void 0);
|
|
54
|
-
tslib_1.__decorate([
|
|
55
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'NORMAL, IMPORTANT or URGENT; NORMAL when empty.' }),
|
|
56
|
-
tslib_1.__metadata("design:type", String)
|
|
57
|
-
], AnnouncementInput.prototype, "importance", void 0);
|
|
58
|
-
tslib_1.__decorate([
|
|
59
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'When it starts to be shown - empty publishes it at once.' }),
|
|
60
|
-
tslib_1.__metadata("design:type", Date)
|
|
61
|
-
], AnnouncementInput.prototype, "startsAt", void 0);
|
|
62
|
-
tslib_1.__decorate([
|
|
63
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'When it stops being a current one.' }),
|
|
64
|
-
tslib_1.__metadata("design:type", Date)
|
|
65
|
-
], AnnouncementInput.prototype, "endsAt", void 0);
|
|
66
|
-
tslib_1.__decorate([
|
|
67
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'Kept on top of the list while current.' }),
|
|
68
|
-
tslib_1.__metadata("design:type", Boolean)
|
|
69
|
-
], AnnouncementInput.prototype, "pinned", void 0);
|
|
70
|
-
tslib_1.__decorate([
|
|
71
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'Each reader is asked to acknowledge it.' }),
|
|
72
|
-
tslib_1.__metadata("design:type", Boolean)
|
|
73
|
-
], AnnouncementInput.prototype, "requiresAcknowledgement", void 0);
|
|
74
|
-
tslib_1.__decorate([
|
|
75
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'The day by which readers are asked to acknowledge it.' }),
|
|
76
|
-
tslib_1.__metadata("design:type", Date)
|
|
77
|
-
], AnnouncementInput.prototype, "acknowledgeBy", void 0);
|
|
78
|
-
tslib_1.__decorate([
|
|
79
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'Shown in a popup to its readers.' }),
|
|
80
|
-
tslib_1.__metadata("design:type", Boolean)
|
|
81
|
-
], AnnouncementInput.prototype, "popup", void 0);
|
|
82
|
-
tslib_1.__decorate([
|
|
83
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'Sent by mail too, where the domain has mail on.' }),
|
|
84
|
-
tslib_1.__metadata("design:type", Boolean)
|
|
85
|
-
], AnnouncementInput.prototype, "sendEmail", void 0);
|
|
86
|
-
tslib_1.__decorate([
|
|
87
|
-
(0, type_graphql_1.Field)(type => [AnnouncementLinkInput], { nullable: true, description: 'Screens it points to.' }),
|
|
88
|
-
tslib_1.__metadata("design:type", Array)
|
|
89
|
-
], AnnouncementInput.prototype, "links", void 0);
|
|
90
|
-
tslib_1.__decorate([
|
|
91
|
-
(0, type_graphql_1.Field)(type => [AnnouncementAudienceInput], { nullable: true, description: 'Whom it is addressed to - the whole list.' }),
|
|
92
|
-
tslib_1.__metadata("design:type", Array)
|
|
93
|
-
], AnnouncementInput.prototype, "audiences", void 0);
|
|
94
|
-
exports.AnnouncementInput = AnnouncementInput = tslib_1.__decorate([
|
|
95
|
-
(0, type_graphql_1.InputType)({ description: 'What an announcement says, to whom and how.' })
|
|
96
|
-
], AnnouncementInput);
|
|
97
|
-
let AnnouncementList = class AnnouncementList {
|
|
98
|
-
};
|
|
99
|
-
exports.AnnouncementList = AnnouncementList;
|
|
100
|
-
tslib_1.__decorate([
|
|
101
|
-
(0, type_graphql_1.Field)(type => [announcement_1.Announcement], { description: 'The announcements of the page.' }),
|
|
102
|
-
tslib_1.__metadata("design:type", Array)
|
|
103
|
-
], AnnouncementList.prototype, "items", void 0);
|
|
104
|
-
tslib_1.__decorate([
|
|
105
|
-
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'How many there are in all.' }),
|
|
106
|
-
tslib_1.__metadata("design:type", Number)
|
|
107
|
-
], AnnouncementList.prototype, "total", void 0);
|
|
108
|
-
exports.AnnouncementList = AnnouncementList = tslib_1.__decorate([
|
|
109
|
-
(0, type_graphql_1.ObjectType)({ description: 'A page of announcements.' })
|
|
110
|
-
], AnnouncementList);
|
|
111
|
-
let AnnouncementSummary = class AnnouncementSummary {
|
|
112
|
-
};
|
|
113
|
-
exports.AnnouncementSummary = AnnouncementSummary;
|
|
114
|
-
tslib_1.__decorate([
|
|
115
|
-
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Current announcements the reader has not read.' }),
|
|
116
|
-
tslib_1.__metadata("design:type", Number)
|
|
117
|
-
], AnnouncementSummary.prototype, "unread", void 0);
|
|
118
|
-
tslib_1.__decorate([
|
|
119
|
-
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Current announcements the reader has not acknowledged though they ask for it.' }),
|
|
120
|
-
tslib_1.__metadata("design:type", Number)
|
|
121
|
-
], AnnouncementSummary.prototype, "toAcknowledge", void 0);
|
|
122
|
-
tslib_1.__decorate([
|
|
123
|
-
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Current announcements still owed anything - unread, or read and not yet acknowledged. The menu badge.' }),
|
|
124
|
-
tslib_1.__metadata("design:type", Number)
|
|
125
|
-
], AnnouncementSummary.prototype, "pending", void 0);
|
|
126
|
-
exports.AnnouncementSummary = AnnouncementSummary = tslib_1.__decorate([
|
|
127
|
-
(0, type_graphql_1.ObjectType)({ description: "What the reader still owes the announcements addressed to them that are current." })
|
|
128
|
-
], AnnouncementSummary);
|
|
129
|
-
let AnnouncementReceiptRow = class AnnouncementReceiptRow {
|
|
130
|
-
};
|
|
131
|
-
exports.AnnouncementReceiptRow = AnnouncementReceiptRow;
|
|
132
|
-
tslib_1.__decorate([
|
|
133
|
-
(0, type_graphql_1.Field)({ description: 'The user id.' }),
|
|
134
|
-
tslib_1.__metadata("design:type", String)
|
|
135
|
-
], AnnouncementReceiptRow.prototype, "userId", void 0);
|
|
136
|
-
tslib_1.__decorate([
|
|
137
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'The name.' }),
|
|
138
|
-
tslib_1.__metadata("design:type", String)
|
|
139
|
-
], AnnouncementReceiptRow.prototype, "name", void 0);
|
|
140
|
-
tslib_1.__decorate([
|
|
141
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'The e-mail.' }),
|
|
142
|
-
tslib_1.__metadata("design:type", String)
|
|
143
|
-
], AnnouncementReceiptRow.prototype, "email", void 0);
|
|
144
|
-
tslib_1.__decorate([
|
|
145
|
-
(0, type_graphql_1.Field)({ description: 'On the roster - addressed when it went out or when its audience changed.' }),
|
|
146
|
-
tslib_1.__metadata("design:type", Boolean)
|
|
147
|
-
], AnnouncementReceiptRow.prototype, "listed", void 0);
|
|
148
|
-
tslib_1.__decorate([
|
|
149
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'When they were last told of it.' }),
|
|
150
|
-
tslib_1.__metadata("design:type", Date)
|
|
151
|
-
], AnnouncementReceiptRow.prototype, "notifiedAt", void 0);
|
|
152
|
-
tslib_1.__decorate([
|
|
153
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'When they read it.' }),
|
|
154
|
-
tslib_1.__metadata("design:type", Date)
|
|
155
|
-
], AnnouncementReceiptRow.prototype, "readAt", void 0);
|
|
156
|
-
tslib_1.__decorate([
|
|
157
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'When they acknowledged it.' }),
|
|
158
|
-
tslib_1.__metadata("design:type", Date)
|
|
159
|
-
], AnnouncementReceiptRow.prototype, "acknowledgedAt", void 0);
|
|
160
|
-
exports.AnnouncementReceiptRow = AnnouncementReceiptRow = tslib_1.__decorate([
|
|
161
|
-
(0, type_graphql_1.ObjectType)({ description: "One person's reading of an announcement, for its writer." })
|
|
162
|
-
], AnnouncementReceiptRow);
|
|
163
|
-
let AnnouncementChoice = class AnnouncementChoice {
|
|
164
|
-
};
|
|
165
|
-
exports.AnnouncementChoice = AnnouncementChoice;
|
|
166
|
-
tslib_1.__decorate([
|
|
167
|
-
(0, type_graphql_1.Field)({ description: 'The id.' }),
|
|
168
|
-
tslib_1.__metadata("design:type", String)
|
|
169
|
-
], AnnouncementChoice.prototype, "id", void 0);
|
|
170
|
-
tslib_1.__decorate([
|
|
171
|
-
(0, type_graphql_1.Field)({ description: 'The name.' }),
|
|
172
|
-
tslib_1.__metadata("design:type", String)
|
|
173
|
-
], AnnouncementChoice.prototype, "name", void 0);
|
|
174
|
-
tslib_1.__decorate([
|
|
175
|
-
(0, type_graphql_1.Field)({ nullable: true, description: 'The department above, for a department; the e-mail, for a person.' }),
|
|
176
|
-
tslib_1.__metadata("design:type", String)
|
|
177
|
-
], AnnouncementChoice.prototype, "note", void 0);
|
|
178
|
-
exports.AnnouncementChoice = AnnouncementChoice = tslib_1.__decorate([
|
|
179
|
-
(0, type_graphql_1.ObjectType)({ description: 'A target the writer may choose.' })
|
|
180
|
-
], AnnouncementChoice);
|
|
181
|
-
let AnnouncementAudienceChoices = class AnnouncementAudienceChoices {
|
|
182
|
-
};
|
|
183
|
-
exports.AnnouncementAudienceChoices = AnnouncementAudienceChoices;
|
|
184
|
-
tslib_1.__decorate([
|
|
185
|
-
(0, type_graphql_1.Field)({ description: 'The domain - the whole-domain target names it.' }),
|
|
186
|
-
tslib_1.__metadata("design:type", String)
|
|
187
|
-
], AnnouncementAudienceChoices.prototype, "domainId", void 0);
|
|
188
|
-
tslib_1.__decorate([
|
|
189
|
-
(0, type_graphql_1.Field)({ description: 'The domain name.' }),
|
|
190
|
-
tslib_1.__metadata("design:type", String)
|
|
191
|
-
], AnnouncementAudienceChoices.prototype, "domainName", void 0);
|
|
192
|
-
tslib_1.__decorate([
|
|
193
|
-
(0, type_graphql_1.Field)(type => [AnnouncementChoice], { description: 'The departments of the domain, each reaching those under it.' }),
|
|
194
|
-
tslib_1.__metadata("design:type", Array)
|
|
195
|
-
], AnnouncementAudienceChoices.prototype, "departments", void 0);
|
|
196
|
-
tslib_1.__decorate([
|
|
197
|
-
(0, type_graphql_1.Field)(type => [AnnouncementChoice], { description: 'The roles of the domain, the inherited ones included.' }),
|
|
198
|
-
tslib_1.__metadata("design:type", Array)
|
|
199
|
-
], AnnouncementAudienceChoices.prototype, "roles", void 0);
|
|
200
|
-
exports.AnnouncementAudienceChoices = AnnouncementAudienceChoices = tslib_1.__decorate([
|
|
201
|
-
(0, type_graphql_1.ObjectType)({ description: 'What an announcement may be addressed to in the domain.' })
|
|
202
|
-
], AnnouncementAudienceChoices);
|
|
203
|
-
//# sourceMappingURL=announcement-types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"announcement-types.js","sourceRoot":"","sources":["../../../server/service/announcement/announcement-types.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, InputType, Int, ObjectType } from 'type-graphql'\n\nimport { Announcement } from './announcement'\n\n@InputType({ description: 'A screen an announcement points to.' })\nexport class AnnouncementLinkInput {\n @Field({ description: 'What the link is called on the announcement.' })\n label: string\n\n @Field({ description: \"A screen of the application by its address (`contract-list?id=…`) or an https page.\" })\n url: string\n}\n\n@InputType({ description: 'One target of an announcement.' })\nexport class AnnouncementAudienceInput {\n @Field({ description: 'DOMAIN, DEPARTMENT (with the departments under it), ROLE or USER.' })\n scope: string\n\n @Field({ description: 'The domain, department, role or user id.' })\n targetId: string\n\n @Field({ nullable: true, description: 'Its name, shown to the writer.' })\n targetName?: string\n}\n\n@InputType({ description: 'What an announcement says, to whom and how.' })\nexport class AnnouncementInput {\n @Field({ description: 'The title.' })\n title: string\n\n @Field({ nullable: true, description: 'The body, in Markdown.' })\n body?: string\n\n @Field({ nullable: true, description: 'The kind - one of the codes the module declares; GENERAL when empty.' })\n category?: string\n\n @Field({ nullable: true, description: 'NORMAL, IMPORTANT or URGENT; NORMAL when empty.' })\n importance?: string\n\n @Field({ nullable: true, description: 'When it starts to be shown - empty publishes it at once.' })\n startsAt?: Date\n\n @Field({ nullable: true, description: 'When it stops being a current one.' })\n endsAt?: Date\n\n @Field({ nullable: true, description: 'Kept on top of the list while current.' })\n pinned?: boolean\n\n @Field({ nullable: true, description: 'Each reader is asked to acknowledge it.' })\n requiresAcknowledgement?: boolean\n\n @Field({ nullable: true, description: 'The day by which readers are asked to acknowledge it.' })\n acknowledgeBy?: Date\n\n @Field({ nullable: true, description: 'Shown in a popup to its readers.' })\n popup?: boolean\n\n @Field({ nullable: true, description: 'Sent by mail too, where the domain has mail on.' })\n sendEmail?: boolean\n\n @Field(type => [AnnouncementLinkInput], { nullable: true, description: 'Screens it points to.' })\n links?: AnnouncementLinkInput[]\n\n @Field(type => [AnnouncementAudienceInput], { nullable: true, description: 'Whom it is addressed to - the whole list.' })\n audiences?: AnnouncementAudienceInput[]\n}\n\n@ObjectType({ description: 'A page of announcements.' })\nexport class AnnouncementList {\n @Field(type => [Announcement], { description: 'The announcements of the page.' })\n items: Announcement[]\n\n @Field(type => Int, { description: 'How many there are in all.' })\n total: number\n}\n\n@ObjectType({ description: \"What the reader still owes the announcements addressed to them that are current.\" })\nexport class AnnouncementSummary {\n @Field(type => Int, { description: 'Current announcements the reader has not read.' })\n unread: number\n\n @Field(type => Int, { description: 'Current announcements the reader has not acknowledged though they ask for it.' })\n toAcknowledge: number\n\n @Field(type => Int, { description: 'Current announcements still owed anything - unread, or read and not yet acknowledged. The menu badge.' })\n pending: number\n}\n\n@ObjectType({ description: \"One person's reading of an announcement, for its writer.\" })\nexport class AnnouncementReceiptRow {\n @Field({ description: 'The user id.' })\n userId: string\n\n @Field({ nullable: true, description: 'The name.' })\n name?: string\n\n @Field({ nullable: true, description: 'The e-mail.' })\n email?: string\n\n @Field({ description: 'On the roster - addressed when it went out or when its audience changed.' })\n listed: boolean\n\n @Field({ nullable: true, description: 'When they were last told of it.' })\n notifiedAt?: Date\n\n @Field({ nullable: true, description: 'When they read it.' })\n readAt?: Date\n\n @Field({ nullable: true, description: 'When they acknowledged it.' })\n acknowledgedAt?: Date\n}\n\n@ObjectType({ description: 'A target the writer may choose.' })\nexport class AnnouncementChoice {\n @Field({ description: 'The id.' })\n id: string\n\n @Field({ description: 'The name.' })\n name: string\n\n @Field({ nullable: true, description: 'The department above, for a department; the e-mail, for a person.' })\n note?: string\n}\n\n@ObjectType({ description: 'What an announcement may be addressed to in the domain.' })\nexport class AnnouncementAudienceChoices {\n @Field({ description: 'The domain - the whole-domain target names it.' })\n domainId: string\n\n @Field({ description: 'The domain name.' })\n domainName: string\n\n @Field(type => [AnnouncementChoice], { description: 'The departments of the domain, each reaching those under it.' })\n departments: AnnouncementChoice[]\n\n @Field(type => [AnnouncementChoice], { description: 'The roles of the domain, the inherited ones included.' })\n roles: AnnouncementChoice[]\n}\n"]}
|