feat: Add advanced message, channel, and thread management
This commit is contained in:
parent
152c0f12be
commit
97505948ee
@ -368,6 +368,20 @@ class HTTPClient:
|
||||
f"/channels/{channel_id}/messages/{message_id}/reactions/{encoded}/@me",
|
||||
)
|
||||
|
||||
async def delete_user_reaction(
|
||||
self,
|
||||
channel_id: "Snowflake",
|
||||
message_id: "Snowflake",
|
||||
emoji: str,
|
||||
user_id: "Snowflake",
|
||||
) -> None:
|
||||
"""Removes another user's reaction from a message."""
|
||||
encoded = quote(emoji)
|
||||
await self.request(
|
||||
"DELETE",
|
||||
f"/channels/{channel_id}/messages/{message_id}/reactions/{encoded}/{user_id}",
|
||||
)
|
||||
|
||||
async def get_reactions(
|
||||
self, channel_id: "Snowflake", message_id: "Snowflake", emoji: str
|
||||
) -> List[Dict[str, Any]]:
|
||||
@ -400,6 +414,27 @@ class HTTPClient:
|
||||
)
|
||||
return messages
|
||||
|
||||
async def get_pinned_messages(
|
||||
self, channel_id: "Snowflake"
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Fetches all pinned messages in a channel."""
|
||||
|
||||
return await self.request("GET", f"/channels/{channel_id}/pins")
|
||||
|
||||
async def pin_message(
|
||||
self, channel_id: "Snowflake", message_id: "Snowflake"
|
||||
) -> None:
|
||||
"""Pins a message in a channel."""
|
||||
|
||||
await self.request("PUT", f"/channels/{channel_id}/pins/{message_id}")
|
||||
|
||||
async def unpin_message(
|
||||
self, channel_id: "Snowflake", message_id: "Snowflake"
|
||||
) -> None:
|
||||
"""Unpins a message from a channel."""
|
||||
|
||||
await self.request("DELETE", f"/channels/{channel_id}/pins/{message_id}")
|
||||
|
||||
async def delete_channel(
|
||||
self, channel_id: str, reason: Optional[str] = None
|
||||
) -> None:
|
||||
@ -420,6 +455,21 @@ class HTTPClient:
|
||||
custom_headers=custom_headers if custom_headers else None,
|
||||
)
|
||||
|
||||
async def edit_channel(
|
||||
self,
|
||||
channel_id: "Snowflake",
|
||||
payload: Dict[str, Any],
|
||||
reason: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""Edits a channel."""
|
||||
headers = {"X-Audit-Log-Reason": reason} if reason else None
|
||||
return await self.request(
|
||||
"PATCH",
|
||||
f"/channels/{channel_id}",
|
||||
payload=payload,
|
||||
custom_headers=headers,
|
||||
)
|
||||
|
||||
async def get_channel(self, channel_id: str) -> Dict[str, Any]:
|
||||
"""Fetches a channel by ID."""
|
||||
return await self.request("GET", f"/channels/{channel_id}")
|
||||
@ -1039,3 +1089,32 @@ class HTTPClient:
|
||||
async def get_voice_regions(self) -> List[Dict[str, Any]]:
|
||||
"""Returns available voice regions."""
|
||||
return await self.request("GET", "/voice/regions")
|
||||
|
||||
async def start_thread_from_message(
|
||||
self,
|
||||
channel_id: "Snowflake",
|
||||
message_id: "Snowflake",
|
||||
payload: Dict[str, Any],
|
||||
) -> Dict[str, Any]:
|
||||
"""Starts a new thread from an existing message."""
|
||||
return await self.request(
|
||||
"POST",
|
||||
f"/channels/{channel_id}/messages/{message_id}/threads",
|
||||
payload=payload,
|
||||
)
|
||||
|
||||
async def start_thread_without_message(
|
||||
self, channel_id: "Snowflake", payload: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
"""Starts a new thread that is not attached to a message."""
|
||||
return await self.request(
|
||||
"POST", f"/channels/{channel_id}/threads", payload=payload
|
||||
)
|
||||
|
||||
async def join_thread(self, channel_id: "Snowflake") -> None:
|
||||
"""Joins the current user to a thread."""
|
||||
await self.request("PUT", f"/channels/{channel_id}/thread-members/@me")
|
||||
|
||||
async def leave_thread(self, channel_id: "Snowflake") -> None:
|
||||
"""Removes the current user from a thread."""
|
||||
await self.request("DELETE", f"/channels/{channel_id}/thread-members/@me")
|
||||
|
@ -105,11 +105,38 @@ class Message:
|
||||
self.attachments: List[Attachment] = [
|
||||
Attachment(a) for a in data.get("attachments", [])
|
||||
]
|
||||
self.pinned: bool = data.get("pinned", False)
|
||||
# Add other fields as needed, e.g., attachments, embeds, reactions, etc.
|
||||
# self.mentions: List[User] = [User(u) for u in data.get("mentions", [])]
|
||||
# self.mention_roles: List[str] = data.get("mention_roles", [])
|
||||
# self.mention_everyone: bool = data.get("mention_everyone", False)
|
||||
|
||||
async def pin(self) -> None:
|
||||
"""|coro|
|
||||
|
||||
Pins this message to its channel.
|
||||
|
||||
Raises
|
||||
------
|
||||
HTTPException
|
||||
Pinning the message failed.
|
||||
"""
|
||||
await self._client._http.pin_message(self.channel_id, self.id)
|
||||
self.pinned = True
|
||||
|
||||
async def unpin(self) -> None:
|
||||
"""|coro|
|
||||
|
||||
Unpins this message from its channel.
|
||||
|
||||
Raises
|
||||
------
|
||||
HTTPException
|
||||
Unpinning the message failed.
|
||||
"""
|
||||
await self._client._http.unpin_message(self.channel_id, self.id)
|
||||
self.pinned = False
|
||||
|
||||
async def reply(
|
||||
self,
|
||||
content: Optional[str] = None,
|
||||
@ -210,10 +237,17 @@ class Message:
|
||||
|
||||
await self._client.add_reaction(self.channel_id, self.id, emoji)
|
||||
|
||||
async def remove_reaction(self, emoji: str) -> None:
|
||||
"""|coro| Remove the bot's reaction from this message."""
|
||||
|
||||
await self._client.remove_reaction(self.channel_id, self.id, emoji)
|
||||
async def remove_reaction(self, emoji: str, member: Optional[User] = None) -> None:
|
||||
"""|coro|
|
||||
Removes a reaction from this message.
|
||||
If no ``member`` is provided, removes the bot's own reaction.
|
||||
"""
|
||||
if member:
|
||||
await self._client._http.delete_user_reaction(
|
||||
self.channel_id, self.id, emoji, member.id
|
||||
)
|
||||
else:
|
||||
await self._client.remove_reaction(self.channel_id, self.id, emoji)
|
||||
|
||||
async def clear_reactions(self) -> None:
|
||||
"""|coro| Remove all reactions from this message."""
|
||||
@ -239,6 +273,125 @@ class Message:
|
||||
def __repr__(self) -> str:
|
||||
return f"<Message id='{self.id}' channel_id='{self.channel_id}' author='{self.author!r}'>"
|
||||
|
||||
async def create_thread(
|
||||
self,
|
||||
name: str,
|
||||
*,
|
||||
auto_archive_duration: Optional[int] = None,
|
||||
rate_limit_per_user: Optional[int] = None,
|
||||
reason: Optional[str] = None,
|
||||
) -> "Thread":
|
||||
"""|coro|
|
||||
|
||||
Creates a new thread from this message.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
The name of the thread.
|
||||
auto_archive_duration: Optional[int]
|
||||
The duration in minutes to automatically archive the thread after recent activity.
|
||||
Can be one of 60, 1440, 4320, 10080.
|
||||
rate_limit_per_user: Optional[int]
|
||||
The number of seconds a user has to wait before sending another message.
|
||||
reason: Optional[str]
|
||||
The reason for creating the thread.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Thread
|
||||
The created thread.
|
||||
"""
|
||||
payload: Dict[str, Any] = {"name": name}
|
||||
if auto_archive_duration is not None:
|
||||
payload["auto_archive_duration"] = auto_archive_duration
|
||||
if rate_limit_per_user is not None:
|
||||
payload["rate_limit_per_user"] = rate_limit_per_user
|
||||
|
||||
data = await self._client._http.start_thread_from_message(
|
||||
self.channel_id, self.id, payload
|
||||
)
|
||||
return cast("Thread", self._client.parse_channel(data))
|
||||
|
||||
|
||||
class PartialMessage:
|
||||
"""Represents a partial message, identified by its ID and channel.
|
||||
|
||||
This model is used to perform actions on a message without having the
|
||||
full message object in the cache.
|
||||
|
||||
Attributes:
|
||||
id (str): The message's unique ID.
|
||||
channel (TextChannel): The text channel this message belongs to.
|
||||
"""
|
||||
|
||||
def __init__(self, *, id: str, channel: "TextChannel"):
|
||||
self.id = id
|
||||
self.channel = channel
|
||||
self._client = channel._client
|
||||
|
||||
async def fetch(self) -> "Message":
|
||||
"""|coro|
|
||||
|
||||
Fetches the full message data from Discord.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Message
|
||||
The complete message object.
|
||||
"""
|
||||
data = await self._client._http.get_message(self.channel.id, self.id)
|
||||
return self._client.parse_message(data)
|
||||
|
||||
async def delete(self, *, delay: Optional[float] = None) -> None:
|
||||
"""|coro|
|
||||
|
||||
Deletes this message.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
delay: Optional[float]
|
||||
If provided, wait this many seconds before deleting.
|
||||
"""
|
||||
if delay is not None:
|
||||
await asyncio.sleep(delay)
|
||||
await self._client._http.delete_message(self.channel.id, self.id)
|
||||
|
||||
async def pin(self) -> None:
|
||||
"""|coro|
|
||||
|
||||
Pins this message to its channel.
|
||||
"""
|
||||
await self._client._http.pin_message(self.channel.id, self.id)
|
||||
|
||||
async def unpin(self) -> None:
|
||||
"""|coro|
|
||||
|
||||
Unpins this message from its channel.
|
||||
"""
|
||||
await self._client._http.unpin_message(self.channel.id, self.id)
|
||||
|
||||
async def add_reaction(self, emoji: str) -> None:
|
||||
"""|coro|
|
||||
|
||||
Adds a reaction to this message.
|
||||
"""
|
||||
await self._client._http.create_reaction(self.channel.id, self.id, emoji)
|
||||
|
||||
async def remove_reaction(self, emoji: str, member: Optional[User] = None) -> None:
|
||||
"""|coro|
|
||||
|
||||
Removes a reaction from this message.
|
||||
|
||||
If no ``member`` is provided, removes the bot's own reaction.
|
||||
"""
|
||||
if member:
|
||||
await self._client._http.delete_user_reaction(
|
||||
self.channel.id, self.id, emoji, member.id
|
||||
)
|
||||
else:
|
||||
await self._client._http.delete_reaction(self.channel.id, self.id, emoji)
|
||||
|
||||
|
||||
class EmbedFooter:
|
||||
"""Represents an embed footer."""
|
||||
@ -1305,6 +1458,44 @@ class Thread(TextChannel): # Threads are a specialized TextChannel
|
||||
f"<Thread id='{self.id}' name='{self.name}' parent_id='{self.parent_id}'>"
|
||||
)
|
||||
|
||||
async def join(self) -> None:
|
||||
"""|coro|
|
||||
|
||||
Joins this thread.
|
||||
"""
|
||||
await self._client._http.join_thread(self.id)
|
||||
|
||||
async def leave(self) -> None:
|
||||
"""|coro|
|
||||
|
||||
Leaves this thread.
|
||||
"""
|
||||
await self._client._http.leave_thread(self.id)
|
||||
|
||||
async def archive(self, locked: bool = False, *, reason: Optional[str] = None) -> "Thread":
|
||||
"""|coro|
|
||||
|
||||
Archives this thread.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
locked: bool
|
||||
Whether to lock the thread.
|
||||
reason: Optional[str]
|
||||
The reason for archiving the thread.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Thread
|
||||
The updated thread.
|
||||
"""
|
||||
payload = {
|
||||
"archived": True,
|
||||
"locked": locked,
|
||||
}
|
||||
data = await self._client._http.edit_channel(self.id, payload, reason=reason)
|
||||
return cast("Thread", self._client.parse_channel(data))
|
||||
|
||||
|
||||
class DMChannel(Channel):
|
||||
"""Represents a Direct Message channel."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user