use iso8601_timestamp::Timestamp; use once_cell::sync::Lazy; use regex::Regex; use super::File; #[cfg(feature = "validator")] use validator::Validate; /// Regex for valid usernames /// /// Block zero width space /// Block lookalike characters pub static RE_USERNAME: Lazy = Lazy::new(|| Regex::new(r"^(\p{L}|[\d_.-])+$").unwrap()); /// Regex for valid display names /// /// Block zero width space /// Block newline and carriage return pub static RE_DISPLAY_NAME: Lazy = Lazy::new(|| Regex::new(r"^[^\u200B\n\r]+$").unwrap()); auto_derived_partial!( /// User pub struct User { /// Unique Id #[cfg_attr(feature = "serde", serde(rename = "_id"))] pub id: String, /// Username pub username: String, /// Discriminator pub discriminator: String, /// Display name #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub display_name: Option, #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] /// Avatar attachment pub avatar: Option, /// Relationships with other users #[cfg_attr( feature = "serde", serde(skip_serializing_if = "Vec::is_empty", default) )] pub relations: Vec, /// Bitfield of user badges /// /// https://docs.rs/revolt-models/latest/revolt_models/v0/enum.UserBadges.html #[cfg_attr( feature = "serde", serde(skip_serializing_if = "crate::if_zero_u32", default) )] pub badges: u32, /// User's current status #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub status: Option, /// Enum of user flags /// /// https://docs.rs/revolt-models/latest/revolt_models/v0/enum.UserFlags.html #[cfg_attr( feature = "serde", serde(skip_serializing_if = "crate::if_zero_u32", default) )] pub flags: u32, /// Whether this user is privileged #[cfg_attr( feature = "serde", serde(skip_serializing_if = "crate::if_false", default) )] pub privileged: bool, /// Bot information #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub bot: Option, /// Current session user's relationship with this user pub relationship: RelationshipStatus, /// Whether this user is currently online pub online: bool, }, "PartialUser" ); auto_derived!( /// Optional fields on user object pub enum FieldsUser { Avatar, StatusText, StatusPresence, ProfileContent, ProfileBackground, DisplayName, /// Internal field, ignore this. Internal, } /// User's relationship with another user (or themselves) #[derive(Default)] pub enum RelationshipStatus { /// No relationship with other user #[default] None, /// Other user is us User, /// Friends with the other user Friend, /// Pending friend request to user Outgoing, /// Incoming friend request from user Incoming, /// Blocked this user Blocked, /// Blocked by this user BlockedOther, } /// Relationship entry indicating current status with other user pub struct Relationship { /// Other user's Id #[cfg_attr(feature = "serde", serde(rename = "_id"))] pub user_id: String, /// Relationship status with them pub status: RelationshipStatus, } /// Presence status pub enum Presence { /// User is online Online, /// User is not currently available Idle, /// User is focusing / will only receive mentions Focus, /// User is busy / will not receive any notifications Busy, /// User appears to be offline Invisible, } /// User's active status #[derive(Default)] #[cfg_attr(feature = "validator", derive(Validate))] pub struct UserStatus { /// Custom status text #[validate(length(min = 0, max = 128))] #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub text: Option, /// Current presence option #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub presence: Option, } /// User's profile #[derive(Default)] #[cfg_attr(feature = "validator", derive(Validate))] pub struct UserProfile { /// Text content on user's profile #[validate(length(min = 0, max = 2000))] #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub content: Option, /// Background visible on user's profile #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub background: Option, } /// User badge bitfield #[repr(u32)] pub enum UserBadges { /// Revolt Developer Developer = 1, /// Helped translate Revolt Translator = 2, /// Monetarily supported Revolt Supporter = 4, /// Responsibly disclosed a security issue ResponsibleDisclosure = 8, /// Revolt Founder Founder = 16, /// Platform moderator PlatformModeration = 32, /// Active monetary supporter ActiveSupporter = 64, /// 🦊🦝 Paw = 128, /// Joined as one of the first 1000 users in 2021 EarlyAdopter = 256, /// Amogus ReservedRelevantJokeBadge1 = 512, /// Low resolution troll face ReservedRelevantJokeBadge2 = 1024, } /// User flag enum #[repr(u32)] pub enum UserFlags { /// User has been suspended from the platform SuspendedUntil = 1, /// User has deleted their account Deleted = 2, /// User was banned off the platform Banned = 4, /// User was marked as spam and removed from platform Spam = 8, } /// New user profile data #[cfg_attr(feature = "validator", derive(Validate))] pub struct DataUserProfile { /// Text to set as user profile description #[cfg_attr(feature = "validator", validate(length(min = 0, max = 2000)))] #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub content: Option, /// Attachment Id for background #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] #[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))] pub background: Option, } /// New user information #[cfg_attr(feature = "validator", derive(Validate))] pub struct DataEditUser { /// New display name #[cfg_attr( feature = "validator", validate(length(min = 2, max = 32), regex = "RE_DISPLAY_NAME") )] pub display_name: Option, /// Attachment Id for avatar #[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))] pub avatar: Option, /// New user status #[cfg_attr(feature = "validator", validate)] pub status: Option, /// New user profile data /// /// This is applied as a partial. #[cfg_attr(feature = "validator", validate)] pub profile: Option, /// Bitfield of user badges #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub badges: Option, /// Enum of user flags #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub flags: Option, /// Fields to remove from user object #[cfg_attr(feature = "serde", serde(default))] pub remove: Vec, } /// User flag reponse pub struct FlagResponse { /// Flags pub flags: i32, } /// Mutual friends, servers, groups and DMs response pub struct MutualResponse { /// Array of mutual user IDs that both users are friends with pub users: Vec, /// Array of mutual server IDs that both users are in pub servers: Vec, /// Array of mutual group and dm IDs that both users are in pub channels: Vec, } /// Bot information for if the user is a bot pub struct BotInformation { /// Id of the owner of this bot #[cfg_attr(feature = "serde", serde(rename = "owner"))] pub owner_id: String, } /// User lookup information pub struct DataSendFriendRequest { /// Username and discriminator combo separated by # pub username: String, } ); auto_derived_partial!( /// Voice State information for a user pub struct UserVoiceState { pub id: String, pub joined_at: Timestamp, pub is_receiving: bool, pub is_publishing: bool, pub screensharing: bool, pub camera: bool, }, "PartialUserVoiceState" ); pub trait CheckRelationship { fn with(&self, user: &str) -> RelationshipStatus; } impl CheckRelationship for Vec { fn with(&self, user: &str) -> RelationshipStatus { for entry in self { if entry.user_id == user { return entry.status.clone(); } } RelationshipStatus::None } }