From a72525e7dbd9066267140d9c537638be3f3219bd Mon Sep 17 00:00:00 2001 From: yyd Date: Sat, 8 Nov 2025 15:36:53 +0800 Subject: [PATCH] =?UTF-8?q?yyd=5Fservermanager=20APP=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/servermanager/MemcacheStorage.py | 41 +++-- src/servermanager/admin.py | 21 +-- src/servermanager/api/blogapi.py | 5 +- src/servermanager/api/commonapi.py | 12 +- src/servermanager/apps.py | 37 ++--- src/servermanager/migrations/0001_initial.py | 7 +- ...002_alter_emailsendlog_options_and_more.py | 6 +- src/servermanager/models.py | 7 +- src/servermanager/robot.py | 145 +++++++++++------- src/servermanager/tests.py | 10 +- src/servermanager/urls.py | 5 +- src/servermanager/views.py | 2 +- 12 files changed, 170 insertions(+), 128 deletions(-) diff --git a/src/servermanager/MemcacheStorage.py b/src/servermanager/MemcacheStorage.py index 5610ccd..78e656f 100644 --- a/src/servermanager/MemcacheStorage.py +++ b/src/servermanager/MemcacheStorage.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # 导入WeRoBot框架的会话存储基类和工具函数 from werobot.session import SessionStorage from werobot.utils import json_loads, json_dumps @@ -32,57 +35,53 @@ class MemcacheStorage(SessionStorage): """ value = "1" # 测试值 # 尝试设置一个测试键值对 - self.set('checkavaliable', value=value) + self.set('check_available', value=value) # 读取测试值并比较,验证缓存系统是否正常工作 - return value == self.get('checkavaliable') + return value == self.get('check_available') - def key_name(self, s): + def key_name(self, session_id): """ 生成完整的缓存键名 Args: - s (str): 原始会话ID + session_id (str): 原始会话ID Returns: str: 添加前缀后的完整缓存键名 """ - return '{prefix}{s}'.format(prefix=self.prefix, s=s) + return f'{self.prefix}{session_id}' - def get(self, id): + def get(self, session_id): """ 根据会话ID获取会话数据 Args: - id (str): 会话ID + session_id (str): 会话ID Returns: dict: 解析后的会话数据字典,如果不存在返回空字典 """ - id = self.key_name(id) # 生成完整缓存键 - # 从缓存获取数据,如果不存在则返回空JSON对象 - session_json = self.cache.get(id) or '{}' - # 将JSON字符串解析为Python字典 + key = self.key_name(session_id) # 生成完整缓存键 + session_json = self.cache.get(key) or '{}' # 从缓存获取数据 return json_loads(session_json) - def set(self, id, value): + def set(self, session_id, value): """ 设置会话数据 Args: - id (str): 会话ID + session_id (str): 会话ID value (dict): 要存储的会话数据字典 """ - id = self.key_name(id) # 生成完整缓存键 - # 将会话数据序列化为JSON字符串并存储到缓存 - self.cache.set(id, json_dumps(value)) + key = self.key_name(session_id) + self.cache.set(key, json_dumps(value)) - def delete(self, id): + def delete(self, session_id): """ 删除指定会话ID的数据 Args: - id (str): 要删除的会话ID + session_id (str): 要删除的会话ID """ - id = self.key_name(id) # 生成完整缓存键 - # 从缓存中删除对应的数据 - self.cache.delete(id) \ No newline at end of file + key = self.key_name(session_id) + self.cache.delete(key) diff --git a/src/servermanager/admin.py b/src/servermanager/admin.py index b8cdfe8..d18ca95 100644 --- a/src/servermanager/admin.py +++ b/src/servermanager/admin.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # 导入Django管理模块 from django.contrib import admin # 导入自定义模型(假设已在同一目录的models.py中定义) @@ -14,9 +17,9 @@ class CommandsAdmin(admin.ModelAdmin): # 设置在管理列表页面显示的字段 list_display = ('title', 'command', 'describe') # 字段说明: - # - title: 命令标题 - # - command: 具体命令内容 - # - describe: 命令描述 + # title: 命令标题 + # command: 具体命令内容 + # describe: 命令描述 # 注册EmailSendLog模型到Django管理后台 @@ -29,10 +32,10 @@ class EmailSendLogAdmin(admin.ModelAdmin): # 设置在管理列表页面显示的字段 list_display = ('title', 'emailto', 'send_result', 'creation_time') # 字段说明: - # - title: 邮件标题 - # - emailto: 收件人 - # - send_result: 发送结果 - # - creation_time: 创建时间 + # title: 邮件标题 + # emailto: 收件人 + # send_result: 发送结果 + # creation_time: 创建时间 # 设置只读字段,这些字段在编辑页面不可修改 readonly_fields = ( @@ -54,8 +57,8 @@ class EmailSendLogAdmin(admin.ModelAdmin): bool: 总是返回False,禁止添加操作 """ return False - # 这样设计是因为邮件发送日志应该由系统自动创建 - # 而不是手动添加,保证日志的真实性和完整性 + # 这样设计是因为邮件发送日志应该由系统自动创建1 + # 而不是手动添加,保证日志的真实性和完整性. # 将模型注册到Django管理后台 diff --git a/src/servermanager/api/blogapi.py b/src/servermanager/api/blogapi.py index d9e4a7d..6ba09ef 100644 --- a/src/servermanager/api/blogapi.py +++ b/src/servermanager/api/blogapi.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # 导入Haystack搜索查询集 from haystack.query import SearchQuerySet @@ -72,7 +75,7 @@ class BlogApi: 获取最近的文章 Returns: - QuerySet: 包含最近文章的查询集,最多返回__max_takecount__条 + QuerySet: 包含最近文章的查询集,最多返回__max_takecount__条.1 """ # 获取所有文章并按时间排序(假设Article模型的默认排序是按时间倒序) return Article.objects.all()[:self.__max_takecount__] \ No newline at end of file diff --git a/src/servermanager/api/commonapi.py b/src/servermanager/api/commonapi.py index 98fbc0e..7ba0a43 100644 --- a/src/servermanager/api/commonapi.py +++ b/src/servermanager/api/commonapi.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # 导入必要的模块 import logging import os @@ -101,16 +104,17 @@ class CommandHandler: # 使用os.popen执行系统命令并读取输出 res = os.popen(cmd).read() return res - except BaseException: - # 捕获所有异常,返回错误信息 + except Exception as e: + logger.error(f"命令执行错误:{e}") return '命令执行出错!' + def get_help(self): """ 获取所有命令的帮助信息 Returns: - str: 格式化的命令帮助信息,包含所有命令的标题和描述 + str: 格式化的命令帮助信息,包含所有命令的标题和描述1 """ rsp = '' # 遍历所有命令,格式化输出 @@ -119,7 +123,7 @@ class CommandHandler: return rsp -# 主程序入口 +# 主程序入口. if __name__ == '__main__': # 创建ChatGPT实例 chatbot = ChatGPT() diff --git a/src/servermanager/apps.py b/src/servermanager/apps.py index 8098071..abbb713 100644 --- a/src/servermanager/apps.py +++ b/src/servermanager/apps.py @@ -1,31 +1,22 @@ -# 导入Django的应用配置基类 +#yyd: +# coding: utf-8 + +# 导入 Django 的应用配置基类 from django.apps import AppConfig class ServermanagerConfig(AppConfig): """ - Servermanager应用的配置类 - 继承自Django的AppConfig基类,用于配置servermanager应用的相关设置 + Servermanager 应用配置类 + ------------------------------------- + 用于配置 servermanager 应用的元数据和初始化行为。 - 这个类主要用于: - 1. 定义应用的配置信息 - 2. 在Django启动时执行应用初始化代码 - 3. 配置应用的元数据 + 主要功能: + 1. 定义应用的基本配置信息; + 2. 在 Django 启动时进行应用级初始化; + 3. 提供应用的可读名称和默认主键类型等可选设置。 """ - - # 指定应用的Python路径(必需字段) - # 这应该与settings.INSTALLED_APPS中使用的路径匹配 + + # 应用在项目中的 Python 路径(必填项) + # 该名称必须与 settings.INSTALLED_APPS 中一致。 name = 'servermanager' - # 说明: - # - 'servermanager' 表示应用的Python导入路径 - # - Django使用这个名称来识别和应用配置 - - # 可选配置字段示例(当前代码中未使用): - # - # verbose_name = '服务器管理器' # 应用的可读名称 - # default_auto_field = 'django.db.models.BigAutoField' # 默认主键字段类型 - # - # 可以在ready()方法中添加应用启动时的初始化代码: - # def ready(self): - # # 应用启动时执行的初始化代码 - # import servermanager.signals # 例如:导入信号处理器 \ No newline at end of file diff --git a/src/servermanager/migrations/0001_initial.py b/src/servermanager/migrations/0001_initial.py index 0cfdd13..2fa1be1 100644 --- a/src/servermanager/migrations/0001_initial.py +++ b/src/servermanager/migrations/0001_initial.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # Generated by Django 4.1.7 on 2023-03-02 07:14 from django.db import migrations, models @@ -41,7 +44,7 @@ class Migration(migrations.Migration): }, ), - # 创建邮件发送日志表 + # 创建邮件发送日志表. migrations.CreateModel( name='EmailSendLog', # 模型名称 fields=[ @@ -60,7 +63,7 @@ class Migration(migrations.Migration): ], options={ 'verbose_name': '邮件发送log', # 单数形式的可读名称 - 'verbose_name_plural': '邮件发送log', # 复数形式的可读名称 + 'verbose_name_plural': '邮件发送log', # 复数形式的可读名称1 'ordering': ['-created_time'], # 默认按创建时间降序排列 }, ), diff --git a/src/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py b/src/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py index 67e8c70..38caa17 100644 --- a/src/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py +++ b/src/servermanager/migrations/0002_alter_emailsendlog_options_and_more.py @@ -1,3 +1,5 @@ +#yyd: +# coding: utf-8 # Generated by Django 4.2.5 on 2023-09-06 13:19 from django.db import migrations @@ -27,7 +29,7 @@ class Migration(migrations.Migration): }, ), - # 重命名commands模型的created_time字段为creation_time + # 重命名commands模型的.created_time字段为creation_time migrations.RenameField( model_name='commands', # 模型名称 old_name='created_time', # 原字段名 @@ -41,7 +43,7 @@ class Migration(migrations.Migration): new_name='last_modify_time', # 新字段名 ), - # 重命名emailsendlog模型的created_time字段为creation_time + # 重命名emailsendlog模型的created_time字段为creation_time1 migrations.RenameField( model_name='emailsendlog', # 模型名称 old_name='created_time', # 原字段名 diff --git a/src/servermanager/models.py b/src/servermanager/models.py index 8539cf2..b5d70f0 100644 --- a/src/servermanager/models.py +++ b/src/servermanager/models.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # 导入Django的模型模块 from django.db import models @@ -77,6 +80,6 @@ class EmailSendLog(models.Model): """ 模型的元数据配置类 """ - verbose_name = '邮件发送log' # 单数形式的可读名称 + verbose_name = '邮件发送log' # 单数形式的可读名称. verbose_name_plural = verbose_name # 复数形式的可读名称 - ordering = ['-creation_time'] # 默认按创建时间降序排列(最新的在前) \ No newline at end of file + ordering = ['-creation_time'] # 默认按创建时间降序排列(最新的在前)1 \ No newline at end of file diff --git a/src/servermanager/robot.py b/src/servermanager/robot.py index 1762ed8..878e84e 100644 --- a/src/servermanager/robot.py +++ b/src/servermanager/robot.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # 导入必要的模块 import logging import os @@ -79,7 +82,7 @@ def search(message, session): if result: # 将搜索结果转换为文章对象列表 - articles = list(map(lambda x: x.object, result)) + articles = [x.object for x in result] reply = convert_to_article_reply(articles, message) return reply else: @@ -90,11 +93,12 @@ def search(message, session): def category(message, session): """ 获取所有文章分类 - 触发方式: category + 触发方式:category """ categorys = blogapi.get_category_lists() - content = ','.join(map(lambda x: x.name, categorys)) - return '所有文章分类目录:' + content + content = ','.join([x.name for x in categorys]) + return '所有文章分类目录: ' + content + @robot.filter(re.compile(r'^recent\s*$', re.I)) @@ -171,7 +175,7 @@ class MessageHandler: # 从会话中获取用户信息 info = session[userid] self.userinfo = jsonpickle.decode(info) - except Exception as e: + except Exception: # 如果会话中没有用户信息,创建新的用户信息对象 userinfo = WxUserInfo() self.userinfo = userinfo @@ -193,63 +197,92 @@ class MessageHandler: def handler(self): """主消息处理方法""" - info = self.message.content + info = self.message.content.strip().upper() - # 管理员退出命令 - if self.userinfo.isAdmin and info.upper() == 'EXIT': - self.userinfo = WxUserInfo() - self.save_session() + if self._handle_exit(info): return "退出成功" - - # 进入管理员模式 - if info.upper() == 'ADMIN': - self.userinfo.isAdmin = True - self.save_session() + + if self._handle_admin_entry(info): return "输入管理员密码" - - # 管理员密码验证 - if self.userinfo.isAdmin and not self.userinfo.isPasswordSet: - passwd = settings.WXADMIN # 从设置获取管理员密码 - if settings.TESTING: # 测试环境下使用简单密码 - passwd = '123' - # 验证密码(双重SHA256加密) - if passwd.upper() == get_sha256(get_sha256(info)).upper(): - self.userinfo.isPasswordSet = True - self.save_session() - return "验证通过,请输入命令或者要执行的命令代码:输入helpme获得帮助" - else: - # 密码错误次数限制 - if self.userinfo.Count >= 3: - self.userinfo = WxUserInfo() - self.save_session() - return "超过验证次数" - self.userinfo.Count += 1 - self.save_session() - return "验证失败,请重新输入管理员密码:" - - # 管理员命令执行 - if self.userinfo.isAdmin and self.userinfo.isPasswordSet: - # 确认执行命令 - if self.userinfo.Command != '' and info.upper() == 'Y': - return cmd_handler.run(self.userinfo.Command) - else: - # 获取命令帮助 - if info.upper() == 'HELPME': - return cmd_handler.get_help() - # 保存命令等待确认 - self.userinfo.Command = info - self.save_session() - return "确认执行: " + info + " 命令?" - - # 默认使用ChatGPT回复 - return ChatGPT.chat(info) + + if self._needs_password_verification(): + return self._handle_password_verify(info) + + if self._can_execute_admin_command(): + return self._handle_admin_command(info) + + return self._handle_default_chat(info) + +# ------------------ 以下为子逻辑模块 ------------------ + +def _handle_exit(self, info: str) -> bool: + """管理员退出命令""" + if self.userinfo.isAdmin and info == 'EXIT': + self.userinfo = WxUserInfo() + self.save_session() + return True + return False + +def _handle_admin_entry(self, info: str) -> bool: + """进入管理员模式""" + if info == 'ADMIN': + self.userinfo.isAdmin = True + self.save_session() + return True + return False + +def _needs_password_verification(self) -> bool: + """判断是否需要进行密码验证""" + return self.userinfo.isAdmin and not self.userinfo.isPasswordSet + +def _handle_password_verify(self, info: str) -> str: + """管理员密码验证""" + passwd = settings.WXADMIN + if settings.TESTING: + passwd = '123' + + # 双重加密验证 + if passwd.upper() == get_sha256(get_sha256(info)).upper(): + self.userinfo.isPasswordSet = True + self.save_session() + return "验证通过,请输入命令或者要执行的命令代码:输入helpme获得帮助" + + # 密码错误次数限制 + if self.userinfo.Count >= 3: + self.userinfo = WxUserInfo() + self.save_session() + return "超过验证次数" + + self.userinfo.Count += 1 + self.save_session() + return "验证失败,请重新输入管理员密码:" + +def _can_execute_admin_command(self) -> bool: + """是否处于可执行管理员命令状态""" + return self.userinfo.isAdmin and self.userinfo.isPasswordSet + +def _handle_admin_command(self, info: str) -> str: + """管理员命令执行""" + if self.userinfo.Command and info == 'Y': + return cmd_handler.run(self.userinfo.Command) + + if info == 'HELPME': + return cmd_handler.get_help() + + self.userinfo.Command = info + self.save_session() + return f"确认执行: {info} 命令?" + +def _handle_default_chat(self, info: str) -> str: + """普通模式下使用 ChatGPT 回复""" + return ChatGPT.chat(info) class WxUserInfo(): """微信用户信息类,用于存储用户会话状态""" def __init__(self): - self.isAdmin = False # 是否为管理员 - self.isPasswordSet = False # 是否通过密码验证 - self.Count = 0 # 密码尝试次数 - self.Command = '' # 待确认的命令 \ No newline at end of file + self.is_admin = False # 是否为管理员. + self.is_password_set = False # 是否通过密码验证1 + self.count = 0 # 密码尝试次数 + self.command = '' # 待确认的命令 \ No newline at end of file diff --git a/src/servermanager/tests.py b/src/servermanager/tests.py index 2f57a6c..c42d9fe 100644 --- a/src/servermanager/tests.py +++ b/src/servermanager/tests.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # 导入Django测试相关模块 from django.test import Client, RequestFactory, TestCase from django.utils import timezone @@ -72,7 +75,6 @@ class ServerManagerTest(TestCase): # 测试搜索功能 s = TextMessage([]) # 创建空的文本消息对象 s.content = "nice" # 设置消息内容 - rsp = search(s, None) # 调用搜索函数 # 注意:这里没有对搜索结果进行断言,可能需要补充 # 测试分类功能 @@ -83,7 +85,6 @@ class ServerManagerTest(TestCase): rsp = recents(None, None) # 调用最近文章函数 self.assertTrue(rsp != '暂时还没有文章') # 断言有文章返回 - # 测试命令功能 # 创建测试命令 cmd = commands() cmd.title = "test" @@ -101,9 +102,6 @@ class ServerManagerTest(TestCase): s.content = 'test' # 设置消息内容 msghandler = MessageHandler(s, {}) # 创建消息处理器 - # 注释掉的管理员权限设置 - # msghandler.userinfo.isPasswordSet = True - # msghandler.userinfo.isAdmin = True # 测试各种消息处理场景 msghandler.handler() # 处理'test'消息 @@ -117,5 +115,5 @@ class ServerManagerTest(TestCase): msghandler.handler() s.content = '123' # 输入管理员密码 msghandler.handler() - s.content = 'exit' # 退出管理员模式 + s.content = 'exit' # 退出管理员模式.1 msghandler.handler() \ No newline at end of file diff --git a/src/servermanager/urls.py b/src/servermanager/urls.py index f3b73f5..8ffc494 100644 --- a/src/servermanager/urls.py +++ b/src/servermanager/urls.py @@ -1,3 +1,6 @@ +#yyd: +# coding: utf-8 + # 导入Django的URL路由模块 from django.urls import path # 导入WeRoBot的Django视图创建工具 @@ -18,5 +21,5 @@ urlpatterns = [ # 说明: # - r'robot': URL路径模式,匹配"robot"路径 # - make_view(robot): 将WeRoBot机器人实例包装成Django视图函数 - # - 这个端点用于接收微信服务器发送的消息和事件 + # - 这个端点用于接收微信服务器发送的消息和事件.1 ] \ No newline at end of file diff --git a/src/servermanager/views.py b/src/servermanager/views.py index 60f00ef..c84b472 100644 --- a/src/servermanager/views.py +++ b/src/servermanager/views.py @@ -1 +1 @@ -# Create your views here. +# Create your views here..1 -- 2.34.1