ErisPulse-Feedback 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- erispulse_feedback-1.0.0/ErisPulse_Feedback/Core.py +97 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback/__init__.py +3 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback/logic.py +398 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback/registry.py +985 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback/templates.py +1510 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback.egg-info/PKG-INFO +315 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback.egg-info/SOURCES.txt +12 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback.egg-info/dependency_links.txt +1 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback.egg-info/entry_points.txt +2 -0
- erispulse_feedback-1.0.0/ErisPulse_Feedback.egg-info/top_level.txt +1 -0
- erispulse_feedback-1.0.0/PKG-INFO +315 -0
- erispulse_feedback-1.0.0/README.md +295 -0
- erispulse_feedback-1.0.0/pyproject.toml +37 -0
- erispulse_feedback-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from ErisPulse import sdk
|
|
2
|
+
from ErisPulse.Core.Bases import BaseModule
|
|
3
|
+
from .logic import FeedbackLogic
|
|
4
|
+
from .registry import FeedbackCommandRegistry
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Main(BaseModule):
|
|
8
|
+
|
|
9
|
+
def __init__(self):
|
|
10
|
+
self.sdk = sdk
|
|
11
|
+
self.logger = sdk.logger.get_child("Feedback")
|
|
12
|
+
self.config = self._load_config()
|
|
13
|
+
|
|
14
|
+
# 初始化逻辑和命令注册
|
|
15
|
+
self.logic = None
|
|
16
|
+
self.registry = None
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def get_load_strategy():
|
|
20
|
+
from ErisPulse.loaders import ModuleLoadStrategy
|
|
21
|
+
return ModuleLoadStrategy(
|
|
22
|
+
lazy_load=False,
|
|
23
|
+
priority=0
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
async def on_load(self, event):
|
|
27
|
+
self.logger.info("正在加载反馈系统模块...")
|
|
28
|
+
|
|
29
|
+
# 初始化业务逻辑
|
|
30
|
+
self.logic = FeedbackLogic(self.sdk, self.config)
|
|
31
|
+
|
|
32
|
+
# 初始化命令注册
|
|
33
|
+
self.registry = FeedbackCommandRegistry(self.logic)
|
|
34
|
+
await self.registry.register_commands()
|
|
35
|
+
|
|
36
|
+
self.logger.info("反馈系统模块加载完成")
|
|
37
|
+
self.logger.info(f"命令: {self.registry.commands}")
|
|
38
|
+
self.logger.info(f"默认类别: {self.config.get('default_categories', [])}")
|
|
39
|
+
|
|
40
|
+
async def on_unload(self, event):
|
|
41
|
+
self.logger.info("反馈系统模块正在卸载...")
|
|
42
|
+
self.registry = None
|
|
43
|
+
self.logic = None
|
|
44
|
+
self.logger.info("反馈系统模块卸载完成")
|
|
45
|
+
|
|
46
|
+
def _load_config(self):
|
|
47
|
+
config = self.sdk.config.getConfig("Feedback", {})
|
|
48
|
+
|
|
49
|
+
if not config:
|
|
50
|
+
# 设置默认配置
|
|
51
|
+
default_config = {
|
|
52
|
+
# 命令配置
|
|
53
|
+
"commands": ["提交反馈", "反馈列表", "修改状态", "反馈帮助", "设置反馈组", "导出数据", "导入数据"],
|
|
54
|
+
|
|
55
|
+
# 全局管理员ID列表
|
|
56
|
+
"global_admins": [],
|
|
57
|
+
|
|
58
|
+
# 反馈类别
|
|
59
|
+
"default_categories": ["功能", "优化", "建议", "bug"],
|
|
60
|
+
|
|
61
|
+
# 超时时间(秒)
|
|
62
|
+
"timeout": 60,
|
|
63
|
+
|
|
64
|
+
# 内容最大长度
|
|
65
|
+
"max_content_length": 500,
|
|
66
|
+
|
|
67
|
+
# 反馈ID前缀
|
|
68
|
+
"id_prefix": "#",
|
|
69
|
+
|
|
70
|
+
# 存储前缀
|
|
71
|
+
"storage_prefix": "fb_"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
self.sdk.config.setConfig("Feedback", default_config)
|
|
75
|
+
self.logger.info("已创建默认配置")
|
|
76
|
+
return default_config
|
|
77
|
+
|
|
78
|
+
# 验证并补充配置
|
|
79
|
+
default_config = {
|
|
80
|
+
"commands": ["提交反馈", "反馈列表", "修改状态", "反馈帮助", "设置反馈组", "导出数据", "导入数据"],
|
|
81
|
+
"default_categories": ["功能", "优化", "建议", "bug"],
|
|
82
|
+
"timeout": 60,
|
|
83
|
+
"max_content_length": 500,
|
|
84
|
+
"id_prefix": "#",
|
|
85
|
+
"storage_prefix": "fb_"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for key, value in default_config.items():
|
|
89
|
+
if key not in config:
|
|
90
|
+
config[key] = value
|
|
91
|
+
self.logger.warning(f"配置项 {key} 未设置,使用默认值: {value}")
|
|
92
|
+
|
|
93
|
+
# 保存更新后的配置
|
|
94
|
+
self.sdk.config.setConfig("Feedback", config)
|
|
95
|
+
|
|
96
|
+
self.logger.info("配置加载完成")
|
|
97
|
+
return config
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import json
|
|
3
|
+
from typing import Optional, List, Dict, Tuple
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FeedbackGroupManager:
|
|
7
|
+
|
|
8
|
+
def __init__(self, storage, logger):
|
|
9
|
+
self.storage = storage
|
|
10
|
+
self.logger = logger
|
|
11
|
+
self.group_index_key = "fb_group_index"
|
|
12
|
+
self.mapping_prefix = "fb_mapping:"
|
|
13
|
+
self.group_prefix = "fb_group:"
|
|
14
|
+
|
|
15
|
+
def create_group(self, group_name: str, admin_ids: List[str],
|
|
16
|
+
source_group_id: str, config: Dict) -> str:
|
|
17
|
+
# 生成反馈组ID
|
|
18
|
+
group_id = self._generate_group_id()
|
|
19
|
+
|
|
20
|
+
# 创建反馈组数据
|
|
21
|
+
group_data = {
|
|
22
|
+
"id": group_id,
|
|
23
|
+
"name": group_name,
|
|
24
|
+
"admin_ids": admin_ids,
|
|
25
|
+
"allowed_groups": [source_group_id],
|
|
26
|
+
"config": config,
|
|
27
|
+
"created_at": int(time.time())
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# 保存反馈组
|
|
31
|
+
self.storage.set(f"{self.group_prefix}{group_id}", group_data)
|
|
32
|
+
|
|
33
|
+
# 映射群聊到反馈组
|
|
34
|
+
self.storage.set(f"{self.mapping_prefix}{source_group_id}", group_id)
|
|
35
|
+
|
|
36
|
+
# 更新反馈组索引
|
|
37
|
+
group_index = self.storage.get(self.group_index_key, [])
|
|
38
|
+
group_index.append(group_id)
|
|
39
|
+
self.storage.set(self.group_index_key, group_index)
|
|
40
|
+
|
|
41
|
+
self.logger.info(f"创建反馈组: {group_id} ({group_name}) by {admin_ids}")
|
|
42
|
+
return group_id
|
|
43
|
+
|
|
44
|
+
def add_group_to_feedback_group(self, group_id: str, source_group_id: str,
|
|
45
|
+
operator_id: str) -> Tuple[bool, str]:
|
|
46
|
+
# 获取反馈组
|
|
47
|
+
group_data = self.storage.get(f"{self.group_prefix}{group_id}")
|
|
48
|
+
if not group_data:
|
|
49
|
+
return False, "反馈组不存在"
|
|
50
|
+
|
|
51
|
+
# 检查权限
|
|
52
|
+
if operator_id not in group_data["admin_ids"]:
|
|
53
|
+
return False, "无权限操作此反馈组"
|
|
54
|
+
|
|
55
|
+
# 检查群聊是否已加入
|
|
56
|
+
if source_group_id in group_data["allowed_groups"]:
|
|
57
|
+
return False, "群聊已在此反馈组中"
|
|
58
|
+
|
|
59
|
+
# 添加群聊
|
|
60
|
+
group_data["allowed_groups"].append(source_group_id)
|
|
61
|
+
self.storage.set(f"{self.group_prefix}{group_id}", group_data)
|
|
62
|
+
|
|
63
|
+
# 映射群聊到反馈组
|
|
64
|
+
self.storage.set(f"{self.mapping_prefix}{source_group_id}", group_id)
|
|
65
|
+
|
|
66
|
+
self.logger.info(f"群聊 {source_group_id} 加入反馈组 {group_id} by {operator_id}")
|
|
67
|
+
return True, "成功"
|
|
68
|
+
|
|
69
|
+
def get_group_by_source(self, source_group_id: str) -> Optional[Dict]:
|
|
70
|
+
group_id = self.storage.get(f"{self.mapping_prefix}{source_group_id}")
|
|
71
|
+
if not group_id:
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
return self.storage.get(f"{self.group_prefix}{group_id}")
|
|
75
|
+
|
|
76
|
+
def get_group(self, group_id: str) -> Optional[Dict]:
|
|
77
|
+
return self.storage.get(f"{self.group_prefix}{group_id}")
|
|
78
|
+
|
|
79
|
+
def update_group_config(self, group_id: str, config: Dict,
|
|
80
|
+
operator_id: str) -> Tuple[bool, str]:
|
|
81
|
+
group_data = self.storage.get(f"{self.group_prefix}{group_id}")
|
|
82
|
+
if not group_data:
|
|
83
|
+
return False, "反馈组不存在"
|
|
84
|
+
|
|
85
|
+
if operator_id not in group_data["admin_ids"]:
|
|
86
|
+
return False, "无权限操作此反馈组"
|
|
87
|
+
|
|
88
|
+
group_data["config"].update(config)
|
|
89
|
+
self.storage.set(f"{self.group_prefix}{group_id}", group_data)
|
|
90
|
+
|
|
91
|
+
self.logger.info(f"更新反馈组 {group_id} 配置 by {operator_id}")
|
|
92
|
+
return True, "成功"
|
|
93
|
+
|
|
94
|
+
def dissolve_group(self, group_id: str, operator_id: str) -> Tuple[bool, str]:
|
|
95
|
+
# 获取反馈组
|
|
96
|
+
group_data = self.storage.get(f"{self.group_prefix}{group_id}")
|
|
97
|
+
if not group_data:
|
|
98
|
+
return False, "反馈组不存在"
|
|
99
|
+
|
|
100
|
+
# 检查权限:必须是创建者(admin_ids的第一个元素)
|
|
101
|
+
if not group_data["admin_ids"]:
|
|
102
|
+
return False, "反馈组数据异常"
|
|
103
|
+
|
|
104
|
+
creator_id = group_data["admin_ids"][0]
|
|
105
|
+
if operator_id != creator_id:
|
|
106
|
+
return False, "只有反馈组创建者才能解散反馈组"
|
|
107
|
+
|
|
108
|
+
# 删除所有群聊映射
|
|
109
|
+
for source_group_id in group_data["allowed_groups"]:
|
|
110
|
+
self.storage.delete(f"{self.mapping_prefix}{source_group_id}")
|
|
111
|
+
|
|
112
|
+
# 删除所有反馈数据
|
|
113
|
+
feedback_index = self.storage.get(f"fb_feedback_index:{group_id}", [])
|
|
114
|
+
for feedback_id in feedback_index:
|
|
115
|
+
self.storage.delete(f"fb_feedback:{group_id}:{feedback_id}")
|
|
116
|
+
|
|
117
|
+
# 删除反馈索引
|
|
118
|
+
self.storage.delete(f"fb_feedback_index:{group_id}")
|
|
119
|
+
|
|
120
|
+
# 删除反馈组
|
|
121
|
+
self.storage.delete(f"{self.group_prefix}{group_id}")
|
|
122
|
+
|
|
123
|
+
# 从索引中移除
|
|
124
|
+
group_index = self.storage.get(self.group_index_key, [])
|
|
125
|
+
if group_id in group_index:
|
|
126
|
+
group_index.remove(group_id)
|
|
127
|
+
self.storage.set(self.group_index_key, group_index)
|
|
128
|
+
|
|
129
|
+
self.logger.info(f"反馈组已解散: {group_id} ({group_data['name']}) by {operator_id}")
|
|
130
|
+
return True, "反馈组已解散"
|
|
131
|
+
|
|
132
|
+
def list_all_groups(self) -> List[Dict]:
|
|
133
|
+
group_index = self.storage.get(self.group_index_key, [])
|
|
134
|
+
groups = []
|
|
135
|
+
|
|
136
|
+
for group_id in group_index:
|
|
137
|
+
group_data = self.storage.get(f"{self.group_prefix}{group_id}")
|
|
138
|
+
if group_data:
|
|
139
|
+
groups.append(group_data)
|
|
140
|
+
|
|
141
|
+
return groups
|
|
142
|
+
|
|
143
|
+
def update_group_admins(self, group_id: str, new_admin_ids: List[str],
|
|
144
|
+
operator_id: str) -> Tuple[bool, str]:
|
|
145
|
+
# 获取反馈组
|
|
146
|
+
group_data = self.storage.get(f"{self.group_prefix}{group_id}")
|
|
147
|
+
if not group_data:
|
|
148
|
+
return False, "反馈组不存在"
|
|
149
|
+
|
|
150
|
+
# 更新管理员列表
|
|
151
|
+
group_data["admin_ids"] = new_admin_ids
|
|
152
|
+
self.storage.set(f"{self.group_prefix}{group_id}", group_data)
|
|
153
|
+
|
|
154
|
+
self.logger.info(f"更新反馈组 {group_id} 管理员 by {operator_id}: {new_admin_ids}")
|
|
155
|
+
return True, "成功"
|
|
156
|
+
|
|
157
|
+
def _generate_group_id(self) -> str:
|
|
158
|
+
key = "fb_group_next_id"
|
|
159
|
+
next_id = self.storage.get(key, 1)
|
|
160
|
+
group_id = f"group_{next_id}"
|
|
161
|
+
self.storage.set(key, next_id + 1)
|
|
162
|
+
return group_id
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class FeedbackManager:
|
|
166
|
+
|
|
167
|
+
def __init__(self, storage, logger, storage_prefix="fb_"):
|
|
168
|
+
self.storage = storage
|
|
169
|
+
self.logger = logger
|
|
170
|
+
self.storage_prefix = storage_prefix
|
|
171
|
+
self.feedback_prefix = f"{storage_prefix}feedback:"
|
|
172
|
+
self.index_prefix = f"{storage_prefix}feedback_index:"
|
|
173
|
+
|
|
174
|
+
def submit_feedback(self, feedback_group_id: str, source_group_id: str,
|
|
175
|
+
user_id: str, nickname: str, category: str,
|
|
176
|
+
content: str, config: Dict) -> Tuple[bool, str]:
|
|
177
|
+
# 验证类别
|
|
178
|
+
if category not in config.get("categories", []):
|
|
179
|
+
categories = ", ".join(config["categories"])
|
|
180
|
+
return False, f"无效的类别。请使用: {categories}"
|
|
181
|
+
|
|
182
|
+
# 生成反馈ID
|
|
183
|
+
feedback_id = self._generate_feedback_id(feedback_group_id)
|
|
184
|
+
|
|
185
|
+
# 创建反馈数据
|
|
186
|
+
feedback_data = {
|
|
187
|
+
"id": feedback_id,
|
|
188
|
+
"group_id": feedback_group_id,
|
|
189
|
+
"source_group_id": source_group_id,
|
|
190
|
+
"user_id": user_id,
|
|
191
|
+
"user_nickname": nickname,
|
|
192
|
+
"category": category,
|
|
193
|
+
"content": content,
|
|
194
|
+
"status": "pending",
|
|
195
|
+
"timestamp": int(time.time())
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
# 保存反馈
|
|
199
|
+
storage_key = f"{self.feedback_prefix}{feedback_group_id}:{feedback_id}"
|
|
200
|
+
self.storage.set(storage_key, feedback_data)
|
|
201
|
+
|
|
202
|
+
# 更新索引
|
|
203
|
+
index_key = f"{self.index_prefix}{feedback_group_id}"
|
|
204
|
+
feedback_index = self.storage.get(index_key, [])
|
|
205
|
+
feedback_index.append(feedback_id)
|
|
206
|
+
self.storage.set(index_key, feedback_index)
|
|
207
|
+
|
|
208
|
+
self.logger.info(f"反馈已提交: {feedback_id} (组: {feedback_group_id}) by {user_id}")
|
|
209
|
+
return True, feedback_id
|
|
210
|
+
|
|
211
|
+
def get_feedback(self, feedback_group_id: str, feedback_id: str) -> Optional[Dict]:
|
|
212
|
+
storage_key = f"{self.feedback_prefix}{feedback_group_id}:{feedback_id}"
|
|
213
|
+
return self.storage.get(storage_key)
|
|
214
|
+
|
|
215
|
+
def update_feedback_status(self, feedback_group_id: str, feedback_id: str,
|
|
216
|
+
new_status: str) -> Optional[Tuple[str, Dict]]:
|
|
217
|
+
storage_key = f"{self.feedback_prefix}{feedback_group_id}:{feedback_id}"
|
|
218
|
+
feedback_data = self.storage.get(storage_key)
|
|
219
|
+
if not feedback_data:
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
old_status = feedback_data["status"]
|
|
223
|
+
feedback_data["status"] = new_status
|
|
224
|
+
self.storage.set(storage_key, feedback_data)
|
|
225
|
+
|
|
226
|
+
self.logger.info(f"反馈状态更新: {feedback_id} {old_status} -> {new_status}")
|
|
227
|
+
return old_status, feedback_data
|
|
228
|
+
|
|
229
|
+
def list_all_feedbacks(self, feedback_group_id: str) -> List[Dict]:
|
|
230
|
+
feedbacks = []
|
|
231
|
+
|
|
232
|
+
# 使用索引获取所有反馈ID
|
|
233
|
+
index_key = f"{self.index_prefix}{feedback_group_id}"
|
|
234
|
+
feedback_ids = self.storage.get(index_key, [])
|
|
235
|
+
|
|
236
|
+
for feedback_id in feedback_ids:
|
|
237
|
+
data = self.storage.get(f"{self.feedback_prefix}{feedback_group_id}:{feedback_id}")
|
|
238
|
+
if data:
|
|
239
|
+
feedbacks.append(data)
|
|
240
|
+
|
|
241
|
+
return feedbacks
|
|
242
|
+
|
|
243
|
+
def list_feedbacks_filtered(self, feedback_group_id: str, category: Optional[str] = None,
|
|
244
|
+
status: Optional[str] = None, limit: int = 20) -> List[Dict]:
|
|
245
|
+
all_feedbacks = self.list_all_feedbacks(feedback_group_id)
|
|
246
|
+
|
|
247
|
+
# 筛选
|
|
248
|
+
filtered = []
|
|
249
|
+
for feedback in all_feedbacks:
|
|
250
|
+
if category and feedback["category"] != category:
|
|
251
|
+
continue
|
|
252
|
+
|
|
253
|
+
if status and feedback["status"] != status:
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
filtered.append(feedback)
|
|
257
|
+
|
|
258
|
+
# 按时间排序(最新的在前)
|
|
259
|
+
filtered.sort(key=lambda x: x["timestamp"], reverse=True)
|
|
260
|
+
|
|
261
|
+
return filtered[:limit]
|
|
262
|
+
|
|
263
|
+
def _generate_feedback_id(self, feedback_group_id: str) -> str:
|
|
264
|
+
key = f"{self.feedback_prefix}{feedback_group_id}:next_id"
|
|
265
|
+
next_id = self.storage.get(key, 1)
|
|
266
|
+
id_prefix = self.storage.get(f"fb_group:{feedback_group_id}.config.id_prefix", "#")
|
|
267
|
+
feedback_id = f"{id_prefix}{next_id}"
|
|
268
|
+
self.storage.set(key, next_id + 1)
|
|
269
|
+
return feedback_id
|
|
270
|
+
|
|
271
|
+
def import_feedbacks(self, feedback_group_id: str, feedbacks_data: List[Dict],
|
|
272
|
+
mode: str = "merge") -> Tuple[bool, str, int]:
|
|
273
|
+
if mode == "overwrite":
|
|
274
|
+
# 覆盖模式:先清空现有数据
|
|
275
|
+
self._clear_all_feedbacks(feedback_group_id)
|
|
276
|
+
|
|
277
|
+
# 获取当前索引
|
|
278
|
+
index_key = f"{self.index_prefix}{feedback_group_id}"
|
|
279
|
+
feedback_index = self.storage.get(index_key, [])
|
|
280
|
+
|
|
281
|
+
imported_count = 0
|
|
282
|
+
skipped_count = 0
|
|
283
|
+
|
|
284
|
+
for feedback_data in feedbacks_data:
|
|
285
|
+
feedback_id = feedback_data.get("id")
|
|
286
|
+
|
|
287
|
+
# 检查必要字段
|
|
288
|
+
required_fields = ["id", "user_id", "user_nickname", "category", "content", "status"]
|
|
289
|
+
if not all(field in feedback_data for field in required_fields):
|
|
290
|
+
self.logger.warning(f"跳过不完整的反馈数据: {feedback_id}")
|
|
291
|
+
skipped_count += 1
|
|
292
|
+
continue
|
|
293
|
+
|
|
294
|
+
# 合并模式:检查ID是否已存在
|
|
295
|
+
if mode == "merge":
|
|
296
|
+
if feedback_id in feedback_index:
|
|
297
|
+
skipped_count += 1
|
|
298
|
+
continue
|
|
299
|
+
|
|
300
|
+
# 保存反馈
|
|
301
|
+
storage_key = f"{self.feedback_prefix}{feedback_group_id}:{feedback_id}"
|
|
302
|
+
|
|
303
|
+
# 确保数据包含必要的字段
|
|
304
|
+
full_data = {
|
|
305
|
+
"id": feedback_data["id"],
|
|
306
|
+
"group_id": feedback_group_id,
|
|
307
|
+
"source_group_id": feedback_data.get("source_group_id", ""),
|
|
308
|
+
"user_id": feedback_data["user_id"],
|
|
309
|
+
"user_nickname": feedback_data["user_nickname"],
|
|
310
|
+
"category": feedback_data["category"],
|
|
311
|
+
"content": feedback_data["content"],
|
|
312
|
+
"status": feedback_data["status"],
|
|
313
|
+
"timestamp": feedback_data.get("timestamp", int(time.time()))
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
self.storage.set(storage_key, full_data)
|
|
317
|
+
|
|
318
|
+
# 更新索引
|
|
319
|
+
if feedback_id not in feedback_index:
|
|
320
|
+
feedback_index.append(feedback_id)
|
|
321
|
+
|
|
322
|
+
imported_count += 1
|
|
323
|
+
|
|
324
|
+
# 保存更新后的索引
|
|
325
|
+
self.storage.set(index_key, feedback_index)
|
|
326
|
+
|
|
327
|
+
# 更新反馈ID计数器(避免ID冲突)
|
|
328
|
+
if imported_count > 0:
|
|
329
|
+
self._update_feedback_id_counter(feedback_group_id, feedback_index)
|
|
330
|
+
|
|
331
|
+
message = f"成功导入 {imported_count} 条反馈"
|
|
332
|
+
if skipped_count > 0:
|
|
333
|
+
message += f",跳过 {skipped_count} 条"
|
|
334
|
+
|
|
335
|
+
self.logger.info(f"反馈数据导入完成: 组{feedback_group_id}, 导入{imported_count}条, 跳过{skipped_count}条")
|
|
336
|
+
return True, message, imported_count
|
|
337
|
+
|
|
338
|
+
def _clear_all_feedbacks(self, feedback_group_id: str):
|
|
339
|
+
index_key = f"{self.index_prefix}{feedback_group_id}"
|
|
340
|
+
feedback_ids = self.storage.get(index_key, [])
|
|
341
|
+
|
|
342
|
+
# 删除所有反馈
|
|
343
|
+
for feedback_id in feedback_ids:
|
|
344
|
+
storage_key = f"{self.feedback_prefix}{feedback_group_id}:{feedback_id}"
|
|
345
|
+
self.storage.delete(storage_key)
|
|
346
|
+
|
|
347
|
+
# 清空索引
|
|
348
|
+
self.storage.delete(index_key)
|
|
349
|
+
|
|
350
|
+
self.logger.info(f"已清空反馈组 {feedback_group_id} 的所有反馈数据")
|
|
351
|
+
|
|
352
|
+
def _update_feedback_id_counter(self, feedback_group_id: str, feedback_index: List[str]):
|
|
353
|
+
if not feedback_index:
|
|
354
|
+
return
|
|
355
|
+
|
|
356
|
+
# 提取所有ID中的数字部分
|
|
357
|
+
max_num = 0
|
|
358
|
+
for feedback_id in feedback_index:
|
|
359
|
+
# 去除前缀后提取数字
|
|
360
|
+
import re
|
|
361
|
+
match = re.search(r'\d+', feedback_id)
|
|
362
|
+
if match:
|
|
363
|
+
num = int(match.group())
|
|
364
|
+
if num > max_num:
|
|
365
|
+
max_num = num
|
|
366
|
+
|
|
367
|
+
# 更新计数器
|
|
368
|
+
key = f"{self.feedback_prefix}{feedback_group_id}:next_id"
|
|
369
|
+
self.storage.set(key, max_num + 1)
|
|
370
|
+
|
|
371
|
+
self.logger.info(f"更新反馈组 {feedback_group_id} 的ID计数器到 {max_num + 1}")
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
class FeedbackLogic:
|
|
375
|
+
|
|
376
|
+
def __init__(self, sdk, config: Dict):
|
|
377
|
+
self.sdk = sdk
|
|
378
|
+
self.storage = sdk.storage
|
|
379
|
+
self.logger = sdk.logger.get_child("FeedbackLogic")
|
|
380
|
+
self.config = config
|
|
381
|
+
|
|
382
|
+
# 初始化管理器
|
|
383
|
+
self.group_manager = FeedbackGroupManager(self.storage, self.logger)
|
|
384
|
+
|
|
385
|
+
def get_feedback_manager(self, feedback_group_id: str) -> FeedbackManager:
|
|
386
|
+
return FeedbackManager(self.storage, self.logger, self.config.get("storage_prefix", "fb_"))
|
|
387
|
+
|
|
388
|
+
def is_global_admin(self, user_id: str) -> bool:
|
|
389
|
+
global_admins = self.config.get("global_admins", [])
|
|
390
|
+
return user_id in global_admins
|
|
391
|
+
|
|
392
|
+
def is_group_admin(self, group_data: Dict, user_id: str) -> bool:
|
|
393
|
+
"""
|
|
394
|
+
检查是否为反馈组创建者
|
|
395
|
+
"""
|
|
396
|
+
if not group_data:
|
|
397
|
+
return False
|
|
398
|
+
return user_id in group_data.get("admin_ids", [])
|