use either::Either;
use serde::{Deserialize, Serialize};
use time::{OffsetDateTime, serde::rfc3339};
use url::Url;
use crate::id::{OfflineOr, OfflineOrPrivateOr};
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Serialize,
Deserialize,
strum::AsRefStr,
)]
#[serde(rename_all = "camelCase")]
pub enum DeveloperType {
None,
Trusted,
Internal,
Moderator,
}
impl Default for DeveloperType {
fn default() -> Self { Self::None }
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Serialize,
Deserialize,
strum::AsRefStr,
)]
#[serde(rename_all = "camelCase")]
pub enum UserState {
Offline,
Active,
Online,
}
impl Default for UserState {
fn default() -> Self { Self::Offline }
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Serialize,
Deserialize,
strum::AsRefStr,
)]
#[serde(rename_all = "camelCase")]
pub enum UserStatus {
Offline,
Active,
#[serde(rename = "join me")]
JoinMe,
#[serde(rename = "ask me")]
AskMe,
Busy,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
Serialize,
Deserialize,
strum::AsRefStr,
)]
#[serde(rename_all = "camelCase")]
pub enum FriendRequestStatus {
Incoming,
Outgoing,
#[serde(other)]
Other,
}
#[serde_with::serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Presence {
pub avatar_thumbnail: Option<Url>,
#[serde(default)]
pub display_name: String,
pub groups: Vec<serde_json::Value>,
pub id: crate::id::User,
pub instance: crate::id::OfflineOr<crate::id::Instance>,
#[serde(default)]
pub instance_type: String,
#[serde(default)]
pub platform: String,
#[serde(default)]
#[serde_as(as = "serde_with::NoneAsEmptyString")]
pub profile_pic_override: Option<Url>,
pub status: UserStatus,
pub traveling_to_instance: crate::id::OfflineOrPrivateOr<crate::id::Instance>,
pub traveling_to_world: crate::id::OfflineOrPrivateOr<crate::id::World>,
pub world: crate::id::OfflineOr<String>,
#[serde(default)]
pub is_rejoining: serde_json::Value,
#[serde(default)]
pub current_avatar_tags: Vec<serde_json::Value>,
#[serde(default)]
#[serde_as(as = "serde_with::NoneAsEmptyString")]
pub user_icon: Option<Url>,
#[serde(default)]
pub debugflag: serde_json::Value,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PastDisplayName {
pub display_name: String,
#[serde(rename = "updated_at", with = "rfc3339")]
pub updated_at: OffsetDateTime,
#[serde(default)]
pub reverted: bool,
}
#[serde_with::serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AccountData {
#[serde(default)]
pub bio: String,
#[serde(default)] pub bio_links: Vec<String>,
pub current_avatar_image_url: Url,
#[serde(default)]
pub current_avatar_tags: serde_json::Value,
pub current_avatar_thumbnail_image_url: Url,
pub developer_type: DeveloperType,
pub display_name: String,
pub id: crate::id::User,
pub is_friend: bool,
#[serde(rename = "last_platform")]
pub last_platform: String,
#[serde(default)]
#[serde_as(as = "serde_with::NoneAsEmptyString")]
pub profile_pic_override: Option<Url>,
pub status: UserStatus,
pub status_description: String,
pub tags: Vec<String>,
#[serde(default)]
#[serde_as(as = "serde_with::NoneAsEmptyString")]
pub user_icon: Option<Url>,
}
#[serde_with::serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CurrentAccountData {
#[serde(rename = "acceptedTOSVersion")]
pub accepted_tos_version: u8,
pub accepted_privacy_version: u8,
pub current_avatar_asset_url: Url,
pub email_verified: bool,
pub friend_group_names: Vec<serde_json::Value>,
pub account_deletion_date: serde_json::Value,
pub account_deletion_log: serde_json::Value,
pub friends: Vec<crate::id::User>,
pub has_birthday: bool,
pub has_email: bool,
pub has_logged_in_from_client: bool,
pub has_pending_email: bool,
#[serde(default)]
#[serde_as(as = "serde_with::NoneAsEmptyString")]
pub home_location: Option<crate::id::World>,
#[serde(default)]
pub obfuscated_email: String,
#[serde(default)]
pub obfuscated_pending_email: String,
#[serde(default)]
pub past_display_names: Vec<Either<PastDisplayName, String>>,
pub status_first_time: bool,
pub status_history: Vec<String>,
pub steam_details: serde_json::Value,
#[serde(default)]
pub steam_id: String,
#[serde(default)]
pub google_id: String,
#[serde(default)]
pub oculus_id: String,
#[serde(default)]
pub pico_id: String,
#[serde(default)]
pub vive_id: String,
pub two_factor_auth_enabled: bool,
#[serde(default)]
#[serde(with = "rfc3339::option")]
pub two_factor_auth_enabled_date: Option<OffsetDateTime>,
pub unsubscribe: bool,
#[serde(default)]
pub username: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FriendData {
pub friend_key: String,
#[serde(rename = "last_login", with = "rfc3339")]
pub last_login: OffsetDateTime,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UserOrFriendData {
pub location: OfflineOrPrivateOr<crate::id::Instance>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StatusData {
pub state: UserState,
#[serde(rename = "last_activity", with = "rfc3339")]
pub last_activity: OffsetDateTime,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FriendUserStatusData {
#[serde(flatten)]
pub base: StatusData,
pub traveling_to_location: OfflineOrPrivateOr<String>,
pub traveling_to_instance: OfflineOrPrivateOr<crate::id::Instance>,
pub traveling_to_world: OfflineOrPrivateOr<crate::id::World>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CurrentAccount {
#[serde(flatten)]
pub base: AccountData,
#[serde(flatten)]
pub current: CurrentAccountData,
#[serde(flatten)]
pub status: StatusData,
#[serde(flatten)]
pub friend_data: FriendData,
pub presence: Presence,
pub offline_friends: Vec<crate::id::User>,
pub online_friends: Vec<crate::id::User>,
pub active_friends: Vec<crate::id::User>,
#[serde(rename = "updated_at", with = "rfc3339")]
pub updated_at: OffsetDateTime,
#[serde(default)]
pub current_avatar: String,
#[serde(default)]
pub fallback_avatar: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Friend {
#[serde(flatten)]
pub base: AccountData,
#[serde(flatten)]
pub friend: FriendData,
#[serde(flatten)]
pub user_or_friend: UserOrFriendData,
pub image_url: Url,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct User {
#[serde(flatten)]
pub base: AccountData,
#[serde(flatten)]
pub user_or_friend: UserOrFriendData,
pub allow_avatar_copying: bool,
#[serde(rename = "date_joined", with = "crate::date_format")]
pub date_joined: time::Date,
pub friend_request_status: FriendRequestStatus,
pub note: String,
pub instance_id: OfflineOr<crate::id::Instance>,
pub world_id: OfflineOr<crate::id::World>,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CurrentUser {
#[serde(flatten)]
pub base: User,
#[serde(flatten)]
pub account: CurrentAccountData,
#[serde(flatten)]
pub status: FriendUserStatusData,
#[serde(flatten)]
pub friend: FriendData,
pub fallback_avatar: crate::id::Avatar,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FriendUser {
#[serde(flatten)]
pub base: User,
#[serde(flatten)]
pub status: FriendUserStatusData,
#[serde(flatten)]
pub friend: FriendData,
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum AnyUser {
Authenticated(Box<CurrentUser>),
Friend(Box<FriendUser>),
User(Box<User>),
}
impl AnyUser {
#[must_use]
pub const fn as_user(&self) -> &User {
match &self {
Self::Authenticated(a) => &a.base,
Self::Friend(f) => &f.base,
Self::User(u) => u,
}
}
#[must_use]
pub fn into_user(self) -> User {
match self {
Self::Authenticated(a) => a.base,
Self::Friend(f) => f.base,
Self::User(u) => *u,
}
}
#[must_use]
pub const fn status(&self) -> &UserStatus {
match &self {
Self::Authenticated(a) => &a.base.base.status,
Self::Friend(f) => &f.base.base.status,
Self::User(u) => &u.base.status,
}
}
#[must_use]
pub const fn friend(&self) -> Option<&FriendData> {
match &self {
Self::Authenticated(a) => Some(&a.friend),
Self::Friend(f) => Some(&f.friend),
Self::User(_) => None,
}
}
}