twilight_cache_any_backend/model/
member.rs

1use time::{error::ComponentRange, OffsetDateTime};
2use twilight_model::{
3    gateway::payload::incoming::MemberUpdate,
4    guild::Member,
5    id::{
6        marker::{GuildMarker, UserMarker},
7        Id,
8    },
9    user::{PremiumType, UserFlags},
10    util::{ImageHash, Timestamp},
11};
12
13/// A cached member
14///
15/// It's the same as [`twilight_model::guild::member::Member`] except:
16///
17/// - `user` field is flattened and `avatar` field is renamed to `guild_avatar`
18///   since member users are rarely duplicates, making this struct easier to
19///   cache
20///
21/// - `roles` field is removed, as member roles are cached separately
22///
23/// - `email` and `verified` fields are removed, as they're only sent in some
24///   HTTP endpoints
25#[derive(Clone, Debug)]
26pub struct CachedMember {
27    pub guild_avatar: Option<ImageHash>,
28    pub communication_disabled_until: Option<Timestamp>,
29    pub deaf: bool,
30    pub guild_id: Id<GuildMarker>,
31    pub joined_at: Timestamp,
32    pub mute: bool,
33    pub nick: Option<String>,
34    pub pending: bool,
35    pub premium_since: Option<Timestamp>,
36    pub accent_color: Option<u32>,
37    pub avatar: Option<ImageHash>,
38    pub banner: Option<ImageHash>,
39    pub bot: bool,
40    pub discriminator: u16,
41    pub flags: Option<UserFlags>,
42    pub id: Id<UserMarker>,
43    pub locale: Option<String>,
44    pub mfa_enabled: Option<bool>,
45    pub name: String,
46    pub premium_type: Option<PremiumType>,
47    pub public_flags: Option<UserFlags>,
48    pub system: Option<bool>,
49}
50
51impl CachedMember {
52    /// Return whether the user is timed out
53    ///
54    /// # Warnings
55    ///
56    /// Make sure the system time is correct
57    ///
58    /// # Errors
59    ///
60    /// Returns an error if the member's timestamp isn't valid (a Twilight or
61    /// Discord error)
62    pub fn communication_disabled(&self) -> Result<bool, ComponentRange> {
63        if let Some(timestamp) = self.communication_disabled_until {
64            Ok(OffsetDateTime::from_unix_timestamp(timestamp.as_secs())?
65                > OffsetDateTime::now_utc())
66        } else {
67            Ok(false)
68        }
69    }
70
71    /// Update the cached member with the partial member
72    pub fn update(&mut self, member: &MemberUpdate) {
73        self.guild_avatar = member.avatar;
74        self.communication_disabled_until = member.communication_disabled_until;
75        if let Some(deaf) = member.deaf {
76            self.deaf = deaf;
77        }
78        if let Some(mute) = member.mute {
79            self.mute = mute;
80        }
81        self.nick.clone_from(&member.nick);
82        self.pending = member.pending;
83        self.premium_since = member.premium_since;
84        self.accent_color = member.user.accent_color;
85        self.avatar = member.user.avatar;
86        self.banner = member.user.banner;
87        self.discriminator = member.user.discriminator;
88        self.flags = member.user.flags;
89        self.id = member.user.id;
90        self.locale.clone_from(&member.user.locale);
91        self.mfa_enabled = member.user.mfa_enabled;
92        self.name.clone_from(&member.user.name);
93        self.premium_type = member.user.premium_type;
94        self.public_flags = member.user.public_flags;
95        self.system = member.user.system;
96    }
97}
98
99impl From<&Member> for CachedMember {
100    fn from(member: &Member) -> Self {
101        Self {
102            guild_avatar: member.avatar,
103            communication_disabled_until: member.communication_disabled_until,
104            deaf: member.deaf,
105            guild_id: member.guild_id,
106            joined_at: member.joined_at,
107            mute: member.mute,
108            nick: member.nick.clone(),
109            pending: member.pending,
110            premium_since: member.premium_since,
111            accent_color: member.user.accent_color,
112            system: member.user.system,
113            avatar: member.avatar,
114            banner: member.user.banner,
115            bot: member.user.bot,
116            discriminator: member.user.discriminator,
117            flags: member.user.flags,
118            id: member.user.id,
119            locale: member.user.locale.clone(),
120            mfa_enabled: member.user.mfa_enabled,
121            name: member.user.name.clone(),
122            premium_type: member.user.premium_type,
123            public_flags: member.user.public_flags,
124        }
125    }
126}