feat: complete V1 phases 0-7
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import type { NotificationType } from '@lehuo/contracts';
|
||||
import { AppConfigService } from '../config/app-config.service';
|
||||
export interface SubscriptionMessage {
|
||||
openid: string;
|
||||
type: NotificationType;
|
||||
title: string;
|
||||
body: string;
|
||||
resourcePublicId: string | null;
|
||||
}
|
||||
export interface SubscriptionSendResult {
|
||||
providerMessageId: string | null;
|
||||
}
|
||||
export abstract class WechatSubscriptionAdapter {
|
||||
abstract get configured(): boolean;
|
||||
abstract send(message: SubscriptionMessage): Promise<SubscriptionSendResult>;
|
||||
}
|
||||
@Injectable()
|
||||
export class HttpWechatSubscriptionAdapter extends WechatSubscriptionAdapter {
|
||||
constructor(@Inject(AppConfigService) private readonly config: AppConfigService) {
|
||||
super();
|
||||
}
|
||||
get configured() {
|
||||
return this.config.wechatNotificationConfigured;
|
||||
}
|
||||
async send(message: SubscriptionMessage) {
|
||||
if (!this.config.wechatAppId || !this.config.wechatAppSecret)
|
||||
throw new Error('WECHAT_NOT_CONFIGURED');
|
||||
const templateId = this.config.wechatNotificationTemplates[message.type];
|
||||
if (!templateId) throw new Error('WECHAT_TEMPLATE_NOT_CONFIGURED');
|
||||
const tokenResponse = await fetch(
|
||||
`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${encodeURIComponent(this.config.wechatAppId)}&secret=${encodeURIComponent(this.config.wechatAppSecret)}`,
|
||||
);
|
||||
const token = (await tokenResponse.json()) as { access_token?: string; errcode?: number };
|
||||
if (!tokenResponse.ok || !token.access_token)
|
||||
throw new Error(`WECHAT_TOKEN_${token.errcode ?? 'FAILED'}`);
|
||||
const response = await fetch(
|
||||
`https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${encodeURIComponent(token.access_token)}`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
touser: message.openid,
|
||||
template_id: templateId,
|
||||
page: message.resourcePublicId
|
||||
? `pages/index/index?resource=${message.resourcePublicId}`
|
||||
: 'pages/index/index',
|
||||
data: {
|
||||
thing1: { value: message.title.slice(0, 20) },
|
||||
thing2: { value: message.body.slice(0, 20) },
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
const result = (await response.json()) as {
|
||||
errcode?: number;
|
||||
errmsg?: string;
|
||||
msgid?: string | number;
|
||||
};
|
||||
if (!response.ok || result.errcode !== 0)
|
||||
throw new Error(`WECHAT_SEND_${result.errcode ?? 'FAILED'}`);
|
||||
return { providerMessageId: result.msgid?.toString() ?? null };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user