@nocobase/plugin-file-manager 0.5.0-alpha.32 → 0.5.0-alpha.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["actions/upload.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AA2BlD,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,gBAkDxD;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,kBAwCpD","file":"upload.d.ts","sourcesContent":["import path from 'path';\nimport multer from '@koa/multer';\nimport { Context, Next } from '@nocobase/actions';\nimport storageMakers from '../storages';\nimport * as Rules from '../rules';\nimport { FILE_FIELD_NAME, LIMIT_FILES, LIMIT_MAX_FILE_SIZE } from '../constants';\n\nfunction getRules(ctx: Context) {\n const { resourceField } = ctx.action.params;\n if (!resourceField) {\n return ctx.storage.rules;\n }\n const { rules = {} } = resourceField.getOptions().attachment || {};\n return Object.assign({}, ctx.storage.rules, rules);\n}\n\n// TODO(optimize): 需要优化错误处理,计算失败后需要抛出对应错误,以便程序处理\nfunction getFileFilter(ctx: Context) {\n return (req, file, cb) => {\n // size 交给 limits 处理\n const { size, ...rules } = getRules(ctx);\n const ruleKeys = Object.keys(rules);\n const result = !ruleKeys.length || !ruleKeys\n .some(key => typeof Rules[key] !== 'function'\n || !Rules[key](file, rules[key], ctx));\n cb(null, result);\n }\n}\n\nexport async function middleware(ctx: Context, next: Next) {\n const { resourceName, actionName, resourceField } = ctx.action.params;\n if (actionName !== 'upload') {\n return next();\n }\n\n // NOTE:\n // 1. 存储引擎选择依赖于字段定义\n // 2. 字段定义中需包含引擎的外键值\n // 3. 无字段时按 storages 表的默认项\n // 4. 插件初始化后应提示用户添加至少一个存储引擎并设为默认\n\n const StorageModel = ctx.db.getModel('storages');\n let storage;\n\n if (resourceName === 'attachments') {\n // 如果没有包含关联,则直接按默认文件上传至默认存储引擎\n storage = await StorageModel.findOne({ where: { default: true } });\n } else {\n const fieldOptions = resourceField.getOptions();\n storage = await StorageModel.findOne({\n where: fieldOptions.defaultValue\n ? { [StorageModel.primaryKeyAttribute]: fieldOptions.defaultValue }\n : { default: true }\n });\n }\n\n if (!storage) {\n console.error('[file-manager] no default or linked storage provided');\n return ctx.throw(500);\n }\n // 传递已取得的存储引擎,避免重查\n ctx.storage = storage;\n\n const makeStorage = storageMakers.get(storage.type);\n if (!makeStorage) {\n console.error(`[file-manager] storage type \"${storage.type}\" is not defined`);\n return ctx.throw(500);\n }\n const multerOptions = {\n fileFilter: getFileFilter(ctx),\n limits: {\n fileSize: Math.min(getRules(ctx).size || LIMIT_MAX_FILE_SIZE, LIMIT_MAX_FILE_SIZE),\n // 每次只允许提交一个文件\n files: LIMIT_FILES\n },\n storage: makeStorage(storage),\n };\n const upload = multer(multerOptions);\n return upload.single(FILE_FIELD_NAME)(ctx, next);\n};\n\nexport async function action(ctx: Context, next: Next) {\n const { [FILE_FIELD_NAME]: file, storage } = ctx;\n if (!file) {\n return ctx.throw(400, 'file validation failed');\n }\n const { associatedName, associatedKey, resourceField } = ctx.action.params;\n const extname = path.extname(file.filename);\n const data = {\n title: file.originalname.replace(extname, ''),\n filename: file.filename,\n extname,\n // TODO(feature): 暂时两者相同,后面 storage.path 模版化以后,这里只是 file 实际的 path\n path: storage.path,\n size: file.size,\n // 直接缓存起来\n url: `${storage.baseUrl}${storage.path}/${file.filename}`,\n mimetype: file.mimetype,\n // @ts-ignore\n meta: ctx.request.body\n }\n\n const attachment = await ctx.db.sequelize.transaction(async transaction => {\n // TODO(optimize): 应使用关联 accessors 获取\n const result = await storage.createAttachment(data, { transaction });\n\n if (associatedKey && resourceField) {\n const Attachment = ctx.db.getModel('attachments');\n const SourceModel = ctx.db.getModel(associatedName);\n const source = await SourceModel.findByPk(associatedKey, { transaction });\n await source[resourceField.getAccessors().set](result[Attachment.primaryKeyAttribute], { transaction });\n }\n\n return result;\n });\n\n // 将存储引擎的信息附在已创建的记录里,节省一次查询\n // attachment.setDataValue('storage', storage);\n ctx.body = attachment;\n\n await next();\n};\n"]}
1
+ {"version":3,"sources":["actions/upload.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AA2BlD,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,gBAkDxD;AAED,wBAAsB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,kBAkDpD","file":"upload.d.ts","sourcesContent":["import path from 'path';\nimport multer from '@koa/multer';\nimport { Context, Next } from '@nocobase/actions';\nimport { getStorageConfig } from '../storages';\nimport * as Rules from '../rules';\nimport { FILE_FIELD_NAME, LIMIT_FILES, LIMIT_MAX_FILE_SIZE } from '../constants';\n\nfunction getRules(ctx: Context) {\n const { resourceField } = ctx.action.params;\n if (!resourceField) {\n return ctx.storage.rules;\n }\n const { rules = {} } = resourceField.getOptions().attachment || {};\n return Object.assign({}, ctx.storage.rules, rules);\n}\n\n// TODO(optimize): 需要优化错误处理,计算失败后需要抛出对应错误,以便程序处理\nfunction getFileFilter(ctx: Context) {\n return (req, file, cb) => {\n // size 交给 limits 处理\n const { size, ...rules } = getRules(ctx);\n const ruleKeys = Object.keys(rules);\n const result = !ruleKeys.length || !ruleKeys\n .some(key => typeof Rules[key] !== 'function'\n || !Rules[key](file, rules[key], ctx));\n cb(null, result);\n }\n}\n\nexport async function middleware(ctx: Context, next: Next) {\n const { resourceName, actionName, resourceField } = ctx.action.params;\n if (actionName !== 'upload') {\n return next();\n }\n\n // NOTE:\n // 1. 存储引擎选择依赖于字段定义\n // 2. 字段定义中需包含引擎的外键值\n // 3. 无字段时按 storages 表的默认项\n // 4. 插件初始化后应提示用户添加至少一个存储引擎并设为默认\n\n const StorageModel = ctx.db.getModel('storages');\n let storage;\n\n if (resourceName === 'attachments') {\n // 如果没有包含关联,则直接按默认文件上传至默认存储引擎\n storage = await StorageModel.findOne({ where: { default: true } });\n } else {\n const { attachment = {} } = resourceField.getOptions();\n storage = await StorageModel.findOne({\n where: attachment.storage\n ? { name: attachment.storage }\n : { default: true }\n });\n }\n\n if (!storage) {\n console.error('[file-manager] no default or linked storage provided');\n return ctx.throw(500);\n }\n // 传递已取得的存储引擎,避免重查\n ctx.storage = storage;\n\n const storageConfig = getStorageConfig(storage.type);\n if (!storageConfig) {\n console.error(`[file-manager] storage type \"${storage.type}\" is not defined`);\n return ctx.throw(500);\n }\n const multerOptions = {\n fileFilter: getFileFilter(ctx),\n limits: {\n fileSize: Math.min(getRules(ctx).size || LIMIT_MAX_FILE_SIZE, LIMIT_MAX_FILE_SIZE),\n // 每次只允许提交一个文件\n files: LIMIT_FILES\n },\n storage: storageConfig.make(storage),\n };\n const upload = multer(multerOptions).single(FILE_FIELD_NAME);\n return upload(ctx, next);\n};\n\nexport async function action(ctx: Context, next: Next) {\n const { [FILE_FIELD_NAME]: file, storage } = ctx;\n if (!file) {\n return ctx.throw(400, 'file validation failed');\n }\n\n const storageConfig = getStorageConfig(storage.type);\n const { [storageConfig.filenameKey || 'filename']: name } = file;\n // make compatible filename across cloud service (with path)\n const filename = path.basename(name);\n const extname = path.extname(filename);\n const urlPath = storage.path\n ? storage.path.replace(/^([^\\/])/, '/$1')\n : '';\n\n const data = {\n title: file.originalname.replace(extname, ''),\n filename,\n extname,\n // TODO(feature): 暂时两者相同,后面 storage.path 模版化以后,这里只是 file 实际的 path\n path: storage.path,\n size: file.size,\n // 直接缓存起来\n url: `${storage.baseUrl}${urlPath}/${filename}`,\n mimetype: file.mimetype,\n // @ts-ignore\n meta: ctx.request.body,\n ...(storageConfig.getFileData ? storageConfig.getFileData(file) : {})\n };\n \n const attachment = await ctx.db.sequelize.transaction(async transaction => {\n // TODO(optimize): 应使用关联 accessors 获取\n const result = await storage.createAttachment(data, { transaction });\n \n const { associatedName, associatedIndex, resourceField } = ctx.action.params;\n if (associatedIndex && resourceField) {\n const Attachment = ctx.db.getModel('attachments');\n const SourceModel = ctx.db.getModel(associatedName);\n const source = await SourceModel.findByPk(associatedIndex, { transaction });\n await source[resourceField.getAccessors().set](result[Attachment.primaryKeyAttribute], { transaction });\n }\n\n return result;\n });\n\n // 将存储引擎的信息附在已创建的记录里,节省一次查询\n // attachment.setDataValue('storage', storage);\n ctx.body = attachment;\n\n await next();\n};\n"]}
@@ -102,7 +102,7 @@ const path_1 = __importDefault(require("path"));
102
102
 
103
103
  const multer_1 = __importDefault(require("@koa/multer"));
104
104
 
105
- const storages_1 = __importDefault(require("../storages"));
105
+ const storages_1 = require("../storages");
106
106
 
107
107
  const Rules = __importStar(require("../rules"));
108
108
 
@@ -155,10 +155,13 @@ function middleware(ctx, next) {
155
155
  }
156
156
  });
157
157
  } else {
158
- const fieldOptions = resourceField.getOptions();
158
+ const _resourceField$getOpt = resourceField.getOptions(),
159
+ _resourceField$getOpt2 = _resourceField$getOpt.attachment,
160
+ attachment = _resourceField$getOpt2 === void 0 ? {} : _resourceField$getOpt2;
161
+
159
162
  storage = yield StorageModel.findOne({
160
- where: fieldOptions.defaultValue ? {
161
- [StorageModel.primaryKeyAttribute]: fieldOptions.defaultValue
163
+ where: attachment.storage ? {
164
+ name: attachment.storage
162
165
  } : {
163
166
  default: true
164
167
  }
@@ -171,9 +174,9 @@ function middleware(ctx, next) {
171
174
  }
172
175
 
173
176
  ctx.storage = storage;
174
- const makeStorage = storages_1.default.get(storage.type);
177
+ const storageConfig = (0, storages_1.getStorageConfig)(storage.type);
175
178
 
176
- if (!makeStorage) {
179
+ if (!storageConfig) {
177
180
  console.error(`[file-manager] storage type "${storage.type}" is not defined`);
178
181
  return ctx.throw(500);
179
182
  }
@@ -184,10 +187,10 @@ function middleware(ctx, next) {
184
187
  fileSize: Math.min(getRules(ctx).size || constants_1.LIMIT_MAX_FILE_SIZE, constants_1.LIMIT_MAX_FILE_SIZE),
185
188
  files: constants_1.LIMIT_FILES
186
189
  },
187
- storage: makeStorage(storage)
190
+ storage: storageConfig.make(storage)
188
191
  };
189
- const upload = multer_1.default(multerOptions);
190
- return upload.single(constants_1.FILE_FIELD_NAME)(ctx, next);
192
+ const upload = (0, multer_1.default)(multerOptions).single(constants_1.FILE_FIELD_NAME);
193
+ return upload(ctx, next);
191
194
  });
192
195
  }
193
196
 
@@ -203,30 +206,34 @@ function action(ctx, next) {
203
206
  return ctx.throw(400, 'file validation failed');
204
207
  }
205
208
 
206
- const _ctx$action$params2 = ctx.action.params,
207
- associatedName = _ctx$action$params2.associatedName,
208
- associatedKey = _ctx$action$params2.associatedKey,
209
- resourceField = _ctx$action$params2.resourceField;
210
- const extname = path_1.default.extname(file.filename);
211
- const data = {
209
+ const storageConfig = (0, storages_1.getStorageConfig)(storage.type);
210
+ const name = file[storageConfig.filenameKey || 'filename'];
211
+ const filename = path_1.default.basename(name);
212
+ const extname = path_1.default.extname(filename);
213
+ const urlPath = storage.path ? storage.path.replace(/^([^\/])/, '/$1') : '';
214
+ const data = Object.assign({
212
215
  title: file.originalname.replace(extname, ''),
213
- filename: file.filename,
216
+ filename,
214
217
  extname,
215
218
  path: storage.path,
216
219
  size: file.size,
217
- url: `${storage.baseUrl}${storage.path}/${file.filename}`,
220
+ url: `${storage.baseUrl}${urlPath}/${filename}`,
218
221
  mimetype: file.mimetype,
219
222
  meta: ctx.request.body
220
- };
223
+ }, storageConfig.getFileData ? storageConfig.getFileData(file) : {});
221
224
  const attachment = yield ctx.db.sequelize.transaction(transaction => __awaiter(this, void 0, void 0, function* () {
222
225
  const result = yield storage.createAttachment(data, {
223
226
  transaction
224
227
  });
228
+ const _ctx$action$params2 = ctx.action.params,
229
+ associatedName = _ctx$action$params2.associatedName,
230
+ associatedIndex = _ctx$action$params2.associatedIndex,
231
+ resourceField = _ctx$action$params2.resourceField;
225
232
 
226
- if (associatedKey && resourceField) {
233
+ if (associatedIndex && resourceField) {
227
234
  const Attachment = ctx.db.getModel('attachments');
228
235
  const SourceModel = ctx.db.getModel(associatedName);
229
- const source = yield SourceModel.findByPk(associatedKey, {
236
+ const source = yield SourceModel.findByPk(associatedIndex, {
230
237
  transaction
231
238
  });
232
239
  yield source[resourceField.getAccessors().set](result[Attachment.primaryKeyAttribute], {
@@ -1 +1 @@
1
- {"version":3,"sources":["actions/upload.ts"],"names":[],"mappings":"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","file":"upload.js","sourcesContent":["import path from 'path';\nimport multer from '@koa/multer';\nimport { Context, Next } from '@nocobase/actions';\nimport storageMakers from '../storages';\nimport * as Rules from '../rules';\nimport { FILE_FIELD_NAME, LIMIT_FILES, LIMIT_MAX_FILE_SIZE } from '../constants';\n\nfunction getRules(ctx: Context) {\n const { resourceField } = ctx.action.params;\n if (!resourceField) {\n return ctx.storage.rules;\n }\n const { rules = {} } = resourceField.getOptions().attachment || {};\n return Object.assign({}, ctx.storage.rules, rules);\n}\n\n// TODO(optimize): 需要优化错误处理,计算失败后需要抛出对应错误,以便程序处理\nfunction getFileFilter(ctx: Context) {\n return (req, file, cb) => {\n // size 交给 limits 处理\n const { size, ...rules } = getRules(ctx);\n const ruleKeys = Object.keys(rules);\n const result = !ruleKeys.length || !ruleKeys\n .some(key => typeof Rules[key] !== 'function'\n || !Rules[key](file, rules[key], ctx));\n cb(null, result);\n }\n}\n\nexport async function middleware(ctx: Context, next: Next) {\n const { resourceName, actionName, resourceField } = ctx.action.params;\n if (actionName !== 'upload') {\n return next();\n }\n\n // NOTE:\n // 1. 存储引擎选择依赖于字段定义\n // 2. 字段定义中需包含引擎的外键值\n // 3. 无字段时按 storages 表的默认项\n // 4. 插件初始化后应提示用户添加至少一个存储引擎并设为默认\n\n const StorageModel = ctx.db.getModel('storages');\n let storage;\n\n if (resourceName === 'attachments') {\n // 如果没有包含关联,则直接按默认文件上传至默认存储引擎\n storage = await StorageModel.findOne({ where: { default: true } });\n } else {\n const fieldOptions = resourceField.getOptions();\n storage = await StorageModel.findOne({\n where: fieldOptions.defaultValue\n ? { [StorageModel.primaryKeyAttribute]: fieldOptions.defaultValue }\n : { default: true }\n });\n }\n\n if (!storage) {\n console.error('[file-manager] no default or linked storage provided');\n return ctx.throw(500);\n }\n // 传递已取得的存储引擎,避免重查\n ctx.storage = storage;\n\n const makeStorage = storageMakers.get(storage.type);\n if (!makeStorage) {\n console.error(`[file-manager] storage type \"${storage.type}\" is not defined`);\n return ctx.throw(500);\n }\n const multerOptions = {\n fileFilter: getFileFilter(ctx),\n limits: {\n fileSize: Math.min(getRules(ctx).size || LIMIT_MAX_FILE_SIZE, LIMIT_MAX_FILE_SIZE),\n // 每次只允许提交一个文件\n files: LIMIT_FILES\n },\n storage: makeStorage(storage),\n };\n const upload = multer(multerOptions);\n return upload.single(FILE_FIELD_NAME)(ctx, next);\n};\n\nexport async function action(ctx: Context, next: Next) {\n const { [FILE_FIELD_NAME]: file, storage } = ctx;\n if (!file) {\n return ctx.throw(400, 'file validation failed');\n }\n const { associatedName, associatedKey, resourceField } = ctx.action.params;\n const extname = path.extname(file.filename);\n const data = {\n title: file.originalname.replace(extname, ''),\n filename: file.filename,\n extname,\n // TODO(feature): 暂时两者相同,后面 storage.path 模版化以后,这里只是 file 实际的 path\n path: storage.path,\n size: file.size,\n // 直接缓存起来\n url: `${storage.baseUrl}${storage.path}/${file.filename}`,\n mimetype: file.mimetype,\n // @ts-ignore\n meta: ctx.request.body\n }\n\n const attachment = await ctx.db.sequelize.transaction(async transaction => {\n // TODO(optimize): 应使用关联 accessors 获取\n const result = await storage.createAttachment(data, { transaction });\n\n if (associatedKey && resourceField) {\n const Attachment = ctx.db.getModel('attachments');\n const SourceModel = ctx.db.getModel(associatedName);\n const source = await SourceModel.findByPk(associatedKey, { transaction });\n await source[resourceField.getAccessors().set](result[Attachment.primaryKeyAttribute], { transaction });\n }\n\n return result;\n });\n\n // 将存储引擎的信息附在已创建的记录里,节省一次查询\n // attachment.setDataValue('storage', storage);\n ctx.body = attachment;\n\n await next();\n};\n"]}
1
+ {"version":3,"sources":["actions/upload.ts"],"names":[],"mappings":"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","file":"upload.js","sourcesContent":["import path from 'path';\nimport multer from '@koa/multer';\nimport { Context, Next } from '@nocobase/actions';\nimport { getStorageConfig } from '../storages';\nimport * as Rules from '../rules';\nimport { FILE_FIELD_NAME, LIMIT_FILES, LIMIT_MAX_FILE_SIZE } from '../constants';\n\nfunction getRules(ctx: Context) {\n const { resourceField } = ctx.action.params;\n if (!resourceField) {\n return ctx.storage.rules;\n }\n const { rules = {} } = resourceField.getOptions().attachment || {};\n return Object.assign({}, ctx.storage.rules, rules);\n}\n\n// TODO(optimize): 需要优化错误处理,计算失败后需要抛出对应错误,以便程序处理\nfunction getFileFilter(ctx: Context) {\n return (req, file, cb) => {\n // size 交给 limits 处理\n const { size, ...rules } = getRules(ctx);\n const ruleKeys = Object.keys(rules);\n const result = !ruleKeys.length || !ruleKeys\n .some(key => typeof Rules[key] !== 'function'\n || !Rules[key](file, rules[key], ctx));\n cb(null, result);\n }\n}\n\nexport async function middleware(ctx: Context, next: Next) {\n const { resourceName, actionName, resourceField } = ctx.action.params;\n if (actionName !== 'upload') {\n return next();\n }\n\n // NOTE:\n // 1. 存储引擎选择依赖于字段定义\n // 2. 字段定义中需包含引擎的外键值\n // 3. 无字段时按 storages 表的默认项\n // 4. 插件初始化后应提示用户添加至少一个存储引擎并设为默认\n\n const StorageModel = ctx.db.getModel('storages');\n let storage;\n\n if (resourceName === 'attachments') {\n // 如果没有包含关联,则直接按默认文件上传至默认存储引擎\n storage = await StorageModel.findOne({ where: { default: true } });\n } else {\n const { attachment = {} } = resourceField.getOptions();\n storage = await StorageModel.findOne({\n where: attachment.storage\n ? { name: attachment.storage }\n : { default: true }\n });\n }\n\n if (!storage) {\n console.error('[file-manager] no default or linked storage provided');\n return ctx.throw(500);\n }\n // 传递已取得的存储引擎,避免重查\n ctx.storage = storage;\n\n const storageConfig = getStorageConfig(storage.type);\n if (!storageConfig) {\n console.error(`[file-manager] storage type \"${storage.type}\" is not defined`);\n return ctx.throw(500);\n }\n const multerOptions = {\n fileFilter: getFileFilter(ctx),\n limits: {\n fileSize: Math.min(getRules(ctx).size || LIMIT_MAX_FILE_SIZE, LIMIT_MAX_FILE_SIZE),\n // 每次只允许提交一个文件\n files: LIMIT_FILES\n },\n storage: storageConfig.make(storage),\n };\n const upload = multer(multerOptions).single(FILE_FIELD_NAME);\n return upload(ctx, next);\n};\n\nexport async function action(ctx: Context, next: Next) {\n const { [FILE_FIELD_NAME]: file, storage } = ctx;\n if (!file) {\n return ctx.throw(400, 'file validation failed');\n }\n\n const storageConfig = getStorageConfig(storage.type);\n const { [storageConfig.filenameKey || 'filename']: name } = file;\n // make compatible filename across cloud service (with path)\n const filename = path.basename(name);\n const extname = path.extname(filename);\n const urlPath = storage.path\n ? storage.path.replace(/^([^\\/])/, '/$1')\n : '';\n\n const data = {\n title: file.originalname.replace(extname, ''),\n filename,\n extname,\n // TODO(feature): 暂时两者相同,后面 storage.path 模版化以后,这里只是 file 实际的 path\n path: storage.path,\n size: file.size,\n // 直接缓存起来\n url: `${storage.baseUrl}${urlPath}/${filename}`,\n mimetype: file.mimetype,\n // @ts-ignore\n meta: ctx.request.body,\n ...(storageConfig.getFileData ? storageConfig.getFileData(file) : {})\n };\n \n const attachment = await ctx.db.sequelize.transaction(async transaction => {\n // TODO(optimize): 应使用关联 accessors 获取\n const result = await storage.createAttachment(data, { transaction });\n \n const { associatedName, associatedIndex, resourceField } = ctx.action.params;\n if (associatedIndex && resourceField) {\n const Attachment = ctx.db.getModel('attachments');\n const SourceModel = ctx.db.getModel(associatedName);\n const source = await SourceModel.findByPk(associatedIndex, { transaction });\n await source[resourceField.getAccessors().set](result[Attachment.primaryKeyAttribute], { transaction });\n }\n\n return result;\n });\n\n // 将存储引擎的信息附在已创建的记录里,节省一次查询\n // attachment.setDataValue('storage', storage);\n ctx.body = attachment;\n\n await next();\n};\n"]}
@@ -3,3 +3,4 @@ export declare const LIMIT_FILES = 1;
3
3
  export declare const LIMIT_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
+ export declare const STORAGE_TYPE_S3 = "s3";
@@ -1 +1 @@
1
- {"version":3,"sources":["constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,mBAAmB,QAAqB,CAAC;AAEtD,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAC1C,eAAO,MAAM,oBAAoB,YAAY,CAAC","file":"constants.d.ts","sourcesContent":["export const FILE_FIELD_NAME = 'file';\nexport const LIMIT_FILES = 1;\nexport const LIMIT_MAX_FILE_SIZE = 1024 * 1024 * 1024;\n\nexport const STORAGE_TYPE_LOCAL = 'local';\nexport const STORAGE_TYPE_ALI_OSS = 'ali-oss';\n"]}
1
+ {"version":3,"sources":["constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,SAAS,CAAC;AACtC,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,mBAAmB,QAAqB,CAAC;AAEtD,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAC1C,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAC9C,eAAO,MAAM,eAAe,OAAO,CAAC","file":"constants.d.ts","sourcesContent":["export const FILE_FIELD_NAME = 'file';\nexport const LIMIT_FILES = 1;\nexport const LIMIT_MAX_FILE_SIZE = 1024 * 1024 * 1024;\n\nexport const STORAGE_TYPE_LOCAL = 'local';\nexport const STORAGE_TYPE_ALI_OSS = 'ali-oss';\nexport const STORAGE_TYPE_S3 = 's3';\n"]}
package/lib/constants.js CHANGED
@@ -15,10 +15,11 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
15
15
  Object.defineProperty(exports, "__esModule", {
16
16
  value: true
17
17
  });
18
- exports.STORAGE_TYPE_ALI_OSS = exports.STORAGE_TYPE_LOCAL = exports.LIMIT_MAX_FILE_SIZE = exports.LIMIT_FILES = exports.FILE_FIELD_NAME = void 0;
18
+ exports.STORAGE_TYPE_S3 = exports.STORAGE_TYPE_ALI_OSS = exports.STORAGE_TYPE_LOCAL = exports.LIMIT_MAX_FILE_SIZE = exports.LIMIT_FILES = exports.FILE_FIELD_NAME = void 0;
19
19
  exports.FILE_FIELD_NAME = 'file';
20
20
  exports.LIMIT_FILES = 1;
21
21
  exports.LIMIT_MAX_FILE_SIZE = 1024 * 1024 * 1024;
22
22
  exports.STORAGE_TYPE_LOCAL = 'local';
23
23
  exports.STORAGE_TYPE_ALI_OSS = 'ali-oss';
24
+ exports.STORAGE_TYPE_S3 = 's3';
24
25
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAAG,MAAM,CAAC;AACzB,QAAA,WAAW,GAAG,CAAC,CAAC;AAChB,QAAA,mBAAmB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,QAAA,kBAAkB,GAAG,OAAO,CAAC;AAC7B,QAAA,oBAAoB,GAAG,SAAS,CAAC","file":"constants.js","sourcesContent":["export const FILE_FIELD_NAME = 'file';\nexport const LIMIT_FILES = 1;\nexport const LIMIT_MAX_FILE_SIZE = 1024 * 1024 * 1024;\n\nexport const STORAGE_TYPE_LOCAL = 'local';\nexport const STORAGE_TYPE_ALI_OSS = 'ali-oss';\n"]}
1
+ {"version":3,"sources":["constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAAG,MAAM,CAAC;AACzB,QAAA,WAAW,GAAG,CAAC,CAAC;AAChB,QAAA,mBAAmB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,QAAA,kBAAkB,GAAG,OAAO,CAAC;AAC7B,QAAA,oBAAoB,GAAG,SAAS,CAAC;AACjC,QAAA,eAAe,GAAG,IAAI,CAAC","file":"constants.js","sourcesContent":["export const FILE_FIELD_NAME = 'file';\nexport const LIMIT_FILES = 1;\nexport const LIMIT_MAX_FILE_SIZE = 1024 * 1024 * 1024;\n\nexport const STORAGE_TYPE_LOCAL = 'local';\nexport const STORAGE_TYPE_ALI_OSS = 'ali-oss';\nexport const STORAGE_TYPE_S3 = 's3';\n"]}
package/lib/index.d.ts CHANGED
@@ -1 +1,2 @@
1
-
1
+ export * from './constants';
2
+ export { default } from './server';
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"names":[],"mappings":"","file":"index.d.ts","sourcesContent":[""]}
1
+ {"version":3,"sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC","file":"index.d.ts","sourcesContent":["export * from './constants';\nexport { default } from './server';\n"]}
package/lib/index.js CHANGED
@@ -11,4 +11,43 @@ function _react() {
11
11
  }
12
12
 
13
13
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
+
15
+ var __createBinding = void 0 && (void 0).__createBinding || (Object.create ? function (o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ Object.defineProperty(o, k2, {
18
+ enumerable: true,
19
+ get: function get() {
20
+ return m[k];
21
+ }
22
+ });
23
+ } : function (o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ });
27
+
28
+ var __exportStar = void 0 && (void 0).__exportStar || function (m, exports) {
29
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
30
+ };
31
+
32
+ var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
33
+ return mod && mod.__esModule ? mod : {
34
+ "default": mod
35
+ };
36
+ };
37
+
38
+ Object.defineProperty(exports, "__esModule", {
39
+ value: true
40
+ });
41
+ exports.default = void 0;
42
+
43
+ __exportStar(require("./constants"), exports);
44
+
45
+ var server_1 = require("./server");
46
+
47
+ Object.defineProperty(exports, "default", {
48
+ enumerable: true,
49
+ get: function get() {
50
+ return __importDefault(server_1).default;
51
+ }
52
+ });
14
53
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["index.ts"],"names":[],"mappings":"","file":"index.js","sourcesContent":[""]}
1
+ {"version":3,"sources":["index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,mCAAmC;AAA1B,kHAAA,OAAO,OAAA","file":"index.js","sourcesContent":["export * from './constants';\nexport { default } from './server';\n"]}
@@ -25,7 +25,7 @@ Object.defineProperty(exports, "__esModule", {
25
25
  const mime_match_1 = __importDefault(require("mime-match"));
26
26
 
27
27
  function default_1(file, options = '*', ctx) {
28
- return options.toString().split(',').some(mime_match_1.default(file.mimetype));
28
+ return options.toString().split(',').some((0, mime_match_1.default)(file.mimetype));
29
29
  }
30
30
 
31
31
  exports.default = default_1;
@@ -1 +1 @@
1
- {"version":3,"sources":["rules/mimetype.ts"],"names":[],"mappings":";;;;;AAAA,4DAA+B;AAE/B,mBAAyB,IAAI,EAAE,UAA6B,GAAG,EAAE,GAAG;IAClE,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,oBAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClE,CAAC;AAFD,4BAEC","file":"mimetype.js","sourcesContent":["import match from 'mime-match';\n\nexport default function (file, options: string | string[] = '*', ctx): boolean {\n return options.toString().split(',').some(match(file.mimetype));\n}\n"]}
1
+ {"version":3,"sources":["rules/mimetype.ts"],"names":[],"mappings":";;;;;AAAA,4DAA+B;AAE/B,mBAAyB,IAAI,EAAE,UAA6B,GAAG,EAAE,GAAG;IAClE,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAA,oBAAK,EAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClE,CAAC;AAFD,4BAEC","file":"mimetype.js","sourcesContent":["import match from 'mime-match';\n\nexport default function (file, options: string | string[] = '*', ctx): boolean {\n return options.toString().split(',').some(match(file.mimetype));\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAU,MAAM,kBAAkB,CAAC;;AAUzD,wBAuCmB","file":"server.d.ts","sourcesContent":["import path from 'path';\nimport Database from '@nocobase/database';\nimport Resourcer from '@nocobase/resourcer';\nimport { PluginOptions, Plugin } from '@nocobase/server';\n\nimport {\n action as uploadAction,\n middleware as uploadMiddleware,\n} from './actions/upload';\nimport {\n middleware as localMiddleware,\n} from './storages/local';\n\nexport default {\n name: 'file-manager',\n async load() {\n const database: Database = this.app.db;\n const resourcer: Resourcer = this.app.resourcer;\n \n database.import({\n directory: path.resolve(__dirname, 'collections'),\n });\n \n // 暂时中间件只能通过 use 加进来\n resourcer.use(uploadMiddleware);\n resourcer.registerActionHandler('upload', uploadAction);\n localMiddleware(this.app);\n \n const Storage = database.getModel('storages');\n \n this.app.on('db.init', async () => {\n await Storage.create({\n title: '本地存储',\n name: `local`,\n type: 'local',\n baseUrl: process.env.LOCAL_STORAGE_BASE_URL,\n default: process.env.STORAGE_TYPE === 'local',\n });\n await Storage.create({\n name: `ali-oss`,\n type: 'ali-oss',\n baseUrl: process.env.ALI_OSS_STORAGE_BASE_URL,\n options: {\n region: process.env.ALI_OSS_REGION,\n accessKeyId: process.env.ALI_OSS_ACCESS_KEY_ID,\n accessKeySecret: process.env.ALI_OSS_ACCESS_KEY_SECRET,\n bucket: process.env.ALI_OSS_BUCKET,\n },\n default: process.env.STORAGE_TYPE === 'ali-oss',\n });\n });\n },\n} as PluginOptions;\n"]}
1
+ {"version":3,"sources":["server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;;AASjD,wBAkCmB","file":"server.d.ts","sourcesContent":["import path from 'path';\nimport Database from '@nocobase/database';\nimport Resourcer from '@nocobase/resourcer';\nimport { PluginOptions } from '@nocobase/server';\n\nimport {\n action as uploadAction,\n middleware as uploadMiddleware,\n} from './actions/upload';\nimport { getStorageConfig } from './storages';\nimport { STORAGE_TYPE_LOCAL } from './constants';\n\nexport default {\n name: 'file-manager',\n async load() {\n const database: Database = this.app.db;\n const resourcer: Resourcer = this.app.resourcer;\n \n database.import({\n directory: path.resolve(__dirname, 'collections'),\n });\n \n // 暂时中间件只能通过 use 加进来\n resourcer.use(uploadMiddleware);\n resourcer.registerActionHandler('upload', uploadAction);\n\n const { DEFAULT_STORAGE_TYPE } = process.env;\n\n if (process.env.NOCOBASE_ENV !== 'production') {\n this.app.on('beforeStart', async () => {\n await getStorageConfig(STORAGE_TYPE_LOCAL).middleware(this.app);\n });\n }\n\n this.app.on('db.init', async () => {\n const defaultStorageConfig = getStorageConfig(DEFAULT_STORAGE_TYPE);\n if (defaultStorageConfig) {\n const StorageModel = database.getModel('storages');\n await StorageModel.create({\n ...defaultStorageConfig.defaults(),\n type: DEFAULT_STORAGE_TYPE,\n default: true\n });\n }\n });\n },\n} as PluginOptions;\n"]}
package/lib/server.js CHANGED
@@ -58,7 +58,9 @@ const path_1 = __importDefault(require("path"));
58
58
 
59
59
  const upload_1 = require("./actions/upload");
60
60
 
61
- const local_1 = require("./storages/local");
61
+ const storages_1 = require("./storages");
62
+
63
+ const constants_1 = require("./constants");
62
64
 
63
65
  exports.default = {
64
66
  name: 'file-manager',
@@ -72,28 +74,24 @@ exports.default = {
72
74
  });
73
75
  resourcer.use(upload_1.middleware);
74
76
  resourcer.registerActionHandler('upload', upload_1.action);
75
- local_1.middleware(this.app);
76
- const Storage = database.getModel('storages');
77
+ const DEFAULT_STORAGE_TYPE = process.env.DEFAULT_STORAGE_TYPE;
78
+
79
+ if (process.env.NOCOBASE_ENV !== 'production') {
80
+ this.app.on('beforeStart', () => __awaiter(this, void 0, void 0, function* () {
81
+ yield (0, storages_1.getStorageConfig)(constants_1.STORAGE_TYPE_LOCAL).middleware(this.app);
82
+ }));
83
+ }
84
+
77
85
  this.app.on('db.init', () => __awaiter(this, void 0, void 0, function* () {
78
- yield Storage.create({
79
- title: '本地存储',
80
- name: `local`,
81
- type: 'local',
82
- baseUrl: process.env.LOCAL_STORAGE_BASE_URL,
83
- default: process.env.STORAGE_TYPE === 'local'
84
- });
85
- yield Storage.create({
86
- name: `ali-oss`,
87
- type: 'ali-oss',
88
- baseUrl: process.env.ALI_OSS_STORAGE_BASE_URL,
89
- options: {
90
- region: process.env.ALI_OSS_REGION,
91
- accessKeyId: process.env.ALI_OSS_ACCESS_KEY_ID,
92
- accessKeySecret: process.env.ALI_OSS_ACCESS_KEY_SECRET,
93
- bucket: process.env.ALI_OSS_BUCKET
94
- },
95
- default: process.env.STORAGE_TYPE === 'ali-oss'
96
- });
86
+ const defaultStorageConfig = (0, storages_1.getStorageConfig)(DEFAULT_STORAGE_TYPE);
87
+
88
+ if (defaultStorageConfig) {
89
+ const StorageModel = database.getModel('storages');
90
+ yield StorageModel.create(Object.assign(Object.assign({}, defaultStorageConfig.defaults()), {
91
+ type: DEFAULT_STORAGE_TYPE,
92
+ default: true
93
+ }));
94
+ }
97
95
  }));
98
96
  });
99
97
  }
package/lib/server.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,gDAAwB;AAKxB,6CAG0B;AAC1B,4CAE0B;AAE1B,kBAAe;IACb,IAAI,EAAE,cAAc;IACd,IAAI;;YACR,MAAM,QAAQ,GAAa,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,MAAM,SAAS,GAAc,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;YAEhD,QAAQ,CAAC,MAAM,CAAC;gBACd,SAAS,EAAE,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC;aAClD,CAAC,CAAC;YAGH,SAAS,CAAC,GAAG,CAAC,mBAAgB,CAAC,CAAC;YAChC,SAAS,CAAC,qBAAqB,CAAC,QAAQ,EAAE,eAAY,CAAC,CAAC;YACxD,kBAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE1B,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;YAE9C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAS,EAAE;gBAChC,MAAM,OAAO,CAAC,MAAM,CAAC;oBACnB,KAAK,EAAE,MAAM;oBACb,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,OAAO;oBACb,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;oBAC3C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,OAAO;iBAC9C,CAAC,CAAC;gBACH,MAAM,OAAO,CAAC,MAAM,CAAC;oBACnB,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB;oBAC7C,OAAO,EAAE;wBACP,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;wBAClC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB;wBAC9C,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB;wBACtD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;qBACnC;oBACD,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,SAAS;iBAChD,CAAC,CAAC;YACL,CAAC,CAAA,CAAC,CAAC;QACL,CAAC;KAAA;CACe,CAAC","file":"server.js","sourcesContent":["import path from 'path';\nimport Database from '@nocobase/database';\nimport Resourcer from '@nocobase/resourcer';\nimport { PluginOptions, Plugin } from '@nocobase/server';\n\nimport {\n action as uploadAction,\n middleware as uploadMiddleware,\n} from './actions/upload';\nimport {\n middleware as localMiddleware,\n} from './storages/local';\n\nexport default {\n name: 'file-manager',\n async load() {\n const database: Database = this.app.db;\n const resourcer: Resourcer = this.app.resourcer;\n \n database.import({\n directory: path.resolve(__dirname, 'collections'),\n });\n \n // 暂时中间件只能通过 use 加进来\n resourcer.use(uploadMiddleware);\n resourcer.registerActionHandler('upload', uploadAction);\n localMiddleware(this.app);\n \n const Storage = database.getModel('storages');\n \n this.app.on('db.init', async () => {\n await Storage.create({\n title: '本地存储',\n name: `local`,\n type: 'local',\n baseUrl: process.env.LOCAL_STORAGE_BASE_URL,\n default: process.env.STORAGE_TYPE === 'local',\n });\n await Storage.create({\n name: `ali-oss`,\n type: 'ali-oss',\n baseUrl: process.env.ALI_OSS_STORAGE_BASE_URL,\n options: {\n region: process.env.ALI_OSS_REGION,\n accessKeyId: process.env.ALI_OSS_ACCESS_KEY_ID,\n accessKeySecret: process.env.ALI_OSS_ACCESS_KEY_SECRET,\n bucket: process.env.ALI_OSS_BUCKET,\n },\n default: process.env.STORAGE_TYPE === 'ali-oss',\n });\n });\n },\n} as PluginOptions;\n"]}
1
+ {"version":3,"sources":["server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,gDAAwB;AAKxB,6CAG0B;AAC1B,yCAA8C;AAC9C,2CAAiD;AAEjD,kBAAe;IACb,IAAI,EAAE,cAAc;IACd,IAAI;;YACR,MAAM,QAAQ,GAAa,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,MAAM,SAAS,GAAc,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;YAEhD,QAAQ,CAAC,MAAM,CAAC;gBACd,SAAS,EAAE,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC;aAClD,CAAC,CAAC;YAGH,SAAS,CAAC,GAAG,CAAC,mBAAgB,CAAC,CAAC;YAChC,SAAS,CAAC,qBAAqB,CAAC,QAAQ,EAAE,eAAY,CAAC,CAAC;YAExD,MAAM,EAAE,oBAAoB,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;YAE7C,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,YAAY,EAAE;gBAC7C,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,aAAa,EAAE,GAAS,EAAE;oBACpC,MAAM,IAAA,2BAAgB,EAAC,8BAAkB,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAClE,CAAC,CAAA,CAAC,CAAC;aACJ;YAED,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAS,EAAE;gBAChC,MAAM,oBAAoB,GAAG,IAAA,2BAAgB,EAAC,oBAAoB,CAAC,CAAC;gBACpE,IAAI,oBAAoB,EAAE;oBACxB,MAAM,YAAY,GAAG,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;oBACnD,MAAM,YAAY,CAAC,MAAM,iCACpB,oBAAoB,CAAC,QAAQ,EAAE,KAClC,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,IAAI,IACb,CAAC;iBACJ;YACH,CAAC,CAAA,CAAC,CAAC;QACL,CAAC;KAAA;CACe,CAAC","file":"server.js","sourcesContent":["import path from 'path';\nimport Database from '@nocobase/database';\nimport Resourcer from '@nocobase/resourcer';\nimport { PluginOptions } from '@nocobase/server';\n\nimport {\n action as uploadAction,\n middleware as uploadMiddleware,\n} from './actions/upload';\nimport { getStorageConfig } from './storages';\nimport { STORAGE_TYPE_LOCAL } from './constants';\n\nexport default {\n name: 'file-manager',\n async load() {\n const database: Database = this.app.db;\n const resourcer: Resourcer = this.app.resourcer;\n \n database.import({\n directory: path.resolve(__dirname, 'collections'),\n });\n \n // 暂时中间件只能通过 use 加进来\n resourcer.use(uploadMiddleware);\n resourcer.registerActionHandler('upload', uploadAction);\n\n const { DEFAULT_STORAGE_TYPE } = process.env;\n\n if (process.env.NOCOBASE_ENV !== 'production') {\n this.app.on('beforeStart', async () => {\n await getStorageConfig(STORAGE_TYPE_LOCAL).middleware(this.app);\n });\n }\n\n this.app.on('db.init', async () => {\n const defaultStorageConfig = getStorageConfig(DEFAULT_STORAGE_TYPE);\n if (defaultStorageConfig) {\n const StorageModel = database.getModel('storages');\n await StorageModel.create({\n ...defaultStorageConfig.defaults(),\n type: DEFAULT_STORAGE_TYPE,\n default: true\n });\n }\n });\n },\n} as PluginOptions;\n"]}
@@ -1,9 +1,16 @@
1
- export declare class AliOssStorage {
2
- private client;
3
- private getFilename;
4
- constructor(opts: any);
5
- _handleFile(req: any, file: any, cb: any): any;
6
- _removeFile(req: any, file: any, cb: any): any;
7
- }
8
- declare const _default: (storage: any) => AliOssStorage;
1
+ declare const _default: {
2
+ make(storage: any): any;
3
+ defaults(): {
4
+ title: string;
5
+ type: string;
6
+ name: string;
7
+ baseUrl: string;
8
+ options: {
9
+ region: string;
10
+ accessKeyId: string;
11
+ accessKeySecret: string;
12
+ bucket: string;
13
+ };
14
+ };
15
+ };
9
16
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"sources":["storages/ali-oss.ts"],"names":[],"mappings":"AAGA,qBAAa,aAAa;IAExB,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,WAAW,CAAW;gBAElB,IAAI,KAAA;IAKhB,WAAW,CAAC,GAAG,KAAA,EAAE,IAAI,KAAA,EAAE,EAAE,KAAA;IAgBzB,WAAW,CAAC,GAAG,KAAA,EAAE,IAAI,KAAA,EAAE,EAAE,KAAA;CAS1B;;AAED,wBAA2E","file":"ali-oss.d.ts","sourcesContent":["import AliOss from 'ali-oss';\nimport { getFilename } from '../utils';\n\nexport class AliOssStorage {\n\n private client: AliOss;\n\n private getFilename: Function;\n\n constructor(opts) {\n this.client = new AliOss(opts.config);\n this.getFilename = opts.filename || getFilename;\n }\n\n _handleFile(req, file, cb) {\n if (!this.client) {\n console.error('oss client undefined');\n return cb({ message: 'oss client undefined' });\n }\n this.getFilename(req, file, (err, filename) => {\n if (err) return cb(err)\n this.client.putStream(filename, file.stream).then(\n result => cb(null, {\n filename: result.name,\n url: result.url\n })\n ).catch(cb);\n });\n }\n\n _removeFile(req, file, cb) {\n if (!this.client) {\n console.error('oss client undefined');\n return cb({ message: 'oss client undefined' });\n }\n this.client.delete(file.filename).then(\n result => cb(null, result)\n ).catch(cb);\n }\n}\n\nexport default (storage) => new AliOssStorage({ config: storage.options });\n"]}
1
+ {"version":3,"sources":["storages/ali-oss.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAGA,wBAsBC","file":"ali-oss.d.ts","sourcesContent":["import { STORAGE_TYPE_ALI_OSS } from '../constants';\nimport { cloudFilenameGetter } from '../utils';\n\nexport default {\n make(storage) {\n const createAliOssStorage = require('multer-aliyun-oss');\n return new createAliOssStorage({\n config: storage.options,\n filename: cloudFilenameGetter(storage)\n });\n },\n defaults() {\n return {\n title: '阿里云对象存储',\n type: STORAGE_TYPE_ALI_OSS,\n name: 'ali-oss-1',\n baseUrl: process.env.ALI_OSS_STORAGE_BASE_URL,\n options: {\n region: process.env.ALI_OSS_REGION,\n accessKeyId: process.env.ALI_OSS_ACCESS_KEY_ID,\n accessKeySecret: process.env.ALI_OSS_ACCESS_KEY_SECRET,\n bucket: process.env.ALI_OSS_BUCKET,\n }\n }\n }\n}\n"]}
@@ -12,60 +12,38 @@ function _react() {
12
12
 
13
13
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
14
 
15
- var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
16
- return mod && mod.__esModule ? mod : {
17
- "default": mod
18
- };
19
- };
20
-
21
15
  Object.defineProperty(exports, "__esModule", {
22
16
  value: true
23
17
  });
24
- exports.AliOssStorage = void 0;
25
18
 
26
- const ali_oss_1 = __importDefault(require("ali-oss"));
19
+ const constants_1 = require("../constants");
27
20
 
28
21
  const utils_1 = require("../utils");
29
22
 
30
- class AliOssStorage {
31
- constructor(opts) {
32
- this.client = new ali_oss_1.default(opts.config);
33
- this.getFilename = opts.filename || utils_1.getFilename;
34
- }
23
+ exports.default = {
24
+ make(storage) {
25
+ const createAliOssStorage = require('multer-aliyun-oss');
35
26
 
36
- _handleFile(req, file, cb) {
37
- if (!this.client) {
38
- console.error('oss client undefined');
39
- return cb({
40
- message: 'oss client undefined'
41
- });
42
- }
43
-
44
- this.getFilename(req, file, (err, filename) => {
45
- if (err) return cb(err);
46
- this.client.putStream(filename, file.stream).then(result => cb(null, {
47
- filename: result.name,
48
- url: result.url
49
- })).catch(cb);
27
+ return new createAliOssStorage({
28
+ config: storage.options,
29
+ filename: (0, utils_1.cloudFilenameGetter)(storage)
50
30
  });
31
+ },
32
+
33
+ defaults() {
34
+ return {
35
+ title: '阿里云对象存储',
36
+ type: constants_1.STORAGE_TYPE_ALI_OSS,
37
+ name: 'ali-oss-1',
38
+ baseUrl: process.env.ALI_OSS_STORAGE_BASE_URL,
39
+ options: {
40
+ region: process.env.ALI_OSS_REGION,
41
+ accessKeyId: process.env.ALI_OSS_ACCESS_KEY_ID,
42
+ accessKeySecret: process.env.ALI_OSS_ACCESS_KEY_SECRET,
43
+ bucket: process.env.ALI_OSS_BUCKET
44
+ }
45
+ };
51
46
  }
52
47
 
53
- _removeFile(req, file, cb) {
54
- if (!this.client) {
55
- console.error('oss client undefined');
56
- return cb({
57
- message: 'oss client undefined'
58
- });
59
- }
60
-
61
- this.client.delete(file.filename).then(result => cb(null, result)).catch(cb);
62
- }
63
-
64
- }
65
-
66
- exports.AliOssStorage = AliOssStorage;
67
-
68
- exports.default = storage => new AliOssStorage({
69
- config: storage.options
70
- });
48
+ };
71
49
  //# sourceMappingURL=ali-oss.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["storages/ali-oss.ts"],"names":[],"mappings":";;;;;;AAAA,sDAA6B;AAC7B,oCAAuC;AAEvC,MAAa,aAAa;IAMxB,YAAY,IAAI;QACd,IAAI,CAAC,MAAM,GAAG,IAAI,iBAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,IAAI,mBAAW,CAAC;IAClD,CAAC;IAED,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAChB,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;YACtC,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;SAChD;QACD,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;YAC5C,IAAI,GAAG;gBAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAAA;YACvB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAC/C,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE;gBACjB,QAAQ,EAAE,MAAM,CAAC,IAAI;gBACrB,GAAG,EAAE,MAAM,CAAC,GAAG;aAChB,CAAC,CACH,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC;IAED,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAChB,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;YACtC,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC,CAAC;SAChD;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CACpC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAC3B,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;CACF;AApCD,sCAoCC;AAED,kBAAe,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,aAAa,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC","file":"ali-oss.js","sourcesContent":["import AliOss from 'ali-oss';\nimport { getFilename } from '../utils';\n\nexport class AliOssStorage {\n\n private client: AliOss;\n\n private getFilename: Function;\n\n constructor(opts) {\n this.client = new AliOss(opts.config);\n this.getFilename = opts.filename || getFilename;\n }\n\n _handleFile(req, file, cb) {\n if (!this.client) {\n console.error('oss client undefined');\n return cb({ message: 'oss client undefined' });\n }\n this.getFilename(req, file, (err, filename) => {\n if (err) return cb(err)\n this.client.putStream(filename, file.stream).then(\n result => cb(null, {\n filename: result.name,\n url: result.url\n })\n ).catch(cb);\n });\n }\n\n _removeFile(req, file, cb) {\n if (!this.client) {\n console.error('oss client undefined');\n return cb({ message: 'oss client undefined' });\n }\n this.client.delete(file.filename).then(\n result => cb(null, result)\n ).catch(cb);\n }\n}\n\nexport default (storage) => new AliOssStorage({ config: storage.options });\n"]}
1
+ {"version":3,"sources":["storages/ali-oss.ts"],"names":[],"mappings":";;AAAA,4CAAoD;AACpD,oCAA+C;AAE/C,kBAAe;IACb,IAAI,CAAC,OAAO;QACV,MAAM,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;QACzD,OAAO,IAAI,mBAAmB,CAAC;YAC7B,MAAM,EAAE,OAAO,CAAC,OAAO;YACvB,QAAQ,EAAE,IAAA,2BAAmB,EAAC,OAAO,CAAC;SACvC,CAAC,CAAC;IACL,CAAC;IACD,QAAQ;QACN,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,IAAI,EAAE,gCAAoB;YAC1B,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB;YAC7C,OAAO,EAAE;gBACP,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;gBAClC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB;gBAC9C,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB;gBACtD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;aACnC;SACF,CAAA;IACH,CAAC;CACF,CAAA","file":"ali-oss.js","sourcesContent":["import { STORAGE_TYPE_ALI_OSS } from '../constants';\nimport { cloudFilenameGetter } from '../utils';\n\nexport default {\n make(storage) {\n const createAliOssStorage = require('multer-aliyun-oss');\n return new createAliOssStorage({\n config: storage.options,\n filename: cloudFilenameGetter(storage)\n });\n },\n defaults() {\n return {\n title: '阿里云对象存储',\n type: STORAGE_TYPE_ALI_OSS,\n name: 'ali-oss-1',\n baseUrl: process.env.ALI_OSS_STORAGE_BASE_URL,\n options: {\n region: process.env.ALI_OSS_REGION,\n accessKeyId: process.env.ALI_OSS_ACCESS_KEY_ID,\n accessKeySecret: process.env.ALI_OSS_ACCESS_KEY_SECRET,\n bucket: process.env.ALI_OSS_BUCKET,\n }\n }\n }\n}\n"]}
@@ -1,2 +1,8 @@
1
- declare const map: Map<string, Function>;
2
- export default map;
1
+ export interface IStorage {
2
+ filenameKey?: string;
3
+ middleware?: Function;
4
+ getFileData?: Function;
5
+ make: Function;
6
+ defaults: Function;
7
+ }
8
+ export declare function getStorageConfig(key: string): IStorage;
@@ -1 +1 @@
1
- {"version":3,"sources":["storages/index.ts"],"names":[],"mappings":"AAMA,QAAA,MAAM,GAAG,uBAA8B,CAAC;AAIxC,eAAe,GAAG,CAAC","file":"index.d.ts","sourcesContent":["import local from './local';\nimport oss from './ali-oss';\nimport { STORAGE_TYPE_LOCAL, STORAGE_TYPE_ALI_OSS } from '../constants';\n\n\n\nconst map = new Map<string, Function>();\nmap.set(STORAGE_TYPE_LOCAL, local);\nmap.set(STORAGE_TYPE_ALI_OSS, oss);\n\nexport default map;\n"]}
1
+ {"version":3,"sources":["storages/index.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAQD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAEtD","file":"index.d.ts","sourcesContent":["import local from './local';\nimport oss from './ali-oss';\nimport s3 from './s3';\n\nimport {\n STORAGE_TYPE_LOCAL,\n STORAGE_TYPE_ALI_OSS,\n STORAGE_TYPE_S3\n} from '../constants';\n\nexport interface IStorage {\n filenameKey?: string;\n middleware?: Function;\n getFileData?: Function;\n make: Function;\n defaults: Function;\n}\n\nconst map = new Map<string, IStorage>();\nmap.set(STORAGE_TYPE_LOCAL, local);\nmap.set(STORAGE_TYPE_ALI_OSS, oss);\nmap.set(STORAGE_TYPE_S3, s3);\n\n\nexport function getStorageConfig(key: string): IStorage {\n return map.get(key);\n};\n"]}
@@ -21,15 +21,25 @@ var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
21
21
  Object.defineProperty(exports, "__esModule", {
22
22
  value: true
23
23
  });
24
+ exports.getStorageConfig = void 0;
24
25
 
25
26
  const local_1 = __importDefault(require("./local"));
26
27
 
27
28
  const ali_oss_1 = __importDefault(require("./ali-oss"));
28
29
 
30
+ const s3_1 = __importDefault(require("./s3"));
31
+
29
32
  const constants_1 = require("../constants");
30
33
 
31
34
  const map = new Map();
32
35
  map.set(constants_1.STORAGE_TYPE_LOCAL, local_1.default);
33
36
  map.set(constants_1.STORAGE_TYPE_ALI_OSS, ali_oss_1.default);
34
- exports.default = map;
37
+ map.set(constants_1.STORAGE_TYPE_S3, s3_1.default);
38
+
39
+ function getStorageConfig(key) {
40
+ return map.get(key);
41
+ }
42
+
43
+ exports.getStorageConfig = getStorageConfig;
44
+ ;
35
45
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["storages/index.ts"],"names":[],"mappings":";;;;;AAAA,oDAA4B;AAC5B,wDAA4B;AAC5B,4CAAwE;AAIxE,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;AACxC,GAAG,CAAC,GAAG,CAAC,8BAAkB,EAAE,eAAK,CAAC,CAAC;AACnC,GAAG,CAAC,GAAG,CAAC,gCAAoB,EAAE,iBAAG,CAAC,CAAC;AAEnC,kBAAe,GAAG,CAAC","file":"index.js","sourcesContent":["import local from './local';\nimport oss from './ali-oss';\nimport { STORAGE_TYPE_LOCAL, STORAGE_TYPE_ALI_OSS } from '../constants';\n\n\n\nconst map = new Map<string, Function>();\nmap.set(STORAGE_TYPE_LOCAL, local);\nmap.set(STORAGE_TYPE_ALI_OSS, oss);\n\nexport default map;\n"]}
1
+ {"version":3,"sources":["storages/index.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAC5B,wDAA4B;AAC5B,8CAAsB;AAEtB,4CAIsB;AAUtB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;AACxC,GAAG,CAAC,GAAG,CAAC,8BAAkB,EAAE,eAAK,CAAC,CAAC;AACnC,GAAG,CAAC,GAAG,CAAC,gCAAoB,EAAE,iBAAG,CAAC,CAAC;AACnC,GAAG,CAAC,GAAG,CAAC,2BAAe,EAAE,YAAE,CAAC,CAAC;AAG7B,SAAgB,gBAAgB,CAAC,GAAW;IAC1C,OAAO,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC;AAFD,4CAEC;AAAA,CAAC","file":"index.js","sourcesContent":["import local from './local';\nimport oss from './ali-oss';\nimport s3 from './s3';\n\nimport {\n STORAGE_TYPE_LOCAL,\n STORAGE_TYPE_ALI_OSS,\n STORAGE_TYPE_S3\n} from '../constants';\n\nexport interface IStorage {\n filenameKey?: string;\n middleware?: Function;\n getFileData?: Function;\n make: Function;\n defaults: Function;\n}\n\nconst map = new Map<string, IStorage>();\nmap.set(STORAGE_TYPE_LOCAL, local);\nmap.set(STORAGE_TYPE_ALI_OSS, oss);\nmap.set(STORAGE_TYPE_S3, s3);\n\n\nexport function getStorageConfig(key: string): IStorage {\n return map.get(key);\n};\n"]}
@@ -1,5 +1,13 @@
1
1
  import multer from 'multer';
2
- export declare function getDocumentRoot(storage: any): string;
3
- export declare function middleware(app: any): any;
4
- declare const _default: (storage: any) => multer.StorageEngine;
2
+ declare function middleware(app: any, options?: any): Promise<void>;
3
+ declare const _default: {
4
+ middleware: typeof middleware;
5
+ make(storage: any): multer.StorageEngine;
6
+ defaults(): {
7
+ title: string;
8
+ type: string;
9
+ name: string;
10
+ baseUrl: string;
11
+ };
12
+ };
5
13
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"sources":["storages/local.ts"],"names":[],"mappings":"AAGA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAM5B,wBAAgB,eAAe,CAAC,OAAO,KAAA,GAAG,MAAM,CAM/C;AAGD,wBAAgB,UAAU,CAAC,GAAG,KAAA,OAkD7B;;AAED,wBAQG","file":"local.d.ts","sourcesContent":["import path from 'path';\nimport { URL } from 'url';\nimport mkdirp from 'mkdirp';\nimport multer from 'multer';\nimport serve from 'koa-static';\nimport mount from 'koa-mount';\nimport { STORAGE_TYPE_LOCAL } from '../constants';\nimport { getFilename } from '../utils';\n\nexport function getDocumentRoot(storage): string {\n const { documentRoot = 'uploads' } = storage.options || {};\n // TODO(feature): 后面考虑以字符串模板的方式使用,可注入 req/action 相关变量,以便于区分文件夹\n return path.resolve(path.isAbsolute(documentRoot)\n ? documentRoot\n : path.join(process.cwd(), documentRoot), storage.path);\n}\n\n// TODO(optimize): 初始化的时机不应该放在中间件里\nexport function middleware(app) {\n if (process.env.NOCOBASE_ENV === 'production') {\n return;\n }\n\n const storages = new Map<string, any>();\n const StorageModel = app.db.getModel('storages');\n\n return app.use(async function (ctx, next) {\n const items = await StorageModel.findAll({\n where: {\n type: STORAGE_TYPE_LOCAL,\n }\n });\n\n const primaryKey = StorageModel.primaryKeyAttribute;\n\n for (const storage of items) {\n\n // TODO:未解决 storage 更新问题\n if (storages.has(storage[primaryKey])) {\n continue;\n }\n\n const baseUrl = storage.get('baseUrl');\n\n let url;\n try {\n url = new URL(baseUrl);\n } catch (e) {\n url = {\n protocol: 'http:',\n hostname: 'localhost',\n port: process.env.API_PORT,\n pathname: baseUrl\n };\n }\n\n // 以下情况才认为当前进程所应该提供静态服务\n // 否则都忽略,交给其他 server 来提供(如 nginx/cdn 等)\n // TODO(bug): https、端口 80 默认值和其他本地 ip/hostname 的情况未考虑\n // TODO 实际应该用 NOCOBASE_ENV 来判断,或者抛给 env 处理\n if (process.env.LOCAL_STORAGE_USE_STATIC_SERVER) {\n const basePath = url.pathname.startsWith('/') ? url.pathname : `/${url.pathname}`;\n app.use(mount(basePath, serve(getDocumentRoot(storage))));\n }\n storages.set(storage.primaryKey, storage);\n }\n await next();\n });\n}\n\nexport default (storage) => multer.diskStorage({\n destination: function (req, file, cb) {\n const destPath = getDocumentRoot(storage);\n mkdirp(destPath).then(() => {\n cb(null, destPath);\n }).catch(cb);\n },\n filename: getFilename\n});\n"]}
1
+ {"version":3,"sources":["storages/local.ts"],"names":[],"mappings":"AAGA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAoD5B,iBAAe,UAAU,CAAC,GAAG,KAAA,EAAE,OAAO,CAAC,KAAA,iBAmDtC;;;;;;;;;;;AAED,wBAmBE","file":"local.d.ts","sourcesContent":["import path from 'path';\nimport { URL } from 'url';\nimport mkdirp from 'mkdirp';\nimport multer from 'multer';\nimport serve from 'koa-static';\nimport { STORAGE_TYPE_LOCAL } from '../constants';\nimport { getFilename } from '../utils';\n\n// use koa-mount match logic\nfunction match(basePath: string, pathname: string): boolean {\n if (!pathname.startsWith(basePath)) {\n return false;\n }\n\n const newPath = pathname.replace(basePath, '') || '/';\n if (basePath.slice(-1) === '/') {\n return true;\n }\n\n return newPath[0] === '/';\n}\n\nasync function update(app, storages) {\n const StorageModel = app.db.getModel('storages');\n\n const items = await StorageModel.findAll({\n where: {\n type: STORAGE_TYPE_LOCAL,\n }\n });\n\n const primaryKey = StorageModel.primaryKeyAttribute;\n\n storages.clear();\n for (const storage of items) {\n storages.set(storage[primaryKey], storage);\n }\n}\n\nfunction createLocalServerUpdateHook(app, storages) {\n return async function (row) {\n if (row.get('type') === STORAGE_TYPE_LOCAL) {\n await update(app, storages);\n }\n }\n}\n\nfunction getDocumentRoot(storage): string {\n const { documentRoot = 'uploads' } = storage.options || {};\n // TODO(feature): 后面考虑以字符串模板的方式使用,可注入 req/action 相关变量,以便于区分文件夹\n return path.resolve(path.isAbsolute(documentRoot)\n ? documentRoot\n : path.join(process.cwd(), documentRoot));\n}\n\nasync function middleware(app, options?) {\n const LOCALHOST = `http://localhost:${process.env.API_PORT}`;\n\n const StorageModel = app.db.getModel('storages');\n const storages = new Map<string, any>();\n\n const localServerUpdateHook = createLocalServerUpdateHook(app, storages);\n StorageModel.addHook('afterCreate', localServerUpdateHook);\n StorageModel.addHook('afterUpdate', localServerUpdateHook);\n StorageModel.addHook('afterDestroy', localServerUpdateHook);\n\n await update(app, storages);\n\n app.use(async function (ctx, next) {\n for (const storage of storages.values()) {\n const baseUrl = storage.get('baseUrl');\n\n let url;\n try {\n url = new URL(baseUrl);\n } catch (e) {\n url = {\n pathname: baseUrl\n };\n }\n\n // 以下情况才认为当前进程所应该提供静态服务\n // 否则都忽略,交给其他 server 来提供(如 nginx/cdn 等)\n if (url.origin && url.origin !== LOCALHOST) {\n continue;\n }\n\n const basePath = url.pathname.startsWith('/') ? url.pathname : `/${url.pathname}`;\n if (!match(basePath, ctx.path)) {\n continue;\n }\n\n return serve(getDocumentRoot(storage), {\n // for handle files after any api handlers\n defer: true\n })(ctx, async () => {\n if (ctx.path.startsWith(basePath)) {\n ctx.path = ctx.path.replace(basePath, '');\n }\n // console.log('file request:', `${basePath}${ctx.path}`);\n await next();\n });\n }\n\n await next();\n });\n}\n\nexport default {\n middleware,\n make(storage) {\n return multer.diskStorage({\n destination: function (req, file, cb) {\n const destPath = path.join(getDocumentRoot(storage), storage.path);\n mkdirp(destPath, (err: Error | null) => cb(err, destPath));\n },\n filename: getFilename\n });\n },\n defaults() {\n return {\n title: '本地存储',\n type: STORAGE_TYPE_LOCAL,\n name: `local`,\n baseUrl: process.env.LOCAL_STORAGE_BASE_URL || `http://localhost:${process.env.API_PORT}/uploads`\n };\n }\n};\n"]}
@@ -59,7 +59,6 @@ var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
59
59
  Object.defineProperty(exports, "__esModule", {
60
60
  value: true
61
61
  });
62
- exports.middleware = exports.getDocumentRoot = void 0;
63
62
 
64
63
  const path_1 = __importDefault(require("path"));
65
64
 
@@ -71,90 +70,151 @@ const multer_1 = __importDefault(require("multer"));
71
70
 
72
71
  const koa_static_1 = __importDefault(require("koa-static"));
73
72
 
74
- const koa_mount_1 = __importDefault(require("koa-mount"));
75
-
76
73
  const constants_1 = require("../constants");
77
74
 
78
75
  const utils_1 = require("../utils");
79
76
 
80
- function getDocumentRoot(storage) {
81
- const _ref = storage.options || {},
82
- _ref$documentRoot = _ref.documentRoot,
83
- documentRoot = _ref$documentRoot === void 0 ? 'uploads' : _ref$documentRoot;
77
+ function match(basePath, pathname) {
78
+ if (!pathname.startsWith(basePath)) {
79
+ return false;
80
+ }
84
81
 
85
- return path_1.default.resolve(path_1.default.isAbsolute(documentRoot) ? documentRoot : path_1.default.join(process.cwd(), documentRoot), storage.path);
82
+ const newPath = pathname.replace(basePath, '') || '/';
83
+
84
+ if (basePath.slice(-1) === '/') {
85
+ return true;
86
+ }
87
+
88
+ return newPath[0] === '/';
86
89
  }
87
90
 
88
- exports.getDocumentRoot = getDocumentRoot;
91
+ function update(app, storages) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ const StorageModel = app.db.getModel('storages');
94
+ const items = yield StorageModel.findAll({
95
+ where: {
96
+ type: constants_1.STORAGE_TYPE_LOCAL
97
+ }
98
+ });
99
+ const primaryKey = StorageModel.primaryKeyAttribute;
100
+ storages.clear();
101
+
102
+ var _iterator = _createForOfIteratorHelper(items),
103
+ _step;
89
104
 
90
- function middleware(app) {
91
- if (process.env.NOCOBASE_ENV === 'production') {
92
- return;
93
- }
105
+ try {
106
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
107
+ const storage = _step.value;
108
+ storages.set(storage[primaryKey], storage);
109
+ }
110
+ } catch (err) {
111
+ _iterator.e(err);
112
+ } finally {
113
+ _iterator.f();
114
+ }
115
+ });
116
+ }
94
117
 
95
- const storages = new Map();
96
- const StorageModel = app.db.getModel('storages');
97
- return app.use(function (ctx, next) {
118
+ function createLocalServerUpdateHook(app, storages) {
119
+ return function (row) {
98
120
  return __awaiter(this, void 0, void 0, function* () {
99
- const items = yield StorageModel.findAll({
100
- where: {
101
- type: constants_1.STORAGE_TYPE_LOCAL
102
- }
103
- });
104
- const primaryKey = StorageModel.primaryKeyAttribute;
105
-
106
- var _iterator = _createForOfIteratorHelper(items),
107
- _step;
121
+ if (row.get('type') === constants_1.STORAGE_TYPE_LOCAL) {
122
+ yield update(app, storages);
123
+ }
124
+ });
125
+ };
126
+ }
108
127
 
109
- try {
110
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
111
- const storage = _step.value;
128
+ function getDocumentRoot(storage) {
129
+ const _ref = storage.options || {},
130
+ _ref$documentRoot = _ref.documentRoot,
131
+ documentRoot = _ref$documentRoot === void 0 ? 'uploads' : _ref$documentRoot;
112
132
 
113
- if (storages.has(storage[primaryKey])) {
114
- continue;
115
- }
133
+ return path_1.default.resolve(path_1.default.isAbsolute(documentRoot) ? documentRoot : path_1.default.join(process.cwd(), documentRoot));
134
+ }
116
135
 
117
- const baseUrl = storage.get('baseUrl');
118
- let url;
119
-
120
- try {
121
- url = new url_1.URL(baseUrl);
122
- } catch (e) {
123
- url = {
124
- protocol: 'http:',
125
- hostname: 'localhost',
126
- port: process.env.API_PORT,
127
- pathname: baseUrl
128
- };
129
- }
136
+ function middleware(app, options) {
137
+ return __awaiter(this, void 0, void 0, function* () {
138
+ const LOCALHOST = `http://localhost:${process.env.API_PORT}`;
139
+ const StorageModel = app.db.getModel('storages');
140
+ const storages = new Map();
141
+ const localServerUpdateHook = createLocalServerUpdateHook(app, storages);
142
+ StorageModel.addHook('afterCreate', localServerUpdateHook);
143
+ StorageModel.addHook('afterUpdate', localServerUpdateHook);
144
+ StorageModel.addHook('afterDestroy', localServerUpdateHook);
145
+ yield update(app, storages);
146
+ app.use(function (ctx, next) {
147
+ return __awaiter(this, void 0, void 0, function* () {
148
+ var _iterator2 = _createForOfIteratorHelper(storages.values()),
149
+ _step2;
150
+
151
+ try {
152
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
153
+ const storage = _step2.value;
154
+ const baseUrl = storage.get('baseUrl');
155
+ let url;
156
+
157
+ try {
158
+ url = new url_1.URL(baseUrl);
159
+ } catch (e) {
160
+ url = {
161
+ pathname: baseUrl
162
+ };
163
+ }
164
+
165
+ if (url.origin && url.origin !== LOCALHOST) {
166
+ continue;
167
+ }
130
168
 
131
- if (process.env.LOCAL_STORAGE_USE_STATIC_SERVER) {
132
169
  const basePath = url.pathname.startsWith('/') ? url.pathname : `/${url.pathname}`;
133
- app.use(koa_mount_1.default(basePath, koa_static_1.default(getDocumentRoot(storage))));
134
- }
135
170
 
136
- storages.set(storage.primaryKey, storage);
171
+ if (!match(basePath, ctx.path)) {
172
+ continue;
173
+ }
174
+
175
+ return (0, koa_static_1.default)(getDocumentRoot(storage), {
176
+ defer: true
177
+ })(ctx, () => __awaiter(this, void 0, void 0, function* () {
178
+ if (ctx.path.startsWith(basePath)) {
179
+ ctx.path = ctx.path.replace(basePath, '');
180
+ }
181
+
182
+ yield next();
183
+ }));
184
+ }
185
+ } catch (err) {
186
+ _iterator2.e(err);
187
+ } finally {
188
+ _iterator2.f();
137
189
  }
138
- } catch (err) {
139
- _iterator.e(err);
140
- } finally {
141
- _iterator.f();
142
- }
143
190
 
144
- yield next();
191
+ yield next();
192
+ });
145
193
  });
146
194
  });
147
195
  }
148
196
 
149
- exports.middleware = middleware;
197
+ exports.default = {
198
+ middleware,
150
199
 
151
- exports.default = storage => multer_1.default.diskStorage({
152
- destination: function destination(req, file, cb) {
153
- const destPath = getDocumentRoot(storage);
154
- mkdirp_1.default(destPath).then(() => {
155
- cb(null, destPath);
156
- }).catch(cb);
200
+ make(storage) {
201
+ return multer_1.default.diskStorage({
202
+ destination: function destination(req, file, cb) {
203
+ const destPath = path_1.default.join(getDocumentRoot(storage), storage.path);
204
+ (0, mkdirp_1.default)(destPath, err => cb(err, destPath));
205
+ },
206
+ filename: utils_1.getFilename
207
+ });
157
208
  },
158
- filename: utils_1.getFilename
159
- });
209
+
210
+ defaults() {
211
+ return {
212
+ title: '本地存储',
213
+ type: constants_1.STORAGE_TYPE_LOCAL,
214
+ name: `local`,
215
+ baseUrl: process.env.LOCAL_STORAGE_BASE_URL || `http://localhost:${process.env.API_PORT}/uploads`
216
+ };
217
+ }
218
+
219
+ };
160
220
  //# sourceMappingURL=local.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["storages/local.ts"],"names":[],"mappings":"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","file":"local.js","sourcesContent":["import path from 'path';\nimport { URL } from 'url';\nimport mkdirp from 'mkdirp';\nimport multer from 'multer';\nimport serve from 'koa-static';\nimport mount from 'koa-mount';\nimport { STORAGE_TYPE_LOCAL } from '../constants';\nimport { getFilename } from '../utils';\n\nexport function getDocumentRoot(storage): string {\n const { documentRoot = 'uploads' } = storage.options || {};\n // TODO(feature): 后面考虑以字符串模板的方式使用,可注入 req/action 相关变量,以便于区分文件夹\n return path.resolve(path.isAbsolute(documentRoot)\n ? documentRoot\n : path.join(process.cwd(), documentRoot), storage.path);\n}\n\n// TODO(optimize): 初始化的时机不应该放在中间件里\nexport function middleware(app) {\n if (process.env.NOCOBASE_ENV === 'production') {\n return;\n }\n\n const storages = new Map<string, any>();\n const StorageModel = app.db.getModel('storages');\n\n return app.use(async function (ctx, next) {\n const items = await StorageModel.findAll({\n where: {\n type: STORAGE_TYPE_LOCAL,\n }\n });\n\n const primaryKey = StorageModel.primaryKeyAttribute;\n\n for (const storage of items) {\n\n // TODO:未解决 storage 更新问题\n if (storages.has(storage[primaryKey])) {\n continue;\n }\n\n const baseUrl = storage.get('baseUrl');\n\n let url;\n try {\n url = new URL(baseUrl);\n } catch (e) {\n url = {\n protocol: 'http:',\n hostname: 'localhost',\n port: process.env.API_PORT,\n pathname: baseUrl\n };\n }\n\n // 以下情况才认为当前进程所应该提供静态服务\n // 否则都忽略,交给其他 server 来提供(如 nginx/cdn 等)\n // TODO(bug): https、端口 80 默认值和其他本地 ip/hostname 的情况未考虑\n // TODO 实际应该用 NOCOBASE_ENV 来判断,或者抛给 env 处理\n if (process.env.LOCAL_STORAGE_USE_STATIC_SERVER) {\n const basePath = url.pathname.startsWith('/') ? url.pathname : `/${url.pathname}`;\n app.use(mount(basePath, serve(getDocumentRoot(storage))));\n }\n storages.set(storage.primaryKey, storage);\n }\n await next();\n });\n}\n\nexport default (storage) => multer.diskStorage({\n destination: function (req, file, cb) {\n const destPath = getDocumentRoot(storage);\n mkdirp(destPath).then(() => {\n cb(null, destPath);\n }).catch(cb);\n },\n filename: getFilename\n});\n"]}
1
+ {"version":3,"sources":["storages/local.ts"],"names":[],"mappings":"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","file":"local.js","sourcesContent":["import path from 'path';\nimport { URL } from 'url';\nimport mkdirp from 'mkdirp';\nimport multer from 'multer';\nimport serve from 'koa-static';\nimport { STORAGE_TYPE_LOCAL } from '../constants';\nimport { getFilename } from '../utils';\n\n// use koa-mount match logic\nfunction match(basePath: string, pathname: string): boolean {\n if (!pathname.startsWith(basePath)) {\n return false;\n }\n\n const newPath = pathname.replace(basePath, '') || '/';\n if (basePath.slice(-1) === '/') {\n return true;\n }\n\n return newPath[0] === '/';\n}\n\nasync function update(app, storages) {\n const StorageModel = app.db.getModel('storages');\n\n const items = await StorageModel.findAll({\n where: {\n type: STORAGE_TYPE_LOCAL,\n }\n });\n\n const primaryKey = StorageModel.primaryKeyAttribute;\n\n storages.clear();\n for (const storage of items) {\n storages.set(storage[primaryKey], storage);\n }\n}\n\nfunction createLocalServerUpdateHook(app, storages) {\n return async function (row) {\n if (row.get('type') === STORAGE_TYPE_LOCAL) {\n await update(app, storages);\n }\n }\n}\n\nfunction getDocumentRoot(storage): string {\n const { documentRoot = 'uploads' } = storage.options || {};\n // TODO(feature): 后面考虑以字符串模板的方式使用,可注入 req/action 相关变量,以便于区分文件夹\n return path.resolve(path.isAbsolute(documentRoot)\n ? documentRoot\n : path.join(process.cwd(), documentRoot));\n}\n\nasync function middleware(app, options?) {\n const LOCALHOST = `http://localhost:${process.env.API_PORT}`;\n\n const StorageModel = app.db.getModel('storages');\n const storages = new Map<string, any>();\n\n const localServerUpdateHook = createLocalServerUpdateHook(app, storages);\n StorageModel.addHook('afterCreate', localServerUpdateHook);\n StorageModel.addHook('afterUpdate', localServerUpdateHook);\n StorageModel.addHook('afterDestroy', localServerUpdateHook);\n\n await update(app, storages);\n\n app.use(async function (ctx, next) {\n for (const storage of storages.values()) {\n const baseUrl = storage.get('baseUrl');\n\n let url;\n try {\n url = new URL(baseUrl);\n } catch (e) {\n url = {\n pathname: baseUrl\n };\n }\n\n // 以下情况才认为当前进程所应该提供静态服务\n // 否则都忽略,交给其他 server 来提供(如 nginx/cdn 等)\n if (url.origin && url.origin !== LOCALHOST) {\n continue;\n }\n\n const basePath = url.pathname.startsWith('/') ? url.pathname : `/${url.pathname}`;\n if (!match(basePath, ctx.path)) {\n continue;\n }\n\n return serve(getDocumentRoot(storage), {\n // for handle files after any api handlers\n defer: true\n })(ctx, async () => {\n if (ctx.path.startsWith(basePath)) {\n ctx.path = ctx.path.replace(basePath, '');\n }\n // console.log('file request:', `${basePath}${ctx.path}`);\n await next();\n });\n }\n\n await next();\n });\n}\n\nexport default {\n middleware,\n make(storage) {\n return multer.diskStorage({\n destination: function (req, file, cb) {\n const destPath = path.join(getDocumentRoot(storage), storage.path);\n mkdirp(destPath, (err: Error | null) => cb(err, destPath));\n },\n filename: getFilename\n });\n },\n defaults() {\n return {\n title: '本地存储',\n type: STORAGE_TYPE_LOCAL,\n name: `local`,\n baseUrl: process.env.LOCAL_STORAGE_BASE_URL || `http://localhost:${process.env.API_PORT}/uploads`\n };\n }\n};\n"]}
@@ -0,0 +1,17 @@
1
+ declare const _default: {
2
+ filenameKey: string;
3
+ make(storage: any): any;
4
+ defaults(): {
5
+ title: string;
6
+ name: string;
7
+ type: string;
8
+ baseUrl: string;
9
+ options: {
10
+ region: string;
11
+ accessKeyId: string;
12
+ secretAccessKey: string;
13
+ bucket: string;
14
+ };
15
+ };
16
+ };
17
+ export default _default;
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["storages/s3.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAGA,wBAiDC","file":"s3.d.ts","sourcesContent":["import { STORAGE_TYPE_S3 } from '../constants';\nimport { cloudFilenameGetter } from '../utils';\n\nexport default {\n filenameKey: 'key',\n make(storage) {\n const S3Client = require('aws-sdk/clients/s3');\n const multerS3 = require('multer-s3');\n const {\n accessKeyId,\n secretAccessKey,\n bucket,\n acl = 'public-read',\n ...options\n } = storage.options;\n const s3 = new S3Client({\n ...options,\n credentials: {\n accessKeyId,\n secretAccessKey\n }\n });\n\n return multerS3({\n s3,\n bucket,\n acl,\n contentType(req, file, cb) {\n if (file.mimetype) {\n cb(null, file.mimetype);\n return;\n }\n \n multerS3.AUTO_CONTENT_TYPE(req, file, cb);\n },\n key: cloudFilenameGetter(storage)\n });\n },\n defaults() {\n return {\n title: 'AWS S3',\n name: 'aws-s3',\n type: STORAGE_TYPE_S3,\n baseUrl: process.env.AWS_S3_STORAGE_BASE_URL,\n options: {\n region: process.env.AWS_S3_REGION,\n accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n bucket: process.env.AWS_S3_BUCKET,\n }\n }\n }\n}\n"]}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+
3
+ function _react() {
4
+ const data = _interopRequireDefault(require("react"));
5
+
6
+ _react = function _react() {
7
+ return data;
8
+ };
9
+
10
+ return data;
11
+ }
12
+
13
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
14
+
15
+ var __rest = void 0 && (void 0).__rest || function (s, e) {
16
+ var t = {};
17
+
18
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
19
+
20
+ if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
21
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
22
+ }
23
+ return t;
24
+ };
25
+
26
+ Object.defineProperty(exports, "__esModule", {
27
+ value: true
28
+ });
29
+
30
+ const constants_1 = require("../constants");
31
+
32
+ const utils_1 = require("../utils");
33
+
34
+ exports.default = {
35
+ filenameKey: 'key',
36
+
37
+ make(storage) {
38
+ const S3Client = require('aws-sdk/clients/s3');
39
+
40
+ const multerS3 = require('multer-s3');
41
+
42
+ const _a = storage.options,
43
+ accessKeyId = _a.accessKeyId,
44
+ secretAccessKey = _a.secretAccessKey,
45
+ bucket = _a.bucket,
46
+ _a$acl = _a.acl,
47
+ acl = _a$acl === void 0 ? 'public-read' : _a$acl,
48
+ options = __rest(_a, ["accessKeyId", "secretAccessKey", "bucket", "acl"]);
49
+
50
+ const s3 = new S3Client(Object.assign(Object.assign({}, options), {
51
+ credentials: {
52
+ accessKeyId,
53
+ secretAccessKey
54
+ }
55
+ }));
56
+ return multerS3({
57
+ s3,
58
+ bucket,
59
+ acl,
60
+
61
+ contentType(req, file, cb) {
62
+ if (file.mimetype) {
63
+ cb(null, file.mimetype);
64
+ return;
65
+ }
66
+
67
+ multerS3.AUTO_CONTENT_TYPE(req, file, cb);
68
+ },
69
+
70
+ key: (0, utils_1.cloudFilenameGetter)(storage)
71
+ });
72
+ },
73
+
74
+ defaults() {
75
+ return {
76
+ title: 'AWS S3',
77
+ name: 'aws-s3',
78
+ type: constants_1.STORAGE_TYPE_S3,
79
+ baseUrl: process.env.AWS_S3_STORAGE_BASE_URL,
80
+ options: {
81
+ region: process.env.AWS_S3_REGION,
82
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
83
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
84
+ bucket: process.env.AWS_S3_BUCKET
85
+ }
86
+ };
87
+ }
88
+
89
+ };
90
+ //# sourceMappingURL=s3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["storages/s3.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,4CAA+C;AAC/C,oCAA+C;AAE/C,kBAAe;IACb,WAAW,EAAE,KAAK;IAClB,IAAI,CAAC,OAAO;QACV,MAAM,QAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,KAMF,OAAO,CAAC,OAAO,EANb,EACJ,WAAW,EACX,eAAe,EACf,MAAM,EACN,GAAG,GAAG,aAAa,OAEF,EADd,OAAO,cALN,mDAML,CAAkB,CAAC;QACpB,MAAM,EAAE,GAAG,IAAI,QAAQ,iCAClB,OAAO,KACV,WAAW,EAAE;gBACX,WAAW;gBACX,eAAe;aAChB,IACD,CAAC;QAEH,OAAO,QAAQ,CAAC;YACd,EAAE;YACF,MAAM;YACN,GAAG;YACH,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;gBACvB,IAAI,IAAI,CAAC,QAAQ,EAAE;oBACjB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACxB,OAAO;iBACR;gBAED,QAAQ,CAAC,iBAAiB,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YAC5C,CAAC;YACD,GAAG,EAAE,IAAA,2BAAmB,EAAC,OAAO,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;IACD,QAAQ;QACN,OAAO;YACL,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,2BAAe;YACrB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;YAC5C,OAAO,EAAE;gBACP,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa;gBACjC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB;gBAC1C,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB;gBAClD,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa;aAClC;SACF,CAAA;IACH,CAAC;CACF,CAAA","file":"s3.js","sourcesContent":["import { STORAGE_TYPE_S3 } from '../constants';\nimport { cloudFilenameGetter } from '../utils';\n\nexport default {\n filenameKey: 'key',\n make(storage) {\n const S3Client = require('aws-sdk/clients/s3');\n const multerS3 = require('multer-s3');\n const {\n accessKeyId,\n secretAccessKey,\n bucket,\n acl = 'public-read',\n ...options\n } = storage.options;\n const s3 = new S3Client({\n ...options,\n credentials: {\n accessKeyId,\n secretAccessKey\n }\n });\n\n return multerS3({\n s3,\n bucket,\n acl,\n contentType(req, file, cb) {\n if (file.mimetype) {\n cb(null, file.mimetype);\n return;\n }\n \n multerS3.AUTO_CONTENT_TYPE(req, file, cb);\n },\n key: cloudFilenameGetter(storage)\n });\n },\n defaults() {\n return {\n title: 'AWS S3',\n name: 'aws-s3',\n type: STORAGE_TYPE_S3,\n baseUrl: process.env.AWS_S3_STORAGE_BASE_URL,\n options: {\n region: process.env.AWS_S3_REGION,\n accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,\n bucket: process.env.AWS_S3_BUCKET,\n }\n }\n }\n}\n"]}
package/lib/utils.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export declare function getFilename(req: any, file: any, cb: any): void;
2
+ export declare const cloudFilenameGetter: (storage: any) => (req: any, file: any, cb: any) => void;
@@ -1 +1 @@
1
- {"version":3,"sources":["utils.ts"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,CAAC,GAAG,KAAA,EAAE,IAAI,KAAA,EAAE,EAAE,KAAA,QAIxC","file":"utils.d.ts","sourcesContent":["import crypto from 'crypto';\nimport path from 'path';\n\nexport function getFilename(req, file, cb) {\n crypto.pseudoRandomBytes(16, function (err, raw) {\n cb(err, err ? undefined : `${raw.toString('hex')}${path.extname(file.originalname)}`)\n })\n}\n"]}
1
+ {"version":3,"sources":["utils.ts"],"names":[],"mappings":"AAGA,wBAAgB,WAAW,CAAC,GAAG,KAAA,EAAE,IAAI,KAAA,EAAE,EAAE,KAAA,QAIxC;AAED,eAAO,MAAM,mBAAmB,0DAO/B,CAAA","file":"utils.d.ts","sourcesContent":["import crypto from 'crypto';\nimport path from 'path';\n\nexport function getFilename(req, file, cb) {\n crypto.pseudoRandomBytes(16, function (err, raw) {\n cb(err, err ? undefined : `${raw.toString('hex')}${path.extname(file.originalname)}`)\n });\n}\n\nexport const cloudFilenameGetter = storage => (req, file, cb) => {\n getFilename(req, file, (err, filename) => {\n if (err) {\n return cb(err);\n }\n cb(null, `${storage.path ? `${storage.path}/` : ''}${filename}`);\n });\n}\n"]}
package/lib/utils.js CHANGED
@@ -21,7 +21,7 @@ var __importDefault = void 0 && (void 0).__importDefault || function (mod) {
21
21
  Object.defineProperty(exports, "__esModule", {
22
22
  value: true
23
23
  });
24
- exports.getFilename = void 0;
24
+ exports.cloudFilenameGetter = exports.getFilename = void 0;
25
25
 
26
26
  const crypto_1 = __importDefault(require("crypto"));
27
27
 
@@ -34,4 +34,16 @@ function getFilename(req, file, cb) {
34
34
  }
35
35
 
36
36
  exports.getFilename = getFilename;
37
+
38
+ const cloudFilenameGetter = storage => (req, file, cb) => {
39
+ getFilename(req, file, (err, filename) => {
40
+ if (err) {
41
+ return cb(err);
42
+ }
43
+
44
+ cb(null, `${storage.path ? `${storage.path}/` : ''}${filename}`);
45
+ });
46
+ };
47
+
48
+ exports.cloudFilenameGetter = cloudFilenameGetter;
37
49
  //# sourceMappingURL=utils.js.map
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["utils.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAC5B,gDAAwB;AAExB,SAAgB,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;IACvC,gBAAM,CAAC,iBAAiB,CAAC,EAAE,EAAE,UAAU,GAAG,EAAE,GAAG;QAC7C,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;IACvF,CAAC,CAAC,CAAA;AACJ,CAAC;AAJD,kCAIC","file":"utils.js","sourcesContent":["import crypto from 'crypto';\nimport path from 'path';\n\nexport function getFilename(req, file, cb) {\n crypto.pseudoRandomBytes(16, function (err, raw) {\n cb(err, err ? undefined : `${raw.toString('hex')}${path.extname(file.originalname)}`)\n })\n}\n"]}
1
+ {"version":3,"sources":["utils.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;AAC5B,gDAAwB;AAExB,SAAgB,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;IACvC,gBAAM,CAAC,iBAAiB,CAAC,EAAE,EAAE,UAAU,GAAG,EAAE,GAAG;QAC7C,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;IACvF,CAAC,CAAC,CAAC;AACL,CAAC;AAJD,kCAIC;AAEM,MAAM,mBAAmB,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;IAC9D,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;QACvC,IAAI,GAAG,EAAE;YACP,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;SAChB;QACD,EAAE,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAA;AAPY,QAAA,mBAAmB,uBAO/B","file":"utils.js","sourcesContent":["import crypto from 'crypto';\nimport path from 'path';\n\nexport function getFilename(req, file, cb) {\n crypto.pseudoRandomBytes(16, function (err, raw) {\n cb(err, err ? undefined : `${raw.toString('hex')}${path.extname(file.originalname)}`)\n });\n}\n\nexport const cloudFilenameGetter = storage => (req, file, cb) => {\n getFilename(req, file, (err, filename) => {\n if (err) {\n return cb(err);\n }\n cb(null, `${storage.path ? `${storage.path}/` : ''}${filename}`);\n });\n}\n"]}
package/package.json CHANGED
@@ -1,20 +1,19 @@
1
1
  {
2
2
  "name": "@nocobase/plugin-file-manager",
3
- "version": "0.5.0-alpha.32",
3
+ "version": "0.5.0-alpha.36",
4
4
  "main": "lib/index.js",
5
5
  "license": "MIT",
6
6
  "dependencies": {
7
7
  "@koa/multer": "^3.0.0",
8
- "@nocobase/server": "^0.5.0-alpha.32",
9
- "ali-oss": "^6.12.0",
10
- "koa-mount": "^4.0.0",
8
+ "aws-sdk": "^2.2.32",
11
9
  "koa-static": "^5.0.0",
12
10
  "mime-match": "^1.0.2",
13
- "multer": "^1.4.2"
11
+ "multer": "^1.4.2",
12
+ "multer-aliyun-oss": "1.1.1",
13
+ "multer-s3": "^2.10.0"
14
14
  },
15
15
  "devDependencies": {
16
- "@nocobase/test": "^0.5.0-alpha.32",
17
16
  "@types/multer": "^1.4.5"
18
17
  },
19
- "gitHead": "7be6327458cb376e7281cff42a43a282105b65f8"
18
+ "gitHead": "9998cd903bf87bf9a5d8a7616055f0cd1a007a72"
20
19
  }