From 10316d264dbe04b846784ece1af83a803d45a449 Mon Sep 17 00:00:00 2001 From: H Vs Date: Fri, 14 Feb 2025 16:16:11 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=8B=E5=8F=8B=E5=9C=88=E5=8F=91=E6=96=87?= =?UTF-8?q?=E5=AD=97=E3=80=81=E5=9B=BE=E7=89=87=E3=80=81=E8=A7=86=E9=A2=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.py | 12 ++--- common/interceptors.py | 37 +++++++++++++++ resources/messages_resource.py | 3 +- resources/sns_resources.py | 86 ++++++++++++++++++++++++++++++++++ resources/user_resource.py | 32 ------------- wechat/biz.py | 10 ++-- wechat/gewe_chat.py | 57 ++++++++++++++++++++-- 7 files changed, 189 insertions(+), 48 deletions(-) delete mode 100644 resources/user_resource.py diff --git a/app.py b/app.py index 1c31a43..741af65 100644 --- a/app.py +++ b/app.py @@ -1,11 +1,11 @@ from flask import Flask, send_from_directory, request,jsonify from flask_restful import Api,got_request_exception -from resources.user_resource import UserResource from resources.messages_resource import MessagesResource from resources.contacts_resources import DeleteFriendResource,GetFriendsInfoResource from resources.config_reources import GetWxchatConfigResource ,SaveWxchatConfigResource from resources.groups_resources import GetGroupsInfoResource from resources.login_resources import GetLoginInfoResource +from resources.sns_resources import SendSNSTextResource,SendSNSImageResource, SendSNSVideoResource from common.log import logger, log_exception from common.interceptors import before_request, after_request, handle_exception import threading @@ -196,8 +196,6 @@ app.after_request(after_request) app.register_error_handler(Exception, handle_exception) # 定义路由 -flask_api.add_resource(UserResource, '/api/user', '/api/user/') - flask_api.add_resource(MessagesResource, '/messages') @@ -211,14 +209,14 @@ flask_api.add_resource(GetGroupsInfoResource, '/api/groups/getchatroominfo') flask_api.add_resource(GetLoginInfoResource, '/api/agent/getlogin') +flask_api.add_resource(SendSNSTextResource, '/api/sns/sendtext') +flask_api.add_resource(SendSNSImageResource, '/api/sns/sendimages') +flask_api.add_resource(SendSNSVideoResource, '/api/sns/sendvideo') + load_config() worker() - - - - if __name__ == '__main__': # 获取环境变量 environment = os.environ.get('environment', 'default') diff --git a/common/interceptors.py b/common/interceptors.py index 56fbe88..ac3f635 100644 --- a/common/interceptors.py +++ b/common/interceptors.py @@ -1,7 +1,9 @@ +from functools import wraps import time from flask import request, g, jsonify, make_response,current_app from common.log import logger from datetime import datetime +from common import utils,redis_helper # 定义生成失败响应的函数 def fail_response(code, error_message): @@ -53,3 +55,38 @@ def handle_exception(error): response = jsonify({'message': str(error)}) response.status_code = 500 return response + + + +def auth_required_time(f): + @wraps(f) + def decorated_function(*args, **kwargs): + req = request.get_json() + wxid = req.get("wxid") + if not wxid: + response=jsonify({'code': 400, 'message': '缺少wxid参数'}) + response.status_code = 400 + return response + + k, login_info = utils.get_login_info_by_wxid(wxid) + if not login_info or login_info.get('status') == "0": + response=jsonify({'code': 401, 'message': '用户没有登录'}) + response.status_code = 401 + return response + # 获取登录信息的创建时间 + creation_timestamp=int(login_info.get('create_at')) + current_timestamp = time.time() + three_days_seconds = 3 * 24 * 60 * 60 # 三天的秒数 + diff_flag=(current_timestamp - creation_timestamp) >= three_days_seconds + print(f"creation_timestamp:{creation_timestamp},current_timestamp:{current_timestamp},diff_flag:{diff_flag}") + if not diff_flag: + response=jsonify({'code': 401, 'message': '用户创建不够三天,不能使用该功能'}) + response.status_code = 401 + return response + + # # # 将认证信息注入请求环境变量 + request.environ['token_id'] = login_info.get('tokenId') + request.environ['app_id'] = login_info.get('appId') + + return f(*args, **kwargs) + return decorated_function \ No newline at end of file diff --git a/resources/messages_resource.py b/resources/messages_resource.py index 0dc2829..b7230a1 100644 --- a/resources/messages_resource.py +++ b/resources/messages_resource.py @@ -103,7 +103,8 @@ class MessagesResource(Resource): logger.warning(f'微信ID {wxid}在设备{app_id}已经离线') k,r=get_login_info_by_app_id(app_id) print(k) - redis_helper.redis_helper.update_hash_field(k,'status',0) + redis_helper.redis_helper.update_hash_field(k,'status',0) + redis_helper.redis_helper.update_hash_field(k,'modify_at',int(time.time())) else: logger.warning(f"未知消息类型") diff --git a/resources/sns_resources.py b/resources/sns_resources.py index 771a22b..e640676 100644 --- a/resources/sns_resources.py +++ b/resources/sns_resources.py @@ -1,6 +1,92 @@ from flask_restful import Resource, reqparse +from common.interceptors import auth_required_time from flask import jsonify,request from common import redis_helper,utils from wechat import gewe_chat +class SendSNSTextResource(Resource): + + def __init__(self): + self.parser = reqparse.RequestParser() + self.wxchat = gewe_chat.wxchat + + @auth_required_time + def post(self): + req = request.get_json() + content = req.get("content") + + ret, msg, data = self.wxchat.send_text_sns(request.environ['token_id'], request.environ['app_id'], content) + if ret != 200: + response = jsonify({ + 'code': ret, + 'message': msg + }) + # response.status_code = ret + return response + return jsonify(data) + + +class SendSNSImageResource(Resource): + + def __init__(self): + self.parser = reqparse.RequestParser() + self.wxchat = gewe_chat.wxchat + + @auth_required_time + def post(self): + req = request.get_json() + content = req.get("content","") + image_urls=req.get("imageUrls",[]) + ret, msg, data = self.wxchat.upload_sns_image(request.environ['token_id'], request.environ['app_id'], image_urls) + if ret != 200: + response = jsonify({ + 'code': ret, + 'message': msg + }) + # response.status_code = ret + return response + + + ret, msg, data = self.wxchat.send_image_sns(request.environ['token_id'], request.environ['app_id'], content,data) + if ret != 200: + response = jsonify({ + 'code': ret, + 'message': msg + }) + # response.status_code = ret + return response + return jsonify(data) + + +class SendSNSVideoResource(Resource): + + def __init__(self): + self.parser = reqparse.RequestParser() + self.wxchat = gewe_chat.wxchat + + @auth_required_time + def post(self): + req = request.get_json() + content = req.get("content","") + video_url=req.get("videoUrl","") + video_thumb_url=req.get("videoThumbUrl","") + ret, msg, data = self.wxchat.upload_sns_video(request.environ['token_id'], request.environ['app_id'], video_url,video_thumb_url) + if ret != 200: + response = jsonify({ + 'code': ret, + 'message': msg + }) + # response.status_code = ret + return response + + + ret, msg, data = self.wxchat.send_video_sns(request.environ['token_id'], request.environ['app_id'], content,data) + if ret != 200: + response = jsonify({ + 'code': ret, + 'message': msg + }) + # response.status_code = ret + return response + return jsonify(data) \ No newline at end of file diff --git a/resources/user_resource.py b/resources/user_resource.py deleted file mode 100644 index 1d85fe9..0000000 --- a/resources/user_resource.py +++ /dev/null @@ -1,32 +0,0 @@ -from flask_restful import Resource, reqparse -from flask import jsonify - -class UserResource(Resource): - def __init__(self): - self.parser = reqparse.RequestParser() - self.parser.add_argument('name', type=str, required=True, help='Name cannot be blank') - self.parser.add_argument('email', type=str, required=True, help='Email cannot be blank') - - def get(self, user_id): - # 模拟获取用户逻辑 - # 在实际应用中,你可能会从数据库中获取用户数据 - return jsonify({'user_id': user_id, 'name': 'John Doe', 'email': 'john@example.com'}) - - def post(self): - args = self.parser.parse_args() - # 模拟创建用户逻辑 - # 在实际应用中,你可能会将用户数据插入数据库 - print(args); - # return jsonify({'message': 'User created', 'user': args}), 201 - return jsonify({'message': 'User created', 'user': args}) - - def put(self, user_id): - args = self.parser.parse_args() - # 模拟更新用户逻辑 - # 在实际应用中,你可能会更新数据库中的用户数据 - return jsonify({'message': 'User updated', 'user_id': user_id, 'user': args}) - - def delete(self, user_id): - # 模拟删除用户逻辑 - # 在实际应用中,你可能会从数据库中删除用户数据 - return jsonify({'message': 'User deleted', 'user_id': user_id}) diff --git a/wechat/biz.py b/wechat/biz.py index 39d6267..97fcfcb 100644 --- a/wechat/biz.py +++ b/wechat/biz.py @@ -315,11 +315,15 @@ def login_or_reconnect(wxchat:gewe_chat.GeWeChatCom, token_id, app_id, hash_key, # todo if flag == 2: logger.info(f"登录成功: {res}") + head_img_url=res.get('headImgUrl','') login_info = res.get('loginInfo', {}) - login_info.update({'appId': app_id, 'uuid': uuid, 'tokenId': token_id,'status': 1}) - # cache_login_info=redis_helper.redis_helper.get_hash(hash_key) - + login_info.update({'appId': app_id, 'uuid': uuid, 'tokenId': token_id,'status': 1,'headImgUrl':head_img_url}) + cache_login_info=redis_helper.redis_helper.get_hash(hash_key) + if 'appId' not in cache_login_info: + login_info.update({"create_at":int(time.time()),"modify_at":int(time.time())}) + else: + login_info.update({"modify_at":int(time.time())}) # if 'appId' in cache_login_info: # login_info.update({"reg_time":datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3],"login_time":datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]}) # else: diff --git a/wechat/gewe_chat.py b/wechat/gewe_chat.py index ee3639f..aa73acb 100644 --- a/wechat/gewe_chat.py +++ b/wechat/gewe_chat.py @@ -543,6 +543,7 @@ class GeWeChatCom: return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) ############################### 朋友圈模块 ################################### + # 在新设备登录后的1-3天内,您将无法使用朋友圈发布、点赞、评论等功能。在此期间,如果尝试进行这些操作,您将收到来自微信团队的提醒。请注意遵守相关规定。 def sns_visible_scope(self, token_id, app_id,option): ''' @@ -603,23 +604,52 @@ class GeWeChatCom: response_object = response.json() return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) - def send_image_sns(self, token_id, app_id,infos:list): + def send_image_sns(self, token_id, app_id,content,img_infos:list): ''' 发送图片朋友圈 ''' - api_url = f"{self.base_url}/v2/api/sns/sendImageSns" + api_url = f"{self.base_url}/v2/api/sns/sendImgSns" + print(api_url) headers = { 'X-GEWE-TOKEN': token_id, 'Content-Type': 'application/json' } data = { "appId": app_id, - "imgInfos": infos # 通过上传朋友圈图片接口获取 + "allowWxIds": [], + "atWxIds": [], + "disableWxIds": [], + "content":content, + "imgInfos": img_infos, # 通过上传朋友圈图片接口获取 + "privacy": False } response = requests.post(url=api_url, headers=headers, data=json.dumps(data)) response_object = response.json() + print(response_object) return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) + def send_video_sns(self, token_id, app_id,content:str,video_info:object): + ''' + 发送视频朋友圈 + ''' + api_url = f"{self.base_url}/v2/api/sns/sendVideoSns" + headers = { + 'X-GEWE-TOKEN': token_id, + 'Content-Type': 'application/json' + } + data = { + "appId": app_id, + "content":content, + "allowWxIds": [], + "atWxIds": [], + "disableWxIds": [], + "videoInfo":video_info, + "privacy": False + } + response = requests.post(url=api_url, headers=headers, data=json.dumps(data)) + response_object = response.json() + return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) + def upload_sns_image(self, token_id, app_id,img_urls:list): ''' 上传朋友圈图片 @@ -637,7 +667,24 @@ class GeWeChatCom: response_object = response.json() return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) - + def upload_sns_video(self, token_id, app_id,video_url:str,video_thumb_url:str): + ''' + 上传朋友圈视频 + ''' + api_url = f"{self.base_url}/v2/api/sns/uploadSnsVideo" + headers = { + 'X-GEWE-TOKEN': token_id, + 'Content-Type': 'application/json' + } + data = { + "appId": app_id, + "thumbUrl": video_thumb_url, + "videoUrl": video_url, + } + response = requests.post(url=api_url, headers=headers, data=json.dumps(data)) + response_object = response.json() + return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) + ############################### 其他 ############################### def save_session_messages_to_cache(self, hash_key,item:object)->list: ''' @@ -667,7 +714,7 @@ class GeWeChatCom: messages.append(item) redis_helper.redis_helper.set_hash(hash_key,{"data":json.dumps(messages,ensure_ascii=False)},600) return messages - + def get_contacts_brief_from_cache(self, wxid)->list: """ 获取联系人信息保存到 Redis 缓存。