SeaCogs/issuecards/models/repository.py
cswimr 5c999735f1
Some checks failed
Actions / Lint Code (Ruff & Pylint) (pull_request) Failing after 50s
Actions / Build Documentation (MkDocs) (pull_request) Successful in 1m2s
feat(issuecards): init
2025-03-28 10:23:05 -05:00

140 lines
7.2 KiB
Python

from sys import version as pyversion
from discord import Guild
from pydantic import BaseModel, ConfigDict
from redbot import version_info
from redbot.core.bot import commands
from ..config import config
from .provider import Provider
class Repository(BaseModel):
"""Model for a repository configuration.
Attributes:
cog (commands.Cog): The cog object that allows accessing a discord.py Bot object, along other things.
owner (str): The owner of the repository.
repository (str): The name of the repository.
prefix (str): Prefix used for determining which repository to retrieve an issue from when using the `#<issue-num>` syntax
provider (Provider): The provider configuration for the repository. This requires a provider to be registered at the given URL.
guild (Guild | None): The Discord guild associated with the repository. If None, the repository is considered a global repository.
Properties:
url (str): The URL for the repository.
user_agent (str): The user agent for API requests using this object.
Methods:
to_config: Save the repository to Red's configuration. Saves to guilds if the `guild` class attribute is set.
remove_config: Remove the repository from Red's configuration. Removes from guilds if the `guild` class attribute is set.
Class Methods:
from_config: Create a Repository instance from the Red configuration. Checks both global and guild repositories, prioritizing guild repositories.
from_prefix: Create a Repository instance from the Red configuration using the prefix. Checks both global and guild repositories, prioritizing guild repositories.
fetch_all: Fetch all repositories from the Red configuration. Returns a list of Repository instances.
"""
model_config = ConfigDict(arbitrary_types_allowed=True)
cog: commands.Cog
owner: str
name: str
prefix: str | None = None
provider: Provider
guild: Guild | None = None
@property
def url(self) -> str:
"""Return the URL for the repository."""
return f"{self.provider.url.rstrip('/')}/{self.owner}/{self.name}"
@property
def user_agent(self) -> str:
"""Return the user agent for API requests using this object."""
return f"Red-DiscordBot/{version_info} {self.cog.__cog_name__}/{self.cog.__version__} ({self.cog.__git__}) (Python {pyversion})"
async def to_config(self) -> None:
"""Save the repository to Red's configuration. Saves to guilds if the `guild` class attribute is set."""
if self.guild:
repositories = await config.guild(self.guild).repositories()
else:
repositories = await config.global_repositories()
for repo in repositories:
if repo["owner"] == self.owner and repo["name"] == self.name:
repo["provider"] = self.provider.id
if not any(repo["owner"] == self.owner and repo["name"] == self.name for repo in repositories):
repositories.append({"owner": self.owner, "name": self.name, "prefix": self.prefix, "provider": self.provider.id})
if self.guild:
await config.guild(self.guild).repositories.set(repositories)
else:
await config.global_repositories.set(repositories)
async def remove_config(self) -> None:
"""Remove the repository from Red's configuration. Removes from guilds if the `guild` class attribute is set."""
if self.guild:
repositories = await config.guild(self.guild).repositories()
repositories = [repo for repo in repositories if not (repo["provider"] == self.provider.id and repo["owner"] == self.owner and repo["name"] == self.name)]
await config.guild(self.guild).repositories.set(repositories)
else:
repositories = await config.global_repositories()
repositories = [repo for repo in repositories if not (repo["provider"] == self.provider.id and repo["owner"] == self.owner and repo["name"] == self.name)]
await config.global_repositories.set(repositories)
@classmethod
async def from_config(cls, cog: commands.Cog, provider_id: str, owner: str, repository: str, guild: Guild | None = None) -> "Repository":
"""Create a Repository instance from the Red configuration. Checks both global and guild repositories, prioritizing guild repositories."""
if guild:
guild_repositories = await config.guild(guild).repositories()
for repo in guild_repositories:
if repo["provider"] == provider_id and repo["owner"] == owner and repo["name"] == repository:
try:
provider = await Provider.from_config(repo["provider"], guild=guild)
except ValueError:
pass
return cls(cog=cog, guild=guild, owner=owner, name=repository, prefix=repo["prefix"], provider=provider)
repositories = await config.global_repositories()
for repo in repositories:
if repo["provider"] == provider_id and repo["owner"] == owner and repo["name"] == repository:
try:
provider = await Provider.from_config(repo["provider"])
except ValueError as e:
raise ValueError("Failed to create provider from config: '%s'" % str(e)) from e
return cls(cog=cog, guild=None, owner=owner, name=repository, prefix=repo["prefix"], provider=provider)
raise ValueError("No repository found for owner: '%s' and repository: '%s'" % (owner, repository))
@classmethod
async def from_prefix(cls, cog: commands.Cog, prefix: str, guild: Guild | None = None) -> "Repository":
"""Create a Repository instance from the Red configuration using the prefix. Checks both global and guild repositories, prioritizing guild repositories."""
repositories = await cls.fetch_all(cog, guild)
for repo in repositories:
if repo.prefix is not None and repo.prefix == prefix:
return repo
raise ValueError("No repository found for prefix: '%s'" % prefix)
@classmethod
async def fetch_all(cls, cog: commands.Cog, guild: Guild | None = None) -> tuple["Repository"]:
"""Fetch all repositories from the Red configuration. Returns a list of Repository instances."""
repositories_list = []
if guild:
guild_repositories = await config.guild(guild).repositories()
for repo in guild_repositories:
try:
provider = await Provider.from_config(repo["provider"], guild=guild)
except ValueError:
continue
repositories_list.extend((cls(cog=cog, guild=guild, owner=repo["owner"], name=repo["name"], prefix=repo["prefix"], provider=provider),))
global_repositories = await config.global_repositories()
for repo in global_repositories:
try:
provider = await Provider.from_config(repo["provider"])
except ValueError:
continue
repositories_list.extend((cls(cog=cog, guild=None, owner=repo["owner"], name=repo["name"], prefix=repo["prefix"], provider=provider),))
return tuple(repositories_list)