1use serde::{Deserialize, Serialize};
2use serde_valid::Validate;
3pub use tetratto_core2::model::{ApiReturn, Error, Result, id::Id};
4use totp_rs::TOTP;
5use tritools::{
6 encoding::{hash_salted, salt},
7 time::unix_epoch_timestamp,
8};
9
10#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
11pub enum ThemePreference {
12 #[default]
13 Auto,
14 Light,
15 Dark,
16}
17
18#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
19pub enum UserPermission {
20 ManageUsers,
22 ManageVerified,
24 ManageAuditLog,
26 ManageReports,
28 ManageMiscAppData,
30 ManageNotifications,
32 Banned,
34 ManageBans,
36 DeleteUsers,
38 ManageWarnings,
40 Seedling,
42 SeedlingPlus,
44 ManageProperties,
46 ManageOrganizations,
48 ManagePermissionsLists,
50 Administrator,
52}
53
54#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
55pub enum UserBadge {
56 Staff,
58}
59
60#[derive(Clone, Debug, Serialize, Deserialize, Validate, Default)]
61pub struct UserSettings {
62 #[serde(default)]
63 #[validate(max_length = 32)]
64 pub display_name: String,
65 #[serde(default)]
66 #[validate(max_length = 4096)]
67 pub biography: String,
68 #[serde(default)]
70 #[validate(max_items = 15)]
71 #[validate(unique_items)]
72 pub links: Vec<(String, String)>,
73 #[serde(default)]
75 #[validate(max_items = 5)]
76 #[validate(unique_items)]
77 pub contacts: Vec<(String, String)>,
78 #[serde(default)]
80 pub profile_theme: ThemePreference,
81}
82
83impl UserSettings {
84 pub fn verify_values(&self) -> Result<()> {
85 if let Err(e) = self.validate() {
86 return Err(Error::MiscError(e.to_string()));
87 }
88
89 Ok(())
90 }
91}
92
93#[derive(Clone, Debug, Serialize, Deserialize)]
94pub struct TetrattoLinkedAccount {
95 pub id: Id,
96 pub username: String,
97 pub added: u128,
98}
99
100#[derive(Clone, Debug, Serialize, Deserialize, Default)]
101pub struct UserLinkedAccounts {
102 #[serde(default)]
103 pub tetratto_multiple: Vec<TetrattoLinkedAccount>,
104}
105
106pub type Token = (String, String, u128);
108
109#[derive(Clone, Debug, Serialize, Deserialize)]
110pub struct User {
111 pub id: Id,
112 pub created: u128,
113 pub username: String,
114 pub password: String,
115 pub salt: String,
116 pub settings: UserSettings,
117 pub tokens: Vec<Token>,
118 pub permissions: Vec<UserPermission>,
119 pub is_verified: bool,
120 pub notification_count: usize,
121 #[serde(default)]
123 pub totp: String,
124 #[serde(default)]
126 pub recovery_codes: Vec<String>,
127 #[serde(default)]
129 pub stripe_id: String,
130 #[serde(default)]
132 pub ban_reason: String,
133 #[serde(default)]
135 pub ban_expire: usize,
136 #[serde(default)]
139 pub is_deactivated: bool,
140 #[serde(default)]
145 pub checkouts: Vec<String>,
146 #[serde(default)]
148 pub last_policy_consent: u128,
149 #[serde(default)]
151 pub linked_accounts: UserLinkedAccounts,
152 #[serde(default)]
154 pub badges: Vec<UserBadge>,
155 #[serde(default)]
157 pub principal_org: Id,
158 #[serde(default)]
161 pub org_as_tenant: bool,
162 #[serde(default)]
164 pub org_creation_credits: i32,
165 #[serde(default)]
167 pub org_user_register_credits: i32,
168 #[serde(default)]
172 pub is_super_verified: bool,
173}
174
175impl Default for User {
176 fn default() -> Self {
177 Self::new("<unknown>".to_string(), String::new())
178 }
179}
180
181impl User {
182 pub fn new(username: String, password: String) -> Self {
184 let salt = salt();
185 let password = hash_salted(password, salt.clone());
186 let created = unix_epoch_timestamp();
187
188 Self {
189 id: Id::Legacy(Id::new().as_usize()),
190 created,
191 username,
192 password,
193 salt,
194 settings: UserSettings::default(),
195 tokens: Vec::new(),
196 permissions: Vec::new(),
197 is_verified: false,
198 notification_count: 0,
199 totp: String::new(),
200 recovery_codes: Vec::new(),
201 stripe_id: String::new(),
202 ban_reason: String::new(),
203 is_deactivated: false,
204 ban_expire: 0,
205 checkouts: Vec::new(),
206 last_policy_consent: created,
207 linked_accounts: UserLinkedAccounts::default(),
208 badges: Vec::new(),
209 principal_org: Id::default(),
210 org_as_tenant: false,
211 org_creation_credits: 0,
212 org_user_register_credits: 0,
213 is_super_verified: false,
214 }
215 }
216
217 pub fn deleted() -> Self {
219 Self {
220 username: "<deleted>".to_string(),
221 id: Id::default(),
222 ..Default::default()
223 }
224 }
225
226 pub fn banned() -> Self {
228 Self {
229 username: "<banned>".to_string(),
230 id: Id::default(),
231 permissions: vec![UserPermission::Banned],
232 ..Default::default()
233 }
234 }
235
236 pub fn create_token(ip: &str) -> (String, Token) {
241 let unhashed = Id::new().to_string();
242 (
243 unhashed.clone(),
244 (
245 ip.to_string(),
246 tritools::encoding::hash(unhashed),
247 tritools::time::unix_epoch_timestamp(),
248 ),
249 )
250 }
251
252 pub fn check_password(&self, against: String) -> bool {
254 self.password == hash_salted(against, self.salt.clone())
255 }
256
257 pub fn totp(&self, issuer: Option<String>) -> Option<TOTP> {
259 if self.totp.is_empty() {
260 return None;
261 }
262
263 TOTP::new(
264 totp_rs::Algorithm::SHA1,
265 6,
266 1,
267 30,
268 self.totp.as_bytes().to_owned(),
269 Some(issuer.unwrap_or("tetratto!".to_string())),
270 self.username.clone(),
271 )
272 .ok()
273 }
274
275 pub fn clean(&mut self) {
277 self.password = String::new();
278 self.salt = String::new();
279
280 self.tokens = Vec::new();
281
282 self.recovery_codes = Vec::new();
283 self.totp = String::new();
284
285 self.settings = UserSettings::default();
286 self.stripe_id = String::new();
287 }
288}
289
290#[derive(Debug, Serialize, Deserialize)]
291pub struct Notification {
292 pub id: Id,
293 pub created: u128,
294 pub title: String,
295 pub content: String,
296 pub owner: Id,
297 pub read: bool,
298 pub tag: String,
299}
300
301impl Notification {
302 pub fn new(title: String, content: String, owner: Id) -> Self {
304 Self {
305 id: Id::new(),
306 created: unix_epoch_timestamp(),
307 title,
308 content,
309 owner,
310 read: false,
311 tag: String::new(),
312 }
313 }
314}
315
316#[derive(Serialize, Deserialize)]
317pub struct AuditLogEntry {
318 pub id: Id,
319 pub created: u128,
320 pub moderator: Id,
321 pub content: String,
322}
323
324impl AuditLogEntry {
325 pub fn new(moderator: Id, content: String) -> Self {
327 Self {
328 id: Id::new(),
329 created: unix_epoch_timestamp(),
330 moderator,
331 content,
332 }
333 }
334}
335
336#[derive(Serialize, Deserialize)]
337pub struct IpBan {
338 pub ip: String,
339 pub created: u128,
340 pub reason: String,
341 pub moderator: Id,
342}
343
344impl IpBan {
345 pub fn new(ip: String, moderator: Id, reason: String) -> Self {
347 Self {
348 ip,
349 created: unix_epoch_timestamp(),
350 reason,
351 moderator,
352 }
353 }
354}
355
356#[derive(Serialize, Deserialize)]
357pub struct UserWarning {
358 pub id: Id,
359 pub created: u128,
360 pub receiver: Id,
361 pub moderator: Id,
362 pub content: String,
363}
364
365impl UserWarning {
366 pub fn new(user: Id, moderator: Id, content: String) -> Self {
368 Self {
369 id: Id::new(),
370 created: unix_epoch_timestamp(),
371 receiver: user,
372 moderator,
373 content,
374 }
375 }
376}
377
378pub mod socket {
380 use serde::{Deserialize, Serialize, de::DeserializeOwned};
381
382 #[derive(Serialize, Deserialize, PartialEq, Eq)]
383 pub enum CrudMessageType {
384 Create,
385 Delete,
386 }
387
388 #[derive(Serialize, Deserialize, PartialEq, Eq)]
389 pub enum PacketType {
390 Ping,
392 Text,
394 Crud(CrudMessageType),
396 Key,
398 }
399
400 #[derive(Serialize, Deserialize, PartialEq, Eq)]
401 pub enum SocketMethod {
402 Headers,
404 Message,
406 Delete,
408 Forward(PacketType),
410 Misc(PacketType),
412 Packet(PacketType),
414 }
415
416 #[derive(Serialize, Deserialize)]
417 pub struct SocketMessage {
418 pub method: SocketMethod,
419 pub data: String,
420 }
421
422 impl SocketMessage {
423 pub fn data<T: DeserializeOwned>(&self) -> T {
424 serde_json::from_str(&self.data).unwrap()
425 }
426 }
427
428 #[derive(Serialize, Deserialize, PartialEq, Eq)]
430 pub struct TextMessage {
431 pub text: String,
432 }
433}
434
435pub mod properties {
437 use serde::{Deserialize, Serialize};
438 use tetratto_core2::model::id::Id;
439 use tritools::time::unix_epoch_timestamp;
440
441 #[derive(Serialize, Deserialize, PartialEq, Eq)]
442 pub enum Product {
443 Tetratto,
445 Organization,
449 UserReg,
453 Seedling,
457 UserVerification,
461 }
462
463 #[derive(Serialize, Deserialize)]
464 pub struct Property {
465 pub id: Id,
466 pub created: u128,
467 pub owner: Id,
468 pub name: String,
471 pub product: Product,
472 pub custom_domain: String,
473 }
474
475 impl Property {
476 pub fn new(owner: Id, name: String, product: Product) -> Self {
478 Self {
479 id: Id::new(),
480 created: unix_epoch_timestamp(),
481 owner,
482 name,
483 product,
484 custom_domain: String::new(),
485 }
486 }
487 }
488}
489
490pub mod organizations {
492 use serde::{Deserialize, Serialize};
493 use std::collections::HashMap;
494 use tetratto_core2::model::id::Id;
495 use tritools::time::unix_epoch_timestamp;
496
497 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
498 pub enum OrganizationRole {
499 Owner,
500 Custom(usize),
501 #[default]
502 Member,
503 }
504
505 #[derive(Debug, Clone, Serialize, Deserialize)]
506 pub struct Organization {
507 pub id: Id,
508 pub created: u128,
509 pub owner: Id,
510 pub name: String,
511 pub members: i32,
512 pub roles: HashMap<usize, String>,
513 }
514
515 impl Organization {
516 pub fn new(name: String, owner: Id) -> Self {
518 Self {
519 id: Id::new(),
520 created: unix_epoch_timestamp(),
521 owner,
522 name,
523 members: 0,
524 roles: HashMap::new(),
525 }
526 }
527 }
528
529 #[derive(Debug, Clone, Serialize, Deserialize)]
530 pub struct OrganizationMembership {
531 pub id: Id,
532 pub created: u128,
533 pub organization: Id,
534 pub owner: Id,
535 pub role: OrganizationRole,
536 }
537
538 impl OrganizationMembership {
539 pub fn new(organization: Id, owner: Id) -> Self {
541 Self {
542 id: Id::new(),
543 created: unix_epoch_timestamp(),
544 organization,
545 owner,
546 role: OrganizationRole::Member,
547 }
548 }
549 }
550
551 #[derive(Debug, Clone, Serialize, Deserialize)]
552 pub struct PermissionsList {
553 pub id: Id,
554 pub created: u128,
555 pub owner_org: Id,
556 pub name: String,
557 pub roles: Vec<usize>,
558 }
559
560 impl PermissionsList {
561 pub fn new(owner_org: Id, name: String) -> Self {
563 Self {
564 id: Id::new(),
565 created: unix_epoch_timestamp(),
566 owner_org,
567 name,
568 roles: Vec::new(),
569 }
570 }
571 }
572}