Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

自动更新模板文件夹 #1677

Closed
wants to merge 15 commits into from
Closed

自动更新模板文件夹 #1677

wants to merge 15 commits into from

Conversation

molanp
Copy link
Contributor

@molanp molanp commented Oct 5, 2024

  • 在帮助页面中使用配置的BOT名称替代硬编码的"真寻BOT"
  • 更新自动更新配置,将资源模板文件夹加入替换列表
  • 修改帮助插件以传递BOT名称到模板
  • 修复签到插件中的商品描述拼写错误

Summary by Sourcery

更新项目以支持模板文件夹的自动更新,修复登录插件中的拼写错误,并通过使用可配置的机器人名称增强帮助页面。

新功能:

  • 引入新功能以自动更新项目中的模板文件夹,允许动态更新而无需人工干预。

错误修复:

  • 修复登录插件中产品描述的拼写错误,确保向用户显示准确的信息。

增强功能:

  • 将帮助页面中硬编码的机器人名称“真寻BOT”替换为可配置的机器人名称,提高灵活性和自定义性。
  • 修改帮助插件以将机器人名称传递给模板,改善机器人特定信息的集成和显示。
Original summary in English

Summary by Sourcery

Update the project to support automatic updates of the template folder, fix a typo in the sign-in plugin, and enhance the help page by using a configurable bot name.

New Features:

  • Introduce a new feature to automatically update the template folder in the project, allowing for dynamic updates without manual intervention.

Bug Fixes:

  • Fix a typo in the product description within the sign-in plugin, ensuring accurate information is displayed to users.

Enhancements:

  • Replace hardcoded bot name '真寻BOT' with a configurable bot name in the help page, enhancing flexibility and customization.
  • Modify the help plugin to pass the bot name to the template, improving the integration and display of bot-specific information.

molanp and others added 15 commits October 1, 2024 17:09
- 扩展插件添加、移除和更新功能,支持使用插件ID或模块名
- 增加更新全部插件的功能
- 优化插件商店的命令使用说明
- 修复了一些与插件模块名相关的逻辑问题
- 修复了插件更新函数中的条件判断逻辑
调整了插件更新通知的文本格式,去掉了多余的换行符,使消息内容更加紧凑和清晰。
- 将插件ID和模块名的检查逻辑移至单独的私有方法 _resolve_plugin_key
- 简化了 get_info 和 update_plugin 方法中的逻辑
- 提高了代码的可读性和可维护性
简化了ShopManage类中查询插件信息的逻辑。通过新增的_resolve_plugin_key类方法来解析插件ID或模块名,如果解析失败则捕获ValueError异常并返回错误信息。这样可以更清晰地处理插件查询逻辑,并避免冗余代码。
更新全部插件功能中,移除了日志记录中的f-string,简化了日志消息的格式。这个更改可能是为了统一日志记录的风格或者减少不必要的字符串格式化操作。
- 在帮助页面中使用配置的BOT名称替代硬编码的"真寻BOT"
- 更新自动更新配置,将资源模板文件夹加入替换列表
- 修改帮助插件以传递BOT名称到模板
- 修复签到插件中的商品描述拼写错误
Copy link

sourcery-ai bot commented Oct 5, 2024

审核指南由 Sourcery 提供

此拉取请求对 Zhenxun Bot 项目进行了多项改进和更改。更改包括配置处理的更新、各种插件的重构、Web UI 的改进以及机器人核心功能的增强。

更新的 ShopManage 类图

classDiagram
    class ShopManage {
        +get_data() dict[str, StorePluginInfo]
        +version_check(plugin_info: StorePluginInfo, suc_plugin: dict[str, str]) str
        +check_version_is_new(plugin_info: StorePluginInfo, suc_plugin: dict[str, str]) bool
        +get_loaded_plugins(*args) list[tuple[str, str]]
        +add_plugin(plugin_id: int | str) str
        +install_plugin_with_repo(github_url: str, module_path: str, is_dir: bool, is_external: bool = False)
        +remove_plugin(plugin_id: int | str) str
        +update_plugin(plugin_id: int | str) str
        +update_all_plugin() str
        +_resolve_plugin_key(plugin_id: int | str) str
    }
Loading

更新的 AsyncHttpx 类图

classDiagram
    class AsyncHttpx {
        +get(url: str | list[str], params: dict[str, Any] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, timeout: int, **kwargs) Response
        +_get_first_successful(urls: list[str], **kwargs) Response
        +_get_single(url: str, params: dict[str, Any] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, timeout: int, **kwargs) Response
        +head(url: str, params: dict[str, Any] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, timeout: int, **kwargs) Response
        +post(url: str, data: dict[str, Any] | None, content: Any, files: Any, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, json: dict[str, Any] | None, params: dict[str, str] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, timeout: int, **kwargs) Response
        +download_file(url: str | list[str], path: str | Path, params: dict[str, str] | None, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, timeout: int, stream: bool, follow_redirects: bool, **kwargs) bool
        +gather_download_file(url_list: list[str] | list[list[str]], path_list: list[str | Path], limit_async_number: int | None, params: dict[str, str] | None, use_proxy: bool, proxy: dict[str, str] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, timeout: int, **kwargs) list[bool]
        +get_fastest_mirror(url_list: list[str]) list[str]
    }
Loading

更新的 PluginManage 类图

classDiagram
    class PluginManage {
        +set_default_status(plugin_name: str, status: bool) str
        +set_all_plugin_status(status: bool, default_status: bool, group_id: str | None) str
        +_change_group_task(group_id: str, task_name: str, status: bool) str
        +_change_group_plugin(group_id: str, plugin_name: str, status: bool) str
        +superuser_task_handle(task_name: str, status: bool, group_id: str | None) str
        +superuser_block(plugin_name: str, block_type: BlockType | None, group_id: str | None) str
        +superuser_unblock(plugin_name: str, block_type: BlockType | None, group_id: str | None) str
    }
Loading

文件级更改

更改 详情 文件
重构配置处理和改进插件管理
  • 更新配置加载和保存机制
  • 改进插件注册和元数据处理
  • 重构插件限制和任务管理
zhenxun/configs/utils/__init__.py
zhenxun/builtin_plugins/init/init_plugin.py
zhenxun/models/plugin_info.py
增强 Web UI 功能和 API 端点
  • 为插件管理和仪表板添加新的 API 端点
  • 改进 API 调用中的错误处理和响应格式
  • 更新 WebSocket 实现以实现实时数据更新
zhenxun/builtin_plugins/web_ui/__init__.py
zhenxun/builtin_plugins/web_ui/api/tabs/main/__init__.py
zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/__init__.py
改进机器人核心功能和平台特定处理
  • 重构群组管理和欢迎消息处理
  • 在整个代码库中增强错误处理和日志记录
  • 更新平台特定的实用程序和处理程序
zhenxun/builtin_plugins/platform/qq/group_handle.py
zhenxun/utils/platform.py
zhenxun/builtin_plugins/platform/qq/group_handle/data_source.py
更新和优化各种插件
  • 重构签到插件,改进数据处理
  • 更新图像管理和处理实用程序
  • 改进多个插件中的错误处理和性能
zhenxun/builtin_plugins/sign_in/__init__.py
zhenxun/builtin_plugins/image_management/__init__.py
zhenxun/utils/image_utils.py
实现新功能和命令
  • 添加金币排名功能
  • 实现新的插件商店功能
  • 为插件管理和用户交互添加新命令
zhenxun/builtin_plugins/shop/__init__.py
zhenxun/builtin_plugins/plugin_store/__init__.py
zhenxun/builtin_plugins/admin/plugin_switch/__init__.py

提示和命令

与 Sourcery 互动

  • 触发新审核: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审核评论。
  • 从审核评论生成 GitHub 问题: 通过回复审核评论请求 Sourcery 创建问题。
  • 生成拉取请求标题: 在拉取请求标题中任意位置写 @sourcery-ai 以随时生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中任意位置写 @sourcery-ai summary 以随时生成 PR 摘要。您还可以使用此命令指定摘要应插入的位置。

自定义您的体验

访问您的仪表板以:

  • 启用或禁用审核功能,例如 Sourcery 生成的拉取请求摘要、审核指南等。
  • 更改审核语言。
  • 添加、删除或编辑自定义审核说明。
  • 调整其他审核设置。

获取帮助

Original review guide in English

Reviewer's Guide by Sourcery

This pull request implements several improvements and changes to the Zhenxun Bot project. The changes include updates to configuration handling, refactoring of various plugins, improvements to the web UI, and enhancements to the bot's core functionality.

Updated class diagram for ShopManage

classDiagram
    class ShopManage {
        +get_data() dict[str, StorePluginInfo]
        +version_check(plugin_info: StorePluginInfo, suc_plugin: dict[str, str]) str
        +check_version_is_new(plugin_info: StorePluginInfo, suc_plugin: dict[str, str]) bool
        +get_loaded_plugins(*args) list[tuple[str, str]]
        +add_plugin(plugin_id: int | str) str
        +install_plugin_with_repo(github_url: str, module_path: str, is_dir: bool, is_external: bool = False)
        +remove_plugin(plugin_id: int | str) str
        +update_plugin(plugin_id: int | str) str
        +update_all_plugin() str
        +_resolve_plugin_key(plugin_id: int | str) str
    }
Loading

Updated class diagram for AsyncHttpx

classDiagram
    class AsyncHttpx {
        +get(url: str | list[str], params: dict[str, Any] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, timeout: int, **kwargs) Response
        +_get_first_successful(urls: list[str], **kwargs) Response
        +_get_single(url: str, params: dict[str, Any] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, timeout: int, **kwargs) Response
        +head(url: str, params: dict[str, Any] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, timeout: int, **kwargs) Response
        +post(url: str, data: dict[str, Any] | None, content: Any, files: Any, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, json: dict[str, Any] | None, params: dict[str, str] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, timeout: int, **kwargs) Response
        +download_file(url: str | list[str], path: str | Path, params: dict[str, str] | None, verify: bool, use_proxy: bool, proxy: dict[str, str] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, timeout: int, stream: bool, follow_redirects: bool, **kwargs) bool
        +gather_download_file(url_list: list[str] | list[list[str]], path_list: list[str | Path], limit_async_number: int | None, params: dict[str, str] | None, use_proxy: bool, proxy: dict[str, str] | None, headers: dict[str, str] | None, cookies: dict[str, str] | None, timeout: int, **kwargs) list[bool]
        +get_fastest_mirror(url_list: list[str]) list[str]
    }
Loading

Updated class diagram for PluginManage

classDiagram
    class PluginManage {
        +set_default_status(plugin_name: str, status: bool) str
        +set_all_plugin_status(status: bool, default_status: bool, group_id: str | None) str
        +_change_group_task(group_id: str, task_name: str, status: bool) str
        +_change_group_plugin(group_id: str, plugin_name: str, status: bool) str
        +superuser_task_handle(task_name: str, status: bool, group_id: str | None) str
        +superuser_block(plugin_name: str, block_type: BlockType | None, group_id: str | None) str
        +superuser_unblock(plugin_name: str, block_type: BlockType | None, group_id: str | None) str
    }
Loading

File-Level Changes

Change Details Files
Refactored configuration handling and improved plugin management
  • Updated configuration loading and saving mechanisms
  • Improved plugin registration and metadata handling
  • Refactored plugin limit and task management
zhenxun/configs/utils/__init__.py
zhenxun/builtin_plugins/init/init_plugin.py
zhenxun/models/plugin_info.py
Enhanced Web UI functionality and API endpoints
  • Added new API endpoints for plugin management and dashboard
  • Improved error handling and response formatting in API calls
  • Updated WebSocket implementations for real-time data updates
zhenxun/builtin_plugins/web_ui/__init__.py
zhenxun/builtin_plugins/web_ui/api/tabs/main/__init__.py
zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/__init__.py
Improved bot core functionality and platform-specific handling
  • Refactored group management and welcome message handling
  • Enhanced error handling and logging throughout the codebase
  • Updated platform-specific utilities and handlers
zhenxun/builtin_plugins/platform/qq/group_handle.py
zhenxun/utils/platform.py
zhenxun/builtin_plugins/platform/qq/group_handle/data_source.py
Updated and optimized various plugins
  • Refactored sign-in plugin with improved data handling
  • Updated image management and processing utilities
  • Improved error handling and performance in multiple plugins
zhenxun/builtin_plugins/sign_in/__init__.py
zhenxun/builtin_plugins/image_management/__init__.py
zhenxun/utils/image_utils.py
Implemented new features and commands
  • Added gold ranking feature
  • Implemented new plugin store functionality
  • Added new commands for plugin management and user interactions
zhenxun/builtin_plugins/shop/__init__.py
zhenxun/builtin_plugins/plugin_store/__init__.py
zhenxun/builtin_plugins/admin/plugin_switch/__init__.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@molanp - 我已经审查了你的更改,发现了一些需要解决的问题。

阻塞问题

  • URL 路径中可能存在硬编码的秘密。(链接)
这是我在审查期间查看的内容
  • 🟡 一般问题:发现 8 个问题
  • 🔴 安全性:1 个阻塞问题
  • 🟡 测试:发现 8 个问题
  • 🟡 复杂性:发现 1 个问题
  • 🟢 文档:一切看起来都很好

Sourcery 对开源项目免费 - 如果你喜欢我们的审查,请考虑分享 ✨
帮助我变得更有用!请在每条评论上点击 👍 或 👎,我将使用反馈来改进你的审查。
Original comment in English

Hey @molanp - I've reviewed your changes and found some issues that need to be addressed.

Blocking issues:

  • Potential hard-coded secret in URL path. (link)
Here's what I looked at during the review
  • 🟡 General issues: 8 issues found
  • 🔴 Security: 1 blocking issue
  • 🟡 Testing: 8 issues found
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -295,6 +393,39 @@ async def gather_download_file(
tasks.clear()
return result_

@classmethod
async def get_fastest_mirror(cls, url_list: list[str]) -> list[str]:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议: 添加更详细的注释以解释逻辑

此方法包含复杂的逻辑。考虑添加更详细的注释,解释它如何确定最快的镜像以及在实现中为何做出某些决策。

    @classmethod
    async def get_fastest_mirror(cls, url_list: list[str]) -> list[str]:
        """
        从给定的 URL 列表中确定并返回最快的镜像。

        此方法测试每个 URL 的响应时间并将其从快到慢排序。它处理连接错误和超时。
        """
        assert url_list
Original comment in English

suggestion: Add more detailed comments explaining the logic

This method contains complex logic. Consider adding more detailed comments explaining how it determines the fastest mirror and why certain decisions were made in the implementation.

    @classmethod
    async def get_fastest_mirror(cls, url_list: list[str]) -> list[str]:
        """
        Determine and return the fastest mirror from the given URL list.

        This method tests the response time of each URL and sorts them
        from fastest to slowest. It handles connection errors and timeouts.
        """
        assert url_list

GROUP_HELP_PATH = DATA_PATH / "group_help"


def delete_help_image(gid: str | None = None):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议: 考虑为文件操作添加错误处理

文件操作可能由于各种原因失败(例如,权限、磁盘已满)。考虑添加 try-except 块以处理潜在的异常并适当地记录错误。

def delete_help_image(gid: str | None = None):
    try:
        # 现有函数实现
        pass
    except OSError as e:
        logger.error(f"删除帮助图片时出错,群组 {gid}: {e}")
    except Exception as e:
        logger.error(f"删除帮助图片时出现意外错误,群组 {gid}: {e}")
Original comment in English

suggestion: Consider adding error handling for file operations

File operations can fail for various reasons (e.g., permissions, disk full). Consider adding try-except blocks to handle potential exceptions and log errors appropriately.

def delete_help_image(gid: str | None = None):
    try:
        # Existing function implementation here
        pass
    except OSError as e:
        logger.error(f"Error deleting help image for group {gid}: {e}")
    except Exception as e:
        logger.error(f"Unexpected error deleting help image for group {gid}: {e}")

@@ -51,35 +50,36 @@ async def rank(
"user_id", flat=True
)
query = query.filter(user_id__in=user_list)
all_list = (
user_list = (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议(性能): 考虑为初始查询添加限制以防止大数据集的潜在内存问题。

虽然一次性获取所有数据对于较小的数据集可能更高效,但对于非常大的用户群可能会导致内存问题。考虑在查询中添加 LIMIT 子句,并在需要时实现分页。这在内存使用和数据库查询频率之间进行权衡。

Suggested change
user_list = (
user_list = (
await query.annotate()
.order_by("-impression")
.limit(1000) # 添加限制以防止潜在的内存问题
.values_list("user_id", "impression", "sign_count", "platform")
)
user_id_list = [user[0] for user in user_list]
index = user_id_list.index(user_id) + 1
user_list = user_list[:num] if num < len(user_list) else user_list
Original comment in English

suggestion (performance): Consider adding a limit to the initial query to prevent potential memory issues with large datasets.

While fetching all data at once can be more efficient for smaller datasets, it might cause memory problems for very large user bases. Consider adding a LIMIT clause to the query and implementing pagination if needed. This trades off between memory usage and database query frequency.

Suggested change
user_list = (
user_list = (
await query.annotate()
.order_by("-impression")
.limit(1000) # Add a limit to prevent potential memory issues
.values_list("user_id", "impression", "sign_count", "platform")
)
user_id_list = [user[0] for user in user_list]
index = user_id_list.index(user_id) + 1
user_list = user_list[:num] if num < len(user_list) else user_list

@@ -38,6 +40,7 @@ async def _(bot_id: str | None = None) -> Result:
返回:
Result: 获取指定bot信息与bot列表
"""
global run_time
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议: 避免使用全局变量;考虑替代的设计模式。

使用全局变量可能导致可维护性问题,并使代码更难以理解。考虑将 run_time 作为参数传递,或者如果需要在多个函数中共享,将其封装在类或模块级变量中。

class RuntimeManager:
    _instance = None
    run_time = None

    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance

    @classmethod
    def get_run_time(cls):
        return cls.get_instance().run_time

    @classmethod
    def set_run_time(cls, value):
        cls.get_instance().run_time = value
Original comment in English

suggestion: Avoid using global variables; consider alternative design patterns.

Using global variables can lead to maintainability issues and make the code harder to reason about. Consider passing the run_time as a parameter or encapsulating it within a class or module-level variable if it needs to be shared across multiple functions.

class RuntimeManager:
    _instance = None
    run_time = None

    @classmethod
    def get_instance(cls):
        if cls._instance is None:
            cls._instance = cls()
        return cls._instance

    @classmethod
    def get_run_time(cls):
        return cls.get_instance().run_time

    @classmethod
    def set_run_time(cls, value):
        cls.get_instance().run_time = value

@@ -21,6 +23,8 @@
).dict(),
)

TEMP_LIST = []
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议(bug风险): 考虑为 TEMP_LIST 使用更线程安全的数据结构。

在多线程环境中,使用简单的列表作为 TEMP_LIST 可能导致竞争条件。考虑使用线程安全的数据结构,如 collections.deque 和 threading.Lock,或者如果更适合生产者-消费者模式,则使用 queue.Queue。

Suggested change
TEMP_LIST = []
from collections import deque
from threading import Lock
TEMP_LIST = deque()
TEMP_LIST_LOCK = Lock()
Original comment in English

suggestion (bug_risk): Consider using a more thread-safe data structure for TEMP_LIST.

Using a simple list for TEMP_LIST might lead to race conditions in a multi-threaded environment. Consider using a thread-safe data structure like collections.deque with a threading.Lock, or queue.Queue if producer-consumer pattern is more appropriate.

Suggested change
TEMP_LIST = []
from collections import deque
from threading import Lock
TEMP_LIST = deque()
TEMP_LIST_LOCK = Lock()

result=None,
bot=bot,
)
assert mocked_api["basic_plugins"].called
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议(测试): 考虑为插件移除添加更多断言

测试验证了插件文件被移除,但也可以检查插件不再存在于数据库或任何其他相关数据结构中。

assert not (mock_base_path / "plugins" / "search_image").exists()
from zhenxun.builtin_plugins.plugin_store.data_source import get_plugin_list
plugin_list = await get_plugin_list()
assert not any(plugin['id'] == plugin_id for plugin in plugin_list)
Original comment in English

suggestion (testing): Consider adding more assertions for plugin removal

The test verifies that the plugin file is removed, but it could also check that the plugin is no longer in the database or any other relevant data structures.

assert not (mock_base_path / "plugins" / "search_image").exists()
from zhenxun.builtin_plugins.plugin_store.data_source import get_plugin_list
plugin_list = await get_plugin_list()
assert not any(plugin['id'] == plugin_id for plugin in plugin_list)

mock_build_message_return.send.assert_awaited_once()

assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议(测试): 为插件商店中的错误处理添加测试

当前测试仅涵盖成功场景。考虑添加一个测试用例,以应对 API 调用失败或返回意外数据的情况。

async def test_plugin_store_error_handling(
    app: App,
    mocker: MockerFixture,
    mocked_api: MockRouter,
    create_bot: Callable,
    tmp_path: Path,
) -> None:
    mocked_api["basic_plugins"].side_effect = Exception("API Error")
    mocked_api["extra_plugins"].side_effect = Exception("API Error")

    async with app.test_matcher(_matcher) as ctx:
        bot = create_bot(ctx)
        event = _v11_group_message_event(message="插件商店", to_me=True)
        await ctx.receive_event(bot=bot, event=event)

    assert "获取插件列表失败" in str(ctx.call_next.send.call_args)
Original comment in English

suggestion (testing): Add test for error handling in plugin store

The current test only covers the successful scenario. Consider adding a test case for when the API calls fail or return unexpected data.

async def test_plugin_store_error_handling(
    app: App,
    mocker: MockerFixture,
    mocked_api: MockRouter,
    create_bot: Callable,
    tmp_path: Path,
) -> None:
    mocked_api["basic_plugins"].side_effect = Exception("API Error")
    mocked_api["extra_plugins"].side_effect = Exception("API Error")

    async with app.test_matcher(_matcher) as ctx:
        bot = create_bot(ctx)
        event = _v11_group_message_event(message="插件商店", to_me=True)
        await ctx.receive_event(bot=bot, event=event)

    assert "获取插件列表失败" in str(ctx.call_next.send.call_args)

bot=bot,
)
assert mocked_api["basic_plugins"].called
assert mocked_api["extra_plugins"].called
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议(测试): 为部分更新场景添加测试

考虑添加一个测试用例,其中一些插件成功更新,而其他插件失败。这将测试更新过程的错误处理和报告。

async def test_update_all_plugin_partial_success(
    app: App,
    mocker: MockerFixture,
    mocked_api: MockRouter,
    create_bot: Callable,
    tmp_path: Path,
) -> None:
    # 设置代码类似于 test_update_all_plugin_basic_need_update
    # ...

    # 模拟部分成功:一个插件更新,一个失败
    mocker.patch(
        "zhenxun.builtin_plugins.plugin_store.data_source.ShopManage.update_plugin",
        side_effect=[True, Exception("Update failed")],
    )

    # 测试执行和断言
    # ...
Original comment in English

suggestion (testing): Add test for partial update scenario

Consider adding a test case where some plugins are updated successfully while others fail. This would test the error handling and reporting of the update process.

async def test_update_all_plugin_partial_success(
    app: App,
    mocker: MockerFixture,
    mocked_api: MockRouter,
    create_bot: Callable,
    tmp_path: Path,
) -> None:
    # Setup code similar to test_update_all_plugin_basic_need_update
    # ...

    # Mock partial success: one plugin updates, one fails
    mocker.patch(
        "zhenxun.builtin_plugins.plugin_store.data_source.ShopManage.update_plugin",
        side_effect=[True, Exception("Update failed")],
    )

    # Test execution and assertions
    # ...

router = APIRouter(prefix="/dashboard")


@router.get(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

问题(复杂性): 考虑重构通用查询逻辑为可重用函数以降低复杂性。

虽然当前结构为特定查询提供了清晰、独立的端点,但我们可以通过一些有针对性的更改来降低复杂性并提高可维护性:

  1. 将通用查询逻辑提取为可重用函数:
def get_filtered_query(model, bot_id=None):
    query = model
    if bot_id:
        query = query.filter(bot_id=bot_id)
    return query

def get_count_for_timeframe(query, days=0, hours=0, minutes=0):
    now = datetime.now()
    return query.filter(
        create_time__gte=now - timedelta(days=days, hours=hours, minutes=minutes)
    ).count()
  1. 使用这些函数简化端点逻辑:
@router.get("/get_chat_and_call_count")
async def get_chat_and_call_count(bot_id: str | None = None) -> Result:
    chat_query = get_filtered_query(ChatHistory, bot_id)
    call_query = get_filtered_query(Statistics, bot_id)

    return Result.ok(
        QueryChatCallCount(
            chat_num=await chat_query.count(),
            chat_day=await get_count_for_timeframe(chat_query),
            call_num=await call_query.count(),
            call_day=await get_count_for_timeframe(call_query)
        )
    )
  1. 考虑为这些仪表板查询创建一个单独的文件,例如 dashboard_queries.py,以改善组织。

这些更改将减少代码重复并提高可维护性,同时保留每个端点的清晰性和特定目的。提取的函数可以在多个端点中重用,使得将来添加或修改查询更容易。

Original comment in English

issue (complexity): Consider refactoring common query logic into reusable functions to reduce complexity.

While the current structure provides clear, separate endpoints for specific queries, we can reduce complexity and improve maintainability with a few targeted changes:

  1. Extract common query logic into reusable functions:
def get_filtered_query(model, bot_id=None):
    query = model
    if bot_id:
        query = query.filter(bot_id=bot_id)
    return query

def get_count_for_timeframe(query, days=0, hours=0, minutes=0):
    now = datetime.now()
    return query.filter(
        create_time__gte=now - timedelta(days=days, hours=hours, minutes=minutes)
    ).count()
  1. Use these functions to simplify endpoint logic:
@router.get("/get_chat_and_call_count")
async def get_chat_and_call_count(bot_id: str | None = None) -> Result:
    chat_query = get_filtered_query(ChatHistory, bot_id)
    call_query = get_filtered_query(Statistics, bot_id)

    return Result.ok(
        QueryChatCallCount(
            chat_num=await chat_query.count(),
            chat_day=await get_count_for_timeframe(chat_query),
            call_num=await call_query.count(),
            call_day=await get_count_for_timeframe(call_query)
        )
    )
  1. Consider creating a separate file for these dashboard queries, e.g., dashboard_queries.py, to improve organization.

These changes will reduce code duplication and improve maintainability while preserving the clarity and specific purpose of each endpoint. The extracted functions can be reused across multiple endpoints, making it easier to add or modify queries in the future.

@@ -20,16 +20,24 @@ async def favicon():
return FileResponse(PUBLIC_PATH / "favicon.ico")


@router.get("/79edfa81f3308a9f.jfif")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 问题(安全性): URL 路径中可能存在硬编码的秘密。

URL 路径 '/79edfa81f3308a9f.jfif' 似乎是一个硬编码的值。如果这是一个敏感的标识符或密钥,考虑使用更安全的方法来处理它。

Original comment in English

🚨 issue (security): Potential hard-coded secret in URL path.

The URL path '/79edfa81f3308a9f.jfif' appears to be a hard-coded value. If this is a sensitive identifier or key, consider using a more secure method to handle it.

@molanp molanp changed the base branch from main to dev October 5, 2024 06:01
@molanp molanp closed this Oct 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants