Skip to content
This repository has been archived by the owner on Jan 10, 2025. It is now read-only.

Commit

Permalink
feat: 🎸 个人消息支持给送发备注名,收群消息source.room字段提供群成员更多信息(昵称、备注、id)
Browse files Browse the repository at this point in the history
Closes: #34
  • Loading branch information
danni-cool committed Oct 13, 2023
1 parent 002928f commit d6ffd54
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 19 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ docker logs -f wxBotWebhook

> json 请求发送文件只支持外链
| 参数 | 说明 | 数据类型 | 默认值 | 可否为空 | 可选值 |
| 参数 | 说明 | 数据类型 | 默认值 | 可否为空 | 可选参数 |
|--|--|--|--|--|--|
| to | **会话名**发群消息填群名,发给个人填昵称 | `String` | - | N | - |
| to | **消息接收方**传入`String` 默认是发给昵称(群名同理), 传入`Object` 结构支持发给备注过的人,比如:`{alias: '备注名'}`,群名不支持备注名 | `String` `Object` | - | Y | - |
| isRoom | **是否发的群消息**,这个参数决定了找人的时候找的是群还是人,因为昵称其实和群名相同在技术处理上 | `Boolean` | `false` | Y | `true` `false` |
| type | **消息类型**,消息不支持自动拆分,请手动调多次,发送的文件 Url 在微信里长啥样,是文件后缀决定的。| `String` | - | N | `text` `fileUrl` | 支持 **文字****文件**|
| content | **消息内容**,如果希望发多个Url并解析,type 指定为 fileUrl 同时,content 里填 url 以英文逗号分隔 | `String` | - | N | - |
Expand Down Expand Up @@ -131,7 +131,7 @@ curl --location --request POST 'http://localhost:3001/webhook/msg' \

| formData | 说明 | 数据类型 | 可选值 | 示例 |
|--|--|--|--|-- |
| type | <div>支持的类型</div><ul><li>✅ 文字(text)</li><li>✅ 图片(file)</li><li>✅ 视频(file)</li><li>✅ 附件(file)</li> <li>✅ 语音(file)</li></ul> refer: [wechaty类型支持列表](https://wechaty.js.org/docs/api/message#messagetype--messagetype) | `String` | `text` `file` `urlLink` | - |
| type | <div>支持的类型</div><ul><li>✅ 文字(text)</li><li>✅ 链接卡片(urlLink)</li><li>✅ 图片(file)</li><li>✅ 视频(file)</li><li>✅ 附件(file)</li> <li>✅ 语音(file)</li></ul> refer: [wechaty类型支持列表](https://wechaty.js.org/docs/api/message#messagetype--messagetype) | `String` | `text` `file` `urlLink` | - |
| content | 传输的内容, 文本或传输的文件共用这个字段,结构映射请看示例 | `String` `Binary` | | [示例](docs/recvdApi.example.md#formdatacontent) |
| source | 消息的相关发送方数据, JSON String | `String` | | [示例](docs/recvdApi.example.md#formdatasource) |
| isSystemEvent | 是否是来自系统消息事件(比如上线,掉线、异常事件)| `String` | `1` `0` | - |
Expand Down
7 changes: 3 additions & 4 deletions docs/recvdApi.example.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,9 @@
"id": "@@xxxx",
"adminIdList": [],
"avatar": "xxxx", // 相对路径,应该要配合解密
"memberIdList": [ //群里人的id
"@xxxx",
"@xxxx"
],
"memberList": [
{id: '@xxxx', name:'昵称', alias: '备注名' }
]
},
//以下暂不清楚什么用途,如有兴趣,请查阅 wechaty 官网文档
"_events": {},
Expand Down
12 changes: 6 additions & 6 deletions src/route/msg.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const Service = require('../service')
const Middleware = require('../middleware')
const { getUnvalidParamsList } = require('../utils/index')
const Utils = require('../utils/index')

module.exports = function registerPushHook({ app, bot }) {

Expand All @@ -18,7 +18,7 @@ module.exports = function registerPushHook({ app, bot }) {
type = 'file'

//校验必填参数
unValidParamsStr = getUnvalidParamsList([
unValidParamsStr = Utils.getUnvalidParamsList([
{ key: 'to', val: to, required: true, type: 'string', unValidReason: '' },
{ key: 'isRoom', val: isRoom, required: false, enum: ['1', '0'], type: 'string', unValidReason: '' },
{ key: 'content', val: content.size || 0, required: true, type: 'file', unValidReason: '' },
Expand All @@ -34,8 +34,8 @@ module.exports = function registerPushHook({ app, bot }) {
content = req.body.content

//校验必填参数
unValidParamsStr = getUnvalidParamsList([
{ key: 'to', val: to, required: true, type: 'string', unValidReason: '' },
unValidParamsStr = Utils.getUnvalidParamsList([
{ key: 'to', val: to, required: true, type: ['string','object'], unValidReason: '' },
{ key: 'type', val: type, required: true, type: 'string', enum: ['text', 'img', 'file', 'fileUrl'], unValidReason: '' },
{ key: 'content', val: content, required: true, type: 'string', unValidReason: '' },
{ key: 'isRoom', val: isRoom, required: false, type: 'boolean', unValidReason: '' }
Expand All @@ -44,12 +44,12 @@ module.exports = function registerPushHook({ app, bot }) {
}

if (unValidParamsStr) {
return res.status(200).json({ success: false, message: `[${unValidParamsStr}] params is not valid, please checkout the api reference (https://github.com/danni-cool/docker-wechatbot-webhook#body-%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E)` });
return res.status(200).json({ success: false, message: `[${unValidParamsStr}] params is not valid, please checkout the api reference (https://github.com/danni-cool/docker-wechatbot-webhook#%EF%B8%8F-api)` });
}

const msgReceiver = isRoom ?
await bot.Room.find({ topic: to }) :
await bot.Contact.find({ name: to })
await bot.Contact.find(Utils.equalTrueType(to, 'object')? to : { name: to })

if (msgReceiver) {
const sendStatus = await Service.formatAndSendMsg({ bot, type, content, msgInstance: msgReceiver, res })
Expand Down
20 changes: 18 additions & 2 deletions src/service/webhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import('file-type').then(res => {
})

const sendMsg2RecvdApi = async function (msg) {
// 自己发的消息没有必要转发
if(msg.self()) return

// 检测是否配置了webhookurl
let webhookUrl
let errorText = (key, value) => console.error(chalk.red(`配置参数 ${key}: ${chalk.cyan(value)} <- 不符合 URL 规范, 该 API 将不会收到请求\n`))
Expand All @@ -27,11 +30,24 @@ const sendMsg2RecvdApi = async function (msg) {
webhookUrl = ('' + LOCAL_RECVD_MSG_API).startsWith('http') ? LOCAL_RECVD_MSG_API : ''
!webhookUrl && errorText('LOCAL_RECVD_MSG_API', LOCAL_RECVD_MSG_API)
}

// 有webhookurl才发送
if (!webhookUrl) return

const roomInfo = msg.room()

if (roomInfo) {
const roomMemberInfo = await msg.room().memberAll()
roomInfo.payload.memberList = roomMemberInfo.map(item => ({
id: item.payload.id,
name: item.payload.name,
alias: item.payload.alias
}))
}

const source = {
room: msg.room() || '',
/** room的话解析群成员信息,原始信息不会带 */
room: roomInfo || '',
to: msg.to() || '',
from: msg.talker() || '',
}
Expand Down Expand Up @@ -96,7 +112,7 @@ const sendMsg2RecvdApi = async function (msg) {
break;
}

if (!passed || msg.self()) return
if (!passed) return

console.log('starting fetching api: ' + webhookUrl, msg.payload)

Expand Down
17 changes: 13 additions & 4 deletions src/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { FileBox } = require('file-box') // bugfix: wechaty can not export FileBox until v1.20.2 , so use the dependency of wechaty
const { FileBox } = require('file-box') // hack: wechaty use Instance to Export File-box
const fetch = require('node-fetch-commonjs')

const downloadFile = async fileUrl => {
Expand All @@ -14,6 +14,10 @@ const downloadFile = async fileUrl => {
}
}

const equalTrueType = function (val, expectType) {
return Object.prototype.toString.call(val).toLowerCase() === `[object ${expectType}]`
}

//http://www.baidu.com/image.png?a=1 => image.png
const getFileNameFromUrl = url => url.match(/.*\/([^/?]*)/)?.[1] || ''

Expand Down Expand Up @@ -49,11 +53,15 @@ const getUnvalidParamsList = arr => {
else if (item.type === 'file' && item.val === 0) {
item.unValidReason = `${item.key} 上传的文件不能为空`
}
// exp: type:[string, object]情况
else if (equalTrueType(item.type, 'array')) {
item.unValidReason = item.type.some(type => equalTrueType(item.val, type)) ? '' : `${item.key} 的参数类型不是 ${item.type.map(key => capitalizeFirstLetter(key)).join(' or ')}`
}
else if (item.type !== 'file' && typeof item.val !== item.type) {
item.unValidReason = `${item.key} 的参数类型不是 ${capitalizeFirstLetter(item.type)}`
}
} else {
item.unValidReason = typeof item.val !== item.type ? `${item.key} 的参数类型不是 ${item.type}` : ''
item.unValidReason = typeof item.val !== item.type ? `${item.key} 的参数类型不是 ${capitalizeFirstLetter(item.type)}` : ''
}

//前者通过,如果遇到要校验指定枚举值的情况
Expand All @@ -69,7 +77,7 @@ const getUnvalidParamsList = arr => {
const generateToken = (num = 12) => {
const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~';
let token = '';
for (let i = 0; i < 16; i++) {
for (let i = 0; i < num; i++) {
const randomIndex = Math.floor(Math.random() * charset.length);
token += charset[randomIndex];
}
Expand All @@ -82,6 +90,7 @@ module.exports = {
getMediaFromUrl,
getBufferFile,
getUnvalidParamsList,
generateToken
generateToken,
equalTrueType
}

0 comments on commit d6ffd54

Please sign in to comment.