diff options
| author | Zeyla Hellyer <[email protected]> | 2017-03-25 16:58:14 -0700 |
|---|---|---|
| committer | Zeyla Hellyer <[email protected]> | 2017-03-25 16:58:14 -0700 |
| commit | 3cd0e40e2b30a0452fd9ea5d22c65afbce321fc6 (patch) | |
| tree | 0aa3308e604d9d6288977bd8eddeccea27a591c1 /src | |
| parent | Rework the models directory (diff) | |
| download | serenity-3cd0e40e2b30a0452fd9ea5d22c65afbce321fc6.tar.xz serenity-3cd0e40e2b30a0452fd9ea5d22c65afbce321fc6.zip | |
Update search params
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/rest/mod.rs | 14 | ||||
| -rw-r--r-- | src/utils/builder/mod.rs | 2 | ||||
| -rw-r--r-- | src/utils/builder/search.rs | 334 |
3 files changed, 139 insertions, 211 deletions
diff --git a/src/client/rest/mod.rs b/src/client/rest/mod.rs index a9dc88c..c341bf2 100644 --- a/src/client/rest/mod.rs +++ b/src/client/rest/mod.rs @@ -1386,15 +1386,12 @@ pub fn remove_group_recipient(group_id: u64, user_id: u64) -> Result<()> { /// /// [`Channel`]: ../../model/enum.Channel.html /// [`Message`]: ../../model/struct.Message.html -pub fn search_channel_messages(channel_id: u64, map: BTreeMap<&str, String>) +pub fn search_channel_messages(channel_id: u64, map: BTreeMap<&str, Value>) -> Result<SearchResult> { let mut uri = format!("/channels/{}/messages/search?", channel_id); for (k, v) in map { - uri.push('&'); - uri.push_str(k); - uri.push('='); - uri.push_str(&v); + let _ = write!(uri, "&{}={}", k, v); } let response = request!(Route::ChannelsIdMessagesSearch(channel_id), @@ -1420,15 +1417,12 @@ pub fn search_channel_messages(channel_id: u64, map: BTreeMap<&str, String>) /// [`GuildChannel`]: ../../model/struct.GuildChannel.html pub fn search_guild_messages(guild_id: u64, channel_ids: &[u64], - map: BTreeMap<&str, String>) + map: BTreeMap<&str, Value>) -> Result<SearchResult> { let mut uri = format!("/guilds/{}/messages/search?", guild_id); for (k, v) in map { - uri.push('&'); - uri.push_str(k); - uri.push('='); - uri.push_str(&v); + let _ = write!(uri, "&{}={}", k, v); } for channel_id in channel_ids { diff --git a/src/utils/builder/mod.rs b/src/utils/builder/mod.rs index 9ded8b8..10a20d9 100644 --- a/src/utils/builder/mod.rs +++ b/src/utils/builder/mod.rs @@ -32,4 +32,4 @@ pub use self::edit_profile::EditProfile; pub use self::edit_role::EditRole; pub use self::execute_webhook::ExecuteWebhook; pub use self::get_messages::GetMessages; -pub use self::search::{Search, SortingMode, SortingOrder}; +pub use self::search::{Search, Has}; diff --git a/src/utils/builder/search.rs b/src/utils/builder/search.rs index 904c580..5a4d4a9 100644 --- a/src/utils/builder/search.rs +++ b/src/utils/builder/search.rs @@ -1,71 +1,52 @@ +use serde_json::Value; use std::collections::BTreeMap; use ::model::{MessageId, UserId}; -/// An indicator of the type of sorting mode to use when searching for -/// [`Message`]s via the [`Search`] builder. +/// An indicator for filtering [`Message`]s that have a certain item or quality. /// -/// [`Message`]: ../../model/struct.Message.html -/// [`Search`]: struct.Search.html -pub enum SortingMode { - /// Search by messages' relevance to parameters. - Relevance, - /// Search by messages' timestamp, where results will match according to - /// parameters. This is used in conjunction in the [`Search::sort_order`] - /// method, and is used in conjunction with [`SortingOrder`]. - /// - /// [`Search::sort_order`]: struct.Search.html#method.sort_order - /// [`SortingOrder`]: enum.SortingOrder.html - Timestamp, -} - -impl SortingMode { - /// Retrieves the name of the sorting mode. This is equivalent to a - /// lowercase string version of each variant. - pub fn name(&self) -> &str { - match *self { - SortingMode::Relevance => "relevance", - SortingMode::Timestamp => "timestamp", - } - } -} - -/// An indicator of how to sort results when searching for [`Message`]s via the -/// [`Search`] builder. +/// Used with [`Search::has`]. /// /// [`Message`]: ../../model/struct.Message.html -/// [`Search`]: struct.Search.html -pub enum SortingOrder { - /// Search message results in ascending order. - /// - /// In the case of [`SortingMode::Relevance`], this will search from the - /// least relevant to the most relevant. - /// - /// In the case of [`SortingMode::Timestamp`], this will indicate to search - /// from the least recent to the most recent. +/// [`Search::has`]: struct.Search.html#method.has +pub enum Has { + /// Find messages that have an [`Embed`]. /// - /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance - /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp - Ascending, - /// Search message results in descending order. + /// [`Embed`]: ../../model/struct.Embed.html + Embed, + /// Find messages that have an [`Attachment`]. /// - /// In the case of [`SortingMode::Relevance`], this will search from the - /// most relevant to least relevant. + /// [`Attachment`]: ../../model/struct.Attachment.html + File, + /// Find messages that have an embed with an image. + Image, + /// Find messages with a link of any kind. + Link, + /// Find messages that have an [`Embed`] with a sound [`provider`]. /// - /// In the case of [`SortingMode::Timestamp`], this will search from the - /// most recent to least recent. + /// [`Embed`]: ../../model/struct.Embed.html + /// [`provider`]: ../../model/struct.Embed.html#structfield.provider + Sound, + /// Find messages that have an [`Embed`] with a `video` + /// [type][`Embed::kind`]. /// - /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance - /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp - Descending, + /// [`Embed`]: ../../model/struct.Embed.html + /// [`Embed::kind`]: ../../model/struct.Embed.html#structfield.kind + Video, } -impl SortingOrder { - /// Retrieves the name of the sorting order. This is equivalent to a - /// lowercase string version of each variant. +impl Has { + /// Returns the "name" of the variant. + #[doc(hidden)] pub fn name(&self) -> &str { + use self::Has::*; + match *self { - SortingOrder::Ascending => "asc", - SortingOrder::Descending => "desc", + Embed => "embed", + File => "file", + Image => "image", + Link => "link", + Sound => "sound", + Video => "video", } } } @@ -73,32 +54,28 @@ impl SortingOrder { /// A builder used to query a [`Channel`] or [`Guild`] for its [`Message`]s, /// specifying certain parameters to narrow down the returned messages. /// -/// Many methods are provided to narrow down the results, such as [`sort_by`] - -/// which is used with the [`SortingMode`] enum to sort the results - or -/// [`limit`], which can be used in conjunction with [`offset`] to paginate -/// results. +/// Many methods are provided to narrow down the results, such as [`limit`], +/// which can be used in conjunction with [`offset`] to paginate results. /// /// # Examples /// /// Provided are multiple in-depth examples for searching through different -/// means. Also see [example 08] for a fully runnable bot. +/// means. Also see [example 08] for a fully runnable selfbot. /// /// ### Searching a Channel /// -/// Search for messages via [`Context::search_channel`] with the content -/// `"rust"`, which have no embed, no attachment, searching by relevance in -/// ascending order, and limiting to 5 results: +/// Search for messages via [`Channel::search`] with the content `"rust"`, which +/// have an embed, have a video, and limiting to 5 results: /// /// ```rust,ignore -/// // assuming a `channel_id` has been bound +/// use serenity::utils::builder::Has; +/// +/// // assuming a `channel` has been bound /// -/// let res = channel_id.search(|s| s +/// let search = channel.search(|s| s /// .content("rust") -/// .has_embed(false) -/// .has_attachment(false) -/// .limit(5) -/// .sort_by(SortingMode::Relevance) -/// .sort_order(SortingOrder::Ascending)); +/// .has(vec![Has::Embed, Has::Video]) +/// .limit(5)); /// ``` /// /// ### Searching a Guild's Channels @@ -111,7 +88,6 @@ impl SortingOrder { /// ```rust,ignore /// use serenity::client::{Client, Context}; /// use serenity::model::Message; -/// use serenity::utils::builder::{SortingMode, SortingOrder}; /// use std::env; /// /// let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap()); @@ -120,16 +96,16 @@ impl SortingOrder { /// .configure(|c| c.prefix("~").on_mention(true)) /// .on("search", search)); /// -/// command!(search(context, message, args) { +/// command!(search(ctx, msg, args) { /// let query = args.join(" "); /// /// if query.is_empty() { -/// let _ = message.channel_id.say("You must provide a query"); +/// let _ = msg.channel_id.say("You must provide a query"); /// /// return Ok(()); /// } /// -/// let guild = message.guild().unwrap(); +/// let guild = msg.guild().unwrap(); /// /// let channel_ids = guild /// .channels @@ -143,35 +119,23 @@ impl SortingOrder { /// .context_size(0) /// .has_attachment(true) /// .has_embed(true) -/// .max_id(message.id.0 - 1) -/// .sort_by(SortingMode::Timestamp) -/// .sort_order(SortingOrder::Descending)); +/// .max_id(msg.id.0 - 1)) +/// .unwrap(); /// -/// let mut messages = match search { -/// Ok(messages) => messages, -/// Err(why) => { -/// println!("Error performing search '{}': {:?}", query, why); -/// -/// let _ = message.channel_id.say("Error occurred while searching"); -/// -/// return Ok(()); -/// }, -/// }; -/// -/// let _ = message.channel_id.send_message(|m| m +/// let _ = msg.channel_id.send_message(|m| m /// .content(&format!("Found {} total results", messages.total)) /// .embed(|mut e| { /// for (i, messages) in messages.results.iter_mut().enumerate() { -/// let mut message = match messages.get_mut(i) { -/// Some(message) => message, +/// let mut found = match messages.get_mut(i) { +/// Some(found) => found, /// None => break, /// }; /// -/// message.content.truncate(1000); +/// found.content.truncate(1000); /// /// e = e.field(|f| f /// .name(&format!("Result {}", i)) -/// .value(&message.content)); +/// .value(&found.content)); /// } /// /// e @@ -183,110 +147,81 @@ impl SortingOrder { /// [`Context::search_channel`]: ../../client/struct.Context.html#method.search_channel /// [`Guild`]: ../../model/struct.Guild.html /// [`Message`]: ../../model/struct.Message.html -/// [`SortingMode`]: enum.SortingMode.html /// [`limit`]: #method.limit /// [`offset`]: #method.offset -/// [`sort_by`]: #method.sort_by /// [example 08]: https://github.com/zeyla/serenity/tree/master/examples/08_search -pub struct Search(pub BTreeMap<&'static str, String>); +pub struct Search(pub BTreeMap<&'static str, Value>); impl Search { - /// Sets the list of attachment extensions to search by. - /// - /// When providing a vector of extensions, do _not_ include the period (`.`) - /// character as part of the search. - /// - /// This is sent to Discord as a comma-separated value list of extension - /// names. - pub fn attachment_extensions(mut self, attachment_extensions: &[&str]) -> Self { - let list = attachment_extensions.join(" "); - - self.0.insert("attachment_extensions", list); - - self - } - - /// Sets the filename of the attachments to search for. - pub fn attachment_filename(mut self, attachment_filename: &str) -> Self { - self.0.insert("attachment_filename", attachment_filename.to_owned()); - - self - } - - /// Sets the Id of the author of [`Message`]s to search for. This excludes - /// all messages by other [`User`]s. + /// Filters [`Message`]s by the the Id of the author. /// /// [`Message`]: ../../model/struct.Message.html - /// [`User`]: ../../model/struct.User.html pub fn author_id<U: Into<UserId>>(mut self, author_id: U) -> Self { - self.0.insert("author_id", author_id.into().0.to_string()); + self.0.insert("author_id", Value::U64(author_id.into().0)); self } - /// Sets the content of the [`Message`] to search for. This is a fuzzy - /// search, and can partially match the given query content. + /// Filtes [`Message`] by content. This is a fuzzy search, and can partially + /// match the given query content. /// /// [`Message`]: ../../model/struct.Message.html - pub fn content(mut self, content: &str) -> Self { - self.0.insert("content", content.to_owned()); + pub fn content<S: Into<String>>(mut self, content: S) -> Self { + self.0.insert("content", Value::String(content.into())); self } - /// Sets the amount of "context" [`Message`]s to provide, at maximum. This - /// is the number of messages to provide around each side + /// Sets the amount of "contextual" [`Message`]s to provide, at maximum. + /// This is the number of messages to provide around each side /// (ascending+descending) of the "hit" (aka found) message. /// + /// The number of returned contextual messages can be lower if there are + /// fewer messages in the order. + /// /// The default value is `2`. The minimum value is `0`. The maximum value is /// `2`. /// /// [`Message`]: ../../model/struct.Message.html - pub fn context_size(mut self, context_size: u8) -> Self { - self.0.insert("context_size", context_size.to_string()); + pub fn context_size(mut self, mut context_size: u8) -> Self { + if context_size > 2 { + context_size = 2; + } + + self.0.insert("context_size", Value::U64(context_size as u64)); self } - /// Sets the embed providers to search by. + /// Filter [`Message`]s by whether they have a certain item. /// - /// This is a list of the providers' names. + /// You can pass either one or more [`Has`] variants. /// - /// This is sent to Discord as a comma-separated value list of provider - /// names. - pub fn embed_providers(mut self, embed_providers: &[&str]) -> Self { - self.0.insert("embed_providers", embed_providers.join(" ")); - - self - } - - /// Sets the type of [`Embed`]s to search by. + /// # Examples /// - /// An example of an [embed type][`Embed::kind`] is `"rich"`. + /// Passing a single variant: /// - /// [`Embed`]: ../../model/struct.Embed.html - /// [`Embed::kind`]: ../../model/struct.Embed.html#structfield.kind - pub fn embed_types(mut self, embed_types: &[&str]) -> Self { - self.0.insert("embed_types", embed_types.join(" ")); - - self - } - - /// Sets whether to search for methods that do - or do not - have an - /// attachment. + /// ```rust,no_run + /// use serenity::model::ChannelId; + /// use serenity::utils::builder::Has; /// - /// Do not specify to search for both. - pub fn has_attachment(mut self, has_attachment: bool) -> Self { - self.0.insert("has_attachment", has_attachment.to_string()); - - self - } - - /// Sets whether to search for methods that do - or do not - have an embed. + /// let _ = ChannelId(7).search(|s| s.has(vec![Has::Embed])); + /// ``` /// - /// Do not specify to search for both. - pub fn has_embed(mut self, has_embed: bool) -> Self { - self.0.insert("has_embed", has_embed.to_string()); + /// Passing multiple: + /// + /// ```rust,no_run + /// use serenity::model::ChannelId; + /// use serenity::utils::builder::Has; + /// + /// let _ = ChannelId(7).search(|s| s.has(vec![Has::Embed, Has::Sound])); + /// ``` + /// + /// [`Has`]: enum.Has.html + /// [`Message`]: ../../model/struct.Message.html + pub fn has(mut self, has: Vec<Has>) -> Self { + let names = has.into_iter().map(|h| Value::String(h.name().to_owned())).collect(); + self.0.insert("has", Value::Array(names)); self } @@ -298,7 +233,7 @@ impl Search { /// /// [`offset`]: #method.offset pub fn limit(mut self, limit: u8) -> Self { - self.0.insert("limit", limit.to_string()); + self.0.insert("limit", Value::U64(limit as u64)); self } @@ -308,7 +243,39 @@ impl Search { /// /// [`Message`]: ../../model/struct.Message.html pub fn max_id<M: Into<MessageId>>(mut self, message_id: M) -> Self { - self.0.insert("max_id", message_id.into().0.to_string()); + self.0.insert("max_id", Value::U64(message_id.into().0)); + + self + } + + /// Filter [`Message`]s by whether they mention one or more specific + /// [`User`]s. + /// + /// This is an OR statement. + /// + /// # Examples + /// + /// Search for only one mention: + /// + /// ```rust,no_run + /// use serenity::model::{ChannelId, UserId}; + /// + /// let _ = ChannelId(7).search(|s| s.mentions(vec![UserId(8)])); + /// ``` + /// + /// Search for two mentions: + /// + /// ```rust,no_run + /// use serenity::model::{ChannelId, UserId}; + /// + /// let _ = ChannelId(7).search(|s| s.mentions(vec![UserId(8), UserId(9)])); + /// ``` + /// + /// [`Message`]: ../../model/struct.Message.html + /// [`User`]: ../../model/struct.User.html + pub fn mentions(mut self, mentions: Vec<UserId>) -> Self { + let ids = mentions.into_iter().map(|m| Value::U64(m.0)).collect(); + self.0.insert("mentions", Value::Array(ids)); self } @@ -318,7 +285,7 @@ impl Search { /// /// [`Message`]: ../../model/struct.Message.html pub fn min_id<M: Into<MessageId>>(mut self, message_id: M) -> Self { - self.0.insert("min_id", message_id.into().0.to_string()); + self.0.insert("min_id", Value::U64(message_id.into().0)); self } @@ -331,29 +298,7 @@ impl Search { /// [`Message`]: ../../model/struct.Message.html /// [`limit`]: #method.limit pub fn offset(mut self, offset: u16) -> Self { - self.0.insert("offset", offset.to_string()); - - self - } - - /// The sorting mode to use. - /// - /// Refer to [`SortingMode`] for more information. - /// - /// [`SortingMode`]: enum.SortingMode.html - pub fn sort_by(mut self, sorting_mode: SortingMode) -> Self { - self.0.insert("sort_by", sorting_mode.name().to_string()); - - self - } - - /// The order to sort results by. - /// - /// Refer to the documentation for [`SortingOrder`] for more information. - /// - /// [`SortingOrder`]: enum.SortingOrder.html - pub fn sort_order(mut self, sorting_order: SortingOrder) -> Self { - self.0.insert("sort_order", sorting_order.name().to_string()); + self.0.insert("offset", Value::U64(offset as u64)); self } @@ -367,18 +312,7 @@ impl Default for Search { /// The library does not provide defaults differently than what Discord /// itself defaults to. /// - /// This list of defaults is: - /// - /// - [`context_size`]: 2 - /// - [`limit`]: 25 - /// - [`offset`]: 0 - /// - [`sort_by`]: [`SortingMode::Timestamp`] - /// - /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp - /// [`context_size`]: #method.context_size - /// [`limit`]: #method.limit - /// [`offset`]: #method.offset - /// [`sort_by`]: #method.sort_by + /// [`Message`]: ../../model/struct.Message.html fn default() -> Search { Search(BTreeMap::default()) } |