halldyll_memory_model/models/
user_model.rs

1//! User model and role management
2
3use crate::core::MemoryId;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6
7/// User roles for authorization
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9#[serde(rename_all = "lowercase")]
10pub enum UserRole {
11    /// Administrator with full access
12    Admin,
13    /// Standard user with personal access
14    User,
15    /// Service account
16    Service,
17    /// Read-only viewer
18    Viewer,
19}
20
21impl UserRole {
22    pub fn as_str(&self) -> &'static str {
23        match self {
24            Self::Admin => "admin",
25            Self::User => "user",
26            Self::Service => "service",
27            Self::Viewer => "viewer",
28        }
29    }
30}
31
32/// User account in the system
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct UserModel {
35    /// Unique user identifier
36    pub id: MemoryId,
37
38    /// Username (unique)
39    pub username: String,
40
41    /// User email (unique)
42    pub email: String,
43
44    /// User role
45    pub role: UserRole,
46
47    /// Whether the account is active
48    pub is_active: bool,
49
50    /// Account creation date
51    pub created_at: DateTime<Utc>,
52
53    /// Last login date
54    pub last_login_at: Option<DateTime<Utc>>,
55
56    /// Account updated date
57    pub updated_at: DateTime<Utc>,
58}
59
60impl UserModel {
61    /// Create a new user
62    pub fn new(username: impl Into<String>, email: impl Into<String>, role: UserRole) -> Self {
63        let now = Utc::now();
64        Self {
65            id: MemoryId::new(),
66            username: username.into(),
67            email: email.into(),
68            role,
69            is_active: true,
70            created_at: now,
71            last_login_at: None,
72            updated_at: now,
73        }
74    }
75
76    /// Check if user can perform an action based on role
77    pub fn can_perform(&self, action: UserAction) -> bool {
78        match self.role {
79            UserRole::Admin => true,
80            UserRole::User => matches!(action, UserAction::ReadOwn | UserAction::WriteOwn),
81            UserRole::Service => matches!(action, UserAction::ReadOwn | UserAction::WriteOwn),
82            UserRole::Viewer => matches!(action, UserAction::ReadOwn),
83        }
84    }
85}
86
87/// User actions for permission checking
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum UserAction {
90    ReadOwn,
91    WriteOwn,
92    ReadOther,
93    WriteOther,
94    DeleteOwn,
95    DeleteOther,
96    ManageUsers,
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_user_creation() {
105        let user = UserModel::new("john_doe", "john@example.com", UserRole::User);
106        assert_eq!(user.username, "john_doe");
107        assert_eq!(user.email, "john@example.com");
108        assert_eq!(user.role, UserRole::User);
109        assert!(user.is_active);
110    }
111
112    #[test]
113    fn test_user_permissions() {
114        let admin = UserModel::new("admin", "admin@example.com", UserRole::Admin);
115        assert!(admin.can_perform(UserAction::ManageUsers));
116
117        let user = UserModel::new("user", "user@example.com", UserRole::User);
118        assert!(user.can_perform(UserAction::ReadOwn));
119        assert!(!user.can_perform(UserAction::ManageUsers));
120
121        let viewer = UserModel::new("viewer", "viewer@example.com", UserRole::Viewer);
122        assert!(viewer.can_perform(UserAction::ReadOwn));
123        assert!(!viewer.can_perform(UserAction::WriteOwn));
124    }
125}