-
-
Notifications
You must be signed in to change notification settings - Fork 494
feat: Guild Message Search #3160
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
base: master
Are you sure you want to change the base?
Changes from 24 commits
aad1630
4d7419c
fa3e0ec
4d671fe
7c755b8
e8d340d
93f6dbd
7ad0198
32b65bc
0f5d110
4c22f00
875b1be
f901164
93bb7fe
db40d7f
05d5ece
7188ef9
355a7d8
0cb6f67
05aa66b
58438ea
b730d65
ceb227a
0405f8b
9dcba5a
81f6b82
6ec6936
e342ca1
9f24761
cd6fe35
25347b5
272ede6
7819675
e1492c5
33ead34
69fd2e8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,6 +85,9 @@ | |
| "SubscriptionStatus", | ||
| "SeparatorSpacingSize", | ||
| "SelectDefaultValueType", | ||
| "SearchEmbedType", | ||
| "SearchSortMode", | ||
| "SearchSortOrder", | ||
| "ApplicationEventWebhookStatus", | ||
| "InviteTargetUsersJobStatusCode", | ||
| ) | ||
|
|
@@ -1136,6 +1139,39 @@ class SelectDefaultValueType(Enum): | |
| user = "user" | ||
|
|
||
|
|
||
| class SearchEmbedType(Enum): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to be documented |
||
| """The types of media embedded on a message.""" | ||
|
|
||
| image = "image" | ||
| video = "video" | ||
| gif = "gif" | ||
| sound = "sound" | ||
| article = "article" | ||
|
|
||
| def __str__(self): | ||
| return self.value | ||
|
|
||
|
|
||
| class SearchSortMode(Enum): | ||
| """The sorting algorithm used for message searches.""" | ||
|
|
||
| timestamp = "timestamp" | ||
| relevance = "relevance" | ||
|
|
||
| def __str__(self): | ||
| return self.value | ||
|
|
||
|
|
||
| class SearchSortOrder(Enum): | ||
| """The order to sort message searches.""" | ||
|
|
||
| asc = "asc" | ||
| desc = "desc" | ||
|
|
||
| def __str__(self): | ||
| return self.value | ||
|
|
||
|
|
||
| class RoleType(IntEnum): | ||
| """Represents the type of role. | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -63,6 +63,9 @@ | |
| OnboardingMode, | ||
| ScheduledEventLocationType, | ||
| ScheduledEventPrivacyLevel, | ||
| SearchEmbedType, | ||
| SearchSortMode, | ||
| SearchSortOrder, | ||
| SortOrder, | ||
| VerificationLevel, | ||
| VideoQualityMode, | ||
|
|
@@ -80,6 +83,7 @@ | |
| BanIterator, | ||
| EntitlementIterator, | ||
| MemberIterator, | ||
| MessageSearchIterator, | ||
| ) | ||
| from .member import Member, VoiceState | ||
| from .mixins import Hashable | ||
|
|
@@ -97,7 +101,7 @@ | |
| from .welcome_screen import WelcomeScreen, WelcomeScreenChannel | ||
| from .widget import Widget | ||
|
|
||
| __all__ = ("BanEntry", "Guild", "GuildRoleCounts") | ||
| __all__ = ("BanEntry", "Guild", "GuildRoleCounts", "SearchHas", "SearchAuthors") | ||
|
|
||
| MISSING = utils.MISSING | ||
|
|
||
|
|
@@ -151,6 +155,64 @@ class _GuildLimit(NamedTuple): | |
| filesize: int | ||
|
|
||
|
|
||
| class Parsable: | ||
| # idk this kinda sucks lmao | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😭
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. gave this a bit more thought, the intent is to have the same syntax as
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be better if it didn't contain "flags" as that might be confusing since flags are an actual thing in the API. |
||
| def __init__(self, **values): | ||
| self._values = values | ||
| for k, v in values.items(): | ||
| setattr(self, k, v) | ||
|
|
||
| def parse(self) -> list[str]: | ||
| true, false = [], [] | ||
| for k, v in self._values.items(): | ||
| if v: | ||
| true.append(k) | ||
| elif v is False: | ||
| false.append(f"-{k}") | ||
| return true + false | ||
|
|
||
| def __repr__(self) -> str: | ||
| return f"<{self.__class__.__name__} resolved={self.parse()!r}>" | ||
|
|
||
|
|
||
| class SearchAuthors(Parsable): | ||
| def __init__( | ||
| self, | ||
| *, | ||
| user: bool | None = None, | ||
| bot: bool | None = None, | ||
| webhook: bool | None = None, | ||
| ): | ||
| super().__init__(user=user, bot=bot, webhook=webhook) | ||
|
|
||
|
|
||
| class SearchHas(Parsable): | ||
| def __init__( | ||
| self, | ||
| *, | ||
| image: bool | None = None, | ||
| sound: bool | None = None, | ||
| video: bool | None = None, | ||
| file: bool | None = None, | ||
| sticker: bool | None = None, | ||
| embed: bool | None = None, | ||
| link: bool | None = None, | ||
| poll: bool | None = None, | ||
| snapshot: bool | None = None, | ||
| ): | ||
| super().__init__( | ||
| image=image, | ||
| sound=sound, | ||
| video=video, | ||
| file=file, | ||
| sticker=sticker, | ||
| embed=embed, | ||
| link=link, | ||
| poll=poll, | ||
| snapshot=snapshot, | ||
| ) | ||
|
|
||
|
|
||
| class GuildRoleCounts(dict[int, int]): | ||
| """A dictionary subclass that maps role IDs to their member counts. | ||
|
|
||
|
|
@@ -4723,3 +4785,157 @@ def get_sound(self, sound_id: int) -> SoundboardSound | None: | |
| The sound or ``None`` if not found. | ||
| """ | ||
| return self._sounds.get(sound_id) | ||
|
|
||
| def search( | ||
| self, | ||
| *, | ||
| limit: int | None = 25, | ||
| offset: int | None = None, | ||
| after: Snowflake | None = None, | ||
| before: Snowflake | None = None, | ||
| slop: int | None = 2, | ||
| content: str | None = None, | ||
| channels: list[Snowflake] | None = None, | ||
| author_types: SearchAuthors | None = None, | ||
| authors: list[Snowflake] | None = None, | ||
| mentions: list[Snowflake] | None = None, | ||
| mentions_roles: list[Snowflake] | None = None, | ||
| mention_everyone: bool | None = None, | ||
| replied_to_users: list[Snowflake] | None = None, | ||
| replied_to_messages: list[Snowflake] | None = None, | ||
| pinned: bool | None = None, | ||
| has: SearchHas | None = None, | ||
| embed_types: list[SearchEmbedType] | None = None, | ||
| embed_providers: list[str] | None = None, | ||
| link_hostnames: list[str] | None = None, | ||
| attachment_filenames: list[str] | None = None, | ||
| attachment_extensions: list[str] | None = None, | ||
| sort_by: SearchSortMode | None = None, | ||
| sort_order: SearchSortOrder | None = SearchSortOrder.desc, | ||
| include_nsfw: bool | None = False, | ||
| ) -> list[Message]: | ||
|
NeloBlivion marked this conversation as resolved.
Outdated
|
||
| """etc...""" | ||
|
|
||
| params = {} | ||
|
|
||
| if limit: | ||
| if limit <= 0: | ||
| raise ValueError("limit must be above 1") | ||
| params["limit"] = limit if limit <= 25 else limit | ||
|
|
||
| if offset is not None: | ||
| if offset > 9975 or offset < 0: | ||
| raise ValueError("offset must be between 0 and 9975") | ||
| params["offset"] = offset | ||
|
|
||
| if after: | ||
| params["min_id"] = after.id | ||
|
|
||
| if before: | ||
| params["max_id"] = before.id | ||
|
|
||
| if slop is not None: | ||
| if slop > 100 or slop < 0: | ||
| raise ValueError("slop must be between 0 and 100") | ||
| params["slop"] = int(slop) | ||
|
|
||
| if content: | ||
| if len(content) > 1024: | ||
| raise ValueError("content must be under 1024 characters") | ||
| params["content"] = content | ||
|
|
||
| if channels: | ||
| if len(channels) > 500: | ||
| raise ValueError("can only specify up to 500 channels") | ||
| params["channel_id"] = [c.id for c in channels] | ||
|
|
||
| if author_types: | ||
| params["author_type"] = author_types.parse() | ||
|
|
||
| if authors: | ||
| if len(authors) > 100: | ||
| raise ValueError("can only specify up to 100 authors") | ||
| params["author_id"] = [a.id for a in authors] | ||
|
|
||
| if mentions: | ||
| if len(mentions) > 100: | ||
| raise ValueError("can only specify up to 100 mentions") | ||
| params["mentions"] = [m.id for m in mentions] | ||
|
|
||
| if mentions_roles: | ||
| if len(mentions_roles) > 100: | ||
| raise ValueError("can only specify up to 100 mentions_roles") | ||
| params["mentions_role_id"] = [m.id for m in mentions_roles] | ||
|
|
||
| if mention_everyone is not None: | ||
| params["mention_everyone"] = mention_everyone | ||
|
|
||
| if replied_to_users: | ||
| if len(replied_to_users) > 100: | ||
| raise ValueError("can only specify up to 100 replied_to_users") | ||
| params["replied_to_user_id"] = [u.id for u in replied_to_users] | ||
|
|
||
| if replied_to_messages: | ||
| if len(replied_to_messages) > 100: | ||
| raise ValueError("can only specify up to 100 replied_to_messages") | ||
| params["replied_to_message_id"] = [m.id for u in replied_to_messages] | ||
|
|
||
| if pinned is not None: | ||
| params["pinned"] = pinned | ||
|
|
||
| if has: | ||
| params["has"] = has.parse() | ||
|
|
||
| if embed_types: | ||
| params["embed_type"] = [str(t) for t in embed_types] | ||
|
|
||
| if embed_providers: | ||
| if len(embed_providers) > 100: | ||
| raise ValueError("can only specify up to 100 embed_providers") | ||
| for e in embed_providers: | ||
| if len(e) > 256: | ||
| raise ValueError( | ||
| f"embed_provider {e!r} must be up to 256 characters." | ||
| ) | ||
| params["embed_provider"] = embed_providers | ||
|
|
||
| if link_hostnames: | ||
| if len(link_hostnames) > 100: | ||
| raise ValueError("can only specify up to 100 link_hostnames") | ||
| for l in link_hostnames: | ||
| if len(l) > 256: | ||
| raise ValueError( | ||
| f"link_hostname {l!r} must be up to 256 characters." | ||
| ) | ||
| params["link_hostname"] = link_hostnames | ||
|
|
||
| if attachment_filenames: | ||
| if len(attachment_filenames) > 100: | ||
| raise ValueError("can only specify up to 100 attachment_filenames") | ||
| for a in attachment_filenames: | ||
| if len(a) > 1024: | ||
| raise ValueError( | ||
| f"attachment_filename {a!r} must be up to 1024 characters." | ||
| ) | ||
| params["attachment_filename"] = attachment_filenames | ||
|
|
||
| if attachment_extensions: | ||
| if len(attachment_extensions) > 100: | ||
| raise ValueError("can only specify up to 100 attachment_extensions") | ||
| for a in attachment_extensions: | ||
| if len(a) > 256: | ||
| raise ValueError( | ||
| f"attachment_extension {a!r} must be up to 256 characters." | ||
| ) | ||
| params["attachment_extension"] = attachment_extensions | ||
|
|
||
| if sort_by: | ||
| params["sort_by"] = str(sort_by) | ||
|
|
||
| if sort_order: | ||
| params["sort_order"] = str(sort_order) | ||
|
|
||
| if include_nsfw is not None: | ||
| params["include_nsfw"] = include_nsfw | ||
|
|
||
| return MessageSearchIterator(self, limit, params) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to type this