@raketa-cloud/admin 0.0.34 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/handlers/article_revisions/LocksHandler.js +22 -4
- package/src/handlers/article_revisions/UnlocksHandler.js +3 -1
- package/src/handlers/event_revisions/LocksHandler.js +17 -4
- package/src/handlers/event_revisions/UnlocksHandler.js +1 -1
- package/src/handlers/page_revisions/LocksHandler.js +13 -3
- package/src/handlers/page_revisions/UnlocksHandler.js +1 -1
- package/src/handlers/page_revisions/VisualHandler.js +1 -0
- package/src/helpers/FormBuilder.js +88 -38
- package/src/helpers/Inflector.js +1 -1
- package/src/styles/application.css +11 -2
- package/src/tests/handlers/article_revisions/CodesHandler.test/update.test.js +5 -5
- package/src/tests/handlers/article_revisions/LocksHandler.test/create.test.js +142 -0
- package/src/tests/handlers/article_revisions/LocksHandler.test/create_form.test.js +55 -0
- package/src/tests/handlers/article_revisions/UnlocksHandler.test/create.test.js +84 -0
- package/src/tests/handlers/event_revisions/CodesHandler.test/update.test.js +5 -5
- package/src/tests/handlers/event_revisions/LocksHandler.test/create.test.js +142 -0
- package/src/tests/handlers/event_revisions/LocksHandler.test/create_form.test.js +55 -0
- package/src/tests/handlers/event_revisions/UnlocksHandler.test/create.test.js +84 -0
- package/src/tests/handlers/page_revisions/CodesHandler.test/edit_form.test.js +1 -1
- package/src/tests/handlers/page_revisions/CodesHandler.test/update.test.js +5 -5
- package/src/tests/handlers/page_revisions/LocksHandler.test/create.test.js +138 -0
- package/src/tests/handlers/page_revisions/LocksHandler.test/create_form.test.js +55 -0
- package/src/tests/handlers/page_revisions/UnlocksHandler.test/create.test.js +80 -0
- package/src/views/article_revisions/codes/edit_form.ejs +3 -3
- package/src/views/article_revisions/tags/edit_form.ejs +1 -1
- package/src/views/articles/_form.ejs +1 -1
- package/src/views/articles/create_form.ejs +1 -1
- package/src/views/articles/deletes/create_form.ejs +1 -1
- package/src/views/articles/translations/_form.ejs +1 -1
- package/src/views/articles/translations/create_form.ejs +1 -1
- package/src/views/event_revisions/codes/edit_form.ejs +3 -3
- package/src/views/event_revisions/tags/edit_form.ejs +1 -1
- package/src/views/events/_form.ejs +1 -1
- package/src/views/events/create_form.ejs +1 -1
- package/src/views/events/deletes/create_form.ejs +1 -1
- package/src/views/events/translations/_form.ejs +1 -1
- package/src/views/events/translations/create_form.ejs +1 -1
- package/src/views/page_revisions/codes/edit_form.ejs +3 -3
- package/src/views/pages/_form.ejs +1 -1
- package/src/views/pages/create_form.ejs +1 -1
- package/src/views/pages/deletes/create_form.ejs +1 -1
- package/src/views/pages/translations/_form.ejs +1 -1
- package/src/views/pages/translations/create_form.ejs +1 -1
package/package.json
CHANGED
|
@@ -6,6 +6,10 @@ const create_form = async (ctx) => {
|
|
|
6
6
|
ctx.locale
|
|
7
7
|
);
|
|
8
8
|
|
|
9
|
+
if (!revision) {
|
|
10
|
+
throw new Error(`Missing revision #${parent_id}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
9
13
|
const resource = {
|
|
10
14
|
id: revision.id,
|
|
11
15
|
originalId: revision.originalId,
|
|
@@ -25,8 +29,20 @@ const create = async (ctx) => {
|
|
|
25
29
|
const { parent_id } = ctx.params;
|
|
26
30
|
const { message } = ctx.resourceParams.resource;
|
|
27
31
|
|
|
28
|
-
const
|
|
29
|
-
|
|
32
|
+
const revision = await ctx.client.articleRevisions.find(
|
|
33
|
+
parent_id,
|
|
34
|
+
ctx.locale
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (!revision) {
|
|
38
|
+
throw new Error(`Missing revision #${parent_id}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { errors, articleErrors } = await ctx.client.articleRevisions.lock(
|
|
42
|
+
parent_id,
|
|
43
|
+
ctx.locale,
|
|
44
|
+
message
|
|
45
|
+
);
|
|
30
46
|
|
|
31
47
|
if (errors) {
|
|
32
48
|
return {
|
|
@@ -37,7 +53,7 @@ const create = async (ctx) => {
|
|
|
37
53
|
message,
|
|
38
54
|
},
|
|
39
55
|
errors: {
|
|
40
|
-
resource: ctx.client.
|
|
56
|
+
resource: ctx.client.articleRevisions.formatErrors(errors, "message"),
|
|
41
57
|
},
|
|
42
58
|
_translations: [],
|
|
43
59
|
},
|
|
@@ -45,7 +61,9 @@ const create = async (ctx) => {
|
|
|
45
61
|
}
|
|
46
62
|
|
|
47
63
|
if (articleErrors) {
|
|
48
|
-
throw
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Failed to lock revision: ${JSON.stringify(articleErrors)}`
|
|
66
|
+
);
|
|
49
67
|
}
|
|
50
68
|
|
|
51
69
|
return {
|
|
@@ -3,6 +3,10 @@ const create_form = async (ctx) => {
|
|
|
3
3
|
|
|
4
4
|
const revision = await ctx.client.eventRevisions.find(parent_id, ctx.locale);
|
|
5
5
|
|
|
6
|
+
if (!revision) {
|
|
7
|
+
throw new Error(`Missing revision #${parent_id}`);
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
const resource = {
|
|
7
11
|
id: revision.id,
|
|
8
12
|
originalId: revision.originalId,
|
|
@@ -22,15 +26,24 @@ const create = async (ctx) => {
|
|
|
22
26
|
const { parent_id } = ctx.params;
|
|
23
27
|
const { message } = ctx.resourceParams.resource;
|
|
24
28
|
|
|
25
|
-
const
|
|
26
|
-
|
|
29
|
+
const revision = await ctx.client.eventRevisions.find(parent_id, ctx.locale);
|
|
30
|
+
|
|
31
|
+
if (!revision) {
|
|
32
|
+
throw new Error(`Missing revision #${parent_id}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { errors, eventErrors } = await ctx.client.eventRevisions.lock(
|
|
36
|
+
parent_id,
|
|
37
|
+
ctx.locale,
|
|
38
|
+
message
|
|
39
|
+
);
|
|
27
40
|
|
|
28
41
|
if (errors) {
|
|
29
42
|
return {
|
|
30
43
|
assigns: {
|
|
31
44
|
resource: { id: revision.id, originalId: revision.originalId, message },
|
|
32
45
|
errors: {
|
|
33
|
-
resource: ctx.client.
|
|
46
|
+
resource: ctx.client.eventRevisions.formatErrors(errors, "message"),
|
|
34
47
|
},
|
|
35
48
|
_translations: [],
|
|
36
49
|
},
|
|
@@ -38,7 +51,7 @@ const create = async (ctx) => {
|
|
|
38
51
|
}
|
|
39
52
|
|
|
40
53
|
if (eventErrors) {
|
|
41
|
-
throw `Failed to lock
|
|
54
|
+
throw new Error(`Failed to lock revision: ${JSON.stringify(eventErrors)}`);
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
return {
|
|
@@ -3,6 +3,10 @@ const create_form = async (ctx) => {
|
|
|
3
3
|
|
|
4
4
|
const revision = await ctx.client.pageRevisions.find(parent_id, ctx.locale);
|
|
5
5
|
|
|
6
|
+
if (!revision) {
|
|
7
|
+
throw new Error(`Missing revision #${parent_id}`);
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
const resource = {
|
|
7
11
|
id: revision.id,
|
|
8
12
|
originalId: revision.originalId,
|
|
@@ -22,7 +26,13 @@ const create = async (ctx) => {
|
|
|
22
26
|
const { parent_id } = ctx.params;
|
|
23
27
|
const { message } = ctx.resourceParams.resource;
|
|
24
28
|
|
|
25
|
-
const
|
|
29
|
+
const revision = await ctx.client.pageRevisions.find(parent_id, ctx.locale);
|
|
30
|
+
|
|
31
|
+
if (!revision) {
|
|
32
|
+
throw new Error(`Missing revision #${parent_id}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { errors, pageErrors } = await ctx.client.pageRevisions.lock(
|
|
26
36
|
parent_id,
|
|
27
37
|
ctx.locale,
|
|
28
38
|
message
|
|
@@ -37,7 +47,7 @@ const create = async (ctx) => {
|
|
|
37
47
|
message,
|
|
38
48
|
},
|
|
39
49
|
errors: {
|
|
40
|
-
resource: ctx.client.
|
|
50
|
+
resource: ctx.client.pageRevisions.formatErrors(errors, "message"),
|
|
41
51
|
},
|
|
42
52
|
_translations: [],
|
|
43
53
|
},
|
|
@@ -45,7 +55,7 @@ const create = async (ctx) => {
|
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
if (pageErrors) {
|
|
48
|
-
throw `Failed to lock
|
|
58
|
+
throw new Error(`Failed to lock revision: ${JSON.stringify(pageErrors)}`);
|
|
49
59
|
}
|
|
50
60
|
|
|
51
61
|
return {
|
|
@@ -117,27 +117,45 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
117
117
|
return humanize(field);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
withHint(markup, hint) {
|
|
121
|
+
return [markup, hint ? this.hint(hint) : ""].join("");
|
|
122
|
+
}
|
|
123
|
+
|
|
120
124
|
input(name, opts = {}) {
|
|
125
|
+
const { hint = "", ...rest } = opts;
|
|
121
126
|
const value = this.__getValue(name);
|
|
122
|
-
|
|
127
|
+
|
|
128
|
+
return this.withHint(
|
|
129
|
+
this.tag("input", null, { type: "text", name, value, ...rest }),
|
|
130
|
+
hint
|
|
131
|
+
);
|
|
123
132
|
}
|
|
124
133
|
|
|
125
134
|
textarea(name, opts = {}) {
|
|
126
|
-
const { value, ...rest } = opts;
|
|
127
|
-
|
|
128
|
-
return this.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
const { value, hint = "", ...rest } = opts;
|
|
136
|
+
|
|
137
|
+
return this.withHint(
|
|
138
|
+
this.tag(
|
|
139
|
+
"textarea",
|
|
140
|
+
value || this.__getValue(name),
|
|
141
|
+
{
|
|
142
|
+
name,
|
|
143
|
+
...rest,
|
|
144
|
+
},
|
|
145
|
+
{ nonVoid: true }
|
|
146
|
+
),
|
|
147
|
+
hint
|
|
136
148
|
);
|
|
137
149
|
}
|
|
138
150
|
|
|
139
151
|
select(name, opts = {}) {
|
|
140
|
-
const {
|
|
152
|
+
const {
|
|
153
|
+
value,
|
|
154
|
+
options = [],
|
|
155
|
+
prompt = "Please select...",
|
|
156
|
+
hint = "",
|
|
157
|
+
...rest
|
|
158
|
+
} = opts;
|
|
141
159
|
const selected = value || this.__getValue(name);
|
|
142
160
|
|
|
143
161
|
const renderedOpts = [];
|
|
@@ -154,11 +172,14 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
154
172
|
);
|
|
155
173
|
}
|
|
156
174
|
|
|
157
|
-
return this.
|
|
175
|
+
return this.withHint(
|
|
176
|
+
this.tag("select", renderedOpts.join(""), { name, ...rest }),
|
|
177
|
+
hint
|
|
178
|
+
);
|
|
158
179
|
}
|
|
159
180
|
|
|
160
181
|
radio_group(name, opts = {}) {
|
|
161
|
-
const { value, options = [], ...rest } = opts;
|
|
182
|
+
const { value, options = [], hint = "", ...rest } = opts;
|
|
162
183
|
const selected = value || this.__getValue(name);
|
|
163
184
|
|
|
164
185
|
const renderedOpts = [];
|
|
@@ -176,11 +197,17 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
176
197
|
renderedOpts.push(this.tag("label", `${radio} ${o[1]}`));
|
|
177
198
|
}
|
|
178
199
|
|
|
179
|
-
return this.
|
|
200
|
+
return this.withHint(
|
|
201
|
+
this.tag("div", renderedOpts.join(""), {
|
|
202
|
+
...rest,
|
|
203
|
+
class: ["radio-group", rest.class].filter(Boolean).join(" "),
|
|
204
|
+
}),
|
|
205
|
+
hint
|
|
206
|
+
);
|
|
180
207
|
}
|
|
181
208
|
|
|
182
209
|
checkbox_group(name, opts = {}) {
|
|
183
|
-
const { value, options = [], ...rest } = opts;
|
|
210
|
+
const { value, options = [], hint = "", ...rest } = opts;
|
|
184
211
|
const selected = value || this.__getValue(name);
|
|
185
212
|
|
|
186
213
|
const renderedOpts = [];
|
|
@@ -200,30 +227,34 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
200
227
|
renderedOpts.push(this.tag("label", `${checkbox} ${o[1]}`));
|
|
201
228
|
}
|
|
202
229
|
|
|
203
|
-
return this.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
230
|
+
return this.withHint(
|
|
231
|
+
this.tag(
|
|
232
|
+
"div",
|
|
233
|
+
|
|
234
|
+
renderedOpts.length
|
|
235
|
+
? renderedOpts.join("")
|
|
236
|
+
: this.tag("div", "No items available.", {
|
|
237
|
+
class: "italic opacity-50",
|
|
238
|
+
}),
|
|
239
|
+
|
|
240
|
+
{
|
|
241
|
+
...rest,
|
|
242
|
+
class: ["checkbox-group", rest.class].filter(Boolean).join(" "),
|
|
243
|
+
}
|
|
244
|
+
),
|
|
245
|
+
hint
|
|
214
246
|
);
|
|
215
247
|
}
|
|
216
248
|
|
|
217
249
|
checkbox(name, opts = {}) {
|
|
218
|
-
const { value: desiredValue, default_value: defaultValue } = opts;
|
|
219
|
-
|
|
250
|
+
const { value: desiredValue, default_value: defaultValue, ...rest } = opts;
|
|
220
251
|
const value = this.__getValue(name);
|
|
221
252
|
const selected = value === desiredValue ? { checked: "checked" } : {};
|
|
222
253
|
|
|
223
254
|
const checkboxItem = this.tag("input", null, {
|
|
224
255
|
type: "checkbox",
|
|
225
|
-
value,
|
|
226
|
-
...
|
|
256
|
+
value: desiredValue,
|
|
257
|
+
...rest,
|
|
227
258
|
...selected,
|
|
228
259
|
});
|
|
229
260
|
|
|
@@ -250,6 +281,10 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
250
281
|
return this.tag("span", children, { class: "text-red-600" });
|
|
251
282
|
}
|
|
252
283
|
|
|
284
|
+
hint(children) {
|
|
285
|
+
return this.tag("span", children, { class: "help-block" });
|
|
286
|
+
}
|
|
287
|
+
|
|
253
288
|
group(children, opts = {}) {
|
|
254
289
|
return this.tag("div", children, {
|
|
255
290
|
class: ["mb-4", opts.class].filter(Boolean).join(" "),
|
|
@@ -261,8 +296,8 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
261
296
|
}
|
|
262
297
|
|
|
263
298
|
button(name, opts) {
|
|
264
|
-
const { label,
|
|
265
|
-
const defaultLabel =
|
|
299
|
+
const { label, hint = "" } = opts;
|
|
300
|
+
const defaultLabel = label || this.__getDefaultLabel(name);
|
|
266
301
|
const fields = Object.keys(BUTTON_FIELDS_MAP).map((key) => {
|
|
267
302
|
const innerOpts = BUTTON_FIELDS_MAP[key];
|
|
268
303
|
|
|
@@ -282,7 +317,11 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
282
317
|
|
|
283
318
|
return this.tag(
|
|
284
319
|
"fieldset",
|
|
285
|
-
[
|
|
320
|
+
[
|
|
321
|
+
this.tag("legend", defaultLabel, {}),
|
|
322
|
+
...fields,
|
|
323
|
+
hint ? this.hint(hint) : "",
|
|
324
|
+
].join(""),
|
|
286
325
|
{
|
|
287
326
|
class: "button-group",
|
|
288
327
|
}
|
|
@@ -290,8 +329,8 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
290
329
|
}
|
|
291
330
|
|
|
292
331
|
link(name, opts) {
|
|
293
|
-
const { label,
|
|
294
|
-
const defaultLabel =
|
|
332
|
+
const { label, hint = "" } = opts;
|
|
333
|
+
const defaultLabel = label || this.__getDefaultLabel(name);
|
|
295
334
|
const fields = Object.keys(LINK_FIELDS_MAP).map((key) => {
|
|
296
335
|
const innerOpts = LINK_FIELDS_MAP[key];
|
|
297
336
|
|
|
@@ -311,7 +350,11 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
311
350
|
|
|
312
351
|
return this.tag(
|
|
313
352
|
"fieldset",
|
|
314
|
-
[
|
|
353
|
+
[
|
|
354
|
+
this.tag("legend", defaultLabel, {}),
|
|
355
|
+
...fields,
|
|
356
|
+
hint ? this.hint(hint) : "",
|
|
357
|
+
].join(""),
|
|
315
358
|
{
|
|
316
359
|
class: "link-group",
|
|
317
360
|
}
|
|
@@ -330,12 +373,18 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
330
373
|
const error = this.__getError(name);
|
|
331
374
|
|
|
332
375
|
if (as === "checkbox") {
|
|
376
|
+
const { hint = "", ...cbOptsRest } = rest;
|
|
377
|
+
|
|
333
378
|
return this.group(
|
|
334
379
|
[
|
|
335
380
|
this.tag(
|
|
336
381
|
"div",
|
|
337
382
|
[
|
|
338
|
-
this[as](name, {
|
|
383
|
+
this[as](name, {
|
|
384
|
+
id: htmlID,
|
|
385
|
+
name: toFormName(name),
|
|
386
|
+
...cbOptsRest,
|
|
387
|
+
}),
|
|
339
388
|
this.label(name, `${label || defaultLabel}`),
|
|
340
389
|
]
|
|
341
390
|
.filter(Boolean)
|
|
@@ -344,6 +393,7 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
344
393
|
class: "checkbox-wrapper",
|
|
345
394
|
}
|
|
346
395
|
),
|
|
396
|
+
hint ? this.hint(hint) : "",
|
|
347
397
|
error ? this.error(error) : "",
|
|
348
398
|
]
|
|
349
399
|
.filter(Boolean)
|
package/src/helpers/Inflector.js
CHANGED
|
@@ -26,7 +26,6 @@ body {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
@layer components {
|
|
29
|
-
|
|
30
29
|
/* Utils */
|
|
31
30
|
.dbg {
|
|
32
31
|
@apply outline-1 outline-dashed outline-red-500;
|
|
@@ -144,10 +143,16 @@ body {
|
|
|
144
143
|
@apply border-red-600;
|
|
145
144
|
}
|
|
146
145
|
|
|
146
|
+
.help-block {
|
|
147
|
+
@apply opacity-50 text-sm;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.radio-group,
|
|
147
151
|
.checkbox-group {
|
|
148
152
|
@apply max-h-[200px] overflow-y-auto py-1 px-2 mt-1 rounded shadow-inner border border-neutral-300 bg-raketa-background dark:border-neutral-700;
|
|
149
153
|
}
|
|
150
154
|
|
|
155
|
+
.radio-group label,
|
|
151
156
|
.checkbox-group label {
|
|
152
157
|
@apply flex gap-2 text-nowrap items-center py-2;
|
|
153
158
|
}
|
|
@@ -156,6 +161,10 @@ body {
|
|
|
156
161
|
@apply size-4 px-0;
|
|
157
162
|
}
|
|
158
163
|
|
|
164
|
+
.radio-group input[type="radio"] {
|
|
165
|
+
@apply size-4 px-0 rounded-full;
|
|
166
|
+
}
|
|
167
|
+
|
|
159
168
|
.checkbox-wrapper {
|
|
160
169
|
@apply flex gap-2 text-nowrap;
|
|
161
170
|
}
|
|
@@ -275,7 +284,7 @@ body {
|
|
|
275
284
|
.pagination {
|
|
276
285
|
@apply text-center py-8 text-raketa-foreground/50;
|
|
277
286
|
|
|
278
|
-
|
|
287
|
+
& > div {
|
|
279
288
|
@apply inline-flex items-center gap-4;
|
|
280
289
|
}
|
|
281
290
|
|
|
@@ -30,7 +30,7 @@ describe("Article revision code settings", () => {
|
|
|
30
30
|
settings: {
|
|
31
31
|
codes: {
|
|
32
32
|
scripts: JSON.stringify([{ type: "bla" }]),
|
|
33
|
-
|
|
33
|
+
structured_json: JSON.stringify({ type: "article" }),
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
36
|
};
|
|
@@ -63,7 +63,7 @@ describe("Article revision code settings", () => {
|
|
|
63
63
|
...revision.settings,
|
|
64
64
|
codes: {
|
|
65
65
|
scripts: [{ type: "bla" }],
|
|
66
|
-
|
|
66
|
+
structured_json: { type: "article" },
|
|
67
67
|
},
|
|
68
68
|
},
|
|
69
69
|
});
|
|
@@ -82,7 +82,7 @@ describe("Article revision code settings", () => {
|
|
|
82
82
|
settings: {
|
|
83
83
|
codes: {
|
|
84
84
|
scripts: JSON.stringify([{ type: "bla" }]),
|
|
85
|
-
|
|
85
|
+
structured_json: JSON.stringify({ type: "article" }),
|
|
86
86
|
},
|
|
87
87
|
},
|
|
88
88
|
};
|
|
@@ -115,7 +115,7 @@ describe("Article revision code settings", () => {
|
|
|
115
115
|
...revision.settings,
|
|
116
116
|
codes: {
|
|
117
117
|
scripts: [{ type: "bla" }],
|
|
118
|
-
|
|
118
|
+
structured_json: { type: "article" },
|
|
119
119
|
},
|
|
120
120
|
},
|
|
121
121
|
});
|
|
@@ -129,7 +129,7 @@ describe("Article revision code settings", () => {
|
|
|
129
129
|
...revision.settings,
|
|
130
130
|
codes: {
|
|
131
131
|
scripts: [{ type: "bla" }],
|
|
132
|
-
|
|
132
|
+
structured_json: { type: "article" },
|
|
133
133
|
},
|
|
134
134
|
},
|
|
135
135
|
},
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import Factory from "../../../support/factory";
|
|
2
|
+
import ArticleRevisions from "../../../../cloud/ArticleRevisions";
|
|
3
|
+
import LocksHandler from "../../../../handlers/article_revisions/LocksHandler";
|
|
4
|
+
|
|
5
|
+
function buildCtx(revision, lockSettings) {
|
|
6
|
+
return {
|
|
7
|
+
client: {
|
|
8
|
+
articleRevisions: new ArticleRevisions(() => ({}), "token"),
|
|
9
|
+
},
|
|
10
|
+
params: { parent_id: revision.id },
|
|
11
|
+
resourceParams: {
|
|
12
|
+
resource: lockSettings,
|
|
13
|
+
},
|
|
14
|
+
locale: "en",
|
|
15
|
+
resourceConfig: {
|
|
16
|
+
articleType: "article",
|
|
17
|
+
articleTypePlural: "articles",
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe("Article revision lock ", () => {
|
|
23
|
+
test("lock successful", async () => {
|
|
24
|
+
const revision = Factory.build("article_revision");
|
|
25
|
+
const lockSettings = { message: "Some lock message" };
|
|
26
|
+
const ctx = buildCtx(revision, lockSettings);
|
|
27
|
+
|
|
28
|
+
const mockFind = jest
|
|
29
|
+
.spyOn(ctx.client.articleRevisions, "find")
|
|
30
|
+
.mockImplementation(() => revision);
|
|
31
|
+
|
|
32
|
+
const mockLock = jest
|
|
33
|
+
.spyOn(ctx.client.articleRevisions, "lock")
|
|
34
|
+
.mockImplementation(() => ({
|
|
35
|
+
revision,
|
|
36
|
+
errors: null,
|
|
37
|
+
articleErrors: null,
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
const result = await LocksHandler.create(ctx);
|
|
41
|
+
|
|
42
|
+
expect(mockFind).toHaveBeenCalledWith(revision.id, "en");
|
|
43
|
+
expect(mockLock).toHaveBeenCalledWith(
|
|
44
|
+
revision.id,
|
|
45
|
+
"en",
|
|
46
|
+
lockSettings.message
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(result).toEqual({
|
|
50
|
+
redirect: `/en/articles/${revision.originalId}`,
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("lock failed with errors", async () => {
|
|
55
|
+
const revision = Factory.build("article_revision");
|
|
56
|
+
const lockSettings = { message: "" };
|
|
57
|
+
const ctx = buildCtx(revision, lockSettings);
|
|
58
|
+
const errors = [{ key: "message", message: "Cannot be blank" }];
|
|
59
|
+
|
|
60
|
+
const mockFind = jest
|
|
61
|
+
.spyOn(ctx.client.articleRevisions, "find")
|
|
62
|
+
.mockImplementation(() => revision);
|
|
63
|
+
|
|
64
|
+
const mockLock = jest
|
|
65
|
+
.spyOn(ctx.client.articleRevisions, "lock")
|
|
66
|
+
.mockImplementation(() => ({
|
|
67
|
+
revision: null,
|
|
68
|
+
errors,
|
|
69
|
+
articleErrors: null,
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
const result = await LocksHandler.create(ctx);
|
|
73
|
+
|
|
74
|
+
expect(mockFind).toHaveBeenCalledWith(revision.id, "en");
|
|
75
|
+
expect(mockLock).toHaveBeenCalledWith(
|
|
76
|
+
revision.id,
|
|
77
|
+
"en",
|
|
78
|
+
lockSettings.message
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
expect(result).toEqual({
|
|
82
|
+
assigns: {
|
|
83
|
+
resource: {
|
|
84
|
+
id: revision.id,
|
|
85
|
+
originalId: revision.originalId,
|
|
86
|
+
message: lockSettings.message,
|
|
87
|
+
},
|
|
88
|
+
errors: {
|
|
89
|
+
resource: { message: "Cannot be blank" },
|
|
90
|
+
},
|
|
91
|
+
_translations: [],
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("lock failed with article errors", async () => {
|
|
97
|
+
const revision = Factory.build("article_revision");
|
|
98
|
+
const lockSettings = { message: "Some lock message" };
|
|
99
|
+
const ctx = buildCtx(revision, lockSettings);
|
|
100
|
+
const articleErrors = [
|
|
101
|
+
{ key: "generalError", message: "Failed to lock revision" },
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const mockFind = jest
|
|
105
|
+
.spyOn(ctx.client.articleRevisions, "find")
|
|
106
|
+
.mockImplementation(() => revision);
|
|
107
|
+
|
|
108
|
+
const mockLock = jest
|
|
109
|
+
.spyOn(ctx.client.articleRevisions, "lock")
|
|
110
|
+
.mockImplementation(() => ({
|
|
111
|
+
revision: null,
|
|
112
|
+
errors: null,
|
|
113
|
+
articleErrors,
|
|
114
|
+
}));
|
|
115
|
+
|
|
116
|
+
await expect(LocksHandler.create(ctx)).rejects.toThrow(
|
|
117
|
+
`Failed to lock revision: ${JSON.stringify(articleErrors)}`
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expect(mockFind).toHaveBeenCalledWith(revision.id, "en");
|
|
121
|
+
expect(mockLock).toHaveBeenCalledWith(
|
|
122
|
+
revision.id,
|
|
123
|
+
"en",
|
|
124
|
+
lockSettings.message
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("create for non existing article revision", async () => {
|
|
129
|
+
const lockSettings = { message: "Some lock message" };
|
|
130
|
+
const ctx = buildCtx({ id: 42 }, lockSettings);
|
|
131
|
+
|
|
132
|
+
const mockFind = jest
|
|
133
|
+
.spyOn(ctx.client.articleRevisions, "find")
|
|
134
|
+
.mockImplementation(() => null);
|
|
135
|
+
|
|
136
|
+
await expect(LocksHandler.create(ctx)).rejects.toThrow(
|
|
137
|
+
`Missing revision #42`
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
expect(mockFind).toHaveBeenCalledWith(42, "en");
|
|
141
|
+
});
|
|
142
|
+
});
|