Skip to main content

roblox_api/api/friends/
v1.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{DateTime, Paging, endpoint};
4
5pub const URL: &str = "https://friends.roblox.com/v1";
6
7#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
8#[serde(rename_all = "camelCase")]
9pub struct FollowingStatus {
10    #[serde(rename = "userId")]
11    pub id: u64,
12    pub is_following: bool,
13    pub is_followed: bool,
14}
15
16#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
17pub struct FriendStatus {
18    pub id: u64,
19    pub status: String,
20}
21
22#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
23pub enum FriendRequestSourceType {
24    InGame,
25    UserProfile,
26    PlayerSearch,
27    FriendRecommendations,
28}
29
30#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
31#[serde(rename_all = "camelCase")]
32pub struct FriendRequester {
33    #[serde(rename = "senderId")]
34    pub id: u64,
35    #[serde(rename = "senderNickname")]
36    pub display_name: String,
37    pub contact_name: Option<String>,
38
39    pub source_universe_id: Option<u64>,
40    pub origin_source_type: FriendRequestSourceType,
41    pub sent_at: DateTime,
42}
43
44#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
45#[serde(rename_all = "camelCase")]
46pub struct FriendRequest {
47    pub id: u64,
48    pub mutual_friends_list: Vec<String>,
49    #[serde(rename = "friendRequest")]
50    pub requester: FriendRequester,
51}
52
53#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
54#[serde(rename_all = "camelCase")]
55pub struct FriendRequests {
56    #[serde(rename = "data")]
57    pub requests: Vec<FriendRequest>,
58    #[serde(rename = "nextPageCursor")]
59    pub next_cursor: Option<String>,
60    #[serde(rename = "previousPageCursor")]
61    pub previous_cursor: Option<String>,
62}
63
64#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
65#[serde(rename_all = "camelCase")]
66pub struct User {
67    pub id: u64,
68    #[serde(rename = "hasVerifiedBadge")]
69    pub is_verified: Option<bool>,
70}
71
72#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
73#[serde(rename_all = "camelCase")]
74pub struct Followers {
75    #[serde(rename = "data")]
76    pub users: Vec<User>,
77    #[serde(rename = "nextPageCursor")]
78    pub next_cursor: Option<String>,
79    #[serde(rename = "previousPageCursor")]
80    pub previous_cursor: Option<String>,
81}
82
83#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
84#[serde(rename_all = "PascalCase")]
85pub struct FriendsFind {
86    #[serde(rename = "PageItems")]
87    pub users: Vec<User>,
88    pub next_cursor: Option<String>,
89    pub previous_cursor: Option<String>,
90    pub has_more: Option<bool>,
91}
92
93#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
94#[serde(rename_all = "camelCase")]
95pub struct UserPresence {
96    #[serde(rename = "UserPresenceType")]
97    pub kind: String,
98    #[serde(rename = "UserLocationType")]
99    pub location_kind: String,
100
101    #[serde(rename = "lastLocation")]
102    pub status: String,
103    pub last_online: DateTime,
104
105    pub place_id: Option<u64>,
106    pub root_place_id: Option<u64>,
107    pub universe_id: Option<u64>,
108    #[serde(rename = "gameInstanceId")]
109    pub job_id: Option<String>,
110}
111
112#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
113#[serde(rename_all = "camelCase")]
114pub struct FriendOnlineStatus {
115    pub id: u64,
116    #[serde(rename = "userPresence")]
117    pub presence: UserPresence,
118}
119
120#[derive(Debug, Deserialize)]
121struct CountResponse {
122    count: u16,
123}
124
125endpoint! {
126    friend_requests_count() -> u16 {
127        GET "{URL}/user/friend-requests/count";
128        map |r: CountResponse| r.count
129    }
130
131    new_friend_requests_count() -> u16 {
132        GET "{URL}/my/new-friend-requests/count";
133        map |r: CountResponse| r.count
134    }
135
136    user_friends_count(id: u64) -> u16 {
137        GET "{URL}/users/{id}/friends/count";
138        map |r: CountResponse| r.count
139    }
140
141    user_followings_count(id: u64) -> u16 {
142        GET "{URL}/users/{id}/followings/count";
143        map |r: CountResponse| r.count
144    }
145
146    user_followers_count(id: u64) -> u16 {
147        GET "{URL}/users/{id}/followers/count";
148        map |r: CountResponse| r.count
149    }
150
151    following_status(ids: &[u64]) -> Vec<FollowingStatus> {
152        POST "{URL}/user/following-exists";
153        types {
154            Request<'a> {
155                user_ids("targetUserIds"): &'a [u64],
156            }
157            Response {
158                statuses("followings"): Vec<FollowingStatus>,
159            }
160        }
161        body_serialize {
162            &Request { user_ids: ids }
163        }
164        map |r: Response| r.statuses
165    }
166
167    friend_requests(paging: Paging<'_>) -> FriendRequests {
168        GET "{URL}/my/friends/requests";
169        paging_query { paging, limit = 18 }
170    }
171
172    user_followers(id: u64) -> Followers {
173        GET "{URL}/users/{id}/followers";
174    }
175
176    user_followings(id: u64) -> Followers {
177        GET "{URL}/users/{id}/followings";
178    }
179
180    user_friends_online(id: u64) -> Vec<FriendOnlineStatus> {
181        GET "{URL}/users/{id}/friends/online";
182        types {
183            Response {
184                online("data"): Vec<FriendOnlineStatus>,
185            }
186        }
187        map |r: Response| r.online
188    }
189
190    user_friends_find(id: u64, paging: Paging<'_>) -> FriendsFind {
191        GET "{URL}/users/{id}/friends/find";
192        prelude {
193            let limit = paging.limit.unwrap_or(18).to_string();
194            let cursor = paging.cursor.unwrap_or("");
195        }
196        query {
197            "cursor" => cursor,
198            "limit" => &limit,
199            "userSort" => "1",
200        }
201    }
202
203    user_friends_search(id: u64, query: &str, paging: Paging<'_>) -> FriendsFind {
204        GET "{URL}/users/{id}/friends/search";
205        paging_query { paging, limit = 36 }
206        query {
207            "query" => query,
208        }
209    }
210
211    user_friend_statuses(id: u64, friends: &[u64]) -> Vec<FriendStatus> {
212        GET "{URL}/users/{id}/friends/statuses";
213        types {
214            Response {
215                statuses("data"): Vec<FriendStatus>,
216            }
217        }
218        prelude {
219            let ids = friends
220                .iter()
221                .map(|x| x.to_string())
222                .collect::<Vec<String>>()
223                .join(",");
224        }
225        query {
226            "userIds" => &ids,
227        }
228        map |r: Response| r.statuses
229    }
230}