mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 04:05:45 +00:00
feat: create file record via path (#5088)
This commit is contained in:
parent
fc86ec5fa5
commit
f3d15d5e8e
@ -11,6 +11,7 @@ import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import { getApp } from '.';
|
||||
import { FILE_FIELD_NAME, FILE_SIZE_LIMIT_DEFAULT, STORAGE_TYPE_LOCAL } from '../../constants';
|
||||
import PluginFileManagerServer from '../server';
|
||||
|
||||
const { LOCAL_STORAGE_BASE_URL, LOCAL_STORAGE_DEST = 'storage/uploads', APP_PORT = '13000' } = process.env;
|
||||
|
||||
@ -50,6 +51,23 @@ describe('action', () => {
|
||||
|
||||
describe('create / upload', () => {
|
||||
describe('default storage', () => {
|
||||
it('createFileRecord', async () => {
|
||||
const Plugin = app.pm.get(PluginFileManagerServer) as PluginFileManagerServer;
|
||||
const model = await Plugin.createFileRecord({
|
||||
collection: 'attachments',
|
||||
filePath: path.resolve(__dirname, './files/text.txt'),
|
||||
});
|
||||
const matcher = {
|
||||
title: 'text',
|
||||
extname: '.txt',
|
||||
path: '',
|
||||
// size: 13,
|
||||
meta: {},
|
||||
storageId: 1,
|
||||
};
|
||||
expect(model.toJSON()).toMatchObject(matcher);
|
||||
});
|
||||
|
||||
it('upload file should be ok', async () => {
|
||||
const { body } = await agent.resource('attachments').create({
|
||||
[FILE_FIELD_NAME]: path.resolve(__dirname, './files/text.txt'),
|
||||
|
@ -11,15 +11,15 @@ import { Context, Next } from '@nocobase/actions';
|
||||
import { koaMulter as multer } from '@nocobase/utils';
|
||||
import Path from 'path';
|
||||
|
||||
import Plugin from '..';
|
||||
import {
|
||||
FILE_FIELD_NAME,
|
||||
FILE_SIZE_LIMIT_DEFAULT,
|
||||
FILE_SIZE_LIMIT_MAX,
|
||||
FILE_FIELD_NAME,
|
||||
LIMIT_FILES,
|
||||
FILE_SIZE_LIMIT_MIN,
|
||||
LIMIT_FILES,
|
||||
} from '../../constants';
|
||||
import * as Rules from '../rules';
|
||||
import Plugin from '..';
|
||||
|
||||
// TODO(optimize): 需要优化错误处理,计算失败后需要抛出对应错误,以便程序处理
|
||||
function getFileFilter(storage) {
|
||||
@ -33,7 +33,7 @@ function getFileFilter(storage) {
|
||||
};
|
||||
}
|
||||
|
||||
function getFileData(ctx: Context) {
|
||||
export function getFileData(ctx: Context) {
|
||||
const { [FILE_FIELD_NAME]: file, storage } = ctx;
|
||||
if (!file) {
|
||||
return ctx.throw(400, 'file validation failed');
|
||||
|
@ -7,29 +7,77 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { resolve } from 'path';
|
||||
|
||||
import { Plugin } from '@nocobase/server';
|
||||
import { Registry } from '@nocobase/utils';
|
||||
|
||||
import { basename, resolve } from 'path';
|
||||
|
||||
import { Transactionable } from '@nocobase/database';
|
||||
import fs from 'fs';
|
||||
import { STORAGE_TYPE_ALI_OSS, STORAGE_TYPE_LOCAL, STORAGE_TYPE_S3, STORAGE_TYPE_TX_COS } from '../constants';
|
||||
import { FileModel } from './FileModel';
|
||||
import initActions from './actions';
|
||||
import { getFileData } from './actions/attachments';
|
||||
import { AttachmentInterface } from './interfaces/attachment-interface';
|
||||
import { IStorage, StorageModel } from './storages';
|
||||
import { STORAGE_TYPE_ALI_OSS, STORAGE_TYPE_LOCAL, STORAGE_TYPE_S3, STORAGE_TYPE_TX_COS } from '../constants';
|
||||
import StorageTypeLocal from './storages/local';
|
||||
import StorageTypeAliOss from './storages/ali-oss';
|
||||
import StorageTypeLocal from './storages/local';
|
||||
import StorageTypeS3 from './storages/s3';
|
||||
import StorageTypeTxCos from './storages/tx-cos';
|
||||
import { AttachmentInterface } from './interfaces/attachment-interface';
|
||||
|
||||
export type * from './storages';
|
||||
|
||||
const DEFAULT_STORAGE_TYPE = STORAGE_TYPE_LOCAL;
|
||||
|
||||
export type FileRecordOptions = {
|
||||
collection: string;
|
||||
filePath: string;
|
||||
} & Transactionable;
|
||||
|
||||
export default class PluginFileManagerServer extends Plugin {
|
||||
storageTypes = new Registry<IStorage>();
|
||||
storagesCache = new Map<number, StorageModel>();
|
||||
|
||||
async createFileRecord(options: FileRecordOptions) {
|
||||
const { collection, filePath, transaction } = options;
|
||||
const storageRepository = this.db.getRepository('storages');
|
||||
const collectionRepository = this.db.getRepository(collection);
|
||||
const storage = await storageRepository.findOne();
|
||||
|
||||
const fileStream = fs.createReadStream(filePath);
|
||||
|
||||
if (!storage) {
|
||||
throw new Error('[file-manager] no linked or default storage provided');
|
||||
}
|
||||
|
||||
const storageConfig = this.storageTypes.get(storage.type);
|
||||
|
||||
if (!storageConfig) {
|
||||
throw new Error(`[file-manager] storage type "${storage.type}" is not defined`);
|
||||
}
|
||||
|
||||
const engine = storageConfig.make(storage);
|
||||
|
||||
const file = {
|
||||
originalname: basename(filePath),
|
||||
path: filePath,
|
||||
stream: fileStream,
|
||||
} as any;
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
engine._handleFile({} as any, file, (error, info) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
Object.assign(file, info);
|
||||
resolve(info);
|
||||
});
|
||||
});
|
||||
|
||||
const values = getFileData({ app: this.app, file, storage, request: { body: {} } } as any);
|
||||
return await collectionRepository.create({ values, transaction });
|
||||
}
|
||||
|
||||
async loadStorages(options?: { transaction: any }) {
|
||||
const repository = this.db.getRepository('storages');
|
||||
const storages = await repository.find({
|
||||
|
Loading…
Reference in New Issue
Block a user