# -*- coding: utf8 # Author: [email protected] import hashlib import xml.etree.ElementTree as ET class WeiXin(object): def __init__(self, token=None, timestamp=None, nonce=None, signature=None, echostr=None, xml_body=None): self.token = token self.timestamp = timestamp self.nonce = nonce self.signature = signature self.echostr = echostr self.xml_body = xml_body @classmethod def on_connect(self, token=None, timestamp=None, nonce=None, signature=None, echostr=None): obj = WeiXin(token=token, timestamp=timestamp, nonce=nonce, signature=signature, echostr=echostr) return obj @classmethod def on_message(self, xml_body): obj = WeiXin(xml_body=xml_body) return obj def to_json(self): '''http://docs.python.org/2/library/xml.etree.elementtree.html#xml.etree.ElementTree.XML ''' j = {} root = ET.fromstring(self.xml_body) for child in root: if child.tag == 'CreateTime': value = long(child.text) else: value = child.text j[child.tag] = value return j def _to_tag(self, k): return ''.join([w.capitalize() for w in k.split('_')]) def _cdata(self, data): '''http://stackoverflow.com/questions/174890/how-to-output-cdata-using-elementtree ''' if type(data) is str: return '<![CDATA[%s]]>' % data.replace(']]>', ']]]]><![CDATA[>') return data def to_xml(self, **kwargs): xml = '<xml>' def cmp(x, y): ''' WeiXin need ordered elements? ''' orderd = ['to_user_name', 'from_user_name', 'create_time', 'msg_type', 'content', 'func_flag'] try: ix = orderd.index(x) except ValueError: return 1 try: iy = orderd.index(y) except ValueError: return -1 return ix - iy for k in sorted(kwargs.iterkeys(), cmp): v = kwargs[k] tag = self._to_tag(k) xml += '<%s>%s</%s>' % (tag, self._cdata(v), tag) xml += '</xml>' return xml def validate(self): params = {} params['token'] = self.token params['timestamp'] = self.timestamp params['nonce'] = self.nonce signature = self.signature echostr = self.echostr if echostr is not None and self.is_not_none(params): _signature = self._signature(params) if _signature == signature: return True return False def is_not_none(self, params): for k, v in params.items(): if v is None: return False return True def _signature(self, params): '''http://docs.python.org/2/library/hashlib.html ''' a = sorted([v for k, v in params.items()]) s = ''.join(a) return hashlib.sha1(s).hexdigest() import unittest class WeiXinTestCase(unittest.TestCase): def test_on_connect_validate(self): weixin = WeiXin.on_connect(token='token', timestamp='timestamp', nonce='nonce', signature='6db4861c77e0633e0105672fcd41c9fc2766e26e', echostr='echostr') self.assertEqual(weixin.validate(), True) def test_on_connect_validate_false(self): weixin = WeiXin.on_connect(token='token', timestamp='timestamp', nonce='nonce_false', signature='6db4861c77e0633e0105672fcd41c9fc2766e26e', echostr='echostr') self.assertEqual(weixin.validate(), False) def test_on_message_text(self): body = ''' <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml> ''' weixin = WeiXin.on_message(body) j = weixin.to_json() def assertParam(name, value): self.assertEqual(name in j, True) self.assertEqual(j[name], value) assertParam('ToUserName', 'toUser') assertParam('FromUserName', 'fromUser') assertParam('CreateTime', 1348831860) assertParam('MsgType', 'text') assertParam('Content', 'this is a test') assertParam('MsgId', '1234567890123456') def test_on_message_image(self): body = ''' <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[image]]></MsgType> <PicUrl><![CDATA[this is a url]]></PicUrl> <MsgId>1234567890123456</MsgId> </xml> ''' weixin = WeiXin.on_message(body) j = weixin.to_json() def assertParam(name, value): self.assertEqual(name in j, True) self.assertEqual(j[name], value) assertParam('ToUserName', 'toUser') assertParam('FromUserName', 'fromUser') assertParam('CreateTime', 1348831860) assertParam('MsgType', 'image') assertParam('PicUrl', 'this is a url') assertParam('MsgId', '1234567890123456') def test_on_message_location(self): body = ''' <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1351776360</CreateTime> <MsgType><![CDATA[location]]></MsgType> <Location_X>23.134521</Location_X> <Location_Y>113.358803</Location_Y> <Scale>20</Scale> <Label><![CDATA[位置信息]]></Label> <MsgId>1234567890123456</MsgId> </xml> ''' weixin = WeiXin.on_message(body) j = weixin.to_json() def assertParam(name, value): self.assertEqual(name in j, True) self.assertEqual(j[name], value) assertParam('ToUserName', 'toUser') assertParam('FromUserName', 'fromUser') assertParam('CreateTime', 1351776360) assertParam('MsgType', 'location') assertParam('Location_X', '23.134521') assertParam('Location_Y', '113.358803') assertParam('Scale', '20') assertParam('Label', u'位置信息') assertParam('MsgId', '1234567890123456') def test_on_message_link(self): body = ''' <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1351776360</CreateTime> <MsgType><![CDATA[link]]></MsgType> <Title><![CDATA[公众平台官网链接]]></Title> <Description><![CDATA[公众平台官网链接]]></Description> <Url><![CDATA[url]]></Url> <MsgId>1234567890123456</MsgId> </xml> ''' weixin = WeiXin.on_message(body) j = weixin.to_json() def assertParam(name, value): self.assertEqual(name in j, True) self.assertEqual(j[name], value) assertParam('ToUserName', 'toUser') assertParam('FromUserName', 'fromUser') assertParam('CreateTime', 1351776360) assertParam('MsgType', 'link') assertParam('Title', u'公众平台官网链接') assertParam('Description', u'公众平台官网链接') assertParam('Url', 'url') assertParam('MsgId', '1234567890123456') def test_to_xml_text(self): xml = ''' <xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[content]]></Content> <FuncFlag>0</FuncFlag> </xml> ''' weixin = WeiXin() to_user_name = 'toUser' from_user_name = 'fromUser' create_time = 12345678 msg_type = 'text' content = 'content' func_flag = 0 self.assertEqual(xml.replace('\n', '').replace(' ', '').strip(), weixin.to_xml(to_user_name=to_user_name, from_user_name=from_user_name, create_time=create_time, msg_type=msg_type, content=content, func_flag=func_flag)) if __name__ == '__main__': unittest.main()