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

feat: adjust settings to use guild configs #86

Closed
wants to merge 29 commits into from

Conversation

JacobCoffee
Copy link
Owner

@JacobCoffee JacobCoffee commented Oct 11, 2024

Description

  • more work toward per-guild settings

Summary by Sourcery

Implement per-guild configuration settings, allowing for customization of various guild-specific options. Add new API endpoints for managing these configurations and introduce a system health check endpoint. Update the bot's guild join process and enhance logging. Update CI to use Python 3.12 and add new Makefile targets for database management.

New Features:

  • Introduce per-guild configuration settings, allowing for customization of various guild-specific options such as GitHub, StackOverflow tags, allowed users, and forum configurations.
  • Add new API endpoints for updating and retrieving guild configurations, including GitHub, StackOverflow tags, allowed users, and forum settings.
  • Implement a new command to schedule office hours events on Discord, with options to specify the timing.
  • Add a system health check endpoint to monitor the status of backend components including the database and bot status.

Enhancements:

  • Refactor the guild controller to support additional services and schemas for managing guild-specific configurations.
  • Update the logging configuration to include HTTPX and HTTP core libraries for better monitoring of HTTP requests.
  • Enhance the bot's guild join process to log and notify about successful or failed guild additions to the database.

Build:

  • Add new Makefile targets for managing the Byte database container, including starting, stopping, and refreshing the container.

CI:

  • Update the CI configuration to use Python 3.12 for all jobs, ensuring compatibility with the latest Python version.

Documentation:

  • Update the index.html template to dynamically display the server count and overall system status based on the new health check endpoint.

Tests:

  • Add new tests for the guild configuration services and controllers to ensure correct functionality of the new per-guild settings.

JacobCoffee and others added 29 commits May 10, 2024 20:06
chore(ui): increase byte screen logo size
* feat: add guild configuration command

* feat: add litestar office hours command

* fix: centralize options for slashcmd and dropdown

* ci: apply pre-commit

* chore: dependecy updates

* chore: clean up utils

* fix: move moved import

* fix: attempt to fix broken modal submission

* feat:  finalize working config selection and sub selections

* ci: for some reason pre-commit is stupid and changed every fucking file
Copy link
Contributor

sourcery-ai bot commented Oct 11, 2024

Reviewer's Guide by Sourcery

This pull request implements significant changes to support per-guild settings in the Byte Discord bot. It includes modifications to database models, API endpoints, and bot commands to allow for more granular configuration of bot features on a per-guild basis. The changes also include improvements to the project structure, type hinting, and error handling.

ER diagram for Guild Configuration

erDiagram
    GUILD {
        UUID id
        string guild_name
        string prefix
        int help_channel_id
        int showcase_channel_id
        string sync_label
        boolean issue_linking
        boolean comment_linking
        boolean pep_linking
    }

    GITHUB_CONFIG {
        int guild_id
        boolean discussion_sync
        string github_organization
        string github_repository
    }

    SOTAGS_CONFIG {
        int guild_id
        string tag_name
    }

    ALLOWED_USERS_CONFIG {
        int guild_id
        UUID user_id
    }

    FORUM_CONFIG {
        int guild_id
        boolean help_forum
        string help_forum_category
        boolean help_thread_auto_close
        int help_thread_auto_close_days
        boolean help_thread_notify
        string help_thread_notify_roles
        int help_thread_notify_days
        boolean showcase_forum
        string showcase_forum_category
        boolean showcase_thread_auto_close
        int showcase_thread_auto_close_days
    }

    GUILD ||--o{ GITHUB_CONFIG : has
    GUILD ||--o{ SOTAGS_CONFIG : has
    GUILD ||--o{ ALLOWED_USERS_CONFIG : has
    GUILD ||--o{ FORUM_CONFIG : has
Loading

Class diagram for Guild Configuration

classDiagram
    class GuildsController {
        +get_guild(guild_id: int) GuildSchema
        +update_guild(guild_id: int, setting: UpdateableGuildSetting, value: str | int) GuildSchema
        +get_guild_github_config(guild_id: int) GitHubConfigSchema
        +get_guild_sotags_config(guild_id: int) SOTagsConfigSchema
        +get_guild_allowed_users_config(guild_id: int) AllowedUsersConfigSchema
        +get_guild_forum_config(guild_id: int) ForumConfigSchema
    }

    class GuildSchema {
        +UUID guild_id
        +bool issue_linking
        +bool comment_linking
        +bool pep_linking
        +GitHubConfigSchema github_config
        +list~SOTagsConfigSchema~ sotags_configs
        +list~AllowedUsersConfigSchema~ allowed_users
        +ForumConfigSchema forum_config
    }

    class GitHubConfigSchema {
        +UUID guild_id
        +bool discussion_sync
        +str github_organization
        +str github_repository
    }

    class SOTagsConfigSchema {
        +UUID guild_id
        +str tag_name
    }

    class AllowedUsersConfigSchema {
        +UUID guild_id
        +UUID user_id
    }

    class ForumConfigSchema {
        +UUID guild_id
        +bool help_forum
        +str help_forum_category
        +bool help_thread_auto_close
        +int help_thread_auto_close_days
        +bool help_thread_notify
        +list~int~ help_thread_notify_roles
        +int help_thread_notify_days
        +bool help_thread_sync
        +bool showcase_forum
        +str showcase_forum_category
        +bool showcase_thread_auto_close
        +int showcase_thread_auto_close_days
    }

    GuildsController --> GuildSchema
    GuildSchema --> GitHubConfigSchema
    GuildSchema --> SOTagsConfigSchema
    GuildSchema --> AllowedUsersConfigSchema
    GuildSchema --> ForumConfigSchema
Loading

File-Level Changes

Change Details Files
Implemented per-guild settings and configurations
  • Added new database models for forum, GitHub, and Stack Overflow tag configurations
  • Updated existing models to support new configuration options
  • Created new API endpoints for managing guild configurations
  • Implemented new Discord UI views and modals for configuration management
  • Added new bot commands for guild admins to configure Byte features
src/server/domain/db/models.py
src/server/domain/guilds/controllers.py
src/server/domain/guilds/schemas.py
src/server/domain/guilds/services.py
src/byte/views/config.py
src/byte/plugins/config.py
Refactored and improved project structure
  • Moved utility functions to separate modules
  • Created new type definitions for improved type hinting
  • Reorganized imports and updated import statements
  • Implemented new helper functions and utility classes
src/byte/lib/common/mention.py
src/byte/lib/types/astral.py
src/byte/lib/types/python.py
src/server/lib/dto.py
src/byte/lib/checks.py
Enhanced error handling and system health monitoring
  • Implemented new system health check endpoints
  • Added database and bot status checks
  • Created new DTOs for system health information
src/server/domain/system/helpers.py
src/server/domain/system/dtos.py
src/server/domain/web/controllers/web.py
Updated dependencies and development environment
  • Upgraded Python version to 3.12
  • Updated pre-commit hooks and GitHub Actions workflows
  • Added new Makefile commands for database management
.github/workflows/ci.yml
.pre-commit-config.yaml
Makefile

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
Contributor

@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.

Hey @JacobCoffee - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟡 General issues: 3 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟡 Documentation: 2 issues found

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.

@@ -48,3 +115,75 @@ class GuildUpdate(CamelizedBaseModel):
issue_linking: bool | None = Field(title="Issue Linking", description="Is issue linking enabled.")
comment_linking: bool | None = Field(title="Comment Linking", description="Is comment linking enabled.")
pep_linking: bool | None = Field(title="PEP Linking", description="Is PEP linking enabled.")


class UpdateableGuildSetting(CamelizedBaseModel):
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Review and enhance validation for UpdateableGuildSetting

Ensure that the UpdateableGuildSetting class covers all possible settings and includes comprehensive validation logic. Consider adding more specific validators for each field to prevent invalid data.

logger.info("successfully added guild %s (ID: %s)", guild.name, guild.id)
else:
logger.error("%s joined guild '%s' but was not added to database", self.user.name, guild.name)
try:
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Enhance error logging in on_guild_join method

While error handling has been added, consider including more detailed error messages in the logging statements. This will help with debugging and identifying the root cause of any issues that may occur during guild joining.

        try:
            async with httpx.AsyncClient() as client:
                response = await client.post(api_url)
                response.raise_for_status()
        except httpx.HTTPError as e:
            logger.error(f"HTTP error occurred while joining guild {guild.name} (ID: {guild.id}): {str(e)}")
        except Exception as e:
            logger.error(f"Unexpected error occurred while joining guild {guild.name} (ID: {guild.id}): {str(e)}")

__all__ = ("get_byte_server_count",)


async def get_byte_server_count() -> int:
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Add error handling for database operations

Consider adding try-except blocks to handle potential database errors gracefully. This will make the function more robust and prevent unexpected crashes.

async def get_byte_server_count() -> int:
    try:
        # Existing code to get server count
        pass
    except Exception as e:
        logger.error(f"Error fetching Byte server count: {e}")
        return 0

Comment on lines +1 to 2
=====
Usage
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (documentation): Remove extra underlining for consistency in header formatting.

The 'Usage' header now has underlining both above and below. This isn't consistent with other headers in the documentation. Consider removing the top line of '=' signs to maintain consistency.

Suggested change
=====
Usage
Usage
=====

Comment on lines -17 to 18
guild
testing
Copy link
Contributor

Choose a reason for hiding this comment

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

question (documentation): Clarify the removal of the 'guild' plugin documentation.

The 'guild' plugin documentation has been removed and replaced with 'python'. Can you confirm if the guild functionality has been removed or moved elsewhere? This change might impact users who were relying on the guild plugin documentation.



class GuildController(Controller):
class GuildsController(Controller):
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider implementing a generic method and service for handling all configuration types.

The controller's complexity has increased significantly with the addition of multiple methods for different guild configurations. To reduce complexity while maintaining functionality, consider the following changes:

  1. Implement a generic method for handling all configuration types:
@get(
    operation_id="ConfigDetail",
    name="guilds:config",
    summary="Get config for a guild.",
    path="/guilds/{guild_id}/{config_type}",
)
async def get_guild_config(
    self,
    config_service: Annotated[ConfigService, Depends(get_config_service)],
    guild_id: int = Parameter(title="Guild ID", description="The guild ID."),
    config_type: str = Parameter(title="Config Type", description="The type of configuration to retrieve."),
) -> ConfigSchema | OffsetPagination[ConfigSchema]:
    """Get a guild's config by ID and type."""
    result = await config_service.get(guild_id, config_type)
    return config_service.to_schema(result)
  1. Create a ConfigService that handles all configuration types:
class ConfigService:
    def __init__(self, config_services: dict[str, BaseConfigService]):
        self.config_services = config_services

    async def get(self, guild_id: int, config_type: str) -> Any:
        service = self.config_services.get(config_type)
        if not service:
            raise ValueError(f"Invalid config type: {config_type}")
        return await service.get(guild_id, id_attribute="guild_id")

    def to_schema(self, result: Any) -> ConfigSchema | OffsetPagination[ConfigSchema]:
        # Implementation depends on your specific needs
        pass
  1. Update the dependency injection to use the new ConfigService:
def get_config_service():
    return ConfigService({
        "github": provides_github_config_service(),
        "sotags": provides_sotags_config_service(),
        "allowed_users": provides_allowed_users_config_service(),
        "forum": provides_forum_config_service(),
    })

These changes will significantly reduce code duplication and complexity in the controller while maintaining the separation of concerns for different configuration types. The ConfigService acts as a facade, delegating to the appropriate service based on the config type. This approach is more scalable and easier to maintain as new configuration types are added in the future.

batch_op.add_column(sa.Column("showcase_thread_auto_close", sa.Boolean(), nullable=False))
batch_op.add_column(sa.Column("showcase_thread_auto_close_days", sa.Integer(), nullable=True))
batch_op.add_column(sa.Column("sa_orm_sentinel", sa.Integer(), nullable=True))
batch_op.add_column(sa.Column("created_at", sa.DateTimeUTC(timezone=True), nullable=False))
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Extract duplicate code into function (extract-duplicate-method)

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.

1 participant