Skip to main content

reinhardt_auth/core/
full_user.rs

1use chrono::{DateTime, Utc};
2
3use crate::core::base_user::BaseUser;
4
5/// FullUser trait - Django's AbstractUser equivalent
6///
7/// This trait extends `BaseUser` with additional user information fields
8/// commonly needed in web applications. It is inspired by Django's AbstractUser.
9///
10/// # Examples
11///
12/// ```no_run
13/// use reinhardt_auth::{BaseUser, FullUser, PasswordHasher};
14/// #[cfg(feature = "argon2-hasher")]
15/// use reinhardt_auth::Argon2Hasher;
16/// use uuid::Uuid;
17/// use chrono::{DateTime, Utc};
18/// use serde::{Serialize, Deserialize};
19///
20/// #[derive(Serialize, Deserialize)]
21/// struct MyUser {
22///     id: Uuid,
23///     username: String,
24///     email: String,
25///     first_name: String,
26///     last_name: String,
27///     password_hash: Option<String>,
28///     last_login: Option<DateTime<Utc>>,
29///     is_active: bool,
30///     is_staff: bool,
31///     is_superuser: bool,
32///     date_joined: DateTime<Utc>,
33/// }
34///
35/// #[cfg(feature = "argon2-hasher")]
36/// impl BaseUser for MyUser {
37///     type PrimaryKey = Uuid;
38///     type Hasher = Argon2Hasher;
39///
40///     fn get_username_field() -> &'static str { "username" }
41///     fn get_username(&self) -> &str { &self.username }
42///     fn password_hash(&self) -> Option<&str> { self.password_hash.as_deref() }
43///     fn set_password_hash(&mut self, hash: String) { self.password_hash = Some(hash); }
44///     fn last_login(&self) -> Option<DateTime<Utc>> { self.last_login }
45///     fn set_last_login(&mut self, time: DateTime<Utc>) { self.last_login = Some(time); }
46///     fn is_active(&self) -> bool { self.is_active }
47/// }
48///
49/// impl FullUser for MyUser {
50///     fn username(&self) -> &str { &self.username }
51///     fn email(&self) -> &str { &self.email }
52///     fn first_name(&self) -> &str { &self.first_name }
53///     fn last_name(&self) -> &str { &self.last_name }
54///     fn is_staff(&self) -> bool { self.is_staff }
55///     fn is_superuser(&self) -> bool { self.is_superuser }
56///     fn date_joined(&self) -> DateTime<Utc> { self.date_joined }
57/// }
58///
59/// # #[cfg(feature = "argon2-hasher")]
60/// # {
61/// let user = MyUser {
62///     id: Uuid::now_v7(),
63///     username: "alice".to_string(),
64///     email: "alice@example.com".to_string(),
65///     first_name: "Alice".to_string(),
66///     last_name: "Smith".to_string(),
67///     password_hash: None,
68///     last_login: None,
69///     is_active: true,
70///     is_staff: true,
71///     is_superuser: false,
72///     date_joined: Utc::now(),
73/// };
74///
75/// assert_eq!(user.get_full_name(), "Alice Smith");
76/// assert_eq!(user.get_short_name(), "Alice");
77/// assert!(user.is_staff());
78/// # }
79/// ```
80pub trait FullUser: BaseUser {
81	/// Returns the username
82	fn username(&self) -> &str;
83
84	/// Returns the email address
85	fn email(&self) -> &str;
86
87	/// Returns the first name
88	fn first_name(&self) -> &str;
89
90	/// Returns the last name
91	fn last_name(&self) -> &str;
92
93	/// Returns whether the user is a staff member
94	///
95	/// Staff members typically have access to the admin interface.
96	fn is_staff(&self) -> bool;
97
98	/// Returns whether the user is a superuser
99	///
100	/// Superusers have all permissions without explicit assignment.
101	fn is_superuser(&self) -> bool;
102
103	/// Returns when the user account was created
104	fn date_joined(&self) -> DateTime<Utc>;
105
106	/// Returns the full name (first name + last name)
107	///
108	/// # Examples
109	///
110	/// ```no_run
111	/// # use reinhardt_auth::{BaseUser, FullUser, PasswordHasher};
112	/// # #[cfg(feature = "argon2-hasher")]
113	/// # use reinhardt_auth::Argon2Hasher;
114	/// # use uuid::Uuid;
115	/// # use chrono::{DateTime, Utc};
116	/// # use serde::{Serialize, Deserialize};
117	/// # #[derive(Serialize, Deserialize)]
118	/// # struct MyUser { id: Uuid, username: String, email: String,
119	/// #   first_name: String, last_name: String, password_hash: Option<String>,
120	/// #   last_login: Option<DateTime<Utc>>, is_active: bool, is_staff: bool,
121	/// #   is_superuser: bool, date_joined: DateTime<Utc> }
122	/// # #[cfg(feature = "argon2-hasher")]
123	/// # impl BaseUser for MyUser {
124	/// #     type PrimaryKey = Uuid;
125	/// #     type Hasher = Argon2Hasher;
126	/// #     fn get_username_field() -> &'static str { "username" }
127	/// #     fn get_username(&self) -> &str { &self.username }
128	/// #     fn password_hash(&self) -> Option<&str> { self.password_hash.as_deref() }
129	/// #     fn set_password_hash(&mut self, hash: String) { self.password_hash = Some(hash); }
130	/// #     fn last_login(&self) -> Option<DateTime<Utc>> { self.last_login }
131	/// #     fn set_last_login(&mut self, time: DateTime<Utc>) { self.last_login = Some(time); }
132	/// #     fn is_active(&self) -> bool { self.is_active }
133	/// # }
134	/// # impl FullUser for MyUser {
135	/// #     fn username(&self) -> &str { &self.username }
136	/// #     fn email(&self) -> &str { &self.email }
137	/// #     fn first_name(&self) -> &str { &self.first_name }
138	/// #     fn last_name(&self) -> &str { &self.last_name }
139	/// #     fn is_staff(&self) -> bool { self.is_staff }
140	/// #     fn is_superuser(&self) -> bool { self.is_superuser }
141	/// #     fn date_joined(&self) -> DateTime<Utc> { self.date_joined }
142	/// # }
143	///
144	/// # #[cfg(feature = "argon2-hasher")]
145	/// # {
146	/// let user = MyUser {
147	///     id: Uuid::now_v7(),
148	///     username: "bob".to_string(),
149	///     email: "bob@example.com".to_string(),
150	///     first_name: "Bob".to_string(),
151	///     last_name: "Jones".to_string(),
152	///     password_hash: None,
153	///     last_login: None,
154	///     is_active: true,
155	///     is_staff: false,
156	///     is_superuser: false,
157	///     date_joined: Utc::now(),
158	/// };
159	///
160	/// assert_eq!(user.get_full_name(), "Bob Jones");
161	/// # }
162	/// ```
163	fn get_full_name(&self) -> String {
164		format!("{} {}", self.first_name(), self.last_name())
165			.trim()
166			.to_string()
167	}
168
169	/// Returns the short name (first name only)
170	///
171	/// # Examples
172	///
173	/// ```no_run
174	/// # use reinhardt_auth::{BaseUser, FullUser, PasswordHasher};
175	/// # #[cfg(feature = "argon2-hasher")]
176	/// # use reinhardt_auth::Argon2Hasher;
177	/// # use uuid::Uuid;
178	/// # use chrono::{DateTime, Utc};
179	/// # use serde::{Serialize, Deserialize};
180	/// # #[derive(Serialize, Deserialize)]
181	/// # struct MyUser { id: Uuid, username: String, email: String,
182	/// #   first_name: String, last_name: String, password_hash: Option<String>,
183	/// #   last_login: Option<DateTime<Utc>>, is_active: bool, is_staff: bool,
184	/// #   is_superuser: bool, date_joined: DateTime<Utc> }
185	/// # #[cfg(feature = "argon2-hasher")]
186	/// # impl BaseUser for MyUser {
187	/// #     type PrimaryKey = Uuid;
188	/// #     type Hasher = Argon2Hasher;
189	/// #     fn get_username_field() -> &'static str { "username" }
190	/// #     fn get_username(&self) -> &str { &self.username }
191	/// #     fn password_hash(&self) -> Option<&str> { self.password_hash.as_deref() }
192	/// #     fn set_password_hash(&mut self, hash: String) { self.password_hash = Some(hash); }
193	/// #     fn last_login(&self) -> Option<DateTime<Utc>> { self.last_login }
194	/// #     fn set_last_login(&mut self, time: DateTime<Utc>) { self.last_login = Some(time); }
195	/// #     fn is_active(&self) -> bool { self.is_active }
196	/// # }
197	/// # impl FullUser for MyUser {
198	/// #     fn username(&self) -> &str { &self.username }
199	/// #     fn email(&self) -> &str { &self.email }
200	/// #     fn first_name(&self) -> &str { &self.first_name }
201	/// #     fn last_name(&self) -> &str { &self.last_name }
202	/// #     fn is_staff(&self) -> bool { self.is_staff }
203	/// #     fn is_superuser(&self) -> bool { self.is_superuser }
204	/// #     fn date_joined(&self) -> DateTime<Utc> { self.date_joined }
205	/// # }
206	///
207	/// # #[cfg(feature = "argon2-hasher")]
208	/// # {
209	/// let user = MyUser {
210	///     id: Uuid::now_v7(),
211	///     username: "charlie".to_string(),
212	///     email: "charlie@example.com".to_string(),
213	///     first_name: "Charlie".to_string(),
214	///     last_name: "Brown".to_string(),
215	///     password_hash: None,
216	///     last_login: None,
217	///     is_active: true,
218	///     is_staff: false,
219	///     is_superuser: false,
220	///     date_joined: Utc::now(),
221	/// };
222	///
223	/// assert_eq!(user.get_short_name(), "Charlie");
224	/// # }
225	/// ```
226	fn get_short_name(&self) -> &str {
227		self.first_name()
228	}
229}