@nocobase/plugin-verification 0.9.0-alpha.1 → 0.9.1-alpha.1

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.
Files changed (32) hide show
  1. package/README.md +9 -0
  2. package/README.zh-CN.md +9 -0
  3. package/lib/client/locale/index.js +7 -12
  4. package/lib/client/locale/zh-CN.d.ts +6 -0
  5. package/lib/client/locale/zh-CN.js +7 -1
  6. package/lib/client/providerTypes/index.js +3 -0
  7. package/lib/client/providerTypes/sms-tencent.d.ts +57 -0
  8. package/lib/client/providerTypes/sms-tencent.js +58 -0
  9. package/lib/client/schemas/providers.js +3 -0
  10. package/lib/server/actions/verifications.js +1 -6
  11. package/lib/server/collections/verifications.d.ts +2 -0
  12. package/lib/server/collections/verifications.js +2 -0
  13. package/lib/server/collections/verifications_providers.d.ts +2 -0
  14. package/lib/server/collections/verifications_providers.js +2 -0
  15. package/lib/server/constants.d.ts +1 -0
  16. package/lib/server/constants.js +3 -1
  17. package/lib/server/providers/index.js +1 -1
  18. package/lib/server/providers/sms-tencent.d.ts +10 -0
  19. package/lib/server/providers/sms-tencent.js +94 -0
  20. package/package.json +8 -7
  21. package/src/client/locale/index.ts +2 -3
  22. package/src/client/locale/zh-CN.ts +7 -0
  23. package/src/client/providerTypes/index.ts +2 -0
  24. package/src/client/providerTypes/sms-tencent.ts +52 -0
  25. package/src/client/schemas/providers.ts +1 -0
  26. package/src/server/actions/verifications.ts +3 -8
  27. package/src/server/collections/verifications.ts +2 -0
  28. package/src/server/collections/verifications_providers.ts +2 -0
  29. package/src/server/constants.ts +1 -0
  30. package/src/server/locale/zh-CN.ts +1 -1
  31. package/src/server/providers/index.ts +6 -5
  32. package/src/server/providers/sms-tencent.ts +57 -0
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # verification
2
+
3
+ English | [中文](./README.zh-CN.md)
4
+
5
+ ## 安装激活
6
+
7
+ 内置插件无需手动安装激活。
8
+
9
+ ## 使用方法
@@ -0,0 +1,9 @@
1
+ # verification
2
+
3
+ [English](./README.md) | 中文
4
+
5
+ ## 安装激活
6
+
7
+ 内置插件无需手动安装激活。
8
+
9
+ ## 使用方法
@@ -7,35 +7,30 @@ exports.NAMESPACE = void 0;
7
7
  exports.lang = lang;
8
8
  exports.useVerificationTranslation = useVerificationTranslation;
9
9
 
10
- function _reactI18next() {
11
- const data = require("react-i18next");
10
+ function _client() {
11
+ const data = require("@nocobase/client");
12
12
 
13
- _reactI18next = function _reactI18next() {
13
+ _client = function _client() {
14
14
  return data;
15
15
  };
16
16
 
17
17
  return data;
18
18
  }
19
19
 
20
- function _client() {
21
- const data = require("@nocobase/client");
20
+ function _reactI18next() {
21
+ const data = require("react-i18next");
22
22
 
23
- _client = function _client() {
23
+ _reactI18next = function _reactI18next() {
24
24
  return data;
25
25
  };
26
26
 
27
27
  return data;
28
28
  }
29
29
 
30
- var _zhCN = _interopRequireDefault(require("./zh-CN"));
31
-
32
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
30
+ const NAMESPACE = 'verification'; // i18n.addResources('zh-CN', NAMESPACE, zhCN);
33
31
 
34
- const NAMESPACE = 'verification';
35
32
  exports.NAMESPACE = NAMESPACE;
36
33
 
37
- _client().i18n.addResources('zh-CN', NAMESPACE, _zhCN.default);
38
-
39
34
  function lang(key) {
40
35
  return _client().i18n.t(key, {
41
36
  ns: NAMESPACE
@@ -8,5 +8,11 @@ declare const _default: {
8
8
  Endpoint: string;
9
9
  Sign: string;
10
10
  'Template code': string;
11
+ 'Secret Id': string;
12
+ 'Secret Key': string;
13
+ Region: string;
14
+ 'Sign name': string;
15
+ 'Sms sdk app id': string;
16
+ 'Template Id': string;
11
17
  };
12
18
  export default _default;
@@ -14,6 +14,12 @@ var _default = {
14
14
  'Access Key Secret': 'Access Key Secret',
15
15
  'Endpoint': '接入点',
16
16
  'Sign': '签名',
17
- 'Template code': '模板代码'
17
+ 'Template code': '模板代码',
18
+ 'Secret Id': 'Secret Id',
19
+ 'Secret Key': 'Secret Key',
20
+ 'Region': '地域',
21
+ 'Sign name': '短信签名内容',
22
+ 'Sms sdk app id': '短信应用 ID',
23
+ 'Template Id': '短信模板 ID'
18
24
  };
19
25
  exports.default = _default;
@@ -17,9 +17,12 @@ function _client() {
17
17
 
18
18
  var _smsAliyun = _interopRequireDefault(require("./sms-aliyun"));
19
19
 
20
+ var _smsTencent = _interopRequireDefault(require("./sms-tencent"));
21
+
20
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
23
 
22
24
  const providerTypes = new (_client().Registry)();
23
25
  providerTypes.register('sms-aliyun', _smsAliyun.default);
26
+ providerTypes.register('sms-tencent', _smsTencent.default);
24
27
  var _default = providerTypes;
25
28
  exports.default = _default;
@@ -0,0 +1,57 @@
1
+ declare const _default: import("@formily/react").Stringify<{
2
+ [key: symbol]: any;
3
+ [key: `x-${string}`]: any;
4
+ [key: `x-${number}`]: any;
5
+ version?: string;
6
+ name?: import("@formily/react").SchemaKey;
7
+ title?: any;
8
+ description?: any;
9
+ default?: any;
10
+ readOnly?: boolean;
11
+ writeOnly?: boolean;
12
+ type?: import("@formily/react").SchemaTypes;
13
+ enum?: import("@formily/react").SchemaEnum<any>;
14
+ const?: any;
15
+ multipleOf?: number;
16
+ maximum?: number;
17
+ exclusiveMaximum?: number;
18
+ minimum?: number;
19
+ exclusiveMinimum?: number;
20
+ maxLength?: number;
21
+ minLength?: number;
22
+ pattern?: string | RegExp;
23
+ maxItems?: number;
24
+ minItems?: number;
25
+ uniqueItems?: boolean;
26
+ maxProperties?: number;
27
+ minProperties?: number;
28
+ required?: string | boolean | string[];
29
+ format?: string;
30
+ $ref?: string;
31
+ $namespace?: string;
32
+ definitions?: import("@formily/react").SchemaProperties<any, any, any, any, any, any, any, any>;
33
+ properties?: import("@formily/react").SchemaProperties<any, any, any, any, any, any, any, any>;
34
+ items?: import("@formily/react").SchemaItems<any, any, any, any, any, any, any, any>;
35
+ additionalItems?: import("@formily/react").Stringify<any>;
36
+ patternProperties?: import("@formily/react").SchemaProperties<any, any, any, any, any, any, any, any>;
37
+ additionalProperties?: import("@formily/react").Stringify<any>;
38
+ "x-value"?: any;
39
+ "x-index"?: number;
40
+ "x-pattern"?: any;
41
+ "x-display"?: any;
42
+ "x-validator"?: any;
43
+ "x-decorator"?: any;
44
+ "x-decorator-props"?: any;
45
+ "x-component"?: any;
46
+ "x-component-props"?: any;
47
+ "x-reactions"?: import("@formily/react").SchemaReactions<any>;
48
+ "x-content"?: any;
49
+ "x-data"?: any;
50
+ "x-visible"?: boolean;
51
+ "x-hidden"?: boolean;
52
+ "x-disabled"?: boolean;
53
+ "x-editable"?: boolean;
54
+ "x-read-only"?: boolean;
55
+ "x-read-pretty"?: boolean;
56
+ }>;
57
+ export default _default;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _locale = require("../locale");
9
+
10
+ var _default = {
11
+ type: 'object',
12
+ properties: {
13
+ secretId: {
14
+ title: `{{t("Secret Id", { ns: "${_locale.NAMESPACE}" })}}`,
15
+ type: 'string',
16
+ 'x-decorator': 'FormItem',
17
+ 'x-component': 'Input'
18
+ },
19
+ secretKey: {
20
+ title: `{{t("Secret Key", { ns: "${_locale.NAMESPACE}" })}}`,
21
+ type: 'string',
22
+ 'x-decorator': 'FormItem',
23
+ 'x-component': 'Password'
24
+ },
25
+ region: {
26
+ title: `{{t("Region", { ns: "${_locale.NAMESPACE}" })}}`,
27
+ type: 'string',
28
+ 'x-decorator': 'FormItem',
29
+ 'x-component': 'Input'
30
+ },
31
+ endpoint: {
32
+ title: `{{t("Endpoint", { ns: "${_locale.NAMESPACE}" })}}`,
33
+ type: 'string',
34
+ 'x-decorator': 'FormItem',
35
+ 'x-component': 'Input',
36
+ default: 'sms.tencentcloudapi.com'
37
+ },
38
+ SignName: {
39
+ title: `{{t("Sign name", { ns: "${_locale.NAMESPACE}" })}}`,
40
+ type: 'string',
41
+ 'x-decorator': 'FormItem',
42
+ 'x-component': 'Input'
43
+ },
44
+ SmsSdkAppId: {
45
+ title: `{{t("Sms sdk app id", { ns: "${_locale.NAMESPACE}" })}}`,
46
+ type: 'string',
47
+ 'x-decorator': 'FormItem',
48
+ 'x-component': 'Input'
49
+ },
50
+ TemplateId: {
51
+ title: `{{t("Template Id", { ns: "${_locale.NAMESPACE}" })}}`,
52
+ type: 'string',
53
+ 'x-decorator': 'FormItem',
54
+ 'x-component': 'Input'
55
+ }
56
+ }
57
+ };
58
+ exports.default = _default;
@@ -67,6 +67,9 @@ const collection = {
67
67
  enum: [{
68
68
  label: `{{t("Aliyun SMS", { ns: "${_locale.NAMESPACE}" })}}`,
69
69
  value: 'sms-aliyun'
70
+ }, {
71
+ label: `{{t("Tencent SMS", { ns: "${_locale.NAMESPACE}" })}}`,
72
+ value: 'sms-tencent'
70
73
  }]
71
74
  }
72
75
  }, {
@@ -83,12 +83,7 @@ function _create() {
83
83
  return context.throw(400, 'Invalid action type');
84
84
  }
85
85
 
86
- const ProviderRepo = context.db.getRepository('verifications_providers');
87
- const providerItem = yield ProviderRepo.findOne({
88
- filter: {
89
- default: true
90
- }
91
- });
86
+ const providerItem = yield plugin.getDefault();
92
87
 
93
88
  if (!providerItem) {
94
89
  console.error(`[verification] no provider for action (${values.type}) provided`);
@@ -1,4 +1,6 @@
1
1
  declare const _default: {
2
+ namespace: string;
3
+ duplicator: string;
2
4
  name: string;
3
5
  fields: ({
4
6
  type: string;
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _default = {
8
+ namespace: 'verification',
9
+ duplicator: 'optional',
8
10
  name: 'verifications',
9
11
  fields: [{
10
12
  type: 'uuid',
@@ -1,4 +1,6 @@
1
1
  declare const _default: {
2
+ namespace: string;
3
+ duplicator: string;
2
4
  name: string;
3
5
  fields: ({
4
6
  type: string;
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _default = {
8
+ namespace: 'verification',
9
+ duplicator: 'optional',
8
10
  name: 'verifications_providers',
9
11
  fields: [{
10
12
  type: 'string',
@@ -1,3 +1,4 @@
1
1
  export declare const PROVIDER_TYPE_SMS_ALIYUN = "sms-aliyun";
2
+ export declare const PROVIDER_TYPE_SMS_TENCENT = "sms-tencent";
2
3
  export declare const CODE_STATUS_UNUSED = 0;
3
4
  export declare const CODE_STATUS_USED = 1;
@@ -3,9 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.PROVIDER_TYPE_SMS_ALIYUN = exports.CODE_STATUS_USED = exports.CODE_STATUS_UNUSED = void 0;
6
+ exports.PROVIDER_TYPE_SMS_TENCENT = exports.PROVIDER_TYPE_SMS_ALIYUN = exports.CODE_STATUS_USED = exports.CODE_STATUS_UNUSED = void 0;
7
7
  const PROVIDER_TYPE_SMS_ALIYUN = 'sms-aliyun';
8
8
  exports.PROVIDER_TYPE_SMS_ALIYUN = PROVIDER_TYPE_SMS_ALIYUN;
9
+ const PROVIDER_TYPE_SMS_TENCENT = 'sms-tencent';
10
+ exports.PROVIDER_TYPE_SMS_TENCENT = PROVIDER_TYPE_SMS_TENCENT;
9
11
  const CODE_STATUS_UNUSED = 0;
10
12
  exports.CODE_STATUS_UNUSED = CODE_STATUS_UNUSED;
11
13
  const CODE_STATUS_USED = 1;
@@ -70,7 +70,7 @@ exports.Provider = Provider;
70
70
 
71
71
  function _default(plugin, more = {}) {
72
72
  const providers = plugin.providers;
73
- const natives = [_constants.PROVIDER_TYPE_SMS_ALIYUN].reduce((result, key) => Object.assign(result, {
73
+ const natives = [_constants.PROVIDER_TYPE_SMS_ALIYUN, _constants.PROVIDER_TYPE_SMS_TENCENT].reduce((result, key) => Object.assign(result, {
74
74
  [key]: (0, _utils().requireModule)(_path().default.isAbsolute(key) ? key : _path().default.join(__dirname, key))
75
75
  }), {});
76
76
 
@@ -0,0 +1,10 @@
1
+ import { Provider } from '.';
2
+ declare const smsClient: typeof import("tencentcloud-sdk-nodejs/tencentcloud/services/sms/v20210111/sms_client").Client;
3
+ export default class extends Provider {
4
+ client: InstanceType<typeof smsClient>;
5
+ constructor(plugin: any, options: any);
6
+ send(phoneNumbers: any, data: {
7
+ code: string;
8
+ }): Promise<string>;
9
+ }
10
+ export {};
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _ = require(".");
9
+
10
+ function tencentcloud() {
11
+ const data = _interopRequireWildcard(require("tencentcloud-sdk-nodejs"));
12
+
13
+ tencentcloud = function tencentcloud() {
14
+ return data;
15
+ };
16
+
17
+ return data;
18
+ }
19
+
20
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
21
+
22
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
23
+
24
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
25
+
26
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
27
+
28
+ // 导入对应产品模块的client models。
29
+ const smsClient = tencentcloud().sms.v20210111.Client;
30
+
31
+ class _default extends _.Provider {
32
+ constructor(plugin, options) {
33
+ super(plugin, options);
34
+ this.client = void 0;
35
+ const _this$options = this.options,
36
+ secretId = _this$options.secretId,
37
+ secretKey = _this$options.secretKey,
38
+ region = _this$options.region,
39
+ endpoint = _this$options.endpoint;
40
+ /* 实例化要请求产品(以sms为例)的client对象 */
41
+
42
+ this.client = new smsClient({
43
+ credential: {
44
+ secretId,
45
+ secretKey
46
+ },
47
+ region,
48
+ profile: {
49
+ httpProfile: {
50
+ endpoint
51
+ }
52
+ }
53
+ });
54
+ }
55
+
56
+ send(phoneNumbers, data) {
57
+ var _this = this;
58
+
59
+ return _asyncToGenerator(function* () {
60
+ const _this$options2 = _this.options,
61
+ SignName = _this$options2.SignName,
62
+ TemplateId = _this$options2.TemplateId,
63
+ SmsSdkAppId = _this$options2.SmsSdkAppId;
64
+ const result = yield _this.client.SendSms({
65
+ PhoneNumberSet: [phoneNumbers],
66
+ SignName,
67
+ TemplateId,
68
+ SmsSdkAppId,
69
+ TemplateParamSet: [data.code]
70
+ });
71
+ const errCode = result.SendStatusSet[0].Code;
72
+ const error = new Error(`${errCode}:${result.SendStatusSet[0].Message}`);
73
+
74
+ switch (errCode) {
75
+ case 'Ok':
76
+ return result.RequestId;
77
+
78
+ case 'InvalidParameterValue.IncorrectPhoneNumber':
79
+ error.name = 'InvalidReceiver';
80
+
81
+ case 'LimitExceeded.DeliveryFrequencyLimit':
82
+ case 'LimitExceeded.PhoneNumberDailyLimit':
83
+ case 'LimitExceeded.PhoneNumberThirtySecondLimit':
84
+ case 'LimitExceeded.PhoneNumberOneHourLimit':
85
+ error.name = 'RateLimit';
86
+ }
87
+
88
+ throw error;
89
+ })();
90
+ }
91
+
92
+ }
93
+
94
+ exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/plugin-verification",
3
- "version": "0.9.0-alpha.1",
3
+ "version": "0.9.1-alpha.1",
4
4
  "description": "",
5
5
  "license": "AGPL-3.0",
6
6
  "main": "./lib/index.js",
@@ -9,13 +9,14 @@
9
9
  "@alicloud/dysmsapi20170525": "2.0.17",
10
10
  "@alicloud/openapi-client": "0.4.1",
11
11
  "@alicloud/tea-util": "1.4.4",
12
- "@nocobase/actions": "0.9.0-alpha.1",
13
- "@nocobase/resourcer": "0.9.0-alpha.1",
14
- "@nocobase/server": "0.9.0-alpha.1",
15
- "@nocobase/utils": "0.9.0-alpha.1"
12
+ "@nocobase/actions": "0.9.1-alpha.1",
13
+ "@nocobase/resourcer": "0.9.1-alpha.1",
14
+ "@nocobase/server": "0.9.1-alpha.1",
15
+ "@nocobase/utils": "0.9.1-alpha.1",
16
+ "tencentcloud-sdk-nodejs": "^4.0.525"
16
17
  },
17
18
  "devDependencies": {
18
- "@nocobase/test": "0.9.0-alpha.1"
19
+ "@nocobase/test": "0.9.1-alpha.1"
19
20
  },
20
- "gitHead": "d84c2a47c42c2ffec4fbf317d53268952fbd58d7"
21
+ "gitHead": "56cb184b00dc383b853015d525bf6e79dea92169"
21
22
  }
@@ -1,11 +1,10 @@
1
- import { useTranslation } from 'react-i18next';
2
1
  import { i18n } from '@nocobase/client';
2
+ import { useTranslation } from 'react-i18next';
3
3
 
4
- import zhCN from './zh-CN';
5
4
 
6
5
  export const NAMESPACE = 'verification';
7
6
 
8
- i18n.addResources('zh-CN', NAMESPACE, zhCN);
7
+ // i18n.addResources('zh-CN', NAMESPACE, zhCN);
9
8
 
10
9
  export function lang(key: string) {
11
10
  return i18n.t(key, { ns: NAMESPACE });
@@ -10,4 +10,11 @@ export default {
10
10
  'Endpoint': '接入点',
11
11
  'Sign': '签名',
12
12
  'Template code': '模板代码',
13
+
14
+ 'Secret Id': 'Secret Id',
15
+ 'Secret Key': 'Secret Key',
16
+ 'Region': '地域',
17
+ 'Sign name': '短信签名内容',
18
+ 'Sms sdk app id': '短信应用 ID',
19
+ 'Template Id': '短信模板 ID'
13
20
  };
@@ -1,9 +1,11 @@
1
1
  import { ISchema } from '@formily/react';
2
2
  import { Registry } from "@nocobase/utils/client";
3
3
  import SMSAliyun from './sms-aliyun';
4
+ import SMSTencent from './sms-tencent';
4
5
 
5
6
  const providerTypes: Registry<ISchema> = new Registry();
6
7
 
7
8
  providerTypes.register('sms-aliyun', SMSAliyun);
9
+ providerTypes.register('sms-tencent', SMSTencent);
8
10
 
9
11
  export default providerTypes;
@@ -0,0 +1,52 @@
1
+ import { ISchema } from '@formily/react';
2
+
3
+ import { NAMESPACE } from '../locale';
4
+
5
+ export default {
6
+ type: 'object',
7
+ properties: {
8
+ secretId: {
9
+ title: `{{t("Secret Id", { ns: "${NAMESPACE}" })}}`,
10
+ type: 'string',
11
+ 'x-decorator': 'FormItem',
12
+ 'x-component': 'Input',
13
+ },
14
+ secretKey: {
15
+ title: `{{t("Secret Key", { ns: "${NAMESPACE}" })}}`,
16
+ type: 'string',
17
+ 'x-decorator': 'FormItem',
18
+ 'x-component': 'Password',
19
+ },
20
+ region: {
21
+ title: `{{t("Region", { ns: "${NAMESPACE}" })}}`,
22
+ type: 'string',
23
+ 'x-decorator': 'FormItem',
24
+ 'x-component': 'Input',
25
+ },
26
+ endpoint: {
27
+ title: `{{t("Endpoint", { ns: "${NAMESPACE}" })}}`,
28
+ type: 'string',
29
+ 'x-decorator': 'FormItem',
30
+ 'x-component': 'Input',
31
+ default: 'sms.tencentcloudapi.com',
32
+ },
33
+ SignName: {
34
+ title: `{{t("Sign name", { ns: "${NAMESPACE}" })}}`,
35
+ type: 'string',
36
+ 'x-decorator': 'FormItem',
37
+ 'x-component': 'Input',
38
+ },
39
+ SmsSdkAppId: {
40
+ title: `{{t("Sms sdk app id", { ns: "${NAMESPACE}" })}}`,
41
+ type: 'string',
42
+ 'x-decorator': 'FormItem',
43
+ 'x-component': 'Input',
44
+ },
45
+ TemplateId: {
46
+ title: `{{t("Template Id", { ns: "${NAMESPACE}" })}}`,
47
+ type: 'string',
48
+ 'x-decorator': 'FormItem',
49
+ 'x-component': 'Input',
50
+ }
51
+ }
52
+ } as ISchema;
@@ -38,6 +38,7 @@ const collection = {
38
38
  required: true,
39
39
  enum: [
40
40
  { label: `{{t("Aliyun SMS", { ns: "${NAMESPACE}" })}}`, value: 'sms-aliyun' },
41
+ { label: `{{t("Tencent SMS", { ns: "${NAMESPACE}" })}}`, value: 'sms-tencent' },
41
42
  ],
42
43
  },
43
44
  },
@@ -19,12 +19,7 @@ export async function create(context: Context, next: Next) {
19
19
  return context.throw(400, 'Invalid action type');
20
20
  }
21
21
 
22
- const ProviderRepo = context.db.getRepository('verifications_providers');
23
- const providerItem = await ProviderRepo.findOne({
24
- filter: {
25
- default: true
26
- }
27
- });
22
+ const providerItem = await plugin.getDefault()
28
23
  if (!providerItem) {
29
24
  console.error(`[verification] no provider for action (${values.type}) provided`);
30
25
  return context.throw(500);
@@ -32,7 +27,7 @@ export async function create(context: Context, next: Next) {
32
27
 
33
28
  const receiver = interceptor.getReceiver(context);
34
29
  if (!receiver) {
35
- return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', {ns: namespace }) });
30
+ return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', { ns: namespace }) });
36
31
  }
37
32
  const VerificationModel = context.db.getModel('verifications');
38
33
  const record = await VerificationModel.findOne({
@@ -70,7 +65,7 @@ export async function create(context: Context, next: Next) {
70
65
  switch (error.name) {
71
66
  case 'InvalidReceiver':
72
67
  // TODO: message should consider email and other providers, maybe use "receiver"
73
- return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', {ns: namespace })});
68
+ return context.throw(400, { code: 'InvalidReceiver', message: context.t('Not a valid cellphone number, please re-enter', { ns: namespace }) });
74
69
  case 'RateLimit':
75
70
  return context.throw(429, context.t('You are trying so frequently, please slow down', { ns: namespace }));
76
71
  default:
@@ -1,4 +1,6 @@
1
1
  export default {
2
+ namespace: 'verification',
3
+ duplicator: 'optional',
2
4
  name: 'verifications',
3
5
  fields: [
4
6
  {
@@ -1,4 +1,6 @@
1
1
  export default {
2
+ namespace: 'verification',
3
+ duplicator: 'optional',
2
4
  name: 'verifications_providers',
3
5
  fields: [
4
6
  {
@@ -1,4 +1,5 @@
1
1
  export const PROVIDER_TYPE_SMS_ALIYUN = 'sms-aliyun';
2
+ export const PROVIDER_TYPE_SMS_TENCENT = 'sms-tencent';
2
3
 
3
4
  export const CODE_STATUS_UNUSED = 0;
4
5
  export const CODE_STATUS_USED = 1;
@@ -3,5 +3,5 @@ export default {
3
3
  'Not a valid cellphone number, please re-enter': '不是有效的手机号,请重新输入',
4
4
  "Please don't retry in {{time}} seconds": '请 {{time}} 秒后再试',
5
5
  'You are trying so frequently, please slow down': '您的操作太频繁,请稍后再试',
6
- 'Verification code is invalid': '无效的验证码'
6
+ 'Verification code is invalid': '无效的验证码',
7
7
  };
@@ -3,25 +3,26 @@ import path from 'path';
3
3
  import { requireModule } from '@nocobase/utils';
4
4
 
5
5
  import Plugin from '../Plugin';
6
- import { PROVIDER_TYPE_SMS_ALIYUN } from '../constants';
6
+ import { PROVIDER_TYPE_SMS_ALIYUN, PROVIDER_TYPE_SMS_TENCENT } from '../constants';
7
7
 
8
8
 
9
9
 
10
10
  export class Provider {
11
- constructor(protected plugin: Plugin, protected options) {}
11
+ constructor(protected plugin: Plugin, protected options) { }
12
12
 
13
- async send(receiver: string, data: { [key: string]: any }): Promise<any>{}
13
+ async send(receiver: string, data: { [key: string]: any }): Promise<any> { }
14
14
  }
15
15
 
16
16
  interface Providers {
17
17
  [key: string]: typeof Provider
18
18
  }
19
19
 
20
- export default function(plugin: Plugin, more: Providers = {}) {
20
+ export default function (plugin: Plugin, more: Providers = {}) {
21
21
  const { providers } = plugin;
22
22
 
23
23
  const natives = [
24
- PROVIDER_TYPE_SMS_ALIYUN
24
+ PROVIDER_TYPE_SMS_ALIYUN,
25
+ PROVIDER_TYPE_SMS_TENCENT
25
26
  ].reduce((result, key) => Object.assign(result, {
26
27
  [key]: requireModule(path.isAbsolute(key) ? key : path.join(__dirname, key)) as typeof Provider
27
28
  }), {} as Providers);
@@ -0,0 +1,57 @@
1
+ import { Provider } from '.';
2
+ import * as tencentcloud from "tencentcloud-sdk-nodejs"
3
+
4
+ // 导入对应产品模块的client models。
5
+ const smsClient = tencentcloud.sms.v20210111.Client;
6
+
7
+ export default class extends Provider {
8
+ client: InstanceType<typeof smsClient>;
9
+
10
+ constructor(plugin, options) {
11
+ super(plugin, options);
12
+
13
+ const { secretId, secretKey, region, endpoint } = this.options;
14
+
15
+
16
+ /* 实例化要请求产品(以sms为例)的client对象 */
17
+ this.client = new smsClient({
18
+ credential: {
19
+ secretId,
20
+ secretKey
21
+ },
22
+ region,
23
+ profile: {
24
+ httpProfile: {
25
+ endpoint
26
+ },
27
+ },
28
+ })
29
+ }
30
+
31
+
32
+ async send(phoneNumbers, data: { code: string }) {
33
+ const { SignName, TemplateId, SmsSdkAppId } = this.options
34
+ const result = await this.client.SendSms({
35
+ PhoneNumberSet: [phoneNumbers],
36
+ SignName,
37
+ TemplateId,
38
+ SmsSdkAppId,
39
+ TemplateParamSet: [data.code]
40
+ })
41
+
42
+ const errCode = result.SendStatusSet[0].Code
43
+ const error = new Error(`${errCode}:${result.SendStatusSet[0].Message}`)
44
+ switch (errCode) {
45
+ case 'Ok':
46
+ return result.RequestId
47
+ case 'InvalidParameterValue.IncorrectPhoneNumber':
48
+ error.name = 'InvalidReceiver'
49
+ case 'LimitExceeded.DeliveryFrequencyLimit':
50
+ case 'LimitExceeded.PhoneNumberDailyLimit':
51
+ case 'LimitExceeded.PhoneNumberThirtySecondLimit':
52
+ case 'LimitExceeded.PhoneNumberOneHourLimit':
53
+ error.name = 'RateLimit'
54
+ }
55
+ throw error
56
+ }
57
+ }