@terreno/announcements 57.4.0 → 57.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/announcementsApp.js +378 -639
- package/dist/help.js +38 -46
- package/dist/helpRoutes.js +80 -200
- package/dist/models/announcement.js +42 -95
- package/dist/models/announcementAcknowledgement.js +6 -6
- package/dist/models/announcementClickEvent.js +7 -9
- package/dist/models/announcementImpression.js +7 -9
- package/dist/overview.js +151 -300
- package/dist/pending.js +62 -140
- package/package.json +6 -6
- package/src/models/announcement.ts +6 -2
- package/src/models/announcementAcknowledgement.ts +5 -4
- package/src/models/announcementClickEvent.ts +5 -4
- package/src/models/announcementImpression.ts +5 -4
- package/src/tests/index.test.ts +43 -2
- package/tsconfig.json +6 -21
package/dist/help.js
CHANGED
|
@@ -1,72 +1,64 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.toHelpDetail = exports.toHelpSummary = exports.matchesHelpQueries = exports.excerptBody = exports.buildHelpStatusFilter = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const pending_1 = require("./pending");
|
|
5
|
+
const buildHelpStatusFilter = (includeArchived) => {
|
|
6
6
|
if (includeArchived) {
|
|
7
7
|
return ["published", "archived"];
|
|
8
8
|
}
|
|
9
9
|
return ["published"];
|
|
10
10
|
};
|
|
11
11
|
exports.buildHelpStatusFilter = buildHelpStatusFilter;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
var normalized = body.replace(/\s+/g, " ").trim();
|
|
12
|
+
const excerptBody = (body, maxLength = 240) => {
|
|
13
|
+
const normalized = body.replace(/\s+/g, " ").trim();
|
|
15
14
|
if (normalized.length <= maxLength) {
|
|
16
15
|
return normalized;
|
|
17
16
|
}
|
|
18
|
-
return
|
|
17
|
+
return `${normalized.slice(0, maxLength)}…`;
|
|
19
18
|
};
|
|
20
19
|
exports.excerptBody = excerptBody;
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const matchesSingleQuery = (doc, query) => {
|
|
21
|
+
const normalized = query.trim().toLowerCase();
|
|
23
22
|
if (!normalized) {
|
|
24
23
|
return true;
|
|
25
24
|
}
|
|
26
|
-
|
|
25
|
+
const haystack = `${doc.title}\n${doc.body}`.toLowerCase();
|
|
27
26
|
return haystack.includes(normalized);
|
|
28
27
|
};
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const matchesHelpQueries = (doc, queries) => {
|
|
29
|
+
const activeQueries = queries.map((query) => query.trim()).filter(Boolean);
|
|
31
30
|
if (activeQueries.length === 0) {
|
|
32
31
|
return true;
|
|
33
32
|
}
|
|
34
|
-
return activeQueries.some(
|
|
33
|
+
return activeQueries.some((query) => matchesSingleQuery(doc, query));
|
|
35
34
|
};
|
|
36
35
|
exports.matchesHelpQueries = matchesHelpQueries;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
version: doc.version,
|
|
47
|
-
});
|
|
48
|
-
};
|
|
36
|
+
const toHelpSummary = (doc) => ({
|
|
37
|
+
archivedAt: doc.archivedAt?.toISOString(),
|
|
38
|
+
excerpt: (0, exports.excerptBody)(doc.body),
|
|
39
|
+
id: doc._id.toString(),
|
|
40
|
+
publishedAt: doc.publishedAt?.toISOString(),
|
|
41
|
+
status: doc.status,
|
|
42
|
+
title: doc.title,
|
|
43
|
+
version: doc.version,
|
|
44
|
+
});
|
|
49
45
|
exports.toHelpSummary = toHelpSummary;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
title: doc.title,
|
|
69
|
-
version: doc.version,
|
|
70
|
-
});
|
|
71
|
-
};
|
|
46
|
+
const toHelpDetail = (doc, defaultAcknowledgementPolicy = "dismiss-only") => ({
|
|
47
|
+
archivedAt: doc.archivedAt?.toISOString(),
|
|
48
|
+
body: doc.body,
|
|
49
|
+
expiresAt: doc.expiresAt?.toISOString(),
|
|
50
|
+
id: doc._id.toString(),
|
|
51
|
+
platforms: doc.platforms,
|
|
52
|
+
primaryAction: doc.primaryAction,
|
|
53
|
+
priority: doc.priority,
|
|
54
|
+
publishAt: doc.publishAt?.toISOString(),
|
|
55
|
+
publishedAt: doc.publishedAt?.toISOString(),
|
|
56
|
+
requiresAcknowledgement: (0, pending_1.requiresAcknowledgementForAnnouncement)({
|
|
57
|
+
announcement: doc,
|
|
58
|
+
defaultAcknowledgementPolicy,
|
|
59
|
+
}),
|
|
60
|
+
status: doc.status,
|
|
61
|
+
title: doc.title,
|
|
62
|
+
version: doc.version,
|
|
63
|
+
});
|
|
72
64
|
exports.toHelpDetail = toHelpDetail;
|
package/dist/helpRoutes.js
CHANGED
|
@@ -1,233 +1,113 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
-
function step(op) {
|
|
16
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
-
switch (op[0]) {
|
|
21
|
-
case 0: case 1: t = op; break;
|
|
22
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
-
default:
|
|
26
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
-
if (t[2]) _.ops.pop();
|
|
31
|
-
_.trys.pop(); continue;
|
|
32
|
-
}
|
|
33
|
-
op = body.call(thisArg, _);
|
|
34
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
var __read = (this && this.__read) || function (o, n) {
|
|
39
|
-
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
40
|
-
if (!m) return o;
|
|
41
|
-
var i = m.call(o), r, ar = [], e;
|
|
42
|
-
try {
|
|
43
|
-
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
44
|
-
}
|
|
45
|
-
catch (error) { e = { error: error }; }
|
|
46
|
-
finally {
|
|
47
|
-
try {
|
|
48
|
-
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
49
|
-
}
|
|
50
|
-
finally { if (e) throw e.error; }
|
|
51
|
-
}
|
|
52
|
-
return ar;
|
|
53
|
-
};
|
|
54
|
-
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
55
|
-
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
56
|
-
if (ar || !(i in from)) {
|
|
57
|
-
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
58
|
-
ar[i] = from[i];
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return to.concat(ar || Array.prototype.slice.call(from));
|
|
62
|
-
};
|
|
63
|
-
var __values = (this && this.__values) || function(o) {
|
|
64
|
-
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
65
|
-
if (m) return m.call(o);
|
|
66
|
-
if (o && typeof o.length === "number") return {
|
|
67
|
-
next: function () {
|
|
68
|
-
if (o && i >= o.length) o = void 0;
|
|
69
|
-
return { value: o && o[i++], done: !o };
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
73
|
-
};
|
|
74
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
75
3
|
exports.registerAnnouncementHelpRoutes = void 0;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
4
|
+
const api_1 = require("@terreno/api");
|
|
5
|
+
const express_1 = require("express");
|
|
6
|
+
const help_1 = require("./help");
|
|
7
|
+
const announcement_1 = require("./models/announcement");
|
|
8
|
+
const pending_1 = require("./pending");
|
|
9
|
+
const defaultIsStaff = (user) => user.admin === true;
|
|
10
|
+
const parseHelpQueries = (req) => {
|
|
11
|
+
const raw = req.query.q;
|
|
84
12
|
if (typeof raw === "string" && raw.trim()) {
|
|
85
13
|
return [raw.trim()];
|
|
86
14
|
}
|
|
87
15
|
if (Array.isArray(raw)) {
|
|
88
|
-
return raw.filter(
|
|
16
|
+
return raw.filter((value) => typeof value === "string" && value.trim().length > 0);
|
|
89
17
|
}
|
|
90
18
|
return [];
|
|
91
19
|
};
|
|
92
|
-
|
|
93
|
-
|
|
20
|
+
const parseIncludeArchived = (req) => {
|
|
21
|
+
const raw = req.query.includeArchived;
|
|
94
22
|
if (raw === "true" || raw === "1") {
|
|
95
23
|
return true;
|
|
96
24
|
}
|
|
97
25
|
return false;
|
|
98
26
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
var parsed = Number((_a = req.query.limit) !== null && _a !== void 0 ? _a : 10);
|
|
27
|
+
const parseLimit = (req) => {
|
|
28
|
+
const parsed = Number(req.query.limit ?? 10);
|
|
102
29
|
return Math.min(Math.max(parsed, 1), 50);
|
|
103
30
|
};
|
|
104
|
-
|
|
31
|
+
const isAnnouncementHelpVisible = (announcement) => {
|
|
105
32
|
if (announcement.status === "archived") {
|
|
106
33
|
return true;
|
|
107
34
|
}
|
|
108
|
-
return (0, pending_1.isAnnouncementVisibleNow)({ announcement
|
|
35
|
+
return (0, pending_1.isAnnouncementVisibleNow)({ announcement });
|
|
109
36
|
};
|
|
110
|
-
|
|
111
|
-
return
|
|
112
|
-
var _a, _b, _c, _d;
|
|
37
|
+
const sortHelpResults = (docs) => {
|
|
38
|
+
return [...docs].sort((left, right) => {
|
|
113
39
|
if (right.priority !== left.priority) {
|
|
114
40
|
return right.priority - left.priority;
|
|
115
41
|
}
|
|
116
|
-
|
|
117
|
-
|
|
42
|
+
const rightPublished = right.publishedAt?.getTime() ?? 0;
|
|
43
|
+
const leftPublished = left.publishedAt?.getTime() ?? 0;
|
|
118
44
|
return rightPublished - leftPublished;
|
|
119
45
|
});
|
|
120
46
|
};
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
47
|
+
const registerAnnouncementHelpRoutes = ({ app, basePath, defaultAcknowledgementPolicy = "dismiss-only", isStaff = defaultIsStaff, matchAudience, }) => {
|
|
48
|
+
const audienceMatcher = matchAudience ?? (() => true);
|
|
49
|
+
const matchesAnnouncementAudience = async (user, announcement) => {
|
|
50
|
+
if (!(0, pending_1.matchAudienceByType)({ announcement, isStaff, user })) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return audienceMatcher(user, announcement);
|
|
54
|
+
};
|
|
55
|
+
const router = (0, express_1.Router)();
|
|
56
|
+
router.get("/help/search", (0, api_1.authenticateMiddleware)(), (0, api_1.asyncHandler)(async (req, res) => {
|
|
57
|
+
const user = req.user;
|
|
58
|
+
if (!user) {
|
|
59
|
+
throw new api_1.APIError({ status: 401, title: "Authentication required" });
|
|
60
|
+
}
|
|
61
|
+
const queries = parseHelpQueries(req);
|
|
62
|
+
const includeArchived = parseIncludeArchived(req);
|
|
63
|
+
const limit = parseLimit(req);
|
|
64
|
+
const queryVersion = (0, pending_1.parseQueryVersion)(req.query.version);
|
|
65
|
+
const statuses = (0, help_1.buildHelpStatusFilter)(includeArchived);
|
|
66
|
+
const candidates = (await announcement_1.Announcement.find({ status: { $in: statuses } }).lean());
|
|
67
|
+
const matched = [];
|
|
68
|
+
for (const doc of candidates) {
|
|
69
|
+
if (!isAnnouncementHelpVisible(doc)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (!(0, pending_1.passesMinBuildNumber)({ announcement: doc, queryVersion })) {
|
|
73
|
+
continue;
|
|
128
74
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
var router = (0, express_1.Router)();
|
|
133
|
-
router.get("/help/search", (0, api_1.authenticateMiddleware)(), (0, api_1.asyncHandler)(function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
|
|
134
|
-
var user, queries, includeArchived, limit, queryVersion, statuses, candidates, matched, candidates_1, candidates_1_1, doc, matchesAudience, e_1_1, page;
|
|
135
|
-
var e_1, _a;
|
|
136
|
-
return __generator(this, function (_b) {
|
|
137
|
-
switch (_b.label) {
|
|
138
|
-
case 0:
|
|
139
|
-
user = req.user;
|
|
140
|
-
if (!user) {
|
|
141
|
-
throw new api_1.APIError({ status: 401, title: "Authentication required" });
|
|
142
|
-
}
|
|
143
|
-
queries = parseHelpQueries(req);
|
|
144
|
-
includeArchived = parseIncludeArchived(req);
|
|
145
|
-
limit = parseLimit(req);
|
|
146
|
-
queryVersion = (0, pending_1.parseQueryVersion)(req.query.version);
|
|
147
|
-
statuses = (0, help_1.buildHelpStatusFilter)(includeArchived);
|
|
148
|
-
return [4 /*yield*/, announcement_1.Announcement.find({ status: { $in: statuses } }).lean()];
|
|
149
|
-
case 1:
|
|
150
|
-
candidates = (_b.sent());
|
|
151
|
-
matched = [];
|
|
152
|
-
_b.label = 2;
|
|
153
|
-
case 2:
|
|
154
|
-
_b.trys.push([2, 7, 8, 9]);
|
|
155
|
-
candidates_1 = __values(candidates), candidates_1_1 = candidates_1.next();
|
|
156
|
-
_b.label = 3;
|
|
157
|
-
case 3:
|
|
158
|
-
if (!!candidates_1_1.done) return [3 /*break*/, 6];
|
|
159
|
-
doc = candidates_1_1.value;
|
|
160
|
-
if (!isAnnouncementHelpVisible(doc)) {
|
|
161
|
-
return [3 /*break*/, 5];
|
|
162
|
-
}
|
|
163
|
-
if (!(0, pending_1.passesMinBuildNumber)({ announcement: doc, queryVersion: queryVersion })) {
|
|
164
|
-
return [3 /*break*/, 5];
|
|
165
|
-
}
|
|
166
|
-
return [4 /*yield*/, matchesAnnouncementAudience(user, doc)];
|
|
167
|
-
case 4:
|
|
168
|
-
matchesAudience = _b.sent();
|
|
169
|
-
if (!matchesAudience) {
|
|
170
|
-
return [3 /*break*/, 5];
|
|
171
|
-
}
|
|
172
|
-
if (!(0, help_1.matchesHelpQueries)(doc, queries)) {
|
|
173
|
-
return [3 /*break*/, 5];
|
|
174
|
-
}
|
|
175
|
-
matched.push(doc);
|
|
176
|
-
_b.label = 5;
|
|
177
|
-
case 5:
|
|
178
|
-
candidates_1_1 = candidates_1.next();
|
|
179
|
-
return [3 /*break*/, 3];
|
|
180
|
-
case 6: return [3 /*break*/, 9];
|
|
181
|
-
case 7:
|
|
182
|
-
e_1_1 = _b.sent();
|
|
183
|
-
e_1 = { error: e_1_1 };
|
|
184
|
-
return [3 /*break*/, 9];
|
|
185
|
-
case 8:
|
|
186
|
-
try {
|
|
187
|
-
if (candidates_1_1 && !candidates_1_1.done && (_a = candidates_1.return)) _a.call(candidates_1);
|
|
188
|
-
}
|
|
189
|
-
finally { if (e_1) throw e_1.error; }
|
|
190
|
-
return [7 /*endfinally*/];
|
|
191
|
-
case 9:
|
|
192
|
-
page = sortHelpResults(matched).slice(0, limit).map(help_1.toHelpSummary);
|
|
193
|
-
return [2 /*return*/, res.json({ data: page, total: matched.length })];
|
|
75
|
+
const matchesAudience = await matchesAnnouncementAudience(user, doc);
|
|
76
|
+
if (!matchesAudience) {
|
|
77
|
+
continue;
|
|
194
78
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
router.get("/help/:id", (0, api_1.authenticateMiddleware)(), (0, api_1.asyncHandler)(function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
|
|
198
|
-
var user, includeArchived, queryVersion, statuses, announcement, matchesAudience;
|
|
199
|
-
return __generator(this, function (_a) {
|
|
200
|
-
switch (_a.label) {
|
|
201
|
-
case 0:
|
|
202
|
-
user = req.user;
|
|
203
|
-
if (!user) {
|
|
204
|
-
throw new api_1.APIError({ status: 401, title: "Authentication required" });
|
|
205
|
-
}
|
|
206
|
-
includeArchived = parseIncludeArchived(req);
|
|
207
|
-
queryVersion = (0, pending_1.parseQueryVersion)(req.query.version);
|
|
208
|
-
statuses = (0, help_1.buildHelpStatusFilter)(includeArchived);
|
|
209
|
-
return [4 /*yield*/, announcement_1.Announcement.findById(req.params.id).lean()];
|
|
210
|
-
case 1:
|
|
211
|
-
announcement = (_a.sent());
|
|
212
|
-
if (!announcement || !statuses.includes(announcement.status)) {
|
|
213
|
-
throw new api_1.APIError({ status: 404, title: "Update note not found" });
|
|
214
|
-
}
|
|
215
|
-
if (!isAnnouncementHelpVisible(announcement)) {
|
|
216
|
-
throw new api_1.APIError({ status: 404, title: "Update note not found" });
|
|
217
|
-
}
|
|
218
|
-
if (!(0, pending_1.passesMinBuildNumber)({ announcement: announcement, queryVersion: queryVersion })) {
|
|
219
|
-
throw new api_1.APIError({ status: 404, title: "Update note not found" });
|
|
220
|
-
}
|
|
221
|
-
return [4 /*yield*/, matchesAnnouncementAudience(user, announcement)];
|
|
222
|
-
case 2:
|
|
223
|
-
matchesAudience = _a.sent();
|
|
224
|
-
if (!matchesAudience) {
|
|
225
|
-
throw new api_1.APIError({ status: 404, title: "Update note not found" });
|
|
226
|
-
}
|
|
227
|
-
return [2 /*return*/, res.json({ data: (0, help_1.toHelpDetail)(announcement, defaultAcknowledgementPolicy) })];
|
|
79
|
+
if (!(0, help_1.matchesHelpQueries)(doc, queries)) {
|
|
80
|
+
continue;
|
|
228
81
|
}
|
|
229
|
-
|
|
230
|
-
|
|
82
|
+
matched.push(doc);
|
|
83
|
+
}
|
|
84
|
+
const page = sortHelpResults(matched).slice(0, limit).map(help_1.toHelpSummary);
|
|
85
|
+
return res.json({ data: page, total: matched.length });
|
|
86
|
+
}));
|
|
87
|
+
router.get("/help/:id", (0, api_1.authenticateMiddleware)(), (0, api_1.asyncHandler)(async (req, res) => {
|
|
88
|
+
const user = req.user;
|
|
89
|
+
if (!user) {
|
|
90
|
+
throw new api_1.APIError({ status: 401, title: "Authentication required" });
|
|
91
|
+
}
|
|
92
|
+
const includeArchived = parseIncludeArchived(req);
|
|
93
|
+
const queryVersion = (0, pending_1.parseQueryVersion)(req.query.version);
|
|
94
|
+
const statuses = (0, help_1.buildHelpStatusFilter)(includeArchived);
|
|
95
|
+
const announcement = (await announcement_1.Announcement.findById(req.params.id).lean());
|
|
96
|
+
if (!announcement || !statuses.includes(announcement.status)) {
|
|
97
|
+
throw new api_1.APIError({ status: 404, title: "Update note not found" });
|
|
98
|
+
}
|
|
99
|
+
if (!isAnnouncementHelpVisible(announcement)) {
|
|
100
|
+
throw new api_1.APIError({ status: 404, title: "Update note not found" });
|
|
101
|
+
}
|
|
102
|
+
if (!(0, pending_1.passesMinBuildNumber)({ announcement, queryVersion })) {
|
|
103
|
+
throw new api_1.APIError({ status: 404, title: "Update note not found" });
|
|
104
|
+
}
|
|
105
|
+
const matchesAudience = await matchesAnnouncementAudience(user, announcement);
|
|
106
|
+
if (!matchesAudience) {
|
|
107
|
+
throw new api_1.APIError({ status: 404, title: "Update note not found" });
|
|
108
|
+
}
|
|
109
|
+
return res.json({ data: (0, help_1.toHelpDetail)(announcement, defaultAcknowledgementPolicy) });
|
|
110
|
+
}));
|
|
231
111
|
app.use(basePath, router);
|
|
232
112
|
};
|
|
233
113
|
exports.registerAnnouncementHelpRoutes = registerAnnouncementHelpRoutes;
|
|
@@ -1,51 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
-
function step(op) {
|
|
16
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
-
switch (op[0]) {
|
|
21
|
-
case 0: case 1: t = op; break;
|
|
22
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
-
default:
|
|
26
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
-
if (t[2]) _.ops.pop();
|
|
31
|
-
_.trys.pop(); continue;
|
|
32
|
-
}
|
|
33
|
-
op = body.call(thisArg, _);
|
|
34
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
4
|
};
|
|
41
|
-
var _a;
|
|
42
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
6
|
exports.toAnnouncementPublic = exports.Announcement = void 0;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
7
|
+
const api_1 = require("@terreno/api");
|
|
8
|
+
const mongoose_1 = __importDefault(require("mongoose"));
|
|
9
|
+
const pending_1 = require("../pending");
|
|
10
|
+
const ALL_PLATFORMS = ["ios", "android", "web"];
|
|
11
|
+
const announcementSchema = new mongoose_1.default.Schema({
|
|
49
12
|
acknowledgementPolicy: {
|
|
50
13
|
description: "Whether users must acknowledge (required) or may dismiss with an impression only (dismiss-only). Omitted values resolve from the plugin defaultAcknowledgementPolicy at read time.",
|
|
51
14
|
enum: ["required", "dismiss-only"],
|
|
@@ -142,45 +105,32 @@ announcementSchema.plugin(api_1.findExactlyOne);
|
|
|
142
105
|
announcementSchema.plugin(api_1.findOneOrNone);
|
|
143
106
|
announcementSchema.index({ publishAt: 1, status: 1 });
|
|
144
107
|
announcementSchema.index({ priority: -1, publishedAt: -1, status: 1 });
|
|
145
|
-
announcementSchema.pre("save", function bumpVersionOnPublishedEdit() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
previous = _b.sent();
|
|
164
|
-
if ((previous === null || previous === void 0 ? void 0 : previous.status) !== "published") {
|
|
165
|
-
return [2 /*return*/];
|
|
166
|
-
}
|
|
167
|
-
if (previous.title === this.title && previous.body === this.body) {
|
|
168
|
-
return [2 /*return*/];
|
|
169
|
-
}
|
|
170
|
-
this.version = ((_a = previous.version) !== null && _a !== void 0 ? _a : 1) + 1;
|
|
171
|
-
return [2 /*return*/];
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
});
|
|
108
|
+
announcementSchema.pre("save", async function bumpVersionOnPublishedEdit() {
|
|
109
|
+
if (this.isNew) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (this.status !== "published") {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (!this.isModified("title") && !this.isModified("body")) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const previous = await exports.Announcement.findById(this._id).select("title body status version");
|
|
119
|
+
if (previous?.status !== "published") {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (previous.title === this.title && previous.body === this.body) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.version = (previous.version ?? 1) + 1;
|
|
175
126
|
});
|
|
176
127
|
announcementSchema.pre("validate", function validatePrimaryAction() {
|
|
177
|
-
|
|
178
|
-
var action = this.primaryAction;
|
|
128
|
+
const action = this.primaryAction;
|
|
179
129
|
if (!action) {
|
|
180
130
|
return;
|
|
181
131
|
}
|
|
182
|
-
|
|
183
|
-
|
|
132
|
+
const hasLabel = Boolean(action.label?.trim());
|
|
133
|
+
const hasUrl = Boolean(action.url?.trim());
|
|
184
134
|
if (!hasLabel && !hasUrl) {
|
|
185
135
|
this.primaryAction = undefined;
|
|
186
136
|
return;
|
|
@@ -192,23 +142,20 @@ announcementSchema.pre("validate", function validatePrimaryAction() {
|
|
|
192
142
|
});
|
|
193
143
|
}
|
|
194
144
|
});
|
|
195
|
-
exports.Announcement =
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
version: doc.version,
|
|
212
|
-
});
|
|
213
|
-
};
|
|
145
|
+
exports.Announcement = mongoose_1.default.models.TerrenoAnnouncement ??
|
|
146
|
+
mongoose_1.default.model("TerrenoAnnouncement", announcementSchema, "announcements");
|
|
147
|
+
const toAnnouncementPublic = (doc, defaultAcknowledgementPolicy = "dismiss-only") => ({
|
|
148
|
+
body: doc.body,
|
|
149
|
+
displayMode: (0, pending_1.resolveDisplayMode)(doc),
|
|
150
|
+
id: doc._id.toString(),
|
|
151
|
+
primaryAction: doc.primaryAction,
|
|
152
|
+
priority: doc.priority,
|
|
153
|
+
publishedAt: doc.publishedAt?.toISOString(),
|
|
154
|
+
requiresAcknowledgement: (0, pending_1.requiresAcknowledgementForAnnouncement)({
|
|
155
|
+
announcement: doc,
|
|
156
|
+
defaultAcknowledgementPolicy,
|
|
157
|
+
}),
|
|
158
|
+
title: doc.title,
|
|
159
|
+
version: doc.version,
|
|
160
|
+
});
|
|
214
161
|
exports.toAnnouncementPublic = toAnnouncementPublic;
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
|
-
var _a;
|
|
6
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
6
|
exports.AnnouncementAcknowledgement = void 0;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const api_1 = require("@terreno/api");
|
|
8
|
+
const mongoose_1 = __importDefault(require("mongoose"));
|
|
9
|
+
const announcementAcknowledgementSchema = new mongoose_1.default.Schema({
|
|
11
10
|
acknowledgedAt: {
|
|
12
11
|
description: "When the user acknowledged this announcement version",
|
|
13
12
|
required: true,
|
|
@@ -16,7 +15,7 @@ var announcementAcknowledgementSchema = new mongoose_1.default.Schema({
|
|
|
16
15
|
announcementId: {
|
|
17
16
|
description: "Announcement that was acknowledged",
|
|
18
17
|
index: true,
|
|
19
|
-
ref: "
|
|
18
|
+
ref: "TerrenoAnnouncement",
|
|
20
19
|
required: true,
|
|
21
20
|
type: mongoose_1.default.Schema.Types.ObjectId,
|
|
22
21
|
},
|
|
@@ -38,4 +37,5 @@ announcementAcknowledgementSchema.plugin(api_1.isDeletedPlugin);
|
|
|
38
37
|
announcementAcknowledgementSchema.plugin(api_1.findExactlyOne);
|
|
39
38
|
announcementAcknowledgementSchema.plugin(api_1.findOneOrNone);
|
|
40
39
|
announcementAcknowledgementSchema.index({ announcementId: 1, userId: 1, version: 1 }, { unique: true });
|
|
41
|
-
exports.AnnouncementAcknowledgement =
|
|
40
|
+
exports.AnnouncementAcknowledgement = mongoose_1.default.models.TerrenoAnnouncementAcknowledgement ??
|
|
41
|
+
mongoose_1.default.model("TerrenoAnnouncementAcknowledgement", announcementAcknowledgementSchema, "announcementacknowledgements");
|