1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use steamid::SteamID;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[non_exhaustive]
10#[repr(i32)]
11#[derive(Default)]
12pub enum PrivacyState {
13 Private = 1,
15 FriendsOnly = 2,
17 #[default]
19 Public = 3,
20}
21
22impl From<i32> for PrivacyState {
23 fn from(value: i32) -> Self {
24 match value {
25 1 => Self::Private,
26 2 => Self::FriendsOnly,
27 3 => Self::Public,
28 _ => Self::Public,
29 }
30 }
31}
32
33#[derive(Debug, Clone, Default, Serialize, Deserialize)]
35pub struct ProfileSettings {
36 pub name: Option<String>,
38 pub real_name: Option<String>,
40 pub summary: Option<String>,
42 pub country: Option<String>,
44 pub state: Option<String>,
46 pub city: Option<String>,
48 pub custom_url: Option<String>,
50 pub primary_group: Option<u64>,
52}
53
54#[derive(Debug, Clone, Default, Serialize, Deserialize)]
56pub struct PrivacySettings {
57 pub profile: Option<PrivacyState>,
59 pub comments: Option<i32>,
62 pub inventory: Option<PrivacyState>,
64 pub inventory_gifts: Option<PrivacyState>,
66 pub game_details: Option<PrivacyState>,
68 pub playtime: Option<PrivacyState>,
70 pub friends_list: Option<PrivacyState>,
72}
73
74impl PrivacySettings {
75 pub fn to_steam_format(&self) -> serde_json::Value {
77 serde_json::json!({
78 "PrivacyProfile": self.profile.unwrap_or_default() as i32,
79 "PrivacyInventory": self.inventory.unwrap_or_default() as i32,
80 "PrivacyInventoryGifts": self.inventory_gifts.map(|s| s as i32).unwrap_or(3),
81 "PrivacyOwnedGames": self.game_details.unwrap_or_default() as i32,
82 "PrivacyPlaytime": self.playtime.map(|s| s as i32).unwrap_or(3),
83 "PrivacyFriendsList": self.friends_list.unwrap_or_default() as i32,
84 })
85 }
86
87 pub fn from_steam_json(json: &serde_json::Value) -> Option<Self> {
89 let privacy = json.get("PrivacySettings").or_else(|| json.get("Privacy")?.get("PrivacySettings"))?;
90
91 let comments = json.get("eCommentPermission").or_else(|| json.get("Privacy")?.get("eCommentPermission"))?.as_i64().map(|v| v as i32);
92
93 Some(Self {
94 profile: privacy.get("PrivacyProfile").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
95 comments,
96 inventory: privacy.get("PrivacyInventory").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
97 inventory_gifts: privacy.get("PrivacyInventoryGifts").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
98 game_details: privacy.get("PrivacyOwnedGames").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
99 playtime: privacy.get("PrivacyPlaytime").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
100 friends_list: privacy.get("PrivacyFriendsList").and_then(|v| v.as_i64()).map(|v| PrivacyState::from(v as i32)),
101 })
102 }
103
104 pub fn merge(&mut self, other: PrivacySettings) {
106 if other.profile.is_some() {
107 self.profile = other.profile;
108 }
109 if other.comments.is_some() {
110 self.comments = other.comments;
111 }
112 if other.inventory.is_some() {
113 self.inventory = other.inventory;
114 }
115 if other.inventory_gifts.is_some() {
116 self.inventory_gifts = other.inventory_gifts;
117 }
118 if other.game_details.is_some() {
119 self.game_details = other.game_details;
120 }
121 if other.playtime.is_some() {
122 self.playtime = other.playtime;
123 }
124 if other.friends_list.is_some() {
125 self.friends_list = other.friends_list;
126 }
127 }
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct SteamProfile {
133 pub name: String,
134 pub real_name: String,
135 pub online_state: String,
136 pub steam_id: SteamID,
137 pub avatar_hash: String,
138 pub avatar_frame: Option<String>,
139 pub custom_url: String,
140 pub location: String,
141 pub summary: Option<String>,
142 pub not_yet_setup: bool,
143 pub profile_private_info: Option<String>,
144 pub lobby_link: Option<String>,
145 pub add_friend_enable: bool,
146 pub is_private: bool,
147 pub url: String,
148 pub nickname: Option<String>,
149 pub level: Option<u32>,
150 pub day_last_ban: Option<i64>,
151 pub game_ban: Option<GameBanData>,
152 pub state_message_game: Option<String>,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize, Default)]
156pub struct GameBanData {
157 #[serde(default)]
158 pub is_vac_ban: BanStatus,
159 #[serde(default)]
160 pub is_game_ban: BanStatus,
161 #[serde(default)]
162 pub is_trade_ban: bool,
163 pub days_since_last_ban: Option<u32>,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
167#[non_exhaustive]
168pub enum BanStatus {
169 #[default]
170 None,
171 Single,
172 Multiple,
173}
174
175impl From<i32> for BanStatus {
176 fn from(v: i32) -> Self {
177 match v {
178 1 => BanStatus::Single,
179 _ => BanStatus::None,
180 }
181 }
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct AvatarUploadResponse {
187 pub url: String,
189 pub hash: String,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct SteamUserProfile {
196 #[serde(rename = "steamId")]
197 pub steam_id: SteamID,
198 #[serde(rename = "accountId")]
199 pub account_id: u32,
200 #[serde(rename = "persona_name")]
201 pub name: String,
202 #[serde(rename = "real_name")]
203 pub real_name: String,
204 #[serde(rename = "avatar_url")]
205 pub avatar_hash: String,
206 #[serde(rename = "profile_url")]
207 pub custom_url: String,
208 #[serde(rename = "persona_state")]
209 pub persona_state: i32,
210 pub city: String,
211 pub state: String,
212 pub country: String,
213 #[serde(rename = "is_friend")]
214 pub is_friend: bool,
215 #[serde(rename = "friends_in_common")]
216 pub friends_in_common: u32,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct AvatarHistoryEntry {
222 pub avatar_sha1: String,
224 pub user_uploaded: bool,
226 pub timestamp: u32,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct UserSummaryXml {
235 pub name: String,
237 pub real_name: Option<String>,
239 pub steam_id: SteamID,
241 pub online_state: String,
243 pub state_message: String,
245 pub state_message_game: Option<String>,
247 pub state_message_non_steam_game: Option<String>,
249 pub privacy_state: String,
251 pub visibility_state: Option<i32>,
253 pub avatar_hash: String,
255 pub vac_banned: Option<i32>,
257 pub trade_ban_state: Option<String>,
259 pub is_limited_account: Option<bool>,
261 pub custom_url: Option<String>,
263 pub member_since: Option<i64>,
265 pub steam_rating: Option<String>,
267 pub location: Option<String>,
269 pub summary: Option<String>,
271 pub privacy_message: Option<String>,
273 pub not_yet_setup: bool,
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct UserSummaryProfile {
282 pub name: String,
284 pub real_name: String,
286 pub online_state: String,
288 pub steam_id: SteamID,
290 pub avatar_hash: String,
292 pub avatar_frame: Option<String>,
294 pub custom_url: String,
296 pub location: String,
298 pub summary: Option<String>,
300 pub not_yet_setup: bool,
302 pub profile_private_info: Option<String>,
304 pub lobby_link: Option<String>,
306 pub add_friend_enable: bool,
308 pub is_private: bool,
310 pub url: String,
312 pub nickname: Option<String>,
314 pub level: Option<u32>,
316 pub day_last_ban: Option<i64>,
318 pub game_ban: Option<GameBanData>,
320 pub state_message_game: Option<String>,
322}
323
324#[derive(Debug, Clone, PartialEq, Eq)]
329pub enum OnlineState {
330 Online,
331 Offline,
332 InGame,
333 Snooze,
334 Busy,
335 Away,
336 LookingToTrade,
337 LookingToPlay,
338 Other(String),
339}
340
341impl OnlineState {
342 pub(crate) fn from_xml(s: &str) -> Self {
343 match s {
344 "online" => Self::Online,
345 "offline" => Self::Offline,
346 "in-game" => Self::InGame,
347 "snooze" => Self::Snooze,
348 "busy" => Self::Busy,
349 "away" => Self::Away,
350 "looking to trade" => Self::LookingToTrade,
351 "looking to play" => Self::LookingToPlay,
352 other => Self::Other(other.to_owned()),
353 }
354 }
355}
356
357#[derive(Debug, Clone, PartialEq, Eq)]
359pub enum TradeBanState {
360 None,
361 Probation,
362 Banned,
363 Other(String),
364}
365
366impl TradeBanState {
367 pub(crate) fn from_xml(s: &str) -> Self {
368 match s {
369 "None" => Self::None,
370 "Probation" => Self::Probation,
371 "Banned" => Self::Banned,
372 other => Self::Other(other.to_owned()),
373 }
374 }
375}
376
377#[derive(Debug, Clone)]
384pub struct PublicProfileSummary {
385 pub steam_id: SteamID,
387 pub persona_name: String,
389 pub online_state: OnlineState,
391 pub state_message: String,
393 pub privacy_state: PrivacyState,
396 pub avatar_icon: String,
398 pub avatar_medium: String,
400 pub avatar_full: String,
402 pub vac_banned: bool,
404 pub trade_ban_state: TradeBanState,
406 pub is_limited_account: bool,
408 pub custom_url: Option<String>,
410 pub member_since: Option<DateTime<Utc>>,
415 pub headline: Option<String>,
417 pub location: Option<String>,
419 pub real_name: Option<String>,
421 pub summary: Option<String>,
423 pub hours_played_2wk: Option<f32>,
425}