apostrophe 3.62.0 → 3.63.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/CHANGELOG.md +29 -0
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBar.vue +1 -1
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextBar.vue +6 -4
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaEditor.vue +9 -1
- package/modules/@apostrophecms/area/ui/apos/components/AposAreaWidget.vue +8 -0
- package/modules/@apostrophecms/area/ui/apos/components/AposWidgetControls.vue +6 -3
- package/modules/@apostrophecms/doc/index.js +254 -5
- package/modules/@apostrophecms/doc/ui/apos/mixins/AposFieldMetaUtilsMixin.js +93 -0
- package/modules/@apostrophecms/doc-type/index.js +70 -10
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +2 -0
- package/modules/@apostrophecms/doc-type/ui/apos/logic/AposDocContextMenu.js +12 -3
- package/modules/@apostrophecms/i18n/i18n/en.json +1 -0
- package/modules/@apostrophecms/login/index.js +25 -19
- package/modules/@apostrophecms/login/ui/apos/components/AposLoginForm.vue +11 -1
- package/modules/@apostrophecms/login/ui/apos/logic/AposLoginForm.js +46 -2
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalShareDraft.vue +8 -3
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +3 -0
- package/modules/@apostrophecms/page/index.js +87 -20
- package/modules/@apostrophecms/page-type/index.js +67 -2
- package/modules/@apostrophecms/piece-type/index.js +1 -34
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +8 -0
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposUtilityOperations.vue +16 -1
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +8 -0
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposTiptapImage.vue +7 -7
- package/modules/@apostrophecms/schema/index.js +9 -0
- package/modules/@apostrophecms/schema/lib/addFieldTypes.js +3 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposArrayEditor.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputArea.vue +3 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputArray.vue +4 -8
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputObject.vue +2 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputString.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +74 -29
- package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +1 -1
- package/modules/@apostrophecms/schema/ui/apos/logic/AposArrayEditor.js +7 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArea.js +13 -1
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArray.js +5 -1
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputObject.js +21 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputWrapper.js +35 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposSchema.js +6 -0
- package/modules/@apostrophecms/schema/ui/apos/mixins/AposInputMixin.js +41 -0
- package/modules/@apostrophecms/ui/ui/apos/mixins/AposPublishMixin.js +10 -4
- package/modules/@apostrophecms/widget-type/ui/apos/components/AposWidgetEditor.vue +7 -0
- package/modules/@apostrophecms/widget-type/ui/apos/mixins/AposWidgetMixin.js +6 -0
- package/package.json +2 -2
- package/test/areas.js +1 -1
- package/test/assets.js +2 -2
- package/test/attachments.js +2 -2
- package/test/base-module.js +2 -1
- package/test/base-url-env-var.js +2 -2
- package/test/change-doc-ids.js +33 -31
- package/test/command-menu.js +2 -2
- package/test/content-i18n.js +47 -46
- package/test/db.js +2 -2
- package/test/docs.js +301 -126
- package/test/draft-published.js +2 -2
- package/test/email.js +2 -1
- package/test/express.js +3 -2
- package/test/external-front.js +4 -4
- package/test/field-meta.js +363 -0
- package/test/global.js +2 -1
- package/test/http.js +4 -2
- package/test/images.js +87 -88
- package/test/job.js +34 -34
- package/test/locks.js +2 -2
- package/test/login-requirements.js +3 -2
- package/test/middleware-and-route-order.js +2 -2
- package/test/page-type.js +2 -1
- package/test/pages-autocomplete.js +0 -11
- package/test/pages-public-api.js +2 -2
- package/test/pages-rest.js +4 -4
- package/test/pages.js +389 -57
- package/test/parked-pages.js +47 -47
- package/test/pieces-page-type.js +2 -1
- package/test/pieces-public-api.js +38 -38
- package/test/pieces.js +4 -4
- package/test/published-pages.js +16 -16
- package/test/schemaBuilders.js +4 -4
- package/test/schemas.js +220 -221
- package/test/search.js +2 -2
- package/test/soft-redirects.js +2 -1
- package/test/templates.js +2 -2
- package/test/users.js +2 -1
package/test/job.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const t = require('../test-lib/test.js');
|
|
2
2
|
const assert = require('assert');
|
|
3
3
|
const Promise = require('bluebird');
|
|
4
|
-
let apos;
|
|
5
4
|
|
|
6
5
|
describe('Job module', function() {
|
|
7
6
|
|
|
7
|
+
let apos;
|
|
8
|
+
|
|
8
9
|
this.timeout(t.timeout);
|
|
9
10
|
|
|
10
11
|
after(async function() {
|
|
@@ -182,43 +183,42 @@ describe('Job module', function() {
|
|
|
182
183
|
// Tests failure()
|
|
183
184
|
assert(bad === (articleIds.length / 2));
|
|
184
185
|
});
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
186
|
+
function padInteger (i, places) {
|
|
187
|
+
let s = i + '';
|
|
188
|
+
while (s.length < places) {
|
|
189
|
+
s = '0' + s;
|
|
190
|
+
}
|
|
191
|
+
return s;
|
|
191
192
|
}
|
|
192
|
-
return s;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async function insert (req, pieceModule, title, data, i) {
|
|
196
|
-
const docData = Object.assign(pieceModule.newInstance(), {
|
|
197
|
-
title: `${title} #${padInteger(i, 5)}`,
|
|
198
|
-
slug: `${title}-${padInteger(i, 5)}`,
|
|
199
|
-
...data
|
|
200
|
-
});
|
|
201
193
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
total,
|
|
209
|
-
good,
|
|
210
|
-
bad
|
|
211
|
-
} = await apos.http.get(job.route, { jar });
|
|
194
|
+
async function insert (req, pieceModule, title, data, i) {
|
|
195
|
+
const docData = Object.assign(pieceModule.newInstance(), {
|
|
196
|
+
title: `${title} #${padInteger(i, 5)}`,
|
|
197
|
+
slug: `${title}-${padInteger(i, 5)}`,
|
|
198
|
+
...data
|
|
199
|
+
});
|
|
212
200
|
|
|
213
|
-
|
|
214
|
-
|
|
201
|
+
return pieceModule.insert(req, docData);
|
|
202
|
+
};
|
|
215
203
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
204
|
+
async function pollJob(job, { jar }) {
|
|
205
|
+
const {
|
|
206
|
+
processed,
|
|
207
|
+
total,
|
|
220
208
|
good,
|
|
221
209
|
bad
|
|
222
|
-
};
|
|
210
|
+
} = await apos.http.get(job.route, { jar });
|
|
211
|
+
|
|
212
|
+
if (processed < total) {
|
|
213
|
+
Promise.delay(100);
|
|
214
|
+
|
|
215
|
+
return await pollJob(job, { jar });
|
|
216
|
+
} else {
|
|
217
|
+
return {
|
|
218
|
+
completed: processed,
|
|
219
|
+
good,
|
|
220
|
+
bad
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
223
|
}
|
|
224
|
-
}
|
|
224
|
+
});
|
package/test/locks.js
CHANGED
package/test/page-type.js
CHANGED
|
@@ -145,17 +145,6 @@ describe('Pages Autocomplete', function() {
|
|
|
145
145
|
assert.equal(suggestions.results[0].slug, '/complex-page', 'complex page slug not found');
|
|
146
146
|
}
|
|
147
147
|
});
|
|
148
|
-
|
|
149
|
-
it('should ignore type when no autocomplete', async function () {
|
|
150
|
-
const result = await apos.http.get('/api/v1/@apostrophecms/page', {
|
|
151
|
-
jar,
|
|
152
|
-
qs: {
|
|
153
|
-
type: 'test-page'
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
assert.equal(result.slug, '/', 'home page not found');
|
|
157
|
-
assert.equal(result._children.length, 2, 'children result does not match');
|
|
158
|
-
});
|
|
159
148
|
});
|
|
160
149
|
|
|
161
150
|
async function login(apos) {
|
package/test/pages-public-api.js
CHANGED
package/test/pages-rest.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
const t = require('../test-lib/test.js');
|
|
2
2
|
const assert = require('assert');
|
|
3
3
|
|
|
4
|
-
let apos;
|
|
5
|
-
let homeId;
|
|
6
|
-
let jar;
|
|
7
|
-
|
|
8
4
|
const areaConfig = {
|
|
9
5
|
'@apostrophecms/image': {},
|
|
10
6
|
'@apostrophecms/video': {},
|
|
@@ -38,6 +34,10 @@ const areaConfig = {
|
|
|
38
34
|
|
|
39
35
|
describe('Pages REST', function() {
|
|
40
36
|
|
|
37
|
+
let apos;
|
|
38
|
+
let homeId;
|
|
39
|
+
let jar;
|
|
40
|
+
|
|
41
41
|
this.timeout(t.timeout);
|
|
42
42
|
|
|
43
43
|
after(function() {
|
package/test/pages.js
CHANGED
|
@@ -2,21 +2,15 @@ const t = require('../test-lib/test.js');
|
|
|
2
2
|
const assert = require('assert');
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
|
|
5
|
-
let apos;
|
|
6
|
-
let homeId;
|
|
7
|
-
const apiKey = 'this is a test api key';
|
|
8
|
-
|
|
9
5
|
describe('Pages', function() {
|
|
6
|
+
let apos;
|
|
7
|
+
let home;
|
|
8
|
+
let homeId;
|
|
9
|
+
const apiKey = 'this is a test api key';
|
|
10
10
|
|
|
11
11
|
this.timeout(t.timeout);
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
return t.destroy(apos);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
// EXISTENCE
|
|
18
|
-
|
|
19
|
-
it('should be a property of the apos object', async function() {
|
|
13
|
+
before(async function() {
|
|
20
14
|
apos = await t.create({
|
|
21
15
|
root: module,
|
|
22
16
|
modules: {
|
|
@@ -54,54 +48,9 @@ describe('Pages', function() {
|
|
|
54
48
|
}
|
|
55
49
|
});
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// SETUP
|
|
61
|
-
|
|
62
|
-
it('should make sure all of the expected indexes are configured', async function() {
|
|
63
|
-
const expectedIndexes = [ 'path' ];
|
|
64
|
-
const actualIndexes = [];
|
|
65
|
-
|
|
66
|
-
const info = await apos.doc.db.indexInformation();
|
|
67
|
-
|
|
68
|
-
// Extract the actual index info we care about
|
|
69
|
-
_.each(info, function(index) {
|
|
70
|
-
actualIndexes.push(index[0][0]);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Now make sure everything in expectedIndexes is in actualIndexes
|
|
74
|
-
_.each(expectedIndexes, function(index) {
|
|
75
|
-
assert(_.includes(actualIndexes, index));
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('parked homepage exists', async function() {
|
|
80
|
-
const home = await apos.page.find(apos.task.getAnonReq(), { level: 0 }).toObject();
|
|
81
|
-
|
|
82
|
-
assert(home);
|
|
51
|
+
home = await apos.page.find(apos.task.getAnonReq(), { level: 0 }).toObject();
|
|
83
52
|
homeId = home._id;
|
|
84
|
-
assert(home.slug === '/');
|
|
85
|
-
assert(`${home.path}:en:published` === home._id);
|
|
86
|
-
assert(home.type === '@apostrophecms/home-page');
|
|
87
|
-
assert(home.parked);
|
|
88
|
-
assert(home.visibility === 'public');
|
|
89
|
-
});
|
|
90
53
|
|
|
91
|
-
it('parked archive page exists', async function() {
|
|
92
|
-
const archive = await apos.page.find(apos.task.getReq(), { slug: '/archive' }).archived(null).toObject();
|
|
93
|
-
assert(archive);
|
|
94
|
-
assert(archive.slug === '/archive');
|
|
95
|
-
assert(archive.path === `${homeId.replace(':en:published', '')}/${archive._id.replace(':en:published', '')}`);
|
|
96
|
-
assert(archive.type === '@apostrophecms/archive-page');
|
|
97
|
-
assert(archive.parked);
|
|
98
|
-
// Verify that clonePermanent did its
|
|
99
|
-
// job and removed properties not meant
|
|
100
|
-
// to be stored in mongodb
|
|
101
|
-
assert(!archive._children);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('should be able to use db to insert documents', async function() {
|
|
105
54
|
const testItems = [
|
|
106
55
|
{
|
|
107
56
|
_id: 'parent:en:published',
|
|
@@ -172,9 +121,11 @@ describe('Pages', function() {
|
|
|
172
121
|
}
|
|
173
122
|
];
|
|
174
123
|
// Insert draft versions too to match the A3 data model
|
|
124
|
+
const lastPublishedAt = new Date();
|
|
175
125
|
const draftItems = await apos.doc.db.insertMany(testItems.map(item => ({
|
|
176
126
|
...item,
|
|
177
127
|
aposLocale: item.aposLocale.replace(':published', ':draft'),
|
|
128
|
+
lastPublishedAt,
|
|
178
129
|
_id: item._id.replace(':published', ':draft')
|
|
179
130
|
})));
|
|
180
131
|
assert(draftItems.result.ok === 1);
|
|
@@ -186,6 +137,57 @@ describe('Pages', function() {
|
|
|
186
137
|
assert(items.insertedCount === 6);
|
|
187
138
|
});
|
|
188
139
|
|
|
140
|
+
after(function() {
|
|
141
|
+
return t.destroy(apos);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// EXISTENCE
|
|
145
|
+
|
|
146
|
+
it('should be a property of the apos object', async function() {
|
|
147
|
+
assert(apos.page.__meta.name === '@apostrophecms/page');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// SETUP
|
|
151
|
+
|
|
152
|
+
it('should make sure all of the expected indexes are configured', async function() {
|
|
153
|
+
const expectedIndexes = [ 'path' ];
|
|
154
|
+
const actualIndexes = [];
|
|
155
|
+
|
|
156
|
+
const info = await apos.doc.db.indexInformation();
|
|
157
|
+
|
|
158
|
+
// Extract the actual index info we care about
|
|
159
|
+
_.each(info, function(index) {
|
|
160
|
+
actualIndexes.push(index[0][0]);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Now make sure everything in expectedIndexes is in actualIndexes
|
|
164
|
+
_.each(expectedIndexes, function(index) {
|
|
165
|
+
assert(_.includes(actualIndexes, index));
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('parked homepage exists', async function() {
|
|
170
|
+
assert(home);
|
|
171
|
+
assert(home.slug === '/');
|
|
172
|
+
assert(`${home.path}:en:published` === home._id);
|
|
173
|
+
assert(home.type === '@apostrophecms/home-page');
|
|
174
|
+
assert(home.parked);
|
|
175
|
+
assert(home.visibility === 'public');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('parked archive page exists', async function() {
|
|
179
|
+
const archive = await apos.page.find(apos.task.getReq(), { slug: '/archive' }).archived(null).toObject();
|
|
180
|
+
assert(archive);
|
|
181
|
+
assert(archive.slug === '/archive');
|
|
182
|
+
assert(archive.path === `${homeId.replace(':en:published', '')}/${archive._id.replace(':en:published', '')}`);
|
|
183
|
+
assert(archive.type === '@apostrophecms/archive-page');
|
|
184
|
+
assert(archive.parked);
|
|
185
|
+
// Verify that clonePermanent did its
|
|
186
|
+
// job and removed properties not meant
|
|
187
|
+
// to be stored in mongodb
|
|
188
|
+
assert(!archive._children);
|
|
189
|
+
});
|
|
190
|
+
|
|
189
191
|
// FINDING
|
|
190
192
|
|
|
191
193
|
it('should have a find method on pages that returns a cursor', async function() {
|
|
@@ -278,6 +280,55 @@ describe('Pages', function() {
|
|
|
278
280
|
assert.strictEqual(page._ancestors[1]._children[1].path, `${homeId.replace(':en:published', '')}/parent/sibling`);
|
|
279
281
|
});
|
|
280
282
|
|
|
283
|
+
it('should return pages from a specific type when type is provided', async function () {
|
|
284
|
+
const result = await apos.http.get('/api/v1/@apostrophecms/page', {
|
|
285
|
+
qs: {
|
|
286
|
+
type: 'test-page'
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
const expected = {
|
|
291
|
+
results: [
|
|
292
|
+
{
|
|
293
|
+
type: 'test-page',
|
|
294
|
+
slug: '/parent'
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
type: 'test-page',
|
|
298
|
+
slug: '/parent/child'
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
type: 'test-page',
|
|
302
|
+
slug: '/parent/child/grandchild'
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
type: 'test-page',
|
|
306
|
+
slug: '/parent/sibling'
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
type: 'test-page',
|
|
310
|
+
slug: '/parent/sibling/cousin'
|
|
311
|
+
},
|
|
312
|
+
{
|
|
313
|
+
type: 'test-page',
|
|
314
|
+
slug: '/another-parent'
|
|
315
|
+
}
|
|
316
|
+
],
|
|
317
|
+
pages: 1,
|
|
318
|
+
currentPage: 1
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const mappedResult = result.results.map(({ type, slug }) => ({
|
|
322
|
+
type,
|
|
323
|
+
slug
|
|
324
|
+
}));
|
|
325
|
+
|
|
326
|
+
assert.deepEqual({
|
|
327
|
+
...result,
|
|
328
|
+
results: mappedResult
|
|
329
|
+
}, expected);
|
|
330
|
+
});
|
|
331
|
+
|
|
281
332
|
// INSERTING
|
|
282
333
|
|
|
283
334
|
it('is able to insert a new page', async function() {
|
|
@@ -1309,4 +1360,285 @@ describe('Pages', function() {
|
|
|
1309
1360
|
});
|
|
1310
1361
|
});
|
|
1311
1362
|
});
|
|
1363
|
+
|
|
1364
|
+
describe('publish, move and draft', function () {
|
|
1365
|
+
beforeEach(async function() {
|
|
1366
|
+
await t.destroy(apos);
|
|
1367
|
+
apos = await t.create({
|
|
1368
|
+
root: module,
|
|
1369
|
+
modules: {
|
|
1370
|
+
'@apostrophecms/page': {
|
|
1371
|
+
options: {
|
|
1372
|
+
park: [],
|
|
1373
|
+
types: [
|
|
1374
|
+
{
|
|
1375
|
+
name: '@apostrophecms/home-page',
|
|
1376
|
+
label: 'Home'
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
name: 'test-page',
|
|
1380
|
+
label: 'Test Page'
|
|
1381
|
+
}
|
|
1382
|
+
]
|
|
1383
|
+
}
|
|
1384
|
+
},
|
|
1385
|
+
'test-page': {
|
|
1386
|
+
extend: '@apostrophecms/page-type'
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
it('should publish and move published after draft doc', async function () {
|
|
1393
|
+
const req = apos.task.getReq({ mode: 'draft' });
|
|
1394
|
+
|
|
1395
|
+
const page1 = await apos.page.insert(req, '_home', 'lastChild', {
|
|
1396
|
+
title: 'Root First Page',
|
|
1397
|
+
type: 'test-page',
|
|
1398
|
+
slug: 'root-first-page'
|
|
1399
|
+
});
|
|
1400
|
+
const page2 = await apos.page.insert(req, '_home', 'lastChild', {
|
|
1401
|
+
title: 'Root Second Page',
|
|
1402
|
+
type: 'test-page',
|
|
1403
|
+
slug: 'root-second-page'
|
|
1404
|
+
});
|
|
1405
|
+
const page3 = await apos.page.insert(req, '_home', 'lastChild', {
|
|
1406
|
+
title: 'Root Third Page',
|
|
1407
|
+
type: 'test-page',
|
|
1408
|
+
slug: 'root-third-page'
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1411
|
+
// Publish and assert.
|
|
1412
|
+
// Obviously, should not throw an error.
|
|
1413
|
+
await apos.page.publish(req, page3);
|
|
1414
|
+
{
|
|
1415
|
+
const pages = await apos.doc.db.find({
|
|
1416
|
+
type: 'test-page'
|
|
1417
|
+
}).sort({ rank: 1 }).toArray();
|
|
1418
|
+
|
|
1419
|
+
const p1Idx = pages.findIndex(p => p._id === page1._id);
|
|
1420
|
+
assert(p1Idx !== -1);
|
|
1421
|
+
const p2Idx = pages.findIndex(p => p._id === page2._id);
|
|
1422
|
+
assert(p2Idx !== -1);
|
|
1423
|
+
const p3Idx = pages.findIndex(p => p._id === page3._id);
|
|
1424
|
+
assert(p3Idx !== -1);
|
|
1425
|
+
const p3IdxPublished = pages.findIndex(p => p._id === page3._id.replace(':draft', ':published'));
|
|
1426
|
+
assert(p3IdxPublished !== -1);
|
|
1427
|
+
|
|
1428
|
+
// first, second, third/third-published
|
|
1429
|
+
assert(p1Idx < p2Idx);
|
|
1430
|
+
assert(p2Idx < p3Idx);
|
|
1431
|
+
assert(p2Idx < p3IdxPublished);
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// Move and assert.
|
|
1435
|
+
await apos.page.move(req, page3._id, page1._id, 'after');
|
|
1436
|
+
{
|
|
1437
|
+
const pages = await apos.doc.db.find({
|
|
1438
|
+
type: 'test-page'
|
|
1439
|
+
}).sort({ rank: 1 }).toArray();
|
|
1440
|
+
|
|
1441
|
+
const p1Idx = pages.findIndex(p => p._id === page1._id);
|
|
1442
|
+
assert(p1Idx !== -1);
|
|
1443
|
+
const p2Idx = pages.findIndex(p => p._id === page2._id);
|
|
1444
|
+
assert(p2Idx !== -1);
|
|
1445
|
+
const p3Idx = pages.findIndex(p => p._id === page3._id);
|
|
1446
|
+
assert(p3Idx !== -1);
|
|
1447
|
+
const p3IdxPublished = pages.findIndex(p => p._id === page3._id.replace(':draft', ':published'));
|
|
1448
|
+
assert(p3IdxPublished !== -1);
|
|
1449
|
+
|
|
1450
|
+
// first, third/third-published, second
|
|
1451
|
+
assert(p1Idx < p3Idx);
|
|
1452
|
+
assert(p1Idx < p3IdxPublished);
|
|
1453
|
+
assert(p3Idx < p2Idx);
|
|
1454
|
+
assert(p3IdxPublished < p2Idx);
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
it('should publish and move published after draft doc (nested)', async function () {
|
|
1459
|
+
const req = apos.task.getReq({ mode: 'draft' });
|
|
1460
|
+
|
|
1461
|
+
const root = await apos.page.insert(req, '_home', 'lastChild', {
|
|
1462
|
+
title: 'Root Page',
|
|
1463
|
+
type: 'test-page'
|
|
1464
|
+
});
|
|
1465
|
+
await apos.page.publish(req, root);
|
|
1466
|
+
|
|
1467
|
+
const page1 = await apos.page.insert(req, root._id, 'lastChild', {
|
|
1468
|
+
title: 'First Page',
|
|
1469
|
+
type: 'test-page'
|
|
1470
|
+
});
|
|
1471
|
+
const page2 = await apos.page.insert(req, root._id, 'lastChild', {
|
|
1472
|
+
title: 'Second Page',
|
|
1473
|
+
type: 'test-page'
|
|
1474
|
+
});
|
|
1475
|
+
const page3 = await apos.page.insert(req, root._id, 'lastChild', {
|
|
1476
|
+
title: 'Third Page',
|
|
1477
|
+
type: 'test-page'
|
|
1478
|
+
});
|
|
1479
|
+
|
|
1480
|
+
// Publish and assert.
|
|
1481
|
+
// Obviously, should not throw an error.
|
|
1482
|
+
await apos.page.publish(req, page3);
|
|
1483
|
+
{
|
|
1484
|
+
const pages = await apos.doc.db.find({
|
|
1485
|
+
type: 'test-page',
|
|
1486
|
+
level: 2
|
|
1487
|
+
}).sort({
|
|
1488
|
+
level: 1,
|
|
1489
|
+
rank: 1
|
|
1490
|
+
}).toArray();
|
|
1491
|
+
|
|
1492
|
+
const p1Idx = pages.findIndex(p => p._id === page1._id);
|
|
1493
|
+
assert(p1Idx !== -1);
|
|
1494
|
+
assert.equal(pages[p1Idx].path, `${root.path}/${page1.aposDocId}`);
|
|
1495
|
+
const p2Idx = pages.findIndex(p => p._id === page2._id);
|
|
1496
|
+
assert(p2Idx !== -1);
|
|
1497
|
+
assert.equal(pages[p2Idx].path, `${root.path}/${page2.aposDocId}`);
|
|
1498
|
+
const p3Idx = pages.findIndex(p => p._id === page3._id);
|
|
1499
|
+
assert(p3Idx !== -1);
|
|
1500
|
+
assert.equal(pages[p3Idx].path, `${root.path}/${page3.aposDocId}`);
|
|
1501
|
+
const p3IdxPublished = pages.findIndex(p => p._id === page3._id.replace(':draft', ':published'));
|
|
1502
|
+
assert(p3IdxPublished !== -1);
|
|
1503
|
+
assert.equal(pages[p3IdxPublished].path, `${root.path}/${page3.aposDocId}`);
|
|
1504
|
+
|
|
1505
|
+
// first, second, third/third-published
|
|
1506
|
+
assert(p1Idx < p2Idx);
|
|
1507
|
+
assert(p2Idx < p3Idx);
|
|
1508
|
+
assert(p2Idx < p3IdxPublished);
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
// Move and assert.
|
|
1512
|
+
await apos.page.move(req, page3._id, page1._id, 'after');
|
|
1513
|
+
{
|
|
1514
|
+
const pages = await apos.doc.db.find({
|
|
1515
|
+
type: 'test-page',
|
|
1516
|
+
level: 2
|
|
1517
|
+
}).sort({
|
|
1518
|
+
level: 1,
|
|
1519
|
+
rank: 1
|
|
1520
|
+
}).toArray();
|
|
1521
|
+
|
|
1522
|
+
const p1Idx = pages.findIndex(p => p._id === page1._id);
|
|
1523
|
+
assert(p1Idx !== -1);
|
|
1524
|
+
const p2Idx = pages.findIndex(p => p._id === page2._id);
|
|
1525
|
+
assert(p2Idx !== -1);
|
|
1526
|
+
const p3Idx = pages.findIndex(p => p._id === page3._id);
|
|
1527
|
+
assert(p3Idx !== -1);
|
|
1528
|
+
const p3IdxPublished = pages.findIndex(p => p._id === page3._id.replace(':draft', ':published'));
|
|
1529
|
+
assert(p3IdxPublished !== -1);
|
|
1530
|
+
|
|
1531
|
+
// first, third/third-published, second
|
|
1532
|
+
assert(p1Idx < p3Idx);
|
|
1533
|
+
assert(p1Idx < p3IdxPublished);
|
|
1534
|
+
assert(p3Idx < p2Idx);
|
|
1535
|
+
assert(p3IdxPublished < p2Idx);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
// Publish the last draft and assert it's sorted right.
|
|
1539
|
+
await apos.page.publish(req, page2);
|
|
1540
|
+
{
|
|
1541
|
+
const pages = await apos.doc.db.find({
|
|
1542
|
+
type: 'test-page',
|
|
1543
|
+
level: 2
|
|
1544
|
+
}).sort({
|
|
1545
|
+
level: 1,
|
|
1546
|
+
rank: 1
|
|
1547
|
+
}).toArray();
|
|
1548
|
+
|
|
1549
|
+
const p1Idx = pages.findIndex(p => p._id === page1._id);
|
|
1550
|
+
assert(p1Idx !== -1);
|
|
1551
|
+
const p2Idx = pages.findIndex(p => p._id === page2._id);
|
|
1552
|
+
assert(p2Idx !== -1);
|
|
1553
|
+
const p2IdxPublished = pages.findIndex(p => p._id === page2._id.replace(':draft', ':published'));
|
|
1554
|
+
assert(p2IdxPublished !== -1);
|
|
1555
|
+
const p3Idx = pages.findIndex(p => p._id === page3._id);
|
|
1556
|
+
assert(p3Idx !== -1);
|
|
1557
|
+
const p3IdxPublished = pages.findIndex(p => p._id === page3._id.replace(':draft', ':published'));
|
|
1558
|
+
assert(p3IdxPublished !== -1);
|
|
1559
|
+
|
|
1560
|
+
// first, third/third-published, second
|
|
1561
|
+
assert(p1Idx < p3Idx);
|
|
1562
|
+
assert(p1Idx < p3IdxPublished);
|
|
1563
|
+
assert(p3Idx < p2Idx);
|
|
1564
|
+
assert(p3IdxPublished < p2IdxPublished);
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
|
|
1568
|
+
it('should not be able to move published inside draft doc', async function () {
|
|
1569
|
+
const req = apos.task.getReq({ mode: 'draft' });
|
|
1570
|
+
|
|
1571
|
+
const root = await apos.page.insert(req, '_home', 'lastChild', {
|
|
1572
|
+
title: 'Root Page',
|
|
1573
|
+
type: 'test-page'
|
|
1574
|
+
});
|
|
1575
|
+
|
|
1576
|
+
const page1 = await apos.page.insert(req, '_home', 'lastChild', {
|
|
1577
|
+
title: 'First Page',
|
|
1578
|
+
type: 'test-page'
|
|
1579
|
+
});
|
|
1580
|
+
await apos.page.publish(req, page1);
|
|
1581
|
+
|
|
1582
|
+
await assert.rejects(apos.page.move(req, page1._id, root._id, 'firstChild'), {
|
|
1583
|
+
name: 'forbidden',
|
|
1584
|
+
message: 'Publish the parent page first.'
|
|
1585
|
+
});
|
|
1586
|
+
});
|
|
1587
|
+
|
|
1588
|
+
it('should not be able to publish inside draft doc', async function () {
|
|
1589
|
+
const req = apos.task.getReq({ mode: 'draft' });
|
|
1590
|
+
|
|
1591
|
+
const root = await apos.page.insert(req, '_home', 'lastChild', {
|
|
1592
|
+
title: 'Root Page',
|
|
1593
|
+
type: 'test-page'
|
|
1594
|
+
});
|
|
1595
|
+
|
|
1596
|
+
const page1 = await apos.page.insert(req, root._id, 'lastChild', {
|
|
1597
|
+
title: 'First Page',
|
|
1598
|
+
type: 'test-page'
|
|
1599
|
+
});
|
|
1600
|
+
|
|
1601
|
+
await assert.rejects(
|
|
1602
|
+
apos.page.publish(req, page1),
|
|
1603
|
+
(error) => {
|
|
1604
|
+
assert.equal(error.name, 'invalid');
|
|
1605
|
+
assert.equal(error.data?.unpublishedAncestors?.length, 1);
|
|
1606
|
+
assert.equal(error.data.unpublishedAncestors[0].title, 'Root Page');
|
|
1607
|
+
return true;
|
|
1608
|
+
}
|
|
1609
|
+
);
|
|
1610
|
+
});
|
|
1611
|
+
|
|
1612
|
+
it('should not be able to insert publish inside draft doc', async function () {
|
|
1613
|
+
const req = apos.task.getReq({ mode: 'draft' });
|
|
1614
|
+
|
|
1615
|
+
const root = await apos.page.insert(req, '_home', 'lastChild', {
|
|
1616
|
+
title: 'Root Page',
|
|
1617
|
+
type: 'test-page'
|
|
1618
|
+
});
|
|
1619
|
+
|
|
1620
|
+
// Publish directly via insert and req.mode = 'published'.
|
|
1621
|
+
// This can really be done only programmatically, but it's a valid use case.
|
|
1622
|
+
await assert.rejects(
|
|
1623
|
+
apos.page.insert(req.clone({ mode: 'published' }), root._id, 'lastChild', {
|
|
1624
|
+
title: 'First Page',
|
|
1625
|
+
type: 'test-page'
|
|
1626
|
+
}),
|
|
1627
|
+
{
|
|
1628
|
+
name: 'forbidden',
|
|
1629
|
+
message: 'Publish the parent page first.'
|
|
1630
|
+
}
|
|
1631
|
+
);
|
|
1632
|
+
|
|
1633
|
+
// IMPORTANT - assert the published page is gone, the draft is still there.
|
|
1634
|
+
const pages = await apos.doc.db.find({
|
|
1635
|
+
type: 'test-page'
|
|
1636
|
+
}).sort({ rank: 1 }).toArray();
|
|
1637
|
+
const draftPage = pages.find(p => p.title === 'First Page' && p.aposMode === 'draft');
|
|
1638
|
+
const publishedPage = pages.find(p => p.title === 'First Page' && p.aposMode === 'published');
|
|
1639
|
+
assert(draftPage);
|
|
1640
|
+
assert(draftPage.level === 2);
|
|
1641
|
+
assert.equal(typeof publishedPage, 'undefined');
|
|
1642
|
+
});
|
|
1643
|
+
});
|
|
1312
1644
|
});
|