阿里、腾讯、云片短信

This commit is contained in:
cool_team 2023-05-26 19:27:08 +08:00
parent 79a1fa05d3
commit b82c32f90d
22 changed files with 636 additions and 38 deletions

View File

@ -4,13 +4,13 @@
"description": "一个项目用COOL就够了",
"private": true,
"dependencies": {
"@alicloud/pop-core": "^1.7.12",
"@cool-midway/cloud": "^6.0.0",
"@cool-midway/core": "^6.0.6",
"@cool-midway/file": "^6.0.1",
"@cool-midway/iot": "^6.0.0",
"@cool-midway/pay": "^6.0.0",
"@cool-midway/rpc": "^6.0.1",
"@cool-midway/sms": "^6.0.1",
"@cool-midway/task": "^6.0.0",
"@midwayjs/bootstrap": "^3.11.4",
"@midwayjs/cache": "^3.11.5",
@ -36,6 +36,7 @@
"mysql2": "^3.2.4",
"svg-captcha": "^1.4.0",
"svg2png-wasm": "^1.3.4",
"tencentcloud-sdk-nodejs": "^4.0.607",
"typeorm": "^0.3.15",
"uuid": "^9.0.0"
},

View File

@ -0,0 +1,11 @@
# 🎨 editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

View File

@ -0,0 +1,28 @@
{
"extends": "./node_modules/mwts/",
"ignorePatterns": [
"node_modules",
"dist",
"test",
"jest.config.js",
"typings",
"public/**/**",
"view/**/**"
],
"env": {
"jest": true
},
"rules": {
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/ban-ts-comment": "off",
"node/no-extraneous-import": "off",
"no-empty": "off",
"node/no-extraneous-require": "off",
"eqeqeq": "off",
"node/no-unsupported-features/node-builtins": "off",
"@typescript-eslint/ban-types": "off",
"no-control-regex": "off",
"prefer-const": "off"
}
}

15
packages/sms/.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
logs/
npm-debug.log
yarn-error.log
node_modules/
package-lock.json
yarn.lock
coverage/
dist/
.idea/
run/
.DS_Store
*.sw*
*.un~
.tsbuildinfo
.tsbuildinfo.*

View File

@ -0,0 +1,3 @@
module.exports = {
...require('mwts/.prettierrc.json')
}

10
packages/sms/index.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
export * from './dist/index';
declare module '@midwayjs/core/dist/interface' {
interface MidwayConfig {
book?: PowerPartial<{
a: number;
b: string;
}>;
}
}

View File

@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
coveragePathIgnorePatterns: ['<rootDir>/test/'],
setupFilesAfterEnv: ['./jest.setup.js']
};

View File

@ -0,0 +1 @@
jest.setTimeout(30000);

49
packages/sms/package.json Normal file
View File

@ -0,0 +1,49 @@
{
"name": "@cool-midway/sms",
"version": "6.0.1",
"description": "cool-js.com 短信",
"main": "dist/index.js",
"typings": "index.d.ts",
"scripts": {
"build": "cross-env midway-bin build -c",
"test": "cross-env midway-bin test --ts",
"cov": "cross-env midway-bin cov --ts",
"lint": "mwts check",
"lint:fix": "mwts fix"
},
"keywords": [
"cool",
"cool-admin",
"cooljs"
],
"author": "COOL",
"readme": "README.md",
"files": [
"dist/**/*.js",
"dist/**/*.d.ts",
"index.d.ts"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://cool-js.com"
},
"devDependencies": {
"@cool-midway/core": "^6.0.0",
"@midwayjs/cli": "^2.0.9",
"@midwayjs/core": "^3.9.0",
"@midwayjs/decorator": "^3.9.0",
"@midwayjs/mock": "^3.9.0",
"@types/jest": "^29.2.5",
"@types/node": "^18.11.18",
"cross-env": "^7.0.3",
"jest": "^29.3.1",
"mwts": "^1.3.0",
"ts-jest": "^29.0.3",
"typescript": "^4.9.4"
},
"dependencies": {
"@alicloud/pop-core": "^1.7.13",
"tencentcloud-sdk-nodejs": "^4.0.607"
}
}

64
packages/sms/src/ali.ts Normal file
View File

@ -0,0 +1,64 @@
import * as Core from '@alicloud/pop-core';
import { Config, Provide } from "@midwayjs/core";
import { CoolSmsAliConfig } from './interface';
import { CoolCommException } from '@cool-midway/core';
/**
*
*/
@Provide()
export class SmsAli {
@Config('cool.sms.ali')
config: CoolSmsAliConfig;
/**
*
* @param config
*/
setConfig(config: CoolSmsAliConfig) {
this.config = config;
}
/**
*
* @param phone
* @param params
* @param config signName template
* @returns
*/
async send(phone, params: {
[key: string]: string;
}, config?: {
signName: string;
template: string;
}) {
const { accessKeyId, accessKeySecret } = this.config;
if (!accessKeyId || !accessKeyId) {
throw new CoolCommException('请配置阿里云短信');
}
if (!config) {
config = {
signName: this.config.signName,
template: this.config.template,
};
}
const client = new Core({
accessKeyId,
accessKeySecret,
endpoint: 'https://dysmsapi.aliyuncs.com',
// endpoint: 'https://cs.cn-hangzhou.aliyuncs.com',
apiVersion: '2017-05-25',
// apiVersion: '2018-04-18',
});
const data = {
RegionId: 'cn-shanghai',
PhoneNumbers: phone,
signName: config.signName,
templateCode: config.template,
TemplateParam: JSON.stringify(params),
};
return await client.request('SendSms', data, {
method: 'POST',
});
}
}

View File

@ -0,0 +1,5 @@
export const customKey = {
a: 1,
b: 'hello',
};

View File

@ -0,0 +1,17 @@
import { Configuration } from '@midwayjs/decorator';
import * as DefaultConfig from './config/config.default';
import { IMidwayContainer } from '@midwayjs/core';
@Configuration({
namespace: 'cool:sms',
importConfigs: [
{
default: DefaultConfig,
},
],
})
export class CoolPayConfiguration {
async onReady(container: IMidwayContainer) {
// TODO something
}
}

View File

@ -0,0 +1,9 @@
export { CoolPayConfiguration as Configuration } from './configuration';
export * from './interface';
export * from './ali';
export * from './yp';
export * from './tx';
export * from './sms';

View File

@ -0,0 +1,80 @@
export interface CoolSmsConfig {
/**
*
*/
ali: CoolSmsAliConfig;
/**
*
*/
tx: CoolTxConfig;
/**
*
*/
yp: CoolYpConfig;
}
/**
*
*/
export interface CoolSmsAliConfig {
/**
* accessKeyId
*/
accessKeyId: string;
/**
* accessKeySecret
*/
accessKeySecret: string;
/**
*
*/
signName?: string;
/**
*
*/
template?: string;
}
/**
*
*/
export interface CoolTxConfig {
/**
* ID
*/
appId: string;
/**
* secretId
*/
secretId: string;
/**
* secretKey
*/
secretKey: string;
/**
*
*/
signName?: string;
/**
*
*/
template?: string;
}
/**
*
*/
export interface CoolYpConfig {
/**
* apikey
*/
apikey: string;
/**
*
*/
signName?: string;
/**
*
*/
template?: string;
}

View File

@ -0,0 +1,49 @@
{
"name": "@cool-midway/sms",
"version": "6.0.1",
"description": "cool-js.com 短信",
"main": "index.js",
"typings": "index.d.ts",
"scripts": {
"build": "cross-env midway-bin build -c",
"test": "cross-env midway-bin test --ts",
"cov": "cross-env midway-bin cov --ts",
"lint": "mwts check",
"lint:fix": "mwts fix"
},
"keywords": [
"cool",
"cool-admin",
"cooljs"
],
"author": "COOL",
"readme": "README.md",
"files": [
"**/*.js",
"**/*.d.ts",
"index.d.ts"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://cool-js.com"
},
"devDependencies": {
"@cool-midway/core": "^6.0.0",
"@midwayjs/cli": "^2.0.9",
"@midwayjs/core": "^3.9.0",
"@midwayjs/decorator": "^3.9.0",
"@midwayjs/mock": "^3.9.0",
"@types/jest": "^29.2.5",
"@types/node": "^18.11.18",
"cross-env": "^7.0.3",
"jest": "^29.3.1",
"mwts": "^1.3.0",
"ts-jest": "^29.0.3",
"typescript": "^4.9.4"
},
"dependencies": {
"@alicloud/pop-core": "^1.7.13",
"tencentcloud-sdk-nodejs": "^4.0.607"
}
}

83
packages/sms/src/sms.ts Normal file
View File

@ -0,0 +1,83 @@
import { Config, Inject, Provide } from "@midwayjs/core";
import { SmsYp } from "./yp";
import { SmsAli } from "./ali";
import { SmsTx } from "./tx";
import { CoolSmsConfig } from "./interface";
@Provide()
export class CoolSms {
@Inject()
smsYp: SmsYp
@Inject()
smsAli: SmsAli
@Inject()
smsTx: SmsTx
@Config('cool.sms')
config: CoolSmsConfig;
/**
*
* @param config
*/
setConfig(config: CoolSmsConfig) {
this.smsYp.setConfig(config.yp);
this.smsAli.setConfig(config.ali);
this.smsTx.setConfig(config.tx);
this.config = config;
}
/**
* code
* @param phone
* @param config
*/
async sendCode(phone, config?: {
signName: string;
template: string;
}) {
const code = this.generateNumber();
let params = {
code
}
await this.send(phone, this.config.tx ? [code] : params, config)
return code;
}
/**
*
* @param phone
* @param params
* @param config
* @returns
*/
async send(phone: string, params: any, config?: {
signName: string;
template: string;
}) {
if (this.config.ali) {
return await this.smsAli.send(phone, params, config);
}
if (this.config.tx) {
return await this.smsTx.send(phone, params, config);
}
if (this.config.yp) {
return await this.smsYp.send(phone, params, config);
}
return true;
}
/**
*
*/
generateNumber(digits = 4) {
if (digits <= 0) {
return 0;
}
const min = Math.pow(10, digits - 1);
const max = Math.pow(10, digits) - 1;
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}

70
packages/sms/src/tx.ts Normal file
View File

@ -0,0 +1,70 @@
import { Config, Provide } from "@midwayjs/core";
import { CoolTxConfig } from './interface';
import * as tencentcloud from "tencentcloud-sdk-nodejs";
import { CoolCommException } from "@cool-midway/core";
/**
*
*/
@Provide()
export class SmsTx {
@Config('cool.sms.tx')
config: CoolTxConfig;
/**
*
* @param config
*/
setConfig(config: CoolTxConfig) {
this.config = config;
}
/**
*
* @param phone
* @param params
* @param config signName template
* @returns
*/
async send(phone: string, params: string[], config?: {
signName: string;
template: string;
}) {
const { appId, secretId, secretKey } = this.config;
if(!config) {
config = {
signName: this.config.signName,
template: this.config.template,
};
}
if(!appId || !secretId || !secretKey) {
throw new CoolCommException('请配置腾讯云短信');
}
const smsClient = tencentcloud.sms.v20210111.Client;
const client = new smsClient({
credential: {
secretId,
secretKey,
},
region: 'ap-guangzhou',
profile: {
signMethod: 'HmacSHA256',
httpProfile: {
reqMethod: 'POST',
reqTimeout: 30,
endpoint: 'sms.tencentcloudapi.com',
},
},
});
const data = {
SmsSdkAppId: appId,
SignName: config.signName,
TemplateId: config.template,
TemplateParamSet: params,
PhoneNumberSet: [`+86${phone}`],
};
return client.SendSms(data);
}
}

86
packages/sms/src/yp.ts Normal file
View File

@ -0,0 +1,86 @@
import { Config, Provide } from "@midwayjs/core";
import { CoolYpConfig } from "./interface";
import { CoolCommException } from "@cool-midway/core";
import axios from 'axios';
/**
*
*/
@Provide()
export class SmsYp {
@Config('cool.sms.yp')
config: CoolYpConfig;
/**
*
* @param config
*/
setConfig(config: CoolYpConfig) {
this.config = config;
}
/**
*
* @param phones ["+8612345678901"]
* @param params
* @param config signName template
* @returns
*/
async send(phones: string, params: {
[key: string]: string;
}, config?: {
signName: string;
template: string;
}) {
const { apikey } = this.config;
if (!config) {
config = {
signName: this.config.signName,
template: this.config.template,
};
}
if (!apikey) {
throw new CoolCommException('请配置云片短信');
}
const headers = {
Accept: 'application/json;charset=utf-8',
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
};
const data = {
apikey: apikey,
mobile: phones,
tpl_id: config.template,
tpl_value: this.smsTplValue(params),
};
const result = await axios.post(
'https://sms.yunpian.com/v2/sms/tpl_single_send.json',
data,
{ headers }
);
if (result.data.code === 0) {
return true;
}
return false;
}
/**
*
* @param obj
* @returns
*/
protected smsTplValue(obj) {
const urlParams = [];
for (let key in obj) {
// eslint-disable-next-line no-prototype-builtins
if (obj.hasOwnProperty(key)) {
const encodedKey = encodeURIComponent(`#${key}#`);
const encodedValue = encodeURIComponent(obj[key]);
urlParams.push(`${encodedKey}=${encodedValue}`);
}
}
return urlParams.join('&');
}
}

View File

@ -0,0 +1,14 @@
import { createLightApp } from '@midwayjs/mock';
import * as custom from '../src';
describe('/test/index.test.ts', () => {
it('test component', async () => {
const app = await createLightApp('', {
imports: [
custom
]
});
const bookService = await app.getApplicationContext().getAsync(custom.BookService);
expect(await bookService.getBookById()).toEqual('hello world');
});
});

View File

@ -0,0 +1,24 @@
{
"compileOnSave": true,
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"inlineSourceMap":false,
"noImplicitThis": true,
"noUnusedLocals": true,
"stripInternal": true,
"skipLibCheck": true,
"noImplicitReturns": false,
"pretty": true,
"declaration": true,
"outDir": "dist"
},
"exclude": [
"dist",
"node_modules",
"test"
]
}

View File

@ -11,6 +11,7 @@ import * as localTask from '@midwayjs/task';
import * as cool from '@cool-midway/core';
import * as cloud from '@cool-midway/cloud';
import * as file from '@cool-midway/file';
// import * as sms from '@cool-midway/sms';
// import * as rpc from '@cool-midway/rpc';
// import * as task from '@cool-midway/task';
// import * as pay from '@cool-midway/pay';
@ -46,6 +47,8 @@ import * as file from '@cool-midway/file';
// pay,
// 物联网开发如MQTT支持等
// iot,
// 短信
// sms
{
component: info,
enabledEnvironment: ['local'],

View File

@ -1,8 +1,8 @@
import { Provide, Config, Inject } from '@midwayjs/decorator';
import { BaseService, CoolCommException } from '@cool-midway/core';
import * as _ from 'lodash';
import * as Core from '@alicloud/pop-core';
import { CacheManager } from '@midwayjs/cache';
import { CoolSms } from '@cool-midway/sms';
/**
*
@ -16,19 +16,17 @@ export class UserSmsService extends BaseService {
@Inject()
cacheManager: CacheManager;
@Inject()
coolSms: CoolSms;
/**
*
* @param phone
*/
async sendSms(phone) {
try {
const TemplateParam = { code: _.random(1000, 9999) };
await this.send(phone, TemplateParam);
this.cacheManager.set(
`sms:${phone}`,
TemplateParam.code,
this.config.timeout
);
const code = await this.coolSms.sendCode(phone);
this.cacheManager.set(`sms:${phone}`, code, this.config.timeout);
} catch (error) {
throw new CoolCommException('发送过于频繁,请稍后再试');
}
@ -47,33 +45,4 @@ export class UserSmsService extends BaseService {
}
return false;
}
/**
*
* @param phone
* @param templateCode
* @param template
*/
async send(phone, TemplateParam) {
const { signName, accessKeyId, accessKeySecret, templateCode } =
this.config;
const client = new Core({
accessKeyId,
accessKeySecret,
endpoint: 'https://dysmsapi.aliyuncs.com',
// endpoint: 'https://cs.cn-hangzhou.aliyuncs.com',
apiVersion: '2017-05-25',
// apiVersion: '2018-04-18',
});
const params = {
RegionId: 'cn-shanghai',
PhoneNumbers: phone,
signName,
templateCode,
TemplateParam: JSON.stringify(TemplateParam),
};
return await client.request('SendSms', params, {
method: 'POST',
});
}
}