@raketa-cloud/admin 0.0.33 → 0.0.36
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/helpers/FormBuilder.js +108 -49
- 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,33 +227,49 @@ 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 } = 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
|
-
name,
|
|
226
256
|
value,
|
|
227
|
-
...
|
|
257
|
+
...rest,
|
|
228
258
|
...selected,
|
|
229
259
|
});
|
|
260
|
+
|
|
261
|
+
if (defaultValue === undefined) {
|
|
262
|
+
return checkboxItem;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Make sure to submit the negative value if unchecked
|
|
266
|
+
const hiddenComplementaryItem = this.tag("input", null, {
|
|
267
|
+
type: "hidden",
|
|
268
|
+
name: toFormName(name),
|
|
269
|
+
value: defaultValue,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return [hiddenComplementaryItem, checkboxItem].join("");
|
|
230
273
|
}
|
|
231
274
|
|
|
232
275
|
label(name, children, opts = {}) {
|
|
@@ -238,6 +281,10 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
238
281
|
return this.tag("span", children, { class: "text-red-600" });
|
|
239
282
|
}
|
|
240
283
|
|
|
284
|
+
hint(children) {
|
|
285
|
+
return this.tag("span", children, { class: "help-block" });
|
|
286
|
+
}
|
|
287
|
+
|
|
241
288
|
group(children, opts = {}) {
|
|
242
289
|
return this.tag("div", children, {
|
|
243
290
|
class: ["mb-4", opts.class].filter(Boolean).join(" "),
|
|
@@ -249,8 +296,8 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
249
296
|
}
|
|
250
297
|
|
|
251
298
|
button(name, opts) {
|
|
252
|
-
const { label,
|
|
253
|
-
const defaultLabel =
|
|
299
|
+
const { label, hint = "" } = opts;
|
|
300
|
+
const defaultLabel = label || this.__getDefaultLabel(name);
|
|
254
301
|
const fields = Object.keys(BUTTON_FIELDS_MAP).map((key) => {
|
|
255
302
|
const innerOpts = BUTTON_FIELDS_MAP[key];
|
|
256
303
|
|
|
@@ -261,17 +308,20 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
261
308
|
label: innerOpts.label,
|
|
262
309
|
class: "no-margin",
|
|
263
310
|
});
|
|
264
|
-
} else {
|
|
265
|
-
return this.field(`${name}.${key}`, {
|
|
266
|
-
label: innerOpts.label,
|
|
267
|
-
class: "no-margin",
|
|
268
|
-
});
|
|
269
311
|
}
|
|
312
|
+
return this.field(`${name}.${key}`, {
|
|
313
|
+
label: innerOpts.label,
|
|
314
|
+
class: "no-margin",
|
|
315
|
+
});
|
|
270
316
|
});
|
|
271
317
|
|
|
272
318
|
return this.tag(
|
|
273
319
|
"fieldset",
|
|
274
|
-
[
|
|
320
|
+
[
|
|
321
|
+
this.tag("legend", defaultLabel, {}),
|
|
322
|
+
...fields,
|
|
323
|
+
hint ? this.hint(hint) : "",
|
|
324
|
+
].join(""),
|
|
275
325
|
{
|
|
276
326
|
class: "button-group",
|
|
277
327
|
}
|
|
@@ -279,8 +329,8 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
279
329
|
}
|
|
280
330
|
|
|
281
331
|
link(name, opts) {
|
|
282
|
-
const { label,
|
|
283
|
-
const defaultLabel =
|
|
332
|
+
const { label, hint = "" } = opts;
|
|
333
|
+
const defaultLabel = label || this.__getDefaultLabel(name);
|
|
284
334
|
const fields = Object.keys(LINK_FIELDS_MAP).map((key) => {
|
|
285
335
|
const innerOpts = LINK_FIELDS_MAP[key];
|
|
286
336
|
|
|
@@ -291,17 +341,20 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
291
341
|
label: innerOpts.label,
|
|
292
342
|
class: "no-margin",
|
|
293
343
|
});
|
|
294
|
-
} else {
|
|
295
|
-
return this.field(`${name}.${key}`, {
|
|
296
|
-
label: innerOpts.label,
|
|
297
|
-
class: "no-margin",
|
|
298
|
-
});
|
|
299
344
|
}
|
|
345
|
+
return this.field(`${name}.${key}`, {
|
|
346
|
+
label: innerOpts.label,
|
|
347
|
+
class: "no-margin",
|
|
348
|
+
});
|
|
300
349
|
});
|
|
301
350
|
|
|
302
351
|
return this.tag(
|
|
303
352
|
"fieldset",
|
|
304
|
-
[
|
|
353
|
+
[
|
|
354
|
+
this.tag("legend", defaultLabel, {}),
|
|
355
|
+
...fields,
|
|
356
|
+
hint ? this.hint(hint) : "",
|
|
357
|
+
].join(""),
|
|
305
358
|
{
|
|
306
359
|
class: "link-group",
|
|
307
360
|
}
|
|
@@ -320,12 +373,17 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
320
373
|
const error = this.__getError(name);
|
|
321
374
|
|
|
322
375
|
if (as === "checkbox") {
|
|
376
|
+
const { hint = "", cbOptsRest } = rest;
|
|
323
377
|
return this.group(
|
|
324
378
|
[
|
|
325
379
|
this.tag(
|
|
326
380
|
"div",
|
|
327
381
|
[
|
|
328
|
-
this[as](name, {
|
|
382
|
+
this[as](name, {
|
|
383
|
+
id: htmlID,
|
|
384
|
+
name: toFormName(name),
|
|
385
|
+
...cbOptsRest,
|
|
386
|
+
}),
|
|
329
387
|
this.label(name, `${label || defaultLabel}`),
|
|
330
388
|
]
|
|
331
389
|
.filter(Boolean)
|
|
@@ -334,6 +392,7 @@ export default class FormBuilder extends HTMLBuilder {
|
|
|
334
392
|
class: "checkbox-wrapper",
|
|
335
393
|
}
|
|
336
394
|
),
|
|
395
|
+
hint ? this.hint(hint) : "",
|
|
337
396
|
error ? this.error(error) : "",
|
|
338
397
|
]
|
|
339
398
|
.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
|
+
});
|