@qkix/strapi-plugin-rewind 0.2.1 → 0.3.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/README.md +13 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +183 -141
- package/dist/admin/src/components/ChangesDialog.d.ts +22 -1
- package/dist/server/index.js +2 -2
- package/dist/server/index.mjs +248 -241
- package/package.json +3 -3
package/dist/server/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash as J } from "node:crypto";
|
|
2
2
|
import { AsyncLocalStorage as Z } from "node:async_hooks";
|
|
3
|
-
const Q = ["id", "documentId", "locale"],
|
|
3
|
+
const Q = ["id", "documentId", "locale"], E = [
|
|
4
4
|
"createdAt",
|
|
5
5
|
"updatedAt",
|
|
6
6
|
"publishedAt",
|
|
@@ -10,15 +10,15 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
10
10
|
"strapi_assignee",
|
|
11
11
|
"locale",
|
|
12
12
|
"localizations"
|
|
13
|
-
],
|
|
13
|
+
], k = (e, t) => e.getModel(t), x = (e) => e?.type === "relation" || e?.type === "media", F = (e) => e?.type === "relation" && String(e.relation ?? "").toLowerCase().startsWith("morph"), _ = (e, t) => Object.entries(k(e, t).attributes).filter(
|
|
14
14
|
([, n]) => !["relation", "media", "component", "dynamiczone"].includes(n.type)
|
|
15
|
-
).map(([n]) => n),
|
|
16
|
-
const
|
|
17
|
-
return Object.entries(
|
|
18
|
-
(a, [s,
|
|
19
|
-
switch (
|
|
15
|
+
).map(([n]) => n), $ = (e, t, n = !0) => {
|
|
16
|
+
const r = k(e, t), o = n ? "select" : "fields";
|
|
17
|
+
return Object.entries(r.attributes).reduce(
|
|
18
|
+
(a, [s, i]) => {
|
|
19
|
+
switch (i.type) {
|
|
20
20
|
case "relation": {
|
|
21
|
-
if (
|
|
21
|
+
if (F(i)) break;
|
|
22
22
|
a[s] = { [o]: ["documentId", "locale", "publishedAt"] };
|
|
23
23
|
break;
|
|
24
24
|
}
|
|
@@ -28,17 +28,17 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
28
28
|
}
|
|
29
29
|
case "component": {
|
|
30
30
|
a[s] = {
|
|
31
|
-
populate:
|
|
32
|
-
[o]:
|
|
31
|
+
populate: $(e, i.component, n),
|
|
32
|
+
[o]: _(e, i.component)
|
|
33
33
|
};
|
|
34
34
|
break;
|
|
35
35
|
}
|
|
36
36
|
case "dynamiczone": {
|
|
37
37
|
a[s] = {
|
|
38
|
-
on: (
|
|
38
|
+
on: (i.components ?? []).reduce(
|
|
39
39
|
(c, l) => (c[l] = {
|
|
40
|
-
populate:
|
|
41
|
-
[o]:
|
|
40
|
+
populate: $(e, l, n),
|
|
41
|
+
[o]: _(e, l)
|
|
42
42
|
}, c),
|
|
43
43
|
{}
|
|
44
44
|
)
|
|
@@ -51,99 +51,99 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
51
51
|
{}
|
|
52
52
|
);
|
|
53
53
|
}, ee = (e, t) => {
|
|
54
|
-
const n = {},
|
|
54
|
+
const n = {}, r = (a) => {
|
|
55
55
|
if (n[a]) return;
|
|
56
|
-
const s =
|
|
57
|
-
n[a] =
|
|
58
|
-
for (const
|
|
59
|
-
if (
|
|
60
|
-
for (const c of
|
|
61
|
-
}, o =
|
|
56
|
+
const s = k(e, a).attributes;
|
|
57
|
+
n[a] = N(s, E);
|
|
58
|
+
for (const i of Object.values(s))
|
|
59
|
+
if (i.type === "component" && r(i.component), i.type === "dynamiczone")
|
|
60
|
+
for (const c of i.components ?? []) r(c);
|
|
61
|
+
}, o = k(e, t).attributes;
|
|
62
62
|
for (const a of Object.values(o))
|
|
63
|
-
if (a.type === "component" &&
|
|
64
|
-
for (const s of a.components ?? [])
|
|
63
|
+
if (a.type === "component" && r(a.component), a.type === "dynamiczone")
|
|
64
|
+
for (const s of a.components ?? []) r(s);
|
|
65
65
|
return {
|
|
66
|
-
attributes:
|
|
66
|
+
attributes: N(o, E),
|
|
67
67
|
components: n
|
|
68
68
|
};
|
|
69
|
-
},
|
|
69
|
+
}, N = (e, t) => Object.fromEntries(Object.entries(e ?? {}).filter(([n]) => !t.includes(n))), te = (e, t, n) => (Array.isArray(e) ? e : [e]).filter((o) => !!o).map(
|
|
70
70
|
(o) => n ? { id: o.id, targetUid: t } : {
|
|
71
71
|
documentId: o.documentId,
|
|
72
72
|
locale: o.locale ?? null,
|
|
73
73
|
targetUid: t
|
|
74
74
|
}
|
|
75
75
|
), ne = (e, t, n) => {
|
|
76
|
-
const
|
|
77
|
-
for (const [
|
|
78
|
-
const l = i
|
|
76
|
+
const r = k(e, t).attributes, o = {}, a = {}, s = N(n, [...E, ...Q]);
|
|
77
|
+
for (const [i, c] of Object.entries(s)) {
|
|
78
|
+
const l = r[i];
|
|
79
79
|
if (l && x(l)) {
|
|
80
|
-
if (
|
|
80
|
+
if (F(l)) continue;
|
|
81
81
|
const d = l.type === "media" ? "plugin::upload.file" : l.target;
|
|
82
|
-
a[
|
|
82
|
+
a[i] = te(c, d, l.type === "media");
|
|
83
83
|
continue;
|
|
84
84
|
}
|
|
85
|
-
o[
|
|
85
|
+
o[i] = l ? H(e, l, c) : c;
|
|
86
86
|
}
|
|
87
87
|
return { data: o, relations: a, schemaSnapshot: ee(e, t) };
|
|
88
|
-
},
|
|
88
|
+
}, H = (e, t, n) => {
|
|
89
89
|
if (n == null) return n;
|
|
90
90
|
if (t.type === "component") {
|
|
91
|
-
const
|
|
92
|
-
return Array.isArray(n) ? n.map((o) =>
|
|
91
|
+
const r = (o) => j(e, t.component, o);
|
|
92
|
+
return Array.isArray(n) ? n.map((o) => r(o)) : r(n);
|
|
93
93
|
}
|
|
94
|
-
return t.type === "dynamiczone" && Array.isArray(n) ? n.map((
|
|
95
|
-
const o =
|
|
96
|
-
return
|
|
94
|
+
return t.type === "dynamiczone" && Array.isArray(n) ? n.map((r) => {
|
|
95
|
+
const o = r;
|
|
96
|
+
return j(e, o.__component, o);
|
|
97
97
|
}) : n;
|
|
98
|
-
},
|
|
98
|
+
}, j = (e, t, n) => {
|
|
99
99
|
if (!n || !t) return n;
|
|
100
|
-
const
|
|
100
|
+
const r = k(e, t).attributes, o = {};
|
|
101
101
|
for (const [a, s] of Object.entries(n)) {
|
|
102
102
|
if (a === "id") continue;
|
|
103
|
-
const
|
|
104
|
-
o[a] =
|
|
103
|
+
const i = r[a];
|
|
104
|
+
o[a] = i ? H(e, i, s) : s;
|
|
105
105
|
}
|
|
106
106
|
return o;
|
|
107
|
-
},
|
|
108
|
-
const t = /* @__PURE__ */ new Map(), n = async (
|
|
109
|
-
if (t.has(
|
|
107
|
+
}, W = (e) => {
|
|
108
|
+
const t = /* @__PURE__ */ new Map(), n = async (r) => {
|
|
109
|
+
if (t.has(r)) return t.get(r);
|
|
110
110
|
let o;
|
|
111
111
|
try {
|
|
112
|
-
o = (await e.plugin("content-manager").service("content-types").findConfiguration(e.contentTypes[
|
|
112
|
+
o = (await e.plugin("content-manager").service("content-types").findConfiguration(e.contentTypes[r]))?.settings?.mainField;
|
|
113
113
|
} catch {
|
|
114
114
|
}
|
|
115
|
-
return t.set(
|
|
115
|
+
return t.set(r, o), o;
|
|
116
116
|
};
|
|
117
|
-
return async (
|
|
117
|
+
return async (r, o) => {
|
|
118
118
|
if (!o) return null;
|
|
119
|
-
const s = [await n(
|
|
120
|
-
for (const
|
|
121
|
-
const c = o[
|
|
119
|
+
const s = [await n(r), "title", "name", "label"].filter(Boolean);
|
|
120
|
+
for (const i of s) {
|
|
121
|
+
const c = o[i];
|
|
122
122
|
if (typeof c == "string" && c.trim())
|
|
123
123
|
return c.trim().slice(0, 255);
|
|
124
124
|
}
|
|
125
125
|
return null;
|
|
126
126
|
};
|
|
127
127
|
}, v = "plugin::rewind.version", oe = /* @__PURE__ */ new Set(["publish", "unpublish", "discardDraft", "restore"]), se = (e) => J("sha256").update(JSON.stringify(e)).digest("hex"), ie = ({ strapi: e }) => {
|
|
128
|
-
const t =
|
|
129
|
-
const d = i
|
|
130
|
-
return e.db.query(
|
|
128
|
+
const t = W(e), n = (i) => !!e.contentTypes[i]?.options?.draftAndPublish, r = (i) => !!(e.getModel(i)?.pluginOptions?.i18n?.localized ?? e.contentTypes[i]?.pluginOptions?.i18n?.localized), o = async (i, c, l) => {
|
|
129
|
+
const d = r(i) && l.filter(Boolean).length > 0 ? { locale: { $in: l.filter(Boolean) } } : {};
|
|
130
|
+
return e.db.query(i).findMany({
|
|
131
131
|
where: {
|
|
132
132
|
documentId: c,
|
|
133
133
|
...d,
|
|
134
|
-
...n(
|
|
134
|
+
...n(i) ? { publishedAt: null } : {}
|
|
135
135
|
},
|
|
136
|
-
populate:
|
|
136
|
+
populate: $(e, i)
|
|
137
137
|
});
|
|
138
|
-
}, a = async (
|
|
138
|
+
}, a = async (i, c) => {
|
|
139
139
|
try {
|
|
140
|
-
const l = e.plugin("content-manager").service("document-metadata"), d = await l.getMetadata(
|
|
140
|
+
const l = e.plugin("content-manager").service("document-metadata"), d = await l.getMetadata(i, c);
|
|
141
141
|
return l.getStatus(c, d.availableStatus);
|
|
142
142
|
} catch {
|
|
143
143
|
return "draft";
|
|
144
144
|
}
|
|
145
|
-
}, s = async (
|
|
146
|
-
where: { contentType:
|
|
145
|
+
}, s = async (i, c, l) => e.db.query(v).findOne({
|
|
146
|
+
where: { contentType: i, relatedDocumentId: c, locale: l },
|
|
147
147
|
orderBy: { createdAt: "desc" }
|
|
148
148
|
});
|
|
149
149
|
return {
|
|
@@ -154,25 +154,25 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
154
154
|
* Called from the transaction's commit hook and never awaited by the write
|
|
155
155
|
* path - a failure here must not be able to reach the editor's save.
|
|
156
156
|
*/
|
|
157
|
-
async captureAll(
|
|
158
|
-
for (const l of
|
|
157
|
+
async captureAll(i, c) {
|
|
158
|
+
for (const l of i)
|
|
159
159
|
await this.capture(l, c);
|
|
160
160
|
},
|
|
161
|
-
async capture(
|
|
162
|
-
const { uid: l, relatedDocumentId: d, locale:
|
|
163
|
-
for (const
|
|
164
|
-
const
|
|
165
|
-
!oe.has(b) && (await s(l, d,
|
|
161
|
+
async capture(i, c) {
|
|
162
|
+
const { uid: l, relatedDocumentId: d, locale: f, origin: b } = i, h = i.before ?? await o(l, d, [f]);
|
|
163
|
+
for (const m of h) {
|
|
164
|
+
const T = m.locale ?? null, { data: u, relations: y, schemaSnapshot: w } = ne(e, l, m), p = se({ data: u, relations: y });
|
|
165
|
+
!oe.has(b) && (await s(l, d, T))?.contentHash === p || await e.db.query(v).create({
|
|
166
166
|
data: {
|
|
167
167
|
contentType: l,
|
|
168
168
|
relatedDocumentId: d,
|
|
169
|
-
locale:
|
|
170
|
-
status: await a(l,
|
|
171
|
-
label: await t(l,
|
|
172
|
-
data:
|
|
173
|
-
relations:
|
|
174
|
-
schemaSnapshot:
|
|
175
|
-
contentHash:
|
|
169
|
+
locale: T,
|
|
170
|
+
status: await a(l, m),
|
|
171
|
+
label: await t(l, u),
|
|
172
|
+
data: u,
|
|
173
|
+
relations: y,
|
|
174
|
+
schemaSnapshot: w,
|
|
175
|
+
contentHash: p,
|
|
176
176
|
origin: b,
|
|
177
177
|
userId: c,
|
|
178
178
|
pinned: !1
|
|
@@ -181,7 +181,7 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
};
|
|
184
|
-
},
|
|
184
|
+
}, C = [
|
|
185
185
|
"restore",
|
|
186
186
|
"publish",
|
|
187
187
|
"unpublish",
|
|
@@ -189,19 +189,19 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
189
189
|
"clone",
|
|
190
190
|
"create",
|
|
191
191
|
"update"
|
|
192
|
-
],
|
|
193
|
-
let t =
|
|
194
|
-
return t || (t = { intents: [], flushRegistered: !1 },
|
|
192
|
+
], M = /* @__PURE__ */ new WeakMap(), re = (e) => {
|
|
193
|
+
let t = M.get(e);
|
|
194
|
+
return t || (t = { intents: [], flushRegistered: !1 }, M.set(e, t)), t;
|
|
195
195
|
}, ae = (e) => {
|
|
196
196
|
const t = /* @__PURE__ */ new Map();
|
|
197
197
|
for (const n of e) {
|
|
198
|
-
const
|
|
198
|
+
const r = `${n.uid}:${n.relatedDocumentId}:${n.locale ?? ""}`, o = t.get(r);
|
|
199
199
|
if (!o) {
|
|
200
|
-
t.set(
|
|
200
|
+
t.set(r, n);
|
|
201
201
|
continue;
|
|
202
202
|
}
|
|
203
|
-
const a =
|
|
204
|
-
t.set(
|
|
203
|
+
const a = C.indexOf(n.origin) < C.indexOf(o.origin);
|
|
204
|
+
t.set(r, {
|
|
205
205
|
// A winning `publish` still wants the rows an earlier `discardDraft`
|
|
206
206
|
// captured - losing them would lose the only copy of that state.
|
|
207
207
|
...a ? n : o,
|
|
@@ -209,11 +209,11 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
209
209
|
});
|
|
210
210
|
}
|
|
211
211
|
return [...t.values()];
|
|
212
|
-
},
|
|
213
|
-
const n = e.db.query(t),
|
|
214
|
-
if (
|
|
215
|
-
e.log.info(`[rewind] labelling ${
|
|
216
|
-
const o =
|
|
212
|
+
}, K = new Z(), ce = (e) => K.run({ active: !0 }, e), le = () => K.getStore()?.active === !0, de = 200, ue = async (e, t) => {
|
|
213
|
+
const n = e.db.query(t), r = await n.count({ where: { label: null } });
|
|
214
|
+
if (r === 0) return 0;
|
|
215
|
+
e.log.info(`[rewind] labelling ${r} older version(s)…`);
|
|
216
|
+
const o = W(e);
|
|
217
217
|
let a = 0;
|
|
218
218
|
for (; ; ) {
|
|
219
219
|
const s = await n.findMany({
|
|
@@ -222,19 +222,19 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
222
222
|
limit: de
|
|
223
223
|
});
|
|
224
224
|
if (s.length === 0) break;
|
|
225
|
-
for (const
|
|
226
|
-
const c = await o(
|
|
225
|
+
for (const i of s) {
|
|
226
|
+
const c = await o(i.contentType, i.data);
|
|
227
227
|
await n.update({
|
|
228
|
-
where: { id:
|
|
228
|
+
where: { id: i.id },
|
|
229
229
|
data: { label: c ?? "" }
|
|
230
230
|
}), a += 1;
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
return e.log.info(`[rewind] labelled ${a} older version(s)`), a;
|
|
234
|
-
},
|
|
235
|
-
const n = await e.store.get(
|
|
234
|
+
}, U = { type: "core", key: "persisted_tables" }, fe = async (e, t) => {
|
|
235
|
+
const n = await e.store.get(U) ?? [];
|
|
236
236
|
n.map((o) => typeof o == "string" ? o : o.name).includes(t) || await e.store.set({
|
|
237
|
-
...
|
|
237
|
+
...U,
|
|
238
238
|
value: [...n, { name: t }]
|
|
239
239
|
});
|
|
240
240
|
}, pe = [
|
|
@@ -251,28 +251,28 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
251
251
|
`[rewind] could not label older versions: ${o instanceof Error ? o.message : String(o)}`
|
|
252
252
|
)
|
|
253
253
|
), he(e, t);
|
|
254
|
-
const n = () => e.plugin("rewind").service("snapshot"),
|
|
254
|
+
const n = () => e.plugin("rewind").service("snapshot"), r = (o) => {
|
|
255
255
|
if (!pe.includes(o.action)) return !1;
|
|
256
256
|
const a = o.contentType?.uid ?? o.uid ?? "";
|
|
257
257
|
return !(!a.startsWith("api::") || !t.contentTypes.includes(a) || le() || !t.trackApiWrites && !e.requestContext.get()?.request?.url?.startsWith("/content-manager"));
|
|
258
258
|
};
|
|
259
259
|
e.documents.use(async (o, a) => {
|
|
260
|
-
if (!
|
|
261
|
-
const s = o.contentType?.uid ?? o.uid,
|
|
260
|
+
if (!r(o)) return a();
|
|
261
|
+
const s = o.contentType?.uid ?? o.uid, i = o.params?.locale ?? null, c = o.action === "discardDraft" && o.params?.documentId ? await n().readRows(s, o.params.documentId, [i]) : null, l = await a(), d = o.action === "create" || o.action === "clone" ? l?.documentId : o.params?.documentId;
|
|
262
262
|
if (!d) return l;
|
|
263
|
-
const
|
|
264
|
-
return await e.db.transaction(async ({ trx: b, onCommit:
|
|
265
|
-
const
|
|
266
|
-
|
|
263
|
+
const f = ge(e);
|
|
264
|
+
return await e.db.transaction(async ({ trx: b, onCommit: h }) => {
|
|
265
|
+
const m = re(b);
|
|
266
|
+
m.intents.push({
|
|
267
267
|
uid: s,
|
|
268
268
|
relatedDocumentId: d,
|
|
269
|
-
locale:
|
|
269
|
+
locale: i,
|
|
270
270
|
origin: o.action,
|
|
271
271
|
before: c
|
|
272
|
-
}), !
|
|
273
|
-
const
|
|
274
|
-
n().captureAll(ae(
|
|
275
|
-
(
|
|
272
|
+
}), !m.flushRegistered && (m.flushRegistered = !0, h(() => {
|
|
273
|
+
const T = m.intents.splice(0, m.intents.length);
|
|
274
|
+
n().captureAll(ae(T), f).catch(
|
|
275
|
+
(u) => e.log.error("[rewind] failed to record a version", u)
|
|
276
276
|
);
|
|
277
277
|
}));
|
|
278
278
|
}), l;
|
|
@@ -296,12 +296,12 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
296
296
|
const n = e.plugin("rewind").service("lock");
|
|
297
297
|
if (await n.acquire("prune", 30 * 60 * 1e3))
|
|
298
298
|
try {
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
`[rewind] thinned ${
|
|
299
|
+
const r = await e.plugin("rewind").service("retention").prune();
|
|
300
|
+
r.deleted > 0 && e.log.info(
|
|
301
|
+
`[rewind] thinned ${r.deleted} version(s) across ${r.documents} document(s)`
|
|
302
302
|
);
|
|
303
|
-
} catch (
|
|
304
|
-
e.log.error("[rewind] thinning failed",
|
|
303
|
+
} catch (r) {
|
|
304
|
+
e.log.error("[rewind] thinning failed", r);
|
|
305
305
|
} finally {
|
|
306
306
|
await n.release("prune");
|
|
307
307
|
}
|
|
@@ -371,10 +371,10 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
371
371
|
throw new Error(
|
|
372
372
|
'[rewind] config.contentTypes must be an array of content type uids, e.g. ["api::article.article"]'
|
|
373
373
|
);
|
|
374
|
-
const
|
|
375
|
-
if (
|
|
374
|
+
const r = t.filter((o) => !o.startsWith("api::"));
|
|
375
|
+
if (r.length > 0)
|
|
376
376
|
throw new Error(
|
|
377
|
-
`[rewind] config.contentTypes only supports api:: content types, received: ${
|
|
377
|
+
`[rewind] config.contentTypes only supports api:: content types, received: ${r.join(", ")}`
|
|
378
378
|
);
|
|
379
379
|
}
|
|
380
380
|
}, be = "collectionType", Te = "rewind_versions", ve = {
|
|
@@ -479,42 +479,44 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
479
479
|
"createdAt"
|
|
480
480
|
], Ee = ({ strapi: e }) => ({
|
|
481
481
|
async find(t) {
|
|
482
|
-
const { contentType: n, documentId:
|
|
483
|
-
if (!n || !
|
|
482
|
+
const { contentType: n, documentId: r, locale: o, page: a = 1, pageSize: s = 10 } = t.query;
|
|
483
|
+
if (!n || !r)
|
|
484
484
|
return t.badRequest("contentType and documentId are required.");
|
|
485
|
-
const
|
|
485
|
+
const i = {
|
|
486
486
|
contentType: n,
|
|
487
|
-
relatedDocumentId:
|
|
487
|
+
relatedDocumentId: r,
|
|
488
488
|
...o ? { locale: o } : {}
|
|
489
|
-
}, c = Math.min(Number(s) || 10, 100), l = (Math.max(Number(a) || 1, 1) - 1) * c, [d,
|
|
489
|
+
}, c = Math.min(Number(s) || 10, 100), l = (Math.max(Number(a) || 1, 1) - 1) * c, [d, f] = await Promise.all([
|
|
490
490
|
e.db.query(v).findMany({
|
|
491
491
|
select: qe,
|
|
492
|
-
where:
|
|
492
|
+
where: i,
|
|
493
493
|
orderBy: { createdAt: "desc" },
|
|
494
494
|
limit: c,
|
|
495
495
|
offset: l
|
|
496
496
|
}),
|
|
497
|
-
e.db.query(v).count({ where:
|
|
497
|
+
e.db.query(v).count({ where: i })
|
|
498
498
|
]);
|
|
499
499
|
t.body = {
|
|
500
|
-
data: await
|
|
501
|
-
meta: { page: Number(a) || 1, pageSize: c, total:
|
|
500
|
+
data: await B(e, d),
|
|
501
|
+
meta: { page: Number(a) || 1, pageSize: c, total: f }
|
|
502
502
|
};
|
|
503
503
|
},
|
|
504
504
|
async findOne(t) {
|
|
505
505
|
const n = await e.db.query(v).findOne({ where: { id: Number(t.params.id) } });
|
|
506
506
|
if (!n) return t.notFound("No such version.");
|
|
507
|
-
t.body = { data: (await
|
|
507
|
+
t.body = { data: (await B(e, [n]))[0] };
|
|
508
508
|
},
|
|
509
509
|
async diff(t) {
|
|
510
510
|
const { against: n } = t.query;
|
|
511
|
+
if (n !== void 0 && !Number.isInteger(Number(n)))
|
|
512
|
+
return t.badRequest("against must be a version id.");
|
|
511
513
|
try {
|
|
512
514
|
t.body = {
|
|
513
515
|
data: await e.plugin("rewind").service("diff").between(Number(t.params.id), n ? Number(n) : void 0)
|
|
514
516
|
};
|
|
515
|
-
} catch (
|
|
517
|
+
} catch (r) {
|
|
516
518
|
return t.badRequest(
|
|
517
|
-
|
|
519
|
+
r instanceof Error ? r.message : "Could not compare these versions."
|
|
518
520
|
);
|
|
519
521
|
}
|
|
520
522
|
},
|
|
@@ -540,8 +542,8 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
540
542
|
t.body = {
|
|
541
543
|
data: await e.plugin("rewind").service("pin").set(Number(t.params.id), n)
|
|
542
544
|
};
|
|
543
|
-
} catch (
|
|
544
|
-
return t.notFound(
|
|
545
|
+
} catch (r) {
|
|
546
|
+
return t.notFound(r instanceof Error ? r.message : "No such version.");
|
|
545
547
|
}
|
|
546
548
|
},
|
|
547
549
|
async restore(t) {
|
|
@@ -553,10 +555,10 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
553
555
|
return t.badRequest(n instanceof Error ? n.message : "Restore failed.");
|
|
554
556
|
}
|
|
555
557
|
}
|
|
556
|
-
}),
|
|
558
|
+
}), B = async (e, t) => {
|
|
557
559
|
const n = [...new Set(t.map((a) => a.userId).filter(Boolean))];
|
|
558
560
|
if (n.length === 0) return t.map((a) => ({ ...a, user: null }));
|
|
559
|
-
const
|
|
561
|
+
const r = await e.db.query("admin::user").findMany({ select: ["id", "firstname", "lastname", "email"], where: { id: n } }), o = new Map(r.map((a) => [a.id, a]));
|
|
560
562
|
return t.map((a) => {
|
|
561
563
|
const s = o.get(a.userId);
|
|
562
564
|
return {
|
|
@@ -611,29 +613,29 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
611
613
|
]
|
|
612
614
|
}, Ne = {
|
|
613
615
|
admin: $e
|
|
614
|
-
},
|
|
615
|
-
const n =
|
|
616
|
-
if (n.length >
|
|
616
|
+
}, L = (e) => e.match(/\S+\s*/g) ?? [], z = 2500, Fe = (e, t) => {
|
|
617
|
+
const n = L(e), r = L(t);
|
|
618
|
+
if (n.length > z || r.length > z)
|
|
617
619
|
return [
|
|
618
620
|
{ op: "removed", value: e },
|
|
619
621
|
{ op: "added", value: t }
|
|
620
622
|
];
|
|
621
623
|
const o = Array.from(
|
|
622
624
|
{ length: n.length + 1 },
|
|
623
|
-
() => new Array(
|
|
625
|
+
() => new Array(r.length + 1).fill(0)
|
|
624
626
|
);
|
|
625
627
|
for (let l = n.length - 1; l >= 0; l -= 1)
|
|
626
|
-
for (let d =
|
|
627
|
-
o[l][d] = n[l] ===
|
|
628
|
+
for (let d = r.length - 1; d >= 0; d -= 1)
|
|
629
|
+
o[l][d] = n[l] === r[d] ? o[l + 1][d + 1] + 1 : Math.max(o[l + 1][d], o[l][d + 1]);
|
|
628
630
|
const a = [], s = (l, d) => {
|
|
629
|
-
const
|
|
630
|
-
|
|
631
|
+
const f = a[a.length - 1];
|
|
632
|
+
f && f.op === l ? f.value += d : a.push({ op: l, value: d });
|
|
631
633
|
};
|
|
632
|
-
let
|
|
633
|
-
for (;
|
|
634
|
-
n[
|
|
635
|
-
for (;
|
|
636
|
-
for (; c <
|
|
634
|
+
let i = 0, c = 0;
|
|
635
|
+
for (; i < n.length && c < r.length; )
|
|
636
|
+
n[i] === r[c] ? (s("equal", n[i]), i += 1, c += 1) : o[i + 1][c] >= o[i][c + 1] ? (s("removed", n[i]), i += 1) : (s("added", r[c]), c += 1);
|
|
637
|
+
for (; i < n.length; ) s("removed", n[i++]);
|
|
638
|
+
for (; c < r.length; ) s("added", r[c++]);
|
|
637
639
|
return a;
|
|
638
640
|
}, _e = /* @__PURE__ */ new Set([
|
|
639
641
|
"id",
|
|
@@ -643,19 +645,19 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
643
645
|
"level",
|
|
644
646
|
"language",
|
|
645
647
|
"url"
|
|
646
|
-
]),
|
|
648
|
+
]), R = (e, t = 0) => t > 12 || e == null ? "" : typeof e == "string" ? e : typeof e == "boolean" ? "" : typeof e == "number" ? String(e) : Array.isArray(e) ? e.map((n) => R(n, t + 1)).filter(Boolean).join(" ") : typeof e == "object" ? Object.entries(e).filter(([n]) => !_e.has(n)).map(([, n]) => R(n, t + 1)).filter(Boolean).join(" ") : "", P = (e) => e.replace(/\s+/g, " ").trim(), je = 6, Ce = (e, t = je) => {
|
|
647
649
|
const n = [];
|
|
648
|
-
return e.forEach((
|
|
649
|
-
if (
|
|
650
|
-
n.push(
|
|
650
|
+
return e.forEach((r, o) => {
|
|
651
|
+
if (r.op !== "equal") {
|
|
652
|
+
n.push(r);
|
|
651
653
|
return;
|
|
652
654
|
}
|
|
653
|
-
const a =
|
|
655
|
+
const a = r.value.match(/\S+\s*/g) ?? [];
|
|
654
656
|
if (a.length <= t * 2 + 1) {
|
|
655
|
-
n.push(
|
|
657
|
+
n.push(r);
|
|
656
658
|
return;
|
|
657
659
|
}
|
|
658
|
-
const s = o === 0,
|
|
660
|
+
const s = o === 0, i = o === e.length - 1, c = s ? [] : a.slice(0, t), l = i ? [] : a.slice(-t);
|
|
659
661
|
c.length && n.push({ op: "equal", value: c.join("") }), n.push({ op: "equal", value: " … " }), l.length && n.push({ op: "equal", value: l.join("") });
|
|
660
662
|
}), n;
|
|
661
663
|
}, Me = /* @__PURE__ */ new Set([
|
|
@@ -673,7 +675,7 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
673
675
|
"uid",
|
|
674
676
|
"email",
|
|
675
677
|
"password"
|
|
676
|
-
]), Ue = (e, t) => e === "text" || e === "richtext" || e === "blocks" || e === "json" || e === "customField" || e === "component" || e === "dynamiczone" || e === "string" && typeof t == "string" && t.length > 80,
|
|
678
|
+
]), Ue = (e, t) => e === "text" || e === "richtext" || e === "blocks" || e === "json" || e === "customField" || e === "component" || e === "dynamiczone" || e === "string" && typeof t == "string" && t.length > 80, q = (e) => `${e.targetUid}:${e.documentId ?? e.id}`, Be = ({ strapi: e }) => {
|
|
677
679
|
const t = (o) => o && {
|
|
678
680
|
id: o.id,
|
|
679
681
|
label: o.label ?? null,
|
|
@@ -683,7 +685,7 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
683
685
|
const a = await e.db.query(v).findOne({ where: { id: o } });
|
|
684
686
|
if (!a) throw new Error(`No version with id ${o}`);
|
|
685
687
|
return a;
|
|
686
|
-
},
|
|
688
|
+
}, r = async (o) => {
|
|
687
689
|
const [a] = await e.db.query(v).findMany({
|
|
688
690
|
where: {
|
|
689
691
|
contentType: o.contentType,
|
|
@@ -706,46 +708,51 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
706
708
|
* change?", is what `restore.preview()` already answers.
|
|
707
709
|
*/
|
|
708
710
|
async between(o, a) {
|
|
709
|
-
const s = await n(o),
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
711
|
+
const s = await n(o), i = a ? await n(a) : null;
|
|
712
|
+
if (i && (i.contentType !== s.contentType || i.relatedDocumentId !== s.relatedDocumentId || i.locale !== s.locale))
|
|
713
|
+
throw new Error("Those two versions are not of the same document and locale.");
|
|
714
|
+
let c, l;
|
|
715
|
+
i ? (c = i.id < s.id ? i : s, l = i.id < s.id ? s : i) : (c = await r(s), l = s);
|
|
716
|
+
const d = e.getModel(l.contentType)?.attributes, f = l.data ?? {}, b = c?.data ?? {}, h = l.relations ?? {}, m = c?.relations ?? {}, T = [];
|
|
717
|
+
for (const u of /* @__PURE__ */ new Set([...Object.keys(b), ...Object.keys(f)])) {
|
|
718
|
+
const y = b[u], w = f[u];
|
|
719
|
+
if (JSON.stringify(y) === JSON.stringify(w)) continue;
|
|
720
|
+
const p = d?.[u]?.type ?? "unknown", D = d?.[u]?.customField, A = y === void 0 ? "added" : w === void 0 ? "removed" : "changed";
|
|
721
|
+
if (Me.has(p) && !Ue(p, y ?? w)) {
|
|
722
|
+
T.push({ field: u, type: p, customField: D, kind: A, before: y, after: w });
|
|
716
723
|
continue;
|
|
717
724
|
}
|
|
718
|
-
const
|
|
719
|
-
if (
|
|
720
|
-
|
|
725
|
+
const I = P(R(y)), O = P(R(w));
|
|
726
|
+
if (I === O) {
|
|
727
|
+
T.push({ field: u, type: p, customField: D, kind: A, before: void 0, after: void 0 });
|
|
721
728
|
continue;
|
|
722
729
|
}
|
|
723
|
-
|
|
730
|
+
T.push({
|
|
724
731
|
field: u,
|
|
725
|
-
type:
|
|
726
|
-
customField:
|
|
727
|
-
kind:
|
|
732
|
+
type: p,
|
|
733
|
+
customField: D,
|
|
734
|
+
kind: A,
|
|
728
735
|
// Collapsed here rather than in the panel: sending an entire article
|
|
729
736
|
// to highlight one word wastes the payload as well as the reader's
|
|
730
737
|
// attention.
|
|
731
|
-
spans: Ce(Fe(
|
|
738
|
+
spans: Ce(Fe(I, O))
|
|
732
739
|
});
|
|
733
740
|
}
|
|
734
|
-
for (const u of /* @__PURE__ */ new Set([...Object.keys(
|
|
735
|
-
const
|
|
736
|
-
|
|
741
|
+
for (const u of /* @__PURE__ */ new Set([...Object.keys(m), ...Object.keys(h)])) {
|
|
742
|
+
const y = m[u] ?? [], w = h[u] ?? [], p = new Set(y.map(q)), D = new Set(w.map(q)), A = w.filter((O) => !p.has(q(O))), I = y.filter((O) => !D.has(q(O)));
|
|
743
|
+
A.length === 0 && I.length === 0 || T.push({
|
|
737
744
|
field: u,
|
|
738
|
-
type:
|
|
745
|
+
type: d?.[u]?.type ?? "relation",
|
|
739
746
|
kind: "changed",
|
|
740
|
-
linked:
|
|
741
|
-
unlinked:
|
|
747
|
+
linked: A,
|
|
748
|
+
unlinked: I
|
|
742
749
|
});
|
|
743
750
|
}
|
|
744
751
|
return {
|
|
745
|
-
from:
|
|
746
|
-
to: t(
|
|
747
|
-
changes:
|
|
748
|
-
identical:
|
|
752
|
+
from: c ? t(c) : null,
|
|
753
|
+
to: t(l),
|
|
754
|
+
changes: T,
|
|
755
|
+
identical: T.length === 0
|
|
749
756
|
};
|
|
750
757
|
}
|
|
751
758
|
};
|
|
@@ -756,11 +763,11 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
756
763
|
key: `lock:${n}`
|
|
757
764
|
});
|
|
758
765
|
return {
|
|
759
|
-
async acquire(n,
|
|
766
|
+
async acquire(n, r) {
|
|
760
767
|
const o = await e.store.get(t(n));
|
|
761
768
|
return o && o.expires > Date.now() ? !1 : (await e.store.set({
|
|
762
769
|
...t(n),
|
|
763
|
-
value: { expires: Date.now() +
|
|
770
|
+
value: { expires: Date.now() + r }
|
|
764
771
|
}), !0);
|
|
765
772
|
},
|
|
766
773
|
async release(n) {
|
|
@@ -771,46 +778,46 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
771
778
|
async set(t, n) {
|
|
772
779
|
if (!Number.isInteger(t))
|
|
773
780
|
throw new Error("A version id is required.");
|
|
774
|
-
const
|
|
775
|
-
if (!
|
|
781
|
+
const r = await e.db.query(v).findOne({ where: { id: t }, select: ["id", "pinned"] });
|
|
782
|
+
if (!r)
|
|
776
783
|
throw new Error(`No version with id ${t}`);
|
|
777
|
-
return !!
|
|
784
|
+
return !!r.pinned === n ? { id: t, pinned: n } : (await e.db.query(v).update({ where: { id: t }, data: { pinned: n } }), { id: t, pinned: n });
|
|
778
785
|
}
|
|
779
|
-
}),
|
|
786
|
+
}), G = {
|
|
780
787
|
keepAllDays: 7,
|
|
781
788
|
dailyUntilDays: 30,
|
|
782
789
|
maxAgeDays: 365,
|
|
783
790
|
keepAnchors: !0
|
|
784
|
-
}, Pe = /* @__PURE__ */ new Set(["publish", "unpublish", "discardDraft", "restore"]),
|
|
791
|
+
}, Pe = /* @__PURE__ */ new Set(["publish", "unpublish", "discardDraft", "restore"]), V = 24 * 60 * 60 * 1e3, Ye = (e, t) => (t.getTime() - new Date(e).getTime()) / V, He = (e) => e.toISOString().slice(0, 10), We = (e) => {
|
|
785
792
|
const t = new Date(Date.UTC(e.getUTCFullYear(), e.getUTCMonth(), e.getUTCDate())), n = t.getUTCDay() || 7;
|
|
786
793
|
t.setUTCDate(t.getUTCDate() + 4 - n);
|
|
787
|
-
const
|
|
794
|
+
const r = new Date(Date.UTC(t.getUTCFullYear(), 0, 1)), o = Math.ceil(((t.getTime() - r.getTime()) / V + 1) / 7);
|
|
788
795
|
return `${t.getUTCFullYear()}-W${o}`;
|
|
789
|
-
}, Ke = (e, t, n =
|
|
790
|
-
const
|
|
791
|
-
(s,
|
|
796
|
+
}, Ke = (e, t, n = G) => {
|
|
797
|
+
const r = /* @__PURE__ */ new Map(), o = [], a = [...e].sort(
|
|
798
|
+
(s, i) => new Date(i.createdAt).getTime() - new Date(s.createdAt).getTime()
|
|
792
799
|
);
|
|
793
800
|
for (const s of a) {
|
|
794
801
|
if (s.pinned || n.keepAnchors && Pe.has(s.origin)) continue;
|
|
795
|
-
const
|
|
796
|
-
if (
|
|
797
|
-
if (
|
|
802
|
+
const i = Ye(s.createdAt, t);
|
|
803
|
+
if (i <= n.keepAllDays) continue;
|
|
804
|
+
if (i > n.maxAgeDays) {
|
|
798
805
|
o.push(s.id);
|
|
799
806
|
continue;
|
|
800
807
|
}
|
|
801
|
-
const c = new Date(s.createdAt), l =
|
|
802
|
-
|
|
808
|
+
const c = new Date(s.createdAt), l = i <= n.dailyUntilDays ? `d:${He(c)}` : `w:${We(c)}`;
|
|
809
|
+
r.has(l) ? o.push(s.id) : r.set(l, s);
|
|
803
810
|
}
|
|
804
811
|
return o;
|
|
805
|
-
},
|
|
806
|
-
const t = () => e.db.query(v), n = async (
|
|
812
|
+
}, Y = 500, Ge = ({ strapi: e }) => {
|
|
813
|
+
const t = () => e.db.query(v), n = async (r) => {
|
|
807
814
|
const o = await t().findMany({
|
|
808
815
|
select: ["contentType", "relatedDocumentId", "locale"],
|
|
809
|
-
where: { createdAt: { $lt:
|
|
816
|
+
where: { createdAt: { $lt: r } }
|
|
810
817
|
}), a = /* @__PURE__ */ new Map();
|
|
811
818
|
for (const s of o) {
|
|
812
|
-
const
|
|
813
|
-
a.has(
|
|
819
|
+
const i = `${s.contentType}|${s.relatedDocumentId}|${s.locale ?? ""}`;
|
|
820
|
+
a.has(i) || a.set(i, {
|
|
814
821
|
contentType: s.contentType,
|
|
815
822
|
relatedDocumentId: s.relatedDocumentId,
|
|
816
823
|
locale: s.locale ?? null
|
|
@@ -825,14 +832,14 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
825
832
|
* Returns what it did rather than logging and forgetting, so the cron can
|
|
826
833
|
* report it and a test can assert on it.
|
|
827
834
|
*/
|
|
828
|
-
async prune(
|
|
829
|
-
const o = e.config.get("plugin::rewind"), a = { ...
|
|
835
|
+
async prune(r = /* @__PURE__ */ new Date()) {
|
|
836
|
+
const o = e.config.get("plugin::rewind"), a = { ...G, ...o?.retention };
|
|
830
837
|
if (o?.retention?.enabled === !1)
|
|
831
838
|
return { scanned: 0, deleted: 0, documents: 0 };
|
|
832
|
-
const s = new Date(
|
|
839
|
+
const s = new Date(r.getTime() - a.keepAllDays * 24 * 60 * 60 * 1e3), i = await n(s);
|
|
833
840
|
let c = 0, l = 0;
|
|
834
|
-
for (const d of
|
|
835
|
-
const
|
|
841
|
+
for (const d of i) {
|
|
842
|
+
const f = await t().findMany({
|
|
836
843
|
select: ["id", "createdAt", "origin", "pinned"],
|
|
837
844
|
where: {
|
|
838
845
|
contentType: d.contentType,
|
|
@@ -840,23 +847,23 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
840
847
|
locale: d.locale
|
|
841
848
|
}
|
|
842
849
|
});
|
|
843
|
-
c +=
|
|
844
|
-
const b = Ke(
|
|
845
|
-
for (let
|
|
846
|
-
const
|
|
847
|
-
await t().deleteMany({ where: { id: { $in:
|
|
850
|
+
c += f.length;
|
|
851
|
+
const b = Ke(f, r, a);
|
|
852
|
+
for (let h = 0; h < b.length; h += Y) {
|
|
853
|
+
const m = b.slice(h, h + Y);
|
|
854
|
+
await t().deleteMany({ where: { id: { $in: m } } }), l += m.length;
|
|
848
855
|
}
|
|
849
856
|
}
|
|
850
|
-
return { scanned: c, deleted: l, documents:
|
|
857
|
+
return { scanned: c, deleted: l, documents: i.length };
|
|
851
858
|
}
|
|
852
859
|
};
|
|
853
860
|
}, Ve = ({ strapi: e }) => {
|
|
854
861
|
const t = (s) => e.getModel(s), n = async (s) => {
|
|
855
|
-
const
|
|
856
|
-
if (!
|
|
862
|
+
const i = await e.db.query(v).findOne({ where: { id: s } });
|
|
863
|
+
if (!i)
|
|
857
864
|
throw new Error(`No version with id ${s}`);
|
|
858
|
-
return
|
|
859
|
-
},
|
|
865
|
+
return i;
|
|
866
|
+
}, r = (s) => s?.pluginOptions?.i18n?.localized === !0, o = (s) => e.contentTypes[s]?.pluginOptions?.i18n?.localized === !0, a = async (s) => s.targetUid === "plugin::upload.file" ? !!await e.db.query("plugin::upload.file").findOne({ where: { id: s.id } }) : !!await e.db.query(s.targetUid).findOne({
|
|
860
867
|
where: {
|
|
861
868
|
documentId: s.documentId,
|
|
862
869
|
...s.locale ? { locale: s.locale } : {}
|
|
@@ -872,21 +879,21 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
872
879
|
* version of a document quietly rewrites a field in every other language.
|
|
873
880
|
*/
|
|
874
881
|
async preview(s) {
|
|
875
|
-
const
|
|
876
|
-
for (const [
|
|
877
|
-
if (
|
|
878
|
-
for (const
|
|
879
|
-
await a(
|
|
880
|
-
const
|
|
882
|
+
const i = await n(s), c = i.contentType, l = t(c).attributes, d = i.schemaSnapshot?.attributes ?? {}, f = i.data ?? {}, b = i.relations ?? {}, h = Object.keys(l).filter((g) => !E.includes(g)), m = Object.keys(d), T = m.filter((g) => !h.includes(g)), u = h.filter((g) => !m.includes(g)), y = m.filter((g) => h.includes(g)), w = y.filter((g) => F(l[g])), p = y.filter((g) => !w.includes(g)), D = o(c) ? p.filter((g) => !r(l[g])) : [], A = [], I = [];
|
|
883
|
+
for (const [g, X] of Object.entries(b))
|
|
884
|
+
if (p.includes(g))
|
|
885
|
+
for (const S of X)
|
|
886
|
+
await a(S) || (S.targetUid === "plugin::upload.file" ? I.push(S) : A.push(S));
|
|
887
|
+
const O = D.length ? await e.plugin("i18n")?.service("locales").find() : [];
|
|
881
888
|
return {
|
|
882
|
-
fieldsToRestore:
|
|
883
|
-
fieldsKeptAsIs:
|
|
884
|
-
fieldsDropped:
|
|
889
|
+
fieldsToRestore: p.filter((g) => g in f),
|
|
890
|
+
fieldsKeptAsIs: u,
|
|
891
|
+
fieldsDropped: T,
|
|
885
892
|
crossLocaleFields: D,
|
|
886
|
-
unsupportedFields:
|
|
893
|
+
unsupportedFields: w,
|
|
887
894
|
brokenRelations: A,
|
|
888
|
-
missingMedia:
|
|
889
|
-
affectedLocales:
|
|
895
|
+
missingMedia: I,
|
|
896
|
+
affectedLocales: O.map((g) => g.code)
|
|
890
897
|
};
|
|
891
898
|
},
|
|
892
899
|
/**
|
|
@@ -895,8 +902,8 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
895
902
|
* The document lands in "modified" and publishing stays a deliberate act -
|
|
896
903
|
* restoring must never change what the public sees on its own.
|
|
897
904
|
*/
|
|
898
|
-
async apply(s,
|
|
899
|
-
const c = await n(s), l = c.contentType, d = await this.preview(s),
|
|
905
|
+
async apply(s, i) {
|
|
906
|
+
const c = await n(s), l = c.contentType, d = await this.preview(s), f = [];
|
|
900
907
|
await e.plugin("rewind").service("snapshot").capture(
|
|
901
908
|
{
|
|
902
909
|
uid: l,
|
|
@@ -905,30 +912,30 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
905
912
|
origin: "restore",
|
|
906
913
|
before: null
|
|
907
914
|
},
|
|
908
|
-
|
|
915
|
+
i
|
|
909
916
|
);
|
|
910
|
-
const b = {},
|
|
911
|
-
for (const
|
|
912
|
-
b[
|
|
913
|
-
const
|
|
917
|
+
const b = {}, h = c.data ?? {}, m = c.relations ?? {};
|
|
918
|
+
for (const u of d.fieldsToRestore)
|
|
919
|
+
b[u] = h[u];
|
|
920
|
+
const T = new Set(
|
|
914
921
|
[...d.brokenRelations, ...d.missingMedia].map(
|
|
915
|
-
(
|
|
922
|
+
(u) => `${u.targetUid}:${u.documentId ?? u.id}`
|
|
916
923
|
)
|
|
917
924
|
);
|
|
918
|
-
for (const [
|
|
919
|
-
if (d.unsupportedFields.includes(
|
|
920
|
-
const
|
|
921
|
-
(
|
|
925
|
+
for (const [u, y] of Object.entries(m)) {
|
|
926
|
+
if (d.unsupportedFields.includes(u) || d.fieldsDropped.includes(u)) continue;
|
|
927
|
+
const w = y.filter(
|
|
928
|
+
(p) => !T.has(`${p.targetUid}:${p.documentId ?? p.id}`)
|
|
922
929
|
);
|
|
923
|
-
|
|
924
|
-
`${
|
|
925
|
-
), b[
|
|
926
|
-
(
|
|
930
|
+
w.length !== y.length && f.push(
|
|
931
|
+
`${y.length - w.length} target(s) of "${u}" no longer exist and were skipped.`
|
|
932
|
+
), b[u] = w.map(
|
|
933
|
+
(p) => p.targetUid === "plugin::upload.file" ? p.id : p.documentId
|
|
927
934
|
);
|
|
928
935
|
}
|
|
929
|
-
return d.fieldsDropped.length &&
|
|
936
|
+
return d.fieldsDropped.length && f.push(
|
|
930
937
|
`Skipped ${d.fieldsDropped.length} field(s) no longer in the model: ${d.fieldsDropped.join(", ")}.`
|
|
931
|
-
), d.crossLocaleFields.length &&
|
|
938
|
+
), d.crossLocaleFields.length && f.push(
|
|
932
939
|
`${d.crossLocaleFields.join(", ")} are not localised, so they changed in every locale.`
|
|
933
940
|
), await ce(async () => {
|
|
934
941
|
await e.documents(l).update({
|
|
@@ -939,7 +946,7 @@ const Q = ["id", "documentId", "locale"], S = [
|
|
|
939
946
|
status: "draft",
|
|
940
947
|
data: b
|
|
941
948
|
});
|
|
942
|
-
}), { documentId: c.relatedDocumentId, warnings:
|
|
949
|
+
}), { documentId: c.relatedDocumentId, warnings: f };
|
|
943
950
|
}
|
|
944
951
|
};
|
|
945
952
|
}, Xe = {
|