1use std::net::IpAddr;
8
9use chrono::{DateTime, Utc};
10use rand::Rng;
11use serde::Serialize;
12use ulid::Ulid;
13use url::Url;
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
16pub struct User {
17 pub id: Ulid,
18 pub username: String,
19 pub sub: String,
20 pub created_at: DateTime<Utc>,
21 pub locked_at: Option<DateTime<Utc>>,
22 pub deactivated_at: Option<DateTime<Utc>>,
23 pub can_request_admin: bool,
24}
25
26impl User {
27 #[must_use]
29 pub fn is_valid(&self) -> bool {
30 self.locked_at.is_none() && self.deactivated_at.is_none()
31 }
32}
33
34impl User {
35 #[doc(hidden)]
36 #[must_use]
37 pub fn samples(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self> {
38 vec![User {
39 id: Ulid::from_datetime_with_source(now.into(), rng),
40 username: "john".to_owned(),
41 sub: "123-456".to_owned(),
42 created_at: now,
43 locked_at: None,
44 deactivated_at: None,
45 can_request_admin: false,
46 }]
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
51pub struct Password {
52 pub id: Ulid,
53 pub hashed_password: String,
54 pub version: u16,
55 pub upgraded_from_id: Option<Ulid>,
56 pub created_at: DateTime<Utc>,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
60pub struct Authentication {
61 pub id: Ulid,
62 pub created_at: DateTime<Utc>,
63 pub authentication_method: AuthenticationMethod,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
67pub enum AuthenticationMethod {
68 Password { user_password_id: Ulid },
69 UpstreamOAuth2 { upstream_oauth2_session_id: Ulid },
70 Unknown,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
79pub struct UserRecoverySession {
80 pub id: Ulid,
81 pub email: String,
82 pub user_agent: String,
83 pub ip_address: Option<IpAddr>,
84 pub locale: String,
85 pub created_at: DateTime<Utc>,
86 pub consumed_at: Option<DateTime<Utc>>,
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
95pub struct UserRecoveryTicket {
96 pub id: Ulid,
97 pub user_recovery_session_id: Ulid,
98 pub user_email_id: Ulid,
99 pub ticket: String,
100 pub created_at: DateTime<Utc>,
101 pub expires_at: DateTime<Utc>,
102}
103
104impl UserRecoveryTicket {
105 #[must_use]
106 pub fn active(&self, now: DateTime<Utc>) -> bool {
107 now < self.expires_at
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
113pub struct UserEmailAuthentication {
114 pub id: Ulid,
115 pub user_session_id: Option<Ulid>,
116 pub user_registration_id: Option<Ulid>,
117 pub email: String,
118 pub created_at: DateTime<Utc>,
119 pub completed_at: Option<DateTime<Utc>>,
120}
121
122#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
124pub struct UserEmailAuthenticationCode {
125 pub id: Ulid,
126 pub user_email_authentication_id: Ulid,
127 pub code: String,
128 pub created_at: DateTime<Utc>,
129 pub expires_at: DateTime<Utc>,
130}
131
132#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
133pub struct BrowserSession {
134 pub id: Ulid,
135 pub user: User,
136 pub created_at: DateTime<Utc>,
137 pub finished_at: Option<DateTime<Utc>>,
138 pub user_agent: Option<String>,
139 pub last_active_at: Option<DateTime<Utc>>,
140 pub last_active_ip: Option<IpAddr>,
141}
142
143impl BrowserSession {
144 #[must_use]
145 pub fn active(&self) -> bool {
146 self.finished_at.is_none() && self.user.is_valid()
147 }
148}
149
150impl BrowserSession {
151 #[must_use]
152 pub fn samples(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self> {
153 User::samples(now, rng)
154 .into_iter()
155 .map(|user| BrowserSession {
156 id: Ulid::from_datetime_with_source(now.into(), rng),
157 user,
158 created_at: now,
159 finished_at: None,
160 user_agent: Some(
161 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Safari/537.36".to_owned()
162 ),
163 last_active_at: Some(now),
164 last_active_ip: None,
165 })
166 .collect()
167 }
168}
169
170#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
171pub struct UserEmail {
172 pub id: Ulid,
173 pub user_id: Ulid,
174 pub email: String,
175 pub created_at: DateTime<Utc>,
176}
177
178impl UserEmail {
179 #[must_use]
180 pub fn samples(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self> {
181 vec![
182 Self {
183 id: Ulid::from_datetime_with_source(now.into(), rng),
184 user_id: Ulid::from_datetime_with_source(now.into(), rng),
185 email: "alice@example.com".to_owned(),
186 created_at: now,
187 },
188 Self {
189 id: Ulid::from_datetime_with_source(now.into(), rng),
190 user_id: Ulid::from_datetime_with_source(now.into(), rng),
191 email: "bob@example.com".to_owned(),
192 created_at: now,
193 },
194 ]
195 }
196}
197
198#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
199pub struct UserRegistrationPassword {
200 pub hashed_password: String,
201 pub version: u16,
202}
203
204#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
205pub struct UserRegistration {
206 pub id: Ulid,
207 pub username: String,
208 pub display_name: Option<String>,
209 pub terms_url: Option<Url>,
210 pub email_authentication_id: Option<Ulid>,
211 pub password: Option<UserRegistrationPassword>,
212 pub post_auth_action: Option<serde_json::Value>,
213 pub ip_address: Option<IpAddr>,
214 pub user_agent: Option<String>,
215 pub created_at: DateTime<Utc>,
216 pub completed_at: Option<DateTime<Utc>>,
217}