apostrophe 3.53.0 → 3.55.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 +58 -1
- package/defaults.js +1 -0
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextModeAndSettings.vue +5 -2
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposContextTitle.vue +28 -19
- package/modules/@apostrophecms/any-doc-type/index.js +2 -2
- package/modules/@apostrophecms/any-page-type/index.js +2 -2
- package/modules/@apostrophecms/doc/index.js +55 -29
- package/modules/@apostrophecms/doc-type/index.js +11 -6
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocContextMenu.vue +4 -440
- package/modules/@apostrophecms/doc-type/ui/apos/logic/AposDocContextMenu.js +445 -0
- package/modules/@apostrophecms/i18n/i18n/de.json +113 -105
- package/modules/@apostrophecms/i18n/i18n/es.json +10 -0
- package/modules/@apostrophecms/i18n/i18n/fr.json +8 -0
- package/modules/@apostrophecms/i18n/i18n/pt-BR.json +10 -0
- package/modules/@apostrophecms/i18n/i18n/sk.json +8 -0
- package/modules/@apostrophecms/image/ui/apos/components/AposMediaManager.vue +1 -0
- package/modules/@apostrophecms/log/index.js +429 -0
- package/modules/@apostrophecms/login/index.js +47 -4
- package/modules/@apostrophecms/modal/ui/apos/components/AposDocsManagerToolbar.vue +14 -1
- package/modules/@apostrophecms/modal/ui/apos/mixins/AposEditorMixin.js +1 -1
- package/modules/@apostrophecms/module/index.js +32 -6
- package/modules/@apostrophecms/module/lib/log.js +68 -0
- package/modules/@apostrophecms/page/index.js +71 -19
- package/modules/@apostrophecms/page/lib/legacy-migrations.js +0 -57
- package/modules/@apostrophecms/page/ui/apos/components/AposPagesManager.vue +8 -285
- package/modules/@apostrophecms/page/ui/apos/logic/AposPagesManager.js +291 -0
- package/modules/@apostrophecms/page-type/index.js +39 -26
- package/modules/@apostrophecms/piece-type/index.js +19 -11
- package/modules/@apostrophecms/piece-type/ui/apos/components/AposDocsManager.vue +1 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposArrayEditor.vue +2 -357
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputArea.vue +2 -86
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputArray.vue +2 -254
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputAttachment.vue +2 -77
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputBoolean.vue +2 -44
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputCheckboxes.vue +2 -64
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputColor.vue +2 -94
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputDateAndTime.vue +3 -47
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputObject.vue +2 -82
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputPassword.vue +2 -37
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputRadio.vue +2 -26
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputRange.vue +2 -57
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputRelationship.vue +2 -259
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputSelect.vue +2 -38
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputSlug.vue +2 -275
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputString.vue +2 -167
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +2 -115
- package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +3 -279
- package/modules/@apostrophecms/schema/ui/apos/components/AposSearchList.vue +2 -83
- package/modules/@apostrophecms/schema/ui/apos/lib/detectChange.js +10 -1
- package/modules/@apostrophecms/schema/ui/apos/logic/AposArrayEditor.js +361 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArea.js +89 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputArray.js +257 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputAttachment.js +81 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputBoolean.js +48 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputCheckboxes.js +68 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputColor.js +98 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputDateAndTime.js +49 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputObject.js +86 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputPassword.js +41 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRadio.js +29 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRange.js +60 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputRelationship.js +262 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSelect.js +41 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputSlug.js +278 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputString.js +170 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposInputWrapper.js +118 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposSchema.js +281 -0
- package/modules/@apostrophecms/schema/ui/apos/logic/AposSearchList.js +85 -0
- package/modules/@apostrophecms/template/index.js +1 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposTreeHeader.vue +2 -2
- package/modules/@apostrophecms/util/index.js +83 -13
- package/modules/@apostrophecms/util/lib/logger.js +19 -17
- package/package.json +1 -1
- package/test/docs.js +35 -2
- package/test/log.js +1765 -0
- package/test/pages.js +57 -0
- package/test-lib/util.js +1 -1
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// Pages manager (tree) modal business logic.
|
|
2
|
+
|
|
3
|
+
import AposModifiedMixin from 'Modules/@apostrophecms/ui/mixins/AposModifiedMixin';
|
|
4
|
+
import AposArchiveMixin from 'Modules/@apostrophecms/ui/mixins/AposArchiveMixin';
|
|
5
|
+
import AposPublishMixin from 'Modules/@apostrophecms/ui/mixins/AposPublishMixin';
|
|
6
|
+
import AposDocsManagerMixin from 'Modules/@apostrophecms/modal/mixins/AposDocsManagerMixin';
|
|
7
|
+
import { klona } from 'klona';
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
name: 'AposPagesManager',
|
|
11
|
+
mixins: [ AposModifiedMixin, AposDocsManagerMixin, AposArchiveMixin, AposPublishMixin ],
|
|
12
|
+
emits: [ 'archive', 'search', 'safe-close', 'modal-result' ],
|
|
13
|
+
data() {
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
moduleName: '@apostrophecms/page',
|
|
17
|
+
modal: {
|
|
18
|
+
active: false,
|
|
19
|
+
triggerFocusRefresh: 0,
|
|
20
|
+
type: 'slide',
|
|
21
|
+
showModal: false,
|
|
22
|
+
width: 'two-thirds'
|
|
23
|
+
},
|
|
24
|
+
pages: [],
|
|
25
|
+
pagesFlat: [],
|
|
26
|
+
options: {
|
|
27
|
+
columns: [
|
|
28
|
+
{
|
|
29
|
+
columnHeader: 'apostrophe:pageTitle',
|
|
30
|
+
property: 'title',
|
|
31
|
+
cellValue: 'title'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'labels',
|
|
35
|
+
component: 'AposCellLabels'
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
columnHeader: 'apostrophe:lastEdited',
|
|
39
|
+
property: 'updatedAt',
|
|
40
|
+
component: 'AposCellLastEdited',
|
|
41
|
+
cellValue: 'updatedAt'
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
property: 'contextMenu',
|
|
45
|
+
component: 'AposCellContextMenu'
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
treeOptions: {
|
|
50
|
+
bulkSelect: !!this.relationshipField,
|
|
51
|
+
draggable: true,
|
|
52
|
+
ghostUnpublished: true
|
|
53
|
+
},
|
|
54
|
+
moreMenu: [
|
|
55
|
+
{
|
|
56
|
+
label: 'New Page',
|
|
57
|
+
action: 'new'
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
moreMenuButton: {
|
|
61
|
+
tooltip: {
|
|
62
|
+
content: 'More Options',
|
|
63
|
+
placement: 'bottom'
|
|
64
|
+
},
|
|
65
|
+
label: 'More Options',
|
|
66
|
+
icon: 'dots-vertical-icon',
|
|
67
|
+
iconOnly: true,
|
|
68
|
+
type: 'subtle',
|
|
69
|
+
modifiers: [ 'small', 'no-motion' ]
|
|
70
|
+
},
|
|
71
|
+
pageSetMenuSelection: 'live'
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
computed: {
|
|
75
|
+
moduleOptions() {
|
|
76
|
+
return apos.page;
|
|
77
|
+
},
|
|
78
|
+
items() {
|
|
79
|
+
if (!this.pages || !this.headers.length) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
return klona(this.pages);
|
|
83
|
+
},
|
|
84
|
+
selectAllChoice() {
|
|
85
|
+
const checkLen = this.checked.length;
|
|
86
|
+
const rowLen = this.pagesFlat.length;
|
|
87
|
+
|
|
88
|
+
return checkLen > 0 && checkLen !== rowLen ? {
|
|
89
|
+
value: 'checked',
|
|
90
|
+
indeterminate: true
|
|
91
|
+
} : {
|
|
92
|
+
value: 'checked'
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
saveRelationshipLabel() {
|
|
96
|
+
if (this.relationshipField && (this.relationshipField.max === 1)) {
|
|
97
|
+
return 'Select Page';
|
|
98
|
+
} else {
|
|
99
|
+
return 'Select Pages';
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
headers() {
|
|
103
|
+
let headers = this.options.columns || [];
|
|
104
|
+
if (!this.pageSetMenuSelectionIsLive) {
|
|
105
|
+
headers = headers.filter(h => h.component !== 'AposCellLabels');
|
|
106
|
+
}
|
|
107
|
+
return headers;
|
|
108
|
+
},
|
|
109
|
+
pageSetMenu() {
|
|
110
|
+
return [ {
|
|
111
|
+
label: 'apostrophe:live',
|
|
112
|
+
action: 'live',
|
|
113
|
+
modifiers: this.pageSetMenuSelectionIsLive ? [ 'selected', 'disabled' ] : []
|
|
114
|
+
}, {
|
|
115
|
+
label: 'apostrophe:archived',
|
|
116
|
+
action: 'archive',
|
|
117
|
+
modifiers: !this.pageSetMenuSelectionIsLive ? [ 'selected', 'disabled' ] : []
|
|
118
|
+
} ];
|
|
119
|
+
},
|
|
120
|
+
pageSetMenuButton() {
|
|
121
|
+
const button = {
|
|
122
|
+
label: this.pageSetMenuSelectionIsLive ? 'apostrophe:live' : 'apostrophe:archived',
|
|
123
|
+
icon: 'chevron-down-icon',
|
|
124
|
+
modifiers: [ 'no-motion', 'outline', 'icon-right' ],
|
|
125
|
+
class: 'apos-pages-manager__page-set-menu-button'
|
|
126
|
+
};
|
|
127
|
+
return button;
|
|
128
|
+
},
|
|
129
|
+
pageSetMenuSelectionIsLive() {
|
|
130
|
+
return this.pageSetMenuSelection === 'live';
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
watch: {
|
|
134
|
+
async pageSetMenuSelection() {
|
|
135
|
+
await this.getPages();
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
async mounted() {
|
|
139
|
+
// Get the data. This will be more complex in actuality.
|
|
140
|
+
this.modal.active = true;
|
|
141
|
+
await this.getPages();
|
|
142
|
+
this.modal.triggerFocusRefresh++;
|
|
143
|
+
|
|
144
|
+
apos.bus.$on('content-changed', this.getPages);
|
|
145
|
+
apos.bus.$on('command-menu-manager-create-new', this.create);
|
|
146
|
+
apos.bus.$on('command-menu-manager-close', this.confirmAndCancel);
|
|
147
|
+
},
|
|
148
|
+
destroyed() {
|
|
149
|
+
apos.bus.$off('content-changed', this.getPages);
|
|
150
|
+
apos.bus.$off('command-menu-manager-create-new', this.create);
|
|
151
|
+
apos.bus.$off('command-menu-manager-close', this.confirmAndCancel);
|
|
152
|
+
},
|
|
153
|
+
methods: {
|
|
154
|
+
moreMenuHandler(action) {
|
|
155
|
+
if (action === 'new') {
|
|
156
|
+
this.create();
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
async getPages () {
|
|
160
|
+
const self = this;
|
|
161
|
+
if (this.gettingPages) {
|
|
162
|
+
// Avoid race conditions by trying again later if already in progress
|
|
163
|
+
setTimeout(this.getPages, 100);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Not reactive, so not in data()
|
|
167
|
+
this.gettingPages = true;
|
|
168
|
+
try {
|
|
169
|
+
this.pages = [];
|
|
170
|
+
this.pagesFlat = [];
|
|
171
|
+
|
|
172
|
+
let pageTree = (await apos.http.get(
|
|
173
|
+
'/api/v1/@apostrophecms/page', {
|
|
174
|
+
busy: true,
|
|
175
|
+
qs: {
|
|
176
|
+
all: '1',
|
|
177
|
+
archived: this.relationshipField || this.pageSetMenuSelectionIsLive ? '0' : 'any',
|
|
178
|
+
// Also fetch published docs as _publishedDoc subproperties
|
|
179
|
+
withPublished: 1
|
|
180
|
+
},
|
|
181
|
+
draft: true
|
|
182
|
+
}
|
|
183
|
+
));
|
|
184
|
+
|
|
185
|
+
// If editor is looking at the archive tree, trim the normal page tree response
|
|
186
|
+
if (this.pageSetMenuSelection === 'archive') {
|
|
187
|
+
pageTree = pageTree._children.find(page => page.slug === '/archive');
|
|
188
|
+
pageTree = pageTree._children;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
formatPage(pageTree);
|
|
192
|
+
|
|
193
|
+
if (!pageTree.length && pageTree.length !== 0) {
|
|
194
|
+
pageTree = [ pageTree ];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
this.pages = [ ...pageTree ];
|
|
198
|
+
|
|
199
|
+
} finally {
|
|
200
|
+
this.gettingPages = false;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function formatPage(page) {
|
|
204
|
+
if (page.length) {
|
|
205
|
+
page.forEach(formatPage);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
self.pagesFlat.push(klona(page));
|
|
210
|
+
|
|
211
|
+
if (Array.isArray(page._children)) {
|
|
212
|
+
page._children.forEach(formatPage);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
async update(page) {
|
|
217
|
+
const body = {
|
|
218
|
+
_targetId: page.endContext,
|
|
219
|
+
_position: page.endIndex
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const route = `${this.moduleOptions.action}/${page.changedId}`;
|
|
223
|
+
try {
|
|
224
|
+
await apos.http.patch(route, {
|
|
225
|
+
busy: true,
|
|
226
|
+
body,
|
|
227
|
+
draft: true
|
|
228
|
+
});
|
|
229
|
+
} catch (error) {
|
|
230
|
+
await apos.notify(error.body.message || this.$t('apostrophe:treeError'), {
|
|
231
|
+
type: 'danger',
|
|
232
|
+
icon: 'alert-circle-icon',
|
|
233
|
+
dismiss: true,
|
|
234
|
+
localize: false
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
await this.getPages();
|
|
239
|
+
if (this.pagesFlat.find(page => {
|
|
240
|
+
return (page.aposDocId === (window.apos.page.page && window.apos.page.page.aposDocId)) && page.archived;
|
|
241
|
+
})) {
|
|
242
|
+
// With the current page gone, we need to move to safe ground
|
|
243
|
+
location.assign(`${window.apos.prefix}/`);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
toggleRowCheck(id) {
|
|
247
|
+
if (this.checked.includes(id)) {
|
|
248
|
+
this.checked = this.checked.filter(item => item !== id);
|
|
249
|
+
} else {
|
|
250
|
+
this.checked.push(id);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
selectAll(event) {
|
|
254
|
+
if (!this.checked.length) {
|
|
255
|
+
this.pagesFlat.forEach((row) => {
|
|
256
|
+
this.toggleRowCheck(row._id);
|
|
257
|
+
});
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (this.checked.length <= this.pagesFlat.length) {
|
|
262
|
+
this.checked.forEach((id) => {
|
|
263
|
+
this.toggleRowCheck(id);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
async create() {
|
|
268
|
+
const doc = await apos.modal.execute(this.moduleOptions.components.editorModal, {
|
|
269
|
+
moduleName: this.moduleName
|
|
270
|
+
});
|
|
271
|
+
if (!doc) {
|
|
272
|
+
// Cancel clicked
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
await this.getPages();
|
|
276
|
+
if (this.relationshipField) {
|
|
277
|
+
doc._fields = doc._fields || {};
|
|
278
|
+
// Must push to checked docs or it will try to do it for us
|
|
279
|
+
// and not include _fields
|
|
280
|
+
this.checkedDocs.push(doc);
|
|
281
|
+
this.checked.push(doc._id);
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
setCheckedDocs(checkedDocs) {
|
|
285
|
+
this.checked = checkedDocs.map(doc => doc._id);
|
|
286
|
+
},
|
|
287
|
+
updateCheckedDocs() {
|
|
288
|
+
this.checkedDocs = this.checked.map(_id => this.pagesFlat.find(page => page._id === _id));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
@@ -121,10 +121,16 @@ module.exports = {
|
|
|
121
121
|
}, {
|
|
122
122
|
permission: false
|
|
123
123
|
});
|
|
124
|
-
if (published && doc.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
if (published && (doc.level > 0)) {
|
|
125
|
+
const { lastTargetId, lastPosition } = await self.apos.page.inferLastTargetIdAndPosition(doc);
|
|
126
|
+
return self.apos.page.move(
|
|
127
|
+
req.clone({
|
|
128
|
+
mode: 'published'
|
|
129
|
+
}),
|
|
130
|
+
published._id,
|
|
131
|
+
lastTargetId.replace(':draft', ':published'),
|
|
132
|
+
lastPosition
|
|
133
|
+
);
|
|
128
134
|
}
|
|
129
135
|
}
|
|
130
136
|
},
|
|
@@ -200,7 +206,13 @@ module.exports = {
|
|
|
200
206
|
// chance we need to "replay" such a move
|
|
201
207
|
return;
|
|
202
208
|
}
|
|
203
|
-
await self.apos.page.
|
|
209
|
+
const { lastTargetId, lastPosition } = await self.apos.page.inferLastTargetIdAndPosition(result.published);
|
|
210
|
+
await self.apos.page.move(
|
|
211
|
+
publishedReq,
|
|
212
|
+
result.published._id,
|
|
213
|
+
lastTargetId,
|
|
214
|
+
lastPosition
|
|
215
|
+
);
|
|
204
216
|
const published = await self.apos.page.findOneForEditing(publishedReq, {
|
|
205
217
|
_id: result.published._id
|
|
206
218
|
});
|
|
@@ -322,27 +334,37 @@ module.exports = {
|
|
|
322
334
|
...options,
|
|
323
335
|
setModified: false
|
|
324
336
|
};
|
|
325
|
-
if (doc.
|
|
337
|
+
if (doc.level > 0) {
|
|
338
|
+
const { lastTargetId, lastPosition } = await self.apos.page.inferLastTargetIdAndPosition(doc);
|
|
326
339
|
// Replay the high level positioning used to place it in the published locale
|
|
327
|
-
return self.apos.page.insert(
|
|
328
|
-
|
|
340
|
+
return self.apos.page.insert(
|
|
341
|
+
_req,
|
|
342
|
+
lastTargetId.replace(':published', ':draft'),
|
|
343
|
+
lastPosition,
|
|
344
|
+
draft,
|
|
345
|
+
options
|
|
346
|
+
);
|
|
347
|
+
} else {
|
|
329
348
|
// Insert the home page
|
|
330
349
|
return self.apos.doc.insert(_req, draft, options);
|
|
331
|
-
} else {
|
|
332
|
-
throw new Error('Page inserted without using the page APIs, has no aposLastTargetId and aposLastPosition, cannot insert equivalent draft');
|
|
333
350
|
}
|
|
334
351
|
},
|
|
335
|
-
// Called for you when a page is
|
|
336
|
-
//
|
|
337
|
-
// draft page. You don't need to invoke this.
|
|
352
|
+
// Called for you when a page is published for the first time.
|
|
353
|
+
// You don't need to invoke this.
|
|
338
354
|
async insertPublishedOf(req, doc, published, options = {}) {
|
|
339
355
|
const _req = req.clone({
|
|
340
356
|
mode: 'published'
|
|
341
357
|
});
|
|
342
|
-
if (doc.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
358
|
+
if (doc.level > 0) {
|
|
359
|
+
const { lastTargetId, lastPosition } = await self.apos.page.inferLastTargetIdAndPosition(doc);
|
|
360
|
+
// Replay the high level positioning used to place it in the draft locale
|
|
361
|
+
return self.apos.page.insert(
|
|
362
|
+
_req,
|
|
363
|
+
lastTargetId.replace(':draft', ':published'),
|
|
364
|
+
lastPosition,
|
|
365
|
+
published,
|
|
366
|
+
options);
|
|
367
|
+
} else {
|
|
346
368
|
// Insert the home page
|
|
347
369
|
Object.assign(published, {
|
|
348
370
|
path: doc.path,
|
|
@@ -352,8 +374,6 @@ module.exports = {
|
|
|
352
374
|
parkedId: doc.parkedId
|
|
353
375
|
});
|
|
354
376
|
return self.apos.doc.insert(_req, published, options);
|
|
355
|
-
} else {
|
|
356
|
-
throw new Error('insertPublishedOf called on a page that was never inserted via the standard page APIs, has no aposLastTargetId and aposLastPosition, cannot insert equivalent published page');
|
|
357
377
|
}
|
|
358
378
|
},
|
|
359
379
|
// Update a page. The `options` argument may be omitted entirely.
|
|
@@ -399,13 +419,6 @@ module.exports = {
|
|
|
399
419
|
},
|
|
400
420
|
copyForPublication(_super, req, from, to) {
|
|
401
421
|
_super(req, from, to);
|
|
402
|
-
const newMode = to.aposLocale.endsWith(':published') ? ':published' : ':draft';
|
|
403
|
-
const oldMode = (newMode === ':published') ? ':draft' : ':published';
|
|
404
|
-
// Home pages will not have this
|
|
405
|
-
if (from.aposLastTargetId) {
|
|
406
|
-
to.aposLastTargetId = from.aposLastTargetId.replace(oldMode, newMode);
|
|
407
|
-
to.aposLastPosition = from.aposLastPosition;
|
|
408
|
-
}
|
|
409
422
|
to.parkedId = from.parkedId;
|
|
410
423
|
to.parked = from.parked;
|
|
411
424
|
},
|
|
@@ -232,7 +232,7 @@ module.exports = {
|
|
|
232
232
|
getAll: [
|
|
233
233
|
...enableCacheOnDemand ? [ expressCacheOnDemand ] : [],
|
|
234
234
|
async (req) => {
|
|
235
|
-
self.
|
|
235
|
+
await self.publicApiCheckAsync(req);
|
|
236
236
|
const query = self.getRestQuery(req);
|
|
237
237
|
if (!query.get('perPage')) {
|
|
238
238
|
query.perPage(
|
|
@@ -272,7 +272,7 @@ module.exports = {
|
|
|
272
272
|
...enableCacheOnDemand ? [ expressCacheOnDemand ] : [],
|
|
273
273
|
async (req, _id) => {
|
|
274
274
|
_id = self.inferIdLocaleAndMode(req, _id);
|
|
275
|
-
self.
|
|
275
|
+
await self.publicApiCheckAsync(req);
|
|
276
276
|
const doc = self.removeForbiddenFields(
|
|
277
277
|
req,
|
|
278
278
|
await self.getRestQuery(req).and({ _id }).toObject()
|
|
@@ -299,7 +299,7 @@ module.exports = {
|
|
|
299
299
|
}
|
|
300
300
|
],
|
|
301
301
|
async post(req) {
|
|
302
|
-
self.
|
|
302
|
+
await self.publicApiCheckAsync(req);
|
|
303
303
|
if (req.body._newInstance) {
|
|
304
304
|
const newInstance = self.newInstance();
|
|
305
305
|
newInstance._previewable = self.addUrlsViaModule && (await self.addUrlsViaModule.readyToAddUrlsToPieces(req, self.name));
|
|
@@ -310,12 +310,12 @@ module.exports = {
|
|
|
310
310
|
},
|
|
311
311
|
async put(req, _id) {
|
|
312
312
|
_id = self.inferIdLocaleAndMode(req, _id);
|
|
313
|
-
self.
|
|
313
|
+
await self.publicApiCheckAsync(req);
|
|
314
314
|
return self.convertUpdateAndRefresh(req, req.body, _id);
|
|
315
315
|
},
|
|
316
316
|
async delete(req, _id) {
|
|
317
317
|
_id = self.inferIdLocaleAndMode(req, _id);
|
|
318
|
-
self.
|
|
318
|
+
await self.publicApiCheckAsync(req);
|
|
319
319
|
const piece = await self.findOneForEditing(req, {
|
|
320
320
|
_id
|
|
321
321
|
});
|
|
@@ -323,7 +323,7 @@ module.exports = {
|
|
|
323
323
|
},
|
|
324
324
|
async patch(req, _id) {
|
|
325
325
|
_id = self.inferIdLocaleAndMode(req, _id);
|
|
326
|
-
self.
|
|
326
|
+
await self.publicApiCheckAsync(req);
|
|
327
327
|
return self.convertPatchAndRefresh(req, req.body, _id);
|
|
328
328
|
}
|
|
329
329
|
};
|
|
@@ -614,7 +614,7 @@ module.exports = {
|
|
|
614
614
|
|
|
615
615
|
// Return the operation group with the new operation added.
|
|
616
616
|
return {
|
|
617
|
-
|
|
617
|
+
action: groupName,
|
|
618
618
|
...groupProperties,
|
|
619
619
|
operations: [
|
|
620
620
|
...(acc[groupName] && acc[groupName].operations) || [],
|
|
@@ -1028,10 +1028,13 @@ module.exports = {
|
|
|
1028
1028
|
piece.title = 'Generated #' + (i + 1);
|
|
1029
1029
|
return piece;
|
|
1030
1030
|
},
|
|
1031
|
-
|
|
1031
|
+
// Can be extended on a project level with `_super(req, true)` to disable
|
|
1032
|
+
// permission check and public API projection. You shouldn't do this
|
|
1033
|
+
// if you're not sure what you're doing.
|
|
1034
|
+
getRestQuery(req, omitPermissionCheck = false) {
|
|
1032
1035
|
const query = self.find(req).attachments(true);
|
|
1033
1036
|
query.applyBuildersSafely(req.query);
|
|
1034
|
-
if (!self.canAccessApi(req)) {
|
|
1037
|
+
if (!omitPermissionCheck && !self.canAccessApi(req)) {
|
|
1035
1038
|
if (!self.options.publicApiProjection) {
|
|
1036
1039
|
// Shouldn't be needed thanks to publicApiCheck, but be sure
|
|
1037
1040
|
query.and({
|
|
@@ -1058,6 +1061,11 @@ module.exports = {
|
|
|
1058
1061
|
}
|
|
1059
1062
|
}
|
|
1060
1063
|
},
|
|
1064
|
+
// An async version of the above. It can be overridden to implement
|
|
1065
|
+
// an asynchronous check of the public API permissions.
|
|
1066
|
+
async publicApiCheckAsync(req) {
|
|
1067
|
+
return self.publicApiCheck(req);
|
|
1068
|
+
},
|
|
1061
1069
|
// If the piece does not yet have a slug, add one based on the
|
|
1062
1070
|
// title; throw an error if there is no title
|
|
1063
1071
|
ensureSlug(piece) {
|
|
@@ -1164,8 +1172,8 @@ module.exports = {
|
|
|
1164
1172
|
|
|
1165
1173
|
return browserOptions;
|
|
1166
1174
|
},
|
|
1167
|
-
find(_super, req, criteria,
|
|
1168
|
-
return _super(req, criteria,
|
|
1175
|
+
find(_super, req, criteria, options) {
|
|
1176
|
+
return _super(req, criteria, options).defaultSort(self.options.sort || { updatedAt: -1 });
|
|
1169
1177
|
},
|
|
1170
1178
|
newInstance(_super) {
|
|
1171
1179
|
if (!self.options.singletonAuto) {
|