mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-02 03:02:19 +08:00
Merge branch 'main' into feat/gantt-block
This commit is contained in:
commit
36089230e9
@ -50,7 +50,7 @@ async function listWithPagination(ctx: Context) {
|
||||
async function listWithNonPaged(ctx: Context) {
|
||||
const repository = getRepositoryFromParams(ctx);
|
||||
|
||||
const rows = await repository.find(findArgs(ctx.action.params));
|
||||
const rows = await repository.find({ context: ctx, ...findArgs(ctx.action.params) });
|
||||
|
||||
ctx.body = rows;
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ module.exports = (cli) => {
|
||||
...process.argv.slice(3),
|
||||
`--port=${serverPort}`,
|
||||
];
|
||||
|
||||
if (opts.dbSync) {
|
||||
argv.push('--db-sync');
|
||||
}
|
||||
|
@ -244,8 +244,8 @@ export const useACLFieldWhitelist = () => {
|
||||
if (!fieldSchema['x-collection-field']) {
|
||||
return true;
|
||||
}
|
||||
const [, ...keys] = fieldSchema['x-collection-field'].split('.');
|
||||
return whitelist?.includes(keys.join('.'));
|
||||
const [key1, key2] = fieldSchema['x-collection-field'].split('.');
|
||||
return whitelist?.includes(key2 || key1);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -251,6 +251,7 @@ export const AddFieldAction = (props) => {
|
||||
useCancelAction,
|
||||
createOnly: true,
|
||||
isOverride: false,
|
||||
override: false,
|
||||
useCreateCollectionField,
|
||||
record,
|
||||
showReverseFieldConfig: true,
|
||||
|
@ -85,7 +85,7 @@ export const ConfigurationTable = () => {
|
||||
?.filter((item) => !(item.autoCreate && item.isThrough))
|
||||
.filter((item) =>
|
||||
targetScope
|
||||
? targetScope['template']?.includes(item.template) || targetScope['name']?.includes(item.name)
|
||||
? targetScope['template']?.includes(item.template) || targetScope[field.props.name]?.includes(item.name)
|
||||
: true,
|
||||
)
|
||||
.map((item: any) => ({
|
||||
|
@ -128,23 +128,26 @@ const getIsOverriding = (currentFields, record) => {
|
||||
};
|
||||
export const OverridingFieldAction = (props) => {
|
||||
const { scope, getContainer, item: record, children, currentCollection } = props;
|
||||
const { target } = record;
|
||||
const { target, through } = record;
|
||||
const { getInterface, getCurrentCollectionFields, getChildrenCollections } = useCollectionManager();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [schema, setSchema] = useState({});
|
||||
const api = useAPIClient();
|
||||
const { t } = useTranslation();
|
||||
const compile = useCompile();
|
||||
const getFilterCollections = (filterKey) => {
|
||||
const childCollections =
|
||||
target &&
|
||||
getChildrenCollections(target)
|
||||
filterKey &&
|
||||
getChildrenCollections(filterKey)
|
||||
?.map((v) => v.name)
|
||||
.concat([target]);
|
||||
.concat([filterKey]);
|
||||
return childCollections;
|
||||
};
|
||||
const [data, setData] = useState<any>({});
|
||||
const currentFields = getCurrentCollectionFields(currentCollection);
|
||||
const disabled = getIsOverriding(currentFields, record);
|
||||
return (
|
||||
<RecordProvider record={record}>
|
||||
<RecordProvider record={{ ...record, collectionName: record.__parent.name }}>
|
||||
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||
<a
|
||||
//@ts-ignore
|
||||
@ -189,8 +192,9 @@ export const OverridingFieldAction = (props) => {
|
||||
useCancelAction,
|
||||
showReverseFieldConfig: !data?.reverseField,
|
||||
createOnly: true,
|
||||
override: true,
|
||||
isOverride: true,
|
||||
targetScope: { name: childCollections },
|
||||
targetScope: { target: getFilterCollections(target), through: getFilterCollections(through) },
|
||||
...scope,
|
||||
}}
|
||||
/>
|
||||
|
@ -190,7 +190,7 @@ export const m2m: IField = {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-validator': 'uid',
|
||||
'x-disabled': '{{ !createOnly }}',
|
||||
'x-disabled': '{{ !createOnly||override }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -224,7 +224,7 @@ export const m2m: IField = {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-validator': 'uid',
|
||||
'x-disabled': '{{ !createOnly }}',
|
||||
'x-disabled': '{{ !createOnly||override }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -4,8 +4,11 @@ import { Layout, Spin } from 'antd';
|
||||
import React, { createContext, useContext, useMemo, useRef, useState } from 'react';
|
||||
import { useHistory, useRouteMatch } from 'react-router-dom';
|
||||
import {
|
||||
ACLRolesCheckProvider, CurrentAppInfoProvider, CurrentUser,
|
||||
CurrentUserProvider, findByUid,
|
||||
ACLRolesCheckProvider,
|
||||
CurrentAppInfoProvider,
|
||||
CurrentUser,
|
||||
CurrentUserProvider,
|
||||
findByUid,
|
||||
findMenuItem,
|
||||
RemoteCollectionManagerProvider,
|
||||
RemotePluginManagerToolbar,
|
||||
@ -15,7 +18,7 @@ import {
|
||||
useDocumentTitle,
|
||||
useRequest,
|
||||
useRoute,
|
||||
useSystemSettings
|
||||
useSystemSettings,
|
||||
} from '../../../';
|
||||
import { useCollectionManager } from '../../../collection-manager';
|
||||
|
||||
@ -161,12 +164,28 @@ export const InternalAdminLayout = (props: any) => {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
`}
|
||||
>
|
||||
<div
|
||||
style={{ position: 'relative', zIndex: 1, display: 'flex', height: '100%', width: 'calc(100vw - 300px)' }}
|
||||
className={css`
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
`}
|
||||
>
|
||||
<div
|
||||
className={css`
|
||||
width: 200px;
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
align-items: center;
|
||||
`}
|
||||
>
|
||||
<div style={{ width: 200, display: 'inline-flex', color: '#fff', padding: '0', alignItems: 'center' }}>
|
||||
<img
|
||||
className={css`
|
||||
padding: 0 16px;
|
||||
@ -176,17 +195,24 @@ export const InternalAdminLayout = (props: any) => {
|
||||
`}
|
||||
src={result?.data?.data?.logo?.url}
|
||||
/>
|
||||
{/* {result?.data?.data?.title} */}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: 'calc(100% - 590px)',
|
||||
}}
|
||||
className={css`
|
||||
flex: 1 1 auto;
|
||||
width: 0;
|
||||
`}
|
||||
>
|
||||
<MenuEditor sideMenuRef={sideMenuRef} />
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ position: 'absolute', height: '100%', zIndex: 10, top: 0, right: 0 }}>
|
||||
<div
|
||||
className={css`
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
`}
|
||||
>
|
||||
<RemotePluginManagerToolbar />
|
||||
<CurrentUser />
|
||||
</div>
|
||||
|
@ -4,6 +4,7 @@ import { Field } from '.';
|
||||
|
||||
export class InheritedCollection extends Collection {
|
||||
parents?: Collection[];
|
||||
|
||||
constructor(options: CollectionOptions, context: CollectionContext) {
|
||||
if (!options.inherits) {
|
||||
throw new Error('InheritedCollection must have inherits option');
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { InheritedCollection } from './inherited-collection';
|
||||
import lodash from 'lodash';
|
||||
import { Sequelize } from 'sequelize';
|
||||
|
||||
export class SyncRunner {
|
||||
static async syncInheritModel(model: any, options: any) {
|
||||
@ -42,8 +41,10 @@ export class SyncRunner {
|
||||
if (childAttributes.id && childAttributes.id.autoIncrement) {
|
||||
for (const parent of parentTables) {
|
||||
const sequenceNameResult = await queryInterface.sequelize.query(
|
||||
`SELECT column_default FROM information_schema.columns WHERE
|
||||
table_name='${parent}' and "column_name" = 'id';`,
|
||||
`SELECT column_default
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = '${parent}'
|
||||
and "column_name" = 'id';`,
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
@ -65,7 +66,8 @@ export class SyncRunner {
|
||||
const sequenceName = match[1];
|
||||
|
||||
const sequenceCurrentValResult = await queryInterface.sequelize.query(
|
||||
`select last_value from ${sequenceName}`,
|
||||
`select last_value
|
||||
from ${sequenceName}`,
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
@ -94,12 +96,12 @@ export class SyncRunner {
|
||||
|
||||
const idColumnQuery = await queryInterface.sequelize.query(
|
||||
`
|
||||
SELECT true
|
||||
FROM pg_attribute
|
||||
WHERE attrelid = '${queryName}'::regclass -- cast to a registered class (table)
|
||||
SELECT true
|
||||
FROM pg_attribute
|
||||
WHERE attrelid = '${queryName}'::regclass -- cast to a registered class (table)
|
||||
AND attname = 'id'
|
||||
AND NOT attisdropped
|
||||
`,
|
||||
`,
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
@ -110,7 +112,8 @@ AND NOT attisdropped
|
||||
}
|
||||
|
||||
await queryInterface.sequelize.query(
|
||||
`alter table "${sequenceTable}" alter column id set default nextval('${maxSequenceName}')`,
|
||||
`alter table "${sequenceTable}"
|
||||
alter column id set default nextval('${maxSequenceName}')`,
|
||||
{
|
||||
transaction,
|
||||
},
|
||||
|
@ -371,11 +371,13 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
process.exit(1);
|
||||
}
|
||||
await this.dbVersionCheck({ exit: true });
|
||||
|
||||
if (argv?.[2] !== 'upgrade') {
|
||||
await this.load({
|
||||
method: argv?.[2],
|
||||
});
|
||||
}
|
||||
|
||||
return this.cli.parseAsync(argv, options);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,8 @@
|
||||
"@nocobase/database": "0.9.0-alpha.2",
|
||||
"@nocobase/plugin-error-handler": "0.9.0-alpha.2",
|
||||
"@nocobase/server": "0.9.0-alpha.2",
|
||||
"sequelize": "^6.26.0"
|
||||
"sequelize": "^6.26.0",
|
||||
"toposort": "^2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nocobase/test": "0.9.0-alpha.2"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import Topo from '@hapi/topo';
|
||||
import { Model, Repository } from '@nocobase/database';
|
||||
import { Repository } from '@nocobase/database';
|
||||
import { CollectionModel } from '../models/collection';
|
||||
import toposort from 'toposort';
|
||||
|
||||
interface LoadOptions {
|
||||
filter?: any;
|
||||
@ -12,11 +12,14 @@ export class CollectionRepository extends Repository {
|
||||
const { filter, skipExist } = options;
|
||||
const instances = (await this.find({ filter })) as CollectionModel[];
|
||||
|
||||
const sorter = new Topo.Sorter<Model>();
|
||||
|
||||
const inheritedGraph = [];
|
||||
const throughModels = [];
|
||||
const generalModels = [];
|
||||
|
||||
const nameMap = {};
|
||||
|
||||
for (const instance of instances) {
|
||||
nameMap[instance.get('name')] = instance;
|
||||
// @ts-ignore
|
||||
const fields = await instance.getFields();
|
||||
for (const field of fields) {
|
||||
@ -28,29 +31,27 @@ export class CollectionRepository extends Repository {
|
||||
}
|
||||
}
|
||||
|
||||
const topoOptions = {
|
||||
group: instance.get('name'),
|
||||
};
|
||||
|
||||
if (instance.get('inherits')) {
|
||||
topoOptions['after'] = instance.get('inherits');
|
||||
for (const parent of instance.get('inherits')) {
|
||||
inheritedGraph.push([parent, instance.get('name')]);
|
||||
}
|
||||
} else {
|
||||
generalModels.push(instance.get('name'));
|
||||
}
|
||||
}
|
||||
|
||||
sorter.add(instance, topoOptions);
|
||||
}
|
||||
|
||||
const sorted = sorter.nodes;
|
||||
|
||||
sorted.sort((a, b) => {
|
||||
if (throughModels.includes(a.get('name'))) {
|
||||
generalModels.sort((a, b) => {
|
||||
if (throughModels.includes(a)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
for (const instance of sorted) {
|
||||
await instance.load({ skipExist });
|
||||
const sortedNames = [...toposort(inheritedGraph), ...generalModels];
|
||||
|
||||
for (const instanceName of sortedNames) {
|
||||
await nameMap[instanceName].load({ skipExist });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,63 @@
|
||||
import { mockServer, MockServer } from '@nocobase/test';
|
||||
import SnapshotFieldPlugin from '../server';
|
||||
import path from 'path';
|
||||
|
||||
describe('actions', () => {
|
||||
let app: MockServer;
|
||||
|
||||
beforeEach(async () => {
|
||||
app = mockServer({
|
||||
registerActions: true,
|
||||
acl: false,
|
||||
plugins: ['error-handler', 'users', 'ui-schema-storage', 'collection-manager'],
|
||||
});
|
||||
|
||||
app.plugin(SnapshotFieldPlugin, { name: 'snapshot-field' });
|
||||
|
||||
await app.loadAndInstall({ clean: true });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.cleanDb();
|
||||
await app.destroy();
|
||||
});
|
||||
|
||||
it.only('fieldsHistory collectionName and name conflict between tables', async () => {
|
||||
const agent = app.agent();
|
||||
|
||||
const field = {
|
||||
name: 'status',
|
||||
interface: 'input',
|
||||
type: 'string',
|
||||
uiSchema: { type: 'string', 'x-component': 'Input', title: 'status' },
|
||||
};
|
||||
|
||||
await agent.resource('collections').create({
|
||||
values: {
|
||||
name: 'table_a',
|
||||
template: 'general',
|
||||
fields: [field],
|
||||
title: 'table_a',
|
||||
},
|
||||
});
|
||||
|
||||
await agent.resource('collections').create({
|
||||
values: {
|
||||
name: 'table_b',
|
||||
template: 'general',
|
||||
fields: [field],
|
||||
title: 'table_b',
|
||||
},
|
||||
});
|
||||
|
||||
await agent.resource('collections.fields', 'table_b').destroy({
|
||||
filterByTk: 'status',
|
||||
});
|
||||
|
||||
const { statusCode } = await agent.resource('collections.fields', 'table_b').create({
|
||||
values: field,
|
||||
});
|
||||
|
||||
expect(statusCode).toBe(200);
|
||||
});
|
||||
});
|
@ -44,6 +44,7 @@ export class SnapshotFieldPlugin extends Plugin {
|
||||
const existField: Model = await fieldsHistoryRepository.findOne({
|
||||
filter: {
|
||||
name: fieldDoc.name,
|
||||
collectionName: fieldDoc.collectionName,
|
||||
},
|
||||
});
|
||||
if (existField) {
|
||||
|
@ -12,7 +12,8 @@
|
||||
"@nocobase/actions": "0.9.0-alpha.2",
|
||||
"@nocobase/resourcer": "0.9.0-alpha.2",
|
||||
"@nocobase/server": "0.9.0-alpha.2",
|
||||
"@nocobase/utils": "0.9.0-alpha.2"
|
||||
"@nocobase/utils": "0.9.0-alpha.2",
|
||||
"tencentcloud-sdk-nodejs": "^4.0.525"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nocobase/test": "0.9.0-alpha.2"
|
||||
|
@ -10,4 +10,11 @@ export default {
|
||||
'Endpoint': '接入点',
|
||||
'Sign': '签名',
|
||||
'Template code': '模板代码',
|
||||
|
||||
'Secret Id': 'Secret Id',
|
||||
'Secret Key': 'Secret Key',
|
||||
'Region': '地域',
|
||||
'Sign name': '短信签名内容',
|
||||
'Sms sdk app id': '短信应用 ID',
|
||||
'Template Id': '短信模板 ID'
|
||||
};
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
import { Registry } from "@nocobase/utils/client";
|
||||
import SMSAliyun from './sms-aliyun';
|
||||
import SMSTencent from './sms-tencent';
|
||||
|
||||
const providerTypes: Registry<ISchema> = new Registry();
|
||||
|
||||
providerTypes.register('sms-aliyun', SMSAliyun);
|
||||
providerTypes.register('sms-tencent', SMSTencent);
|
||||
|
||||
export default providerTypes;
|
||||
|
@ -0,0 +1,52 @@
|
||||
import { ISchema } from '@formily/react';
|
||||
|
||||
import { NAMESPACE } from '../locale';
|
||||
|
||||
export default {
|
||||
type: 'object',
|
||||
properties: {
|
||||
secretId: {
|
||||
title: `{{t("Secret Id", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'string',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
secretKey: {
|
||||
title: `{{t("Secret Key", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'string',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Password',
|
||||
},
|
||||
region: {
|
||||
title: `{{t("Region", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'string',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
endpoint: {
|
||||
title: `{{t("Endpoint", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'string',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
default: 'sms.tencentcloudapi.com',
|
||||
},
|
||||
SignName: {
|
||||
title: `{{t("Sign name", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'string',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
SmsSdkAppId: {
|
||||
title: `{{t("Sms sdk app id", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'string',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
TemplateId: {
|
||||
title: `{{t("Template Id", { ns: "${NAMESPACE}" })}}`,
|
||||
type: 'string',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
}
|
||||
}
|
||||
} as ISchema;
|
@ -38,6 +38,7 @@ const collection = {
|
||||
required: true,
|
||||
enum: [
|
||||
{ label: `{{t("Aliyun SMS", { ns: "${NAMESPACE}" })}}`, value: 'sms-aliyun' },
|
||||
{ label: `{{t("Tencent SMS", { ns: "${NAMESPACE}" })}}`, value: 'sms-tencent' },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -19,12 +19,7 @@ export async function create(context: Context, next: Next) {
|
||||
return context.throw(400, 'Invalid action type');
|
||||
}
|
||||
|
||||
const ProviderRepo = context.db.getRepository('verifications_providers');
|
||||
const providerItem = await ProviderRepo.findOne({
|
||||
filter: {
|
||||
default: true
|
||||
}
|
||||
});
|
||||
const providerItem = await plugin.getDefault()
|
||||
if (!providerItem) {
|
||||
console.error(`[verification] no provider for action (${values.type}) provided`);
|
||||
return context.throw(500);
|
||||
@ -32,7 +27,7 @@ export async function create(context: Context, next: Next) {
|
||||
|
||||
const receiver = interceptor.getReceiver(context);
|
||||
if (!receiver) {
|
||||
return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', {ns: namespace }) });
|
||||
return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', { ns: namespace }) });
|
||||
}
|
||||
const VerificationModel = context.db.getModel('verifications');
|
||||
const record = await VerificationModel.findOne({
|
||||
@ -70,7 +65,7 @@ export async function create(context: Context, next: Next) {
|
||||
switch (error.name) {
|
||||
case 'InvalidReceiver':
|
||||
// TODO: message should consider email and other providers, maybe use "receiver"
|
||||
return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', {ns: namespace })});
|
||||
return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', { ns: namespace }) });
|
||||
case 'RateLimit':
|
||||
return context.throw(429, context.t('You are trying so frequently, please slow down', { ns: namespace }));
|
||||
default:
|
||||
|
@ -1,4 +1,5 @@
|
||||
export const PROVIDER_TYPE_SMS_ALIYUN = 'sms-aliyun';
|
||||
export const PROVIDER_TYPE_SMS_TENCENT = 'sms-tencent';
|
||||
|
||||
export const CODE_STATUS_UNUSED = 0;
|
||||
export const CODE_STATUS_USED = 1;
|
||||
|
@ -3,5 +3,5 @@ export default {
|
||||
'Not a valid cellphone number, please re-enter': '不是有效的手机号,请重新输入',
|
||||
"Please don't retry in {{time}} seconds": '请 {{time}} 秒后再试',
|
||||
'You are trying so frequently, please slow down': '您的操作太频繁,请稍后再试',
|
||||
'Verification code is invalid': '无效的验证码'
|
||||
'Verification code is invalid': '无效的验证码',
|
||||
};
|
||||
|
@ -3,25 +3,26 @@ import path from 'path';
|
||||
import { requireModule } from '@nocobase/utils';
|
||||
|
||||
import Plugin from '../Plugin';
|
||||
import { PROVIDER_TYPE_SMS_ALIYUN } from '../constants';
|
||||
import { PROVIDER_TYPE_SMS_ALIYUN, PROVIDER_TYPE_SMS_TENCENT } from '../constants';
|
||||
|
||||
|
||||
|
||||
export class Provider {
|
||||
constructor(protected plugin: Plugin, protected options) {}
|
||||
constructor(protected plugin: Plugin, protected options) { }
|
||||
|
||||
async send(receiver: string, data: { [key: string]: any }): Promise<any>{}
|
||||
async send(receiver: string, data: { [key: string]: any }): Promise<any> { }
|
||||
}
|
||||
|
||||
interface Providers {
|
||||
[key: string]: typeof Provider
|
||||
}
|
||||
|
||||
export default function(plugin: Plugin, more: Providers = {}) {
|
||||
export default function (plugin: Plugin, more: Providers = {}) {
|
||||
const { providers } = plugin;
|
||||
|
||||
const natives = [
|
||||
PROVIDER_TYPE_SMS_ALIYUN
|
||||
PROVIDER_TYPE_SMS_ALIYUN,
|
||||
PROVIDER_TYPE_SMS_TENCENT
|
||||
].reduce((result, key) => Object.assign(result, {
|
||||
[key]: requireModule(path.isAbsolute(key) ? key : path.join(__dirname, key)) as typeof Provider
|
||||
}), {} as Providers);
|
||||
|
@ -0,0 +1,57 @@
|
||||
import { Provider } from '.';
|
||||
import * as tencentcloud from "tencentcloud-sdk-nodejs"
|
||||
|
||||
// 导入对应产品模块的client models。
|
||||
const smsClient = tencentcloud.sms.v20210111.Client;
|
||||
|
||||
export default class extends Provider {
|
||||
client: InstanceType<typeof smsClient>;
|
||||
|
||||
constructor(plugin, options) {
|
||||
super(plugin, options);
|
||||
|
||||
const { secretId, secretKey, region, endpoint } = this.options;
|
||||
|
||||
|
||||
/* 实例化要请求产品(以sms为例)的client对象 */
|
||||
this.client = new smsClient({
|
||||
credential: {
|
||||
secretId,
|
||||
secretKey
|
||||
},
|
||||
region,
|
||||
profile: {
|
||||
httpProfile: {
|
||||
endpoint
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
async send(phoneNumbers, data: { code: string }) {
|
||||
const { SignName, TemplateId, SmsSdkAppId } = this.options
|
||||
const result = await this.client.SendSms({
|
||||
PhoneNumberSet: [phoneNumbers],
|
||||
SignName,
|
||||
TemplateId,
|
||||
SmsSdkAppId,
|
||||
TemplateParamSet: [data.code]
|
||||
})
|
||||
|
||||
const errCode = result.SendStatusSet[0].Code
|
||||
const error = new Error(`${errCode}:${result.SendStatusSet[0].Message}`)
|
||||
switch (errCode) {
|
||||
case 'Ok':
|
||||
return result.RequestId
|
||||
case 'InvalidParameterValue.IncorrectPhoneNumber':
|
||||
error.name = 'InvalidReceiver'
|
||||
case 'LimitExceeded.DeliveryFrequencyLimit':
|
||||
case 'LimitExceeded.PhoneNumberDailyLimit':
|
||||
case 'LimitExceeded.PhoneNumberThirtySecondLimit':
|
||||
case 'LimitExceeded.PhoneNumberOneHourLimit':
|
||||
error.name = 'RateLimit'
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
@ -49,9 +49,12 @@ export default {
|
||||
'x-decorator': 'FormItem',
|
||||
'x-decorator-props': {
|
||||
className: css`
|
||||
.ant-formily-item-control-content-component .ant-input-affix-wrapper{
|
||||
.ant-formily-item-control-content-component{
|
||||
.ant-input-affix-wrapper,
|
||||
.ant-input{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`
|
||||
},
|
||||
'x-component': 'Input',
|
||||
|
@ -55,15 +55,15 @@ export class PresetNocoBase extends Plugin {
|
||||
}
|
||||
const version = await this.app.version.get();
|
||||
console.log(`The version number before upgrade is ${version}`);
|
||||
const result = await this.app.version.satisfies('<0.8.0-alpha.1');
|
||||
if (result) {
|
||||
const r = await this.db.collectionExistsInDb('applicationPlugins');
|
||||
if (r) {
|
||||
console.log(`Clear the installed application plugins`);
|
||||
await this.db.getRepository('applicationPlugins').destroy({ truncate: true });
|
||||
await this.app.reload({ method: options.method });
|
||||
}
|
||||
}
|
||||
// const result = await this.app.version.satisfies('<0.8.0-alpha.1');
|
||||
// if (result) {
|
||||
// const r = await this.db.collectionExistsInDb('applicationPlugins');
|
||||
// if (r) {
|
||||
// console.log(`Clear the installed application plugins`);
|
||||
// await this.db.getRepository('applicationPlugins').destroy({ truncate: true });
|
||||
// await this.app.reload({ method: options.method });
|
||||
// }
|
||||
// }
|
||||
});
|
||||
this.app.on('beforeUpgrade', async (options) => {
|
||||
const result = await this.app.version.satisfies('<0.8.0-alpha.1');
|
||||
|
97
yarn.lock
97
yarn.lock
@ -6442,7 +6442,14 @@
|
||||
resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
|
||||
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
|
||||
|
||||
"@types/react-dom@^16.9.8", "@types/react-dom@^17.0.0":
|
||||
"@types/react-dom@^16.9.8":
|
||||
version "16.9.17"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.17.tgz#29100cbcc422d7b7dba7de24bb906de56680dd34"
|
||||
integrity sha512-qSRyxEsrm5btPXnowDOs5jSkgT8ldAA0j6Qp+otHUh+xHzy3sXmgNfyhucZjAjkgpdAUw9rJe0QRtX/l+yaS4g==
|
||||
dependencies:
|
||||
"@types/react" "^16"
|
||||
|
||||
"@types/react-dom@^17.0.0":
|
||||
version "17.0.11"
|
||||
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466"
|
||||
integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==
|
||||
@ -6502,7 +6509,7 @@
|
||||
"@types/history" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@>=16.9.11", "@types/react@^16.9.43", "@types/react@^17.0.0":
|
||||
"@types/react@*", "@types/react@>=16.9.11", "@types/react@^17.0.0":
|
||||
version "17.0.34"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.34.tgz#797b66d359b692e3f19991b6b07e4b0c706c0102"
|
||||
integrity sha512-46FEGrMjc2+8XhHXILr+3+/sTe3OfzSPU9YGKILLrUYbQ1CLQC9Daqo1KzENGXAWwrFwiY0l4ZbF20gRvgpWTg==
|
||||
@ -6511,6 +6518,15 @@
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/react@^16", "@types/react@^16.9.43":
|
||||
version "16.14.34"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.34.tgz#d129324ffda312044e1c47aab18696e4ed493282"
|
||||
integrity sha512-b99nWeGGReLh6aKBppghVqp93dFJtgtDOzc8NXM6hewD8PQ2zZG5kBLgbx+VJr7Q7WBMjHxaIl3dwpwwPIUgyA==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/resolve@1.17.1":
|
||||
version "1.17.1"
|
||||
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
|
||||
@ -8953,7 +8969,7 @@ chalk@^1.1.1, chalk@^1.1.3, chalk@~1.1.3:
|
||||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1:
|
||||
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||
@ -9787,13 +9803,6 @@ copy-to-clipboard@^3.2.0:
|
||||
dependencies:
|
||||
toggle-selection "^1.0.6"
|
||||
|
||||
copy-to-clipboard@^3.3.1:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.npmmirror.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0"
|
||||
integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==
|
||||
dependencies:
|
||||
toggle-selection "^1.0.6"
|
||||
|
||||
copy-to@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5"
|
||||
@ -11090,13 +11099,6 @@ ee-first@1.1.1, ee-first@~1.1.1:
|
||||
resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||
|
||||
ejs@^3.1.8:
|
||||
version "3.1.8"
|
||||
resolved "https://registry.npmmirror.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b"
|
||||
integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==
|
||||
dependencies:
|
||||
jake "^10.8.5"
|
||||
|
||||
electron-to-chromium@^1.3.886:
|
||||
version "1.3.896"
|
||||
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.896.tgz#4a94efe4870b1687eafd5c378198a49da06e8a1b"
|
||||
@ -12122,13 +12124,6 @@ file-uri-to-path@2:
|
||||
resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba"
|
||||
integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==
|
||||
|
||||
filelist@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmmirror.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"
|
||||
integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==
|
||||
dependencies:
|
||||
minimatch "^5.0.1"
|
||||
|
||||
fill-range@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
|
||||
@ -14559,16 +14554,6 @@ istanbul-reports@^3.0.2:
|
||||
html-escaper "^2.0.0"
|
||||
istanbul-lib-report "^3.0.0"
|
||||
|
||||
jake@^10.8.5:
|
||||
version "10.8.5"
|
||||
resolved "https://registry.npmmirror.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46"
|
||||
integrity sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==
|
||||
dependencies:
|
||||
async "^3.2.3"
|
||||
chalk "^4.0.2"
|
||||
filelist "^1.0.1"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
javascript-natural-sort@^0.7.1:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.npmmirror.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
|
||||
@ -17036,13 +17021,6 @@ minimatch@^3.0.3, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^5.0.1:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7"
|
||||
integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimatch@^5.1.0:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.1.tgz#6c9dffcf9927ff2a31e74b5af11adf8b9604b022"
|
||||
@ -17491,6 +17469,13 @@ node-fetch@2.6.7, node-fetch@^2.6.7:
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.2.0:
|
||||
version "2.6.8"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.8.tgz#a68d30b162bc1d8fd71a367e81b997e1f4d4937e"
|
||||
integrity sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^2.6.1:
|
||||
version "2.6.6"
|
||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89"
|
||||
@ -20662,14 +20647,6 @@ react-contenteditable@^3.3.6:
|
||||
fast-deep-equal "^3.1.3"
|
||||
prop-types "^15.7.1"
|
||||
|
||||
react-copy-to-clipboard@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.npmmirror.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz#09aae5ec4c62750ccb2e6421a58725eabc41255c"
|
||||
integrity sha512-k61RsNgAayIJNoy9yDsYzDe/yAZAzEbEgcz3DZMhF686LEyukcE1hzurxe85JandPUG+yTfGVFzuEw3xt8WP/A==
|
||||
dependencies:
|
||||
copy-to-clipboard "^3.3.1"
|
||||
prop-types "^15.8.1"
|
||||
|
||||
react-docgen-typescript-dumi-tmp@^1.22.1-0:
|
||||
version "1.22.1-0"
|
||||
resolved "https://registry.npmjs.org/react-docgen-typescript-dumi-tmp/-/react-docgen-typescript-dumi-tmp-1.22.1-0.tgz#6f452de05c5c114a6e1dd60b34930afaa7ae39a0"
|
||||
@ -23287,6 +23264,18 @@ temp@^0.8.1:
|
||||
dependencies:
|
||||
rimraf "~2.6.2"
|
||||
|
||||
tencentcloud-sdk-nodejs@^4.0.525:
|
||||
version "4.0.525"
|
||||
resolved "https://registry.yarnpkg.com/tencentcloud-sdk-nodejs/-/tencentcloud-sdk-nodejs-4.0.525.tgz#b0b6d6caf6de5a5aeeda4f1f172ea7ecc447b9be"
|
||||
integrity sha512-Ym7DfnWsxtXpAd0sL3108dykO7q4hyTxrLeumPMHnzndGGWDqEcj6UMaZsylBOigYb2i423oJ5ePyPkDP5ot1g==
|
||||
dependencies:
|
||||
form-data "^3.0.0"
|
||||
get-stream "^6.0.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
is-stream "^2.0.0"
|
||||
node-fetch "^2.2.0"
|
||||
tslib "1.13.0"
|
||||
|
||||
term-size@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
|
||||
@ -23580,6 +23569,11 @@ toposort-class@^1.0.1:
|
||||
resolved "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988"
|
||||
integrity sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=
|
||||
|
||||
toposort@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
|
||||
integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==
|
||||
|
||||
tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
@ -23755,6 +23749,11 @@ tsconfig@^7.0.0:
|
||||
strip-bom "^3.0.0"
|
||||
strip-json-comments "^2.0.0"
|
||||
|
||||
tslib@1.13.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||
|
||||
tslib@1.9.3:
|
||||
version "1.9.3"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
|
||||
|
Loading…
x
Reference in New Issue
Block a user