关注数据监听。
This commit is contained in:
@@ -8,20 +8,27 @@ import logging
|
|||||||
import json
|
import json
|
||||||
from typing import List, Dict, Optional, Union, Any
|
from typing import List, Dict, Optional, Union, Any
|
||||||
|
|
||||||
|
from db.base import BaseDBOperator
|
||||||
from db.connection import DBConnectionManager
|
from db.connection import DBConnectionManager
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class ContactsDBOperator:
|
class ContactsDBOperator(BaseDBOperator):
|
||||||
"""微信联系人数据库操作类"""
|
"""微信联系人数据库操作类"""
|
||||||
|
|
||||||
def __init__(self, db_manager: DBConnectionManager):
|
def __init__(self, db_manager=None):
|
||||||
super().__init__(db_manager)
|
"""初始化联系人数据库操作类"""
|
||||||
|
super().__init__(db_manager or DBConnectionManager.get_instance())
|
||||||
|
self.logger = logging.getLogger("ContactsDBOperator")
|
||||||
|
|
||||||
|
# 确保数据库表存在
|
||||||
|
# self._ensure_table_exists()
|
||||||
|
|
||||||
def _ensure_table_exists(self):
|
def _ensure_table_exists(self):
|
||||||
"""确保联系人表存在"""
|
"""确保联系人表存在"""
|
||||||
try:
|
try:
|
||||||
# 创建联系人表
|
# 创建联系人表
|
||||||
sql = """
|
self.execute_update("""
|
||||||
CREATE TABLE IF NOT EXISTS t_wechat_contacts (
|
CREATE TABLE IF NOT EXISTS t_wechat_contacts (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
user_name VARCHAR(64) NOT NULL COMMENT '微信ID',
|
user_name VARCHAR(64) NOT NULL COMMENT '微信ID',
|
||||||
@@ -49,13 +56,10 @@ class ContactsDBOperator:
|
|||||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
UNIQUE KEY `idx_user_name` (`user_name`)
|
UNIQUE KEY `idx_user_name` (`user_name`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信联系人信息表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信联系人信息表';
|
||||||
"""
|
""")
|
||||||
conn = self.db_manager.get_connection()
|
|
||||||
cursor = conn.cursor()
|
|
||||||
cursor.execute(sql)
|
|
||||||
|
|
||||||
# 创建群成员表 - 增加了更多字段以支持详细信息
|
# 创建群成员表 - 增加了更多字段以支持详细信息
|
||||||
sql_chatroom_member = """
|
self.execute_update("""
|
||||||
CREATE TABLE IF NOT EXISTS t_chatroom_member (
|
CREATE TABLE IF NOT EXISTS t_chatroom_member (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
chatroom_id VARCHAR(64) NOT NULL COMMENT '群聊ID',
|
chatroom_id VARCHAR(64) NOT NULL COMMENT '群聊ID',
|
||||||
@@ -84,19 +88,12 @@ class ContactsDBOperator:
|
|||||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
UNIQUE KEY `idx_chatroom_member` (`chatroom_id`, `wxid`)
|
UNIQUE KEY `idx_chatroom_member` (`chatroom_id`, `wxid`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信群成员信息表';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信群成员信息表';
|
||||||
"""
|
""")
|
||||||
cursor.execute(sql_chatroom_member)
|
|
||||||
|
|
||||||
conn.commit()
|
self.logger.info("成功创建或确认微信联系人表和群成员表存在")
|
||||||
logger.info("成功创建或确认微信联系人表和群成员表存在")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"创建微信联系人表或群成员表失败: {e}")
|
self.logger.error(f"创建微信联系人表或群成员表失败: {e}")
|
||||||
raise
|
raise
|
||||||
finally:
|
|
||||||
if 'cursor' in locals():
|
|
||||||
cursor.close()
|
|
||||||
if 'conn' in locals():
|
|
||||||
self.db_manager.release_connection(conn)
|
|
||||||
|
|
||||||
def save_contacts(self, contacts_data: List[Dict], contact_type: str) -> bool:
|
def save_contacts(self, contacts_data: List[Dict], contact_type: str) -> bool:
|
||||||
"""保存联系人信息到数据库
|
"""保存联系人信息到数据库
|
||||||
@@ -109,13 +106,10 @@ class ContactsDBOperator:
|
|||||||
bool: 是否成功保存
|
bool: 是否成功保存
|
||||||
"""
|
"""
|
||||||
if not contacts_data:
|
if not contacts_data:
|
||||||
logger.warning(f"没有{contact_type}类型的联系人数据需要保存")
|
self.logger.warning(f"没有{contact_type}类型的联系人数据需要保存")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = self.db_manager.get_connection()
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
for contact in contacts_data:
|
for contact in contacts_data:
|
||||||
# 将驼峰命名转换为下划线命名
|
# 将驼峰命名转换为下划线命名
|
||||||
data = {
|
data = {
|
||||||
@@ -156,22 +150,14 @@ class ContactsDBOperator:
|
|||||||
ON DUPLICATE KEY UPDATE {update_clause}
|
ON DUPLICATE KEY UPDATE {update_clause}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cursor.execute(sql, values)
|
self.execute_update(sql, values)
|
||||||
|
|
||||||
conn.commit()
|
self.logger.info(f"成功保存{len(contacts_data)}个{contact_type}类型的联系人")
|
||||||
logger.info(f"成功保存{len(contacts_data)}个{contact_type}类型的联系人")
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"保存{contact_type}类型的联系人失败: {e}")
|
self.logger.error(f"保存{contact_type}类型的联系人失败: {e}")
|
||||||
if 'conn' in locals():
|
|
||||||
conn.rollback()
|
|
||||||
return False
|
return False
|
||||||
finally:
|
|
||||||
if 'cursor' in locals():
|
|
||||||
cursor.close()
|
|
||||||
if 'conn' in locals():
|
|
||||||
self.db_manager.release_connection(conn)
|
|
||||||
|
|
||||||
def save_simple_contacts(self, contact_list: List[str], contact_type: str) -> bool:
|
def save_simple_contacts(self, contact_list: List[str], contact_type: str) -> bool:
|
||||||
"""保存简单联系人列表(只有user_name)到数据库
|
"""保存简单联系人列表(只有user_name)到数据库
|
||||||
@@ -184,13 +170,10 @@ class ContactsDBOperator:
|
|||||||
bool: 是否成功保存
|
bool: 是否成功保存
|
||||||
"""
|
"""
|
||||||
if not contact_list:
|
if not contact_list:
|
||||||
logger.warning(f"没有{contact_type}类型的联系人数据需要保存")
|
self.logger.warning(f"没有{contact_type}类型的联系人数据需要保存")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = self.db_manager.get_connection()
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
for user_name in contact_list:
|
for user_name in contact_list:
|
||||||
# 构建SQL语句
|
# 构建SQL语句
|
||||||
sql = """
|
sql = """
|
||||||
@@ -199,22 +182,14 @@ class ContactsDBOperator:
|
|||||||
ON DUPLICATE KEY UPDATE type = VALUES(type), update_time = CURRENT_TIMESTAMP
|
ON DUPLICATE KEY UPDATE type = VALUES(type), update_time = CURRENT_TIMESTAMP
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cursor.execute(sql, (user_name, contact_type))
|
self.execute_update(sql, (user_name, contact_type))
|
||||||
|
|
||||||
conn.commit()
|
self.logger.info(f"成功保存{len(contact_list)}个{contact_type}类型的简单联系人")
|
||||||
logger.info(f"成功保存{len(contact_list)}个{contact_type}类型的简单联系人")
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"保存{contact_type}类型的简单联系人失败: {e}")
|
self.logger.error(f"保存{contact_type}类型的简单联系人失败: {e}")
|
||||||
if 'conn' in locals():
|
|
||||||
conn.rollback()
|
|
||||||
return False
|
return False
|
||||||
finally:
|
|
||||||
if 'cursor' in locals():
|
|
||||||
cursor.close()
|
|
||||||
if 'conn' in locals():
|
|
||||||
self.db_manager.release_connection(conn)
|
|
||||||
|
|
||||||
def get_contacts_by_type(self, contact_type: str) -> List[Dict]:
|
def get_contacts_by_type(self, contact_type: str) -> List[Dict]:
|
||||||
"""根据类型获取联系人列表
|
"""根据类型获取联系人列表
|
||||||
@@ -226,27 +201,17 @@ class ContactsDBOperator:
|
|||||||
List[Dict]: 联系人列表
|
List[Dict]: 联系人列表
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
conn = self.db_manager.get_connection()
|
|
||||||
cursor = conn.cursor(dictionary=True)
|
|
||||||
|
|
||||||
sql = """
|
sql = """
|
||||||
SELECT * FROM t_wechat_contacts
|
SELECT * FROM t_wechat_contacts
|
||||||
WHERE type = %s
|
WHERE type = %s
|
||||||
ORDER BY nick_name
|
ORDER BY nick_name
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cursor.execute(sql, (contact_type,))
|
results = self.execute_query(sql, (contact_type,))
|
||||||
results = cursor.fetchall()
|
|
||||||
|
|
||||||
return results
|
return results
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取{contact_type}类型的联系人失败: {e}")
|
self.logger.error(f"获取{contact_type}类型的联系人失败: {e}")
|
||||||
return []
|
return []
|
||||||
finally:
|
|
||||||
if 'cursor' in locals():
|
|
||||||
cursor.close()
|
|
||||||
if 'conn' in locals():
|
|
||||||
self.db_manager.release_connection(conn)
|
|
||||||
|
|
||||||
def get_contact_by_user_name(self, user_name: str) -> Optional[Dict]:
|
def get_contact_by_user_name(self, user_name: str) -> Optional[Dict]:
|
||||||
"""根据user_name获取联系人信息
|
"""根据user_name获取联系人信息
|
||||||
@@ -258,27 +223,17 @@ class ContactsDBOperator:
|
|||||||
Optional[Dict]: 联系人信息,如果不存在则返回None
|
Optional[Dict]: 联系人信息,如果不存在则返回None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
conn = self.db_manager.get_connection()
|
|
||||||
cursor = conn.cursor(dictionary=True)
|
|
||||||
|
|
||||||
sql = """
|
sql = """
|
||||||
SELECT * FROM t_wechat_contacts
|
SELECT * FROM t_wechat_contacts
|
||||||
WHERE user_name = %s
|
WHERE user_name = %s
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cursor.execute(sql, (user_name,))
|
result = self.execute_query(sql, (user_name,), fetch_one=True)
|
||||||
result = cursor.fetchone()
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取联系人{user_name}失败: {e}")
|
self.logger.error(f"获取联系人{user_name}失败: {e}")
|
||||||
return None
|
return None
|
||||||
finally:
|
|
||||||
if 'cursor' in locals():
|
|
||||||
cursor.close()
|
|
||||||
if 'conn' in locals():
|
|
||||||
self.db_manager.release_connection(conn)
|
|
||||||
|
|
||||||
def get_display_name(self, user_name: str) -> str:
|
def get_display_name(self, user_name: str) -> str:
|
||||||
"""获取联系人的显示名称(优先使用备注,其次是昵称,最后是微信ID)
|
"""获取联系人的显示名称(优先使用备注,其次是昵称,最后是微信ID)
|
||||||
@@ -302,30 +257,24 @@ class ContactsDBOperator:
|
|||||||
Dict[str, str]: 联系人ID到显示名称的映射
|
Dict[str, str]: 联系人ID到显示名称的映射
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
conn = self.db_manager.get_connection()
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
sql = """
|
sql = """
|
||||||
SELECT user_name, remark, nick_name FROM t_wechat_contacts
|
SELECT user_name, remark, nick_name FROM t_wechat_contacts
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cursor.execute(sql)
|
results = self.execute_query(sql)
|
||||||
results = cursor.fetchall()
|
|
||||||
|
|
||||||
name_map = {}
|
name_map = {}
|
||||||
for user_name, remark, nick_name in results:
|
for result in results:
|
||||||
|
user_name = result.get('user_name')
|
||||||
|
remark = result.get('remark')
|
||||||
|
nick_name = result.get('nick_name')
|
||||||
display_name = remark or nick_name or user_name
|
display_name = remark or nick_name or user_name
|
||||||
name_map[user_name] = display_name
|
name_map[user_name] = display_name
|
||||||
|
|
||||||
return name_map
|
return name_map
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"获取所有联系人名称映射失败: {e}")
|
self.logger.error(f"获取所有联系人名称映射失败: {e}")
|
||||||
return {}
|
return {}
|
||||||
finally:
|
|
||||||
if 'cursor' in locals():
|
|
||||||
cursor.close()
|
|
||||||
if 'conn' in locals():
|
|
||||||
self.db_manager.release_connection(conn)
|
|
||||||
|
|
||||||
def save_chatroom_member_detail(self, chatroom_id: str, member_details: List[Dict]) -> bool:
|
def save_chatroom_member_detail(self, chatroom_id: str, member_details: List[Dict]) -> bool:
|
||||||
"""保存群成员详细信息到数据库
|
"""保存群成员详细信息到数据库
|
||||||
@@ -338,20 +287,18 @@ class ContactsDBOperator:
|
|||||||
bool: 是否成功保存
|
bool: 是否成功保存
|
||||||
"""
|
"""
|
||||||
if not member_details or not chatroom_id:
|
if not member_details or not chatroom_id:
|
||||||
logger.warning(f"没有群聊{chatroom_id}的成员详细信息需要保存")
|
self.logger.warning(f"没有群聊{chatroom_id}的成员详细信息需要保存")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = self.db_manager.get_connection()
|
|
||||||
cursor = conn.cursor()
|
|
||||||
|
|
||||||
# 获取现有的群成员信息,以便更新而不是替换
|
# 获取现有的群成员信息,以便更新而不是替换
|
||||||
existing_members_sql = """
|
existing_members_sql = """
|
||||||
SELECT wxid, is_owner, is_admin FROM t_chatroom_member
|
SELECT wxid, is_owner, is_admin FROM t_chatroom_member
|
||||||
WHERE chatroom_id = %s
|
WHERE chatroom_id = %s
|
||||||
"""
|
"""
|
||||||
cursor.execute(existing_members_sql, (chatroom_id,))
|
existing_members_result = self.execute_query(existing_members_sql, (chatroom_id,))
|
||||||
existing_members = {row[0]: (row[1], row[2]) for row in cursor.fetchall()}
|
existing_members = {row.get('wxid'): (row.get('is_owner'), row.get('is_admin'))
|
||||||
|
for row in existing_members_result}
|
||||||
|
|
||||||
for member in member_details:
|
for member in member_details:
|
||||||
wxid = member.get('userName', '')
|
wxid = member.get('userName', '')
|
||||||
@@ -407,22 +354,14 @@ class ContactsDBOperator:
|
|||||||
VALUES ({placeholders})
|
VALUES ({placeholders})
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cursor.execute(sql, values)
|
self.execute_update(sql, values)
|
||||||
|
|
||||||
conn.commit()
|
self.logger.info(f"成功保存群聊{chatroom_id}的{len(member_details)}个成员详细信息")
|
||||||
logger.info(f"成功保存群聊{chatroom_id}的{len(member_details)}个成员详细信息")
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"保存群聊{chatroom_id}的成员详细信息失败: {e}")
|
self.logger.error(f"保存群聊{chatroom_id}的成员详细信息失败: {e}")
|
||||||
if 'conn' in locals():
|
|
||||||
conn.rollback()
|
|
||||||
return False
|
return False
|
||||||
finally:
|
|
||||||
if 'cursor' in locals():
|
|
||||||
cursor.close()
|
|
||||||
if 'conn' in locals():
|
|
||||||
self.db_manager.release_connection(conn)
|
|
||||||
|
|
||||||
def process_chatroom_member_detail_response(self, chatroom_id: str, response: Dict) -> bool:
|
def process_chatroom_member_detail_response(self, chatroom_id: str, response: Dict) -> bool:
|
||||||
"""处理获取群成员详情的API响应
|
"""处理获取群成员详情的API响应
|
||||||
@@ -436,16 +375,16 @@ class ContactsDBOperator:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if response.get('ret') != 200:
|
if response.get('ret') != 200:
|
||||||
logger.error(f"获取群聊{chatroom_id}成员详情失败: {response.get('msg')}")
|
self.logger.error(f"获取群聊{chatroom_id}成员详情失败: {response.get('msg')}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
data = response.get('data', [])
|
data = response.get('data', [])
|
||||||
if not data:
|
if not data:
|
||||||
logger.warning(f"群聊{chatroom_id}成员详情数据为空")
|
self.logger.warning(f"群聊{chatroom_id}成员详情数据为空")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.save_chatroom_member_detail(chatroom_id, data)
|
return self.save_chatroom_member_detail(chatroom_id, data)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"处理群聊{chatroom_id}成员详情数据失败: {e}")
|
self.logger.error(f"处理群聊{chatroom_id}成员详情数据失败: {e}")
|
||||||
return False
|
return False
|
||||||
22
main.py
22
main.py
@@ -109,17 +109,17 @@ def main(chat_type: int):
|
|||||||
print(f"已将新的APP_ID: {app_id} 写入配置文件")
|
print(f"已将新的APP_ID: {app_id} 写入配置文件")
|
||||||
# 同时更新当前配置对象中的APP_ID
|
# 同时更新当前配置对象中的APP_ID
|
||||||
config.APP_ID = app_id
|
config.APP_ID = app_id
|
||||||
#
|
|
||||||
# # 创建机器人实例
|
# 创建机器人实例
|
||||||
# robot = Robot(config, app_id, client, chat_type)
|
robot = Robot(config, app_id, client, chat_type)
|
||||||
# robot.LOG.info(f"WeChatRobot gewechat 成功启动···")
|
robot.LOG.info(f"WeChatRobot gewechat 成功启动···")
|
||||||
#
|
|
||||||
# # # 注册Robot实例到callback模块
|
# # 注册Robot实例到callback模块
|
||||||
# # from gewechat.api.callback import register_robot
|
from gewechat.api.callback import register_robot
|
||||||
# # register_robot(app_id, robot)
|
register_robot(app_id, robot)
|
||||||
#
|
|
||||||
# # 机器人启动发送测试消息
|
# 机器人启动发送测试消息
|
||||||
# client.post_text(app_id, send_msg_wxid, "gewechat client 启动成功!")
|
client.post_text(app_id, send_msg_wxid, "gewechat client 启动成功!")
|
||||||
#
|
#
|
||||||
# # 每天 8:30 发送新闻
|
# # 每天 8:30 发送新闻
|
||||||
# robot.onEveryTime("08:30", robot.news_baidu_report_auto)
|
# robot.onEveryTime("08:30", robot.news_baidu_report_auto)
|
||||||
|
|||||||
Reference in New Issue
Block a user