Add guild templates support (#41)

This commit is contained in:
Slipstream 2025-06-10 21:10:29 -06:00 committed by GitHub
parent c250c22737
commit 9509213f7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 143 additions and 0 deletions

View File

@ -51,6 +51,7 @@ if TYPE_CHECKING:
Thread,
DMChannel,
Webhook,
GuildTemplate,
ScheduledEvent,
AuditLogEntry,
Invite,
@ -710,6 +711,13 @@ class Client:
self._webhooks[webhook.id] = webhook
return webhook
def parse_template(self, data: Dict[str, Any]) -> "GuildTemplate":
"""Parses template data into a GuildTemplate object."""
from .models import GuildTemplate
return GuildTemplate(data, client_instance=self)
def parse_scheduled_event(self, data: Dict[str, Any]) -> "ScheduledEvent":
"""Parses scheduled event data and updates cache."""
@ -1313,6 +1321,45 @@ class Client:
await self._http.delete_webhook(webhook_id)
async def fetch_templates(self, guild_id: Snowflake) -> List["GuildTemplate"]:
"""|coro| Fetch all templates for a guild."""
if self._closed:
raise DisagreementException("Client is closed.")
data = await self._http.get_guild_templates(guild_id)
return [self.parse_template(t) for t in data]
async def create_template(
self, guild_id: Snowflake, payload: Dict[str, Any]
) -> "GuildTemplate":
"""|coro| Create a template for a guild."""
if self._closed:
raise DisagreementException("Client is closed.")
data = await self._http.create_guild_template(guild_id, payload)
return self.parse_template(data)
async def sync_template(
self, guild_id: Snowflake, template_code: str
) -> "GuildTemplate":
"""|coro| Sync a template to the guild's current state."""
if self._closed:
raise DisagreementException("Client is closed.")
data = await self._http.sync_guild_template(guild_id, template_code)
return self.parse_template(data)
async def delete_template(self, guild_id: Snowflake, template_code: str) -> None:
"""|coro| Delete a guild template."""
if self._closed:
raise DisagreementException("Client is closed.")
await self._http.delete_guild_template(guild_id, template_code)
async def fetch_scheduled_events(
self, guild_id: Snowflake
) -> List["ScheduledEvent"]:

View File

@ -628,6 +628,33 @@ class HTTPClient:
"""Fetches a guild object for a given guild ID."""
return await self.request("GET", f"/guilds/{guild_id}")
async def get_guild_templates(self, guild_id: "Snowflake") -> List[Dict[str, Any]]:
"""Fetches all templates for the given guild."""
return await self.request("GET", f"/guilds/{guild_id}/templates")
async def create_guild_template(
self, guild_id: "Snowflake", payload: Dict[str, Any]
) -> Dict[str, Any]:
"""Creates a guild template."""
return await self.request(
"POST", f"/guilds/{guild_id}/templates", payload=payload
)
async def sync_guild_template(
self, guild_id: "Snowflake", template_code: str
) -> Dict[str, Any]:
"""Syncs a guild template to the guild's current state."""
return await self.request(
"PUT",
f"/guilds/{guild_id}/templates/{template_code}",
)
async def delete_guild_template(
self, guild_id: "Snowflake", template_code: str
) -> None:
"""Deletes a guild template."""
await self.request("DELETE", f"/guilds/{guild_id}/templates/{template_code}")
async def get_guild_scheduled_events(
self, guild_id: "Snowflake"
) -> List[Dict[str, Any]]:

View File

@ -1516,6 +1516,33 @@ class Webhook:
return self._client.parse_message(message_data)
class GuildTemplate:
"""Represents a guild template."""
def __init__(
self, data: Dict[str, Any], client_instance: Optional["Client"] = None
):
self._client = client_instance
self.code: str = data["code"]
self.name: str = data["name"]
self.description: Optional[str] = data.get("description")
self.usage_count: int = data.get("usage_count", 0)
self.creator_id: str = data.get("creator_id", "")
self.creator: Optional[User] = (
User(data["creator"]) if data.get("creator") else None
)
self.created_at: Optional[str] = data.get("created_at")
self.updated_at: Optional[str] = data.get("updated_at")
self.source_guild_id: Optional[str] = data.get("source_guild_id")
self.serialized_source_guild: Dict[str, Any] = data.get(
"serialized_source_guild", {}
)
self.is_dirty: Optional[bool] = data.get("is_dirty")
def __repr__(self) -> str:
return f"<GuildTemplate code='{self.code}' name='{self.name}'>"
# --- Message Components ---

42
tests/test_templates.py Normal file
View File

@ -0,0 +1,42 @@
import pytest
from types import SimpleNamespace
from unittest.mock import AsyncMock
from disagreement.http import HTTPClient
from disagreement.client import Client
from disagreement.models import GuildTemplate
@pytest.mark.asyncio
async def test_get_guild_templates_calls_request():
http = HTTPClient(token="t")
http.request = AsyncMock(return_value=[])
await http.get_guild_templates("1")
http.request.assert_called_once_with("GET", "/guilds/1/templates")
@pytest.mark.asyncio
async def test_client_fetch_templates_returns_models():
http = SimpleNamespace(
get_guild_templates=AsyncMock(
return_value=[
{
"code": "c",
"name": "n",
"usage_count": 0,
"creator_id": "u",
"created_at": "t",
"updated_at": "t",
"source_guild_id": "g",
}
]
)
)
client = Client.__new__(Client)
client._http = http
client._closed = False
templates = await client.fetch_templates("g")
http.get_guild_templates.assert_awaited_once_with("g")
assert isinstance(templates[0], GuildTemplate)