1pub mod permissions;
2pub mod settings;
3
4use std::sync::Arc;
5
6use super::lists::Lists;
7use permissions::Permission;
8use regex::Regex;
9use serde::{
10 de::{Unexpected, Visitor},
11 Deserialize, Serialize,
12};
13use settings::Settings;
14
15#[derive(Debug, Serialize, Deserialize)]
17pub struct User {
18 actor_id: ActorID,
20 username: String,
22 lists: Lists,
24 pfp: Option<String>,
26 banner: Option<String>,
28 following: Vec<Arc<str>>,
30 followers: Vec<Arc<str>>,
32 settings: Settings,
34 permissions: Vec<Permission>,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq)]
43pub struct ActorID {
44 instance_url: Arc<str>,
45 user_id: u64,
46}
47
48impl ActorID {
49 pub fn new(instance_url: &str, user_id: u64) -> Self {
50 Self {
51 instance_url: instance_url.into(),
52 user_id,
53 }
54 }
55
56 pub fn to_string(&self) -> String {
57 self.into()
58 }
59}
60
61impl From<ActorID> for String {
62 fn from(value: ActorID) -> Self {
63 format!("{}/user/{}", value.instance_url, value.user_id)
64 }
65}
66
67impl From<&ActorID> for String {
68 fn from(value: &ActorID) -> Self {
69 Self::from(value.clone())
70 }
71}
72
73impl Serialize for ActorID {
74 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75 where
76 S: serde::Serializer,
77 {
78 serializer.collect_str(&self.to_string())
79 }
80}
81
82struct ActorIDVisitor;
83static USERID_EXPECTED: &str = "an integer between 0 and 2^64";
84static EXPECTED: &str = "a URL of the form {instance_url}/user/{user_id}, where `user_id` is an integer between 0 and 2^64";
85
86impl<'de> Visitor<'de> for ActorIDVisitor {
87 type Value = ActorID;
88
89 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
90 formatter.write_str(EXPECTED)
91 }
92
93 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
94 where
95 E: serde::de::Error,
96 {
97 let actorid_re =
100 Regex::new(r"^(?:((?:https?://)?(?:[^:/$]+)(?::(?:\d+))?)(?:/user/(\d+)))$")
101 .expect("Hardcoded valid regex");
102
103 let Some((_, [instance_url, user_id])) = actorid_re.captures(v).map(|c| c.extract()) else {
105 return Err(E::invalid_value(Unexpected::Str(v), &EXPECTED));
106 };
107 let Ok(user_id) = user_id.parse::<u64>() else {
108 return Err(E::invalid_type(
109 Unexpected::Other(user_id),
110 &USERID_EXPECTED,
111 ));
112 };
113
114 Ok(Self::Value {
115 instance_url: instance_url.into(),
116 user_id,
117 })
118 }
119
120 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
121 where
122 E: serde::de::Error,
123 {
124 self.visit_str(&v)
125 }
126}
127
128impl<'de> Deserialize<'de> for ActorID {
129 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
130 where
131 D: serde::Deserializer<'de>,
132 {
133 deserializer.deserialize_any(ActorIDVisitor)
134 }
135}