diff --git a/src/cache/cache.rs b/src/cache/cache.rs index f021de2e..cf1ba8de 100644 --- a/src/cache/cache.rs +++ b/src/cache/cache.rs @@ -94,6 +94,8 @@ impl Cache { Event::GuildEmojisUpdate(event) => event.update_cache(self).await, Event::MemberChunk(event) => event.update_cache(self).await, Event::MemberAdd(event) => event.update_cache(self).await, + Event::MemberRemove(event) => event.update_cache(self).await, + Event::MemberUpdate(event) => event.update_cache(self).await, _ => {} } } diff --git a/src/cache/events/guild.rs b/src/cache/events/guild.rs index f2120757..09a35208 100644 --- a/src/cache/events/guild.rs +++ b/src/cache/events/guild.rs @@ -1,3 +1,5 @@ +use std::{collections::HashMap, sync::Arc}; + use async_trait::async_trait; use twilight_model::gateway::payload::incoming::{GuildCreate, GuildDelete, GuildEmojisUpdate}; @@ -24,6 +26,11 @@ impl UpdateCache for GuildCreate { .iter() .map(|t| (t.id, t.parent_id.unwrap())) .collect(), + members: self + .members + .iter() + .map(|m| (m.user.id, Arc::new(m.into()))) + .collect::>(), }; cache.guilds.insert(self.id, guild); } diff --git a/src/cache/events/member.rs b/src/cache/events/member.rs index 52ea9098..5e53fbe0 100644 --- a/src/cache/events/member.rs +++ b/src/cache/events/member.rs @@ -1,7 +1,9 @@ use std::sync::Arc; use async_trait::async_trait; -use twilight_model::gateway::payload::incoming::{MemberAdd, MemberChunk}; +use twilight_model::gateway::payload::incoming::{ + MemberAdd, MemberChunk, MemberRemove, MemberUpdate, +}; use crate::cache::{cache::Cache, update::UpdateCache}; @@ -13,6 +15,13 @@ impl UpdateCache for MemberChunk { .users .insert(member.user.id, Some(Arc::new((&member.user).into()))); } + + cache.guilds.alter(&self.guild_id, |_, mut g| { + for member in &self.members { + g.members.insert(member.user.id, Arc::new(member.into())); + } + g + }) } } @@ -22,5 +31,30 @@ impl UpdateCache for MemberAdd { cache .users .insert(self.user.id, Some(Arc::new((&self.user).into()))); + + cache.guilds.alter(&self.guild_id, |_, mut g| { + g.members.insert(self.user.id, Arc::new((&self.0).into())); + g + }); + } +} + +#[async_trait] +impl UpdateCache for MemberRemove { + async fn update_cache(&self, cache: &Cache) { + cache.guilds.alter(&self.guild_id, |_, mut g| { + g.members.remove(&self.user.id); + g + }); + } +} + +#[async_trait] +impl UpdateCache for MemberUpdate { + async fn update_cache(&self, cache: &Cache) { + cache.guilds.alter(&self.guild_id, |_, mut g| { + g.members.insert(self.user.id, Arc::new(self.into())); + g + }) } } diff --git a/src/cache/models/guild.rs b/src/cache/models/guild.rs index 52b4b903..e9b16eab 100644 --- a/src/cache/models/guild.rs +++ b/src/cache/models/guild.rs @@ -1,16 +1,17 @@ -use std::collections::HashMap; +use std::{collections::HashMap, sync::Arc}; use twilight_model::id::{ - marker::{ChannelMarker, EmojiMarker}, + marker::{ChannelMarker, EmojiMarker, UserMarker}, Id, }; -use super::channel::CachedChannel; +use super::{channel::CachedChannel, member::CachedMember}; pub struct CachedGuild { /// all custom emojis mapped to whether they are animated pub emojis: HashMap, bool>, /// all textable channels except for threads pub channels: HashMap, CachedChannel>, + pub members: HashMap, Arc>, pub active_thread_parents: HashMap, Id>, } diff --git a/src/cache/models/member.rs b/src/cache/models/member.rs new file mode 100644 index 00000000..12785cde --- /dev/null +++ b/src/cache/models/member.rs @@ -0,0 +1,48 @@ +use twilight_model::{gateway::payload::incoming::MemberUpdate, guild::Member}; + +pub struct CachedMember { + pub nickname: Option, + pub server_avatar_url: Option, +} + +impl From for CachedMember { + fn from(member: Member) -> Self { + Self { + nickname: member.nick, + server_avatar_url: member.avatar.map(|av| { + format!( + "https://cdn.discordapp.com/avatars/{}/{}.png", + member.user.id, av + ) + }), + } + } +} + +impl From<&Member> for CachedMember { + fn from(member: &Member) -> Self { + Self { + nickname: member.nick.as_ref().cloned(), + server_avatar_url: member.avatar.as_ref().map(|av| { + format!( + "https://cdn.discordapp.com/avatars/{}/{}.png", + member.user.id, av + ) + }), + } + } +} + +impl From<&MemberUpdate> for CachedMember { + fn from(member: &MemberUpdate) -> Self { + Self { + nickname: member.nick.as_ref().cloned(), + server_avatar_url: member.avatar.as_ref().map(|av| { + format!( + "https://cdn.discordapp.com/avatars/{}/{}.png", + member.user.id, av + ) + }), + } + } +} diff --git a/src/cache/models/mod.rs b/src/cache/models/mod.rs index 4eff55ec..15d00873 100644 --- a/src/cache/models/mod.rs +++ b/src/cache/models/mod.rs @@ -1,4 +1,5 @@ pub mod channel; pub mod guild; +pub mod member; pub mod message; pub mod user; diff --git a/src/core/embedder/builder.rs b/src/core/embedder/builder.rs index 9b118953..f8d9c91b 100644 --- a/src/core/embedder/builder.rs +++ b/src/core/embedder/builder.rs @@ -145,16 +145,40 @@ impl BuiltStarboardEmbed { true => &handle.referenced_message_author, false => &handle.orig_message_author, }; - let avatar: Option<&str>; - let name; + let avatar: Option; + let name: String; (name, avatar) = match maybe_user { - None => ("Deleted User", None), - Some(user) => (user.name.as_str(), user.avatar_url.as_deref()), + None => ("Deleted User".to_string(), None), + Some(user) => { + let member = handle.bot.cache.guilds.with( + &handle.config.starboard.guild_id.into_id(), + |_, g| { + if let Some(g) = g { + g.value().members.get(&orig.author_id).map(|m| (*m).clone()) + } else { + None + } + }, + ); + + let (name, avatar) = match &member { + Some(member) => ( + member.nickname.as_ref().unwrap_or(&user.name).to_owned(), + member + .server_avatar_url + .as_ref() + .or(user.avatar_url.as_ref()) + .cloned(), + ), + None => (user.name.clone(), user.avatar_url.as_ref().cloned()), + }; + (name, avatar) + } }; let name = if is_reply { format!("Replying to {}", name) } else { - name.to_string() + name }; let mut author = EmbedAuthorBuilder::new(name).url(&link); diff --git a/src/core/embedder/handle.rs b/src/core/embedder/handle.rs index e3976b8d..48d9fe14 100644 --- a/src/core/embedder/handle.rs +++ b/src/core/embedder/handle.rs @@ -12,7 +12,8 @@ use crate::{ use super::{attachment_handle::VecAttachments, builder::BuiltStarboardEmbed}; -pub struct Embedder<'config> { +pub struct Embedder<'config, 'bot> { + pub bot: &'bot StarboardBot, pub points: i32, pub config: &'config StarboardConfig, pub orig_message: Option>, @@ -22,8 +23,9 @@ pub struct Embedder<'config> { pub orig_sql_message: Arc, } -impl<'config> Embedder<'config> { +impl<'config, 'bot> Embedder<'config, 'bot> { pub fn new( + bot: &'bot StarboardBot, points: i32, config: &'config StarboardConfig, orig_message: Option>, @@ -33,6 +35,7 @@ impl<'config> Embedder<'config> { orig_sql_message: Arc, ) -> Self { Self { + bot, points, config, orig_message, @@ -44,7 +47,7 @@ impl<'config> Embedder<'config> { } } -impl Embedder<'_> { +impl Embedder<'_, '_> { fn build(&self) -> BuiltStarboardEmbed { BuiltStarboardEmbed::build(self) } diff --git a/src/core/starboard/handle.rs b/src/core/starboard/handle.rs index 17dabb33..a5134b41 100644 --- a/src/core/starboard/handle.rs +++ b/src/core/starboard/handle.rs @@ -185,6 +185,7 @@ impl<'this, 'bot> RefreshStarboard<'this, 'bot> { }; let embedder = Embedder::new( + self.refresh.bot, points, self.config, orig_message,