@@ -1,11 +1,11 @@ | |||||
from flask import Flask, send_from_directory, request,jsonify | from flask import Flask, send_from_directory, request,jsonify | ||||
from flask_restful import Api,got_request_exception | from flask_restful import Api,got_request_exception | ||||
from resources.user_resource import UserResource | |||||
from resources.messages_resource import MessagesResource | from resources.messages_resource import MessagesResource | ||||
from resources.contacts_resources import DeleteFriendResource,GetFriendsInfoResource | from resources.contacts_resources import DeleteFriendResource,GetFriendsInfoResource | ||||
from resources.config_reources import GetWxchatConfigResource ,SaveWxchatConfigResource | from resources.config_reources import GetWxchatConfigResource ,SaveWxchatConfigResource | ||||
from resources.groups_resources import GetGroupsInfoResource | from resources.groups_resources import GetGroupsInfoResource | ||||
from resources.login_resources import GetLoginInfoResource | from resources.login_resources import GetLoginInfoResource | ||||
from resources.sns_resources import SendSNSTextResource,SendSNSImageResource, SendSNSVideoResource | |||||
from common.log import logger, log_exception | from common.log import logger, log_exception | ||||
from common.interceptors import before_request, after_request, handle_exception | from common.interceptors import before_request, after_request, handle_exception | ||||
import threading | import threading | ||||
@@ -196,8 +196,6 @@ app.after_request(after_request) | |||||
app.register_error_handler(Exception, handle_exception) | app.register_error_handler(Exception, handle_exception) | ||||
# 定义路由 | # 定义路由 | ||||
flask_api.add_resource(UserResource, '/api/user', '/api/user/<int:user_id>') | |||||
flask_api.add_resource(MessagesResource, '/messages') | 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(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() | load_config() | ||||
worker() | worker() | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
# 获取环境变量 | # 获取环境变量 | ||||
environment = os.environ.get('environment', 'default') | environment = os.environ.get('environment', 'default') | ||||
@@ -1,7 +1,9 @@ | |||||
from functools import wraps | |||||
import time | import time | ||||
from flask import request, g, jsonify, make_response,current_app | from flask import request, g, jsonify, make_response,current_app | ||||
from common.log import logger | from common.log import logger | ||||
from datetime import datetime | from datetime import datetime | ||||
from common import utils,redis_helper | |||||
# 定义生成失败响应的函数 | # 定义生成失败响应的函数 | ||||
def fail_response(code, error_message): | def fail_response(code, error_message): | ||||
@@ -53,3 +55,38 @@ def handle_exception(error): | |||||
response = jsonify({'message': str(error)}) | response = jsonify({'message': str(error)}) | ||||
response.status_code = 500 | response.status_code = 500 | ||||
return response | 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 |
@@ -103,7 +103,8 @@ class MessagesResource(Resource): | |||||
logger.warning(f'微信ID {wxid}在设备{app_id}已经离线') | logger.warning(f'微信ID {wxid}在设备{app_id}已经离线') | ||||
k,r=get_login_info_by_app_id(app_id) | k,r=get_login_info_by_app_id(app_id) | ||||
print(k) | 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: | else: | ||||
logger.warning(f"未知消息类型") | logger.warning(f"未知消息类型") | ||||
@@ -1,6 +1,92 @@ | |||||
from flask_restful import Resource, reqparse | from flask_restful import Resource, reqparse | ||||
from common.interceptors import auth_required_time | |||||
from flask import jsonify,request | from flask import jsonify,request | ||||
from common import redis_helper,utils | from common import redis_helper,utils | ||||
from wechat import gewe_chat | 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) |
@@ -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}) |
@@ -315,11 +315,15 @@ def login_or_reconnect(wxchat:gewe_chat.GeWeChatCom, token_id, app_id, hash_key, | |||||
# todo | # todo | ||||
if flag == 2: | if flag == 2: | ||||
logger.info(f"登录成功: {res}") | logger.info(f"登录成功: {res}") | ||||
head_img_url=res.get('headImgUrl','') | |||||
login_info = res.get('loginInfo', {}) | 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: | # 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]}) | # 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: | # else: | ||||
@@ -543,6 +543,7 @@ class GeWeChatCom: | |||||
return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) | 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): | def sns_visible_scope(self, token_id, app_id,option): | ||||
''' | ''' | ||||
@@ -603,23 +604,52 @@ class GeWeChatCom: | |||||
response_object = response.json() | response_object = response.json() | ||||
return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) | 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 = { | headers = { | ||||
'X-GEWE-TOKEN': token_id, | 'X-GEWE-TOKEN': token_id, | ||||
'Content-Type': 'application/json' | 'Content-Type': 'application/json' | ||||
} | } | ||||
data = { | data = { | ||||
"appId": app_id, | "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 = requests.post(url=api_url, headers=headers, data=json.dumps(data)) | ||||
response_object = response.json() | response_object = response.json() | ||||
print(response_object) | |||||
return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) | 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): | def upload_sns_image(self, token_id, app_id,img_urls:list): | ||||
''' | ''' | ||||
上传朋友圈图片 | 上传朋友圈图片 | ||||
@@ -637,7 +667,24 @@ class GeWeChatCom: | |||||
response_object = response.json() | response_object = response.json() | ||||
return response_object.get('ret',None),response_object.get('msg',None),response_object.get('data',None) | 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: | def save_session_messages_to_cache(self, hash_key,item:object)->list: | ||||
''' | ''' | ||||
@@ -667,7 +714,7 @@ class GeWeChatCom: | |||||
messages.append(item) | messages.append(item) | ||||
redis_helper.redis_helper.set_hash(hash_key,{"data":json.dumps(messages,ensure_ascii=False)},600) | redis_helper.redis_helper.set_hash(hash_key,{"data":json.dumps(messages,ensure_ascii=False)},600) | ||||
return messages | return messages | ||||
def get_contacts_brief_from_cache(self, wxid)->list: | def get_contacts_brief_from_cache(self, wxid)->list: | ||||
""" | """ | ||||
获取联系人信息保存到 Redis 缓存。 | 获取联系人信息保存到 Redis 缓存。 | ||||