@strapi/upload 5.9.0 → 5.10.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/dist/admin/chunks/App-BJY37n6T.js +993 -0
- package/dist/admin/chunks/App-BJY37n6T.js.map +1 -0
- package/dist/admin/chunks/App-DcpAXZuK.mjs +972 -0
- package/dist/admin/chunks/App-DcpAXZuK.mjs.map +1 -0
- package/dist/admin/chunks/ConfigureTheView-Bwf5I3Vq.mjs +276 -0
- package/dist/admin/chunks/ConfigureTheView-Bwf5I3Vq.mjs.map +1 -0
- package/dist/admin/chunks/ConfigureTheView-CnUk2xYx.js +297 -0
- package/dist/admin/chunks/ConfigureTheView-CnUk2xYx.js.map +1 -0
- package/dist/admin/chunks/SettingsPage-7DUsHuJU.js +354 -0
- package/dist/admin/chunks/SettingsPage-7DUsHuJU.js.map +1 -0
- package/dist/admin/chunks/SettingsPage-DJe31MUj.mjs +332 -0
- package/dist/admin/chunks/SettingsPage-DJe31MUj.mjs.map +1 -0
- package/dist/admin/chunks/ca-Bi4qskZD.mjs +120 -0
- package/dist/{_chunks/es-CuWi2pOn.mjs.map → admin/chunks/ca-Bi4qskZD.mjs.map} +1 -1
- package/dist/admin/chunks/ca-pCOhKIn8.js +122 -0
- package/dist/{_chunks/es-DWFtw_h4.js.map → admin/chunks/ca-pCOhKIn8.js.map} +1 -1
- package/dist/admin/chunks/de-BlbX8Dl_.mjs +106 -0
- package/dist/{_chunks/pl-Cj8jChOO.mjs.map → admin/chunks/de-BlbX8Dl_.mjs.map} +1 -1
- package/dist/admin/chunks/de-DUjKLmOP.js +108 -0
- package/dist/{_chunks/de-uGb_Pkq7.js.map → admin/chunks/de-DUjKLmOP.js.map} +1 -1
- package/dist/admin/chunks/dk-C2ydE6A7.mjs +102 -0
- package/dist/{_chunks/ko-vJl9kPpn.mjs.map → admin/chunks/dk-C2ydE6A7.mjs.map} +1 -1
- package/dist/admin/chunks/dk-DSsspA0e.js +104 -0
- package/dist/{_chunks/dk-Cd8oFO-O.js.map → admin/chunks/dk-DSsspA0e.js.map} +1 -1
- package/dist/admin/chunks/en-Bw_Cb2IV.mjs +143 -0
- package/dist/{_chunks/en-oDx2Gnre.mjs.map → admin/chunks/en-Bw_Cb2IV.mjs.map} +1 -1
- package/dist/admin/chunks/en-UjETkewz.js +145 -0
- package/dist/{_chunks/en-BcOqhiNe.js.map → admin/chunks/en-UjETkewz.js.map} +1 -1
- package/dist/admin/chunks/es-CiEgbw0k.mjs +119 -0
- package/dist/{_chunks/ca-B2_I-q1t.mjs.map → admin/chunks/es-CiEgbw0k.mjs.map} +1 -1
- package/dist/admin/chunks/es-qAL8YcZz.js +121 -0
- package/dist/{_chunks/ca-BUpuZx8N.js.map → admin/chunks/es-qAL8YcZz.js.map} +1 -1
- package/dist/admin/chunks/fr-BL0Uyj6j.js +145 -0
- package/dist/admin/chunks/fr-BL0Uyj6j.js.map +1 -0
- package/dist/admin/chunks/fr-CwRt2FJu.mjs +143 -0
- package/dist/admin/chunks/fr-CwRt2FJu.mjs.map +1 -0
- package/dist/admin/chunks/he-BAmhVpfZ.js +77 -0
- package/dist/admin/chunks/he-BAmhVpfZ.js.map +1 -0
- package/dist/admin/chunks/he-DdpYNQdt.mjs +75 -0
- package/dist/admin/chunks/he-DdpYNQdt.mjs.map +1 -0
- package/dist/admin/chunks/index-DAhjYc5x.mjs +7350 -0
- package/dist/admin/chunks/index-DAhjYc5x.mjs.map +1 -0
- package/dist/admin/chunks/index-jZnIE90w.js +7407 -0
- package/dist/admin/chunks/index-jZnIE90w.js.map +1 -0
- package/dist/admin/chunks/it-Be4kgSNB.mjs +75 -0
- package/dist/admin/chunks/it-Be4kgSNB.mjs.map +1 -0
- package/dist/admin/chunks/it-_NQZYepl.js +77 -0
- package/dist/admin/chunks/it-_NQZYepl.js.map +1 -0
- package/dist/admin/chunks/ja-B75QiyXf.js +77 -0
- package/dist/admin/chunks/ja-B75QiyXf.js.map +1 -0
- package/dist/admin/chunks/ja-U1NhT0bU.mjs +75 -0
- package/dist/admin/chunks/ja-U1NhT0bU.mjs.map +1 -0
- package/dist/admin/chunks/ko-BOvUcJqv.js +107 -0
- package/dist/{_chunks/pl-esgZ7ltN.js.map → admin/chunks/ko-BOvUcJqv.js.map} +1 -1
- package/dist/admin/chunks/ko-BciqXefq.mjs +105 -0
- package/dist/{_chunks/de-A7mEKx6c.mjs.map → admin/chunks/ko-BciqXefq.mjs.map} +1 -1
- package/dist/admin/chunks/ms-B7Zl6Lm9.js +69 -0
- package/dist/admin/chunks/ms-B7Zl6Lm9.js.map +1 -0
- package/dist/admin/chunks/ms-D-8McNeg.mjs +67 -0
- package/dist/admin/chunks/ms-D-8McNeg.mjs.map +1 -0
- package/dist/admin/chunks/pl-DdUYocl5.mjs +104 -0
- package/dist/{_chunks/dk-BPfkJb9q.mjs.map → admin/chunks/pl-DdUYocl5.mjs.map} +1 -1
- package/dist/admin/chunks/pl-cYDYHOEf.js +106 -0
- package/dist/{_chunks/ko-Pzj-818C.js.map → admin/chunks/pl-cYDYHOEf.js.map} +1 -1
- package/dist/admin/chunks/pt-BR-D1u_azCM.js +77 -0
- package/dist/admin/chunks/pt-BR-D1u_azCM.js.map +1 -0
- package/dist/admin/chunks/pt-BR-Demjoq41.mjs +75 -0
- package/dist/admin/chunks/pt-BR-Demjoq41.mjs.map +1 -0
- package/dist/admin/chunks/pt-D8is2LpS.mjs +75 -0
- package/dist/admin/chunks/pt-D8is2LpS.mjs.map +1 -0
- package/dist/admin/chunks/pt-L2DZeTPL.js +77 -0
- package/dist/admin/chunks/pt-L2DZeTPL.js.map +1 -0
- package/dist/admin/chunks/ru-CGgHRTey.mjs +75 -0
- package/dist/admin/chunks/ru-CGgHRTey.mjs.map +1 -0
- package/dist/admin/chunks/ru-Uxbk_WWv.js +77 -0
- package/dist/admin/chunks/ru-Uxbk_WWv.js.map +1 -0
- package/dist/admin/chunks/sk-BlLP5HAX.js +123 -0
- package/dist/admin/chunks/sk-BlLP5HAX.js.map +1 -0
- package/dist/admin/chunks/sk-xtSwaPXq.mjs +121 -0
- package/dist/admin/chunks/sk-xtSwaPXq.mjs.map +1 -0
- package/dist/admin/chunks/th-BOpLVfmg.mjs +75 -0
- package/dist/admin/chunks/th-BOpLVfmg.mjs.map +1 -0
- package/dist/admin/chunks/th-DNxPLegS.js +77 -0
- package/dist/admin/chunks/th-DNxPLegS.js.map +1 -0
- package/dist/admin/chunks/tr-BmAPh-f1.mjs +121 -0
- package/dist/admin/chunks/tr-BmAPh-f1.mjs.map +1 -0
- package/dist/admin/chunks/tr-DWgXG75k.js +123 -0
- package/dist/admin/chunks/tr-DWgXG75k.js.map +1 -0
- package/dist/admin/chunks/uk-CMvuEdG-.mjs +72 -0
- package/dist/admin/chunks/uk-CMvuEdG-.mjs.map +1 -0
- package/dist/admin/chunks/uk-D1_rBLhp.js +74 -0
- package/dist/admin/chunks/uk-D1_rBLhp.js.map +1 -0
- package/dist/admin/chunks/zh-BIl0qgBy.mjs +128 -0
- package/dist/admin/chunks/zh-BIl0qgBy.mjs.map +1 -0
- package/dist/admin/chunks/zh-Hans-B1GabBRx.mjs +151 -0
- package/dist/{_chunks/zh-Hans-Cpmhg8uH.mjs.map → admin/chunks/zh-Hans-B1GabBRx.mjs.map} +1 -1
- package/dist/admin/chunks/zh-Hans-B8qxMQIl.js +153 -0
- package/dist/{_chunks/zh-Hans-k_xAc6nm.js.map → admin/chunks/zh-Hans-B8qxMQIl.js.map} +1 -1
- package/dist/admin/chunks/zh-MemsyMV6.js +130 -0
- package/dist/admin/chunks/zh-MemsyMV6.js.map +1 -0
- package/dist/admin/index.js +29 -6
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +24 -8
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/src/hooks/useMediaLibraryPermissions.d.ts +2 -5
- package/dist/admin/src/hooks/useRemoveAsset.d.ts +6 -64
- package/dist/server/chunks/graphql-BTbIs_EU.js +116 -0
- package/dist/server/chunks/graphql-BTbIs_EU.js.map +1 -0
- package/dist/server/chunks/graphql-CCPJbCFt.mjs +114 -0
- package/dist/server/chunks/graphql-CCPJbCFt.mjs.map +1 -0
- package/dist/server/chunks/index-BU4qzb-i.mjs +3161 -0
- package/dist/server/chunks/index-BU4qzb-i.mjs.map +1 -0
- package/dist/server/chunks/index-BkUy20d9.js +3164 -0
- package/dist/server/chunks/index-BkUy20d9.js.map +1 -0
- package/dist/server/index.js +19 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +14 -4
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/validation/admin/folder-file.d.ts.map +1 -1
- package/dist/shared/contracts/configuration.d.ts +1 -1
- package/dist/shared/contracts/settings.d.ts +1 -1
- package/package.json +13 -9
- package/dist/_chunks/App-BLY6RlTm.mjs +0 -844
- package/dist/_chunks/App-BLY6RlTm.mjs.map +0 -1
- package/dist/_chunks/App-DNScJAhi.js +0 -864
- package/dist/_chunks/App-DNScJAhi.js.map +0 -1
- package/dist/_chunks/ConfigureTheView-CJbBTq0t.js +0 -252
- package/dist/_chunks/ConfigureTheView-CJbBTq0t.js.map +0 -1
- package/dist/_chunks/ConfigureTheView-Dk28Sh2k.mjs +0 -230
- package/dist/_chunks/ConfigureTheView-Dk28Sh2k.mjs.map +0 -1
- package/dist/_chunks/SettingsPage-CrvbJCia.js +0 -285
- package/dist/_chunks/SettingsPage-CrvbJCia.js.map +0 -1
- package/dist/_chunks/SettingsPage-DjNyJDaf.mjs +0 -264
- package/dist/_chunks/SettingsPage-DjNyJDaf.mjs.map +0 -1
- package/dist/_chunks/ca-B2_I-q1t.mjs +0 -121
- package/dist/_chunks/ca-BUpuZx8N.js +0 -121
- package/dist/_chunks/de-A7mEKx6c.mjs +0 -107
- package/dist/_chunks/de-uGb_Pkq7.js +0 -107
- package/dist/_chunks/dk-BPfkJb9q.mjs +0 -103
- package/dist/_chunks/dk-Cd8oFO-O.js +0 -103
- package/dist/_chunks/en-BcOqhiNe.js +0 -144
- package/dist/_chunks/en-oDx2Gnre.mjs +0 -144
- package/dist/_chunks/es-CuWi2pOn.mjs +0 -120
- package/dist/_chunks/es-DWFtw_h4.js +0 -120
- package/dist/_chunks/fr-BN6ndmWf.mjs +0 -144
- package/dist/_chunks/fr-BN6ndmWf.mjs.map +0 -1
- package/dist/_chunks/fr-D2bop66d.js +0 -144
- package/dist/_chunks/fr-D2bop66d.js.map +0 -1
- package/dist/_chunks/graphql-DMPTPlvx.mjs +0 -71
- package/dist/_chunks/graphql-DMPTPlvx.mjs.map +0 -1
- package/dist/_chunks/graphql-QF5Y36Qj.js +0 -71
- package/dist/_chunks/graphql-QF5Y36Qj.js.map +0 -1
- package/dist/_chunks/he-BpxHjaZg.js +0 -76
- package/dist/_chunks/he-BpxHjaZg.js.map +0 -1
- package/dist/_chunks/he-C9ZOXBB-.mjs +0 -76
- package/dist/_chunks/he-C9ZOXBB-.mjs.map +0 -1
- package/dist/_chunks/index-BfAVIhAL.js +0 -6144
- package/dist/_chunks/index-BfAVIhAL.js.map +0 -1
- package/dist/_chunks/index-D57iKFts.js +0 -2721
- package/dist/_chunks/index-D57iKFts.js.map +0 -1
- package/dist/_chunks/index-DH9hUSe3.mjs +0 -6119
- package/dist/_chunks/index-DH9hUSe3.mjs.map +0 -1
- package/dist/_chunks/index-sOlgMDiZ.mjs +0 -2711
- package/dist/_chunks/index-sOlgMDiZ.mjs.map +0 -1
- package/dist/_chunks/it-B7rmoZNx.mjs +0 -76
- package/dist/_chunks/it-B7rmoZNx.mjs.map +0 -1
- package/dist/_chunks/it-BKCWXl8t.js +0 -76
- package/dist/_chunks/it-BKCWXl8t.js.map +0 -1
- package/dist/_chunks/ja-DlaJTi_3.mjs +0 -76
- package/dist/_chunks/ja-DlaJTi_3.mjs.map +0 -1
- package/dist/_chunks/ja-ajHzIJz6.js +0 -76
- package/dist/_chunks/ja-ajHzIJz6.js.map +0 -1
- package/dist/_chunks/ko-Pzj-818C.js +0 -106
- package/dist/_chunks/ko-vJl9kPpn.mjs +0 -106
- package/dist/_chunks/ms-CqwG8v8l.mjs +0 -68
- package/dist/_chunks/ms-CqwG8v8l.mjs.map +0 -1
- package/dist/_chunks/ms-h3gjldBy.js +0 -68
- package/dist/_chunks/ms-h3gjldBy.js.map +0 -1
- package/dist/_chunks/pl-Cj8jChOO.mjs +0 -105
- package/dist/_chunks/pl-esgZ7ltN.js +0 -105
- package/dist/_chunks/pt-BR-B4LJHJIp.mjs +0 -76
- package/dist/_chunks/pt-BR-B4LJHJIp.mjs.map +0 -1
- package/dist/_chunks/pt-BR-Cazr7Z5I.js +0 -76
- package/dist/_chunks/pt-BR-Cazr7Z5I.js.map +0 -1
- package/dist/_chunks/pt-CNOOM_7x.mjs +0 -76
- package/dist/_chunks/pt-CNOOM_7x.mjs.map +0 -1
- package/dist/_chunks/pt-cbUnkHM5.js +0 -76
- package/dist/_chunks/pt-cbUnkHM5.js.map +0 -1
- package/dist/_chunks/ru-DqglvSUC.mjs +0 -76
- package/dist/_chunks/ru-DqglvSUC.mjs.map +0 -1
- package/dist/_chunks/ru-H6MzFUxp.js +0 -76
- package/dist/_chunks/ru-H6MzFUxp.js.map +0 -1
- package/dist/_chunks/sk-CZxC4dFY.js +0 -122
- package/dist/_chunks/sk-CZxC4dFY.js.map +0 -1
- package/dist/_chunks/sk-Dgpb3lnz.mjs +0 -122
- package/dist/_chunks/sk-Dgpb3lnz.mjs.map +0 -1
- package/dist/_chunks/th-C6unJZ8j.js +0 -76
- package/dist/_chunks/th-C6unJZ8j.js.map +0 -1
- package/dist/_chunks/th-DRfzuiFf.mjs +0 -76
- package/dist/_chunks/th-DRfzuiFf.mjs.map +0 -1
- package/dist/_chunks/tr--GzWXE_A.mjs +0 -122
- package/dist/_chunks/tr--GzWXE_A.mjs.map +0 -1
- package/dist/_chunks/tr-CY6AwX50.js +0 -122
- package/dist/_chunks/tr-CY6AwX50.js.map +0 -1
- package/dist/_chunks/uk-BniyNsD4.js +0 -73
- package/dist/_chunks/uk-BniyNsD4.js.map +0 -1
- package/dist/_chunks/uk-DVMT2Piq.mjs +0 -73
- package/dist/_chunks/uk-DVMT2Piq.mjs.map +0 -1
- package/dist/_chunks/zh-CsZw0IpM.js +0 -129
- package/dist/_chunks/zh-CsZw0IpM.js.map +0 -1
- package/dist/_chunks/zh-HOnih0is.mjs +0 -129
- package/dist/_chunks/zh-HOnih0is.mjs.map +0 -1
- package/dist/_chunks/zh-Hans-Cpmhg8uH.mjs +0 -152
- package/dist/_chunks/zh-Hans-k_xAc6nm.js +0 -152
|
@@ -1,2721 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const _ = require("lodash");
|
|
3
|
-
const utils = require("@strapi/utils");
|
|
4
|
-
const range = require("koa-range");
|
|
5
|
-
const koaStatic = require("koa-static");
|
|
6
|
-
const fp = require("lodash/fp");
|
|
7
|
-
const os = require("os");
|
|
8
|
-
const path = require("path");
|
|
9
|
-
const crypto = require("crypto");
|
|
10
|
-
const fs = require("fs");
|
|
11
|
-
const fse = require("fs-extra");
|
|
12
|
-
const mimeTypes = require("mime-types");
|
|
13
|
-
const sharp = require("sharp");
|
|
14
|
-
const dateFns = require("date-fns");
|
|
15
|
-
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
16
|
-
const ___default = /* @__PURE__ */ _interopDefault(_);
|
|
17
|
-
const utils__default = /* @__PURE__ */ _interopDefault(utils);
|
|
18
|
-
const range__default = /* @__PURE__ */ _interopDefault(range);
|
|
19
|
-
const koaStatic__default = /* @__PURE__ */ _interopDefault(koaStatic);
|
|
20
|
-
const os__default = /* @__PURE__ */ _interopDefault(os);
|
|
21
|
-
const path__default = /* @__PURE__ */ _interopDefault(path);
|
|
22
|
-
const crypto__default = /* @__PURE__ */ _interopDefault(crypto);
|
|
23
|
-
const fs__default = /* @__PURE__ */ _interopDefault(fs);
|
|
24
|
-
const fse__default = /* @__PURE__ */ _interopDefault(fse);
|
|
25
|
-
const sharp__default = /* @__PURE__ */ _interopDefault(sharp);
|
|
26
|
-
const registerUploadMiddleware = ({ strapi: strapi2 }) => {
|
|
27
|
-
strapi2.server.app.on("error", (err) => {
|
|
28
|
-
if (err.code === "EPIPE") {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
strapi2.server.app.onerror(err);
|
|
32
|
-
});
|
|
33
|
-
const localServerConfig = strapi2.config.get("plugin::upload.providerOptions.localServer", {});
|
|
34
|
-
strapi2.server.routes([
|
|
35
|
-
{
|
|
36
|
-
method: "GET",
|
|
37
|
-
path: "/uploads/(.*)",
|
|
38
|
-
handler: [range__default.default, koaStatic__default.default(strapi2.dirs.static.public, { defer: true, ...localServerConfig })],
|
|
39
|
-
config: { auth: false }
|
|
40
|
-
}
|
|
41
|
-
]);
|
|
42
|
-
};
|
|
43
|
-
const paths = {
|
|
44
|
-
"/upload": {
|
|
45
|
-
post: {
|
|
46
|
-
description: "Upload files",
|
|
47
|
-
responses: {
|
|
48
|
-
"200": {
|
|
49
|
-
description: "response",
|
|
50
|
-
content: {
|
|
51
|
-
"application/json": {
|
|
52
|
-
schema: {
|
|
53
|
-
type: "array",
|
|
54
|
-
items: {
|
|
55
|
-
$ref: "#/components/schemas/UploadFile"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
summary: "",
|
|
63
|
-
tags: [
|
|
64
|
-
"Upload - File"
|
|
65
|
-
],
|
|
66
|
-
requestBody: {
|
|
67
|
-
description: "Upload files",
|
|
68
|
-
required: true,
|
|
69
|
-
content: {
|
|
70
|
-
"multipart/form-data": {
|
|
71
|
-
schema: {
|
|
72
|
-
required: [
|
|
73
|
-
"files"
|
|
74
|
-
],
|
|
75
|
-
type: "object",
|
|
76
|
-
properties: {
|
|
77
|
-
path: {
|
|
78
|
-
type: "string",
|
|
79
|
-
description: "The folder where the file(s) will be uploaded to (only supported on strapi-provider-upload-aws-s3)."
|
|
80
|
-
},
|
|
81
|
-
refId: {
|
|
82
|
-
type: "string",
|
|
83
|
-
description: "The ID of the entry which the file(s) will be linked to"
|
|
84
|
-
},
|
|
85
|
-
ref: {
|
|
86
|
-
type: "string",
|
|
87
|
-
description: "The unique ID (uid) of the model which the file(s) will be linked to (api::restaurant.restaurant)."
|
|
88
|
-
},
|
|
89
|
-
field: {
|
|
90
|
-
type: "string",
|
|
91
|
-
description: "The field of the entry which the file(s) will be precisely linked to."
|
|
92
|
-
},
|
|
93
|
-
files: {
|
|
94
|
-
type: "array",
|
|
95
|
-
items: {
|
|
96
|
-
type: "string",
|
|
97
|
-
format: "binary"
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
},
|
|
107
|
-
"/upload?id={id}": {
|
|
108
|
-
post: {
|
|
109
|
-
parameters: [
|
|
110
|
-
{
|
|
111
|
-
name: "id",
|
|
112
|
-
"in": "query",
|
|
113
|
-
description: "File id",
|
|
114
|
-
required: true,
|
|
115
|
-
schema: {
|
|
116
|
-
type: "string"
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
],
|
|
120
|
-
description: "Upload file information",
|
|
121
|
-
responses: {
|
|
122
|
-
"200": {
|
|
123
|
-
description: "response",
|
|
124
|
-
content: {
|
|
125
|
-
"application/json": {
|
|
126
|
-
schema: {
|
|
127
|
-
type: "array",
|
|
128
|
-
items: {
|
|
129
|
-
$ref: "#/components/schemas/UploadFile"
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
summary: "",
|
|
137
|
-
tags: [
|
|
138
|
-
"Upload - File"
|
|
139
|
-
],
|
|
140
|
-
requestBody: {
|
|
141
|
-
description: "Upload files",
|
|
142
|
-
required: true,
|
|
143
|
-
content: {
|
|
144
|
-
"multipart/form-data": {
|
|
145
|
-
schema: {
|
|
146
|
-
type: "object",
|
|
147
|
-
properties: {
|
|
148
|
-
fileInfo: {
|
|
149
|
-
type: "object",
|
|
150
|
-
properties: {
|
|
151
|
-
name: {
|
|
152
|
-
type: "string"
|
|
153
|
-
},
|
|
154
|
-
alternativeText: {
|
|
155
|
-
type: "string"
|
|
156
|
-
},
|
|
157
|
-
caption: {
|
|
158
|
-
type: "string"
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
files: {
|
|
163
|
-
type: "string",
|
|
164
|
-
format: "binary"
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
"/upload/files": {
|
|
174
|
-
get: {
|
|
175
|
-
tags: [
|
|
176
|
-
"Upload - File"
|
|
177
|
-
],
|
|
178
|
-
responses: {
|
|
179
|
-
"200": {
|
|
180
|
-
description: "Get a list of files",
|
|
181
|
-
content: {
|
|
182
|
-
"application/json": {
|
|
183
|
-
schema: {
|
|
184
|
-
type: "array",
|
|
185
|
-
items: {
|
|
186
|
-
$ref: "#/components/schemas/UploadFile"
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
"/upload/files/{id}": {
|
|
196
|
-
get: {
|
|
197
|
-
parameters: [
|
|
198
|
-
{
|
|
199
|
-
name: "id",
|
|
200
|
-
"in": "path",
|
|
201
|
-
description: "",
|
|
202
|
-
deprecated: false,
|
|
203
|
-
required: true,
|
|
204
|
-
schema: {
|
|
205
|
-
type: "string"
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
],
|
|
209
|
-
tags: [
|
|
210
|
-
"Upload - File"
|
|
211
|
-
],
|
|
212
|
-
responses: {
|
|
213
|
-
"200": {
|
|
214
|
-
description: "Get a specific file",
|
|
215
|
-
content: {
|
|
216
|
-
"application/json": {
|
|
217
|
-
schema: {
|
|
218
|
-
$ref: "#/components/schemas/UploadFile"
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
"delete": {
|
|
226
|
-
parameters: [
|
|
227
|
-
{
|
|
228
|
-
name: "id",
|
|
229
|
-
"in": "path",
|
|
230
|
-
description: "",
|
|
231
|
-
deprecated: false,
|
|
232
|
-
required: true,
|
|
233
|
-
schema: {
|
|
234
|
-
type: "string"
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
],
|
|
238
|
-
tags: [
|
|
239
|
-
"Upload - File"
|
|
240
|
-
],
|
|
241
|
-
responses: {
|
|
242
|
-
"200": {
|
|
243
|
-
description: "Delete a file",
|
|
244
|
-
content: {
|
|
245
|
-
"application/json": {
|
|
246
|
-
schema: {
|
|
247
|
-
$ref: "#/components/schemas/UploadFile"
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
const components = {
|
|
257
|
-
schemas: {
|
|
258
|
-
UploadFile: {
|
|
259
|
-
properties: {
|
|
260
|
-
id: {
|
|
261
|
-
type: "number"
|
|
262
|
-
},
|
|
263
|
-
name: {
|
|
264
|
-
type: "string"
|
|
265
|
-
},
|
|
266
|
-
alternativeText: {
|
|
267
|
-
type: "string"
|
|
268
|
-
},
|
|
269
|
-
caption: {
|
|
270
|
-
type: "string"
|
|
271
|
-
},
|
|
272
|
-
width: {
|
|
273
|
-
type: "number",
|
|
274
|
-
format: "integer"
|
|
275
|
-
},
|
|
276
|
-
height: {
|
|
277
|
-
type: "number",
|
|
278
|
-
format: "integer"
|
|
279
|
-
},
|
|
280
|
-
formats: {
|
|
281
|
-
type: "number"
|
|
282
|
-
},
|
|
283
|
-
hash: {
|
|
284
|
-
type: "string"
|
|
285
|
-
},
|
|
286
|
-
ext: {
|
|
287
|
-
type: "string"
|
|
288
|
-
},
|
|
289
|
-
mime: {
|
|
290
|
-
type: "string"
|
|
291
|
-
},
|
|
292
|
-
size: {
|
|
293
|
-
type: "number",
|
|
294
|
-
format: "double"
|
|
295
|
-
},
|
|
296
|
-
url: {
|
|
297
|
-
type: "string"
|
|
298
|
-
},
|
|
299
|
-
previewUrl: {
|
|
300
|
-
type: "string"
|
|
301
|
-
},
|
|
302
|
-
provider: {
|
|
303
|
-
type: "string"
|
|
304
|
-
},
|
|
305
|
-
provider_metadata: {
|
|
306
|
-
type: "object"
|
|
307
|
-
},
|
|
308
|
-
createdAt: {
|
|
309
|
-
type: "string",
|
|
310
|
-
format: "date-time"
|
|
311
|
-
},
|
|
312
|
-
updatedAt: {
|
|
313
|
-
type: "string",
|
|
314
|
-
format: "date-time"
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
const spec = {
|
|
321
|
-
paths,
|
|
322
|
-
components
|
|
323
|
-
};
|
|
324
|
-
const { PayloadTooLargeError } = utils.errors;
|
|
325
|
-
const { bytesToHumanReadable, kbytesToBytes } = utils.file;
|
|
326
|
-
async function register({ strapi: strapi2 }) {
|
|
327
|
-
strapi2.plugin("upload").provider = createProvider(strapi2.config.get("plugin::upload"));
|
|
328
|
-
await registerUploadMiddleware({ strapi: strapi2 });
|
|
329
|
-
if (strapi2.plugin("graphql")) {
|
|
330
|
-
const { installGraphqlExtension } = await Promise.resolve().then(() => require("./graphql-QF5Y36Qj.js"));
|
|
331
|
-
installGraphqlExtension({ strapi: strapi2 });
|
|
332
|
-
}
|
|
333
|
-
if (strapi2.plugin("documentation")) {
|
|
334
|
-
strapi2.plugin("documentation").service("override").registerOverride(spec, {
|
|
335
|
-
pluginOrigin: "upload",
|
|
336
|
-
excludeFromGeneration: ["upload"]
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
const createProvider = (config2) => {
|
|
341
|
-
const { providerOptions, actionOptions = {} } = config2;
|
|
342
|
-
const providerName = ___default.default.toLower(config2.provider);
|
|
343
|
-
let provider2;
|
|
344
|
-
let modulePath;
|
|
345
|
-
try {
|
|
346
|
-
modulePath = require.resolve(`@strapi/provider-upload-${providerName}`);
|
|
347
|
-
} catch (error) {
|
|
348
|
-
if (typeof error === "object" && error !== null && "code" in error && error.code === "MODULE_NOT_FOUND") {
|
|
349
|
-
modulePath = providerName;
|
|
350
|
-
} else {
|
|
351
|
-
throw error;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
try {
|
|
355
|
-
provider2 = require(modulePath);
|
|
356
|
-
} catch (err) {
|
|
357
|
-
const newError = new Error(`Could not load upload provider "${providerName}".`);
|
|
358
|
-
if (err instanceof Error) {
|
|
359
|
-
newError.stack = err.stack;
|
|
360
|
-
}
|
|
361
|
-
throw newError;
|
|
362
|
-
}
|
|
363
|
-
const providerInstance = provider2.init(providerOptions);
|
|
364
|
-
if (!providerInstance.delete) {
|
|
365
|
-
throw new Error(`The upload provider "${providerName}" doesn't implement the delete method.`);
|
|
366
|
-
}
|
|
367
|
-
if (!providerInstance.upload && !providerInstance.uploadStream) {
|
|
368
|
-
throw new Error(
|
|
369
|
-
`The upload provider "${providerName}" doesn't implement the uploadStream nor the upload method.`
|
|
370
|
-
);
|
|
371
|
-
}
|
|
372
|
-
if (!providerInstance.uploadStream) {
|
|
373
|
-
process.emitWarning(
|
|
374
|
-
`The upload provider "${providerName}" doesn't implement the uploadStream function. Strapi will fallback on the upload method. Some performance issues may occur.`
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
const wrappedProvider = ___default.default.mapValues(providerInstance, (method, methodName) => {
|
|
378
|
-
return async (file2, options = actionOptions[methodName]) => providerInstance[methodName](file2, options);
|
|
379
|
-
});
|
|
380
|
-
return Object.assign(Object.create(baseProvider), wrappedProvider);
|
|
381
|
-
};
|
|
382
|
-
const baseProvider = {
|
|
383
|
-
extend(obj) {
|
|
384
|
-
Object.assign(this, obj);
|
|
385
|
-
},
|
|
386
|
-
checkFileSize(file2, { sizeLimit }) {
|
|
387
|
-
if (sizeLimit && kbytesToBytes(file2.size) > sizeLimit) {
|
|
388
|
-
throw new PayloadTooLargeError(
|
|
389
|
-
`${file2.originalFilename} exceeds size limit of ${bytesToHumanReadable(sizeLimit)}.`
|
|
390
|
-
);
|
|
391
|
-
}
|
|
392
|
-
},
|
|
393
|
-
getSignedUrl(file2) {
|
|
394
|
-
return file2;
|
|
395
|
-
},
|
|
396
|
-
isPrivate() {
|
|
397
|
-
return false;
|
|
398
|
-
}
|
|
399
|
-
};
|
|
400
|
-
const getService = (name) => {
|
|
401
|
-
return strapi.plugin("upload").service(name);
|
|
402
|
-
};
|
|
403
|
-
const ACTIONS = {
|
|
404
|
-
read: "plugin::upload.read",
|
|
405
|
-
readSettings: "plugin::upload.settings.read",
|
|
406
|
-
create: "plugin::upload.assets.create",
|
|
407
|
-
update: "plugin::upload.assets.update",
|
|
408
|
-
download: "plugin::upload.assets.download",
|
|
409
|
-
copyLink: "plugin::upload.assets.copy-link",
|
|
410
|
-
configureView: "plugin::upload.configure-view"
|
|
411
|
-
};
|
|
412
|
-
const ALLOWED_SORT_STRINGS = [
|
|
413
|
-
"createdAt:DESC",
|
|
414
|
-
"createdAt:ASC",
|
|
415
|
-
"name:ASC",
|
|
416
|
-
"name:DESC",
|
|
417
|
-
"updatedAt:DESC",
|
|
418
|
-
"updatedAt:ASC"
|
|
419
|
-
];
|
|
420
|
-
const ALLOWED_WEBHOOK_EVENTS = {
|
|
421
|
-
MEDIA_CREATE: "media.create",
|
|
422
|
-
MEDIA_UPDATE: "media.update",
|
|
423
|
-
MEDIA_DELETE: "media.delete"
|
|
424
|
-
};
|
|
425
|
-
const FOLDER_MODEL_UID = "plugin::upload.folder";
|
|
426
|
-
const FILE_MODEL_UID = "plugin::upload.file";
|
|
427
|
-
const API_UPLOAD_FOLDER_BASE_NAME = "API Uploads";
|
|
428
|
-
async function bootstrap({ strapi: strapi2 }) {
|
|
429
|
-
const defaultConfig = {
|
|
430
|
-
settings: {
|
|
431
|
-
sizeOptimization: true,
|
|
432
|
-
responsiveDimensions: true,
|
|
433
|
-
autoOrientation: false
|
|
434
|
-
},
|
|
435
|
-
view_configuration: {
|
|
436
|
-
pageSize: 10,
|
|
437
|
-
sort: ALLOWED_SORT_STRINGS[0]
|
|
438
|
-
}
|
|
439
|
-
};
|
|
440
|
-
for (const [key, defaultValue] of Object.entries(defaultConfig)) {
|
|
441
|
-
const configurator = strapi2.store({ type: "plugin", name: "upload", key });
|
|
442
|
-
const config2 = await configurator.get({});
|
|
443
|
-
if (config2 && Object.keys(defaultValue).every((key2) => Object.prototype.hasOwnProperty.call(config2, key2))) {
|
|
444
|
-
continue;
|
|
445
|
-
}
|
|
446
|
-
await configurator.set({
|
|
447
|
-
value: Object.assign(defaultValue, config2 || {})
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
await registerPermissionActions();
|
|
451
|
-
await registerWebhookEvents();
|
|
452
|
-
await getService("weeklyMetrics").registerCron();
|
|
453
|
-
getService("metrics").sendUploadPluginMetrics();
|
|
454
|
-
getService("extensions").signFileUrlsOnDocumentService();
|
|
455
|
-
}
|
|
456
|
-
const registerWebhookEvents = async () => Object.entries(ALLOWED_WEBHOOK_EVENTS).forEach(([key, value]) => {
|
|
457
|
-
strapi.get("webhookStore").addAllowedEvent(key, value);
|
|
458
|
-
});
|
|
459
|
-
const registerPermissionActions = async () => {
|
|
460
|
-
const actions = [
|
|
461
|
-
{
|
|
462
|
-
section: "plugins",
|
|
463
|
-
displayName: "Access the Media Library",
|
|
464
|
-
uid: "read",
|
|
465
|
-
pluginName: "upload"
|
|
466
|
-
},
|
|
467
|
-
{
|
|
468
|
-
section: "plugins",
|
|
469
|
-
displayName: "Create (upload)",
|
|
470
|
-
uid: "assets.create",
|
|
471
|
-
subCategory: "assets",
|
|
472
|
-
pluginName: "upload"
|
|
473
|
-
},
|
|
474
|
-
{
|
|
475
|
-
section: "plugins",
|
|
476
|
-
displayName: "Update (crop, details, replace) + delete",
|
|
477
|
-
uid: "assets.update",
|
|
478
|
-
subCategory: "assets",
|
|
479
|
-
pluginName: "upload"
|
|
480
|
-
},
|
|
481
|
-
{
|
|
482
|
-
section: "plugins",
|
|
483
|
-
displayName: "Download",
|
|
484
|
-
uid: "assets.download",
|
|
485
|
-
subCategory: "assets",
|
|
486
|
-
pluginName: "upload"
|
|
487
|
-
},
|
|
488
|
-
{
|
|
489
|
-
section: "plugins",
|
|
490
|
-
displayName: "Copy link",
|
|
491
|
-
uid: "assets.copy-link",
|
|
492
|
-
subCategory: "assets",
|
|
493
|
-
pluginName: "upload"
|
|
494
|
-
},
|
|
495
|
-
{
|
|
496
|
-
section: "plugins",
|
|
497
|
-
displayName: "Configure view",
|
|
498
|
-
uid: "configure-view",
|
|
499
|
-
pluginName: "upload"
|
|
500
|
-
},
|
|
501
|
-
{
|
|
502
|
-
section: "settings",
|
|
503
|
-
displayName: "Access the Media Library settings page",
|
|
504
|
-
uid: "settings.read",
|
|
505
|
-
category: "media library",
|
|
506
|
-
pluginName: "upload"
|
|
507
|
-
}
|
|
508
|
-
];
|
|
509
|
-
await strapi.service("admin::permission").actionProvider.registerMany(actions);
|
|
510
|
-
};
|
|
511
|
-
const file$1 = {
|
|
512
|
-
schema: {
|
|
513
|
-
collectionName: "files",
|
|
514
|
-
info: {
|
|
515
|
-
singularName: "file",
|
|
516
|
-
pluralName: "files",
|
|
517
|
-
displayName: "File",
|
|
518
|
-
description: ""
|
|
519
|
-
},
|
|
520
|
-
options: {},
|
|
521
|
-
pluginOptions: {
|
|
522
|
-
"content-manager": {
|
|
523
|
-
visible: false
|
|
524
|
-
},
|
|
525
|
-
"content-type-builder": {
|
|
526
|
-
visible: false
|
|
527
|
-
}
|
|
528
|
-
},
|
|
529
|
-
attributes: {
|
|
530
|
-
name: {
|
|
531
|
-
type: "string",
|
|
532
|
-
configurable: false,
|
|
533
|
-
required: true
|
|
534
|
-
},
|
|
535
|
-
alternativeText: {
|
|
536
|
-
type: "string",
|
|
537
|
-
configurable: false
|
|
538
|
-
},
|
|
539
|
-
caption: {
|
|
540
|
-
type: "string",
|
|
541
|
-
configurable: false
|
|
542
|
-
},
|
|
543
|
-
width: {
|
|
544
|
-
type: "integer",
|
|
545
|
-
configurable: false
|
|
546
|
-
},
|
|
547
|
-
height: {
|
|
548
|
-
type: "integer",
|
|
549
|
-
configurable: false
|
|
550
|
-
},
|
|
551
|
-
formats: {
|
|
552
|
-
type: "json",
|
|
553
|
-
configurable: false
|
|
554
|
-
},
|
|
555
|
-
hash: {
|
|
556
|
-
type: "string",
|
|
557
|
-
configurable: false,
|
|
558
|
-
required: true
|
|
559
|
-
},
|
|
560
|
-
ext: {
|
|
561
|
-
type: "string",
|
|
562
|
-
configurable: false
|
|
563
|
-
},
|
|
564
|
-
mime: {
|
|
565
|
-
type: "string",
|
|
566
|
-
configurable: false,
|
|
567
|
-
required: true
|
|
568
|
-
},
|
|
569
|
-
size: {
|
|
570
|
-
type: "decimal",
|
|
571
|
-
configurable: false,
|
|
572
|
-
required: true
|
|
573
|
-
},
|
|
574
|
-
url: {
|
|
575
|
-
type: "string",
|
|
576
|
-
configurable: false,
|
|
577
|
-
required: true
|
|
578
|
-
},
|
|
579
|
-
previewUrl: {
|
|
580
|
-
type: "string",
|
|
581
|
-
configurable: false
|
|
582
|
-
},
|
|
583
|
-
provider: {
|
|
584
|
-
type: "string",
|
|
585
|
-
configurable: false,
|
|
586
|
-
required: true
|
|
587
|
-
},
|
|
588
|
-
provider_metadata: {
|
|
589
|
-
type: "json",
|
|
590
|
-
configurable: false
|
|
591
|
-
},
|
|
592
|
-
related: {
|
|
593
|
-
type: "relation",
|
|
594
|
-
relation: "morphToMany",
|
|
595
|
-
configurable: false
|
|
596
|
-
},
|
|
597
|
-
folder: {
|
|
598
|
-
type: "relation",
|
|
599
|
-
relation: "manyToOne",
|
|
600
|
-
target: FOLDER_MODEL_UID,
|
|
601
|
-
inversedBy: "files",
|
|
602
|
-
private: true
|
|
603
|
-
},
|
|
604
|
-
folderPath: {
|
|
605
|
-
type: "string",
|
|
606
|
-
minLength: 1,
|
|
607
|
-
required: true,
|
|
608
|
-
private: true,
|
|
609
|
-
searchable: false
|
|
610
|
-
}
|
|
611
|
-
},
|
|
612
|
-
// experimental feature:
|
|
613
|
-
indexes: [
|
|
614
|
-
{
|
|
615
|
-
name: "upload_files_folder_path_index",
|
|
616
|
-
columns: ["folder_path"],
|
|
617
|
-
type: null
|
|
618
|
-
},
|
|
619
|
-
{
|
|
620
|
-
name: `upload_files_created_at_index`,
|
|
621
|
-
columns: ["created_at"],
|
|
622
|
-
type: null
|
|
623
|
-
},
|
|
624
|
-
{
|
|
625
|
-
name: `upload_files_updated_at_index`,
|
|
626
|
-
columns: ["updated_at"],
|
|
627
|
-
type: null
|
|
628
|
-
},
|
|
629
|
-
{
|
|
630
|
-
name: `upload_files_name_index`,
|
|
631
|
-
columns: ["name"],
|
|
632
|
-
type: null
|
|
633
|
-
},
|
|
634
|
-
{
|
|
635
|
-
name: `upload_files_size_index`,
|
|
636
|
-
columns: ["size"],
|
|
637
|
-
type: null
|
|
638
|
-
},
|
|
639
|
-
{
|
|
640
|
-
name: `upload_files_ext_index`,
|
|
641
|
-
columns: ["ext"],
|
|
642
|
-
type: null
|
|
643
|
-
}
|
|
644
|
-
]
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
|
-
const folder$1 = {
|
|
648
|
-
schema: {
|
|
649
|
-
collectionName: "upload_folders",
|
|
650
|
-
info: {
|
|
651
|
-
singularName: "folder",
|
|
652
|
-
pluralName: "folders",
|
|
653
|
-
displayName: "Folder"
|
|
654
|
-
},
|
|
655
|
-
options: {},
|
|
656
|
-
pluginOptions: {
|
|
657
|
-
"content-manager": {
|
|
658
|
-
visible: false
|
|
659
|
-
},
|
|
660
|
-
"content-type-builder": {
|
|
661
|
-
visible: false
|
|
662
|
-
}
|
|
663
|
-
},
|
|
664
|
-
attributes: {
|
|
665
|
-
name: {
|
|
666
|
-
type: "string",
|
|
667
|
-
minLength: 1,
|
|
668
|
-
required: true
|
|
669
|
-
},
|
|
670
|
-
pathId: {
|
|
671
|
-
type: "integer",
|
|
672
|
-
unique: true,
|
|
673
|
-
required: true
|
|
674
|
-
},
|
|
675
|
-
parent: {
|
|
676
|
-
type: "relation",
|
|
677
|
-
relation: "manyToOne",
|
|
678
|
-
target: FOLDER_MODEL_UID,
|
|
679
|
-
inversedBy: "children"
|
|
680
|
-
},
|
|
681
|
-
children: {
|
|
682
|
-
type: "relation",
|
|
683
|
-
relation: "oneToMany",
|
|
684
|
-
target: FOLDER_MODEL_UID,
|
|
685
|
-
mappedBy: "parent"
|
|
686
|
-
},
|
|
687
|
-
files: {
|
|
688
|
-
type: "relation",
|
|
689
|
-
relation: "oneToMany",
|
|
690
|
-
target: FILE_MODEL_UID,
|
|
691
|
-
mappedBy: "folder"
|
|
692
|
-
},
|
|
693
|
-
path: {
|
|
694
|
-
type: "string",
|
|
695
|
-
minLength: 1,
|
|
696
|
-
required: true
|
|
697
|
-
}
|
|
698
|
-
},
|
|
699
|
-
// experimental feature:
|
|
700
|
-
indexes: [
|
|
701
|
-
{
|
|
702
|
-
name: "upload_folders_path_id_index",
|
|
703
|
-
columns: ["path_id"],
|
|
704
|
-
type: "unique"
|
|
705
|
-
},
|
|
706
|
-
{
|
|
707
|
-
name: "upload_folders_path_index",
|
|
708
|
-
columns: ["path"],
|
|
709
|
-
type: "unique"
|
|
710
|
-
}
|
|
711
|
-
]
|
|
712
|
-
}
|
|
713
|
-
};
|
|
714
|
-
const contentTypes = {
|
|
715
|
-
file: file$1,
|
|
716
|
-
folder: folder$1
|
|
717
|
-
};
|
|
718
|
-
const provider = ({ strapi: strapi2 }) => ({
|
|
719
|
-
async checkFileSize(file2) {
|
|
720
|
-
const { sizeLimit } = strapi2.config.get("plugin::upload");
|
|
721
|
-
await strapi2.plugin("upload").provider.checkFileSize(file2, { sizeLimit });
|
|
722
|
-
},
|
|
723
|
-
async upload(file2) {
|
|
724
|
-
if (fp.isFunction(strapi2.plugin("upload").provider.uploadStream)) {
|
|
725
|
-
file2.stream = file2.getStream();
|
|
726
|
-
await strapi2.plugin("upload").provider.uploadStream(file2);
|
|
727
|
-
delete file2.stream;
|
|
728
|
-
if ("filepath" in file2) {
|
|
729
|
-
delete file2.filepath;
|
|
730
|
-
}
|
|
731
|
-
} else {
|
|
732
|
-
file2.buffer = await utils.file.streamToBuffer(file2.getStream());
|
|
733
|
-
await strapi2.plugin("upload").provider.upload(file2);
|
|
734
|
-
delete file2.buffer;
|
|
735
|
-
if ("filepath" in file2) {
|
|
736
|
-
delete file2.filepath;
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
});
|
|
741
|
-
const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = utils.contentTypes.constants;
|
|
742
|
-
const { MEDIA_CREATE, MEDIA_UPDATE, MEDIA_DELETE } = ALLOWED_WEBHOOK_EVENTS;
|
|
743
|
-
const { ApplicationError, NotFoundError } = utils.errors;
|
|
744
|
-
const { bytesToKbytes: bytesToKbytes$1 } = utils.file;
|
|
745
|
-
const upload = ({ strapi: strapi2 }) => {
|
|
746
|
-
const randomSuffix = () => crypto__default.default.randomBytes(5).toString("hex");
|
|
747
|
-
const generateFileName = (name) => {
|
|
748
|
-
const baseName = utils.strings.nameToSlug(name, { separator: "_", lowercase: false });
|
|
749
|
-
return `${baseName}_${randomSuffix()}`;
|
|
750
|
-
};
|
|
751
|
-
const sendMediaMetrics = (data) => {
|
|
752
|
-
if (___default.default.has(data, "caption") && !___default.default.isEmpty(data.caption)) {
|
|
753
|
-
strapi2.telemetry.send("didSaveMediaWithCaption");
|
|
754
|
-
}
|
|
755
|
-
if (___default.default.has(data, "alternativeText") && !___default.default.isEmpty(data.alternativeText)) {
|
|
756
|
-
strapi2.telemetry.send("didSaveMediaWithAlternativeText");
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
const createAndAssignTmpWorkingDirectoryToFiles = async (files) => {
|
|
760
|
-
const tmpWorkingDirectory = await fse__default.default.mkdtemp(path__default.default.join(os__default.default.tmpdir(), "strapi-upload-"));
|
|
761
|
-
if (Array.isArray(files)) {
|
|
762
|
-
files.forEach((file2) => {
|
|
763
|
-
file2.tmpWorkingDirectory = tmpWorkingDirectory;
|
|
764
|
-
});
|
|
765
|
-
} else {
|
|
766
|
-
files.tmpWorkingDirectory = tmpWorkingDirectory;
|
|
767
|
-
}
|
|
768
|
-
return tmpWorkingDirectory;
|
|
769
|
-
};
|
|
770
|
-
function filenameReservedRegex() {
|
|
771
|
-
return /[<>:"/\\|?*\u0000-\u001F]/g;
|
|
772
|
-
}
|
|
773
|
-
function windowsReservedNameRegex() {
|
|
774
|
-
return /^(con|prn|aux|nul|com\d|lpt\d)$/i;
|
|
775
|
-
}
|
|
776
|
-
function isValidFilename(string) {
|
|
777
|
-
if (!string || string.length > 255) {
|
|
778
|
-
return false;
|
|
779
|
-
}
|
|
780
|
-
if (filenameReservedRegex().test(string) || windowsReservedNameRegex().test(string)) {
|
|
781
|
-
return false;
|
|
782
|
-
}
|
|
783
|
-
if (string === "." || string === "..") {
|
|
784
|
-
return false;
|
|
785
|
-
}
|
|
786
|
-
return true;
|
|
787
|
-
}
|
|
788
|
-
async function emitEvent(event, data) {
|
|
789
|
-
const modelDef = strapi2.getModel(FILE_MODEL_UID);
|
|
790
|
-
const sanitizedData = await utils.sanitize.sanitizers.defaultSanitizeOutput(
|
|
791
|
-
{
|
|
792
|
-
schema: modelDef,
|
|
793
|
-
getModel(uid) {
|
|
794
|
-
return strapi2.getModel(uid);
|
|
795
|
-
}
|
|
796
|
-
},
|
|
797
|
-
data
|
|
798
|
-
);
|
|
799
|
-
strapi2.eventHub.emit(event, { media: sanitizedData });
|
|
800
|
-
}
|
|
801
|
-
async function formatFileInfo({ filename, type, size }, fileInfo = {}, metas = {}) {
|
|
802
|
-
const fileService = getService("file");
|
|
803
|
-
if (!isValidFilename(filename)) {
|
|
804
|
-
throw new ApplicationError("File name contains invalid characters");
|
|
805
|
-
}
|
|
806
|
-
let ext = path__default.default.extname(filename);
|
|
807
|
-
if (!ext) {
|
|
808
|
-
ext = `.${mimeTypes.extension(type)}`;
|
|
809
|
-
}
|
|
810
|
-
const usedName = (fileInfo.name || filename).normalize();
|
|
811
|
-
const basename = path__default.default.basename(usedName, ext);
|
|
812
|
-
if (!isValidFilename(filename)) {
|
|
813
|
-
throw new ApplicationError("File name contains invalid characters");
|
|
814
|
-
}
|
|
815
|
-
const entity = {
|
|
816
|
-
name: usedName,
|
|
817
|
-
alternativeText: fileInfo.alternativeText,
|
|
818
|
-
caption: fileInfo.caption,
|
|
819
|
-
folder: fileInfo.folder,
|
|
820
|
-
folderPath: await fileService.getFolderPath(fileInfo.folder),
|
|
821
|
-
hash: generateFileName(basename),
|
|
822
|
-
ext,
|
|
823
|
-
mime: type,
|
|
824
|
-
size: bytesToKbytes$1(size),
|
|
825
|
-
sizeInBytes: size
|
|
826
|
-
};
|
|
827
|
-
const { refId, ref, field } = metas;
|
|
828
|
-
if (refId && ref && field) {
|
|
829
|
-
entity.related = [
|
|
830
|
-
{
|
|
831
|
-
id: refId,
|
|
832
|
-
__type: ref,
|
|
833
|
-
__pivot: { field }
|
|
834
|
-
}
|
|
835
|
-
];
|
|
836
|
-
}
|
|
837
|
-
if (metas.path) {
|
|
838
|
-
entity.path = metas.path;
|
|
839
|
-
}
|
|
840
|
-
if (metas.tmpWorkingDirectory) {
|
|
841
|
-
entity.tmpWorkingDirectory = metas.tmpWorkingDirectory;
|
|
842
|
-
}
|
|
843
|
-
return entity;
|
|
844
|
-
}
|
|
845
|
-
async function enhanceAndValidateFile(file2, fileInfo, metas) {
|
|
846
|
-
const currentFile = await formatFileInfo(
|
|
847
|
-
{
|
|
848
|
-
filename: file2.originalFilename ?? "unamed",
|
|
849
|
-
type: file2.mimetype ?? "application/octet-stream",
|
|
850
|
-
size: file2.size
|
|
851
|
-
},
|
|
852
|
-
fileInfo,
|
|
853
|
-
{
|
|
854
|
-
...metas,
|
|
855
|
-
tmpWorkingDirectory: file2.tmpWorkingDirectory
|
|
856
|
-
}
|
|
857
|
-
);
|
|
858
|
-
currentFile.filepath = file2.filepath;
|
|
859
|
-
currentFile.getStream = () => fs__default.default.createReadStream(file2.filepath);
|
|
860
|
-
const { optimize: optimize2, isImage: isImage2, isFaultyImage: isFaultyImage2, isOptimizableImage: isOptimizableImage2 } = strapi2.plugin("upload").service("image-manipulation");
|
|
861
|
-
if (await isImage2(currentFile)) {
|
|
862
|
-
if (await isFaultyImage2(currentFile)) {
|
|
863
|
-
throw new ApplicationError("File is not a valid image");
|
|
864
|
-
}
|
|
865
|
-
if (await isOptimizableImage2(currentFile)) {
|
|
866
|
-
return optimize2(currentFile);
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
return currentFile;
|
|
870
|
-
}
|
|
871
|
-
async function upload2({
|
|
872
|
-
data,
|
|
873
|
-
files
|
|
874
|
-
}, opts) {
|
|
875
|
-
const { user } = opts ?? {};
|
|
876
|
-
const tmpWorkingDirectory = await createAndAssignTmpWorkingDirectoryToFiles(files);
|
|
877
|
-
let uploadedFiles = [];
|
|
878
|
-
try {
|
|
879
|
-
const { fileInfo, ...metas } = data;
|
|
880
|
-
const fileArray = Array.isArray(files) ? files : [files];
|
|
881
|
-
const fileInfoArray = Array.isArray(fileInfo) ? fileInfo : [fileInfo];
|
|
882
|
-
const doUpload = async (file2, fileInfo2) => {
|
|
883
|
-
const fileData = await enhanceAndValidateFile(file2, fileInfo2, metas);
|
|
884
|
-
return uploadFileAndPersist(fileData, { user });
|
|
885
|
-
};
|
|
886
|
-
uploadedFiles = await Promise.all(
|
|
887
|
-
fileArray.map((file2, idx) => doUpload(file2, fileInfoArray[idx] || {}))
|
|
888
|
-
);
|
|
889
|
-
} finally {
|
|
890
|
-
await fse__default.default.remove(tmpWorkingDirectory);
|
|
891
|
-
}
|
|
892
|
-
return uploadedFiles;
|
|
893
|
-
}
|
|
894
|
-
async function uploadImage(fileData) {
|
|
895
|
-
const { getDimensions: getDimensions2, generateThumbnail: generateThumbnail2, generateResponsiveFormats: generateResponsiveFormats2, isResizableImage: isResizableImage2 } = getService("image-manipulation");
|
|
896
|
-
const { width, height } = await getDimensions2(fileData);
|
|
897
|
-
___default.default.assign(fileData, {
|
|
898
|
-
width,
|
|
899
|
-
height
|
|
900
|
-
});
|
|
901
|
-
const uploadThumbnail = async (thumbnailFile) => {
|
|
902
|
-
await getService("provider").upload(thumbnailFile);
|
|
903
|
-
___default.default.set(fileData, "formats.thumbnail", thumbnailFile);
|
|
904
|
-
};
|
|
905
|
-
const uploadResponsiveFormat = async (format) => {
|
|
906
|
-
const { key, file: file2 } = format;
|
|
907
|
-
await getService("provider").upload(file2);
|
|
908
|
-
___default.default.set(fileData, ["formats", key], file2);
|
|
909
|
-
};
|
|
910
|
-
const uploadPromises = [];
|
|
911
|
-
uploadPromises.push(getService("provider").upload(fileData));
|
|
912
|
-
if (await isResizableImage2(fileData)) {
|
|
913
|
-
const thumbnailFile = await generateThumbnail2(fileData);
|
|
914
|
-
if (thumbnailFile) {
|
|
915
|
-
uploadPromises.push(uploadThumbnail(thumbnailFile));
|
|
916
|
-
}
|
|
917
|
-
const formats = await generateResponsiveFormats2(fileData);
|
|
918
|
-
if (Array.isArray(formats) && formats.length > 0) {
|
|
919
|
-
for (const format of formats) {
|
|
920
|
-
if (!format) continue;
|
|
921
|
-
uploadPromises.push(uploadResponsiveFormat(format));
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
await Promise.all(uploadPromises);
|
|
926
|
-
}
|
|
927
|
-
async function uploadFileAndPersist(fileData, opts) {
|
|
928
|
-
const { user } = opts ?? {};
|
|
929
|
-
const config2 = strapi2.config.get("plugin::upload");
|
|
930
|
-
const { isImage: isImage2 } = getService("image-manipulation");
|
|
931
|
-
await getService("provider").checkFileSize(fileData);
|
|
932
|
-
if (await isImage2(fileData)) {
|
|
933
|
-
await uploadImage(fileData);
|
|
934
|
-
} else {
|
|
935
|
-
await getService("provider").upload(fileData);
|
|
936
|
-
}
|
|
937
|
-
___default.default.set(fileData, "provider", config2.provider);
|
|
938
|
-
return add(fileData, { user });
|
|
939
|
-
}
|
|
940
|
-
async function updateFileInfo(id, { name, alternativeText, caption, folder: folder2 }, opts) {
|
|
941
|
-
const { user } = opts ?? {};
|
|
942
|
-
const dbFile = await findOne(id);
|
|
943
|
-
if (!dbFile) {
|
|
944
|
-
throw new NotFoundError();
|
|
945
|
-
}
|
|
946
|
-
const fileService = getService("file");
|
|
947
|
-
const newName = ___default.default.isNil(name) ? dbFile.name : name;
|
|
948
|
-
const newInfos = {
|
|
949
|
-
name: newName,
|
|
950
|
-
alternativeText: ___default.default.isNil(alternativeText) ? dbFile.alternativeText : alternativeText,
|
|
951
|
-
caption: ___default.default.isNil(caption) ? dbFile.caption : caption,
|
|
952
|
-
folder: ___default.default.isUndefined(folder2) ? dbFile.folder : folder2,
|
|
953
|
-
folderPath: ___default.default.isUndefined(folder2) ? dbFile.path : await fileService.getFolderPath(folder2)
|
|
954
|
-
};
|
|
955
|
-
return update2(id, newInfos, { user });
|
|
956
|
-
}
|
|
957
|
-
async function replace(id, { data, file: file2 }, opts) {
|
|
958
|
-
const { user } = opts ?? {};
|
|
959
|
-
const config2 = strapi2.config.get("plugin::upload");
|
|
960
|
-
const { isImage: isImage2 } = getService("image-manipulation");
|
|
961
|
-
const dbFile = await findOne(id);
|
|
962
|
-
if (!dbFile) {
|
|
963
|
-
throw new NotFoundError();
|
|
964
|
-
}
|
|
965
|
-
const tmpWorkingDirectory = await createAndAssignTmpWorkingDirectoryToFiles(file2);
|
|
966
|
-
let fileData;
|
|
967
|
-
try {
|
|
968
|
-
const { fileInfo } = data;
|
|
969
|
-
fileData = await enhanceAndValidateFile(file2, fileInfo);
|
|
970
|
-
___default.default.assign(fileData, {
|
|
971
|
-
hash: dbFile.hash,
|
|
972
|
-
ext: dbFile.ext
|
|
973
|
-
});
|
|
974
|
-
if (dbFile.provider === config2.provider) {
|
|
975
|
-
await strapi2.plugin("upload").provider.delete(dbFile);
|
|
976
|
-
if (dbFile.formats) {
|
|
977
|
-
await Promise.all(
|
|
978
|
-
Object.keys(dbFile.formats).map((key) => {
|
|
979
|
-
return strapi2.plugin("upload").provider.delete(dbFile.formats[key]);
|
|
980
|
-
})
|
|
981
|
-
);
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
___default.default.set(fileData, "formats", {});
|
|
985
|
-
if (await isImage2(fileData)) {
|
|
986
|
-
await uploadImage(fileData);
|
|
987
|
-
} else {
|
|
988
|
-
await getService("provider").upload(fileData);
|
|
989
|
-
}
|
|
990
|
-
___default.default.set(fileData, "provider", config2.provider);
|
|
991
|
-
} finally {
|
|
992
|
-
await fse__default.default.remove(tmpWorkingDirectory);
|
|
993
|
-
}
|
|
994
|
-
return update2(id, fileData, { user });
|
|
995
|
-
}
|
|
996
|
-
async function update2(id, values, opts) {
|
|
997
|
-
const { user } = opts ?? {};
|
|
998
|
-
const fileValues = { ...values };
|
|
999
|
-
if (user) {
|
|
1000
|
-
Object.assign(fileValues, {
|
|
1001
|
-
[UPDATED_BY_ATTRIBUTE]: user.id
|
|
1002
|
-
});
|
|
1003
|
-
}
|
|
1004
|
-
sendMediaMetrics(fileValues);
|
|
1005
|
-
const res = await strapi2.db.query(FILE_MODEL_UID).update({ where: { id }, data: fileValues });
|
|
1006
|
-
await emitEvent(MEDIA_UPDATE, res);
|
|
1007
|
-
return res;
|
|
1008
|
-
}
|
|
1009
|
-
async function add(values, opts) {
|
|
1010
|
-
const { user } = opts ?? {};
|
|
1011
|
-
const fileValues = { ...values };
|
|
1012
|
-
if (user) {
|
|
1013
|
-
Object.assign(fileValues, {
|
|
1014
|
-
[UPDATED_BY_ATTRIBUTE]: user.id,
|
|
1015
|
-
[CREATED_BY_ATTRIBUTE]: user.id
|
|
1016
|
-
});
|
|
1017
|
-
}
|
|
1018
|
-
sendMediaMetrics(fileValues);
|
|
1019
|
-
const res = await strapi2.db.query(FILE_MODEL_UID).create({ data: fileValues });
|
|
1020
|
-
await emitEvent(MEDIA_CREATE, res);
|
|
1021
|
-
return res;
|
|
1022
|
-
}
|
|
1023
|
-
function findOne(id, populate = {}) {
|
|
1024
|
-
const query = strapi2.get("query-params").transform(FILE_MODEL_UID, {
|
|
1025
|
-
populate
|
|
1026
|
-
});
|
|
1027
|
-
return strapi2.db.query(FILE_MODEL_UID).findOne({
|
|
1028
|
-
where: { id },
|
|
1029
|
-
...query
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
function findMany(query = {}) {
|
|
1033
|
-
return strapi2.db.query(FILE_MODEL_UID).findMany(strapi2.get("query-params").transform(FILE_MODEL_UID, query));
|
|
1034
|
-
}
|
|
1035
|
-
function findPage(query = {}) {
|
|
1036
|
-
return strapi2.db.query(FILE_MODEL_UID).findPage(strapi2.get("query-params").transform(FILE_MODEL_UID, query));
|
|
1037
|
-
}
|
|
1038
|
-
async function remove(file2) {
|
|
1039
|
-
const config2 = strapi2.config.get("plugin::upload");
|
|
1040
|
-
if (file2.provider === config2.provider) {
|
|
1041
|
-
await strapi2.plugin("upload").provider.delete(file2);
|
|
1042
|
-
if (file2.formats) {
|
|
1043
|
-
const keys = Object.keys(file2.formats);
|
|
1044
|
-
await Promise.all(
|
|
1045
|
-
keys.map((key) => {
|
|
1046
|
-
return strapi2.plugin("upload").provider.delete(file2.formats[key]);
|
|
1047
|
-
})
|
|
1048
|
-
);
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
const media = await strapi2.db.query(FILE_MODEL_UID).findOne({
|
|
1052
|
-
where: { id: file2.id }
|
|
1053
|
-
});
|
|
1054
|
-
await emitEvent(MEDIA_DELETE, media);
|
|
1055
|
-
return strapi2.db.query(FILE_MODEL_UID).delete({ where: { id: file2.id } });
|
|
1056
|
-
}
|
|
1057
|
-
async function getSettings() {
|
|
1058
|
-
const res = await strapi2.store({ type: "plugin", name: "upload", key: "settings" }).get({});
|
|
1059
|
-
return res;
|
|
1060
|
-
}
|
|
1061
|
-
function setSettings(value) {
|
|
1062
|
-
if (value.responsiveDimensions === true) {
|
|
1063
|
-
strapi2.telemetry.send("didEnableResponsiveDimensions");
|
|
1064
|
-
} else {
|
|
1065
|
-
strapi2.telemetry.send("didDisableResponsiveDimensions");
|
|
1066
|
-
}
|
|
1067
|
-
return strapi2.store({ type: "plugin", name: "upload", key: "settings" }).set({ value });
|
|
1068
|
-
}
|
|
1069
|
-
async function getConfiguration() {
|
|
1070
|
-
const res = await strapi2.store({
|
|
1071
|
-
type: "plugin",
|
|
1072
|
-
name: "upload",
|
|
1073
|
-
key: "view_configuration"
|
|
1074
|
-
}).get({});
|
|
1075
|
-
return res;
|
|
1076
|
-
}
|
|
1077
|
-
function setConfiguration(value) {
|
|
1078
|
-
return strapi2.store({ type: "plugin", name: "upload", key: "view_configuration" }).set({
|
|
1079
|
-
value
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
return {
|
|
1083
|
-
formatFileInfo,
|
|
1084
|
-
upload: upload2,
|
|
1085
|
-
updateFileInfo,
|
|
1086
|
-
replace,
|
|
1087
|
-
findOne,
|
|
1088
|
-
findMany,
|
|
1089
|
-
findPage,
|
|
1090
|
-
remove,
|
|
1091
|
-
getSettings,
|
|
1092
|
-
setSettings,
|
|
1093
|
-
getConfiguration,
|
|
1094
|
-
setConfiguration,
|
|
1095
|
-
/**
|
|
1096
|
-
* exposed for testing only
|
|
1097
|
-
* @internal
|
|
1098
|
-
*/
|
|
1099
|
-
_uploadImage: uploadImage
|
|
1100
|
-
};
|
|
1101
|
-
};
|
|
1102
|
-
const { bytesToKbytes } = utils.file;
|
|
1103
|
-
const FORMATS_TO_RESIZE = ["jpeg", "png", "webp", "tiff", "gif"];
|
|
1104
|
-
const FORMATS_TO_PROCESS = ["jpeg", "png", "webp", "tiff", "svg", "gif", "avif"];
|
|
1105
|
-
const FORMATS_TO_OPTIMIZE = ["jpeg", "png", "webp", "tiff", "avif"];
|
|
1106
|
-
const isOptimizableFormat = (format) => format !== void 0 && FORMATS_TO_OPTIMIZE.includes(format);
|
|
1107
|
-
const writeStreamToFile = (stream, path2) => new Promise((resolve, reject) => {
|
|
1108
|
-
const writeStream = fs__default.default.createWriteStream(path2);
|
|
1109
|
-
stream.on("error", reject);
|
|
1110
|
-
stream.pipe(writeStream);
|
|
1111
|
-
writeStream.on("close", resolve);
|
|
1112
|
-
writeStream.on("error", reject);
|
|
1113
|
-
});
|
|
1114
|
-
const getMetadata = (file2) => {
|
|
1115
|
-
if (!file2.filepath) {
|
|
1116
|
-
return new Promise((resolve, reject) => {
|
|
1117
|
-
const pipeline = sharp__default.default();
|
|
1118
|
-
pipeline.metadata().then(resolve).catch(reject);
|
|
1119
|
-
file2.getStream().pipe(pipeline);
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1122
|
-
return sharp__default.default(file2.filepath).metadata();
|
|
1123
|
-
};
|
|
1124
|
-
const getDimensions = async (file2) => {
|
|
1125
|
-
const { width = null, height = null } = await getMetadata(file2);
|
|
1126
|
-
return { width, height };
|
|
1127
|
-
};
|
|
1128
|
-
const THUMBNAIL_RESIZE_OPTIONS = {
|
|
1129
|
-
width: 245,
|
|
1130
|
-
height: 156,
|
|
1131
|
-
fit: "inside"
|
|
1132
|
-
};
|
|
1133
|
-
const resizeFileTo = async (file2, options, {
|
|
1134
|
-
name,
|
|
1135
|
-
hash
|
|
1136
|
-
}) => {
|
|
1137
|
-
const filePath = file2.tmpWorkingDirectory ? path.join(file2.tmpWorkingDirectory, hash) : hash;
|
|
1138
|
-
let newInfo;
|
|
1139
|
-
if (!file2.filepath) {
|
|
1140
|
-
const transform = sharp__default.default().resize(options).on("info", (info) => {
|
|
1141
|
-
newInfo = info;
|
|
1142
|
-
});
|
|
1143
|
-
await writeStreamToFile(file2.getStream().pipe(transform), filePath);
|
|
1144
|
-
} else {
|
|
1145
|
-
newInfo = await sharp__default.default(file2.filepath).resize(options).toFile(filePath);
|
|
1146
|
-
}
|
|
1147
|
-
const { width, height, size } = newInfo ?? {};
|
|
1148
|
-
const newFile = {
|
|
1149
|
-
name,
|
|
1150
|
-
hash,
|
|
1151
|
-
ext: file2.ext,
|
|
1152
|
-
mime: file2.mime,
|
|
1153
|
-
filepath: filePath,
|
|
1154
|
-
path: file2.path || null,
|
|
1155
|
-
getStream: () => fs__default.default.createReadStream(filePath)
|
|
1156
|
-
};
|
|
1157
|
-
Object.assign(newFile, {
|
|
1158
|
-
width,
|
|
1159
|
-
height,
|
|
1160
|
-
size: size ? bytesToKbytes(size) : 0,
|
|
1161
|
-
sizeInBytes: size
|
|
1162
|
-
});
|
|
1163
|
-
return newFile;
|
|
1164
|
-
};
|
|
1165
|
-
const generateThumbnail = async (file2) => {
|
|
1166
|
-
if (file2.width && file2.height && (file2.width > THUMBNAIL_RESIZE_OPTIONS.width || file2.height > THUMBNAIL_RESIZE_OPTIONS.height)) {
|
|
1167
|
-
return resizeFileTo(file2, THUMBNAIL_RESIZE_OPTIONS, {
|
|
1168
|
-
name: `thumbnail_${file2.name}`,
|
|
1169
|
-
hash: `thumbnail_${file2.hash}`
|
|
1170
|
-
});
|
|
1171
|
-
}
|
|
1172
|
-
return null;
|
|
1173
|
-
};
|
|
1174
|
-
const optimize = async (file2) => {
|
|
1175
|
-
const { sizeOptimization = false, autoOrientation = false } = await getService("upload").getSettings() ?? {};
|
|
1176
|
-
const { format, size } = await getMetadata(file2);
|
|
1177
|
-
if ((sizeOptimization || autoOrientation) && isOptimizableFormat(format)) {
|
|
1178
|
-
let transformer;
|
|
1179
|
-
if (!file2.filepath) {
|
|
1180
|
-
transformer = sharp__default.default();
|
|
1181
|
-
} else {
|
|
1182
|
-
transformer = sharp__default.default(file2.filepath);
|
|
1183
|
-
}
|
|
1184
|
-
transformer[format]({ quality: sizeOptimization ? 80 : 100 });
|
|
1185
|
-
if (autoOrientation) {
|
|
1186
|
-
transformer.rotate();
|
|
1187
|
-
}
|
|
1188
|
-
const filePath = file2.tmpWorkingDirectory ? path.join(file2.tmpWorkingDirectory, `optimized-${file2.hash}`) : `optimized-${file2.hash}`;
|
|
1189
|
-
let newInfo;
|
|
1190
|
-
if (!file2.filepath) {
|
|
1191
|
-
transformer.on("info", (info) => {
|
|
1192
|
-
newInfo = info;
|
|
1193
|
-
});
|
|
1194
|
-
await writeStreamToFile(file2.getStream().pipe(transformer), filePath);
|
|
1195
|
-
} else {
|
|
1196
|
-
newInfo = await transformer.toFile(filePath);
|
|
1197
|
-
}
|
|
1198
|
-
const { width: newWidth, height: newHeight, size: newSize } = newInfo ?? {};
|
|
1199
|
-
const newFile = { ...file2 };
|
|
1200
|
-
newFile.getStream = () => fs__default.default.createReadStream(filePath);
|
|
1201
|
-
newFile.filepath = filePath;
|
|
1202
|
-
if (newSize && size && newSize > size) {
|
|
1203
|
-
return file2;
|
|
1204
|
-
}
|
|
1205
|
-
return Object.assign(newFile, {
|
|
1206
|
-
width: newWidth,
|
|
1207
|
-
height: newHeight,
|
|
1208
|
-
size: newSize ? bytesToKbytes(newSize) : 0,
|
|
1209
|
-
sizeInBytes: newSize
|
|
1210
|
-
});
|
|
1211
|
-
}
|
|
1212
|
-
return file2;
|
|
1213
|
-
};
|
|
1214
|
-
const DEFAULT_BREAKPOINTS = {
|
|
1215
|
-
large: 1e3,
|
|
1216
|
-
medium: 750,
|
|
1217
|
-
small: 500
|
|
1218
|
-
};
|
|
1219
|
-
const getBreakpoints = () => strapi.config.get("plugin::upload.breakpoints", DEFAULT_BREAKPOINTS);
|
|
1220
|
-
const generateResponsiveFormats = async (file2) => {
|
|
1221
|
-
const { responsiveDimensions = false } = await getService("upload").getSettings() ?? {};
|
|
1222
|
-
if (!responsiveDimensions) return [];
|
|
1223
|
-
const originalDimensions = await getDimensions(file2);
|
|
1224
|
-
const breakpoints = getBreakpoints();
|
|
1225
|
-
return Promise.all(
|
|
1226
|
-
Object.keys(breakpoints).map((key) => {
|
|
1227
|
-
const breakpoint = breakpoints[key];
|
|
1228
|
-
if (breakpointSmallerThan(breakpoint, originalDimensions)) {
|
|
1229
|
-
return generateBreakpoint(key, { file: file2, breakpoint });
|
|
1230
|
-
}
|
|
1231
|
-
return void 0;
|
|
1232
|
-
})
|
|
1233
|
-
);
|
|
1234
|
-
};
|
|
1235
|
-
const generateBreakpoint = async (key, { file: file2, breakpoint }) => {
|
|
1236
|
-
const newFile = await resizeFileTo(
|
|
1237
|
-
file2,
|
|
1238
|
-
{
|
|
1239
|
-
width: breakpoint,
|
|
1240
|
-
height: breakpoint,
|
|
1241
|
-
fit: "inside"
|
|
1242
|
-
},
|
|
1243
|
-
{
|
|
1244
|
-
name: `${key}_${file2.name}`,
|
|
1245
|
-
hash: `${key}_${file2.hash}`
|
|
1246
|
-
}
|
|
1247
|
-
);
|
|
1248
|
-
return {
|
|
1249
|
-
key,
|
|
1250
|
-
file: newFile
|
|
1251
|
-
};
|
|
1252
|
-
};
|
|
1253
|
-
const breakpointSmallerThan = (breakpoint, { width, height }) => {
|
|
1254
|
-
return breakpoint < (width ?? 0) || breakpoint < (height ?? 0);
|
|
1255
|
-
};
|
|
1256
|
-
const isFaultyImage = async (file2) => {
|
|
1257
|
-
if (!file2.filepath) {
|
|
1258
|
-
return new Promise((resolve, reject) => {
|
|
1259
|
-
const pipeline = sharp__default.default();
|
|
1260
|
-
pipeline.stats().then(resolve).catch(reject);
|
|
1261
|
-
file2.getStream().pipe(pipeline);
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
try {
|
|
1265
|
-
await sharp__default.default(file2.filepath).stats();
|
|
1266
|
-
return false;
|
|
1267
|
-
} catch (e) {
|
|
1268
|
-
return true;
|
|
1269
|
-
}
|
|
1270
|
-
};
|
|
1271
|
-
const isOptimizableImage = async (file2) => {
|
|
1272
|
-
let format;
|
|
1273
|
-
try {
|
|
1274
|
-
const metadata = await getMetadata(file2);
|
|
1275
|
-
format = metadata.format;
|
|
1276
|
-
} catch (e) {
|
|
1277
|
-
return false;
|
|
1278
|
-
}
|
|
1279
|
-
return format && FORMATS_TO_OPTIMIZE.includes(format);
|
|
1280
|
-
};
|
|
1281
|
-
const isResizableImage = async (file2) => {
|
|
1282
|
-
let format;
|
|
1283
|
-
try {
|
|
1284
|
-
const metadata = await getMetadata(file2);
|
|
1285
|
-
format = metadata.format;
|
|
1286
|
-
} catch (e) {
|
|
1287
|
-
return false;
|
|
1288
|
-
}
|
|
1289
|
-
return format && FORMATS_TO_RESIZE.includes(format);
|
|
1290
|
-
};
|
|
1291
|
-
const isImage = async (file2) => {
|
|
1292
|
-
let format;
|
|
1293
|
-
try {
|
|
1294
|
-
const metadata = await getMetadata(file2);
|
|
1295
|
-
format = metadata.format;
|
|
1296
|
-
} catch (e) {
|
|
1297
|
-
return false;
|
|
1298
|
-
}
|
|
1299
|
-
return format && FORMATS_TO_PROCESS.includes(format);
|
|
1300
|
-
};
|
|
1301
|
-
const imageManipulation = {
|
|
1302
|
-
isFaultyImage,
|
|
1303
|
-
isOptimizableImage,
|
|
1304
|
-
isResizableImage,
|
|
1305
|
-
isImage,
|
|
1306
|
-
getDimensions,
|
|
1307
|
-
generateResponsiveFormats,
|
|
1308
|
-
generateThumbnail,
|
|
1309
|
-
optimize
|
|
1310
|
-
};
|
|
1311
|
-
const setPathIdAndPath = async (folder2) => {
|
|
1312
|
-
const { max } = await strapi.db.queryBuilder(FOLDER_MODEL_UID).max("pathId").first().execute();
|
|
1313
|
-
const pathId = max + 1;
|
|
1314
|
-
let parentPath = "/";
|
|
1315
|
-
if (folder2.parent) {
|
|
1316
|
-
const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folder2.parent } });
|
|
1317
|
-
parentPath = parentFolder.path;
|
|
1318
|
-
}
|
|
1319
|
-
return Object.assign(folder2, {
|
|
1320
|
-
pathId,
|
|
1321
|
-
path: utils.strings.joinBy("/", parentPath, `${pathId}`)
|
|
1322
|
-
});
|
|
1323
|
-
};
|
|
1324
|
-
const create = async (folderData, opts) => {
|
|
1325
|
-
const folderService = getService("folder");
|
|
1326
|
-
const { user } = opts || {};
|
|
1327
|
-
let enrichedFolder = await folderService.setPathIdAndPath(folderData);
|
|
1328
|
-
if (user) {
|
|
1329
|
-
enrichedFolder = await utils.setCreatorFields({ user })(enrichedFolder);
|
|
1330
|
-
}
|
|
1331
|
-
const folder2 = await strapi.db.query(FOLDER_MODEL_UID).create({ data: enrichedFolder });
|
|
1332
|
-
strapi.eventHub.emit("media-folder.create", { folder: folder2 });
|
|
1333
|
-
return folder2;
|
|
1334
|
-
};
|
|
1335
|
-
const deleteByIds$1 = async (ids = []) => {
|
|
1336
|
-
const folders = await strapi.db.query(FOLDER_MODEL_UID).findMany({ where: { id: { $in: ids } } });
|
|
1337
|
-
if (folders.length === 0) {
|
|
1338
|
-
return {
|
|
1339
|
-
folders: [],
|
|
1340
|
-
totalFolderNumber: 0,
|
|
1341
|
-
totalFileNumber: 0
|
|
1342
|
-
};
|
|
1343
|
-
}
|
|
1344
|
-
const pathsToDelete = fp.map("path", folders);
|
|
1345
|
-
const filesToDelete = await strapi.db.query(FILE_MODEL_UID).findMany({
|
|
1346
|
-
where: {
|
|
1347
|
-
$or: pathsToDelete.flatMap((path2) => [
|
|
1348
|
-
{ folderPath: { $eq: path2 } },
|
|
1349
|
-
{ folderPath: { $startsWith: `${path2}/` } }
|
|
1350
|
-
])
|
|
1351
|
-
}
|
|
1352
|
-
});
|
|
1353
|
-
await Promise.all(filesToDelete.map((file2) => getService("upload").remove(file2)));
|
|
1354
|
-
const { count: totalFolderNumber } = await strapi.db.query(FOLDER_MODEL_UID).deleteMany({
|
|
1355
|
-
where: {
|
|
1356
|
-
$or: pathsToDelete.flatMap((path2) => [
|
|
1357
|
-
{ path: { $eq: path2 } },
|
|
1358
|
-
{ path: { $startsWith: `${path2}/` } }
|
|
1359
|
-
])
|
|
1360
|
-
}
|
|
1361
|
-
});
|
|
1362
|
-
strapi.eventHub.emit("media-folder.delete", { folders });
|
|
1363
|
-
return {
|
|
1364
|
-
folders,
|
|
1365
|
-
totalFolderNumber,
|
|
1366
|
-
totalFileNumber: filesToDelete.length
|
|
1367
|
-
};
|
|
1368
|
-
};
|
|
1369
|
-
const update = async (id, {
|
|
1370
|
-
name,
|
|
1371
|
-
parent
|
|
1372
|
-
}, { user }) => {
|
|
1373
|
-
if (fp.isUndefined(parent)) {
|
|
1374
|
-
const existingFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id } });
|
|
1375
|
-
if (!existingFolder) {
|
|
1376
|
-
return void 0;
|
|
1377
|
-
}
|
|
1378
|
-
const newFolder = utils.setCreatorFields({ user, isEdition: true })({ name, parent });
|
|
1379
|
-
if (fp.isUndefined(parent)) {
|
|
1380
|
-
const folder2 = await strapi.db.query(FOLDER_MODEL_UID).update({ where: { id }, data: newFolder });
|
|
1381
|
-
return folder2;
|
|
1382
|
-
}
|
|
1383
|
-
} else {
|
|
1384
|
-
const trx = await strapi.db.transaction();
|
|
1385
|
-
try {
|
|
1386
|
-
const existingFolder = await strapi.db.queryBuilder(FOLDER_MODEL_UID).select(["pathId", "path"]).where({ id }).transacting(trx.get()).forUpdate().first().execute();
|
|
1387
|
-
const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;
|
|
1388
|
-
await strapi.db.queryBuilder(joinTable.name).transacting(trx.get()).delete().where({ [joinTable.joinColumn.name]: id }).execute();
|
|
1389
|
-
if (parent !== null) {
|
|
1390
|
-
await strapi.db.queryBuilder(joinTable.name).transacting(trx.get()).insert({ [joinTable.inverseJoinColumn.name]: parent, [joinTable.joinColumn.name]: id }).where({ [joinTable.joinColumn.name]: id }).execute();
|
|
1391
|
-
}
|
|
1392
|
-
let destinationFolderPath = "/";
|
|
1393
|
-
if (parent !== null) {
|
|
1394
|
-
const destinationFolder = await strapi.db.queryBuilder(FOLDER_MODEL_UID).select("path").where({ id: parent }).transacting(trx.get()).first().execute();
|
|
1395
|
-
destinationFolderPath = destinationFolder.path;
|
|
1396
|
-
}
|
|
1397
|
-
const folderTable = strapi.getModel(FOLDER_MODEL_UID).collectionName;
|
|
1398
|
-
const fileTable = strapi.getModel(FILE_MODEL_UID).collectionName;
|
|
1399
|
-
const folderPathColumnName = (
|
|
1400
|
-
// @ts-expect-error - no dynamic types
|
|
1401
|
-
strapi.db.metadata.get(FILE_MODEL_UID).attributes.folderPath.columnName
|
|
1402
|
-
);
|
|
1403
|
-
const pathColumnName = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;
|
|
1404
|
-
await strapi.db.getConnection(folderTable).transacting(trx.get()).where(pathColumnName, existingFolder.path).orWhere(pathColumnName, "like", `${existingFolder.path}/%`).update(
|
|
1405
|
-
pathColumnName,
|
|
1406
|
-
strapi.db.connection.raw("REPLACE(??, ?, ?)", [
|
|
1407
|
-
pathColumnName,
|
|
1408
|
-
existingFolder.path,
|
|
1409
|
-
utils.strings.joinBy("/", destinationFolderPath, `${existingFolder.pathId}`)
|
|
1410
|
-
])
|
|
1411
|
-
);
|
|
1412
|
-
await strapi.db.getConnection(fileTable).transacting(trx.get()).where(folderPathColumnName, existingFolder.path).orWhere(folderPathColumnName, "like", `${existingFolder.path}/%`).update(
|
|
1413
|
-
folderPathColumnName,
|
|
1414
|
-
strapi.db.connection.raw("REPLACE(??, ?, ?)", [
|
|
1415
|
-
folderPathColumnName,
|
|
1416
|
-
existingFolder.path,
|
|
1417
|
-
utils.strings.joinBy("/", destinationFolderPath, `${existingFolder.pathId}`)
|
|
1418
|
-
])
|
|
1419
|
-
);
|
|
1420
|
-
await trx.commit();
|
|
1421
|
-
} catch (e) {
|
|
1422
|
-
await trx.rollback();
|
|
1423
|
-
throw e;
|
|
1424
|
-
}
|
|
1425
|
-
const newFolder = utils.setCreatorFields({ user, isEdition: true })({ name });
|
|
1426
|
-
const folder2 = await strapi.db.query(FOLDER_MODEL_UID).update({ where: { id }, data: newFolder });
|
|
1427
|
-
strapi.eventHub.emit("media-folder.update", { folder: folder2 });
|
|
1428
|
-
return folder2;
|
|
1429
|
-
}
|
|
1430
|
-
};
|
|
1431
|
-
const exists = async (params = {}) => {
|
|
1432
|
-
const count = await strapi.db.query(FOLDER_MODEL_UID).count({ where: params });
|
|
1433
|
-
return count > 0;
|
|
1434
|
-
};
|
|
1435
|
-
const getStructure = async () => {
|
|
1436
|
-
const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;
|
|
1437
|
-
const qb = strapi.db.queryBuilder(FOLDER_MODEL_UID);
|
|
1438
|
-
const alias = qb.getAlias();
|
|
1439
|
-
const folders = await qb.select(["id", "name", `${alias}.${joinTable.inverseJoinColumn.name} as parent`]).join({
|
|
1440
|
-
alias,
|
|
1441
|
-
referencedTable: joinTable.name,
|
|
1442
|
-
referencedColumn: joinTable.joinColumn.name,
|
|
1443
|
-
rootColumn: joinTable.joinColumn.referencedColumn,
|
|
1444
|
-
rootTable: qb.alias
|
|
1445
|
-
}).execute({ mapResults: false });
|
|
1446
|
-
const folderMap = {
|
|
1447
|
-
null: { children: [] }
|
|
1448
|
-
};
|
|
1449
|
-
folders.forEach((f) => {
|
|
1450
|
-
folderMap[f.id] = { ...f, children: [] };
|
|
1451
|
-
});
|
|
1452
|
-
folders.forEach((f) => {
|
|
1453
|
-
const parentId = f.parent || "null";
|
|
1454
|
-
if (!folderMap[parentId]) {
|
|
1455
|
-
folderMap[parentId] = { children: [] };
|
|
1456
|
-
}
|
|
1457
|
-
folderMap[parentId].children.push(folderMap[f.id]);
|
|
1458
|
-
folderMap[parentId].children = fp.sortBy("name", folderMap[parentId].children);
|
|
1459
|
-
delete folderMap[f.id].parent;
|
|
1460
|
-
});
|
|
1461
|
-
return folderMap.null.children;
|
|
1462
|
-
};
|
|
1463
|
-
const folder = {
|
|
1464
|
-
create,
|
|
1465
|
-
exists,
|
|
1466
|
-
deleteByIds: deleteByIds$1,
|
|
1467
|
-
update,
|
|
1468
|
-
setPathIdAndPath,
|
|
1469
|
-
getStructure
|
|
1470
|
-
};
|
|
1471
|
-
const getFolderPath = async (folderId) => {
|
|
1472
|
-
if (!folderId) return "/";
|
|
1473
|
-
const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } });
|
|
1474
|
-
return parentFolder.path;
|
|
1475
|
-
};
|
|
1476
|
-
const deleteByIds = async (ids = []) => {
|
|
1477
|
-
const filesToDelete = await strapi.db.query(FILE_MODEL_UID).findMany({ where: { id: { $in: ids } } });
|
|
1478
|
-
await Promise.all(filesToDelete.map((file2) => getService("upload").remove(file2)));
|
|
1479
|
-
return filesToDelete;
|
|
1480
|
-
};
|
|
1481
|
-
const signFileUrls = async (file2) => {
|
|
1482
|
-
const { provider: provider2 } = strapi.plugins.upload;
|
|
1483
|
-
const { provider: providerConfig } = strapi.config.get("plugin::upload");
|
|
1484
|
-
const isPrivate = await provider2.isPrivate();
|
|
1485
|
-
file2.isUrlSigned = false;
|
|
1486
|
-
if (file2.provider !== providerConfig || !isPrivate) {
|
|
1487
|
-
return file2;
|
|
1488
|
-
}
|
|
1489
|
-
const signUrl = async (file22) => {
|
|
1490
|
-
const signedUrl = await provider2.getSignedUrl(file22);
|
|
1491
|
-
file22.url = signedUrl.url;
|
|
1492
|
-
file22.isUrlSigned = true;
|
|
1493
|
-
};
|
|
1494
|
-
const signedFile = fp.cloneDeep(file2);
|
|
1495
|
-
await signUrl(signedFile);
|
|
1496
|
-
if (file2.formats) {
|
|
1497
|
-
await utils.async.map(Object.values(signedFile.formats ?? {}), signUrl);
|
|
1498
|
-
}
|
|
1499
|
-
return signedFile;
|
|
1500
|
-
};
|
|
1501
|
-
const file = { getFolderPath, deleteByIds, signFileUrls };
|
|
1502
|
-
const getWeeklyCronScheduleAt = (date) => `${date.getSeconds()} ${date.getMinutes()} ${date.getHours()} * * ${date.getDay()}`;
|
|
1503
|
-
const ONE_WEEK = 7 * 24 * 60 * 60 * 1e3;
|
|
1504
|
-
const getMetricsStoreValue = async () => {
|
|
1505
|
-
const value = await strapi.store.get({ type: "plugin", name: "upload", key: "metrics" });
|
|
1506
|
-
return fp.defaultTo({}, value);
|
|
1507
|
-
};
|
|
1508
|
-
const setMetricsStoreValue = (value) => strapi.store.set({ type: "plugin", name: "upload", key: "metrics", value });
|
|
1509
|
-
const weeklyMetrics = ({ strapi: strapi2 }) => ({
|
|
1510
|
-
async computeMetrics() {
|
|
1511
|
-
const pathColName = strapi2.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;
|
|
1512
|
-
const folderTable = strapi2.getModel(FOLDER_MODEL_UID).collectionName;
|
|
1513
|
-
let keepOnlySlashesSQLString = "??";
|
|
1514
|
-
const queryParams = [pathColName];
|
|
1515
|
-
for (let i = 0; i < 10; i += 1) {
|
|
1516
|
-
keepOnlySlashesSQLString = `REPLACE(${keepOnlySlashesSQLString}, ?, ?)`;
|
|
1517
|
-
queryParams.push(String(i), "");
|
|
1518
|
-
}
|
|
1519
|
-
const res = await strapi2.db.getConnection(folderTable).select(
|
|
1520
|
-
strapi2.db.connection.raw(
|
|
1521
|
-
`LENGTH(${keepOnlySlashesSQLString}) AS depth, COUNT(*) AS occurence`,
|
|
1522
|
-
queryParams
|
|
1523
|
-
)
|
|
1524
|
-
).groupBy("depth");
|
|
1525
|
-
const folderLevelsArray = res.map((map) => ({
|
|
1526
|
-
depth: Number(map.depth),
|
|
1527
|
-
occurence: Number(map.occurence)
|
|
1528
|
-
}));
|
|
1529
|
-
let product = 0;
|
|
1530
|
-
let folderNumber = 0;
|
|
1531
|
-
let maxDepth = 0;
|
|
1532
|
-
for (const folderLevel of folderLevelsArray) {
|
|
1533
|
-
product += folderLevel.depth * folderLevel.occurence;
|
|
1534
|
-
folderNumber += folderLevel.occurence;
|
|
1535
|
-
if (folderLevel.depth > maxDepth) {
|
|
1536
|
-
maxDepth = folderLevel.depth;
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
const averageDepth = folderNumber !== 0 ? product / folderNumber : 0;
|
|
1540
|
-
let sumOfDeviation = 0;
|
|
1541
|
-
for (const folderLevel of folderLevelsArray) {
|
|
1542
|
-
sumOfDeviation += Math.abs(folderLevel.depth - averageDepth) * folderLevel.occurence;
|
|
1543
|
-
}
|
|
1544
|
-
const averageDeviationDepth = folderNumber !== 0 ? sumOfDeviation / folderNumber : 0;
|
|
1545
|
-
const assetNumber = await strapi2.db.query(FILE_MODEL_UID).count();
|
|
1546
|
-
return {
|
|
1547
|
-
assetNumber,
|
|
1548
|
-
folderNumber,
|
|
1549
|
-
averageDepth,
|
|
1550
|
-
maxDepth,
|
|
1551
|
-
averageDeviationDepth
|
|
1552
|
-
};
|
|
1553
|
-
},
|
|
1554
|
-
async sendMetrics() {
|
|
1555
|
-
const metrics2 = await this.computeMetrics();
|
|
1556
|
-
strapi2.telemetry.send("didSendUploadPropertiesOnceAWeek", {
|
|
1557
|
-
groupProperties: { metrics: metrics2 }
|
|
1558
|
-
});
|
|
1559
|
-
const metricsInfoStored = await getMetricsStoreValue();
|
|
1560
|
-
await setMetricsStoreValue({ ...metricsInfoStored, lastWeeklyUpdate: (/* @__PURE__ */ new Date()).getTime() });
|
|
1561
|
-
},
|
|
1562
|
-
async ensureWeeklyStoredCronSchedule() {
|
|
1563
|
-
const metricsInfoStored = await getMetricsStoreValue();
|
|
1564
|
-
const { weeklySchedule: currentSchedule, lastWeeklyUpdate } = metricsInfoStored;
|
|
1565
|
-
const now = /* @__PURE__ */ new Date();
|
|
1566
|
-
let weeklySchedule = currentSchedule;
|
|
1567
|
-
if (!weeklySchedule || !lastWeeklyUpdate || lastWeeklyUpdate + ONE_WEEK < now.getTime()) {
|
|
1568
|
-
weeklySchedule = getWeeklyCronScheduleAt(dateFns.add(now, { minutes: 5 }));
|
|
1569
|
-
await setMetricsStoreValue({ ...metricsInfoStored, weeklySchedule });
|
|
1570
|
-
return weeklySchedule;
|
|
1571
|
-
}
|
|
1572
|
-
return weeklySchedule;
|
|
1573
|
-
},
|
|
1574
|
-
async registerCron() {
|
|
1575
|
-
const weeklySchedule = await this.ensureWeeklyStoredCronSchedule();
|
|
1576
|
-
strapi2.cron.add({
|
|
1577
|
-
uploadWeekly: {
|
|
1578
|
-
task: this.sendMetrics.bind(this),
|
|
1579
|
-
options: weeklySchedule
|
|
1580
|
-
}
|
|
1581
|
-
});
|
|
1582
|
-
}
|
|
1583
|
-
});
|
|
1584
|
-
const getProviderName = () => strapi.config.get("plugin::upload.provider", "local");
|
|
1585
|
-
const isProviderPrivate = async () => strapi.plugin("upload").provider.isPrivate();
|
|
1586
|
-
const metrics = ({ strapi: strapi2 }) => ({
|
|
1587
|
-
async sendUploadPluginMetrics() {
|
|
1588
|
-
const uploadProvider = getProviderName();
|
|
1589
|
-
const privateProvider = await isProviderPrivate();
|
|
1590
|
-
strapi2.telemetry.send("didInitializePluginUpload", {
|
|
1591
|
-
groupProperties: {
|
|
1592
|
-
uploadProvider,
|
|
1593
|
-
privateProvider
|
|
1594
|
-
}
|
|
1595
|
-
});
|
|
1596
|
-
}
|
|
1597
|
-
});
|
|
1598
|
-
const getStore = () => strapi.store({ type: "plugin", name: "upload", key: "api-folder" });
|
|
1599
|
-
const createApiUploadFolder = async () => {
|
|
1600
|
-
let name = API_UPLOAD_FOLDER_BASE_NAME;
|
|
1601
|
-
const folderService = getService("folder");
|
|
1602
|
-
let exists2 = true;
|
|
1603
|
-
let index2 = 1;
|
|
1604
|
-
while (exists2) {
|
|
1605
|
-
exists2 = await folderService.exists({ name, parent: null });
|
|
1606
|
-
if (exists2) {
|
|
1607
|
-
name = `${API_UPLOAD_FOLDER_BASE_NAME} (${index2})`;
|
|
1608
|
-
index2 += 1;
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1611
|
-
const folder2 = await folderService.create({ name });
|
|
1612
|
-
await getStore().set({ value: { id: folder2.id } });
|
|
1613
|
-
return folder2;
|
|
1614
|
-
};
|
|
1615
|
-
const getAPIUploadFolder = async () => {
|
|
1616
|
-
const storeValue = await getStore().get({});
|
|
1617
|
-
const folderId = fp.get("id", storeValue);
|
|
1618
|
-
const folder2 = folderId ? await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } }) : null;
|
|
1619
|
-
return fp.isNil(folder2) ? createApiUploadFolder() : folder2;
|
|
1620
|
-
};
|
|
1621
|
-
const apiUploadFolder = {
|
|
1622
|
-
getAPIUploadFolder
|
|
1623
|
-
};
|
|
1624
|
-
function isFile(value, attribute) {
|
|
1625
|
-
if (!value || attribute.type !== "media") {
|
|
1626
|
-
return false;
|
|
1627
|
-
}
|
|
1628
|
-
return true;
|
|
1629
|
-
}
|
|
1630
|
-
const signEntityMediaVisitor = async ({ key, value, attribute }, { set }) => {
|
|
1631
|
-
const { signFileUrls: signFileUrls2 } = getService("file");
|
|
1632
|
-
if (!attribute) {
|
|
1633
|
-
return;
|
|
1634
|
-
}
|
|
1635
|
-
if (attribute.type !== "media") {
|
|
1636
|
-
return;
|
|
1637
|
-
}
|
|
1638
|
-
if (isFile(value, attribute)) {
|
|
1639
|
-
if (attribute.multiple) {
|
|
1640
|
-
const signedFiles = await utils.async.map(value, signFileUrls2);
|
|
1641
|
-
set(key, signedFiles);
|
|
1642
|
-
return;
|
|
1643
|
-
}
|
|
1644
|
-
const signedFile = await signFileUrls2(value);
|
|
1645
|
-
set(key, signedFile);
|
|
1646
|
-
}
|
|
1647
|
-
};
|
|
1648
|
-
const signEntityMedia = async (entity, uid) => {
|
|
1649
|
-
const model = strapi.getModel(uid);
|
|
1650
|
-
return utils.traverseEntity(
|
|
1651
|
-
// @ts-expect-error - FIXME: fix traverseEntity using wrong types
|
|
1652
|
-
signEntityMediaVisitor,
|
|
1653
|
-
{ schema: model, getModel: strapi.getModel.bind(strapi) },
|
|
1654
|
-
entity
|
|
1655
|
-
);
|
|
1656
|
-
};
|
|
1657
|
-
const signFileUrlsOnDocumentService = async () => {
|
|
1658
|
-
const { provider: provider2 } = strapi.plugins.upload;
|
|
1659
|
-
const isPrivate = await provider2.isPrivate();
|
|
1660
|
-
if (!isPrivate) {
|
|
1661
|
-
return;
|
|
1662
|
-
}
|
|
1663
|
-
strapi.documents.use(async (ctx, next) => {
|
|
1664
|
-
const uid = ctx.uid;
|
|
1665
|
-
const result = await next();
|
|
1666
|
-
if (ctx.action === "findMany") {
|
|
1667
|
-
return utils.async.map(result, (entry) => signEntityMedia(entry, uid));
|
|
1668
|
-
}
|
|
1669
|
-
if (ctx.action === "findFirst" || ctx.action === "findOne" || ctx.action === "create" || ctx.action === "update") {
|
|
1670
|
-
return signEntityMedia(result, uid);
|
|
1671
|
-
}
|
|
1672
|
-
if (ctx.action === "delete" || ctx.action === "clone" || ctx.action === "publish" || ctx.action === "unpublish" || ctx.action === "discardDraft") {
|
|
1673
|
-
return {
|
|
1674
|
-
...result,
|
|
1675
|
-
entries: await utils.async.map(result.entries, (entry) => signEntityMedia(entry, uid))
|
|
1676
|
-
};
|
|
1677
|
-
}
|
|
1678
|
-
return result;
|
|
1679
|
-
});
|
|
1680
|
-
};
|
|
1681
|
-
const extensions = {
|
|
1682
|
-
signFileUrlsOnDocumentService
|
|
1683
|
-
};
|
|
1684
|
-
const services = {
|
|
1685
|
-
provider,
|
|
1686
|
-
upload,
|
|
1687
|
-
folder,
|
|
1688
|
-
file,
|
|
1689
|
-
weeklyMetrics,
|
|
1690
|
-
metrics,
|
|
1691
|
-
"image-manipulation": imageManipulation,
|
|
1692
|
-
"api-upload-folder": apiUploadFolder,
|
|
1693
|
-
extensions
|
|
1694
|
-
};
|
|
1695
|
-
const routes$3 = {
|
|
1696
|
-
type: "admin",
|
|
1697
|
-
routes: [
|
|
1698
|
-
{
|
|
1699
|
-
method: "GET",
|
|
1700
|
-
path: "/settings",
|
|
1701
|
-
handler: "admin-settings.getSettings",
|
|
1702
|
-
config: {
|
|
1703
|
-
policies: [
|
|
1704
|
-
"admin::isAuthenticatedAdmin",
|
|
1705
|
-
{
|
|
1706
|
-
name: "admin::hasPermissions",
|
|
1707
|
-
config: {
|
|
1708
|
-
actions: ["plugin::upload.settings.read"]
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
]
|
|
1712
|
-
}
|
|
1713
|
-
},
|
|
1714
|
-
{
|
|
1715
|
-
method: "PUT",
|
|
1716
|
-
path: "/settings",
|
|
1717
|
-
handler: "admin-settings.updateSettings",
|
|
1718
|
-
config: {
|
|
1719
|
-
policies: [
|
|
1720
|
-
"admin::isAuthenticatedAdmin",
|
|
1721
|
-
{
|
|
1722
|
-
name: "admin::hasPermissions",
|
|
1723
|
-
config: {
|
|
1724
|
-
actions: ["plugin::upload.settings.read"]
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
]
|
|
1728
|
-
}
|
|
1729
|
-
},
|
|
1730
|
-
{
|
|
1731
|
-
method: "POST",
|
|
1732
|
-
path: "/",
|
|
1733
|
-
handler: "admin-upload.upload",
|
|
1734
|
-
config: {
|
|
1735
|
-
policies: ["admin::isAuthenticatedAdmin"]
|
|
1736
|
-
}
|
|
1737
|
-
},
|
|
1738
|
-
{
|
|
1739
|
-
method: "GET",
|
|
1740
|
-
path: "/files",
|
|
1741
|
-
handler: "admin-file.find",
|
|
1742
|
-
config: {
|
|
1743
|
-
policies: [
|
|
1744
|
-
"admin::isAuthenticatedAdmin",
|
|
1745
|
-
{
|
|
1746
|
-
name: "admin::hasPermissions",
|
|
1747
|
-
config: {
|
|
1748
|
-
actions: ["plugin::upload.read"]
|
|
1749
|
-
}
|
|
1750
|
-
}
|
|
1751
|
-
]
|
|
1752
|
-
}
|
|
1753
|
-
},
|
|
1754
|
-
{
|
|
1755
|
-
method: "GET",
|
|
1756
|
-
path: "/files/:id",
|
|
1757
|
-
handler: "admin-file.findOne",
|
|
1758
|
-
config: {
|
|
1759
|
-
policies: [
|
|
1760
|
-
"admin::isAuthenticatedAdmin",
|
|
1761
|
-
{
|
|
1762
|
-
name: "admin::hasPermissions",
|
|
1763
|
-
config: {
|
|
1764
|
-
actions: ["plugin::upload.read"]
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
]
|
|
1768
|
-
}
|
|
1769
|
-
},
|
|
1770
|
-
{
|
|
1771
|
-
method: "DELETE",
|
|
1772
|
-
path: "/files/:id",
|
|
1773
|
-
handler: "admin-file.destroy",
|
|
1774
|
-
config: {
|
|
1775
|
-
policies: [
|
|
1776
|
-
"admin::isAuthenticatedAdmin",
|
|
1777
|
-
{
|
|
1778
|
-
name: "admin::hasPermissions",
|
|
1779
|
-
config: {
|
|
1780
|
-
actions: ["plugin::upload.assets.update"]
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
]
|
|
1784
|
-
}
|
|
1785
|
-
},
|
|
1786
|
-
{
|
|
1787
|
-
method: "GET",
|
|
1788
|
-
path: "/folders/:id",
|
|
1789
|
-
handler: "admin-folder.findOne",
|
|
1790
|
-
config: {
|
|
1791
|
-
policies: [
|
|
1792
|
-
"admin::isAuthenticatedAdmin",
|
|
1793
|
-
{
|
|
1794
|
-
name: "admin::hasPermissions",
|
|
1795
|
-
config: {
|
|
1796
|
-
actions: ["plugin::upload.read"]
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
]
|
|
1800
|
-
}
|
|
1801
|
-
},
|
|
1802
|
-
{
|
|
1803
|
-
method: "GET",
|
|
1804
|
-
path: "/folders",
|
|
1805
|
-
handler: "admin-folder.find",
|
|
1806
|
-
config: {
|
|
1807
|
-
policies: [
|
|
1808
|
-
"admin::isAuthenticatedAdmin",
|
|
1809
|
-
{
|
|
1810
|
-
name: "admin::hasPermissions",
|
|
1811
|
-
config: {
|
|
1812
|
-
actions: ["plugin::upload.read"]
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
]
|
|
1816
|
-
}
|
|
1817
|
-
},
|
|
1818
|
-
{
|
|
1819
|
-
method: "POST",
|
|
1820
|
-
path: "/folders",
|
|
1821
|
-
handler: "admin-folder.create",
|
|
1822
|
-
config: {
|
|
1823
|
-
policies: [
|
|
1824
|
-
"admin::isAuthenticatedAdmin",
|
|
1825
|
-
{
|
|
1826
|
-
name: "admin::hasPermissions",
|
|
1827
|
-
config: {
|
|
1828
|
-
actions: ["plugin::upload.assets.create"]
|
|
1829
|
-
}
|
|
1830
|
-
}
|
|
1831
|
-
]
|
|
1832
|
-
}
|
|
1833
|
-
},
|
|
1834
|
-
{
|
|
1835
|
-
method: "PUT",
|
|
1836
|
-
path: "/folders/:id",
|
|
1837
|
-
handler: "admin-folder.update",
|
|
1838
|
-
config: {
|
|
1839
|
-
policies: [
|
|
1840
|
-
"admin::isAuthenticatedAdmin",
|
|
1841
|
-
{
|
|
1842
|
-
name: "admin::hasPermissions",
|
|
1843
|
-
config: {
|
|
1844
|
-
actions: ["plugin::upload.assets.update"]
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
]
|
|
1848
|
-
}
|
|
1849
|
-
},
|
|
1850
|
-
{
|
|
1851
|
-
method: "GET",
|
|
1852
|
-
path: "/folder-structure",
|
|
1853
|
-
handler: "admin-folder.getStructure",
|
|
1854
|
-
config: {
|
|
1855
|
-
policies: [
|
|
1856
|
-
"admin::isAuthenticatedAdmin",
|
|
1857
|
-
{
|
|
1858
|
-
name: "admin::hasPermissions",
|
|
1859
|
-
config: {
|
|
1860
|
-
actions: ["plugin::upload.read"]
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
]
|
|
1864
|
-
}
|
|
1865
|
-
},
|
|
1866
|
-
{
|
|
1867
|
-
method: "POST",
|
|
1868
|
-
path: "/actions/bulk-delete",
|
|
1869
|
-
handler: "admin-folder-file.deleteMany",
|
|
1870
|
-
config: {
|
|
1871
|
-
policies: [
|
|
1872
|
-
"admin::isAuthenticatedAdmin",
|
|
1873
|
-
{
|
|
1874
|
-
name: "admin::hasPermissions",
|
|
1875
|
-
config: {
|
|
1876
|
-
actions: ["plugin::upload.assets.update"]
|
|
1877
|
-
}
|
|
1878
|
-
}
|
|
1879
|
-
]
|
|
1880
|
-
}
|
|
1881
|
-
},
|
|
1882
|
-
{
|
|
1883
|
-
method: "POST",
|
|
1884
|
-
path: "/actions/bulk-move",
|
|
1885
|
-
handler: "admin-folder-file.moveMany",
|
|
1886
|
-
config: {
|
|
1887
|
-
policies: [
|
|
1888
|
-
"admin::isAuthenticatedAdmin",
|
|
1889
|
-
{
|
|
1890
|
-
name: "admin::hasPermissions",
|
|
1891
|
-
config: {
|
|
1892
|
-
actions: ["plugin::upload.assets.update"]
|
|
1893
|
-
}
|
|
1894
|
-
}
|
|
1895
|
-
]
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
]
|
|
1899
|
-
};
|
|
1900
|
-
const routes$2 = {
|
|
1901
|
-
type: "content-api",
|
|
1902
|
-
routes: [
|
|
1903
|
-
{
|
|
1904
|
-
method: "POST",
|
|
1905
|
-
path: "/",
|
|
1906
|
-
handler: "content-api.upload"
|
|
1907
|
-
},
|
|
1908
|
-
{
|
|
1909
|
-
method: "GET",
|
|
1910
|
-
path: "/files",
|
|
1911
|
-
handler: "content-api.find"
|
|
1912
|
-
},
|
|
1913
|
-
{
|
|
1914
|
-
method: "GET",
|
|
1915
|
-
path: "/files/:id",
|
|
1916
|
-
handler: "content-api.findOne"
|
|
1917
|
-
},
|
|
1918
|
-
{
|
|
1919
|
-
method: "DELETE",
|
|
1920
|
-
path: "/files/:id",
|
|
1921
|
-
handler: "content-api.destroy"
|
|
1922
|
-
}
|
|
1923
|
-
]
|
|
1924
|
-
};
|
|
1925
|
-
const routes$1 = {
|
|
1926
|
-
type: "admin",
|
|
1927
|
-
routes: [
|
|
1928
|
-
{
|
|
1929
|
-
method: "GET",
|
|
1930
|
-
path: "/configuration",
|
|
1931
|
-
handler: "view-configuration.findViewConfiguration",
|
|
1932
|
-
config: {
|
|
1933
|
-
policies: ["admin::isAuthenticatedAdmin"]
|
|
1934
|
-
}
|
|
1935
|
-
},
|
|
1936
|
-
{
|
|
1937
|
-
method: "PUT",
|
|
1938
|
-
path: "/configuration",
|
|
1939
|
-
handler: "view-configuration.updateViewConfiguration",
|
|
1940
|
-
config: {
|
|
1941
|
-
policies: [
|
|
1942
|
-
"admin::isAuthenticatedAdmin",
|
|
1943
|
-
{
|
|
1944
|
-
name: "admin::hasPermissions",
|
|
1945
|
-
config: {
|
|
1946
|
-
actions: [ACTIONS.configureView]
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
]
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
]
|
|
1953
|
-
};
|
|
1954
|
-
const routes = {
|
|
1955
|
-
admin: routes$3,
|
|
1956
|
-
"content-api": routes$2,
|
|
1957
|
-
viewConfiguration: routes$1
|
|
1958
|
-
};
|
|
1959
|
-
const config = {
|
|
1960
|
-
default: {
|
|
1961
|
-
enabled: true,
|
|
1962
|
-
provider: "local",
|
|
1963
|
-
sizeLimit: 1e9,
|
|
1964
|
-
// 1GB
|
|
1965
|
-
actionOptions: {}
|
|
1966
|
-
},
|
|
1967
|
-
validator() {
|
|
1968
|
-
}
|
|
1969
|
-
};
|
|
1970
|
-
const findEntityAndCheckPermissions = async (ability, action, model, id) => {
|
|
1971
|
-
const file2 = await getService("upload").findOne(id, [
|
|
1972
|
-
utils.contentTypes.constants.CREATED_BY_ATTRIBUTE,
|
|
1973
|
-
"folder"
|
|
1974
|
-
]);
|
|
1975
|
-
if (___default.default.isNil(file2)) {
|
|
1976
|
-
throw new utils.errors.NotFoundError();
|
|
1977
|
-
}
|
|
1978
|
-
const pm = strapi.service("admin::permission").createPermissionsManager({ ability, action, model });
|
|
1979
|
-
const creatorId = ___default.default.get(file2, [utils.contentTypes.constants.CREATED_BY_ATTRIBUTE, "id"]);
|
|
1980
|
-
const author = creatorId ? await strapi.service("admin::user").findOne(creatorId, ["roles"]) : null;
|
|
1981
|
-
const fileWithRoles = ___default.default.set(___default.default.cloneDeep(file2), "createdBy", author);
|
|
1982
|
-
if (pm.ability.cannot(pm.action, pm.toSubject(fileWithRoles))) {
|
|
1983
|
-
throw new utils.errors.ForbiddenError();
|
|
1984
|
-
}
|
|
1985
|
-
return { pm, file: file2 };
|
|
1986
|
-
};
|
|
1987
|
-
const adminFile = {
|
|
1988
|
-
async find(ctx) {
|
|
1989
|
-
const {
|
|
1990
|
-
state: { userAbility }
|
|
1991
|
-
} = ctx;
|
|
1992
|
-
const defaultQuery = { populate: { folder: true } };
|
|
1993
|
-
const pm = strapi.service("admin::permission").createPermissionsManager({
|
|
1994
|
-
ability: userAbility,
|
|
1995
|
-
action: ACTIONS.read,
|
|
1996
|
-
model: FILE_MODEL_UID
|
|
1997
|
-
});
|
|
1998
|
-
if (!pm.isAllowed) {
|
|
1999
|
-
return ctx.forbidden();
|
|
2000
|
-
}
|
|
2001
|
-
await pm.validateQuery(ctx.query);
|
|
2002
|
-
const query = await utils.async.pipe(
|
|
2003
|
-
// Start by sanitizing the incoming query
|
|
2004
|
-
(q) => pm.sanitizeQuery(q),
|
|
2005
|
-
// Add the default query which should not be validated or sanitized
|
|
2006
|
-
(q) => fp.merge(defaultQuery, q),
|
|
2007
|
-
// Add the dynamic filters based on permissions' conditions
|
|
2008
|
-
(q) => pm.addPermissionsQueryTo(q)
|
|
2009
|
-
)(ctx.query);
|
|
2010
|
-
const { results: files, pagination } = await getService("upload").findPage(query);
|
|
2011
|
-
const signedFiles = await utils.async.map(files, getService("file").signFileUrls);
|
|
2012
|
-
const sanitizedFiles = await pm.sanitizeOutput(signedFiles);
|
|
2013
|
-
return { results: sanitizedFiles, pagination };
|
|
2014
|
-
},
|
|
2015
|
-
async findOne(ctx) {
|
|
2016
|
-
const {
|
|
2017
|
-
state: { userAbility },
|
|
2018
|
-
params: { id }
|
|
2019
|
-
} = ctx;
|
|
2020
|
-
const { pm, file: file2 } = await findEntityAndCheckPermissions(
|
|
2021
|
-
userAbility,
|
|
2022
|
-
ACTIONS.read,
|
|
2023
|
-
FILE_MODEL_UID,
|
|
2024
|
-
id
|
|
2025
|
-
);
|
|
2026
|
-
const signedFile = await getService("file").signFileUrls(file2);
|
|
2027
|
-
ctx.body = await pm.sanitizeOutput(signedFile);
|
|
2028
|
-
},
|
|
2029
|
-
async destroy(ctx) {
|
|
2030
|
-
const { id } = ctx.params;
|
|
2031
|
-
const { userAbility } = ctx.state;
|
|
2032
|
-
const { pm, file: file2 } = await findEntityAndCheckPermissions(
|
|
2033
|
-
userAbility,
|
|
2034
|
-
ACTIONS.update,
|
|
2035
|
-
FILE_MODEL_UID,
|
|
2036
|
-
id
|
|
2037
|
-
);
|
|
2038
|
-
const [body] = await Promise.all([
|
|
2039
|
-
pm.sanitizeOutput(file2, { action: ACTIONS.read }),
|
|
2040
|
-
getService("upload").remove(file2)
|
|
2041
|
-
]);
|
|
2042
|
-
ctx.body = body;
|
|
2043
|
-
}
|
|
2044
|
-
};
|
|
2045
|
-
const folderExists = async (folderId) => {
|
|
2046
|
-
if (fp.isNil(folderId)) {
|
|
2047
|
-
return true;
|
|
2048
|
-
}
|
|
2049
|
-
const exists2 = await getService("folder").exists({ id: folderId });
|
|
2050
|
-
return exists2;
|
|
2051
|
-
};
|
|
2052
|
-
const isFolderOrChild = (folderOrChild, folder2) => folderOrChild.path === folder2.path || folderOrChild.path.startsWith(`${folder2.path}/`);
|
|
2053
|
-
const NO_SLASH_REGEX = /^[^/]+$/;
|
|
2054
|
-
const NO_SPACES_AROUND = /^(?! ).+(?<! )$/;
|
|
2055
|
-
const isNameUniqueInFolder = (id) => {
|
|
2056
|
-
return async function test(name) {
|
|
2057
|
-
const { exists: exists2 } = getService("folder");
|
|
2058
|
-
const filters = { name, parent: this.parent.parent || null };
|
|
2059
|
-
if (id) {
|
|
2060
|
-
filters.id = { $ne: id };
|
|
2061
|
-
if (fp.isUndefined(name)) {
|
|
2062
|
-
const existingFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id } });
|
|
2063
|
-
filters.name = fp.get("name", existingFolder);
|
|
2064
|
-
}
|
|
2065
|
-
}
|
|
2066
|
-
const doesExist = await exists2(filters);
|
|
2067
|
-
return !doesExist;
|
|
2068
|
-
};
|
|
2069
|
-
};
|
|
2070
|
-
const validateCreateFolderSchema = utils.yup.object().shape({
|
|
2071
|
-
name: utils.yup.string().min(1).matches(NO_SLASH_REGEX, "name cannot contain slashes").matches(NO_SPACES_AROUND, "name cannot start or end with a whitespace").required().test("is-folder-unique", "A folder with this name already exists", isNameUniqueInFolder()),
|
|
2072
|
-
parent: utils.yup.strapiID().nullable().test("folder-exists", "parent folder does not exist", folderExists)
|
|
2073
|
-
}).noUnknown().required();
|
|
2074
|
-
const validateUpdateFolderSchema = (id) => utils.yup.object().shape({
|
|
2075
|
-
name: utils.yup.string().min(1).matches(NO_SLASH_REGEX, "name cannot contain slashes").matches(NO_SPACES_AROUND, "name cannot start or end with a whitespace").test(
|
|
2076
|
-
"is-folder-unique",
|
|
2077
|
-
"A folder with this name already exists",
|
|
2078
|
-
isNameUniqueInFolder(id)
|
|
2079
|
-
),
|
|
2080
|
-
parent: utils.yup.strapiID().nullable().test("folder-exists", "parent folder does not exist", folderExists).test(
|
|
2081
|
-
"dont-move-inside-self",
|
|
2082
|
-
"folder cannot be moved inside itself",
|
|
2083
|
-
async function test(parent) {
|
|
2084
|
-
if (fp.isNil(parent)) return true;
|
|
2085
|
-
const destinationFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({
|
|
2086
|
-
select: ["path"],
|
|
2087
|
-
where: { id: parent }
|
|
2088
|
-
});
|
|
2089
|
-
const currentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({
|
|
2090
|
-
select: ["path"],
|
|
2091
|
-
where: { id }
|
|
2092
|
-
});
|
|
2093
|
-
if (!destinationFolder || !currentFolder) return true;
|
|
2094
|
-
return !isFolderOrChild(destinationFolder, currentFolder);
|
|
2095
|
-
}
|
|
2096
|
-
)
|
|
2097
|
-
}).noUnknown().required();
|
|
2098
|
-
const validateCreateFolder = utils.validateYupSchema(validateCreateFolderSchema);
|
|
2099
|
-
const validateUpdateFolder = (id) => utils.validateYupSchema(validateUpdateFolderSchema(id));
|
|
2100
|
-
const adminFolder = {
|
|
2101
|
-
async findOne(ctx) {
|
|
2102
|
-
const { id } = ctx.params;
|
|
2103
|
-
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
2104
|
-
ability: ctx.state.userAbility,
|
|
2105
|
-
model: FOLDER_MODEL_UID
|
|
2106
|
-
});
|
|
2107
|
-
await permissionsManager.validateQuery(ctx.query);
|
|
2108
|
-
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
2109
|
-
const { results } = await strapi.db.query(FOLDER_MODEL_UID).findPage(
|
|
2110
|
-
strapi.get("query-params").transform(
|
|
2111
|
-
FOLDER_MODEL_UID,
|
|
2112
|
-
fp.defaultsDeep(
|
|
2113
|
-
{
|
|
2114
|
-
filters: { id },
|
|
2115
|
-
populate: {
|
|
2116
|
-
children: {
|
|
2117
|
-
count: true
|
|
2118
|
-
},
|
|
2119
|
-
files: {
|
|
2120
|
-
count: true
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
},
|
|
2124
|
-
query
|
|
2125
|
-
)
|
|
2126
|
-
)
|
|
2127
|
-
);
|
|
2128
|
-
if (results.length === 0) {
|
|
2129
|
-
return ctx.notFound("folder not found");
|
|
2130
|
-
}
|
|
2131
|
-
ctx.body = {
|
|
2132
|
-
data: await permissionsManager.sanitizeOutput(results[0])
|
|
2133
|
-
};
|
|
2134
|
-
},
|
|
2135
|
-
async find(ctx) {
|
|
2136
|
-
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
2137
|
-
ability: ctx.state.userAbility,
|
|
2138
|
-
model: FOLDER_MODEL_UID
|
|
2139
|
-
});
|
|
2140
|
-
await permissionsManager.validateQuery(ctx.query);
|
|
2141
|
-
const query = await permissionsManager.sanitizeQuery(ctx.query);
|
|
2142
|
-
const results = await strapi.db.query(FOLDER_MODEL_UID).findMany(
|
|
2143
|
-
strapi.get("query-params").transform(
|
|
2144
|
-
FOLDER_MODEL_UID,
|
|
2145
|
-
fp.defaultsDeep(
|
|
2146
|
-
{
|
|
2147
|
-
populate: {
|
|
2148
|
-
children: {
|
|
2149
|
-
count: true
|
|
2150
|
-
},
|
|
2151
|
-
files: {
|
|
2152
|
-
count: true
|
|
2153
|
-
}
|
|
2154
|
-
}
|
|
2155
|
-
},
|
|
2156
|
-
query
|
|
2157
|
-
)
|
|
2158
|
-
)
|
|
2159
|
-
);
|
|
2160
|
-
ctx.body = {
|
|
2161
|
-
data: await permissionsManager.sanitizeOutput(results)
|
|
2162
|
-
};
|
|
2163
|
-
},
|
|
2164
|
-
async create(ctx) {
|
|
2165
|
-
const { user } = ctx.state;
|
|
2166
|
-
const { body } = ctx.request;
|
|
2167
|
-
await validateCreateFolder(body);
|
|
2168
|
-
const folderService = getService("folder");
|
|
2169
|
-
const folder2 = await folderService.create(body, { user });
|
|
2170
|
-
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
2171
|
-
ability: ctx.state.userAbility,
|
|
2172
|
-
model: FOLDER_MODEL_UID
|
|
2173
|
-
});
|
|
2174
|
-
ctx.created({
|
|
2175
|
-
data: await permissionsManager.sanitizeOutput(folder2)
|
|
2176
|
-
});
|
|
2177
|
-
},
|
|
2178
|
-
async update(ctx) {
|
|
2179
|
-
const { id } = ctx.params;
|
|
2180
|
-
const { user } = ctx.state;
|
|
2181
|
-
const { body } = ctx.request;
|
|
2182
|
-
const permissionsManager = strapi.service("admin::permission").createPermissionsManager({
|
|
2183
|
-
ability: ctx.state.userAbility,
|
|
2184
|
-
model: FOLDER_MODEL_UID
|
|
2185
|
-
});
|
|
2186
|
-
await validateUpdateFolder(id)(body);
|
|
2187
|
-
const folderService = getService("folder");
|
|
2188
|
-
const updatedFolder = await folderService.update(id, body, { user });
|
|
2189
|
-
if (!updatedFolder) {
|
|
2190
|
-
return ctx.notFound("folder not found");
|
|
2191
|
-
}
|
|
2192
|
-
ctx.body = {
|
|
2193
|
-
data: await permissionsManager.sanitizeOutput(updatedFolder)
|
|
2194
|
-
};
|
|
2195
|
-
},
|
|
2196
|
-
async getStructure(ctx) {
|
|
2197
|
-
const { getStructure: getStructure2 } = getService("folder");
|
|
2198
|
-
const structure = await getStructure2();
|
|
2199
|
-
ctx.body = {
|
|
2200
|
-
data: structure
|
|
2201
|
-
};
|
|
2202
|
-
}
|
|
2203
|
-
};
|
|
2204
|
-
const validateDeleteManyFoldersFilesSchema = utils.yup.object().shape({
|
|
2205
|
-
fileIds: utils.yup.array().of(utils.yup.strapiID().required()),
|
|
2206
|
-
folderIds: utils.yup.array().of(utils.yup.strapiID().required())
|
|
2207
|
-
}).noUnknown().required();
|
|
2208
|
-
const validateStructureMoveManyFoldersFilesSchema = utils.yup.object().shape({
|
|
2209
|
-
destinationFolderId: utils.yup.strapiID().nullable().defined().test("folder-exists", "destination folder does not exist", folderExists),
|
|
2210
|
-
fileIds: utils.yup.array().of(utils.yup.strapiID().required()),
|
|
2211
|
-
folderIds: utils.yup.array().of(utils.yup.strapiID().required())
|
|
2212
|
-
}).noUnknown().required();
|
|
2213
|
-
const validateDuplicatesMoveManyFoldersFilesSchema = utils.yup.object().test("are-folders-unique", "some folders already exist", async function areFoldersUnique(value) {
|
|
2214
|
-
const { folderIds, destinationFolderId } = value;
|
|
2215
|
-
if (fp.isEmpty(folderIds)) return true;
|
|
2216
|
-
const folders = await strapi.db.query(FOLDER_MODEL_UID).findMany({
|
|
2217
|
-
select: ["name"],
|
|
2218
|
-
where: { id: { $in: folderIds } }
|
|
2219
|
-
});
|
|
2220
|
-
const existingFolders = await strapi.db.query(FOLDER_MODEL_UID).findMany({
|
|
2221
|
-
select: ["name"],
|
|
2222
|
-
where: { parent: { id: destinationFolderId } }
|
|
2223
|
-
});
|
|
2224
|
-
const duplicatedNames = fp.intersection(fp.map("name", folders), fp.map("name", existingFolders));
|
|
2225
|
-
if (duplicatedNames.length > 0) {
|
|
2226
|
-
return this.createError({
|
|
2227
|
-
message: `some folders already exists: ${duplicatedNames.join(", ")}`
|
|
2228
|
-
});
|
|
2229
|
-
}
|
|
2230
|
-
return true;
|
|
2231
|
-
});
|
|
2232
|
-
const validateMoveFoldersNotInsideThemselvesSchema = utils.yup.object().test(
|
|
2233
|
-
"dont-move-inside-self",
|
|
2234
|
-
"folders cannot be moved inside themselves or one of its children",
|
|
2235
|
-
async function validateMoveFoldersNotInsideThemselves(value) {
|
|
2236
|
-
const { folderIds, destinationFolderId } = value;
|
|
2237
|
-
if (destinationFolderId === null || fp.isEmpty(folderIds)) return true;
|
|
2238
|
-
const destinationFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({
|
|
2239
|
-
select: ["path"],
|
|
2240
|
-
where: { id: destinationFolderId }
|
|
2241
|
-
});
|
|
2242
|
-
const folders = await strapi.db.query(FOLDER_MODEL_UID).findMany({
|
|
2243
|
-
select: ["name", "path"],
|
|
2244
|
-
where: { id: { $in: folderIds } }
|
|
2245
|
-
});
|
|
2246
|
-
const unmovableFoldersNames = folders.filter((folder2) => isFolderOrChild(destinationFolder, folder2)).map((f) => f.name);
|
|
2247
|
-
if (unmovableFoldersNames.length > 0) {
|
|
2248
|
-
return this.createError({
|
|
2249
|
-
message: `folders cannot be moved inside themselves or one of its children: ${unmovableFoldersNames.join(
|
|
2250
|
-
", "
|
|
2251
|
-
)}`
|
|
2252
|
-
});
|
|
2253
|
-
}
|
|
2254
|
-
return true;
|
|
2255
|
-
}
|
|
2256
|
-
);
|
|
2257
|
-
const validateDeleteManyFoldersFiles = utils.validateYupSchema(
|
|
2258
|
-
validateDeleteManyFoldersFilesSchema
|
|
2259
|
-
);
|
|
2260
|
-
async function validateMoveManyFoldersFiles(body) {
|
|
2261
|
-
await utils.validateYupSchema(validateStructureMoveManyFoldersFilesSchema)(body);
|
|
2262
|
-
await utils.validateYupSchema(validateDuplicatesMoveManyFoldersFilesSchema)(body);
|
|
2263
|
-
await utils.validateYupSchema(validateMoveFoldersNotInsideThemselvesSchema)(body);
|
|
2264
|
-
}
|
|
2265
|
-
const adminFolderFile = {
|
|
2266
|
-
async deleteMany(ctx) {
|
|
2267
|
-
const { body } = ctx.request;
|
|
2268
|
-
const {
|
|
2269
|
-
state: { userAbility }
|
|
2270
|
-
} = ctx;
|
|
2271
|
-
const pmFolder = strapi.service("admin::permission").createPermissionsManager({
|
|
2272
|
-
ability: ctx.state.userAbility,
|
|
2273
|
-
model: FOLDER_MODEL_UID
|
|
2274
|
-
});
|
|
2275
|
-
const pmFile = strapi.service("admin::permission").createPermissionsManager({
|
|
2276
|
-
ability: userAbility,
|
|
2277
|
-
action: ACTIONS.read,
|
|
2278
|
-
model: FILE_MODEL_UID
|
|
2279
|
-
});
|
|
2280
|
-
await validateDeleteManyFoldersFiles(body);
|
|
2281
|
-
const fileService = getService("file");
|
|
2282
|
-
const folderService = getService("folder");
|
|
2283
|
-
const deletedFiles = await fileService.deleteByIds(body.fileIds);
|
|
2284
|
-
const {
|
|
2285
|
-
folders: deletedFolders,
|
|
2286
|
-
totalFolderNumber,
|
|
2287
|
-
totalFileNumber
|
|
2288
|
-
} = await folderService.deleteByIds(body.folderIds);
|
|
2289
|
-
if (deletedFiles.length + deletedFolders.length > 1) {
|
|
2290
|
-
strapi.telemetry.send("didBulkDeleteMediaLibraryElements", {
|
|
2291
|
-
eventProperties: {
|
|
2292
|
-
rootFolderNumber: deletedFolders.length,
|
|
2293
|
-
rootAssetNumber: deletedFiles.length,
|
|
2294
|
-
totalFolderNumber,
|
|
2295
|
-
totalAssetNumber: totalFileNumber + deletedFiles.length
|
|
2296
|
-
}
|
|
2297
|
-
});
|
|
2298
|
-
}
|
|
2299
|
-
ctx.body = {
|
|
2300
|
-
data: {
|
|
2301
|
-
files: await pmFile.sanitizeOutput(deletedFiles),
|
|
2302
|
-
folders: await pmFolder.sanitizeOutput(deletedFolders)
|
|
2303
|
-
}
|
|
2304
|
-
};
|
|
2305
|
-
},
|
|
2306
|
-
async moveMany(ctx) {
|
|
2307
|
-
const { body } = ctx.request;
|
|
2308
|
-
const {
|
|
2309
|
-
state: { userAbility }
|
|
2310
|
-
} = ctx;
|
|
2311
|
-
const pmFolder = strapi.service("admin::permission").createPermissionsManager({
|
|
2312
|
-
ability: ctx.state.userAbility,
|
|
2313
|
-
model: FOLDER_MODEL_UID
|
|
2314
|
-
});
|
|
2315
|
-
const pmFile = strapi.service("admin::permission").createPermissionsManager({
|
|
2316
|
-
ability: userAbility,
|
|
2317
|
-
action: ACTIONS.read,
|
|
2318
|
-
model: FILE_MODEL_UID
|
|
2319
|
-
});
|
|
2320
|
-
await validateMoveManyFoldersFiles(body);
|
|
2321
|
-
const { folderIds = [], fileIds = [], destinationFolderId } = body;
|
|
2322
|
-
let totalFolderNumber = 0;
|
|
2323
|
-
let totalFileNumber = 0;
|
|
2324
|
-
const trx = await strapi.db.transaction();
|
|
2325
|
-
try {
|
|
2326
|
-
const existingFolders = await strapi.db.queryBuilder(FOLDER_MODEL_UID).select(["id", "pathId", "path"]).where({ id: { $in: folderIds } }).transacting(trx.get()).forUpdate().execute();
|
|
2327
|
-
const existingFiles = await strapi.db.queryBuilder(FILE_MODEL_UID).select(["id"]).where({ id: { $in: fileIds } }).transacting(trx.get()).forUpdate().execute();
|
|
2328
|
-
let destinationFolderPath = "/";
|
|
2329
|
-
if (destinationFolderId !== null) {
|
|
2330
|
-
const destinationFolder = await strapi.db.queryBuilder(FOLDER_MODEL_UID).select("path").where({ id: destinationFolderId }).transacting(trx.get()).first().execute();
|
|
2331
|
-
destinationFolderPath = destinationFolder.path;
|
|
2332
|
-
}
|
|
2333
|
-
const fileTable = strapi.getModel(FILE_MODEL_UID).collectionName;
|
|
2334
|
-
const folderTable = strapi.getModel(FOLDER_MODEL_UID).collectionName;
|
|
2335
|
-
const folderPathColName = (
|
|
2336
|
-
// @ts-expect-error - no dynamic typings for the models
|
|
2337
|
-
strapi.db.metadata.get(FILE_MODEL_UID).attributes.folderPath.columnName
|
|
2338
|
-
);
|
|
2339
|
-
const pathColName = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.path.columnName;
|
|
2340
|
-
if (existingFolders.length > 0) {
|
|
2341
|
-
const { joinTable } = strapi.db.metadata.get(FOLDER_MODEL_UID).attributes.parent;
|
|
2342
|
-
await strapi.db.queryBuilder(joinTable.name).transacting(trx.get()).delete().where({ [joinTable.joinColumn.name]: { $in: folderIds } }).execute();
|
|
2343
|
-
if (destinationFolderId !== null) {
|
|
2344
|
-
await strapi.db.queryBuilder(joinTable.name).transacting(trx.get()).insert(
|
|
2345
|
-
existingFolders.map((folder2) => ({
|
|
2346
|
-
[joinTable.inverseJoinColumn.name]: destinationFolderId,
|
|
2347
|
-
[joinTable.joinColumn.name]: folder2.id
|
|
2348
|
-
}))
|
|
2349
|
-
).execute();
|
|
2350
|
-
}
|
|
2351
|
-
for (const existingFolder of existingFolders) {
|
|
2352
|
-
let replaceQuery;
|
|
2353
|
-
switch (strapi.db.dialect.client) {
|
|
2354
|
-
case "sqlite":
|
|
2355
|
-
replaceQuery = "? || SUBSTRING(??, ?)";
|
|
2356
|
-
break;
|
|
2357
|
-
case "postgres":
|
|
2358
|
-
replaceQuery = "CONCAT(?::TEXT, SUBSTRING(??, ?::INTEGER))";
|
|
2359
|
-
break;
|
|
2360
|
-
default:
|
|
2361
|
-
replaceQuery = "CONCAT(?, SUBSTRING(??, ?))";
|
|
2362
|
-
}
|
|
2363
|
-
totalFolderNumber = await strapi.db.getConnection(folderTable).transacting(trx.get()).where(pathColName, existingFolder.path).orWhere(pathColName, "like", `${existingFolder.path}/%`).update(
|
|
2364
|
-
pathColName,
|
|
2365
|
-
strapi.db.connection.raw(replaceQuery, [
|
|
2366
|
-
utils.strings.joinBy("/", destinationFolderPath, `${existingFolder.pathId}`),
|
|
2367
|
-
pathColName,
|
|
2368
|
-
existingFolder.path.length + 1
|
|
2369
|
-
])
|
|
2370
|
-
);
|
|
2371
|
-
totalFileNumber = await strapi.db.getConnection(fileTable).transacting(trx.get()).where(folderPathColName, existingFolder.path).orWhere(folderPathColName, "like", `${existingFolder.path}/%`).update(
|
|
2372
|
-
folderPathColName,
|
|
2373
|
-
strapi.db.connection.raw(replaceQuery, [
|
|
2374
|
-
utils.strings.joinBy("/", destinationFolderPath, `${existingFolder.pathId}`),
|
|
2375
|
-
folderPathColName,
|
|
2376
|
-
existingFolder.path.length + 1
|
|
2377
|
-
])
|
|
2378
|
-
);
|
|
2379
|
-
}
|
|
2380
|
-
}
|
|
2381
|
-
if (existingFiles.length > 0) {
|
|
2382
|
-
const fileJoinTable = strapi.db.metadata.get(FILE_MODEL_UID).attributes.folder.joinTable;
|
|
2383
|
-
await strapi.db.queryBuilder(fileJoinTable.name).transacting(trx.get()).delete().where({ [fileJoinTable.joinColumn.name]: { $in: fileIds } }).execute();
|
|
2384
|
-
if (destinationFolderId !== null) {
|
|
2385
|
-
await strapi.db.queryBuilder(fileJoinTable.name).transacting(trx.get()).insert(
|
|
2386
|
-
existingFiles.map((file2) => ({
|
|
2387
|
-
[fileJoinTable.inverseJoinColumn.name]: destinationFolderId,
|
|
2388
|
-
[fileJoinTable.joinColumn.name]: file2.id
|
|
2389
|
-
}))
|
|
2390
|
-
).execute();
|
|
2391
|
-
}
|
|
2392
|
-
await strapi.db.getConnection(fileTable).transacting(trx.get()).whereIn("id", fileIds).update(folderPathColName, destinationFolderPath);
|
|
2393
|
-
}
|
|
2394
|
-
await trx.commit();
|
|
2395
|
-
} catch (e) {
|
|
2396
|
-
await trx.rollback();
|
|
2397
|
-
throw e;
|
|
2398
|
-
}
|
|
2399
|
-
const updatedFolders = await strapi.db.query(FOLDER_MODEL_UID).findMany({
|
|
2400
|
-
where: { id: { $in: folderIds } }
|
|
2401
|
-
});
|
|
2402
|
-
const updatedFiles = await strapi.db.query(FILE_MODEL_UID).findMany({
|
|
2403
|
-
where: { id: { $in: fileIds } }
|
|
2404
|
-
});
|
|
2405
|
-
strapi.telemetry.send("didBulkMoveMediaLibraryElements", {
|
|
2406
|
-
eventProperties: {
|
|
2407
|
-
rootFolderNumber: updatedFolders.length,
|
|
2408
|
-
rootAssetNumber: updatedFiles.length,
|
|
2409
|
-
totalFolderNumber,
|
|
2410
|
-
totalAssetNumber: totalFileNumber + updatedFiles.length
|
|
2411
|
-
}
|
|
2412
|
-
});
|
|
2413
|
-
ctx.body = {
|
|
2414
|
-
data: {
|
|
2415
|
-
files: await pmFile.sanitizeOutput(updatedFiles),
|
|
2416
|
-
folders: await pmFolder.sanitizeOutput(updatedFolders)
|
|
2417
|
-
}
|
|
2418
|
-
};
|
|
2419
|
-
}
|
|
2420
|
-
};
|
|
2421
|
-
const settingsSchema = utils.yup.object({
|
|
2422
|
-
sizeOptimization: utils.yup.boolean().required(),
|
|
2423
|
-
responsiveDimensions: utils.yup.boolean().required(),
|
|
2424
|
-
autoOrientation: utils.yup.boolean()
|
|
2425
|
-
});
|
|
2426
|
-
const validateSettings = utils.validateYupSchema(settingsSchema);
|
|
2427
|
-
const adminSettings = {
|
|
2428
|
-
async updateSettings(ctx) {
|
|
2429
|
-
const {
|
|
2430
|
-
request: { body },
|
|
2431
|
-
state: { userAbility }
|
|
2432
|
-
} = ctx;
|
|
2433
|
-
if (userAbility.cannot(ACTIONS.readSettings, FILE_MODEL_UID)) {
|
|
2434
|
-
return ctx.forbidden();
|
|
2435
|
-
}
|
|
2436
|
-
const data = await validateSettings(body);
|
|
2437
|
-
await getService("upload").setSettings(data);
|
|
2438
|
-
ctx.body = { data };
|
|
2439
|
-
},
|
|
2440
|
-
async getSettings(ctx) {
|
|
2441
|
-
const {
|
|
2442
|
-
state: { userAbility }
|
|
2443
|
-
} = ctx;
|
|
2444
|
-
if (userAbility.cannot(ACTIONS.readSettings, FILE_MODEL_UID)) {
|
|
2445
|
-
return ctx.forbidden();
|
|
2446
|
-
}
|
|
2447
|
-
const data = await getService("upload").getSettings();
|
|
2448
|
-
ctx.body = { data };
|
|
2449
|
-
}
|
|
2450
|
-
};
|
|
2451
|
-
const fileInfoSchema$1 = utils.yup.object({
|
|
2452
|
-
name: utils.yup.string().nullable(),
|
|
2453
|
-
alternativeText: utils.yup.string().nullable(),
|
|
2454
|
-
caption: utils.yup.string().nullable(),
|
|
2455
|
-
folder: utils.yup.strapiID().nullable().test("folder-exists", "the folder does not exist", async (folderId) => {
|
|
2456
|
-
if (fp.isNil(folderId)) {
|
|
2457
|
-
return true;
|
|
2458
|
-
}
|
|
2459
|
-
const exists2 = await getService("folder").exists({ id: folderId });
|
|
2460
|
-
return exists2;
|
|
2461
|
-
})
|
|
2462
|
-
});
|
|
2463
|
-
const uploadSchema$1 = utils.yup.object({
|
|
2464
|
-
fileInfo: fileInfoSchema$1
|
|
2465
|
-
});
|
|
2466
|
-
const multiUploadSchema$1 = utils.yup.object({
|
|
2467
|
-
fileInfo: utils.yup.array().of(fileInfoSchema$1)
|
|
2468
|
-
});
|
|
2469
|
-
const validateUploadBody$1 = (data = {}, isMulti = false) => {
|
|
2470
|
-
const schema = isMulti ? multiUploadSchema$1 : uploadSchema$1;
|
|
2471
|
-
return utils.validateYupSchema(schema, { strict: false })(data);
|
|
2472
|
-
};
|
|
2473
|
-
const adminUpload = {
|
|
2474
|
-
async updateFileInfo(ctx) {
|
|
2475
|
-
const {
|
|
2476
|
-
state: { userAbility, user },
|
|
2477
|
-
query: { id },
|
|
2478
|
-
request: { body }
|
|
2479
|
-
} = ctx;
|
|
2480
|
-
if (typeof id !== "string") {
|
|
2481
|
-
throw new utils.errors.ValidationError("File id is required");
|
|
2482
|
-
}
|
|
2483
|
-
const uploadService = getService("upload");
|
|
2484
|
-
const { pm } = await findEntityAndCheckPermissions(
|
|
2485
|
-
userAbility,
|
|
2486
|
-
ACTIONS.update,
|
|
2487
|
-
FILE_MODEL_UID,
|
|
2488
|
-
id
|
|
2489
|
-
);
|
|
2490
|
-
const data = await validateUploadBody$1(body);
|
|
2491
|
-
const file2 = await uploadService.updateFileInfo(id, data.fileInfo, { user });
|
|
2492
|
-
ctx.body = await pm.sanitizeOutput(file2, { action: ACTIONS.read });
|
|
2493
|
-
},
|
|
2494
|
-
async replaceFile(ctx) {
|
|
2495
|
-
const {
|
|
2496
|
-
state: { userAbility, user },
|
|
2497
|
-
query: { id },
|
|
2498
|
-
request: { body, files: { files } = {} }
|
|
2499
|
-
} = ctx;
|
|
2500
|
-
if (typeof id !== "string") {
|
|
2501
|
-
throw new utils.errors.ValidationError("File id is required");
|
|
2502
|
-
}
|
|
2503
|
-
const uploadService = getService("upload");
|
|
2504
|
-
const { pm } = await findEntityAndCheckPermissions(
|
|
2505
|
-
userAbility,
|
|
2506
|
-
ACTIONS.update,
|
|
2507
|
-
FILE_MODEL_UID,
|
|
2508
|
-
id
|
|
2509
|
-
);
|
|
2510
|
-
if (Array.isArray(files)) {
|
|
2511
|
-
throw new utils.errors.ApplicationError("Cannot replace a file with multiple ones");
|
|
2512
|
-
}
|
|
2513
|
-
const data = await validateUploadBody$1(body);
|
|
2514
|
-
const replacedFile = await uploadService.replace(id, { data, file: files }, { user });
|
|
2515
|
-
const signedFile = await getService("file").signFileUrls(replacedFile);
|
|
2516
|
-
ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });
|
|
2517
|
-
},
|
|
2518
|
-
async uploadFiles(ctx) {
|
|
2519
|
-
const {
|
|
2520
|
-
state: { userAbility, user },
|
|
2521
|
-
request: { body, files: { files } = {} }
|
|
2522
|
-
} = ctx;
|
|
2523
|
-
const uploadService = getService("upload");
|
|
2524
|
-
const pm = strapi.service("admin::permission").createPermissionsManager({
|
|
2525
|
-
ability: userAbility,
|
|
2526
|
-
action: ACTIONS.create,
|
|
2527
|
-
model: FILE_MODEL_UID
|
|
2528
|
-
});
|
|
2529
|
-
if (!pm.isAllowed) {
|
|
2530
|
-
return ctx.forbidden();
|
|
2531
|
-
}
|
|
2532
|
-
const data = await validateUploadBody$1(body);
|
|
2533
|
-
const uploadedFiles = await uploadService.upload({ data, files }, { user });
|
|
2534
|
-
const signedFiles = await utils.async.map(uploadedFiles, getService("file").signFileUrls);
|
|
2535
|
-
ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });
|
|
2536
|
-
ctx.status = 201;
|
|
2537
|
-
},
|
|
2538
|
-
// TODO: split into multiple endpoints
|
|
2539
|
-
async upload(ctx) {
|
|
2540
|
-
const {
|
|
2541
|
-
query: { id },
|
|
2542
|
-
request: { files: { files } = {} }
|
|
2543
|
-
} = ctx;
|
|
2544
|
-
if (___default.default.isEmpty(files) || !Array.isArray(files) && files.size === 0) {
|
|
2545
|
-
if (id) {
|
|
2546
|
-
return this.updateFileInfo(ctx);
|
|
2547
|
-
}
|
|
2548
|
-
throw new utils.errors.ApplicationError("Files are empty");
|
|
2549
|
-
}
|
|
2550
|
-
await (id ? this.replaceFile : this.uploadFiles)(ctx);
|
|
2551
|
-
}
|
|
2552
|
-
};
|
|
2553
|
-
const fileInfoSchema = utils.yup.object({
|
|
2554
|
-
name: utils.yup.string().nullable(),
|
|
2555
|
-
alternativeText: utils.yup.string().nullable(),
|
|
2556
|
-
caption: utils.yup.string().nullable()
|
|
2557
|
-
}).noUnknown();
|
|
2558
|
-
const uploadSchema = utils.yup.object({
|
|
2559
|
-
fileInfo: fileInfoSchema
|
|
2560
|
-
});
|
|
2561
|
-
const multiUploadSchema = utils.yup.object({
|
|
2562
|
-
fileInfo: utils.yup.array().of(fileInfoSchema)
|
|
2563
|
-
});
|
|
2564
|
-
const validateUploadBody = (data = {}, isMulti = false) => {
|
|
2565
|
-
const schema = isMulti ? multiUploadSchema : uploadSchema;
|
|
2566
|
-
return utils.validateYupSchema(schema, { strict: false })(data);
|
|
2567
|
-
};
|
|
2568
|
-
const { ValidationError } = utils__default.default.errors;
|
|
2569
|
-
const contentApi = ({ strapi: strapi2 }) => {
|
|
2570
|
-
const sanitizeOutput = async (data, ctx) => {
|
|
2571
|
-
const schema = strapi2.getModel(FILE_MODEL_UID);
|
|
2572
|
-
const { auth } = ctx.state;
|
|
2573
|
-
return strapi2.contentAPI.sanitize.output(data, schema, { auth });
|
|
2574
|
-
};
|
|
2575
|
-
const validateQuery = async (data, ctx) => {
|
|
2576
|
-
const schema = strapi2.getModel(FILE_MODEL_UID);
|
|
2577
|
-
const { auth } = ctx.state;
|
|
2578
|
-
return strapi2.contentAPI.validate.query(data, schema, { auth });
|
|
2579
|
-
};
|
|
2580
|
-
const sanitizeQuery = async (data, ctx) => {
|
|
2581
|
-
const schema = strapi2.getModel(FILE_MODEL_UID);
|
|
2582
|
-
const { auth } = ctx.state;
|
|
2583
|
-
return strapi2.contentAPI.sanitize.query(data, schema, { auth });
|
|
2584
|
-
};
|
|
2585
|
-
return {
|
|
2586
|
-
async find(ctx) {
|
|
2587
|
-
await validateQuery(ctx.query, ctx);
|
|
2588
|
-
const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
|
|
2589
|
-
const files = await getService("upload").findMany(sanitizedQuery);
|
|
2590
|
-
ctx.body = await sanitizeOutput(files, ctx);
|
|
2591
|
-
},
|
|
2592
|
-
async findOne(ctx) {
|
|
2593
|
-
const {
|
|
2594
|
-
params: { id }
|
|
2595
|
-
} = ctx;
|
|
2596
|
-
await validateQuery(ctx.query, ctx);
|
|
2597
|
-
const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
|
|
2598
|
-
const file2 = await getService("upload").findOne(id, sanitizedQuery.populate);
|
|
2599
|
-
if (!file2) {
|
|
2600
|
-
return ctx.notFound("file.notFound");
|
|
2601
|
-
}
|
|
2602
|
-
ctx.body = await sanitizeOutput(file2, ctx);
|
|
2603
|
-
},
|
|
2604
|
-
async destroy(ctx) {
|
|
2605
|
-
const {
|
|
2606
|
-
params: { id }
|
|
2607
|
-
} = ctx;
|
|
2608
|
-
const file2 = await getService("upload").findOne(id);
|
|
2609
|
-
if (!file2) {
|
|
2610
|
-
return ctx.notFound("file.notFound");
|
|
2611
|
-
}
|
|
2612
|
-
await getService("upload").remove(file2);
|
|
2613
|
-
ctx.body = await sanitizeOutput(file2, ctx);
|
|
2614
|
-
},
|
|
2615
|
-
async updateFileInfo(ctx) {
|
|
2616
|
-
const {
|
|
2617
|
-
query: { id },
|
|
2618
|
-
request: { body }
|
|
2619
|
-
} = ctx;
|
|
2620
|
-
const data = await validateUploadBody(body);
|
|
2621
|
-
if (!id || typeof id !== "string" && typeof id !== "number") {
|
|
2622
|
-
throw new ValidationError("File id is required and must be a single value");
|
|
2623
|
-
}
|
|
2624
|
-
const result = await getService("upload").updateFileInfo(id, data.fileInfo);
|
|
2625
|
-
ctx.body = await sanitizeOutput(result, ctx);
|
|
2626
|
-
},
|
|
2627
|
-
async replaceFile(ctx) {
|
|
2628
|
-
const {
|
|
2629
|
-
query: { id },
|
|
2630
|
-
request: { body, files: { files } = {} }
|
|
2631
|
-
} = ctx;
|
|
2632
|
-
if (Array.isArray(files)) {
|
|
2633
|
-
throw new ValidationError("Cannot replace a file with multiple ones");
|
|
2634
|
-
}
|
|
2635
|
-
if (!id || typeof id !== "string" && typeof id !== "number") {
|
|
2636
|
-
throw new ValidationError("File id is required and must be a single value");
|
|
2637
|
-
}
|
|
2638
|
-
const data = await validateUploadBody(body);
|
|
2639
|
-
const replacedFiles = await getService("upload").replace(id, { data, file: files });
|
|
2640
|
-
ctx.body = await sanitizeOutput(replacedFiles, ctx);
|
|
2641
|
-
},
|
|
2642
|
-
async uploadFiles(ctx) {
|
|
2643
|
-
const {
|
|
2644
|
-
request: { body, files: { files } = {} }
|
|
2645
|
-
} = ctx;
|
|
2646
|
-
const data = await validateUploadBody(body, Array.isArray(files));
|
|
2647
|
-
const apiUploadFolderService = getService("api-upload-folder");
|
|
2648
|
-
const apiUploadFolder2 = await apiUploadFolderService.getAPIUploadFolder();
|
|
2649
|
-
if (Array.isArray(files)) {
|
|
2650
|
-
data.fileInfo = data.fileInfo || [];
|
|
2651
|
-
data.fileInfo = files.map((_f, i) => ({ ...data.fileInfo[i], folder: apiUploadFolder2.id }));
|
|
2652
|
-
} else {
|
|
2653
|
-
data.fileInfo = { ...data.fileInfo, folder: apiUploadFolder2.id };
|
|
2654
|
-
}
|
|
2655
|
-
const uploadedFiles = await getService("upload").upload({
|
|
2656
|
-
data,
|
|
2657
|
-
files
|
|
2658
|
-
});
|
|
2659
|
-
ctx.body = await sanitizeOutput(uploadedFiles, ctx);
|
|
2660
|
-
ctx.status = 201;
|
|
2661
|
-
},
|
|
2662
|
-
// TODO: split into multiple endpoints
|
|
2663
|
-
async upload(ctx) {
|
|
2664
|
-
const {
|
|
2665
|
-
query: { id },
|
|
2666
|
-
request: { files: { files } = {} }
|
|
2667
|
-
} = ctx;
|
|
2668
|
-
if (___default.default.isEmpty(files) || !Array.isArray(files) && files.size === 0) {
|
|
2669
|
-
if (id) {
|
|
2670
|
-
return this.updateFileInfo(ctx);
|
|
2671
|
-
}
|
|
2672
|
-
throw new ValidationError("Files are empty");
|
|
2673
|
-
}
|
|
2674
|
-
await (id ? this.replaceFile : this.uploadFiles)(ctx);
|
|
2675
|
-
}
|
|
2676
|
-
};
|
|
2677
|
-
};
|
|
2678
|
-
const configSchema = utils.yup.object({
|
|
2679
|
-
pageSize: utils.yup.number().required(),
|
|
2680
|
-
sort: utils.yup.mixed().oneOf(ALLOWED_SORT_STRINGS)
|
|
2681
|
-
});
|
|
2682
|
-
const validateViewConfiguration = utils.validateYupSchema(configSchema);
|
|
2683
|
-
const viewConfiguration = {
|
|
2684
|
-
async updateViewConfiguration(ctx) {
|
|
2685
|
-
const {
|
|
2686
|
-
request: { body },
|
|
2687
|
-
state: { userAbility }
|
|
2688
|
-
} = ctx;
|
|
2689
|
-
if (userAbility.cannot(ACTIONS.configureView)) {
|
|
2690
|
-
return ctx.forbidden();
|
|
2691
|
-
}
|
|
2692
|
-
const data = await validateViewConfiguration(body);
|
|
2693
|
-
await getService("upload").setConfiguration(data);
|
|
2694
|
-
ctx.body = { data };
|
|
2695
|
-
},
|
|
2696
|
-
async findViewConfiguration(ctx) {
|
|
2697
|
-
const data = await getService("upload").getConfiguration();
|
|
2698
|
-
ctx.body = { data };
|
|
2699
|
-
}
|
|
2700
|
-
};
|
|
2701
|
-
const controllers = {
|
|
2702
|
-
"admin-file": adminFile,
|
|
2703
|
-
"admin-folder": adminFolder,
|
|
2704
|
-
"admin-folder-file": adminFolderFile,
|
|
2705
|
-
"admin-settings": adminSettings,
|
|
2706
|
-
"admin-upload": adminUpload,
|
|
2707
|
-
"content-api": contentApi,
|
|
2708
|
-
"view-configuration": viewConfiguration
|
|
2709
|
-
};
|
|
2710
|
-
const index = () => ({
|
|
2711
|
-
register,
|
|
2712
|
-
bootstrap,
|
|
2713
|
-
config,
|
|
2714
|
-
routes,
|
|
2715
|
-
controllers,
|
|
2716
|
-
contentTypes,
|
|
2717
|
-
services
|
|
2718
|
-
});
|
|
2719
|
-
exports.FILE_MODEL_UID = FILE_MODEL_UID;
|
|
2720
|
-
exports.index = index;
|
|
2721
|
-
//# sourceMappingURL=index-D57iKFts.js.map
|