@nocobase/plugin-file-manager 0.9.4-alpha.2 → 0.10.0-alpha.2
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/lib/client/FileStorage.d.ts +2 -1
- package/lib/client/FileStorage.js +6 -6
- package/lib/client/StorageOptions.d.ts +1 -1
- package/lib/client/StorageOptions.js +18 -21
- package/lib/client/index.d.ts +2 -2
- package/lib/client/index.js +12 -7
- package/lib/client/initializers/UploadActionInitializer.d.ts +2 -1
- package/lib/client/initializers/UploadActionInitializer.js +1 -1
- package/lib/client/interfaces/attachment.d.ts +2 -0
- package/lib/client/interfaces/attachment.js +139 -0
- package/lib/client/locale/en-US.d.ts +22 -0
- package/lib/client/locale/en-US.js +28 -0
- package/lib/client/locale/index.js +0 -10
- package/lib/client/locale/ja-JP.d.ts +19 -0
- package/lib/client/locale/ja-JP.js +25 -0
- package/lib/client/locale/ru-RU.d.ts +19 -0
- package/lib/client/locale/ru-RU.js +25 -0
- package/lib/client/locale/tr-TR.d.ts +18 -0
- package/lib/client/locale/tr-TR.js +24 -0
- package/lib/client/locale/zh-CN.d.ts +25 -3
- package/lib/client/locale/zh-CN.js +25 -4
- package/lib/client/schemas/storage.js +41 -18
- package/lib/client/templates/file.js +1 -1
- package/lib/server/actions/attachments.d.ts +3 -0
- package/lib/server/actions/{upload.js → attachments.js} +140 -141
- package/lib/server/actions/index.d.ts +3 -0
- package/lib/server/actions/index.js +22 -0
- package/lib/server/collections/attachments.js +1 -0
- package/lib/server/collections/storages.js +3 -2
- package/lib/server/constants.d.ts +1 -1
- package/lib/server/constants.js +3 -3
- package/lib/server/rules/mimetype.d.ts +1 -1
- package/lib/server/rules/mimetype.js +1 -1
- package/lib/server/server.d.ts +1 -0
- package/lib/server/server.js +18 -6
- package/lib/server/storages/ali-oss.d.ts +2 -0
- package/lib/server/storages/ali-oss.js +12 -0
- package/lib/server/storages/index.d.ts +29 -4
- package/lib/server/storages/index.js +17 -7
- package/lib/server/storages/local.d.ts +2 -0
- package/lib/server/storages/local.js +34 -5
- package/lib/server/storages/s3.d.ts +2 -0
- package/lib/server/storages/s3.js +21 -0
- package/lib/server/storages/tx-cos.d.ts +2 -0
- package/lib/server/storages/tx-cos.js +25 -0
- package/package.json +10 -7
- package/lib/client/FileStorageShortcut.d.ts +0 -1
- package/lib/client/FileStorageShortcut.js +0 -91
- package/lib/server/actions/upload.d.ts +0 -4
|
@@ -4,14 +4,35 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
7
|
+
var _default = {
|
|
8
8
|
'File collection': '文件数据表',
|
|
9
9
|
'File name': '文件名',
|
|
10
10
|
'Extension name': '扩展名',
|
|
11
11
|
Size: '文件大小',
|
|
12
|
-
'
|
|
12
|
+
'MIME type': 'MIME 类型',
|
|
13
13
|
URL: 'URL',
|
|
14
|
-
'File storage': '文件存储'
|
|
14
|
+
'File storage': '文件存储',
|
|
15
|
+
'File manager': '文件管理器',
|
|
16
|
+
Attachment: '附件',
|
|
17
|
+
'Allow uploading multiple files': '允许上传多个文件',
|
|
18
|
+
Storage: '存储空间',
|
|
19
|
+
Storages: '存储空间',
|
|
20
|
+
'Storage name': '存储空间标识',
|
|
21
|
+
'Storage type': '存储类型',
|
|
22
|
+
'Default storage': '默认存储空间',
|
|
23
|
+
'Storage base URL': '访问 URL 基础',
|
|
24
|
+
Destination: '上传目标文件夹',
|
|
25
|
+
'Use the built-in static file server': '使用内置静态文件服务',
|
|
26
|
+
'Local storage': '本地存储',
|
|
27
|
+
'Aliyun OSS': '阿里云 OSS',
|
|
28
|
+
'Amazon S3': '亚马逊 S3',
|
|
29
|
+
'Tencent COS': '腾讯云 COS',
|
|
30
|
+
Region: '区域',
|
|
31
|
+
Bucket: '存储桶',
|
|
32
|
+
Path: '相对路径',
|
|
33
|
+
Filename: '文件名',
|
|
34
|
+
'Will be used for API': '将用于 API',
|
|
35
|
+
'Default storage will be used when not selected': '留空将使用默认存储空间',
|
|
36
|
+
'Keep file in storage when destroy record': '删除记录时保留文件'
|
|
15
37
|
};
|
|
16
|
-
var _default = locale;
|
|
17
38
|
exports.default = _default;
|
|
@@ -18,6 +18,7 @@ function _client() {
|
|
|
18
18
|
};
|
|
19
19
|
return data;
|
|
20
20
|
}
|
|
21
|
+
var _locale = require("../locale");
|
|
21
22
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
22
23
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
23
24
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
@@ -30,7 +31,7 @@ const collection = {
|
|
|
30
31
|
name: 'title',
|
|
31
32
|
interface: 'input',
|
|
32
33
|
uiSchema: {
|
|
33
|
-
title: '{{t("
|
|
34
|
+
title: '{{t("Title")}}',
|
|
34
35
|
type: 'string',
|
|
35
36
|
'x-component': 'Input',
|
|
36
37
|
required: true
|
|
@@ -40,7 +41,8 @@ const collection = {
|
|
|
40
41
|
name: 'name',
|
|
41
42
|
interface: 'input',
|
|
42
43
|
uiSchema: {
|
|
43
|
-
title:
|
|
44
|
+
title: `{{t("Storage name", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
45
|
+
descriptions: `{{t("Will be used for API", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
44
46
|
type: 'string',
|
|
45
47
|
'x-component': 'Input'
|
|
46
48
|
}
|
|
@@ -49,21 +51,21 @@ const collection = {
|
|
|
49
51
|
name: 'type',
|
|
50
52
|
interface: 'select',
|
|
51
53
|
uiSchema: {
|
|
52
|
-
title:
|
|
54
|
+
title: `{{t("Storage type", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
53
55
|
type: 'string',
|
|
54
56
|
'x-component': 'Select',
|
|
55
57
|
required: true,
|
|
56
58
|
enum: [{
|
|
57
|
-
label:
|
|
59
|
+
label: `{{t("Local storage", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
58
60
|
value: 'local'
|
|
59
61
|
}, {
|
|
60
|
-
label:
|
|
62
|
+
label: `{{t("Aliyun OSS", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
61
63
|
value: 'ali-oss'
|
|
62
64
|
}, {
|
|
63
|
-
label:
|
|
65
|
+
label: `{{t("Amazon S3", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
64
66
|
value: 's3'
|
|
65
67
|
}, {
|
|
66
|
-
label:
|
|
68
|
+
label: `{{t("Tencent COS", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
67
69
|
value: 'tx-cos'
|
|
68
70
|
}]
|
|
69
71
|
}
|
|
@@ -72,7 +74,7 @@ const collection = {
|
|
|
72
74
|
name: 'baseUrl',
|
|
73
75
|
interface: 'input',
|
|
74
76
|
uiSchema: {
|
|
75
|
-
title:
|
|
77
|
+
title: `{{t("Storage base URL", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
76
78
|
type: 'string',
|
|
77
79
|
'x-component': 'Input',
|
|
78
80
|
required: true
|
|
@@ -82,7 +84,7 @@ const collection = {
|
|
|
82
84
|
name: 'path',
|
|
83
85
|
interface: 'input',
|
|
84
86
|
uiSchema: {
|
|
85
|
-
title:
|
|
87
|
+
title: `{{t("Path", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
86
88
|
type: 'string',
|
|
87
89
|
'x-component': 'Input'
|
|
88
90
|
}
|
|
@@ -91,7 +93,16 @@ const collection = {
|
|
|
91
93
|
name: 'default',
|
|
92
94
|
interface: 'boolean',
|
|
93
95
|
uiSchema: {
|
|
94
|
-
title:
|
|
96
|
+
title: `{{t("Default storage", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
97
|
+
type: 'boolean',
|
|
98
|
+
'x-component': 'Checkbox'
|
|
99
|
+
}
|
|
100
|
+
}, {
|
|
101
|
+
type: 'boolean',
|
|
102
|
+
name: 'paranoid',
|
|
103
|
+
interface: 'boolean',
|
|
104
|
+
uiSchema: {
|
|
105
|
+
title: `{{t("Keep file in storage when destroy record", { ns: "${_locale.NAMESPACE}" })}}`,
|
|
95
106
|
type: 'boolean',
|
|
96
107
|
'x-component': 'Checkbox'
|
|
97
108
|
}
|
|
@@ -137,14 +148,14 @@ const storageSchema = {
|
|
|
137
148
|
'x-component-props': {
|
|
138
149
|
useAction: '{{ cm.useBulkDestroyAction }}',
|
|
139
150
|
confirm: {
|
|
140
|
-
title: "{{t('Delete
|
|
151
|
+
title: "{{t('Delete')}}",
|
|
141
152
|
content: "{{t('Are you sure you want to delete it?')}}"
|
|
142
153
|
}
|
|
143
154
|
}
|
|
144
155
|
},
|
|
145
156
|
create: {
|
|
146
157
|
type: 'void',
|
|
147
|
-
title: '{{t("Add
|
|
158
|
+
title: '{{t("Add new")}}',
|
|
148
159
|
'x-component': 'Action',
|
|
149
160
|
'x-component-props': {
|
|
150
161
|
type: 'primary'
|
|
@@ -166,7 +177,7 @@ const storageSchema = {
|
|
|
166
177
|
}));
|
|
167
178
|
}
|
|
168
179
|
},
|
|
169
|
-
title: '{{t("Add
|
|
180
|
+
title: '{{t("Add new")}}',
|
|
170
181
|
properties: {
|
|
171
182
|
title: {
|
|
172
183
|
'x-component': 'CollectionField',
|
|
@@ -197,7 +208,13 @@ const storageSchema = {
|
|
|
197
208
|
'x-component': 'CollectionField',
|
|
198
209
|
'x-decorator': 'FormItem',
|
|
199
210
|
title: '',
|
|
200
|
-
'x-content':
|
|
211
|
+
'x-content': `{{t("Default storage", { ns: "${_locale.NAMESPACE}" })}}`
|
|
212
|
+
},
|
|
213
|
+
paranoid: {
|
|
214
|
+
title: '',
|
|
215
|
+
'x-component': 'CollectionField',
|
|
216
|
+
'x-decorator': 'FormItem',
|
|
217
|
+
'x-content': `{{t("Keep file in storage when destroy record", { ns: "${_locale.NAMESPACE}" })}}`
|
|
201
218
|
},
|
|
202
219
|
footer: {
|
|
203
220
|
type: 'void',
|
|
@@ -301,7 +318,7 @@ const storageSchema = {
|
|
|
301
318
|
'x-decorator-props': {
|
|
302
319
|
useValues: '{{ cm.useValuesFromRecord }}'
|
|
303
320
|
},
|
|
304
|
-
title: '{{t("Edit
|
|
321
|
+
title: '{{t("Edit")}}',
|
|
305
322
|
properties: {
|
|
306
323
|
title: {
|
|
307
324
|
'x-component': 'CollectionField',
|
|
@@ -333,7 +350,13 @@ const storageSchema = {
|
|
|
333
350
|
title: '',
|
|
334
351
|
'x-component': 'CollectionField',
|
|
335
352
|
'x-decorator': 'FormItem',
|
|
336
|
-
'x-content':
|
|
353
|
+
'x-content': `{{t("Default storage", { ns: "${_locale.NAMESPACE}" })}}`
|
|
354
|
+
},
|
|
355
|
+
paranoid: {
|
|
356
|
+
title: '',
|
|
357
|
+
'x-component': 'CollectionField',
|
|
358
|
+
'x-decorator': 'FormItem',
|
|
359
|
+
'x-content': `{{t("Keep file in storage when destroy record", { ns: "${_locale.NAMESPACE}" })}}`
|
|
337
360
|
},
|
|
338
361
|
footer: {
|
|
339
362
|
type: 'void',
|
|
@@ -366,8 +389,8 @@ const storageSchema = {
|
|
|
366
389
|
'x-component': 'Action.Link',
|
|
367
390
|
'x-component-props': {
|
|
368
391
|
confirm: {
|
|
369
|
-
title:
|
|
370
|
-
content:
|
|
392
|
+
title: '{{t("Delete")}}',
|
|
393
|
+
content: '{{t("Are you sure you want to delete it?")}}'
|
|
371
394
|
},
|
|
372
395
|
useAction: '{{cm.useDestroyAction}}'
|
|
373
396
|
}
|
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
7
|
-
exports.
|
|
8
|
-
exports.uploadAction = uploadAction;
|
|
6
|
+
exports.createMiddleware = createMiddleware;
|
|
7
|
+
exports.destroyMiddleware = destroyMiddleware;
|
|
9
8
|
function _multer() {
|
|
10
9
|
const data = _interopRequireDefault(require("@koa/multer"));
|
|
11
10
|
_multer = function _multer() {
|
|
@@ -27,186 +26,186 @@ const _excluded = ["size"];
|
|
|
27
26
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
28
27
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
29
28
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
29
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
30
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
30
31
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
31
32
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
32
33
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
33
34
|
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
|
|
34
35
|
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
|
|
35
|
-
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
36
|
-
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
37
36
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
38
37
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
39
|
-
function getRules(ctx) {
|
|
40
|
-
const resourceField = ctx.resourceField;
|
|
41
|
-
if (!resourceField) {
|
|
42
|
-
return ctx.storage.rules;
|
|
43
|
-
}
|
|
44
|
-
const _ref = resourceField.options.attachment || {},
|
|
45
|
-
_ref$rules = _ref.rules,
|
|
46
|
-
rules = _ref$rules === void 0 ? {} : _ref$rules;
|
|
47
|
-
return Object.assign({}, ctx.storage.rules, rules);
|
|
48
|
-
}
|
|
49
38
|
// TODO(optimize): 需要优化错误处理,计算失败后需要抛出对应错误,以便程序处理
|
|
50
|
-
function getFileFilter(
|
|
39
|
+
function getFileFilter(storage) {
|
|
51
40
|
return (req, file, cb) => {
|
|
52
41
|
// size 交给 limits 处理
|
|
53
|
-
const
|
|
54
|
-
size =
|
|
55
|
-
rules = _objectWithoutProperties(
|
|
42
|
+
const _storage$rules = storage.rules,
|
|
43
|
+
size = _storage$rules.size,
|
|
44
|
+
rules = _objectWithoutProperties(_storage$rules, _excluded);
|
|
56
45
|
const ruleKeys = Object.keys(rules);
|
|
57
|
-
const result = !ruleKeys.length || !ruleKeys.some(key => typeof Rules[key] !== 'function' || !Rules[key](file, rules[key]
|
|
46
|
+
const result = !ruleKeys.length || !ruleKeys.some(key => typeof Rules[key] !== 'function' || !Rules[key](file, rules[key]));
|
|
58
47
|
cb(null, result);
|
|
59
48
|
};
|
|
60
49
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (actionName === 'upload' && resourceName === 'attachments') {
|
|
67
|
-
return true;
|
|
50
|
+
function getFileData(ctx) {
|
|
51
|
+
const file = ctx[_constants.FILE_FIELD_NAME],
|
|
52
|
+
storage = ctx.storage;
|
|
53
|
+
if (!file) {
|
|
54
|
+
return ctx.throw(400, 'file validation failed');
|
|
68
55
|
}
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return
|
|
56
|
+
const storageConfig = (0, _storages.getStorageConfig)(storage.type);
|
|
57
|
+
const name = file[storageConfig.filenameKey || 'filename'];
|
|
58
|
+
// make compatible filename across cloud service (with path)
|
|
59
|
+
const filename = _path().default.basename(name);
|
|
60
|
+
const extname = _path().default.extname(filename);
|
|
61
|
+
const urlPath = storage.path ? storage.path.replace(/^([^/])/, '/$1') : '';
|
|
62
|
+
return _objectSpread({
|
|
63
|
+
title: file.originalname.replace(extname, ''),
|
|
64
|
+
filename,
|
|
65
|
+
extname,
|
|
66
|
+
// TODO(feature): 暂时两者相同,后面 storage.path 模版化以后,这里只是 file 实际的 path
|
|
67
|
+
path: storage.path,
|
|
68
|
+
size: file.size,
|
|
69
|
+
// 直接缓存起来
|
|
70
|
+
url: `${storage.baseUrl}${urlPath}/${filename}`,
|
|
71
|
+
mimetype: file.mimetype,
|
|
72
|
+
// @ts-ignore
|
|
73
|
+
meta: ctx.request.body,
|
|
74
|
+
storageId: storage.id
|
|
75
|
+
}, storageConfig.getFileData ? storageConfig.getFileData(file) : {});
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const Storage = ctx.db.getCollection('storages');
|
|
85
|
-
let storage;
|
|
86
|
-
if (collection.options.storage) {
|
|
87
|
-
storage = yield Storage.repository.findOne({
|
|
88
|
-
filter: {
|
|
89
|
-
name: collection.options.storage
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
} else {
|
|
93
|
-
storage = yield Storage.repository.findOne({
|
|
94
|
-
filter: {
|
|
95
|
-
default: true
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
}
|
|
77
|
+
function multipart(_x, _x2) {
|
|
78
|
+
return _multipart.apply(this, arguments);
|
|
79
|
+
}
|
|
80
|
+
function _multipart() {
|
|
81
|
+
_multipart = _asyncToGenerator(function* (ctx, next) {
|
|
82
|
+
var _storage$rules$size;
|
|
83
|
+
const storage = ctx.storage;
|
|
99
84
|
if (!storage) {
|
|
100
|
-
|
|
85
|
+
ctx.logger.error('[file-manager] no linked or default storage provided');
|
|
101
86
|
return ctx.throw(500);
|
|
102
87
|
}
|
|
103
|
-
// 传递已取得的存储引擎,避免重查
|
|
104
|
-
ctx.storage = storage;
|
|
105
88
|
const storageConfig = (0, _storages.getStorageConfig)(storage.type);
|
|
106
89
|
if (!storageConfig) {
|
|
107
|
-
|
|
90
|
+
ctx.logger.error(`[file-manager] storage type "${storage.type}" is not defined`);
|
|
108
91
|
return ctx.throw(500);
|
|
109
92
|
}
|
|
110
93
|
const multerOptions = {
|
|
111
|
-
fileFilter: getFileFilter(
|
|
94
|
+
fileFilter: getFileFilter(storage),
|
|
112
95
|
limits: {
|
|
113
|
-
fileSize:
|
|
96
|
+
fileSize: (_storage$rules$size = storage.rules.size) !== null && _storage$rules$size !== void 0 ? _storage$rules$size : _constants.DEFAULT_MAX_FILE_SIZE,
|
|
114
97
|
// 每次只允许提交一个文件
|
|
115
98
|
files: _constants.LIMIT_FILES
|
|
116
99
|
},
|
|
117
100
|
storage: storageConfig.make(storage)
|
|
118
101
|
};
|
|
119
102
|
const upload = (0, _multer().default)(multerOptions).single(_constants.FILE_FIELD_NAME);
|
|
120
|
-
|
|
103
|
+
try {
|
|
104
|
+
// NOTE: empty next and invoke after success
|
|
105
|
+
yield upload(ctx, () => {});
|
|
106
|
+
} catch (err) {
|
|
107
|
+
if (err.name === 'MulterError') {
|
|
108
|
+
return ctx.throw(400, err);
|
|
109
|
+
}
|
|
110
|
+
return ctx.throw(500);
|
|
111
|
+
}
|
|
112
|
+
const values = getFileData(ctx);
|
|
113
|
+
ctx.action.mergeParams({
|
|
114
|
+
values
|
|
115
|
+
});
|
|
116
|
+
yield next();
|
|
121
117
|
});
|
|
122
|
-
return
|
|
118
|
+
return _multipart.apply(this, arguments);
|
|
123
119
|
}
|
|
124
|
-
function
|
|
125
|
-
return
|
|
120
|
+
function createMiddleware(_x3, _x4) {
|
|
121
|
+
return _createMiddleware.apply(this, arguments);
|
|
126
122
|
}
|
|
127
|
-
function
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
function _createMiddleware() {
|
|
124
|
+
_createMiddleware = _asyncToGenerator(function* (ctx, next) {
|
|
125
|
+
var _collection$options, _ctx$db$getFieldByPat, _ctx$db$getFieldByPat2;
|
|
126
|
+
const _ctx$action = ctx.action,
|
|
127
|
+
resourceName = _ctx$action.resourceName,
|
|
128
|
+
actionName = _ctx$action.actionName;
|
|
129
|
+
const attachmentField = ctx.action.params.attachmentField;
|
|
130
|
+
const collection = ctx.db.getCollection(resourceName);
|
|
131
|
+
if ((collection === null || collection === void 0 ? void 0 : (_collection$options = collection.options) === null || _collection$options === void 0 ? void 0 : _collection$options.template) !== 'file' || !['upload', 'create'].includes(actionName)) {
|
|
130
132
|
return next();
|
|
131
133
|
}
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const filename = _path().default.basename(name);
|
|
141
|
-
const extname = _path().default.extname(filename);
|
|
142
|
-
const urlPath = storage.path ? storage.path.replace(/^([^\/])/, '/$1') : '';
|
|
143
|
-
const values = _objectSpread({
|
|
144
|
-
title: file.originalname.replace(extname, ''),
|
|
145
|
-
filename,
|
|
146
|
-
extname,
|
|
147
|
-
// TODO(feature): 暂时两者相同,后面 storage.path 模版化以后,这里只是 file 实际的 path
|
|
148
|
-
path: storage.path,
|
|
149
|
-
size: file.size,
|
|
150
|
-
// 直接缓存起来
|
|
151
|
-
url: `${storage.baseUrl}${urlPath}/${filename}`,
|
|
152
|
-
mimetype: file.mimetype,
|
|
153
|
-
storageId: storage.id,
|
|
154
|
-
// @ts-ignore
|
|
155
|
-
meta: ctx.request.body
|
|
156
|
-
}, storageConfig.getFileData ? storageConfig.getFileData(file) : {});
|
|
157
|
-
ctx.action.mergeParams({
|
|
158
|
-
values
|
|
134
|
+
const storageName = ((_ctx$db$getFieldByPat = ctx.db.getFieldByPath(attachmentField)) === null || _ctx$db$getFieldByPat === void 0 ? void 0 : (_ctx$db$getFieldByPat2 = _ctx$db$getFieldByPat.options) === null || _ctx$db$getFieldByPat2 === void 0 ? void 0 : _ctx$db$getFieldByPat2.storage) || collection.options.storage;
|
|
135
|
+
const StorageRepo = ctx.db.getRepository('storages');
|
|
136
|
+
const storage = yield StorageRepo.findOne({
|
|
137
|
+
filter: storageName ? {
|
|
138
|
+
name: storageName
|
|
139
|
+
} : {
|
|
140
|
+
default: true
|
|
141
|
+
}
|
|
159
142
|
});
|
|
160
|
-
|
|
143
|
+
ctx.storage = storage;
|
|
144
|
+
yield multipart(ctx, next);
|
|
161
145
|
});
|
|
162
|
-
return
|
|
146
|
+
return _createMiddleware.apply(this, arguments);
|
|
163
147
|
}
|
|
164
|
-
function
|
|
165
|
-
return
|
|
148
|
+
function destroyMiddleware(_x5, _x6) {
|
|
149
|
+
return _destroyMiddleware.apply(this, arguments);
|
|
166
150
|
}
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
151
|
+
function _destroyMiddleware() {
|
|
152
|
+
_destroyMiddleware = _asyncToGenerator(function* (ctx, next) {
|
|
153
|
+
var _collection$options2;
|
|
154
|
+
const _ctx$action2 = ctx.action,
|
|
155
|
+
resourceName = _ctx$action2.resourceName,
|
|
156
|
+
actionName = _ctx$action2.actionName;
|
|
157
|
+
const collection = ctx.db.getCollection(resourceName);
|
|
158
|
+
if ((collection === null || collection === void 0 ? void 0 : (_collection$options2 = collection.options) === null || _collection$options2 === void 0 ? void 0 : _collection$options2.template) !== 'file' || actionName !== 'destroy') {
|
|
159
|
+
return next();
|
|
173
160
|
}
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
161
|
+
const repository = ctx.db.getRepository(resourceName);
|
|
162
|
+
const _ctx$action$params = ctx.action.params,
|
|
163
|
+
filterByTk = _ctx$action$params.filterByTk,
|
|
164
|
+
filter = _ctx$action$params.filter;
|
|
165
|
+
const records = yield repository.find({
|
|
166
|
+
filterByTk,
|
|
167
|
+
filter,
|
|
168
|
+
context: ctx
|
|
169
|
+
});
|
|
170
|
+
const storageIds = new Set(records.map(record => record.storageId));
|
|
171
|
+
const storageGroupedRecords = records.reduce((result, record) => {
|
|
172
|
+
const storageId = record.storageId;
|
|
173
|
+
if (!result[storageId]) {
|
|
174
|
+
result[storageId] = [];
|
|
175
|
+
}
|
|
176
|
+
result[storageId].push(record);
|
|
177
|
+
return result;
|
|
178
|
+
}, {});
|
|
179
|
+
const storages = yield ctx.db.getRepository('storages').find({
|
|
180
|
+
filter: {
|
|
181
|
+
id: [...storageIds],
|
|
182
|
+
paranoid: {
|
|
183
|
+
$ne: true
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
let count = 0;
|
|
188
|
+
const undeleted = [];
|
|
189
|
+
yield storages.reduce((promise, storage) => promise.then( /*#__PURE__*/_asyncToGenerator(function* () {
|
|
190
|
+
const storageConfig = (0, _storages.getStorageConfig)(storage.type);
|
|
191
|
+
const result = yield storageConfig.delete(storage, storageGroupedRecords[storage.id]);
|
|
192
|
+
count += result[0];
|
|
193
|
+
undeleted.push(...result[1]);
|
|
194
|
+
})), Promise.resolve());
|
|
195
|
+
if (undeleted.length) {
|
|
196
|
+
const ids = undeleted.map(record => record.id);
|
|
197
|
+
ctx.action.mergeParams({
|
|
198
|
+
filter: {
|
|
199
|
+
id: {
|
|
200
|
+
$notIn: ids
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
203
|
});
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
ctx.body = fileData;
|
|
204
|
+
ctx.logger.error('[file-manager] some of attachment files are not successfully deleted: ', {
|
|
205
|
+
ids
|
|
206
|
+
});
|
|
207
|
+
}
|
|
209
208
|
yield next();
|
|
210
209
|
});
|
|
211
|
-
return
|
|
210
|
+
return _destroyMiddleware.apply(this, arguments);
|
|
212
211
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = _default;
|
|
7
|
+
function _actions() {
|
|
8
|
+
const data = _interopRequireDefault(require("@nocobase/actions"));
|
|
9
|
+
_actions = function _actions() {
|
|
10
|
+
return data;
|
|
11
|
+
};
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
var _attachments = require("./attachments");
|
|
15
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
16
|
+
function _default({
|
|
17
|
+
app
|
|
18
|
+
}) {
|
|
19
|
+
app.resourcer.use(_attachments.createMiddleware);
|
|
20
|
+
app.resourcer.registerActionHandler('upload', _actions().default.create);
|
|
21
|
+
app.resourcer.use(_attachments.destroyMiddleware);
|
|
22
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const FILE_FIELD_NAME = "file";
|
|
2
2
|
export declare const LIMIT_FILES = 1;
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const DEFAULT_MAX_FILE_SIZE: number;
|
|
4
4
|
export declare const STORAGE_TYPE_LOCAL = "local";
|
|
5
5
|
export declare const STORAGE_TYPE_ALI_OSS = "ali-oss";
|
|
6
6
|
export declare const STORAGE_TYPE_S3 = "s3";
|
package/lib/server/constants.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.STORAGE_TYPE_TX_COS = exports.STORAGE_TYPE_S3 = exports.STORAGE_TYPE_LOCAL = exports.STORAGE_TYPE_ALI_OSS = exports.
|
|
6
|
+
exports.STORAGE_TYPE_TX_COS = exports.STORAGE_TYPE_S3 = exports.STORAGE_TYPE_LOCAL = exports.STORAGE_TYPE_ALI_OSS = exports.LIMIT_FILES = exports.FILE_FIELD_NAME = exports.DEFAULT_MAX_FILE_SIZE = void 0;
|
|
7
7
|
const FILE_FIELD_NAME = 'file';
|
|
8
8
|
exports.FILE_FIELD_NAME = FILE_FIELD_NAME;
|
|
9
9
|
const LIMIT_FILES = 1;
|
|
10
10
|
exports.LIMIT_FILES = LIMIT_FILES;
|
|
11
|
-
const
|
|
12
|
-
exports.
|
|
11
|
+
const DEFAULT_MAX_FILE_SIZE = 1024 * 1024 * 1024;
|
|
12
|
+
exports.DEFAULT_MAX_FILE_SIZE = DEFAULT_MAX_FILE_SIZE;
|
|
13
13
|
const STORAGE_TYPE_LOCAL = 'local';
|
|
14
14
|
exports.STORAGE_TYPE_LOCAL = STORAGE_TYPE_LOCAL;
|
|
15
15
|
const STORAGE_TYPE_ALI_OSS = 'ali-oss';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default function (file: any, options
|
|
1
|
+
export default function (file: any, options?: string | string[]): boolean;
|