mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 05:29:26 +08:00
* chore: export xlsx command * chore: container service * chore: report export progress * chore: export * chore: performInsert * chore: export command * chore: base exporter * chore: limit option * chore: export * chore: export * chore: types * chore: ws socket with auth * refactor: refactor exporter, change addRows method to handleRow method to support row-by-row processing * chore: xlsx exporter * chore: base exporter * chore: export limit * chore: import action * chore: load websocket * chore: import action * chore: object to cli args * chore: import options * chore: import action * chore: import runner * chore: import action * chore: import options * chore: import options * chore: plugin load event * chore: test * chore: i18n * chore: i18n * chore: i18n * fix: ws auth status * chore: cache in data source * chore: load datasource * chore: import with field alias * fix: build * fix: test * fix: build * fix: import schema settings * fix: import action * fix: import progress * chore: template creator * fix: import error message * fix: import error message * chore: test * chore: workflow dispatch event * chore: export alias * fix: typo * chore: error render * fix: event error * chore: send message to tags * fix: test * fix: import action setting
194 lines
5.7 KiB
TypeScript
194 lines
5.7 KiB
TypeScript
/**
|
|
* This file is part of the NocoBase (R) project.
|
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
* Authors: NocoBase Team.
|
|
*
|
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
*/
|
|
|
|
import { Model, Transaction } from '@nocobase/database';
|
|
import { Application } from '@nocobase/server';
|
|
import { setCurrentRole } from '@nocobase/plugin-acl';
|
|
import { ACL, AvailableActionOptions } from '@nocobase/acl';
|
|
import { DataSourcesRolesModel } from './data-sources-roles-model';
|
|
import PluginDataSourceManagerServer from '../plugin';
|
|
import * as path from 'path';
|
|
|
|
const availableActions: {
|
|
[key: string]: AvailableActionOptions;
|
|
} = {
|
|
create: {
|
|
displayName: '{{t("Add new")}}',
|
|
type: 'new-data',
|
|
onNewRecord: true,
|
|
allowConfigureFields: true,
|
|
},
|
|
// import: {
|
|
// displayName: '{{t("Import")}}',
|
|
// type: 'new-data',
|
|
// scope: false,
|
|
// },
|
|
// export: {
|
|
// displayName: '{{t("Export")}}',
|
|
// type: 'old-data',
|
|
// allowConfigureFields: true,
|
|
// },
|
|
view: {
|
|
displayName: '{{t("View")}}',
|
|
type: 'old-data',
|
|
aliases: ['get', 'list'],
|
|
allowConfigureFields: true,
|
|
},
|
|
update: {
|
|
displayName: '{{t("Edit")}}',
|
|
type: 'old-data',
|
|
aliases: ['update', 'move'],
|
|
allowConfigureFields: true,
|
|
},
|
|
destroy: {
|
|
displayName: '{{t("Delete")}}',
|
|
type: 'old-data',
|
|
},
|
|
};
|
|
|
|
export class DataSourceModel extends Model {
|
|
isMainRecord() {
|
|
return this.get('type') === 'main';
|
|
}
|
|
|
|
async loadIntoACL(options: { app: Application; acl: ACL; transaction?: Transaction }) {
|
|
const { app, acl } = options;
|
|
const loadRoleIntoACL = async (model: DataSourcesRolesModel) => {
|
|
await model.writeToAcl({
|
|
acl,
|
|
});
|
|
};
|
|
|
|
const rolesModel: DataSourcesRolesModel[] = await app.db.getRepository('dataSourcesRoles').find({
|
|
transaction: options.transaction,
|
|
filter: {
|
|
dataSourceKey: this.get('key'),
|
|
},
|
|
});
|
|
|
|
for (const roleModel of rolesModel) {
|
|
await loadRoleIntoACL(roleModel);
|
|
}
|
|
}
|
|
|
|
async loadIntoApplication(options: { app: Application; transaction?: Transaction; loadAtAfterStart?: boolean }) {
|
|
const { app, loadAtAfterStart } = options;
|
|
|
|
const dataSourceKey = this.get('key');
|
|
|
|
const pluginDataSourceManagerServer = app.pm.get('data-source-manager') as PluginDataSourceManagerServer;
|
|
|
|
if (pluginDataSourceManagerServer.dataSourceStatus[dataSourceKey] === 'loaded') {
|
|
pluginDataSourceManagerServer.dataSourceStatus[dataSourceKey] = 'reloading';
|
|
} else {
|
|
pluginDataSourceManagerServer.dataSourceStatus[dataSourceKey] = 'loading';
|
|
}
|
|
|
|
const type = this.get('type');
|
|
const createOptions = this.get('options');
|
|
|
|
try {
|
|
const dataSource = app.dataSourceManager.factory.create(type, {
|
|
...createOptions,
|
|
name: dataSourceKey,
|
|
logger: app.logger.child({ dataSourceKey }),
|
|
sqlLogger: app.sqlLogger.child({ dataSourceKey }),
|
|
cache: app.cache,
|
|
storagePath: path.join(process.cwd(), 'storage', 'cache', 'apps', app.name),
|
|
});
|
|
|
|
dataSource.on('loadingProgress', (progress) => {
|
|
pluginDataSourceManagerServer.dataSourceLoadingProgress[dataSourceKey] = progress;
|
|
});
|
|
|
|
if (loadAtAfterStart) {
|
|
dataSource.on('loadMessage', ({ message }) => {
|
|
app.setMaintainingMessage(`${message} in data source ${this.get('displayName')}`);
|
|
});
|
|
}
|
|
|
|
const acl = dataSource.acl;
|
|
|
|
for (const [actionName, actionParams] of Object.entries(availableActions)) {
|
|
acl.setAvailableAction(actionName, actionParams);
|
|
}
|
|
|
|
acl.allow('*', '*', (ctx) => {
|
|
return ctx.state.currentRole === 'root';
|
|
});
|
|
|
|
dataSource.resourceManager.use(setCurrentRole, { tag: 'setCurrentRole', before: 'acl', after: 'auth' });
|
|
|
|
await this.loadIntoACL({ app, acl, transaction: options.transaction });
|
|
|
|
await app.dataSourceManager.add(dataSource, {
|
|
localData: await this.loadLocalData(),
|
|
});
|
|
} catch (e) {
|
|
app.logger.error(`load data source failed`, { cause: e });
|
|
|
|
if (pluginDataSourceManagerServer.dataSourceStatus[dataSourceKey] === 'loading') {
|
|
pluginDataSourceManagerServer.dataSourceStatus[dataSourceKey] = 'loading-failed';
|
|
}
|
|
|
|
if (pluginDataSourceManagerServer.dataSourceStatus[dataSourceKey] === 'reloading') {
|
|
pluginDataSourceManagerServer.dataSourceStatus[dataSourceKey] = 'reloading-failed';
|
|
}
|
|
|
|
pluginDataSourceManagerServer.dataSourceErrors[dataSourceKey] = e;
|
|
return;
|
|
}
|
|
|
|
pluginDataSourceManagerServer.dataSourceStatus[dataSourceKey] = 'loaded';
|
|
}
|
|
|
|
private async loadLocalData() {
|
|
const dataSourceKey = this.get('key');
|
|
|
|
const remoteCollections = await this.db.getRepository('dataSourcesCollections').find({
|
|
filter: {
|
|
dataSourceKey,
|
|
},
|
|
});
|
|
|
|
const remoteFields = await this.db.getRepository('dataSourcesFields').find({
|
|
filter: {
|
|
dataSourceKey,
|
|
},
|
|
});
|
|
|
|
const localData = {};
|
|
|
|
for (const remoteCollection of remoteCollections) {
|
|
const remoteCollectionOptions = remoteCollection.toJSON();
|
|
localData[remoteCollectionOptions.name] = remoteCollectionOptions;
|
|
}
|
|
|
|
for (const remoteField of remoteFields) {
|
|
const remoteFieldOptions = remoteField.toJSON();
|
|
const collectionName = remoteFieldOptions.collectionName;
|
|
|
|
if (!localData[collectionName]) {
|
|
localData[collectionName] = {
|
|
name: collectionName,
|
|
fields: [],
|
|
};
|
|
}
|
|
|
|
if (!localData[collectionName].fields) {
|
|
localData[collectionName].fields = [];
|
|
}
|
|
|
|
localData[collectionName].fields.push(remoteFieldOptions);
|
|
}
|
|
|
|
return localData;
|
|
}
|
|
}
|