aboutsummaryrefslogtreecommitdiff
path: root/src/model/guild
diff options
context:
space:
mode:
authoracdenisSK <[email protected]>2017-10-14 22:41:25 +0200
committeracdenisSK <[email protected]>2017-10-14 22:41:25 +0200
commitcae014758a1d1e926a71679f02e32601c57f8d52 (patch)
tree39270dbc2df916a91c3c4272600fd082a2604516 /src/model/guild
parentSwitch to parking_lot::{Mutex, RwLock} (diff)
parentRelease v0.4.1 (diff)
downloadserenity-cae014758a1d1e926a71679f02e32601c57f8d52.tar.xz
serenity-cae014758a1d1e926a71679f02e32601c57f8d52.zip
Update to account for changes made in 0.4.1
Diffstat (limited to 'src/model/guild')
-rw-r--r--src/model/guild/member.rs34
-rw-r--r--src/model/guild/mod.rs239
2 files changed, 231 insertions, 42 deletions
diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs
index bca3ecb..02e5afb 100644
--- a/src/model/guild/member.rs
+++ b/src/model/guild/member.rs
@@ -159,10 +159,7 @@ impl Member {
#[cfg(all(feature = "cache", feature = "utils"))]
pub fn colour(&self) -> Option<Colour> {
let cache = CACHE.read();
- let guild = match cache.guilds.get(&self.guild_id) {
- Some(guild) => guild.read(),
- None => return None,
- };
+ let guild = try_opt!(cache.guilds.get(&self.guild_id)).read();
let mut roles = self.roles
.iter()
@@ -382,25 +379,16 @@ impl Member {
/// If role data can not be found for the member, then `None` is returned.
#[cfg(feature = "cache")]
pub fn roles(&self) -> Option<Vec<Role>> {
- CACHE
- .read()
- .guilds
- .values()
- .find(|guild| {
- guild.read().members.values().any(|m| {
- m.user.read().id == self.user.read().id &&
- m.joined_at == self.joined_at
- })
- })
- .map(|guild| {
- guild
- .read()
- .roles
- .values()
- .filter(|role| self.roles.contains(&role.id))
- .cloned()
- .collect()
- })
+ self
+ .guild_id
+ .find()
+ .map(|g| g
+ .read()
+ .roles
+ .values()
+ .filter(|role| self.roles.contains(&role.id))
+ .cloned()
+ .collect())
}
/// Unbans the [`User`] from the guild.
diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs
index ea6cb17..110ef4e 100644
--- a/src/model/guild/mod.rs
+++ b/src/model/guild/mod.rs
@@ -21,6 +21,7 @@ use serde::de::Error as DeError;
use serde_json;
use super::utils::*;
use model::*;
+use std;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
@@ -740,21 +741,23 @@ impl Guild {
/// Retrieves all [`Member`] that start with a given `String`.
///
- /// If the prefix is "zey", following results are possible:
- /// - "zey", "zeyla", "zey mei"
- /// If 'case_sensitive' is false, the following are not found:
- /// - "Zey", "ZEYla", "zeY mei"
+ /// `sorted` decides whether the best early match of the `prefix`
+ /// should be the criteria to sort the result.
+ /// For the `prefix` "zey" and the unsorted result:
+ /// - "zeya", "zeyaa", "zeyla", "zeyzey", "zeyzeyzey"
+ /// It would be sorted:
+ /// - "zeya", "zeyaa", "zeyla", "zeyzey", "zeyzeyzey"
///
/// [`Member`]: struct.Member.html
- pub fn members_starting_with(&self, prefix: &str, case_sensitive: bool) -> Vec<&Member> {
- self.members
+ pub fn members_starting_with(&self, prefix: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
+ let mut members: Vec<&Member> = self.members
.values()
.filter(|member|
if case_sensitive {
member.user.read().name.starts_with(prefix)
} else {
- starts_with_case_insensitive(&member.user.read().name, &prefix)
+ starts_with_case_insensitive(&member.user.read().name, prefix)
}
|| member.nick.as_ref()
@@ -763,37 +766,214 @@ impl Guild {
if case_sensitive {
nick.starts_with(prefix)
} else {
- starts_with_case_insensitive(&nick, &prefix)
- })).collect()
+ starts_with_case_insensitive(nick, prefix)
+ })).collect();
+
+ if sorted {
+ members
+ .sort_by(|a, b| {
+ let name_a = match a.nick {
+ Some(ref nick) => {
+ if contains_case_insensitive(&a.user.read().name[..], prefix) {
+ a.user.read().name.clone()
+ } else {
+ nick.clone()
+ }
+ },
+ None => a.user.read().name.clone(),
+ };
+
+ let name_b = match b.nick {
+ Some(ref nick) => {
+ if contains_case_insensitive(&b.user.read().name[..], prefix) {
+ b.user.read().name.clone()
+ } else {
+ nick.clone()
+ }
+ },
+ None => b.user.read().name.clone(),
+ };
+
+ closest_to_origin(prefix, &name_a[..], &name_b[..])
+ });
+ members
+ } else {
+ members
+ }
}
- /// Retrieves all [`Member`] containing a given `String`.
+ /// Retrieves all [`Member`] containing a given `String` as
+ /// either username or nick, with a priority on username.
///
/// If the substring is "yla", following results are possible:
/// - "zeyla", "meiyla", "yladenisyla"
/// If 'case_sensitive' is false, the following are not found:
/// - "zeYLa", "meiyLa", "LYAdenislyA"
///
+ /// `sorted` decides whether the best early match of the search-term
+ /// should be the criteria to sort the result.
+ /// It will look at the account name first, if that does not fit the
+ /// search-criteria `substring`, the display-name will be considered.
+ /// For the `substring` "zey" and the unsorted result:
+ /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
+ /// It would be sorted:
+ /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
+ ///
+ /// **Note**: Due to two fields of a `Member` being candidates for
+ /// the searched field, setting `sorted` to `true` will result in an overhead,
+ /// as both fields have to be considered again for sorting.
+ ///
/// [`Member`]: struct.Member.html
- pub fn members_containing(&self, substring: &str, case_sensitive: bool) -> Vec<&Member> {
- self.members
+ pub fn members_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
+ let mut members: Vec<&Member> = self.members
.values()
.filter(|member|
if case_sensitive {
member.user.read().name.contains(substring)
} else {
- contains_case_insensitive(&member.user.read().name, &substring)
+ contains_case_insensitive(&member.user.read().name, substring)
}
|| member.nick.as_ref()
- .map_or(false, |nick|
+ .map_or(false, |nick| {
+
+ if case_sensitive {
+ nick.contains(substring)
+ } else {
+ contains_case_insensitive(nick, substring)
+ }
+ })).collect();
+
+ if sorted {
+ members
+ .sort_by(|a, b| {
+ let name_a = match a.nick {
+ Some(ref nick) => {
+ if contains_case_insensitive(&a.user.read().name[..], substring) {
+ a.user.read().name.clone()
+ } else {
+ nick.clone()
+ }
+ },
+ None => a.user.read().name.clone(),
+ };
+
+ let name_b = match b.nick {
+ Some(ref nick) => {
+ if contains_case_insensitive(&b.user.read().name[..], substring) {
+ b.user.read().name.clone()
+ } else {
+ nick.clone()
+ }
+ },
+ None => b.user.read().name.clone(),
+ };
+
+ closest_to_origin(substring, &name_a[..], &name_b[..])
+ });
+ members
+ } else {
+ members
+ }
+ }
- if case_sensitive {
- nick.starts_with(substring)
- } else {
- contains_case_insensitive(&nick, &substring)
- })).collect()
+ /// Retrieves all [`Member`] containing a given `String` in
+ /// their username.
+ ///
+ /// If the substring is "yla", following results are possible:
+ /// - "zeyla", "meiyla", "yladenisyla"
+ /// If 'case_sensitive' is false, the following are not found:
+ /// - "zeYLa", "meiyLa", "LYAdenislyA"
+ ///
+ /// `sort` decides whether the best early match of the search-term
+ /// should be the criteria to sort the result.
+ /// For the `substring` "zey" and the unsorted result:
+ /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
+ /// It would be sorted:
+ /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
+ ///
+ /// [`Member`]: struct.Member.html
+ pub fn members_username_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
+ let mut members: Vec<&Member> = self.members
+ .values()
+ .filter(|member| {
+ if case_sensitive {
+ member.user.read().name.contains(substring)
+ } else {
+ contains_case_insensitive(&member.user.read().name, substring)
+ }
+ }).collect();
+
+ if sorted {
+ members
+ .sort_by(|a, b| {
+ let name_a = &a.user.read().name;
+ let name_b = &b.user.read().name;
+ closest_to_origin(substring, &name_a[..], &name_b[..])
+ });
+ members
+ } else {
+ members
+ }
+ }
+
+ /// Retrieves all [`Member`] containing a given `String` in
+ /// their nick.
+ ///
+ /// If the substring is "yla", following results are possible:
+ /// - "zeyla", "meiyla", "yladenisyla"
+ /// If 'case_sensitive' is false, the following are not found:
+ /// - "zeYLa", "meiyLa", "LYAdenislyA"
+ ///
+ /// `sort` decides whether the best early match of the search-term
+ /// should be the criteria to sort the result.
+ /// For the `substring` "zey" and the unsorted result:
+ /// - "azey", "zey", "zeyla", "zeylaa", "zeyzeyzey"
+ /// It would be sorted:
+ /// - "zey", "azey", "zeyla", "zeylaa", "zeyzeyzey"
+ ///
+ /// **Note**: Instead of panicing, when sorting does not find
+ /// a nick, the username will be used (this should never happen).
+ ///
+ /// [`Member`]: struct.Member.html
+ pub fn members_nick_containing(&self, substring: &str, case_sensitive: bool, sorted: bool) -> Vec<&Member> {
+ let mut members: Vec<&Member> = self.members
+ .values()
+ .filter(|member|
+ member.nick.as_ref()
+ .map_or(false, |nick| {
+
+ if case_sensitive {
+ nick.contains(substring)
+ } else {
+ contains_case_insensitive(nick, substring)
+ }
+ })).collect();
+
+ if sorted {
+ members
+ .sort_by(|a, b| {
+ let name_a = match a.nick {
+ Some(ref nick) => {
+ nick.clone()
+ },
+ None => a.user.read().name.clone(),
+ };
+
+ let name_b = match b.nick {
+ Some(ref nick) => {
+ nick.clone()
+ },
+ None => b.user.read().name.clone(),
+ };
+
+ closest_to_origin(substring, &name_a[..], &name_b[..])
+ });
+ members
+ } else {
+ members
+ }
}
/// Moves a member to a specific voice channel.
@@ -1270,6 +1450,27 @@ fn starts_with_case_insensitive(to_look_at: &str, to_find: &str) -> bool {
to_look_at.to_lowercase().starts_with(to_find)
}
+/// Takes a `&str` as `origin` and tests if either
+/// `word_a` or `word_b` is closer.
+///
+/// **Note**: Normally `word_a` and `word_b` are
+/// expected to contain `origin` as substring.
+/// If not, using `closest_to_origin` would sort these
+/// the end.
+fn closest_to_origin(origin: &str, word_a: &str, word_b: &str) -> std::cmp::Ordering {
+ let value_a = match word_a.find(origin) {
+ Some(value) => value + word_a.len(),
+ None => return std::cmp::Ordering::Greater,
+ };
+
+ let value_b = match word_b.find(origin) {
+ Some(value) => value + word_b.len(),
+ None => return std::cmp::Ordering::Less,
+ };
+
+ value_a.cmp(&value_b)
+}
+
/// Information relating to a guild's widget embed.
#[derive(Clone, Copy, Debug, Deserialize)]
pub struct GuildEmbed {