@@ -149,6 +149,93 @@ def _handle_local_command(bot: Bot, message, config: Config, cmd: str) -> bool:
149149 return True
150150
151151
152+ async def _check_forum_requirements (bot : Bot , chat_id : int ) -> tuple [bool , str ]:
153+ """检查群组 Topic 功能要求。
154+
155+ Returns:
156+ (is_ok, error_message) - 如果满足要求返回 (True, ""),否则返回 (False, 错误提示)
157+ """
158+ try :
159+ chat = await bot .get_chat (chat_id )
160+ if not chat .is_forum :
161+ return False , (
162+ "⚠️ 群组未开启 Topics 功能\n \n "
163+ "请按以下步骤开启:\n "
164+ "1. 打开群组设置\n "
165+ "2. 点击「Topics」\n "
166+ "3. 开启 Topics 功能\n "
167+ "4. 重新添加 Bot"
168+ )
169+
170+ me = await bot .get_me ()
171+ member = await bot .get_chat_member (chat_id , me .id )
172+ if not getattr (member , 'can_manage_topics' , False ):
173+ return False , (
174+ "⚠️ Bot 缺少「管理 Topics」权限\n \n "
175+ "请按以下步骤授权:\n "
176+ "1. 打开群组设置 > 管理员\n "
177+ "2. 选择此 Bot\n "
178+ "3. 开启「Manage Topics」权限"
179+ )
180+ return True , ""
181+ except Exception as e :
182+ logger .warning (f"Failed to check forum requirements: { e } " )
183+ return False , f"检查权限失败: { str (e )[:100 ]} "
184+
185+
186+ async def _handle_newchat_command (
187+ bot : Bot , message , body : dict , config : Config , sqs , prompts : str
188+ ) -> bool :
189+ """处理 /newchat - 创建 Topic 并发送消息到 SQS。
190+
191+ Args:
192+ bot: Telegram Bot 实例
193+ message: Telegram Message 对象
194+ body: 原始 webhook body (用于构造 SQS 消息)
195+ config: 配置对象
196+ sqs: SQS 客户端
197+ prompts: 用户输入的消息内容
198+
199+ Returns:
200+ True 如果成功,False 如果失败
201+ """
202+ from datetime import datetime
203+
204+ chat_id = message .chat_id
205+ topic_name = f"Chat { datetime .now ().strftime ('%m/%d %H:%M' )} "
206+
207+ try :
208+ forum_topic = await bot .create_forum_topic (chat_id = chat_id , name = topic_name )
209+ new_thread_id = forum_topic .message_thread_id
210+
211+ # 使用标准 SQS 消息格式,覆盖 text 和 thread_id
212+ message_body = {
213+ 'telegram_update' : body ,
214+ 'chat_id' : chat_id ,
215+ 'message_id' : message .message_id ,
216+ 'text' : prompts ,
217+ 'thread_id' : new_thread_id ,
218+ }
219+
220+ success = _send_to_sqs_safe (sqs , config .queue_url , message_body )
221+ if not success :
222+ await bot .send_message (
223+ chat_id = chat_id ,
224+ text = "发送消息失败,请重试" ,
225+ message_thread_id = new_thread_id ,
226+ )
227+ return success
228+
229+ except Exception as e :
230+ logger .warning (f"Failed to create forum topic: { e } " )
231+ await bot .send_message (
232+ chat_id = chat_id ,
233+ text = f"创建 Topic 失败: { str (e )[:100 ]} " ,
234+ message_thread_id = message .message_thread_id ,
235+ )
236+ return False
237+
238+
152239def lambda_handler (event : dict , context : Any ) -> dict :
153240 """Lambda entry point - Producer.
154241
@@ -182,6 +269,23 @@ def lambda_handler(event: dict, context: Any) -> dict:
182269 extra = {'chat_id' : chat_id , 'inviter_id' : inviter_id },
183270 )
184271 _send_metric ('SecurityBlock.UnauthorizedGroup' )
272+ else :
273+ # 授权群组的 Topic 预检
274+ member_update = update .my_chat_member
275+ old_status = member_update .old_chat_member .status
276+ new_status = member_update .new_chat_member .status
277+
278+ if old_status in ('left' , 'kicked' ) and new_status in (
279+ 'member' ,
280+ 'administrator' ,
281+ ):
282+ chat_id = member_update .chat .id
283+ is_ok , error_msg = asyncio .run (
284+ _check_forum_requirements (bot , chat_id )
285+ )
286+ if not is_ok :
287+ asyncio .run (bot .send_message (chat_id = chat_id , text = error_msg ))
288+ _send_metric ('TopicPrecheck.Failed' )
185289 return {'statusCode' : 200 }
186290
187291 message = update .message or update .edited_message
@@ -201,6 +305,25 @@ def lambda_handler(event: dict, context: Any) -> dict:
201305 return {'statusCode' : 200 }
202306
203307 cmd = config .get_command (message .text )
308+
309+ # /newchat 特殊处理 - 创建 Topic 后发 SQS
310+ if cmd == '/newchat' :
311+ # 提取 prompts:移除命令部分(包括可能的 @bot 后缀)
312+ parts = message .text .strip ().split (maxsplit = 1 )
313+ prompts = parts [1 ] if len (parts ) > 1 else ''
314+ if not prompts :
315+ bot .send_message (
316+ chat_id = message .chat_id ,
317+ text = "用法: /newchat <消息内容>" ,
318+ message_thread_id = message .message_thread_id ,
319+ )
320+ return {'statusCode' : 200 }
321+
322+ sqs = _get_sqs_client ()
323+ asyncio .run (_handle_newchat_command (bot , message , body , config , sqs , prompts ))
324+ return {'statusCode' : 200 }
325+
326+ # 其他 local command 正常处理
204327 if cmd and config .is_local_command (cmd ):
205328 _handle_local_command (bot , message , config , cmd )
206329 return {'statusCode' : 200 }
0 commit comments