ghost 4.41.3 → 4.42.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/core/built/assets/ghost-dark-97613c037232aba4490489431ce170ca.css +1 -0
- package/core/built/assets/{ghost.min-1abf114ca26a71e8e1f09054f3592614.js → ghost.min-20096eef632760c3a2906e243adbd24b.js} +400 -323
- package/core/built/assets/ghost.min-c08ce1872f0e09edb63eb13c43606d18.css +1 -0
- package/core/built/assets/{vendor.min-9094db77ba3190cb10876f8e42e1d90d.js → vendor.min-21f79c68a284acb1b70039f3f63e5507.js} +68 -68
- package/core/built/assets/{vendor.min-2c8ad32b7960bb605ebc20097fee5ebd.css → vendor.min-ba66b98f7c24fa40e061c7ffc94f4e23.css} +214 -0
- package/core/frontend/helpers/price.js +1 -0
- package/core/server/api/canary/email-preview.js +2 -1
- package/core/server/api/canary/{email.js → emails.js} +0 -0
- package/core/server/api/canary/index.js +9 -1
- package/core/server/api/canary/members.js +0 -45
- package/core/server/api/canary/newsletters.js +45 -0
- package/core/server/api/canary/stats.js +14 -0
- package/core/server/api/canary/utils/serializers/output/email-previews.js +7 -0
- package/core/server/api/canary/utils/serializers/output/index.js +2 -22
- package/core/server/api/canary/utils/serializers/output/mappers/index.js +1 -0
- package/core/server/api/canary/utils/serializers/output/mappers/snippets.js +36 -0
- package/core/server/api/canary/utils/serializers/output/members.js +0 -2
- package/core/server/api/canary/utils/serializers/output/oembed.js +2 -2
- package/core/server/api/canary/utils/serializers/output/redirects.js +2 -2
- package/core/server/api/canary/utils/serializers/output/schedules.js +2 -2
- package/core/server/api/canary/utils/serializers/output/slack.js +2 -2
- package/core/server/api/canary/utils/serializers/output/themes.js +2 -2
- package/core/server/api/canary/utils/serializers/output/users.js +0 -23
- package/core/server/api/shared/serializers/handle.js +25 -26
- package/core/server/data/exporter/table-lists.js +1 -0
- package/core/server/data/migrations/utils.js +1 -1
- package/core/server/data/migrations/versions/4.42/2022-03-21-17-17-add.js +20 -0
- package/core/server/data/migrations/versions/4.42/2022-03-30-15-44-add-newsletter-permissions.js +28 -0
- package/core/server/data/schema/commands.js +13 -13
- package/core/server/data/schema/schema.js +18 -0
- package/core/server/models/newsletter.js +9 -0
- package/core/server/services/mega/template.js +25 -13
- package/core/server/services/members/service.js +2 -1
- package/core/server/services/stats/index.js +1 -0
- package/core/server/services/stats/lib/members-stats-service.js +165 -0
- package/core/server/services/stats/service.js +6 -0
- package/core/server/services/webhooks/webhooks-service.js +3 -1
- package/core/server/web/admin/views/default-prod.html +5 -5
- package/core/server/web/admin/views/default.html +5 -5
- package/core/server/web/api/canary/admin/routes.js +8 -2
- package/core/shared/config/defaults.json +2 -2
- package/core/shared/config/env/config.development.json +26 -0
- package/core/shared/config/env/config.production.json +21 -0
- package/core/shared/config/env/config.testing-mysql.json +59 -0
- package/core/shared/config/env/config.testing.json +58 -0
- package/package.json +38 -38
- package/yarn.lock +510 -654
- package/core/built/assets/ghost-dark-146c4c688b47d45c4aa018ee0f79cebc.css +0 -1
- package/core/built/assets/ghost.min-a73b150c7eecc4641d377cc73fb5eecd.css +0 -1
- package/core/server/api/canary/utils/serializers/output/email-preview.js +0 -10
- package/core/server/api/canary/utils/serializers/output/emails.js +0 -22
- package/core/server/api/canary/utils/serializers/output/identities.js +0 -7
- package/core/server/api/canary/utils/serializers/output/member-signin-urls.js +0 -7
- package/core/server/api/canary/utils/serializers/output/snippets.js +0 -107
- package/core/server/api/canary/utils/serializers/output/webhooks.js +0 -15
|
@@ -1202,6 +1202,220 @@ ol .occluded-content {
|
|
|
1202
1202
|
height: 0;
|
|
1203
1203
|
}
|
|
1204
1204
|
|
|
1205
|
+
:root {
|
|
1206
|
+
/* The named -duration and -delay variables will be lowered to near zero when using the setupPromiseModals test helper */
|
|
1207
|
+
--epm-animation-backdrop-in-duration: 0.3s;
|
|
1208
|
+
--epm-animation-backdrop-out-duration: 0.18s;
|
|
1209
|
+
--epm-animation-modal-in-duration: 0.3s;
|
|
1210
|
+
--epm-animation-modal-out-duration: 0.18s;
|
|
1211
|
+
--epm-animation-backdrop-in-delay: 0s;
|
|
1212
|
+
--epm-animation-backdrop-out-delay: 0s;
|
|
1213
|
+
--epm-animation-modal-in-delay: 0s;
|
|
1214
|
+
--epm-animation-modal-out-delay: 0s;
|
|
1215
|
+
--epm-animation-backdrop-in: var(--epm-animation-backdrop-in-duration) ease var(--epm-animation-backdrop-in-delay) forwards epm-backdrop-in;
|
|
1216
|
+
--epm-animation-backdrop-out: var(--epm-animation-backdrop-out-duration) ease var(--epm-animation-backdrop-out-delay) forwards epm-backdrop-out;
|
|
1217
|
+
--epm-animation-modal-in: var(--epm-animation-modal-in-duration) ease-out var(--epm-animation-modal-in-delay) forwards epm-modal-in;
|
|
1218
|
+
--epm-animation-modal-out: var(--epm-animation-modal-out-duration) ease-out var(--epm-animation-modal-out-delay) forwards epm-modal-out;
|
|
1219
|
+
--epm-backdrop-background: #2d3748CD;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1223
|
+
:root {
|
|
1224
|
+
--epm-animation-backdrop-in-duration: 0s;
|
|
1225
|
+
--epm-animation-backdrop-out-duration: 0s;
|
|
1226
|
+
--epm-animation-modal-in-duration: 0s;
|
|
1227
|
+
--epm-animation-modal-out-duration: 0s;
|
|
1228
|
+
--epm-animation-backdrop-in-delay: 0s;
|
|
1229
|
+
--epm-animation-backdrop-out-delay: 0s;
|
|
1230
|
+
--epm-animation-modal-in-delay: 0s;
|
|
1231
|
+
--epm-animation-modal-out-delay: 0s;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.epm-scrolling-disabled {
|
|
1236
|
+
overflow: hidden;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
.epm-backdrop,
|
|
1240
|
+
.epm-modal-container {
|
|
1241
|
+
position: fixed;
|
|
1242
|
+
top: 0;
|
|
1243
|
+
right: 0;
|
|
1244
|
+
bottom: 0;
|
|
1245
|
+
left: 0;
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
.epm-backdrop {
|
|
1249
|
+
background-color: #2d3748CD;
|
|
1250
|
+
background-color: var(--epm-backdrop-background);
|
|
1251
|
+
opacity: 0;
|
|
1252
|
+
-webkit-animation: 0.3s ease 0s forwards epm-backdrop-in;
|
|
1253
|
+
animation: 0.3s ease 0s forwards epm-backdrop-in;
|
|
1254
|
+
-webkit-animation: var(--epm-animation-backdrop-in);
|
|
1255
|
+
animation: var(--epm-animation-backdrop-in);
|
|
1256
|
+
-webkit-animation-delay: 0s;
|
|
1257
|
+
animation-delay: 0s;
|
|
1258
|
+
-webkit-animation-delay: var(--epm-animation-backdrop-in-delay);
|
|
1259
|
+
animation-delay: var(--epm-animation-backdrop-in-delay);
|
|
1260
|
+
-webkit-animation-duration: 0.3s;
|
|
1261
|
+
animation-duration: 0.3s;
|
|
1262
|
+
-webkit-animation-duration: var(--epm-animation-backdrop-in-duration);
|
|
1263
|
+
animation-duration: var(--epm-animation-backdrop-in-duration);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
.epm-modal-container {
|
|
1267
|
+
display: flex;
|
|
1268
|
+
align-items: center;
|
|
1269
|
+
justify-content: center;
|
|
1270
|
+
overflow: auto;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
.epm-animating .epm-modal-container {
|
|
1274
|
+
overflow: unset;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
.epm-modal {
|
|
1278
|
+
margin: auto;
|
|
1279
|
+
transform: translate(0, -30vh) scale(1.1);
|
|
1280
|
+
opacity: 0;
|
|
1281
|
+
-webkit-animation: 0.3s ease-out 0s forwards epm-modal-in;
|
|
1282
|
+
animation: 0.3s ease-out 0s forwards epm-modal-in;
|
|
1283
|
+
-webkit-animation: var(--epm-animation-modal-in);
|
|
1284
|
+
animation: var(--epm-animation-modal-in);
|
|
1285
|
+
-webkit-animation-delay: 0s;
|
|
1286
|
+
animation-delay: 0s;
|
|
1287
|
+
-webkit-animation-delay: var(--epm-animation-modal-in-delay);
|
|
1288
|
+
animation-delay: var(--epm-animation-modal-in-delay);
|
|
1289
|
+
-webkit-animation-duration: 0.3s;
|
|
1290
|
+
animation-duration: 0.3s;
|
|
1291
|
+
-webkit-animation-duration: var(--epm-animation-modal-in-duration);
|
|
1292
|
+
animation-duration: var(--epm-animation-modal-in-duration);
|
|
1293
|
+
-webkit-overflow-scrolling: touch; /* momentum-based scrolling for Safari on iOS */
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
.epm-backdrop.epm-out {
|
|
1297
|
+
opacity: 1;
|
|
1298
|
+
-webkit-animation: 0.18s ease 0s forwards epm-backdrop-out;
|
|
1299
|
+
animation: 0.18s ease 0s forwards epm-backdrop-out;
|
|
1300
|
+
-webkit-animation: var(--epm-animation-backdrop-out);
|
|
1301
|
+
animation: var(--epm-animation-backdrop-out);
|
|
1302
|
+
-webkit-animation-delay: 0s;
|
|
1303
|
+
animation-delay: 0s;
|
|
1304
|
+
-webkit-animation-delay: var(--epm-animation-backdrop-out-delay);
|
|
1305
|
+
animation-delay: var(--epm-animation-backdrop-out-delay);
|
|
1306
|
+
-webkit-animation-duration: 0.18s;
|
|
1307
|
+
animation-duration: 0.18s;
|
|
1308
|
+
-webkit-animation-duration: var(--epm-animation-backdrop-out-duration);
|
|
1309
|
+
animation-duration: var(--epm-animation-backdrop-out-duration);
|
|
1310
|
+
pointer-events: none;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
.epm-modal.epm-out {
|
|
1314
|
+
transform: translate(0, 0) scale(1);
|
|
1315
|
+
opacity: 1;
|
|
1316
|
+
-webkit-animation: 0.18s ease-out 0s forwards epm-modal-out;
|
|
1317
|
+
animation: 0.18s ease-out 0s forwards epm-modal-out;
|
|
1318
|
+
-webkit-animation: var(--epm-animation-modal-out);
|
|
1319
|
+
animation: var(--epm-animation-modal-out);
|
|
1320
|
+
-webkit-animation-delay: 0s;
|
|
1321
|
+
animation-delay: 0s;
|
|
1322
|
+
-webkit-animation-delay: var(--epm-animation-modal-out-delay);
|
|
1323
|
+
animation-delay: var(--epm-animation-modal-out-delay);
|
|
1324
|
+
-webkit-animation-duration: 0.18s;
|
|
1325
|
+
animation-duration: 0.18s;
|
|
1326
|
+
-webkit-animation-duration: var(--epm-animation-modal-out-duration);
|
|
1327
|
+
animation-duration: var(--epm-animation-modal-out-duration);
|
|
1328
|
+
pointer-events: none;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
@-webkit-keyframes epm-backdrop-in {
|
|
1332
|
+
0% {
|
|
1333
|
+
opacity: 0;
|
|
1334
|
+
}
|
|
1335
|
+
100% {
|
|
1336
|
+
opacity: 1;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
@keyframes epm-backdrop-in {
|
|
1341
|
+
0% {
|
|
1342
|
+
opacity: 0;
|
|
1343
|
+
}
|
|
1344
|
+
100% {
|
|
1345
|
+
opacity: 1;
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
@-webkit-keyframes epm-backdrop-out {
|
|
1350
|
+
0% {
|
|
1351
|
+
opacity: 1;
|
|
1352
|
+
}
|
|
1353
|
+
100% {
|
|
1354
|
+
opacity: 0;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
@keyframes epm-backdrop-out {
|
|
1359
|
+
0% {
|
|
1360
|
+
opacity: 1;
|
|
1361
|
+
}
|
|
1362
|
+
100% {
|
|
1363
|
+
opacity: 0;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
@-webkit-keyframes epm-modal-in {
|
|
1368
|
+
0% {
|
|
1369
|
+
transform: translate(0, -30vh) scale(1.1);
|
|
1370
|
+
opacity: 0;
|
|
1371
|
+
}
|
|
1372
|
+
72% {
|
|
1373
|
+
transform: translate(0, 0) scale(0.99);
|
|
1374
|
+
opacity: 1;
|
|
1375
|
+
}
|
|
1376
|
+
100% {
|
|
1377
|
+
transform: translate(0, 0) scale(1);
|
|
1378
|
+
opacity: 1;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
@keyframes epm-modal-in {
|
|
1383
|
+
0% {
|
|
1384
|
+
transform: translate(0, -30vh) scale(1.1);
|
|
1385
|
+
opacity: 0;
|
|
1386
|
+
}
|
|
1387
|
+
72% {
|
|
1388
|
+
transform: translate(0, 0) scale(0.99);
|
|
1389
|
+
opacity: 1;
|
|
1390
|
+
}
|
|
1391
|
+
100% {
|
|
1392
|
+
transform: translate(0, 0) scale(1);
|
|
1393
|
+
opacity: 1;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
@-webkit-keyframes epm-modal-out {
|
|
1398
|
+
0% {
|
|
1399
|
+
transform: translate(0, 0) scale(1);
|
|
1400
|
+
opacity: 1;
|
|
1401
|
+
}
|
|
1402
|
+
100% {
|
|
1403
|
+
transform: translate(0, -10vh) scale(0.8);
|
|
1404
|
+
opacity: 0;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
@keyframes epm-modal-out {
|
|
1409
|
+
0% {
|
|
1410
|
+
transform: translate(0, 0) scale(1);
|
|
1411
|
+
opacity: 1;
|
|
1412
|
+
}
|
|
1413
|
+
100% {
|
|
1414
|
+
transform: translate(0, -10vh) scale(0.8);
|
|
1415
|
+
opacity: 0;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1205
1419
|
.ember-tooltip-base {
|
|
1206
1420
|
display: none;
|
|
1207
1421
|
height: 0;
|
|
@@ -58,6 +58,7 @@ module.exports = function price(planOrAmount, options) {
|
|
|
58
58
|
}
|
|
59
59
|
options = options || {};
|
|
60
60
|
options.hash = options.hash || {};
|
|
61
|
+
// NOTE: potentially breaking place once site.lang is removed in favor of site.locale
|
|
61
62
|
const {currency, numberFormat = 'short', currencyFormat = 'symbol', locale = _.get(options, 'data.site.lang', 'en')} = options.hash;
|
|
62
63
|
if (plan) {
|
|
63
64
|
return formatter({
|
|
File without changes
|
|
@@ -158,7 +158,7 @@ module.exports = {
|
|
|
158
158
|
},
|
|
159
159
|
|
|
160
160
|
get emails() {
|
|
161
|
-
return shared.pipeline(require('./
|
|
161
|
+
return shared.pipeline(require('./emails'), localUtils);
|
|
162
162
|
},
|
|
163
163
|
|
|
164
164
|
get site() {
|
|
@@ -169,6 +169,10 @@ module.exports = {
|
|
|
169
169
|
return shared.pipeline(require('./snippets'), localUtils);
|
|
170
170
|
},
|
|
171
171
|
|
|
172
|
+
get stats() {
|
|
173
|
+
return shared.pipeline(require('./stats'), localUtils);
|
|
174
|
+
},
|
|
175
|
+
|
|
172
176
|
get customThemeSettings() {
|
|
173
177
|
return shared.pipeline(require('./custom-theme-settings'), localUtils);
|
|
174
178
|
},
|
|
@@ -177,6 +181,10 @@ module.exports = {
|
|
|
177
181
|
return require('./utils/serializers');
|
|
178
182
|
},
|
|
179
183
|
|
|
184
|
+
get newsletters() {
|
|
185
|
+
return shared.pipeline(require('./newsletters'), localUtils);
|
|
186
|
+
},
|
|
187
|
+
|
|
180
188
|
/**
|
|
181
189
|
* Content API Controllers
|
|
182
190
|
*
|
|
@@ -452,51 +452,6 @@ module.exports = {
|
|
|
452
452
|
};
|
|
453
453
|
}
|
|
454
454
|
},
|
|
455
|
-
subscriberStats: {
|
|
456
|
-
permissions: {
|
|
457
|
-
method: 'browse'
|
|
458
|
-
},
|
|
459
|
-
async query() {
|
|
460
|
-
const statsData = await membersService.api.events.getSubscriptions();
|
|
461
|
-
const totalSubscriptions = (_.last(statsData) && _.last(statsData).subscribed) || 0;
|
|
462
|
-
statsData.forEach((d) => {
|
|
463
|
-
d.date = moment(d.date).format('YYYY-MM-DD');
|
|
464
|
-
});
|
|
465
|
-
return {
|
|
466
|
-
resource: 'subscribers',
|
|
467
|
-
total: totalSubscriptions,
|
|
468
|
-
data: statsData.map((d) => {
|
|
469
|
-
return Object.assign({}, {
|
|
470
|
-
date: moment(d.date).format('YYYY-MM-DD'),
|
|
471
|
-
value: d.subscribed
|
|
472
|
-
});
|
|
473
|
-
})
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
},
|
|
477
|
-
grossVolumeStats: {
|
|
478
|
-
permissions: {
|
|
479
|
-
method: 'browse'
|
|
480
|
-
},
|
|
481
|
-
async query() {
|
|
482
|
-
const volumeData = await membersService.api.events.getVolume();
|
|
483
|
-
const volumeStats = Object.keys(volumeData).map((curr) => {
|
|
484
|
-
return {
|
|
485
|
-
currency: curr,
|
|
486
|
-
data: volumeData[curr].map((d) => {
|
|
487
|
-
return Object.assign({}, {
|
|
488
|
-
date: moment(d.date).format('YYYY-MM-DD'),
|
|
489
|
-
value: d.volume
|
|
490
|
-
});
|
|
491
|
-
})
|
|
492
|
-
};
|
|
493
|
-
});
|
|
494
|
-
return {
|
|
495
|
-
resource: 'gross-volume',
|
|
496
|
-
data: volumeStats
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
},
|
|
500
455
|
|
|
501
456
|
activityFeed: {
|
|
502
457
|
options: [
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const models = require('../../models');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
docName: 'newsletters',
|
|
5
|
+
|
|
6
|
+
browse: {
|
|
7
|
+
options: [
|
|
8
|
+
'filter',
|
|
9
|
+
'fields',
|
|
10
|
+
'limit',
|
|
11
|
+
'order',
|
|
12
|
+
'page'
|
|
13
|
+
],
|
|
14
|
+
permissions: true,
|
|
15
|
+
query(frame) {
|
|
16
|
+
return models.Newsletter.findPage(frame.options);
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
add: {
|
|
21
|
+
statusCode: 201,
|
|
22
|
+
permissions: true,
|
|
23
|
+
async query(frame) {
|
|
24
|
+
return models.Newsletter.add(frame.data.newsletters[0], frame.options);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
edit: {
|
|
29
|
+
headers: {},
|
|
30
|
+
options: [
|
|
31
|
+
'id'
|
|
32
|
+
],
|
|
33
|
+
validation: {
|
|
34
|
+
options: {
|
|
35
|
+
id: {
|
|
36
|
+
required: true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
permissions: true,
|
|
41
|
+
async query(frame) {
|
|
42
|
+
return models.Newsletter.edit(frame.data.newsletters[0], frame.options);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const statsService = require('../../services/stats');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
docName: 'stats',
|
|
5
|
+
memberCountHistory: {
|
|
6
|
+
permissions: {
|
|
7
|
+
docName: 'members',
|
|
8
|
+
method: 'browse'
|
|
9
|
+
},
|
|
10
|
+
async query() {
|
|
11
|
+
return await statsService.members.getCountHistory();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -41,10 +41,6 @@ module.exports = {
|
|
|
41
41
|
return require('./schedules');
|
|
42
42
|
},
|
|
43
43
|
|
|
44
|
-
get webhooks() {
|
|
45
|
-
return require('./webhooks');
|
|
46
|
-
},
|
|
47
|
-
|
|
48
44
|
get posts() {
|
|
49
45
|
return require('./posts');
|
|
50
46
|
},
|
|
@@ -73,14 +69,6 @@ module.exports = {
|
|
|
73
69
|
return require('./tiers');
|
|
74
70
|
},
|
|
75
71
|
|
|
76
|
-
get member_signin_urls() {
|
|
77
|
-
return require('./member-signin-urls');
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
get identities() {
|
|
81
|
-
return require('./identities');
|
|
82
|
-
},
|
|
83
|
-
|
|
84
72
|
get images() {
|
|
85
73
|
return require('./images');
|
|
86
74
|
},
|
|
@@ -121,16 +109,8 @@ module.exports = {
|
|
|
121
109
|
return require('./site');
|
|
122
110
|
},
|
|
123
111
|
|
|
124
|
-
get
|
|
125
|
-
return require('./email-
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
get emails() {
|
|
129
|
-
return require('./emails');
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
get snippets() {
|
|
133
|
-
return require('./snippets');
|
|
112
|
+
get email_previews() {
|
|
113
|
+
return require('./email-previews');
|
|
134
114
|
},
|
|
135
115
|
|
|
136
116
|
get custom_theme_settings() {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('bookshelf').Model} snippet
|
|
3
|
+
* @param {Frame} frame
|
|
4
|
+
*
|
|
5
|
+
* @returns {SerializedSnippet}
|
|
6
|
+
*/
|
|
7
|
+
module.exports = (snippet, frame) => {
|
|
8
|
+
const json = snippet.toJSON(frame.options);
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
id: json.id,
|
|
12
|
+
name: json.name,
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
mobiledoc: json.mobiledoc,
|
|
15
|
+
created_at: json.created_at,
|
|
16
|
+
updated_at: json.updated_at,
|
|
17
|
+
created_by: json.created_by,
|
|
18
|
+
updated_by: json.updated_by
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} SerializedSnippet
|
|
24
|
+
* @prop {string} id
|
|
25
|
+
* @prop {string=} name
|
|
26
|
+
* @prop {string=} mobiledoc
|
|
27
|
+
* @prop {string} created_at
|
|
28
|
+
* @prop {string} updated_at
|
|
29
|
+
* @prop {string} created_by
|
|
30
|
+
* @prop {string} updated_by
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {Object<string, any>} Frame
|
|
35
|
+
* @prop {Object} options
|
|
36
|
+
*/
|
|
@@ -20,8 +20,6 @@ module.exports = {
|
|
|
20
20
|
importCSV: createSerializer('importCSV', passthrough),
|
|
21
21
|
memberStats: createSerializer('memberStats', passthrough),
|
|
22
22
|
mrrStats: createSerializer('mrrStats', passthrough),
|
|
23
|
-
subscriberStats: createSerializer('subscriberStats', passthrough),
|
|
24
|
-
grossVolumeStats: createSerializer('grossVolumeStats', passthrough),
|
|
25
23
|
activityFeed: createSerializer('activityFeed', passthrough)
|
|
26
24
|
};
|
|
27
25
|
|
|
@@ -1,34 +1,11 @@
|
|
|
1
1
|
const debug = require('@tryghost/debug')('api:canary:utils:serializers:output:users');
|
|
2
2
|
const tpl = require('@tryghost/tpl');
|
|
3
|
-
const mappers = require('./mappers');
|
|
4
3
|
|
|
5
4
|
const messages = {
|
|
6
5
|
pwdChangedSuccessfully: 'Password changed successfully.'
|
|
7
6
|
};
|
|
8
7
|
|
|
9
8
|
module.exports = {
|
|
10
|
-
browse(models, apiConfig, frame) {
|
|
11
|
-
debug('browse');
|
|
12
|
-
|
|
13
|
-
frame.response = {
|
|
14
|
-
users: models.data.map(model => mappers.users(model, frame)),
|
|
15
|
-
meta: models.meta
|
|
16
|
-
};
|
|
17
|
-
},
|
|
18
|
-
|
|
19
|
-
read(model, apiConfig, frame) {
|
|
20
|
-
debug('read');
|
|
21
|
-
|
|
22
|
-
frame.response = {
|
|
23
|
-
users: [mappers.users(model, frame)]
|
|
24
|
-
};
|
|
25
|
-
},
|
|
26
|
-
|
|
27
|
-
edit() {
|
|
28
|
-
debug('edit');
|
|
29
|
-
this.read(...arguments);
|
|
30
|
-
},
|
|
31
|
-
|
|
32
9
|
destroy(filename, apiConfig, frame) {
|
|
33
10
|
debug('destroy');
|
|
34
11
|
|
|
@@ -67,6 +67,19 @@ module.exports.input = (apiConfig, apiSerializers, frame) => {
|
|
|
67
67
|
return sequence(tasks);
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
const getBestMatchSerializer = function (apiSerializers, docName, method) {
|
|
71
|
+
if (apiSerializers[docName] && apiSerializers[docName][method]) {
|
|
72
|
+
debug(`Calling ${docName}.${method}`);
|
|
73
|
+
return apiSerializers[docName][method].bind(apiSerializers[docName]);
|
|
74
|
+
} else if (apiSerializers[docName] && apiSerializers[docName].all) {
|
|
75
|
+
debug(`Calling ${docName}.all`);
|
|
76
|
+
return apiSerializers[docName].all.bind(apiSerializers[docName]);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
debug(`Returning as-is`);
|
|
80
|
+
return false;
|
|
81
|
+
};
|
|
82
|
+
|
|
70
83
|
/**
|
|
71
84
|
* @description Shared output serialization handler.
|
|
72
85
|
*
|
|
@@ -101,33 +114,19 @@ module.exports.output = (response = {}, apiConfig, apiSerializers, frame) => {
|
|
|
101
114
|
});
|
|
102
115
|
}
|
|
103
116
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (apiSerializers[apiConfig.docName].all) {
|
|
107
|
-
tasks.push(function serialiseCustomAll() {
|
|
108
|
-
return apiSerializers[apiConfig.docName].all(response, apiConfig, frame);
|
|
109
|
-
});
|
|
110
|
-
}
|
|
117
|
+
const customSerializer = getBestMatchSerializer(apiSerializers, apiConfig.docName, apiConfig.method);
|
|
118
|
+
const defaultSerializer = getBestMatchSerializer(apiSerializers, 'default', apiConfig.method);
|
|
111
119
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return apiSerializers.default.all(response, apiConfig, frame);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (apiSerializers.default[apiConfig.method]) {
|
|
127
|
-
tasks.push(function serializeDefaultMethod() {
|
|
128
|
-
return apiSerializers.default[apiConfig.method](response, apiConfig, frame);
|
|
129
|
-
});
|
|
130
|
-
}
|
|
120
|
+
if (customSerializer) {
|
|
121
|
+
// CASE: custom serializer exists
|
|
122
|
+
tasks.push(function doCustomSerializer() {
|
|
123
|
+
return customSerializer(response, apiConfig, frame);
|
|
124
|
+
});
|
|
125
|
+
} else if (defaultSerializer) {
|
|
126
|
+
// CASE: Fall back to default serializer
|
|
127
|
+
tasks.push(function doDefaultSerializer() {
|
|
128
|
+
return defaultSerializer(response, apiConfig, frame);
|
|
129
|
+
});
|
|
131
130
|
}
|
|
132
131
|
|
|
133
132
|
if (apiSerializers.all && apiSerializers.all.after) {
|
|
@@ -178,7 +178,7 @@ function addPermissionToRole(config) {
|
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
logging.
|
|
181
|
+
logging.info(`Adding permission(${config.permission}) to role(${config.role})`);
|
|
182
182
|
await connection('permissions_roles').insert({
|
|
183
183
|
id: ObjectId().toHexString(),
|
|
184
184
|
permission_id: permission.id,
|