use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use steamid::SteamID;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
#[repr(i32)]
#[derive(Default)]
pub enum PrivacyState {
Private = 1,
FriendsOnly = 2,
#[default]
Public = 3,
}
impl From<i32> for PrivacyState {
fn from(value: i32) -> Self {
match value {
1 => Self::Private,
2 => Self::FriendsOnly,
3 => Self::Public,
_ => Self::Public,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ProfileSettings {
pub name: Option<String>,
pub real_name: Option<String>,
pub summary: Option<String>,
pub country: Option<String>,
pub state: Option<String>,
pub city: Option<String>,
pub custom_url: Option<String>,
pub primary_group: Option<u64>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PrivacySettings {
pub profile: Option<PrivacyState>,
pub comments: Option<i32>,
pub inventory: Option<PrivacyState>,
pub inventory_gifts: Option<PrivacyState>,
pub game_details: Option<PrivacyState>,
pub playtime: Option<PrivacyState>,
pub friends_list: Option<PrivacyState>,
}
impl PrivacySettings {
pub fn to_steam_format(&self) -> serde_json::Value {
serde_json::json!({
"PrivacyProfile": self.profile.unwrap_or_default() as i32,
"PrivacyInventory": self.inventory.unwrap_or_default() as i32,
"PrivacyInventoryGifts": self.inventory_gifts.map(|s| s as i32).unwrap_or(3),
"PrivacyOwnedGames": self.game_details.unwrap_or_default() as i32,
"PrivacyPlaytime": self.playtime.map(|s| s as i32).unwrap_or(3),
"PrivacyFriendsList": self.friends_list.unwrap_or_default() as i32,
})
}
pub fn from_steam_json(json: &serde_json::Value) -> Option<Self> {
let privacy = json.get("PrivacySettings").or_else(|| json.get("Privacy")?.get("PrivacySettings"))?;
let comments = json.get("eCommentPermission").or_else(|| json.get("Privacy")?.get("eCommentPermission"))?.as_i64().map(|v| v as i32);
Some(Self {
profile: privacy.get("PrivacyProfile").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
comments,
inventory: privacy.get("PrivacyInventory").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
inventory_gifts: privacy.get("PrivacyInventoryGifts").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
game_details: privacy.get("PrivacyOwnedGames").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
playtime: privacy.get("PrivacyPlaytime").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
friends_list: privacy.get("PrivacyFriendsList").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
})
}
pub fn merge(&mut self, other: PrivacySettings) {
if other.profile.is_some() {
self.profile = other.profile;
}
if other.comments.is_some() {
self.comments = other.comments;
}
if other.inventory.is_some() {
self.inventory = other.inventory;
}
if other.inventory_gifts.is_some() {
self.inventory_gifts = other.inventory_gifts;
}
if other.game_details.is_some() {
self.game_details = other.game_details;
}
if other.playtime.is_some() {
self.playtime = other.playtime;
}
if other.friends_list.is_some() {
self.friends_list = other.friends_list;
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SteamProfile {
pub name: String,
pub real_name: String,
pub online_state: String,
pub steam_id: SteamID,
pub avatar_hash: String,
pub avatar_frame: Option<String>,
pub custom_url: String,
pub location: String,
pub summary: Option<String>,
pub not_yet_setup: bool,
pub profile_private_info: Option<String>,
pub lobby_link: Option<String>,
pub add_friend_enable: bool,
pub is_private: bool,
pub url: String,
pub nickname: Option<String>,
pub level: Option<u32>,
pub day_last_ban: Option<i64>,
pub game_ban: Option<GameBanData>,
pub state_message_game: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct GameBanData {
#[serde(default)]
pub is_vac_ban: BanStatus,
#[serde(default)]
pub is_game_ban: BanStatus,
#[serde(default)]
pub is_trade_ban: bool,
pub days_since_last_ban: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[non_exhaustive]
pub enum BanStatus {
#[default]
None,
Single,
Multiple,
}
impl From<i32> for BanStatus {
fn from(v: i32) -> Self {
match v {
1 => BanStatus::Single,
_ => BanStatus::None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AvatarUploadResponse {
pub url: String,
pub hash: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SteamUserProfile {
#[serde(rename = "steamId")]
pub steam_id: SteamID,
#[serde(rename = "accountId")]
pub account_id: u32,
#[serde(rename = "persona_name")]
pub name: String,
#[serde(rename = "real_name")]
pub real_name: String,
#[serde(rename = "avatar_url")]
pub avatar_hash: String,
#[serde(rename = "profile_url")]
pub custom_url: String,
#[serde(rename = "persona_state")]
pub persona_state: i32,
pub city: String,
pub state: String,
pub country: String,
#[serde(rename = "is_friend")]
pub is_friend: bool,
#[serde(rename = "friends_in_common")]
pub friends_in_common: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AvatarHistoryEntry {
pub avatar_sha1: String,
pub user_uploaded: bool,
pub timestamp: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserSummaryXml {
pub name: String,
pub real_name: Option<String>,
pub steam_id: SteamID,
pub online_state: String,
pub state_message: String,
pub state_message_game: Option<String>,
pub state_message_non_steam_game: Option<String>,
pub privacy_state: String,
pub visibility_state: Option<i32>,
pub avatar_hash: String,
pub vac_banned: Option<i32>,
pub trade_ban_state: Option<String>,
pub is_limited_account: Option<bool>,
pub custom_url: Option<String>,
pub member_since: Option<i64>,
pub steam_rating: Option<String>,
pub location: Option<String>,
pub summary: Option<String>,
pub privacy_message: Option<String>,
pub not_yet_setup: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserSummaryProfile {
pub name: String,
pub real_name: String,
pub online_state: String,
pub steam_id: SteamID,
pub avatar_hash: String,
pub avatar_frame: Option<String>,
pub custom_url: String,
pub location: String,
pub summary: Option<String>,
pub not_yet_setup: bool,
pub profile_private_info: Option<String>,
pub lobby_link: Option<String>,
pub add_friend_enable: bool,
pub is_private: bool,
pub url: String,
pub nickname: Option<String>,
pub level: Option<u32>,
pub day_last_ban: Option<i64>,
pub game_ban: Option<GameBanData>,
pub state_message_game: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OnlineState {
Online,
Offline,
InGame,
Snooze,
Busy,
Away,
LookingToTrade,
LookingToPlay,
Other(String),
}
impl OnlineState {
pub(crate) fn from_xml(s: &str) -> Self {
match s {
"online" => Self::Online,
"offline" => Self::Offline,
"in-game" => Self::InGame,
"snooze" => Self::Snooze,
"busy" => Self::Busy,
"away" => Self::Away,
"looking to trade" => Self::LookingToTrade,
"looking to play" => Self::LookingToPlay,
other => Self::Other(other.to_owned()),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum TradeBanState {
None,
Probation,
Banned,
Other(String),
}
impl TradeBanState {
pub(crate) fn from_xml(s: &str) -> Self {
match s {
"None" => Self::None,
"Probation" => Self::Probation,
"Banned" => Self::Banned,
other => Self::Other(other.to_owned()),
}
}
}
#[derive(Debug, Clone)]
pub struct PublicProfileSummary {
pub steam_id: SteamID,
pub persona_name: String,
pub online_state: OnlineState,
pub state_message: String,
pub privacy_state: PrivacyState,
pub avatar_icon: String,
pub avatar_medium: String,
pub avatar_full: String,
pub vac_banned: bool,
pub trade_ban_state: TradeBanState,
pub is_limited_account: bool,
pub custom_url: Option<String>,
pub member_since: Option<DateTime<Utc>>,
pub headline: Option<String>,
pub location: Option<String>,
pub real_name: Option<String>,
pub summary: Option<String>,
pub hours_played_2wk: Option<f32>,
}