diff --git a/.history/api/examples/AppChatTest_20250317081400.py b/.history/api/examples/AppChatTest_20250317081400.py new file mode 100644 index 0000000..aed9add --- /dev/null +++ b/.history/api/examples/AppChatTest_20250317081400.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File UserTest.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +sys.path.append("../src/") + +import random + +from CorpApi import * +from TestConf import * + +## test +api = CorpApi(TestConf['CORP_ID'], TestConf['APP_SECRET']) + +chatid = "test210"; +try : +## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_CREATE'], + { + 'name' : 'appchat_test', + 'owner' : 'ZhuBiaoYi', + 'userlist' : ['LiShuang', 'ZhuShengBen', 'LinJianEn', 'ZhuBiaoYi', 'XuBin', 'yangpeiyi', 'HaLuoTeQu', 'lucky', 'raindong', 'simon', 'Wang', 'ZhaoDong', 'DengLinSheng', 'Li'], + 'chatid' : chatid, + }) + print response + chatid = response['chatid'] +except ApiException as e : + print e.errCode, e.errMsg + +try : + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_UPDATE'], + { + 'chatid' : chatid, + 'name' : 'appchat_test_new_name', + 'owner' : 'ZhuShengBen', + 'add_user_list' : ['huqiqi', 'Wang'] + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_UPDATE'], + { + 'chatid' : chatid, + 'name' : '应用发消息测试', + 'owner' : 'ZhuBiaoYi', + 'del_user_list' : 'huqiqi', + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'msgtype' : 'text', + 'text' : {'content':'我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党'}, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'safe' : 1, + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'msgtype' : 'image', + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'image' : { + 'media_id':'3A9Jo9CHit_5UTfOVE38_067dUJQlLs30mOa9FC0a4jEGeoQgpLCZgc7rEza6TbfB', + }, + 'safe' : 1, + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'msgtype' : 'file', + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'file' : { + 'media_id':'35L7MmcpGdyFfqjbGhbECCkGcaNsUajaPQifGLJq_H5E', + }, + 'safe' : 1, + }) + print response + + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'msgtype' : 'voice', + 'voice' : { + 'media_id':'3x1yb34061fDXjyUXy2rWNd-a-hWe-l8eTw2VKyh3bDQ', + }, + 'safe' : 1, + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'msgtype' : 'video', + 'video' : { + 'media_id':'3neA1ypnC3k5QnAZqvyVvCesFYUrXietU5F-Ipnj6ZobiD-PuFlXngzPplWXibw9r', + }, + 'safe' : 1, + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'msgtype' : 'news', + "news" : { + "articles" : [ + { + "title" : "图文消息", + "description" : "今年中秋节公司有豪礼相送", + "url" : "URL", + "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png", + "btntxt":"更多", + }, + { + "title" : "图文消息", + "description" : "今年中秋节公司有豪礼相送", + "url" : "URL", + "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png", + "btntxt":"更多", + }, + { + "title" : "图文消息", + "description" : "今年中秋节公司有豪礼相送", + "url" : "URL", + "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png", + "btntxt":"更多", + }, + ]}, + 'safe' : 1, + }, + ) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'msgtype' : 'textcard', + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'textcard' : { + 'title':'我是文本卡片消息', + 'description' : 'aaaaaaa', + 'url' : 'www.qq.com', + 'btntxt' : '更多', + }, + 'safe' : 1, + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + "msgtype" : "mpnews", + "mpnews": { + "articles" : [ + { + "title" : "图文消息(mpnews)", + "thumb_media_id" : "3uFTZs4MRTr-OwUArqaoXPyqtuedcwCUW1x4sgKcOeQc", + "author" : "author", + "content" : "content", + "digest" : "我是图文" + }, + { + "title" : "图文消息(mpnews)", + "thumb_media_id" : "3uFTZs4MRTr-OwUArqaoXPyqtuedcwCUW1x4sgKcOeQc", + "author" : "author", + "content" : "content", + "digest" : "我是图文" + }, + { + "title" : "图文消息(mpnews)", + "thumb_media_id" : "3uFTZs4MRTr-OwUArqaoXPyqtuedcwCUW1x4sgKcOeQc", + "author" : "author", + "content" : "content", + "digest" : "我是图文" + }, + ] + }, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'safe' : 1, + }) + print response + +except ApiException as e : + print e.errCode, e.errMsg diff --git a/.history/api/examples/AppChatTest_20250317090103.py b/.history/api/examples/AppChatTest_20250317090103.py new file mode 100644 index 0000000..65c181b --- /dev/null +++ b/.history/api/examples/AppChatTest_20250317090103.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File UserTest.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +sys.path.append("../src/") + +import random + +from CorpApi import * +from TestConf import * + +## test +api = CorpApi(TestConf['CORP_ID'], TestConf['APP_SECRET']) + +chatid = "test210"; +try : +## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_CREATE'], + { + 'name' : 'appchat_test', + 'owner' : 'ZhuBiaoYi', + 'userlist' : ['LiShuang', 'ZhuShengBen', 'LinJianEn', 'ZhuBiaoYi', 'XuBin', 'yangpeiyi', 'HaLuoTeQu', 'lucky', 'raindong', 'simon', 'Wang', 'ZhaoDong', 'DengLinSheng', 'Li'], + 'chatid' : chatid, + }) + print(response ) + chatid = response['chatid'] +except ApiException as e : + print(e.errCode, e.errMsg) + +try : + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_UPDATE'], + { + 'chatid' : chatid, + 'name' : 'appchat_test_new_name', + 'owner' : 'ZhuShengBen', + 'add_user_list' : ['huqiqi', 'Wang'] + }) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_UPDATE'], + { + 'chatid' : chatid, + 'name' : '应用发消息测试', + 'owner' : 'ZhuBiaoYi', + 'del_user_list' : 'huqiqi', + }) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'msgtype' : 'text', + 'text' : {'content':'我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党我是文本消息热爱祖国热爱人民热爱中国共产党'}, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'safe' : 1, + }) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'msgtype' : 'image', + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'image' : { + 'media_id':'3A9Jo9CHit_5UTfOVE38_067dUJQlLs30mOa9FC0a4jEGeoQgpLCZgc7rEza6TbfB', + }, + 'safe' : 1, + }) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'msgtype' : 'file', + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'file' : { + 'media_id':'35L7MmcpGdyFfqjbGhbECCkGcaNsUajaPQifGLJq_H5E', + }, + 'safe' : 1, + }) + print(response ) + + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'msgtype' : 'voice', + 'voice' : { + 'media_id':'3x1yb34061fDXjyUXy2rWNd-a-hWe-l8eTw2VKyh3bDQ', + }, + 'safe' : 1, + }) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'msgtype' : 'video', + 'video' : { + 'media_id':'3neA1ypnC3k5QnAZqvyVvCesFYUrXietU5F-Ipnj6ZobiD-PuFlXngzPplWXibw9r', + }, + 'safe' : 1, + }) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'msgtype' : 'news', + "news" : { + "articles" : [ + { + "title" : "图文消息", + "description" : "今年中秋节公司有豪礼相送", + "url" : "URL", + "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png", + "btntxt":"更多", + }, + { + "title" : "图文消息", + "description" : "今年中秋节公司有豪礼相送", + "url" : "URL", + "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png", + "btntxt":"更多", + }, + { + "title" : "图文消息", + "description" : "今年中秋节公司有豪礼相送", + "url" : "URL", + "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png", + "btntxt":"更多", + }, + ]}, + 'safe' : 1, + }, + ) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + 'msgtype' : 'textcard', + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'textcard' : { + 'title':'我是文本卡片消息', + 'description' : 'aaaaaaa', + 'url' : 'www.qq.com', + 'btntxt' : '更多', + }, + 'safe' : 1, + }) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['APP_CHAT_SEND'], + { + 'chatid':chatid, + "msgtype" : "mpnews", + "mpnews": { + "articles" : [ + { + "title" : "图文消息(mpnews)", + "thumb_media_id" : "3uFTZs4MRTr-OwUArqaoXPyqtuedcwCUW1x4sgKcOeQc", + "author" : "author", + "content" : "content", + "digest" : "我是图文" + }, + { + "title" : "图文消息(mpnews)", + "thumb_media_id" : "3uFTZs4MRTr-OwUArqaoXPyqtuedcwCUW1x4sgKcOeQc", + "author" : "author", + "content" : "content", + "digest" : "我是图文" + }, + { + "title" : "图文消息(mpnews)", + "thumb_media_id" : "3uFTZs4MRTr-OwUArqaoXPyqtuedcwCUW1x4sgKcOeQc", + "author" : "author", + "content" : "content", + "digest" : "我是图文" + }, + ] + }, + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'safe' : 1, + }) + print(response ) + +except ApiException as e : + print(e.errCode, e.errMsg) diff --git a/.history/api/examples/MessageTest_20250317081400.py b/.history/api/examples/MessageTest_20250317081400.py new file mode 100644 index 0000000..c07b005 --- /dev/null +++ b/.history/api/examples/MessageTest_20250317081400.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File UserTest.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +sys.path.append("../src/") + +import random + +from CorpApi import * +from TestConf import * + +## test +api = CorpApi(TestConf['CORP_ID'], TestConf['APP_SECRET']) + +try : +## + response = api.httpCall( + CORP_API_TYPE['MESSAGE_SEND'], + { + "touser": "ZhuShengBen", + "agentid": 1000002, + 'msgtype' : 'text', + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'text' : { + 'content':'方法论', + }, + 'safe' : 0, + }) + print response +except ApiException as e : + print e.errCode, e.errMsg + diff --git a/.history/api/examples/MessageTest_20250317114557.py b/.history/api/examples/MessageTest_20250317114557.py new file mode 100644 index 0000000..0c3a514 --- /dev/null +++ b/.history/api/examples/MessageTest_20250317114557.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File UserTest.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +sys.path.append("../src/") + +import random + +from CorpApi import * +from TestConf import * + +## test +api = CorpApi(TestConf['CORP_ID'], TestConf['APP_SECRET']) + +try : +## + response = api.httpCall( + CORP_API_TYPE['MESSAGE_SEND'], + { + "touser": "ZhuShengBen", + "agentid": 1000002, + 'msgtype' : 'text', + 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), + 'text' : { + 'content':'方法论', + }, + 'safe' : 0, + }) + print(response ) +except ApiException as e : + print(e.errCode, e.errMsg) + diff --git a/.history/api/examples/UserTest_20250317081400.py b/.history/api/examples/UserTest_20250317081400.py new file mode 100644 index 0000000..1dd6677 --- /dev/null +++ b/.history/api/examples/UserTest_20250317081400.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File UserTest.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +sys.path.append("../src/") + +from CorpApi import * +from TestConf import * + +## test +api = CorpApi(TestConf['CORP_ID'], TestConf['CONTACT_SYNC_SECRET']) + +try : + ## + response = api.httpCall( + CORP_API_TYPE['USER_CREATE'], + { + 'userid' : 'zhangsan', + 'name' : 'zhangsanfeng', + 'mobile' : '131488888888', + 'email' : 'zhangsan@ipp.cas.cn', + 'department' : 1, + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['USER_GET'], + { + 'userid' : 'zhangsan', + }) + print response + + ## + response = api.httpCall( + CORP_API_TYPE['USER_DELETE'], + { + 'userid' : 'zhangsan', + }) + print response + +except ApiException as e : + print e.errCode, e.errMsg + + ## + response = api.httpCall( + CORP_API_TYPE['USER_DELETE'], + { + 'userid' : 'zhangsan', + }) + print response + + diff --git a/.history/api/examples/UserTest_20250317085526.py b/.history/api/examples/UserTest_20250317085526.py new file mode 100644 index 0000000..ba0a446 --- /dev/null +++ b/.history/api/examples/UserTest_20250317085526.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File UserTest.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +sys.path.append("../src/") + +from CorpApi import * +from TestConf import * + +## test +api = CorpApi(TestConf['CORP_ID'], TestConf['CONTACT_SYNC_SECRET']) + +try : + ## + response = api.httpCall( + CORP_API_TYPE['USER_CREATE'], + { + 'userid' : 'zhangsan', + 'name' : 'zhangsanfeng', + 'mobile' : '131488888888', + 'email' : 'zhangsan@ipp.cas.cn', + 'department' : 1, + }) + print(response ) + + ## + response = api.httpCall( + CORP_API_TYPE['USER_GET'], + { + 'userid' : 'zhangsan', + }) + print(response) + + ## + response = api.httpCall( + CORP_API_TYPE['USER_DELETE'], + { + 'userid' : 'zhangsan', + }) + print(response) + +except ApiException as e : + print(e.errCode, e.errMsg) + + ## + response = api.httpCall( + CORP_API_TYPE['USER_DELETE'], + { + 'userid' : 'zhangsan', + }) + print(response) + + diff --git a/.history/api/src/AbstractApi_20250317081400.py b/.history/api/src/AbstractApi_20250317081400.py new file mode 100644 index 0000000..9c15796 --- /dev/null +++ b/.history/api/src/AbstractApi_20250317081400.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File AbstractApi.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +import os +import re + +import json +import requests + +sys.path.append("../../") + +from conf import DEBUG + +class ApiException(Exception) : + def __init__(self, errCode, errMsg) : + self.errCode = errCode + self.errMsg = errMsg + +class AbstractApi(object) : + def __init__(self) : + return + + def getAccessToken(self) : + raise NotImplementedError + def refreshAccessToken(self) : + raise NotImplementedError + + def getSuiteAccessToken(self) : + raise NotImplementedError + def refreshSuiteAccessToken(self) : + raise NotImplementedError + + def getProviderAccessToken(self) : + raise NotImplementedError + def refreshProviderAccessToken(self) : + raise NotImplementedError + + def httpCall(self, urlType, args=None) : + shortUrl = urlType[0] + method = urlType[1] + response = {} + for retryCnt in range(0, 3) : + if 'POST' == method : + url = self.__makeUrl(shortUrl) + response = self.__httpPost(url, args) + elif 'GET' == method : + url = self.__makeUrl(shortUrl) + url = self.__appendArgs(url, args) + response = self.__httpGet(url) + else : + raise ApiException(-1, "unknown method type") + + # check if token expired + if self.__tokenExpired(response.get('errcode')) : + self.__refreshToken(shortUrl) + retryCnt += 1 + continue + else : + break + + return self.__checkResponse(response) + + @staticmethod + def __appendArgs(url, args) : + if args is None : + return url + + for key, value in args.items() : + if '?' in url : + url += ('&' + key + '=' + value) + else : + url += ('?' + key + '=' + value) + return url + + @staticmethod + def __makeUrl(shortUrl) : + base = "https://qyapi.weixin.qq.com" + if shortUrl[0] == '/' : + return base + shortUrl + else : + return base + '/' + shortUrl + + def __appendToken(self, url) : + if 'SUITE_ACCESS_TOKEN' in url : + return url.replace('SUITE_ACCESS_TOKEN', self.getSuiteAccessToken()) + elif 'PROVIDER_ACCESS_TOKEN' in url : + return url.replace('PROVIDER_ACCESS_TOKEN', self.getProviderAccessToken()) + elif 'ACCESS_TOKEN' in url : + return url.replace('ACCESS_TOKEN', self.getAccessToken()) + else : + return url + + def __httpPost(self, url, args) : + realUrl = self.__appendToken(url) + + if DEBUG is True : + print realUrl, args + + return requests.post(realUrl, data = json.dumps(args, ensure_ascii = False).encode('utf-8')).json() + + def __httpGet(self, url) : + realUrl = self.__appendToken(url) + + if DEBUG is True : + print realUrl + + return requests.get(realUrl).json() + + def __post_file(self, url, media_file): + return requests.post(url, file=media_file).json() + + @staticmethod + def __checkResponse(response): + errCode = response.get('errcode') + errMsg = response.get('errmsg') + + if errCode is 0: + return response + else: + raise ApiException(errCode, errMsg) + + @staticmethod + def __tokenExpired(errCode) : + if errCode == 40014 or errCode == 42001 or errCode == 42007 or errCode == 42009 : + return True + else : + return False + + def __refreshToken(self, url) : + if 'SUITE_ACCESS_TOKEN' in url : + self.refreshSuiteAccessToken() + elif 'PROVIDER_ACCESS_TOKEN' in url : + self.refreshProviderAccessToken() + elif 'ACCESS_TOKEN' in url : + self.refreshAccessToken() diff --git a/.history/api/src/AbstractApi_20250317084136.py b/.history/api/src/AbstractApi_20250317084136.py new file mode 100644 index 0000000..7897931 --- /dev/null +++ b/.history/api/src/AbstractApi_20250317084136.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File AbstractApi.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +import os +import re + +import json +import requests + +sys.path.append("../../") + +from conf import DEBUG + +class ApiException(Exception) : + def __init__(self, errCode, errMsg) : + self.errCode = errCode + self.errMsg = errMsg + +class AbstractApi(object) : + def __init__(self) : + return + + def getAccessToken(self) : + raise NotImplementedError + def refreshAccessToken(self) : + raise NotImplementedError + + def getSuiteAccessToken(self) : + raise NotImplementedError + def refreshSuiteAccessToken(self) : + raise NotImplementedError + + def getProviderAccessToken(self) : + raise NotImplementedError + def refreshProviderAccessToken(self) : + raise NotImplementedError + + def httpCall(self, urlType, args=None) : + shortUrl = urlType[0] + method = urlType[1] + response = {} + for retryCnt in range(0, 3) : + if 'POST' == method : + url = self.__makeUrl(shortUrl) + response = self.__httpPost(url, args) + elif 'GET' == method : + url = self.__makeUrl(shortUrl) + url = self.__appendArgs(url, args) + response = self.__httpGet(url) + else : + raise ApiException(-1, "unknown method type") + + # check if token expired + if self.__tokenExpired(response.get('errcode')) : + self.__refreshToken(shortUrl) + retryCnt += 1 + continue + else : + break + + return self.__checkResponse(response) + + @staticmethod + def __appendArgs(url, args) : + if args is None : + return url + + for key, value in args.items() : + if '?' in url : + url += ('&' + key + '=' + value) + else : + url += ('?' + key + '=' + value) + return url + + @staticmethod + def __makeUrl(shortUrl) : + base = "https://qyapi.weixin.qq.com" + if shortUrl[0] == '/' : + return base + shortUrl + else : + return base + '/' + shortUrl + + def __appendToken(self, url) : + if 'SUITE_ACCESS_TOKEN' in url : + return url.replace('SUITE_ACCESS_TOKEN', self.getSuiteAccessToken()) + elif 'PROVIDER_ACCESS_TOKEN' in url : + return url.replace('PROVIDER_ACCESS_TOKEN', self.getProviderAccessToken()) + elif 'ACCESS_TOKEN' in url : + return url.replace('ACCESS_TOKEN', self.getAccessToken()) + else : + return url + + def __httpPost(self, url, args) : + realUrl = self.__appendToken(url) + + if DEBUG is True : + print(realUrl, args) + + return requests.post(realUrl, data = json.dumps(args, ensure_ascii = False).encode('utf-8')).json() + + def __httpGet(self, url) : + realUrl = self.__appendToken(url) + + if DEBUG is True : + print(realUrl) + + return requests.get(realUrl).json() + + def __post_file(self, url, media_file): + return requests.post(url, file=media_file).json() + + @staticmethod + def __checkResponse(response): + errCode = response.get('errcode') + errMsg = response.get('errmsg') + + if errCode == 0: + return response + else: + raise ApiException(errCode, errMsg) + + @staticmethod + def __tokenExpired(errCode) : + if errCode == 40014 or errCode == 42001 or errCode == 42007 or errCode == 42009 : + return True + else : + return False + + def __refreshToken(self, url) : + if 'SUITE_ACCESS_TOKEN' in url : + self.refreshSuiteAccessToken() + elif 'PROVIDER_ACCESS_TOKEN' in url : + self.refreshProviderAccessToken() + elif 'ACCESS_TOKEN' in url : + self.refreshAccessToken() diff --git a/.history/api/src/AbstractApi_20250317084143.py b/.history/api/src/AbstractApi_20250317084143.py new file mode 100644 index 0000000..7897931 --- /dev/null +++ b/.history/api/src/AbstractApi_20250317084143.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File AbstractApi.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +import sys +import os +import re + +import json +import requests + +sys.path.append("../../") + +from conf import DEBUG + +class ApiException(Exception) : + def __init__(self, errCode, errMsg) : + self.errCode = errCode + self.errMsg = errMsg + +class AbstractApi(object) : + def __init__(self) : + return + + def getAccessToken(self) : + raise NotImplementedError + def refreshAccessToken(self) : + raise NotImplementedError + + def getSuiteAccessToken(self) : + raise NotImplementedError + def refreshSuiteAccessToken(self) : + raise NotImplementedError + + def getProviderAccessToken(self) : + raise NotImplementedError + def refreshProviderAccessToken(self) : + raise NotImplementedError + + def httpCall(self, urlType, args=None) : + shortUrl = urlType[0] + method = urlType[1] + response = {} + for retryCnt in range(0, 3) : + if 'POST' == method : + url = self.__makeUrl(shortUrl) + response = self.__httpPost(url, args) + elif 'GET' == method : + url = self.__makeUrl(shortUrl) + url = self.__appendArgs(url, args) + response = self.__httpGet(url) + else : + raise ApiException(-1, "unknown method type") + + # check if token expired + if self.__tokenExpired(response.get('errcode')) : + self.__refreshToken(shortUrl) + retryCnt += 1 + continue + else : + break + + return self.__checkResponse(response) + + @staticmethod + def __appendArgs(url, args) : + if args is None : + return url + + for key, value in args.items() : + if '?' in url : + url += ('&' + key + '=' + value) + else : + url += ('?' + key + '=' + value) + return url + + @staticmethod + def __makeUrl(shortUrl) : + base = "https://qyapi.weixin.qq.com" + if shortUrl[0] == '/' : + return base + shortUrl + else : + return base + '/' + shortUrl + + def __appendToken(self, url) : + if 'SUITE_ACCESS_TOKEN' in url : + return url.replace('SUITE_ACCESS_TOKEN', self.getSuiteAccessToken()) + elif 'PROVIDER_ACCESS_TOKEN' in url : + return url.replace('PROVIDER_ACCESS_TOKEN', self.getProviderAccessToken()) + elif 'ACCESS_TOKEN' in url : + return url.replace('ACCESS_TOKEN', self.getAccessToken()) + else : + return url + + def __httpPost(self, url, args) : + realUrl = self.__appendToken(url) + + if DEBUG is True : + print(realUrl, args) + + return requests.post(realUrl, data = json.dumps(args, ensure_ascii = False).encode('utf-8')).json() + + def __httpGet(self, url) : + realUrl = self.__appendToken(url) + + if DEBUG is True : + print(realUrl) + + return requests.get(realUrl).json() + + def __post_file(self, url, media_file): + return requests.post(url, file=media_file).json() + + @staticmethod + def __checkResponse(response): + errCode = response.get('errcode') + errMsg = response.get('errmsg') + + if errCode == 0: + return response + else: + raise ApiException(errCode, errMsg) + + @staticmethod + def __tokenExpired(errCode) : + if errCode == 40014 or errCode == 42001 or errCode == 42007 or errCode == 42009 : + return True + else : + return False + + def __refreshToken(self, url) : + if 'SUITE_ACCESS_TOKEN' in url : + self.refreshSuiteAccessToken() + elif 'PROVIDER_ACCESS_TOKEN' in url : + self.refreshProviderAccessToken() + elif 'ACCESS_TOKEN' in url : + self.refreshAccessToken() diff --git a/.history/api/src/CorpApi_20250317081400.py b/.history/api/src/CorpApi_20250317081400.py new file mode 100644 index 0000000..4f04a23 --- /dev/null +++ b/.history/api/src/CorpApi_20250317081400.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File CorpApi.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +from AbstractApi import * + +CORP_API_TYPE = { + 'GET_ACCESS_TOKEN' : ['/cgi-bin/gettoken', 'GET'], + 'USER_CREATE' : ['/cgi-bin/user/create?access_token=ACCESS_TOKEN', 'POST'], + 'USER_GET' : ['/cgi-bin/user/get?access_token=ACCESS_TOKEN', 'GET'], + 'USER_UPDATE' : ['/cgi-bin/user/update?access_token=ACCESS_TOKEN', 'POST'], + 'USER_DELETE' : ['/cgi-bin/user/delete?access_token=ACCESS_TOKEN', 'GET'], + 'USER_BATCH_DELETE': ['/cgi-bin/user/batchdelete?access_token=ACCESS_TOKEN', 'POST'], + 'USER_SIMPLE_LIST': ['/cgi-bin/user/simplelist?access_token=ACCESS_TOKEN', 'GET'], + 'USER_LIST' : ['/cgi-bin/user/list?access_token=ACCESS_TOKEN', 'GET'], + 'USERID_TO_OPENID' : ['/cgi-bin/user/convert_to_openid?access_token=ACCESS_TOKEN', 'POST'], + 'OPENID_TO_USERID' : ['/cgi-bin/user/convert_to_userid?access_token=ACCESS_TOKEN', 'POST'], + 'USER_AUTH_SUCCESS': ['/cgi-bin/user/authsucc?access_token=ACCESS_TOKEN', 'GET'], + + 'DEPARTMENT_CREATE': ['/cgi-bin/department/create?access_token=ACCESS_TOKEN', 'POST'], + 'DEPARTMENT_UPDATE': ['/cgi-bin/department/update?access_token=ACCESS_TOKEN', 'POST'], + 'DEPARTMENT_DELETE': ['/cgi-bin/department/delete?access_token=ACCESS_TOKEN', 'GET'], + 'DEPARTMENT_LIST' : ['/cgi-bin/department/list?access_token=ACCESS_TOKEN', 'GET'], + + 'TAG_CREATE' : ['/cgi-bin/tag/create?access_token=ACCESS_TOKEN', 'POST'], + 'TAG_UPDATE' : ['/cgi-bin/tag/update?access_token=ACCESS_TOKEN', 'POST'], + 'TAG_DELETE' : ['/cgi-bin/tag/delete?access_token=ACCESS_TOKEN', 'GET'], + 'TAG_GET_USER' : ['/cgi-bin/tag/get?access_token=ACCESS_TOKEN', 'GET'], + 'TAG_ADD_USER' : ['/cgi-bin/tag/addtagusers?access_token=ACCESS_TOKEN', 'POST'], + 'TAG_DELETE_USER' : ['/cgi-bin/tag/deltagusers?access_token=ACCESS_TOKEN', 'POST'], + 'TAG_GET_LIST' : ['/cgi-bin/tag/list?access_token=ACCESS_TOKEN', 'GET'], + + 'BATCH_JOB_GET_RESULT' : ['/cgi-bin/batch/getresult?access_token=ACCESS_TOKEN', 'GET'], + + 'BATCH_INVITE' : ['/cgi-bin/batch/invite?access_token=ACCESS_TOKEN', 'POST'], + + 'AGENT_GET' : ['/cgi-bin/agent/get?access_token=ACCESS_TOKEN', 'GET'], + 'AGENT_SET' : ['/cgi-bin/agent/set?access_token=ACCESS_TOKEN', 'POST'], + 'AGENT_GET_LIST' : ['/cgi-bin/agent/list?access_token=ACCESS_TOKEN', 'GET'], + + 'MENU_CREATE' : ['/cgi-bin/menu/create?access_token=ACCESS_TOKEN', 'POST'], ## TODO + 'MENU_GET' : ['/cgi-bin/menu/get?access_token=ACCESS_TOKEN', 'GET'], + 'MENU_DELETE' : ['/cgi-bin/menu/delete?access_token=ACCESS_TOKEN', 'GET'], + + 'MESSAGE_SEND' : ['/cgi-bin/message/send?access_token=ACCESS_TOKEN', 'POST'], + 'MESSAGE_REVOKE' : ['/cgi-bin/message/revoke?access_token=ACCESS_TOKEN', 'POST'], + + 'MEDIA_GET' : ['/cgi-bin/media/get?access_token=ACCESS_TOKEN', 'GET'], + + 'GET_USER_INFO_BY_CODE' : ['/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN', 'GET'], + 'GET_USER_DETAIL' : ['/cgi-bin/user/getuserdetail?access_token=ACCESS_TOKEN', 'POST'], + + 'GET_TICKET' : ['/cgi-bin/ticket/get?access_token=ACCESS_TOKEN', 'GET'], + 'GET_JSAPI_TICKET' : ['/cgi-bin/get_jsapi_ticket?access_token=ACCESS_TOKEN', 'GET'], + + 'GET_CHECKIN_OPTION' : ['/cgi-bin/checkin/getcheckinoption?access_token=ACCESS_TOKEN', 'POST'], + 'GET_CHECKIN_DATA' : ['/cgi-bin/checkin/getcheckindata?access_token=ACCESS_TOKEN', 'POST'], + 'GET_APPROVAL_DATA': ['/cgi-bin/corp/getapprovaldata?access_token=ACCESS_TOKEN', 'POST'], + + 'GET_INVOICE_INFO' : ['/cgi-bin/card/invoice/reimburse/getinvoiceinfo?access_token=ACCESS_TOKEN', 'POST'], + 'UPDATE_INVOICE_STATUS' : + ['/cgi-bin/card/invoice/reimburse/updateinvoicestatus?access_token=ACCESS_TOKEN', 'POST'], + 'BATCH_UPDATE_INVOICE_STATUS' : + ['/cgi-bin/card/invoice/reimburse/updatestatusbatch?access_token=ACCESS_TOKEN', 'POST'], + 'BATCH_GET_INVOICE_INFO' : + ['/cgi-bin/card/invoice/reimburse/getinvoiceinfobatch?access_token=ACCESS_TOKEN', 'POST'], + + 'APP_CHAT_CREATE' : ['/cgi-bin/appchat/create?access_token=ACCESS_TOKEN', 'POST'], + 'APP_CHAT_GET' : ['/cgi-bin/appchat/get?access_token=ACCESS_TOKEN', 'GET'], + 'APP_CHAT_UPDATE' : ['/cgi-bin/appchat/update?access_token=ACCESS_TOKEN', 'POST'], + 'APP_CHAT_SEND' : ['/cgi-bin/appchat/send?access_token=ACCESS_TOKEN', 'POST'], + + 'MINIPROGRAM_CODE_TO_SESSION_KEY' : ['/cgi-bin/miniprogram/jscode2session?access_token=ACCESS_TOKEN', 'GET'], +} + +class CorpApi(AbstractApi) : + def __init__(self, corpid, secret) : + self.corpid = corpid + self.secret = secret + self.access_token = None + + def getAccessToken(self) : + if self.access_token is None : + self.refreshAccessToken() + return self.access_token + + def refreshAccessToken(self) : + response = self.httpCall( + CORP_API_TYPE['GET_ACCESS_TOKEN'], + { + 'corpid' : self.corpid, + 'corpsecret': self.secret, + }) + self.access_token = response.get('access_token') + diff --git a/.history/api/src/CorpApi_20250318130249.py b/.history/api/src/CorpApi_20250318130249.py new file mode 100644 index 0000000..0c164fa --- /dev/null +++ b/.history/api/src/CorpApi_20250318130249.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# -*- coding:utf-8 -*- +## + # Copyright (C) 2018 All rights reserved. + # + # @File CorpApi.py + # @Brief + # @Author abelzhu, abelzhu@tencent.com + # @Version 1.0 + # @Date 2018-02-24 + # + # + +from AbstractApi import * + +CORP_API_TYPE = { + 'GET_ACCESS_TOKEN' : ['/cgi-bin/gettoken', 'GET'], + 'USER_CREATE' : ['/cgi-bin/user/create?access_token=ACCESS_TOKEN', 'POST'], + 'USER_GET': ['/cgi-bin/user/get?access_token=ACCESS_TOKEN', 'GET'], + 'USER_UPDATE' : ['/cgi-bin/user/update?access_token=ACCESS_TOKEN', 'POST'], + 'USER_DELETE' : ['/cgi-bin/user/delete?access_token=ACCESS_TOKEN', 'GET'], + 'USER_BATCH_DELETE': ['/cgi-bin/user/batchdelete?access_token=ACCESS_TOKEN', 'POST'], + 'USER_SIMPLE_LIST': ['/cgi-bin/user/simplelist?access_token=ACCESS_TOKEN', 'GET'], + 'USER_LIST' : ['/cgi-bin/user/list?access_token=ACCESS_TOKEN', 'GET'], + 'USERID_TO_OPENID' : ['/cgi-bin/user/convert_to_openid?access_token=ACCESS_TOKEN', 'POST'], + 'OPENID_TO_USERID' : ['/cgi-bin/user/convert_to_userid?access_token=ACCESS_TOKEN', 'POST'], + 'USER_AUTH_SUCCESS': ['/cgi-bin/user/authsucc?access_token=ACCESS_TOKEN', 'GET'], + + 'DEPARTMENT_CREATE': ['/cgi-bin/department/create?access_token=ACCESS_TOKEN', 'POST'], + 'DEPARTMENT_UPDATE': ['/cgi-bin/department/update?access_token=ACCESS_TOKEN', 'POST'], + 'DEPARTMENT_DELETE': ['/cgi-bin/department/delete?access_token=ACCESS_TOKEN', 'GET'], + 'DEPARTMENT_LIST' : ['/cgi-bin/department/list?access_token=ACCESS_TOKEN', 'GET'], + + 'TAG_CREATE' : ['/cgi-bin/tag/create?access_token=ACCESS_TOKEN', 'POST'], + 'TAG_UPDATE' : ['/cgi-bin/tag/update?access_token=ACCESS_TOKEN', 'POST'], + 'TAG_DELETE' : ['/cgi-bin/tag/delete?access_token=ACCESS_TOKEN', 'GET'], + 'TAG_GET_USER' : ['/cgi-bin/tag/get?access_token=ACCESS_TOKEN', 'GET'], + 'TAG_ADD_USER' : ['/cgi-bin/tag/addtagusers?access_token=ACCESS_TOKEN', 'POST'], + 'TAG_DELETE_USER' : ['/cgi-bin/tag/deltagusers?access_token=ACCESS_TOKEN', 'POST'], + 'TAG_GET_LIST' : ['/cgi-bin/tag/list?access_token=ACCESS_TOKEN', 'GET'], + + 'BATCH_JOB_GET_RESULT' : ['/cgi-bin/batch/getresult?access_token=ACCESS_TOKEN', 'GET'], + + 'BATCH_INVITE' : ['/cgi-bin/batch/invite?access_token=ACCESS_TOKEN', 'POST'], + + 'AGENT_GET' : ['/cgi-bin/agent/get?access_token=ACCESS_TOKEN', 'GET'], + 'AGENT_SET' : ['/cgi-bin/agent/set?access_token=ACCESS_TOKEN', 'POST'], + 'AGENT_GET_LIST' : ['/cgi-bin/agent/list?access_token=ACCESS_TOKEN', 'GET'], + + 'MENU_CREATE' : ['/cgi-bin/menu/create?access_token=ACCESS_TOKEN', 'POST'], ## TODO + 'MENU_GET' : ['/cgi-bin/menu/get?access_token=ACCESS_TOKEN', 'GET'], + 'MENU_DELETE' : ['/cgi-bin/menu/delete?access_token=ACCESS_TOKEN', 'GET'], + + 'MESSAGE_SEND' : ['/cgi-bin/message/send?access_token=ACCESS_TOKEN', 'POST'], + 'MESSAGE_REVOKE' : ['/cgi-bin/message/revoke?access_token=ACCESS_TOKEN', 'POST'], + + 'MEDIA_GET' : ['/cgi-bin/media/get?access_token=ACCESS_TOKEN', 'GET'], + + 'GET_USER_INFO_BY_CODE' : ['/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN', 'GET'], + 'GET_USER_DETAIL' : ['/cgi-bin/user/getuserdetail?access_token=ACCESS_TOKEN', 'POST'], + + 'GET_TICKET' : ['/cgi-bin/ticket/get?access_token=ACCESS_TOKEN', 'GET'], + 'GET_JSAPI_TICKET' : ['/cgi-bin/get_jsapi_ticket?access_token=ACCESS_TOKEN', 'GET'], + + 'GET_CHECKIN_OPTION' : ['/cgi-bin/checkin/getcheckinoption?access_token=ACCESS_TOKEN', 'POST'], + 'GET_CHECKIN_DATA' : ['/cgi-bin/checkin/getcheckindata?access_token=ACCESS_TOKEN', 'POST'], + 'GET_APPROVAL_DATA': ['/cgi-bin/corp/getapprovaldata?access_token=ACCESS_TOKEN', 'POST'], + + 'GET_INVOICE_INFO' : ['/cgi-bin/card/invoice/reimburse/getinvoiceinfo?access_token=ACCESS_TOKEN', 'POST'], + 'UPDATE_INVOICE_STATUS' : + ['/cgi-bin/card/invoice/reimburse/updateinvoicestatus?access_token=ACCESS_TOKEN', 'POST'], + 'BATCH_UPDATE_INVOICE_STATUS' : + ['/cgi-bin/card/invoice/reimburse/updatestatusbatch?access_token=ACCESS_TOKEN', 'POST'], + 'BATCH_GET_INVOICE_INFO' : + ['/cgi-bin/card/invoice/reimburse/getinvoiceinfobatch?access_token=ACCESS_TOKEN', 'POST'], + + 'APP_CHAT_CREATE' : ['/cgi-bin/appchat/create?access_token=ACCESS_TOKEN', 'POST'], + 'APP_CHAT_GET' : ['/cgi-bin/appchat/get?access_token=ACCESS_TOKEN', 'GET'], + 'APP_CHAT_UPDATE' : ['/cgi-bin/appchat/update?access_token=ACCESS_TOKEN', 'POST'], + 'APP_CHAT_SEND' : ['/cgi-bin/appchat/send?access_token=ACCESS_TOKEN', 'POST'], + + 'MINIPROGRAM_CODE_TO_SESSION_KEY' : ['/cgi-bin/miniprogram/jscode2session?access_token=ACCESS_TOKEN', 'GET'], +} + +class CorpApi(AbstractApi) : + def __init__(self, corpid, secret) : + self.corpid = corpid + self.secret = secret + self.access_token = None + + def getAccessToken(self) : + if self.access_token is None : + self.refreshAccessToken() + return self.access_token + + def refreshAccessToken(self) : + response = self.httpCall( + CORP_API_TYPE['GET_ACCESS_TOKEN'], + { + 'corpid' : self.corpid, + 'corpsecret': self.secret, + }) + self.access_token = response.get('access_token') + diff --git a/.history/callback/Sample_20250317081400.py b/.history/callback/Sample_20250317081400.py new file mode 100644 index 0000000..4915ff2 --- /dev/null +++ b/.history/callback/Sample_20250317081400.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +######################################################################### +# Author: jonyqin +# Created Time: Thu 11 Sep 2014 03:55:41 PM CST +# File Name: Sample.py +# Description: WXBizMsgCrypt 使用demo文件 +######################################################################### +from WXBizMsgCrypt import WXBizMsgCrypt +import xml.etree.cElementTree as ET +import sys + +if __name__ == "__main__": + #假设企业在企业微信后台上设置的参数如下 + sToken = "hJqcu3uJ9Tn2gXPmxx2w9kkCkCE2EPYo" + sEncodingAESKey = "6qkdMrq68nTKduznJYO1A37W2oEgpkMUvkttRToqhUt" + sCorpID = "ww1436e0e65a779aee" + ''' + ------------使用示例一:验证回调URL--------------- + *企业开启回调模式时,企业号会向验证url发送一个get请求 + 假设点击验证时,企业收到类似请求: + * GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3×tamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D + * HTTP/1.1 Host: qy.weixin.qq.com + + 接收到该请求时,企业应 1.解析出Get请求的参数,包括消息体签名(msg_signature),时间戳(timestamp),随机数字串(nonce)以及企业微信推送过来的随机加密字符串(echostr), + 这一步注意作URL解码。 + 2.验证消息体签名的正确性 + 3. 解密出echostr原文,将原文当作Get请求的response,返回给企业微信 + 第2,3步可以用企业微信提供的库函数VerifyURL来实现。 + ''' + wxcpt=WXBizMsgCrypt(sToken,sEncodingAESKey,sCorpID) + #sVerifyMsgSig=HttpUtils.ParseUrl("msg_signature") + #ret = wxcpt.VerifyAESKey() + #print ret + sVerifyMsgSig="012bc692d0a58dd4b10f8dfe5c4ac00ae211ebeb" + #sVerifyTimeStamp=HttpUtils.ParseUrl("timestamp") + sVerifyTimeStamp="1476416373" + #sVerifyNonce=HttpUitls.ParseUrl("nonce") + sVerifyNonce="47744683" + #sVerifyEchoStr=HttpUtils.ParseUrl("echostr") + sVerifyEchoStr="fsi1xnbH4yQh0+PJxcOdhhK6TDXkjMyhEPA7xB2TGz6b+g7xyAbEkRxN/3cNXW9qdqjnoVzEtpbhnFyq6SVHyA==" + ret,sEchoStr=wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,sVerifyNonce,sVerifyEchoStr) + if(ret!=0): + print "ERR: VerifyURL ret: " + str(ret) + sys.exit(1) + #验证URL成功,将sEchoStr返回给企业号 + #HttpUtils.SetResponse(sEchoStr) + + ''' + ------------使用示例二:对用户回复的消息解密--------------- + 用户回复消息或者点击事件响应时,企业会收到回调消息,此消息是经过企业微信加密之后的密文以post形式发送给企业,密文格式请参考官方文档 + 假设企业收到企业微信的回调消息如下: + POST /cgi-bin/wxpush? msg_signature=477715d11cdb4164915debcba66cb864d751f3e6×tamp=1409659813&nonce=1372623149 HTTP/1.1 + Host: qy.weixin.qq.com + Content-Length: 613 + + + + + 企业收到post请求之后应该 1.解析出url上的参数,包括消息体签名(msg_signature),时间戳(timestamp)以及随机数字串(nonce) + 2.验证消息体签名的正确性。 3.将post请求的数据进行xml解析,并将标签的内容进行解密,解密出来的明文即是用户回复消息的明文,明文格式请参考官方文档 + 第2,3步可以用企业微信提供的库函数DecryptMsg来实现。 + ''' + # sReqMsgSig = HttpUtils.ParseUrl("msg_signature") + sReqMsgSig = "0c3914025cb4b4d68103f6bfc8db550f79dcf48e" + sReqTimeStamp = "1476422779" + sReqNonce = "1597212914" + sReqData = "\n\n\n" + ret,sMsg=wxcpt.DecryptMsg( sReqData, sReqMsgSig, sReqTimeStamp, sReqNonce) + print ret,sMsg + if( ret!=0 ): + print "ERR: DecryptMsg ret: " + str(ret) + sys.exit(1) + # 解密成功,sMsg即为xml格式的明文 + # TODO: 对明文的处理 + # For example: + xml_tree = ET.fromstring(sMsg) + content = xml_tree.find("Content").text + print content + # ... + # ... + + ''' + ------------使用示例三:企业回复用户消息的加密--------------- + 企业被动回复用户的消息也需要进行加密,并且拼接成密文格式的xml串。 + 假设企业需要回复用户的明文如下: + + + + 1348831860 + + + 1234567890123456 + 128 + + + 为了将此段明文回复给用户,企业应: 1.自己生成时间时间戳(timestamp),随机数字串(nonce)以便生成消息体签名,也可以直接用从企业微信的post url上解析出的对应值。 + 2.将明文加密得到密文。 3.用密文,步骤1生成的timestamp,nonce和企业在企业微信设定的token生成消息体签名。 4.将密文,消息体签名,时间戳,随机数字串拼接成xml格式的字符串,发送给企业号。 + 以上2,3,4步可以用企业微信提供的库函数EncryptMsg来实现。 + ''' + sRespData = "ww1436e0e65a779aeeChenJiaShun1476422779text你好14564537201000002" + ret,sEncryptMsg=wxcpt.EncryptMsg(sRespData, sReqNonce, sReqTimeStamp) + if( ret!=0 ): + print "ERR: EncryptMsg ret: " + str(ret) + sys.exit(1) + #ret == 0 加密成功,企业需要将sEncryptMsg返回给企业号 + #TODO: + #HttpUitls.SetResponse(sEncryptMsg) diff --git a/.history/callback/Sample_20250317162512.py b/.history/callback/Sample_20250317162512.py new file mode 100644 index 0000000..217db78 --- /dev/null +++ b/.history/callback/Sample_20250317162512.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +######################################################################### +# Author: jonyqin +# Created Time: Thu 11 Sep 2014 03:55:41 PM CST +# File Name: Sample.py +# Description: WXBizMsgCrypt 使用demo文件 +######################################################################### +from WXBizMsgCrypt import WXBizMsgCrypt +import xml.etree.cElementTree as ET +import sys + +if __name__ == "__main__": + #假设企业在企业微信后台上设置的参数如下 + sToken = "hJqcu3uJ9Tn2gXPmxx2w9kkCkCE2EPYo" + sEncodingAESKey = "6qkdMrq68nTKduznJYO1A37W2oEgpkMUvkttRToqhUt" + sCorpID = "ww1436e0e65a779aee" + ''' + ------------使用示例一:验证回调URL--------------- + *企业开启回调模式时,企业号会向验证url发送一个get请求 + 假设点击验证时,企业收到类似请求: + * GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3×tamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D + * HTTP/1.1 Host: qy.weixin.qq.com + + 接收到该请求时,企业应 1.解析出Get请求的参数,包括消息体签名(msg_signature),时间戳(timestamp),随机数字串(nonce)以及企业微信推送过来的随机加密字符串(echostr), + 这一步注意作URL解码。 + 2.验证消息体签名的正确性 + 3. 解密出echostr原文,将原文当作Get请求的response,返回给企业微信 + 第2,3步可以用企业微信提供的库函数VerifyURL来实现。 + ''' + wxcpt=WXBizMsgCrypt(sToken,sEncodingAESKey,sCorpID) + #sVerifyMsgSig=HttpUtils.ParseUrl("msg_signature") + #ret = wxcpt.VerifyAESKey() + #print(ret) + sVerifyMsgSig="012bc692d0a58dd4b10f8dfe5c4ac00ae211ebeb" + #sVerifyTimeStamp=HttpUtils.ParseUrl("timestamp") + sVerifyTimeStamp="1476416373" + #sVerifyNonce=HttpUitls.ParseUrl("nonce") + sVerifyNonce="47744683" + #sVerifyEchoStr=HttpUtils.ParseUrl("echostr") + sVerifyEchoStr="fsi1xnbH4yQh0+PJxcOdhhK6TDXkjMyhEPA7xB2TGz6b+g7xyAbEkRxN/3cNXW9qdqjnoVzEtpbhnFyq6SVHyA==" + ret,sEchoStr=wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,sVerifyNonce,sVerifyEchoStr) + if(ret!=0): + print("ERR: VerifyURL ret: " + str(ret)) + sys.exit(1) + #验证URL成功,将sEchoStr返回给企业号 + #HttpUtils.SetResponse(sEchoStr) + + ''' + ------------使用示例二:对用户回复的消息解密--------------- + 用户回复消息或者点击事件响应时,企业会收到回调消息,此消息是经过企业微信加密之后的密文以post形式发送给企业,密文格式请参考官方文档 + 假设企业收到企业微信的回调消息如下: + POST /cgi-bin/wxpush? msg_signature=477715d11cdb4164915debcba66cb864d751f3e6×tamp=1409659813&nonce=1372623149 HTTP/1.1 + Host: qy.weixin.qq.com + Content-Length: 613 + + + + + 企业收到post请求之后应该 1.解析出url上的参数,包括消息体签名(msg_signature),时间戳(timestamp)以及随机数字串(nonce) + 2.验证消息体签名的正确性。 3.将post请求的数据进行xml解析,并将标签的内容进行解密,解密出来的明文即是用户回复消息的明文,明文格式请参考官方文档 + 第2,3步可以用企业微信提供的库函数DecryptMsg来实现。 + ''' + # sReqMsgSig = HttpUtils.ParseUrl("msg_signature") + sReqMsgSig = "0c3914025cb4b4d68103f6bfc8db550f79dcf48e" + sReqTimeStamp = "1476422779" + sReqNonce = "1597212914" + sReqData = "\n\n\n" + ret,sMsg=wxcpt.DecryptMsg( sReqData, sReqMsgSig, sReqTimeStamp, sReqNonce) + print(ret,sMsg) + if( ret!=0 ): + print("ERR: DecryptMsg ret: " + str(ret)) + sys.exit(1) + # 解密成功,sMsg即为xml格式的明文 + # TODO: 对明文的处理 + # For example: + xml_tree = ET.fromstring(sMsg) + content = xml_tree.find("Content").text + print(content) + # ... + # ... + + ''' + ------------使用示例三:企业回复用户消息的加密--------------- + 企业被动回复用户的消息也需要进行加密,并且拼接成密文格式的xml串。 + 假设企业需要回复用户的明文如下: + + + + 1348831860 + + + 1234567890123456 + 128 + + + 为了将此段明文回复给用户,企业应: 1.自己生成时间时间戳(timestamp),随机数字串(nonce)以便生成消息体签名,也可以直接用从企业微信的post url上解析出的对应值。 + 2.将明文加密得到密文。 3.用密文,步骤1生成的timestamp,nonce和企业在企业微信设定的token生成消息体签名。 4.将密文,消息体签名,时间戳,随机数字串拼接成xml格式的字符串,发送给企业号。 + 以上2,3,4步可以用企业微信提供的库函数EncryptMsg来实现。 + ''' + sRespData = "ww1436e0e65a779aeeChenJiaShun1476422779text你好14564537201000002" + ret,sEncryptMsg=wxcpt.EncryptMsg(sRespData, sReqNonce, sReqTimeStamp) + if( ret!=0 ): + print("ERR: EncryptMsg ret: " + str(ret)) + sys.exit(1) + #ret == 0 加密成功,企业需要将sEncryptMsg返回给企业号 + #TODO: + #HttpUitls.SetResponse(sEncryptMsg) diff --git a/api/examples/AppChatTest.py b/api/examples/AppChatTest.py index aed9add..65c181b 100644 --- a/api/examples/AppChatTest.py +++ b/api/examples/AppChatTest.py @@ -33,10 +33,10 @@ 'userlist' : ['LiShuang', 'ZhuShengBen', 'LinJianEn', 'ZhuBiaoYi', 'XuBin', 'yangpeiyi', 'HaLuoTeQu', 'lucky', 'raindong', 'simon', 'Wang', 'ZhaoDong', 'DengLinSheng', 'Li'], 'chatid' : chatid, }) - print response + print(response ) chatid = response['chatid'] except ApiException as e : - print e.errCode, e.errMsg + print(e.errCode, e.errMsg) try : ## @@ -48,7 +48,7 @@ 'owner' : 'ZhuShengBen', 'add_user_list' : ['huqiqi', 'Wang'] }) - print response + print(response ) ## response = api.httpCall( @@ -59,7 +59,7 @@ 'owner' : 'ZhuBiaoYi', 'del_user_list' : 'huqiqi', }) - print response + print(response ) ## response = api.httpCall( @@ -71,7 +71,7 @@ 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), 'safe' : 1, }) - print response + print(response ) ## response = api.httpCall( @@ -85,7 +85,7 @@ }, 'safe' : 1, }) - print response + print(response ) ## response = api.httpCall( @@ -99,7 +99,7 @@ }, 'safe' : 1, }) - print response + print(response ) ## @@ -114,7 +114,7 @@ }, 'safe' : 1, }) - print response + print(response ) ## response = api.httpCall( @@ -128,7 +128,7 @@ }, 'safe' : 1, }) - print response + print(response ) ## response = api.httpCall( @@ -164,7 +164,7 @@ 'safe' : 1, }, ) - print response + print(response ) ## response = api.httpCall( @@ -181,7 +181,7 @@ }, 'safe' : 1, }) - print response + print(response ) ## response = api.httpCall( @@ -217,7 +217,7 @@ 'climsgid' : 'climsgidclimsgid_%f' % (random.random()), 'safe' : 1, }) - print response + print(response ) except ApiException as e : - print e.errCode, e.errMsg + print(e.errCode, e.errMsg) diff --git a/api/examples/MessageTest.py b/api/examples/MessageTest.py index c07b005..0c3a514 100644 --- a/api/examples/MessageTest.py +++ b/api/examples/MessageTest.py @@ -36,7 +36,7 @@ }, 'safe' : 0, }) - print response + print(response ) except ApiException as e : - print e.errCode, e.errMsg + print(e.errCode, e.errMsg) diff --git a/api/examples/UserTest.py b/api/examples/UserTest.py index 1dd6677..ba0a446 100644 --- a/api/examples/UserTest.py +++ b/api/examples/UserTest.py @@ -31,7 +31,7 @@ 'email' : 'zhangsan@ipp.cas.cn', 'department' : 1, }) - print response + print(response ) ## response = api.httpCall( @@ -39,7 +39,7 @@ { 'userid' : 'zhangsan', }) - print response + print(response) ## response = api.httpCall( @@ -47,10 +47,10 @@ { 'userid' : 'zhangsan', }) - print response + print(response) except ApiException as e : - print e.errCode, e.errMsg + print(e.errCode, e.errMsg) ## response = api.httpCall( @@ -58,6 +58,6 @@ { 'userid' : 'zhangsan', }) - print response + print(response) diff --git a/api/src/AbstractApi.py b/api/src/AbstractApi.py index 9c15796..7897931 100644 --- a/api/src/AbstractApi.py +++ b/api/src/AbstractApi.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding:utf-8 -*- ## # Copyright (C) 2018 All rights reserved. @@ -105,7 +105,7 @@ def __httpPost(self, url, args) : realUrl = self.__appendToken(url) if DEBUG is True : - print realUrl, args + print(realUrl, args) return requests.post(realUrl, data = json.dumps(args, ensure_ascii = False).encode('utf-8')).json() @@ -113,7 +113,7 @@ def __httpGet(self, url) : realUrl = self.__appendToken(url) if DEBUG is True : - print realUrl + print(realUrl) return requests.get(realUrl).json() @@ -125,7 +125,7 @@ def __checkResponse(response): errCode = response.get('errcode') errMsg = response.get('errmsg') - if errCode is 0: + if errCode == 0: return response else: raise ApiException(errCode, errMsg) diff --git a/api/src/CorpApi.py b/api/src/CorpApi.py index 4f04a23..0c164fa 100644 --- a/api/src/CorpApi.py +++ b/api/src/CorpApi.py @@ -16,7 +16,7 @@ CORP_API_TYPE = { 'GET_ACCESS_TOKEN' : ['/cgi-bin/gettoken', 'GET'], 'USER_CREATE' : ['/cgi-bin/user/create?access_token=ACCESS_TOKEN', 'POST'], - 'USER_GET' : ['/cgi-bin/user/get?access_token=ACCESS_TOKEN', 'GET'], + 'USER_GET': ['/cgi-bin/user/get?access_token=ACCESS_TOKEN', 'GET'], 'USER_UPDATE' : ['/cgi-bin/user/update?access_token=ACCESS_TOKEN', 'POST'], 'USER_DELETE' : ['/cgi-bin/user/delete?access_token=ACCESS_TOKEN', 'GET'], 'USER_BATCH_DELETE': ['/cgi-bin/user/batchdelete?access_token=ACCESS_TOKEN', 'POST'], diff --git a/callback/Sample.py b/callback/Sample.py index f1faa7c..0ec6abe 100644 --- a/callback/Sample.py +++ b/callback/Sample.py @@ -31,7 +31,7 @@ wxcpt=WXBizMsgCrypt(sToken,sEncodingAESKey,sCorpID) #sVerifyMsgSig=HttpUtils.ParseUrl("msg_signature") #ret = wxcpt.VerifyAESKey() - #print ret + #print(ret) sVerifyMsgSig="012bc692d0a58dd4b10f8dfe5c4ac00ae211ebeb" #sVerifyTimeStamp=HttpUtils.ParseUrl("timestamp") sVerifyTimeStamp="1476416373" @@ -41,7 +41,7 @@ sVerifyEchoStr="fsi1xnbH4yQh0+PJxcOdhhK6TDXkjMyhEPA7xB2TGz6b+g7xyAbEkRxN/3cNXW9qdqjnoVzEtpbhnFyq6SVHyA==" ret,sEchoStr=wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,sVerifyNonce,sVerifyEchoStr) if(ret!=0): - print "ERR: VerifyURL ret: " + str(ret) + print("ERR: VerifyURL ret: " + str(ret)) sys.exit(1) #验证URL成功,将sEchoStr返回给企业号 #HttpUtils.SetResponse(sEchoStr) @@ -67,16 +67,16 @@ sReqNonce = "1597212914" sReqData = "\n\n\n" ret,sMsg=wxcpt.DecryptMsg( sReqData, sReqMsgSig, sReqTimeStamp, sReqNonce) - print ret,sMsg + print(ret,sMsg) if( ret!=0 ): - print "ERR: DecryptMsg ret: " + str(ret) + print("ERR: DecryptMsg ret: " + str(ret)) sys.exit(1) # 解密成功,sMsg即为xml格式的明文 # TODO: 对明文的处理 # For example: xml_tree = ET.fromstring(sMsg) content = xml_tree.find("Content").text - print content + print(content) # ... # ... @@ -101,7 +101,7 @@ sRespData = "ww1436e0e65a779aeeChenJiaShun1476422779text你好14564537201000002" ret,sEncryptMsg=wxcpt.EncryptMsg(sRespData, sReqNonce, sReqTimeStamp) if( ret!=0 ): - print "ERR: EncryptMsg ret: " + str(ret) + print("ERR: EncryptMsg ret: " + str(ret)) sys.exit(1) #ret == 0 加密成功,企业需要将sEncryptMsg返回给企业号 #TODO: