1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, sqlx::Type)]
9#[sqlx(type_name = "user_role", rename_all = "lowercase")]
10#[serde(rename_all = "lowercase")]
11pub enum UserRole {
12 Admin,
14 Editor,
16 Viewer,
18}
19
20impl UserRole {
21 pub fn is_admin(&self) -> bool {
23 matches!(self, UserRole::Admin)
24 }
25
26 pub fn can_edit(&self) -> bool {
28 matches!(self, UserRole::Admin | UserRole::Editor)
29 }
30
31 pub fn can_view(&self) -> bool {
33 true }
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
39pub struct User {
40 pub id: Uuid,
42 pub username: String,
44 pub email: String,
46 #[serde(skip_serializing)]
48 pub password_hash: String,
49 pub display_name: Option<String>,
51 pub avatar_url: Option<String>,
53 pub created_at: DateTime<Utc>,
55 pub updated_at: DateTime<Utc>,
57 pub is_active: bool,
59}
60
61impl User {
62 pub fn new(username: String, email: String, password_hash: String) -> Self {
64 let now = Utc::now();
65 Self {
66 id: Uuid::new_v4(),
67 username,
68 email,
69 password_hash,
70 display_name: None,
71 avatar_url: None,
72 created_at: now,
73 updated_at: now,
74 is_active: true,
75 }
76 }
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
81pub struct TeamWorkspace {
82 pub id: Uuid,
84 pub name: String,
86 pub description: Option<String>,
88 pub owner_id: Uuid,
90 pub config: serde_json::Value,
92 pub version: i64,
94 pub created_at: DateTime<Utc>,
96 pub updated_at: DateTime<Utc>,
98 pub is_archived: bool,
100}
101
102impl TeamWorkspace {
103 pub fn new(name: String, owner_id: Uuid) -> Self {
105 let now = Utc::now();
106 Self {
107 id: Uuid::new_v4(),
108 name,
109 description: None,
110 owner_id,
111 config: serde_json::json!({}),
112 version: 1,
113 created_at: now,
114 updated_at: now,
115 is_archived: false,
116 }
117 }
118}
119
120#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
122pub struct WorkspaceMember {
123 pub id: Uuid,
125 pub workspace_id: Uuid,
127 pub user_id: Uuid,
129 pub role: UserRole,
131 pub joined_at: DateTime<Utc>,
133 pub last_activity: DateTime<Utc>,
135}
136
137impl WorkspaceMember {
138 pub fn new(workspace_id: Uuid, user_id: Uuid, role: UserRole) -> Self {
140 let now = Utc::now();
141 Self {
142 id: Uuid::new_v4(),
143 workspace_id,
144 user_id,
145 role,
146 joined_at: now,
147 last_activity: now,
148 }
149 }
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
154pub struct WorkspaceInvitation {
155 pub id: Uuid,
157 pub workspace_id: Uuid,
159 pub email: String,
161 pub role: UserRole,
163 pub invited_by: Uuid,
165 pub token: String,
167 pub expires_at: DateTime<Utc>,
169 pub created_at: DateTime<Utc>,
171 pub accepted: bool,
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct ActiveSession {
178 pub user_id: Uuid,
180 pub workspace_id: Uuid,
182 pub session_id: Uuid,
184 pub connected_at: DateTime<Utc>,
186 pub last_activity: DateTime<Utc>,
188 pub cursor: Option<CursorPosition>,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct CursorPosition {
195 pub resource: String,
197 pub line: Option<u32>,
199 pub column: Option<u32>,
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206
207 #[test]
208 fn test_user_role_permissions() {
209 assert!(UserRole::Admin.is_admin());
210 assert!(UserRole::Admin.can_edit());
211 assert!(UserRole::Admin.can_view());
212
213 assert!(!UserRole::Editor.is_admin());
214 assert!(UserRole::Editor.can_edit());
215 assert!(UserRole::Editor.can_view());
216
217 assert!(!UserRole::Viewer.is_admin());
218 assert!(!UserRole::Viewer.can_edit());
219 assert!(UserRole::Viewer.can_view());
220 }
221
222 #[test]
223 fn test_user_creation() {
224 let user = User::new(
225 "testuser".to_string(),
226 "test@example.com".to_string(),
227 "hashed_password".to_string(),
228 );
229
230 assert_eq!(user.username, "testuser");
231 assert_eq!(user.email, "test@example.com");
232 assert!(user.is_active);
233 }
234
235 #[test]
236 fn test_workspace_creation() {
237 let owner_id = Uuid::new_v4();
238 let workspace = TeamWorkspace::new("Test Workspace".to_string(), owner_id);
239
240 assert_eq!(workspace.name, "Test Workspace");
241 assert_eq!(workspace.owner_id, owner_id);
242 assert_eq!(workspace.version, 1);
243 assert!(!workspace.is_archived);
244 }
245
246 #[test]
247 fn test_workspace_member_creation() {
248 let workspace_id = Uuid::new_v4();
249 let user_id = Uuid::new_v4();
250 let member = WorkspaceMember::new(workspace_id, user_id, UserRole::Editor);
251
252 assert_eq!(member.workspace_id, workspace_id);
253 assert_eq!(member.user_id, user_id);
254 assert_eq!(member.role, UserRole::Editor);
255 }
256}