yj
2025-08-27 307236190c98c13395b114df990eec50a9160251
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
"""
好友忽略列表管理服务
"""
 
from typing import List, Set, Optional
from loguru import logger
from sqlalchemy.orm import Session
from app.services.redis_queue import redis_queue
from app.models.database import get_db
from app.models.contact import Contact
from app.services.silence_service import silence_service
from config import settings
 
 
class FriendIgnoreService:
    """好友忽略列表管理服务"""
 
    def __init__(self):
        self.ignore_list_key = "ecloud_ignore_friends"
 
    def _get_wid_by_nickname(self, nickname: str) -> Optional[str]:
        """
        根据昵称获取w_id
 
        Args:
            nickname: 好友昵称
 
        Returns:
            对应的w_id,如果未找到返回None
        """
        try:
            with next(get_db()) as db:
                contact = (
                    db.query(Contact).filter(Contact.nick_name == nickname).first()
                )
                if contact:
                    wc_id = contact.wc_id
                    if contact.work_wc_id:
                        wc_id += f",{contact.work_wc_id}"
                    return wc_id
                else:
                    logger.warning(f"未找到昵称为 '{nickname}' 的联系人")
                    return None
        except Exception as e:
            logger.error(f"根据昵称查找w_id异常: nickname={nickname}, error={str(e)}")
            return None
 
    def _get_whitelist_wids(self) -> List[str]:
        """
        将配置中的昵称白名单转换为w_id列表
 
        Returns:
            w_id列表
        """
        wid_list = []
        for nickname in settings.friend_ignore_whitelist:
            wid = self._get_wid_by_nickname(nickname)
            if wid:
                wid_list.append(wid)
                logger.debug(f"白名单昵称 '{nickname}' 对应w_id: {wid}")
            else:
                logger.warning(f"白名单昵称 '{nickname}' 未找到对应的联系人")
        return wid_list
 
    def add_friends_to_ignore_list(self, friends: List[str]) -> bool:
        """
        将好友w_id添加到Redis忽略列表
 
        Args:
            friends: 好友w_id列表
 
        Returns:
            添加成功返回True,失败返回False
        """
        try:
            if not friends:
                logger.info("好友列表为空,无需添加到忽略列表")
                return True
 
            # 清空现有的忽略列表
            redis_queue.redis_client.delete(self.ignore_list_key)
 
            # 批量添加好友w_id到忽略列表
            redis_queue.redis_client.sadd(self.ignore_list_key, *friends)
 
            logger.info(f"已将 {len(friends)} 个好友添加到忽略列表")
            return True
 
        except Exception as e:
            logger.error(f"添加好友到忽略列表异常: error={str(e)}")
            return False
 
    def is_friend_ignored(self, w_id: str, group_id: Optional[str] = None) -> bool:
        """
        检查指定w_id是否应该被忽略
 
        逻辑:
        1. 如果好友忽略功能未启用,返回False(不忽略)
        2. 如果w_id在白名单中,返回False(不忽略)
        3. 如果w_id在忽略列表中,但所在群组为测试群组,返回False(不忽略)
        4. 如果w_id在忽略列表中,返回True(忽略)
        5. 如果w_id不在忽略列表中,返回False(不忽略)
 
        Args:
            w_id: 用户w_id
            group_id: 群组ID(可选),用于检查是否为测试群组
 
        Returns:
            如果应该被忽略返回True,否则返回False
        """
        try:
            # 检查好友忽略功能是否启用
            if not settings.friend_ignore_enabled:
                logger.debug(f"好友忽略功能已禁用,不忽略消息: w_id={w_id}")
                return False
 
            # 检查是否在白名单中(通过昵称)
            whitelist_wids = self._get_whitelist_wids()
 
            if any(w_id in wids for wids in whitelist_wids):
                logger.info(f"w_id在白名单中,不忽略消息: w_id={w_id}")
                return False
 
            # 检查是否在忽略列表中
            is_in_ignore_list = redis_queue.redis_client.sismember(
                self.ignore_list_key, w_id
            )
 
            if is_in_ignore_list:
                # 如果在忽略列表中,检查是否在测试群组中
                if group_id and silence_service.is_test_group(group_id):
                    logger.info(
                        f"测试群组中的好友消息不被忽略: w_id={w_id}, group_id={group_id}"
                    )
                    return False
 
                logger.info(f"w_id在忽略列表中,忽略消息: w_id={w_id}")
 
            return is_in_ignore_list
 
        except Exception as e:
            logger.error(f"检查忽略列表异常: w_id={w_id}, error={str(e)}")
            return False
 
    def get_ignore_list(self) -> Set[str]:
        """
        获取完整的忽略列表
 
        Returns:
            忽略列表中的所有w_id集合
        """
        try:
            return redis_queue.redis_client.smembers(self.ignore_list_key)
        except Exception as e:
            logger.error(f"获取忽略列表异常: error={str(e)}")
            return set()
 
    def remove_friend_from_ignore_list(self, w_id: str) -> bool:
        """
        从忽略列表中移除指定w_id
 
        Args:
            w_id: 用户w_id
 
        Returns:
            移除成功返回True,失败返回False
        """
        try:
            result = redis_queue.redis_client.srem(self.ignore_list_key, w_id)
            if result:
                logger.info(f"已从忽略列表中移除: w_id={w_id}")
            else:
                logger.info(f"w_id不在忽略列表中: w_id={w_id}")
            return True
        except Exception as e:
            logger.error(f"从忽略列表移除w_id异常: w_id={w_id}, error={str(e)}")
            return False
 
    def clear_ignore_list(self) -> bool:
        """
        清空忽略列表
 
        Returns:
            清空成功返回True,失败返回False
        """
        try:
            redis_queue.redis_client.delete(self.ignore_list_key)
            logger.info("已清空忽略列表")
            return True
        except Exception as e:
            logger.error(f"清空忽略列表异常: error={str(e)}")
            return False
 
    def get_ignore_list_count(self) -> int:
        """
        获取忽略列表中的好友数量
 
        Returns:
            忽略列表中的好友数量
        """
        try:
            return redis_queue.redis_client.scard(self.ignore_list_key)
        except Exception as e:
            logger.error(f"获取忽略列表数量异常: error={str(e)}")
            return 0
 
    def get_whitelist(self) -> List[str]:
        """
        获取当前的白名单列表
 
        Returns:
            白名单中的w_id列表
        """
        return settings.friend_ignore_whitelist.copy()
 
    def is_whitelist_enabled(self) -> bool:
        """
        检查白名单功能是否启用
 
        Returns:
            如果启用返回True,否则返回False
        """
        return settings.friend_ignore_enabled
 
    def get_ignore_status_info(self, w_id: str) -> dict:
        """
        获取指定w_id的详细忽略状态信息
 
        Args:
            w_id: 用户w_id
 
        Returns:
            包含详细状态信息的字典
        """
        try:
            # 获取白名单w_id列表
            whitelist_wids = self._get_whitelist_wids()
 
            info = {
                "w_id": w_id,
                "ignore_enabled": settings.friend_ignore_enabled,
                "in_whitelist": w_id in whitelist_wids,
                "in_ignore_list": False,
                "final_ignored": False,
                "reason": "",
                "whitelist_nicknames": settings.friend_ignore_whitelist,
            }
 
            if not settings.friend_ignore_enabled:
                info["reason"] = "好友忽略功能已禁用"
                return info
 
            if w_id in whitelist_wids:
                info["reason"] = "在白名单中,不会被忽略"
                return info
 
            info["in_ignore_list"] = redis_queue.redis_client.sismember(
                self.ignore_list_key, w_id
            )
 
            if info["in_ignore_list"]:
                info["final_ignored"] = True
                info["reason"] = "在忽略列表中,会被忽略"
            else:
                info["reason"] = "不在忽略列表中,不会被忽略"
 
            return info
 
        except Exception as e:
            logger.error(f"获取忽略状态信息异常: w_id={w_id}, error={str(e)}")
            return {"w_id": w_id, "error": str(e), "final_ignored": False}
 
 
# 全局好友忽略服务实例
friend_ignore_service = FriendIgnoreService()