@nocobase/plugin-file-manager 1.7.0-beta.2 → 1.7.0-beta.21
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/client/index.d.ts +13 -0
- package/dist/client/index.js +1 -1
- package/dist/{server/FileModel.d.ts → common/constants.d.ts} +1 -4
- package/dist/common/constants.js +36 -0
- package/dist/externalVersion.js +10 -10
- package/dist/locale/de-DE.json +1 -1
- package/dist/locale/it-IT.json +4 -7
- package/dist/locale/ja-JP.json +1 -1
- package/dist/locale/nl-NL.json +35 -17
- package/dist/locale/zh-CN.json +1 -1
- package/dist/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +834 -834
- package/dist/node_modules/@aws-sdk/client-s3/package.json +1 -1
- package/dist/node_modules/mime-match/package.json +1 -1
- package/dist/node_modules/mkdirp/package.json +1 -1
- package/dist/node_modules/multer-aliyun-oss/index.js +3 -3
- package/dist/node_modules/multer-aliyun-oss/package.json +1 -1
- package/dist/node_modules/multer-cos/index.js +5 -5
- package/dist/node_modules/multer-cos/package.json +1 -1
- package/dist/node_modules/multer-s3/index.js +837 -837
- package/dist/node_modules/multer-s3/package.json +1 -1
- package/dist/node_modules/url-join/.travis.yml +5 -0
- package/dist/node_modules/url-join/LICENSE +21 -0
- package/dist/node_modules/url-join/bin/changelog +28 -0
- package/dist/node_modules/url-join/lib/url-join.js +1 -0
- package/dist/node_modules/url-join/package.json +1 -0
- package/dist/node_modules/url-join/test/tests.js +151 -0
- package/dist/server/actions/attachments.d.ts +0 -11
- package/dist/server/actions/attachments.js +10 -39
- package/dist/server/actions/index.js +19 -0
- package/dist/server/actions/storages.js +4 -1
- package/dist/server/collections/storages.js +8 -4
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +3 -0
- package/dist/server/server.d.ts +6 -6
- package/dist/server/server.js +110 -56
- package/dist/server/storages/index.d.ts +11 -5
- package/dist/server/storages/index.js +49 -2
- package/dist/server/storages/local.d.ts +1 -1
- package/dist/server/storages/local.js +12 -5
- package/dist/server/storages/s3.d.ts +4 -0
- package/dist/server/storages/s3.js +36 -12
- package/dist/server/storages/tx-cos.js +4 -4
- package/dist/server/utils.d.ts +3 -1
- package/dist/server/utils.js +25 -2
- package/package.json +8 -7
- package/dist/server/FileModel.js +0 -58
package/dist/server/server.js
CHANGED
|
@@ -40,19 +40,19 @@ __export(server_exports, {
|
|
|
40
40
|
default: () => server_default
|
|
41
41
|
});
|
|
42
42
|
module.exports = __toCommonJS(server_exports);
|
|
43
|
+
var import_fs = __toESM(require("fs"));
|
|
44
|
+
var import_path = require("path");
|
|
45
|
+
var import_database = require("@nocobase/database");
|
|
43
46
|
var import_server = require("@nocobase/server");
|
|
44
47
|
var import_utils = require("@nocobase/utils");
|
|
45
|
-
var import_path = require("path");
|
|
46
|
-
var import_fs = __toESM(require("fs"));
|
|
47
48
|
var import_constants = require("../constants");
|
|
48
|
-
var import_FileModel = require("./FileModel");
|
|
49
49
|
var import_actions = __toESM(require("./actions"));
|
|
50
|
-
var import_attachments = require("./actions/attachments");
|
|
51
50
|
var import_attachment_interface = require("./interfaces/attachment-interface");
|
|
52
51
|
var import_ali_oss = __toESM(require("./storages/ali-oss"));
|
|
53
52
|
var import_local = __toESM(require("./storages/local"));
|
|
54
53
|
var import_s3 = __toESM(require("./storages/s3"));
|
|
55
54
|
var import_tx_cos = __toESM(require("./storages/tx-cos"));
|
|
55
|
+
var import_utils2 = require("./utils");
|
|
56
56
|
const DEFAULT_STORAGE_TYPE = import_constants.STORAGE_TYPE_LOCAL;
|
|
57
57
|
class FileDeleteError extends Error {
|
|
58
58
|
data;
|
|
@@ -71,11 +71,20 @@ class PluginFileManagerServer extends import_server.Plugin {
|
|
|
71
71
|
if (((_a = collection == null ? void 0 : collection.options) == null ? void 0 : _a.template) !== "file" && collection.name !== "attachments") {
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
|
+
if (!record.get("storageId")) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
74
77
|
const storage = this.storagesCache.get(record.get("storageId"));
|
|
78
|
+
if (!storage) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
75
81
|
if (storage == null ? void 0 : storage.paranoid) {
|
|
76
82
|
return;
|
|
77
83
|
}
|
|
78
84
|
const Type = this.storageTypes.get(storage.type);
|
|
85
|
+
if (!Type) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
79
88
|
const storageConfig = new Type(storage);
|
|
80
89
|
const result = await storageConfig.delete([record]);
|
|
81
90
|
if (!result[0]) {
|
|
@@ -101,29 +110,24 @@ class PluginFileManagerServer extends import_server.Plugin {
|
|
|
101
110
|
}
|
|
102
111
|
async uploadFile(options) {
|
|
103
112
|
const { storageName, filePath, documentRoot } = options;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
default: true
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
const fileStream = import_fs.default.createReadStream(filePath);
|
|
114
|
-
if (!storageInstance) {
|
|
113
|
+
if (!this.storagesCache.size) {
|
|
114
|
+
await this.loadStorages();
|
|
115
|
+
}
|
|
116
|
+
const storages = Array.from(this.storagesCache.values());
|
|
117
|
+
const storage = storages.find((item) => item.name === storageName) || storages.find((item) => item.default);
|
|
118
|
+
if (!storage) {
|
|
115
119
|
throw new Error("[file-manager] no linked or default storage provided");
|
|
116
120
|
}
|
|
117
|
-
|
|
121
|
+
const fileStream = import_fs.default.createReadStream(filePath);
|
|
118
122
|
if (documentRoot) {
|
|
119
|
-
|
|
123
|
+
storage.options["documentRoot"] = documentRoot;
|
|
120
124
|
}
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
if (!
|
|
124
|
-
throw new Error(`[file-manager] storage type "${
|
|
125
|
+
const StorageType = this.storageTypes.get(storage.type);
|
|
126
|
+
const storageInstance = new StorageType(storage);
|
|
127
|
+
if (!storageInstance) {
|
|
128
|
+
throw new Error(`[file-manager] storage type "${storage.type}" is not defined`);
|
|
125
129
|
}
|
|
126
|
-
const engine =
|
|
130
|
+
const engine = storageInstance.make();
|
|
127
131
|
const file = {
|
|
128
132
|
originalname: (0, import_path.basename)(filePath),
|
|
129
133
|
path: filePath,
|
|
@@ -138,7 +142,7 @@ class PluginFileManagerServer extends import_server.Plugin {
|
|
|
138
142
|
resolve(info);
|
|
139
143
|
});
|
|
140
144
|
});
|
|
141
|
-
return
|
|
145
|
+
return storageInstance.getFileData(file, {});
|
|
142
146
|
}
|
|
143
147
|
async loadStorages(options) {
|
|
144
148
|
const repository = this.db.getRepository("storages");
|
|
@@ -149,7 +153,6 @@ class PluginFileManagerServer extends import_server.Plugin {
|
|
|
149
153
|
for (const storage of storages) {
|
|
150
154
|
this.storagesCache.set(storage.get("id"), this.parseStorage(storage));
|
|
151
155
|
}
|
|
152
|
-
this.db["_fileStorages"] = this.storagesCache;
|
|
153
156
|
}
|
|
154
157
|
async install() {
|
|
155
158
|
const defaultStorageType = this.storageTypes.get(DEFAULT_STORAGE_TYPE);
|
|
@@ -172,26 +175,31 @@ class PluginFileManagerServer extends import_server.Plugin {
|
|
|
172
175
|
}
|
|
173
176
|
}
|
|
174
177
|
async handleSyncMessage(message) {
|
|
175
|
-
if (message.type === "
|
|
176
|
-
|
|
177
|
-
filterByTk: message.storageId
|
|
178
|
-
});
|
|
179
|
-
if (storage) {
|
|
180
|
-
this.storagesCache.set(storage.id, this.parseStorage(storage));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
if (message.type === "storageRemove") {
|
|
184
|
-
const id = message.storageId;
|
|
185
|
-
this.storagesCache.delete(id);
|
|
178
|
+
if (message.type === "reloadStorages") {
|
|
179
|
+
await this.loadStorages();
|
|
186
180
|
}
|
|
187
181
|
}
|
|
188
182
|
async beforeLoad() {
|
|
189
|
-
this.db.registerModels({ FileModel:
|
|
183
|
+
this.db.registerModels({ FileModel: import_database.Model });
|
|
190
184
|
this.db.on("beforeDefineCollection", (options) => {
|
|
191
185
|
if (options.template === "file") {
|
|
192
186
|
options.model = "FileModel";
|
|
193
187
|
}
|
|
194
188
|
});
|
|
189
|
+
this.db.on("afterDefineCollection", (collection) => {
|
|
190
|
+
if (collection.options.template !== "file") {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
collection.model.beforeUpdate((model) => {
|
|
194
|
+
if (!model.changed("url") || !model.changed("preview")) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
model.set("url", model.previous("url"));
|
|
198
|
+
model.set("preview", model.previous("preview"));
|
|
199
|
+
model.changed("url", false);
|
|
200
|
+
model.changed("preview", false);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
195
203
|
this.app.on("afterStart", async () => {
|
|
196
204
|
await this.loadStorages();
|
|
197
205
|
});
|
|
@@ -203,25 +211,23 @@ class PluginFileManagerServer extends import_server.Plugin {
|
|
|
203
211
|
this.storageTypes.register(import_constants.STORAGE_TYPE_S3, import_s3.default);
|
|
204
212
|
this.storageTypes.register(import_constants.STORAGE_TYPE_TX_COS, import_tx_cos.default);
|
|
205
213
|
const Storage = this.db.getModel("storages");
|
|
206
|
-
Storage.afterSave((m, { transaction }) => {
|
|
207
|
-
this.
|
|
208
|
-
this.sendSyncMessage(
|
|
209
|
-
{
|
|
210
|
-
type: "storageChange",
|
|
211
|
-
storageId: m.id
|
|
212
|
-
},
|
|
213
|
-
{ transaction }
|
|
214
|
-
);
|
|
214
|
+
Storage.afterSave(async (m, { transaction }) => {
|
|
215
|
+
await this.loadStorages({ transaction });
|
|
216
|
+
this.sendSyncMessage({ type: "reloadStorages" }, { transaction });
|
|
215
217
|
});
|
|
216
|
-
Storage.afterDestroy((m, { transaction }) => {
|
|
217
|
-
|
|
218
|
-
this.
|
|
219
|
-
{
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
218
|
+
Storage.afterDestroy(async (m, { transaction }) => {
|
|
219
|
+
var _a, _b;
|
|
220
|
+
for (const collection of this.db.collections.values()) {
|
|
221
|
+
if (((_a = collection == null ? void 0 : collection.options) == null ? void 0 : _a.template) === "file" && ((_b = collection == null ? void 0 : collection.options) == null ? void 0 : _b.storage) === m.name) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
this.t(
|
|
224
|
+
`The storage "${m.name}" is in use in collection "${collection.name}" and cannot be deleted.`
|
|
225
|
+
)
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
await this.loadStorages({ transaction });
|
|
230
|
+
this.sendSyncMessage({ type: "reloadStorages" }, { transaction });
|
|
225
231
|
});
|
|
226
232
|
this.app.acl.registerSnippet({
|
|
227
233
|
name: `pm.${this.name}.storages`,
|
|
@@ -248,11 +254,59 @@ class PluginFileManagerServer extends import_server.Plugin {
|
|
|
248
254
|
this.app.acl.addFixedParams("attachments", "create", ownMerger);
|
|
249
255
|
this.app.acl.addFixedParams("attachments", "destroy", ownMerger);
|
|
250
256
|
this.app.db.interfaceManager.registerInterfaceType("attachment", import_attachment_interface.AttachmentInterface);
|
|
257
|
+
this.db.on("afterFind", async (instances) => {
|
|
258
|
+
var _a, _b, _c;
|
|
259
|
+
if (!instances) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const records = Array.isArray(instances) ? instances : [instances];
|
|
263
|
+
const name = (_b = (_a = records[0]) == null ? void 0 : _a.constructor) == null ? void 0 : _b.name;
|
|
264
|
+
if (name) {
|
|
265
|
+
const collection = this.db.getCollection(name);
|
|
266
|
+
if ((collection == null ? void 0 : collection.name) === "attachments" || ((_c = collection == null ? void 0 : collection.options) == null ? void 0 : _c.template) === "file") {
|
|
267
|
+
for (const record of records) {
|
|
268
|
+
const url = await this.getFileURL(record);
|
|
269
|
+
const previewUrl = await this.getFileURL(record, true);
|
|
270
|
+
record.set("url", url);
|
|
271
|
+
record.set("preview", previewUrl);
|
|
272
|
+
record.dataValues.preview = previewUrl;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
});
|
|
251
277
|
}
|
|
252
|
-
getFileURL(file) {
|
|
278
|
+
async getFileURL(file, preview = false) {
|
|
279
|
+
if (!file.storageId) {
|
|
280
|
+
return (0, import_utils2.encodeURL)(file.url);
|
|
281
|
+
}
|
|
253
282
|
const storage = this.storagesCache.get(file.storageId);
|
|
283
|
+
if (!storage) {
|
|
284
|
+
return (0, import_utils2.encodeURL)(file.url);
|
|
285
|
+
}
|
|
254
286
|
const storageType = this.storageTypes.get(storage.type);
|
|
255
|
-
return new storageType(storage).getFileURL(file);
|
|
287
|
+
return new storageType(storage).getFileURL(file, preview ? storage.options.thumbnailRule : "");
|
|
288
|
+
}
|
|
289
|
+
async isPublicAccessStorage(storageName) {
|
|
290
|
+
var _a;
|
|
291
|
+
const storageRepository = this.db.getRepository("storages");
|
|
292
|
+
const storages = await storageRepository.findOne({
|
|
293
|
+
filter: { default: true }
|
|
294
|
+
});
|
|
295
|
+
let storage;
|
|
296
|
+
if (!storageName) {
|
|
297
|
+
storage = storages;
|
|
298
|
+
} else {
|
|
299
|
+
storage = await storageRepository.findOne({
|
|
300
|
+
filter: {
|
|
301
|
+
name: storageName
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
storage = this.parseStorage(storage);
|
|
306
|
+
if (["local", "ali-oss", "s3", "tx-cos"].includes(storage.type)) {
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
return !!((_a = storage.options) == null ? void 0 : _a.public);
|
|
256
310
|
}
|
|
257
311
|
}
|
|
258
312
|
var server_default = PluginFileManagerServer;
|
|
@@ -33,12 +33,18 @@ export declare abstract class StorageType {
|
|
|
33
33
|
constructor(storage: StorageModel);
|
|
34
34
|
abstract make(): StorageEngine;
|
|
35
35
|
abstract delete(records: AttachmentModel[]): [number, AttachmentModel[]] | Promise<[number, AttachmentModel[]]>;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
getFileKey(record: AttachmentModel): any;
|
|
37
|
+
getFileData(file: any, meta?: {}): {
|
|
38
|
+
title: string;
|
|
39
|
+
filename: string;
|
|
40
|
+
extname: string;
|
|
41
|
+
path: string;
|
|
42
|
+
size: any;
|
|
43
|
+
mimetype: any;
|
|
44
|
+
meta: {};
|
|
45
|
+
storageId: number;
|
|
40
46
|
};
|
|
41
|
-
getFileURL(file: AttachmentModel): string | Promise<string>;
|
|
47
|
+
getFileURL(file: AttachmentModel, preview?: boolean): string | Promise<string>;
|
|
42
48
|
}
|
|
43
49
|
export type StorageClassType = {
|
|
44
50
|
new (storage: StorageModel): StorageType;
|
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
var __create = Object.create;
|
|
10
11
|
var __defProp = Object.defineProperty;
|
|
11
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
13
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
15
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
16
|
var __export = (target, all) => {
|
|
15
17
|
for (var name in all)
|
|
@@ -23,12 +25,24 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
23
25
|
}
|
|
24
26
|
return to;
|
|
25
27
|
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
26
36
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
37
|
var storages_exports = {};
|
|
28
38
|
__export(storages_exports, {
|
|
29
39
|
StorageType: () => StorageType
|
|
30
40
|
});
|
|
31
41
|
module.exports = __toCommonJS(storages_exports);
|
|
42
|
+
var import_path = __toESM(require("path"));
|
|
43
|
+
var import_url_join = __toESM(require("url-join"));
|
|
44
|
+
var import_utils = require("@nocobase/utils");
|
|
45
|
+
var import_utils2 = require("../utils");
|
|
32
46
|
class StorageType {
|
|
33
47
|
constructor(storage) {
|
|
34
48
|
this.storage = storage;
|
|
@@ -37,8 +51,41 @@ class StorageType {
|
|
|
37
51
|
return {};
|
|
38
52
|
}
|
|
39
53
|
static filenameKey;
|
|
40
|
-
|
|
41
|
-
return
|
|
54
|
+
getFileKey(record) {
|
|
55
|
+
return (0, import_utils2.getFileKey)(record);
|
|
56
|
+
}
|
|
57
|
+
getFileData(file, meta = {}) {
|
|
58
|
+
const { [this.constructor.filenameKey || "filename"]: name } = file;
|
|
59
|
+
const filename = import_path.default.basename(name);
|
|
60
|
+
const extname = import_path.default.extname(filename);
|
|
61
|
+
const path = (this.storage.path || "").replace(/^\/|\/$/g, "");
|
|
62
|
+
const data = {
|
|
63
|
+
title: Buffer.from(file.originalname, "latin1").toString("utf8").replace(extname, ""),
|
|
64
|
+
filename,
|
|
65
|
+
extname,
|
|
66
|
+
// TODO(feature): 暂时两者相同,后面 storage.path 模版化以后,这里只是 file 实际的 path
|
|
67
|
+
path,
|
|
68
|
+
size: file.size,
|
|
69
|
+
mimetype: file.mimetype,
|
|
70
|
+
meta,
|
|
71
|
+
storageId: this.storage.id
|
|
72
|
+
};
|
|
73
|
+
return data;
|
|
74
|
+
}
|
|
75
|
+
getFileURL(file, preview) {
|
|
76
|
+
if (file.url && (0, import_utils.isURL)(file.url)) {
|
|
77
|
+
if (preview) {
|
|
78
|
+
return (0, import_utils2.encodeURL)(file.url) + (this.storage.options.thumbnailRule || "");
|
|
79
|
+
}
|
|
80
|
+
return (0, import_utils2.encodeURL)(file.url);
|
|
81
|
+
}
|
|
82
|
+
const keys = [
|
|
83
|
+
this.storage.baseUrl,
|
|
84
|
+
file.path && encodeURI(file.path),
|
|
85
|
+
(0, import_utils2.ensureUrlEncoded)(file.filename),
|
|
86
|
+
preview && this.storage.options.thumbnailRule
|
|
87
|
+
].filter(Boolean);
|
|
88
|
+
return (0, import_url_join.default)(keys);
|
|
42
89
|
}
|
|
43
90
|
}
|
|
44
91
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -24,5 +24,5 @@ export default class extends StorageType {
|
|
|
24
24
|
};
|
|
25
25
|
make(): multer.StorageEngine;
|
|
26
26
|
delete(records: AttachmentModel[]): Promise<[number, AttachmentModel[]]>;
|
|
27
|
-
getFileURL(file: AttachmentModel):
|
|
27
|
+
getFileURL(file: AttachmentModel, preview?: boolean): Promise<any>;
|
|
28
28
|
}
|
|
@@ -39,13 +39,16 @@ __export(local_exports, {
|
|
|
39
39
|
default: () => local_default
|
|
40
40
|
});
|
|
41
41
|
module.exports = __toCommonJS(local_exports);
|
|
42
|
+
var import_utils = require("@nocobase/utils");
|
|
42
43
|
var import_promises = __toESM(require("fs/promises"));
|
|
43
44
|
var import_mkdirp = __toESM(require("mkdirp"));
|
|
44
45
|
var import_multer = __toESM(require("multer"));
|
|
45
46
|
var import_path = __toESM(require("path"));
|
|
47
|
+
var import_url_join = __toESM(require("url-join"));
|
|
46
48
|
var import__ = require(".");
|
|
47
49
|
var import_constants = require("../../constants");
|
|
48
|
-
var
|
|
50
|
+
var import_utils2 = require("../utils");
|
|
51
|
+
const DEFAULT_BASE_URL = "/storage/uploads";
|
|
49
52
|
function getDocumentRoot(storage) {
|
|
50
53
|
const { documentRoot = process.env.LOCAL_STORAGE_DEST || "storage/uploads" } = storage.options || {};
|
|
51
54
|
return import_path.default.resolve(import_path.default.isAbsolute(documentRoot) ? documentRoot : import_path.default.join(process.cwd(), documentRoot));
|
|
@@ -56,7 +59,7 @@ class local_default extends import__.StorageType {
|
|
|
56
59
|
title: "Local storage",
|
|
57
60
|
type: import_constants.STORAGE_TYPE_LOCAL,
|
|
58
61
|
name: `local`,
|
|
59
|
-
baseUrl:
|
|
62
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
60
63
|
options: {
|
|
61
64
|
documentRoot: "storage/uploads"
|
|
62
65
|
},
|
|
@@ -72,7 +75,7 @@ class local_default extends import__.StorageType {
|
|
|
72
75
|
const destPath = import_path.default.join(getDocumentRoot(this.storage), this.storage.path || "");
|
|
73
76
|
(0, import_mkdirp.default)(destPath, (err) => cb(err, destPath));
|
|
74
77
|
},
|
|
75
|
-
filename:
|
|
78
|
+
filename: import_utils2.getFilename
|
|
76
79
|
});
|
|
77
80
|
}
|
|
78
81
|
async delete(records) {
|
|
@@ -98,7 +101,11 @@ class local_default extends import__.StorageType {
|
|
|
98
101
|
);
|
|
99
102
|
return [count, undeleted];
|
|
100
103
|
}
|
|
101
|
-
getFileURL(file) {
|
|
102
|
-
|
|
104
|
+
async getFileURL(file, preview = false) {
|
|
105
|
+
const url = await super.getFileURL(file, preview);
|
|
106
|
+
if ((0, import_utils.isURL)(url)) {
|
|
107
|
+
return url;
|
|
108
|
+
}
|
|
109
|
+
return (0, import_url_join.default)(process.env.APP_PUBLIC_PATH, url);
|
|
103
110
|
}
|
|
104
111
|
}
|
|
@@ -22,5 +22,9 @@ export default class extends StorageType {
|
|
|
22
22
|
};
|
|
23
23
|
static filenameKey: string;
|
|
24
24
|
make(): any;
|
|
25
|
+
calculateContentMD5(body: any): string;
|
|
26
|
+
deleteS3Objects(bucketName: string, objects: string[]): Promise<{
|
|
27
|
+
Deleted: any[];
|
|
28
|
+
}>;
|
|
25
29
|
delete(records: AttachmentModel[]): Promise<[number, AttachmentModel[]]>;
|
|
26
30
|
}
|
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
var __create = Object.create;
|
|
10
11
|
var __defProp = Object.defineProperty;
|
|
11
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
13
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
15
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
16
|
var __export = (target, all) => {
|
|
15
17
|
for (var name in all)
|
|
@@ -23,12 +25,22 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
23
25
|
}
|
|
24
26
|
return to;
|
|
25
27
|
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
26
36
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
37
|
var s3_exports = {};
|
|
28
38
|
__export(s3_exports, {
|
|
29
39
|
default: () => s3_default
|
|
30
40
|
});
|
|
31
41
|
module.exports = __toCommonJS(s3_exports);
|
|
42
|
+
var import_client_s3 = require("@aws-sdk/client-s3");
|
|
43
|
+
var import_crypto = __toESM(require("crypto"));
|
|
32
44
|
var import__ = require(".");
|
|
33
45
|
var import_constants = require("../../constants");
|
|
34
46
|
var import_utils = require("../utils");
|
|
@@ -49,7 +61,6 @@ class s3_default extends import__.StorageType {
|
|
|
49
61
|
}
|
|
50
62
|
static filenameKey = "key";
|
|
51
63
|
make() {
|
|
52
|
-
const { S3Client } = require("@aws-sdk/client-s3");
|
|
53
64
|
const multerS3 = require("multer-s3");
|
|
54
65
|
const { accessKeyId, secretAccessKey, bucket, acl = "public-read", ...options } = this.storage.options;
|
|
55
66
|
if (options.endpoint) {
|
|
@@ -57,7 +68,7 @@ class s3_default extends import__.StorageType {
|
|
|
57
68
|
} else {
|
|
58
69
|
options.endpoint = void 0;
|
|
59
70
|
}
|
|
60
|
-
const s3 = new S3Client({
|
|
71
|
+
const s3 = new import_client_s3.S3Client({
|
|
61
72
|
...options,
|
|
62
73
|
credentials: {
|
|
63
74
|
accessKeyId,
|
|
@@ -78,17 +89,30 @@ class s3_default extends import__.StorageType {
|
|
|
78
89
|
key: (0, import_utils.cloudFilenameGetter)(this.storage)
|
|
79
90
|
});
|
|
80
91
|
}
|
|
81
|
-
|
|
82
|
-
const
|
|
92
|
+
calculateContentMD5(body) {
|
|
93
|
+
const hash = import_crypto.default.createHash("md5").update(body).digest("base64");
|
|
94
|
+
return hash;
|
|
95
|
+
}
|
|
96
|
+
async deleteS3Objects(bucketName, objects) {
|
|
83
97
|
const { s3 } = this.make();
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
const Deleted = [];
|
|
99
|
+
for (const Key of objects) {
|
|
100
|
+
const deleteCommand = new import_client_s3.DeleteObjectCommand({
|
|
101
|
+
Bucket: bucketName,
|
|
102
|
+
Key
|
|
103
|
+
});
|
|
104
|
+
await s3.send(deleteCommand);
|
|
105
|
+
Deleted.push({ Key });
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
Deleted
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async delete(records) {
|
|
112
|
+
const { Deleted } = await this.deleteS3Objects(
|
|
113
|
+
this.storage.options.bucket,
|
|
114
|
+
records.map((record) => this.getFileKey(record))
|
|
91
115
|
);
|
|
92
|
-
return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key ===
|
|
116
|
+
return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key === this.getFileKey(record)))];
|
|
93
117
|
}
|
|
94
118
|
}
|
|
@@ -32,7 +32,7 @@ module.exports = __toCommonJS(tx_cos_exports);
|
|
|
32
32
|
var import_util = require("util");
|
|
33
33
|
var import__ = require(".");
|
|
34
34
|
var import_constants = require("../../constants");
|
|
35
|
-
var
|
|
35
|
+
var import_utils2 = require("../utils");
|
|
36
36
|
class tx_cos_default extends import__.StorageType {
|
|
37
37
|
static defaults() {
|
|
38
38
|
return {
|
|
@@ -56,7 +56,7 @@ class tx_cos_default extends import__.StorageType {
|
|
|
56
56
|
...this.storage.options,
|
|
57
57
|
dir: (this.storage.path ?? "").replace(/\/+$/, "")
|
|
58
58
|
},
|
|
59
|
-
filename:
|
|
59
|
+
filename: import_utils2.getFilename
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
async delete(records) {
|
|
@@ -64,8 +64,8 @@ class tx_cos_default extends import__.StorageType {
|
|
|
64
64
|
const { Deleted } = await (0, import_util.promisify)(cos.deleteMultipleObject).call(cos, {
|
|
65
65
|
Region: this.storage.options.Region,
|
|
66
66
|
Bucket: this.storage.options.Bucket,
|
|
67
|
-
Objects: records.map((record) => ({ Key: (0,
|
|
67
|
+
Objects: records.map((record) => ({ Key: (0, import_utils2.getFileKey)(record) }))
|
|
68
68
|
});
|
|
69
|
-
return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key === (0,
|
|
69
|
+
return [Deleted.length, records.filter((record) => !Deleted.find((item) => item.Key === (0, import_utils2.getFileKey)(record)))];
|
|
70
70
|
}
|
|
71
71
|
}
|
package/dist/server/utils.d.ts
CHANGED
|
@@ -8,4 +8,6 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function getFilename(req: any, file: any, cb: any): void;
|
|
10
10
|
export declare const cloudFilenameGetter: (storage: any) => (req: any, file: any, cb: any) => void;
|
|
11
|
-
export declare function getFileKey(record: any):
|
|
11
|
+
export declare function getFileKey(record: any): any;
|
|
12
|
+
export declare function ensureUrlEncoded(value: any): any;
|
|
13
|
+
export declare function encodeURL(url: any): string;
|
package/dist/server/utils.js
CHANGED
|
@@ -37,12 +37,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
37
37
|
var utils_exports = {};
|
|
38
38
|
__export(utils_exports, {
|
|
39
39
|
cloudFilenameGetter: () => cloudFilenameGetter,
|
|
40
|
+
encodeURL: () => encodeURL,
|
|
41
|
+
ensureUrlEncoded: () => ensureUrlEncoded,
|
|
40
42
|
getFileKey: () => getFileKey,
|
|
41
43
|
getFilename: () => getFilename
|
|
42
44
|
});
|
|
43
45
|
module.exports = __toCommonJS(utils_exports);
|
|
44
|
-
var import_path = __toESM(require("path"));
|
|
45
46
|
var import_utils = require("@nocobase/utils");
|
|
47
|
+
var import_path = __toESM(require("path"));
|
|
48
|
+
var import_url_join = __toESM(require("url-join"));
|
|
46
49
|
function getFilename(req, file, cb) {
|
|
47
50
|
const originalname = Buffer.from(file.originalname, "binary").toString("utf8");
|
|
48
51
|
const baseName = import_path.default.basename(originalname.replace(/[<>?*|:"\\/]/g, "-"), import_path.default.extname(originalname));
|
|
@@ -57,11 +60,31 @@ const cloudFilenameGetter = (storage) => (req, file, cb) => {
|
|
|
57
60
|
});
|
|
58
61
|
};
|
|
59
62
|
function getFileKey(record) {
|
|
60
|
-
return
|
|
63
|
+
return (0, import_url_join.default)(record.path || "", record.filename).replace(/^\//, "");
|
|
64
|
+
}
|
|
65
|
+
function ensureUrlEncoded(value) {
|
|
66
|
+
try {
|
|
67
|
+
if (decodeURIComponent(value) !== value) {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
return encodeURIComponent(value);
|
|
72
|
+
}
|
|
73
|
+
return encodeURIComponent(value);
|
|
74
|
+
}
|
|
75
|
+
function encodePathKeepSlash(path2) {
|
|
76
|
+
return path2.split("/").map((segment) => ensureUrlEncoded(segment)).join("/");
|
|
77
|
+
}
|
|
78
|
+
function encodeURL(url) {
|
|
79
|
+
const parsedUrl = new URL(url);
|
|
80
|
+
parsedUrl.pathname = encodePathKeepSlash(parsedUrl.pathname);
|
|
81
|
+
return parsedUrl.toString();
|
|
61
82
|
}
|
|
62
83
|
// Annotate the CommonJS export names for ESM import in node:
|
|
63
84
|
0 && (module.exports = {
|
|
64
85
|
cloudFilenameGetter,
|
|
86
|
+
encodeURL,
|
|
87
|
+
ensureUrlEncoded,
|
|
65
88
|
getFileKey,
|
|
66
89
|
getFilename
|
|
67
90
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/plugin-file-manager",
|
|
3
|
-
"version": "1.7.0-beta.
|
|
3
|
+
"version": "1.7.0-beta.21",
|
|
4
4
|
"displayName": "File manager",
|
|
5
5
|
"displayName.zh-CN": "文件管理器",
|
|
6
6
|
"description": "Provides files storage services with files collection template and attachment field.",
|
|
@@ -10,26 +10,27 @@
|
|
|
10
10
|
"homepage": "https://docs.nocobase.com/handbook/file-manager",
|
|
11
11
|
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/file-manager",
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@aws-sdk/client-s3": "
|
|
13
|
+
"@aws-sdk/client-s3": "3.750.0",
|
|
14
14
|
"@formily/antd-v5": "1.x",
|
|
15
15
|
"@formily/core": "2.x",
|
|
16
16
|
"@formily/react": "2.x",
|
|
17
17
|
"@formily/shared": "2.x",
|
|
18
|
-
"@koa/multer": "^3.
|
|
19
|
-
"@types/koa-multer": "^1.0.
|
|
18
|
+
"@koa/multer": "^3.1.0",
|
|
19
|
+
"@types/koa-multer": "^1.0.4",
|
|
20
20
|
"@types/multer": "^1.4.5",
|
|
21
21
|
"antd": "5.x",
|
|
22
22
|
"cos-nodejs-sdk-v5": "^2.11.14",
|
|
23
23
|
"koa-static": "^5.0.0",
|
|
24
24
|
"mime-match": "^1.0.2",
|
|
25
25
|
"mkdirp": "~0.5.4",
|
|
26
|
-
"multer": "^1.4.2",
|
|
26
|
+
"multer": "^1.4.5-lts.2",
|
|
27
27
|
"multer-aliyun-oss": "2.1.3",
|
|
28
28
|
"multer-cos": "^1.0.3",
|
|
29
29
|
"multer-s3": "^3.0.1",
|
|
30
30
|
"react": "^18.2.0",
|
|
31
31
|
"react-i18next": "^11.15.1",
|
|
32
|
-
"supertest": "^6.1.6"
|
|
32
|
+
"supertest": "^6.1.6",
|
|
33
|
+
"url-join": "4.0.1"
|
|
33
34
|
},
|
|
34
35
|
"peerDependencies": {
|
|
35
36
|
"@nocobase/actions": "1.x",
|
|
@@ -43,5 +44,5 @@
|
|
|
43
44
|
"Collections",
|
|
44
45
|
"Collection fields"
|
|
45
46
|
],
|
|
46
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "845f6124b170717387ba9d7ebf3cc2df7a861bc3"
|
|
47
48
|
}
|