Skip to content
This repository has been archived by the owner on Jun 1, 2020. It is now read-only.

Add implementation for room-invite event #107

Merged
merged 7 commits into from
Jul 24, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"homepage": "https://github.com/lijiarui/wechaty-puppet-padchat#readme",
"dependencies": {
"array-flatten": "^2.1.1",
"axios": "^0.18.0",
"express": "^4.16.3",
"flash-store": "^0.5.9",
"fs-extra": "^6.0.1",
Expand All @@ -93,6 +94,8 @@
"promise-retry": "^1.1.1",
"qr-image": "^3.2.0",
"read-pkg-up": "^4.0.0",
"request": "^2.87.0",
"request-promise": "^4.2.2",
"rx-queue": "^0.4.26",
"rxjs": "^6.2.1",
"ws": "^5.2.1",
Expand Down
3 changes: 2 additions & 1 deletion src/padchat-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
PadchatRoomMemberListPayload,
PadchatRoomMemberPayload,
PadchatRoomPayload,
PadchatRequestTokenPayload,
} from './padchat-schemas'

import {
Expand Down Expand Up @@ -1096,7 +1097,7 @@ export class PadchatRpc extends EventEmitter {
// 公众号中获取url访问token, 给下面的函数使用[WXRequestUrl]
// user 公众号用户名
// url 访问的链接
public async WXGetRequestToken (id: string, url: string): Promise<any> {
public async WXGetRequestToken (id: string, url: string): Promise<PadchatRequestTokenPayload> {
const result = await this.rpcCall('WXGetRequestToken', id, url)
log.silly('PadchatRpc', 'WXGetRequestToken , stranger,result: %s', JSON.stringify(result))
if (!result || result.status !== 0) {
Expand Down
10 changes: 9 additions & 1 deletion src/padchat-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,15 @@ export interface PadchatRoomMemberListPayload {

export interface PadchatFriendshipPayload {
fromusername : string, // 'lizhuohuan'
encryptusername : string // v1_xxx@stranger'
encryptusername : string, // v1_xxx@stranger'
content : string, // 'hello'
ticket : string, // 'v2_1a0d2cf325e64b6f74bed09e944529e7cc7a7580cb323475050664566dd0302d89b8e2ed95b596b459cf762d94a0ce606da39babbae0dc26b18a62e079bfc120@stranger',
}

export interface PadchatRequestTokenPayload {
full_url : string,
info : string,
message : string,
share_url : string,
status : number,
}
64 changes: 62 additions & 2 deletions src/puppet-padchat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import LRU from 'lru-cache'

import { FileBox } from 'file-box'

import axios from 'axios'

import {
ContactGender,

Expand All @@ -42,6 +44,7 @@ import {
Receiver,
RoomMemberPayload,
RoomPayload,
RoomInvitation,
} from 'wechaty-puppet'

import {
Expand All @@ -65,6 +68,7 @@ import {
roomRawPayloadParser,

roomTopicEventMessageParser,
roomInviteEventMessageParser,
} from './pure-function-helpers'

import {
Expand Down Expand Up @@ -211,7 +215,7 @@ export class PuppetPadchat extends Puppet {
throw new Error('no padchat manager')
}
await super.login(selfId)
await this.padchatManager.syncContactsAndRooms()
// await this.padchatManager.syncContactsAndRooms()
}

public async startManager (manager: PadchatManager): Promise<void> {
Expand Down Expand Up @@ -303,19 +307,75 @@ export class PuppetPadchat extends Puppet {
break

case PadchatMessageType.App:
await Promise.all([
this.onPadchatMessageRoomInvitation(rawPayload),
])
case PadchatMessageType.Emoticon:
case PadchatMessageType.Image:
case PadchatMessageType.MicroVideo:
case PadchatMessageType.Video:
case PadchatMessageType.Voice:
// TODO: the above types are filel type
// TODO: the above types are field type

default:
this.emit('message', rawPayload.msg_id)
break
}
}

protected async onPadchatMessageRoomInvitation(rawPayload: PadchatMessagePayload): Promise<void> {
log.verbose('PuppetPadchat', 'onPadchatMessageRoomInvitation(%s)', rawPayload)
const roomInviteEvent = roomInviteEventMessageParser(rawPayload)

if (!this.padchatManager) {
throw new Error('no padchat manager')
}

if (roomInviteEvent) {
try {
const shareUrl = roomInviteEvent.url

const response = await this.padchatManager.WXGetRequestToken(this.selfId(), shareUrl)
console.log(response)

const roomInvitation: RoomInvitation = {
roomName: roomInviteEvent.roomName,
fromUser: rawPayload.from_user,
timestamp: rawPayload.timestamp,
accept: async () => {
try {
const res = await require('request-promise')({
method: 'POST',
uri: response.full_url
})

let succeed = false
let message = ''
console.log(res)
if (res.indexOf('你无法查看被转发过的邀请') !== -1) {
message = 'Accept invitation failed, this is a forwarded invitation, can not be accepted'
} else if (res.indexOf('你未开通微信支') !== -1) {
message = 'The user need to enable wechaty pay(微信支付) to join the room, this is requested by Wechat.'
} else {
succeed = true
message = 'Accept Invitation succeed'
}
return { succeed, message }
} catch (e) {
return {
succeed: false,
message: 'Failed with exception: ' + e,
}
}
}
}
this.emit('room-invite', roomInvitation)
} catch (e) {
console.error(e)
}
}
}

/**
* Look for room join event
*/
Expand Down
1 change: 1 addition & 0 deletions src/pure-function-helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export * from './is-type'
export * from './message-raw-payload-parser'
export * from './message-file-name'
export * from './padchat-decode'
export * from './room-event-invite-message-parser'
export * from './room-event-join-message-parser'
export * from './room-event-leave-message-parser'
export * from './room-event-topic-message-parser'
Expand Down
135 changes: 135 additions & 0 deletions src/pure-function-helpers/room-event-invite-message-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { toJson } from 'xml2json'

import {
PuppetRoomInviteEvent,
} from 'wechaty-puppet'

import {
PadchatMessagePayload
} from '../padchat-schemas'
import { isPayload } from './is-type';

/*
{
"msg": {
"appmsg": {
"appid": "",
"sdkver": "0",
"title": "邀请你加入群聊",
"des": "\"user\"邀请你加入群聊💃🏻这个群特别炸💃🏻,进入可查看详情。",
"action": "view",
"type": "5",
"showtype": "0",
"soundtype": "0",
"mediatagname": {},
"messageext": {},
"messageaction": {},
"content": {},
"contentattr": "0",
"url": "http://support.weixin.qq.com/cgi-bin/mmsupport-bin/addchatroombyinvite?ticket=AR4P8WARk7B55o05Gqc65Q%3D%3D",
"lowurl": {},
"dataurl": {},
"lowdataurl": {},
"appattach": {
"totallen": "0",
"attachid": {},
"emoticonmd5": {},
"fileext": {},
"cdnthumbaeskey": {},
"aeskey": {}
},
"extinfo": {},
"sourceusername": {},
"sourcedisplayname": {},
"thumburl": "http://weixin.qq.com/cgi-bin/getheadimg?username=3085b869e7943882d94e05dcdc7f28c524804fc4759b6c273f2be799ed1bf0e9",
"md5": {},
"statextstr": {}
},
"fromusername": "lylezhuifeng",
"scene": "0",
"appinfo": {
"version": "1",
"appname": {}
},
"commenturl": {}
}
}
*/

const ROOM_OTHER_INVITE_TITLE_ZH = [
/邀请你加入群聊/
]

const ROOM_OTHER_INVITE_TITLE_EN = [
/Group Chat Invitation/
]

const ROOM_OTHER_INVITE_LIST_ZH = [
/^"(.+)"邀请你加入群聊(.+),进入可查看详情。/
]

const ROOM_OTHER_INVITE_LIST_EN = [
/"(.+)" invited you to join the group chat "(.+)"\. Enter to view details\./
]

export const roomInviteEventMessageParser = (
rawPayload: PadchatMessagePayload,
): null | PuppetRoomInviteEvent => {

if (!isPayload(rawPayload)) {
return null
}

const { content } = rawPayload;
const tryXmlText = content.replace(/^[^\n]+\n/, '')
interface XmlSchema {
msg: {
appmsg:
{
title: string,
des: string,
url: string,
thumburl: string,
}
}
}

const jsonPayload = toJson(tryXmlText, { object: true }) as XmlSchema
console.log(JSON.stringify(jsonPayload, null, 2))

let matchesForOtherInviteTitleEn = null as null | string[]
let matchesForOtherInviteTitleZh = null as null | string[]
let matchesForOtherInviteEn = null as null | string[]
let matchesForOtherInviteZh = null as null | string[]

ROOM_OTHER_INVITE_TITLE_EN.some(
regex => !!(matchesForOtherInviteTitleEn = jsonPayload.msg.appmsg.title.match(regex)),
)

ROOM_OTHER_INVITE_TITLE_ZH.some(
regex => !!(matchesForOtherInviteTitleZh = jsonPayload.msg.appmsg.title.match(regex)),
)

ROOM_OTHER_INVITE_LIST_EN.some(
regex => !!(matchesForOtherInviteEn = jsonPayload.msg.appmsg.des.match(regex)),
)

ROOM_OTHER_INVITE_LIST_ZH.some(
regex => !!(matchesForOtherInviteZh = jsonPayload.msg.appmsg.des.match(regex)),
)

const titleMatch = matchesForOtherInviteTitleEn || matchesForOtherInviteTitleZh

const matchInviteEvent = matchesForOtherInviteEn || matchesForOtherInviteZh

const matches = !!titleMatch && !!matchInviteEvent

if (!matches) {
return null
}

return {
roomName: matchInviteEvent![2],
url: jsonPayload.msg.appmsg.url
}
}