# -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals import re import six from wechatpy.client.api.base import BaseWeChatAPI class WeChatMessage(BaseWeChatAPI): OPENID_RE = re.compile(r'^[\w\-]{28}$', re.I) def _send_custom_message(self, data, account=None): data = data or {} if account: data['customservice'] = {'kf_account': account} return self._post( 'message/custom/send', data=data ) def send_text(self, user_id, content, account=None): """ 发送文本消息 详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param content: 消息正文 :param account: 可选,客服账号 :return: 返回的 JSON 数据包 使用示例:: from wechatpy import WeChatClient client = WeChatClient('appid', 'secret') res = client.message.send_text('openid', 'text') """ data = { 'touser': user_id, 'msgtype': 'text', 'text': {'content': content} } return self._send_custom_message(data, account=account) def send_image(self, user_id, media_id, account=None): """ 发送图片消息 详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param media_id: 图片的媒体ID。 可以通过 :func:`upload_media` 上传。 :param account: 可选,客服账号 :return: 返回的 JSON 数据包 使用示例:: from wechatpy import WeChatClient client = WeChatClient('appid', 'secret') res = client.message.send_image('openid', 'media_id') """ data = { 'touser': user_id, 'msgtype': 'image', 'image': { 'media_id': media_id } } return self._send_custom_message(data, account=account) def send_voice(self, user_id, media_id, account=None): """ 发送语音消息 详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param media_id: 发送的语音的媒体ID。 可以通过 :func:`upload_media` 上传。 :param account: 可选,客服账号 :return: 返回的 JSON 数据包 使用示例:: from wechatpy import WeChatClient client = WeChatClient('appid', 'secret') res = client.message.send_voice('openid', 'media_id') """ data = { 'touser': user_id, 'msgtype': 'voice', 'voice': { 'media_id': media_id } } return self._send_custom_message(data, account=account) def send_video(self, user_id, media_id, title=None, description=None, account=None): """ 发送视频消息 详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param media_id: 发送的视频的媒体ID。 可以通过 :func:`upload_media` 上传。 :param title: 视频消息的标题 :param description: 视频消息的描述 :param account: 可选,客服账号 :return: 返回的 JSON 数据包 使用示例:: from wechatpy import WeChatClient client = WeChatClient('appid', 'secret') res = client.message.send_video('openid', 'media_id', 'title', 'description') """ video_data = { 'media_id': media_id, } if title: video_data['title'] = title if description: video_data['description'] = description data = { 'touser': user_id, 'msgtype': 'video', 'video': video_data } return self._send_custom_message(data, account=account) def send_music(self, user_id, url, hq_url, thumb_media_id, title=None, description=None, account=None): """ 发送音乐消息 详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param url: 音乐链接 :param hq_url: 高品质音乐链接,wifi环境优先使用该链接播放音乐 :param thumb_media_id: 缩略图的媒体ID。 可以通过 :func:`upload_media` 上传。 :param title: 音乐标题 :param description: 音乐描述 :param account: 可选,客服账号 :return: 返回的 JSON 数据包 """ music_data = { 'musicurl': url, 'hqmusicurl': hq_url, 'thumb_media_id': thumb_media_id } if title: music_data['title'] = title if description: music_data['description'] = description data = { 'touser': user_id, 'msgtype': 'music', 'music': music_data } return self._send_custom_message(data, account=account) def send_articles(self, user_id, articles, account=None): """ 发送图文消息 详情请参考 http://mp.weixin.qq.com/wiki/7/12a5a320ae96fecdf0e15cb06123de9f.html :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param articles: 一个包含至多10个图文的数组, 或者微信图文消息素材 media_id :param account: 可选,客服账号 :return: 返回的 JSON 数据包 """ if isinstance(articles, (tuple, list)): articles_data = [] for article in articles: articles_data.append({ 'title': article['title'], 'description': article['description'], 'url': article['url'], 'picurl': article.get('image', article.get('picurl')), }) data = { 'touser': user_id, 'msgtype': 'news', 'news': { 'articles': articles_data } } else: data = { 'touser': user_id, 'msgtype': 'mpnews', 'mpnews': { 'media_id': articles, } } return self._send_custom_message(data, account=account) def send_card(self, user_id, card_id, card_ext, account=None): """ 发送卡券消息 详情请参参考 http://mp.weixin.qq.com/wiki/1/70a29afed17f56d537c833f89be979c9.html :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param card_id: 卡券 ID :param card_ext: 卡券扩展信息 :param account: 可选,客服账号 :return: 返回的 JSON 数据包 """ data = { 'touser': user_id, 'msgtype': 'wxcard', 'wxcard': { 'card_id': card_id, 'card_ext': card_ext } } return self._send_custom_message(data, account=account) def delete_mass(self, msg_id): """ 删除群发消息 详情请参考 http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html :param msg_id: 要删除的群发消息 ID :return: 返回的 JSON 数据包 使用示例:: from wechatpy import WeChatClient client = WeChatClient('appid', 'secret') res = client.message.delete_mass('message id') """ return self._post( 'message/mass/delete', data={ 'msg_id': msg_id } ) def _send_mass_message(self, group_or_users, msg_type, msg, is_to_all=False, preview=False): data = { 'msgtype': msg_type } if not preview: if isinstance(group_or_users, (tuple, list)): # send by user ids data['touser'] = group_or_users endpoint = 'message/mass/send' else: # send by group id data['filter'] = { 'group_id': group_or_users, 'is_to_all': is_to_all, } endpoint = 'message/mass/sendall' else: if not isinstance(group_or_users, six.string_types): raise ValueError('group_or_users should be string types') # 预览接口 if self.OPENID_RE.match(group_or_users): # 按照 openid 预览群发 data['touser'] = group_or_users else: # 按照微信号预览群发 data['towxname'] = group_or_users endpoint = 'message/mass/preview' data.update(msg) return self._post( endpoint, data=data ) def send_mass_text(self, group_or_users, content, is_to_all=False, preview=False): """ 群发文本消息 详情请参考 http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html :param group_or_users: 值为整型数字时为按分组群发,值为列表/元组时为按 OpenID 列表群发 :param content: 消息正文 :param is_to_all: 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户 选择false可根据group_id发送给指定群组的用户 :param preview: 是否发送预览,此时 group_or_users 参数应为一个openid字符串 :return: 返回的 JSON 数据包 """ return self._send_mass_message( group_or_users, 'text', { 'text': { 'content': content } }, is_to_all, preview ) def send_mass_image(self, group_or_users, media_id, is_to_all=False, preview=False): """ 群发图片消息 详情请参考 http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html :param group_or_users: 值为整型数字时为按分组群发,值为列表/元组时为按 OpenID 列表群发 :param media_id: 图片的媒体 ID。 可以通过 :func:`upload_media` 上传。 :param is_to_all: 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户 选择false可根据group_id发送给指定群组的用户 :param preview: 是否发送预览,此时 group_or_users 参数应为一个openid字符串 :return: 返回的 JSON 数据包 """ return self._send_mass_message( group_or_users, 'image', { 'image': { 'media_id': media_id } }, is_to_all, preview ) def send_mass_voice(self, group_or_users, media_id, is_to_all=False, preview=False): """ 群发语音消息 详情请参考 http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html :param group_or_users: 值为整型数字时为按分组群发,值为列表/元组时为按 OpenID 列表群发 :param media_id: 语音的媒体 ID。可以通过 :func:`upload_media` 上传。 :param is_to_all: 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户 选择false可根据group_id发送给指定群组的用户 :param preview: 是否发送预览,此时 group_or_users 参数应为一个openid字符串 :return: 返回的 JSON 数据包 """ return self._send_mass_message( group_or_users, 'voice', { 'voice': { 'media_id': media_id } }, is_to_all, preview ) def send_mass_video(self, group_or_users, media_id, title=None, description=None, is_to_all=False, preview=False): """ 群发视频消息 详情请参考 http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html :param group_or_users: 值为整型数字时为按分组群发,值为列表/元组时为按 OpenID 列表群发 :param media_id: 视频的媒体 ID。可以通过 :func:`upload_video` 上传。 :param title: 视频标题 :param description: 视频描述 :param is_to_all: 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户 选择false可根据group_id发送给指定群组的用户 :param preview: 是否发送预览,此时 group_or_users 参数应为一个openid字符串 :return: 返回的 JSON 数据包 """ video_data = { 'media_id': media_id } if title: video_data['title'] = title if description: video_data['description'] = description return self._send_mass_message( group_or_users, 'mpvideo', { 'mpvideo': video_data }, is_to_all, preview ) def send_mass_article(self, group_or_users, media_id, is_to_all=False, preview=False): """ 群发图文消息 详情请参考 http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html :param group_or_users: 值为整型数字时为按分组群发,值为列表/元组时为按 OpenID 列表群发 :param media_id: 图文的媒体 ID。可以通过 :func:`upload_articles` 上传。 :param is_to_all: 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户 选择false可根据group_id发送给指定群组的用户 :param preview: 是否发送预览,此时 group_or_users 参数应为一个openid字符串 :return: 返回的 JSON 数据包 """ return self._send_mass_message( group_or_users, 'mpnews', { 'mpnews': { 'media_id': media_id } }, is_to_all, preview ) def get_mass(self, msg_id): """ 查询群发消息发送状态 详情请参考 http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html :param msg_id: 群发消息后返回的消息id :return: 返回的 JSON 数据包 使用示例:: from wechatpy import WeChatClient client = WeChatClient('appid', 'secret') res = client.message.get_mass('mass message id') """ return self._post( 'message/mass/get', data={ 'msg_id': msg_id } ) def send_template(self, user_id, template_id, url, top_color, data): """ 发送模板消息 详情请参考 http://mp.weixin.qq.com/wiki/17/304c1885ea66dbedf7dc170d84999a9d.html :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param template_id: 模板 ID。在公众平台线上模板库中选用模板获得 :param url: 链接地址 :param top_color: 消息顶部颜色 :param data: 模板消息数据 :return: 返回的 JSON 数据包 """ return self._post( 'message/template/send', data={ 'touser': user_id, 'template_id': template_id, 'url': url, 'topcolor': top_color, 'data': data } ) def send_template_applet(self, user_id, template_id, appid, pagepath, data): """ 发送模板消息,点击跳转到小程序 详情请参考 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277 :param user_id: 用户 ID 。 就是你收到的 `Message` 的 source :param template_id: 模板 ID。在公众平台线上模板库中选用模板获得 :param appid: 所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏) :param pagepath: 所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏 不必填 :param data: 模板消息数据 :return: 返回的 JSON 数据包 """ data_all = { 'touser': user_id, 'template_id': template_id, "miniprogram": { "appid": appid, # "pagepath": pagepath }, 'data': data } if pagepath: data_all['miniprogram']['pagepath'] = pagepath return self._post( 'message/template/send', data=data_all ) def get_autoreply_info(self): """ 获取自动回复规则 详情请参考 http://mp.weixin.qq.com/wiki/7/7b5789bb1262fb866d01b4b40b0efecb.html :return: 返回的 JSON 数据包 使用示例:: from wechatpy import WeChatClient client = WeChatClient('appid', 'secret') info = client.message.get_autoreply_info() """ return self._get('get_current_autoreply_info') def send_mass_card(self, group_or_users, card_id, is_to_all=False, preview=False): """ 群发卡券消息 详情请参考 http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html :param group_or_users: 值为整型数字时为按分组群发,值为列表/元组时为按 OpenID 列表群发 :param card_id: 卡券 ID :param is_to_all: 用于设定是否向全部用户发送,值为true或false,选择true该消息群发给所有用户 选择false可根据group_id发送给指定群组的用户 :param preview: 是否发送预览,此时 group_or_users 参数应为一个openid字符串 :return: 返回的 JSON 数据包 """ return self._send_mass_message( group_or_users, 'wxcard', { 'wxcard': { 'card_id': card_id } }, is_to_all, preview )