mockforge_collab/
core_bridge.rs1#![allow(deprecated)]
10
11use crate::error::{CollabError, Result};
12use crate::models::TeamWorkspace;
13use mockforge_core::workspace::Workspace as CoreWorkspace;
14use mockforge_core::workspace_persistence::WorkspacePersistence;
15use serde_json::Value;
16use std::path::Path;
17use uuid::Uuid;
18
19pub struct CoreBridge {
21 persistence: WorkspacePersistence,
22}
23
24impl CoreBridge {
25 pub fn new<P: AsRef<Path>>(workspace_dir: P) -> Self {
27 Self {
28 persistence: WorkspacePersistence::new(workspace_dir),
29 }
30 }
31
32 pub fn team_to_core(&self, team_workspace: &TeamWorkspace) -> Result<CoreWorkspace> {
41 let workspace_json = &team_workspace.config;
43
44 let mut workspace: CoreWorkspace =
46 serde_json::from_value(workspace_json.clone()).map_err(|e| {
47 CollabError::Internal(format!("Failed to deserialize workspace from config: {e}"))
48 })?;
49
50 workspace.id = team_workspace.id.to_string();
53
54 workspace.name.clone_from(&team_workspace.name);
56 workspace.description.clone_from(&team_workspace.description);
57 workspace.updated_at = team_workspace.updated_at;
58
59 workspace.initialize_default_mock_environments();
61
62 Ok(workspace)
63 }
64
65 pub fn core_to_team(
74 &self,
75 core_workspace: &CoreWorkspace,
76 owner_id: Uuid,
77 ) -> Result<TeamWorkspace> {
78 let workspace_json = serde_json::to_value(core_workspace).map_err(|e| {
80 CollabError::Internal(format!("Failed to serialize workspace to JSON: {e}"))
81 })?;
82
83 let mut team_workspace = TeamWorkspace::new(core_workspace.name.clone(), owner_id);
85
86 team_workspace.id = Uuid::parse_str(&core_workspace.id).map_err(|e| {
88 CollabError::Internal(format!(
89 "Invalid workspace ID '{}': {}. Cannot convert to TeamWorkspace with corrupted ID.",
90 core_workspace.id, e
91 ))
92 })?;
93
94 team_workspace.description.clone_from(&core_workspace.description);
95 team_workspace.config = workspace_json;
96 team_workspace.created_at = core_workspace.created_at;
97 team_workspace.updated_at = core_workspace.updated_at;
98
99 Ok(team_workspace)
100 }
101
102 pub fn get_workspace_state(&self, team_workspace: &TeamWorkspace) -> Result<CoreWorkspace> {
110 self.team_to_core(team_workspace)
111 }
112
113 pub fn update_workspace_state(
121 &self,
122 team_workspace: &mut TeamWorkspace,
123 core_workspace: &CoreWorkspace,
124 ) -> Result<()> {
125 let workspace_json = serde_json::to_value(core_workspace)
127 .map_err(|e| CollabError::Internal(format!("Failed to serialize workspace: {e}")))?;
128
129 team_workspace.config = workspace_json;
131 team_workspace.updated_at = chrono::Utc::now();
132
133 Ok(())
134 }
135
136 pub async fn load_workspace_from_disk(
144 &self,
145 workspace_id: &str,
146 owner_id: Uuid,
147 ) -> Result<TeamWorkspace> {
148 let core_workspace = self
150 .persistence
151 .load_workspace(workspace_id)
152 .await
153 .map_err(|e| CollabError::Internal(format!("Failed to load workspace: {e}")))?;
154
155 self.core_to_team(&core_workspace, owner_id)
157 }
158
159 pub async fn save_workspace_to_disk(&self, team_workspace: &TeamWorkspace) -> Result<()> {
167 let core_workspace = self.team_to_core(team_workspace)?;
169
170 self.persistence
172 .save_workspace(&core_workspace)
173 .await
174 .map_err(|e| CollabError::Internal(format!("Failed to save workspace: {e}")))?;
175
176 Ok(())
177 }
178
179 #[allow(clippy::unused_async)]
187 pub async fn export_workspace_for_backup(
188 &self,
189 team_workspace: &TeamWorkspace,
190 ) -> Result<Value> {
191 let core_workspace = self.team_to_core(team_workspace)?;
193
194 serde_json::to_value(&core_workspace)
196 .map_err(|e| CollabError::Internal(format!("Failed to serialize for backup: {e}")))
197 }
198
199 #[allow(clippy::unused_async)]
207 pub async fn import_workspace_from_backup(
208 &self,
209 backup_data: &Value,
210 owner_id: Uuid,
211 new_name: Option<String>,
212 ) -> Result<TeamWorkspace> {
213 let mut core_workspace: CoreWorkspace = serde_json::from_value(backup_data.clone())
215 .map_err(|e| CollabError::Internal(format!("Failed to deserialize backup: {e}")))?;
216
217 if let Some(name) = new_name {
219 core_workspace.name = name;
220 }
221
222 core_workspace.id = Uuid::new_v4().to_string();
224 core_workspace.created_at = chrono::Utc::now();
225 core_workspace.updated_at = chrono::Utc::now();
226
227 self.core_to_team(&core_workspace, owner_id)
229 }
230
231 pub fn get_workspace_state_json(&self, team_workspace: &TeamWorkspace) -> Result<Value> {
239 let core_workspace = self.team_to_core(team_workspace)?;
240 serde_json::to_value(&core_workspace)
241 .map_err(|e| CollabError::Internal(format!("Failed to serialize state: {e}")))
242 }
243
244 pub fn update_workspace_state_from_json(
252 &self,
253 team_workspace: &mut TeamWorkspace,
254 state_json: &Value,
255 ) -> Result<()> {
256 let mut core_workspace: CoreWorkspace = serde_json::from_value(state_json.clone())
258 .map_err(|e| CollabError::Internal(format!("Failed to deserialize state JSON: {e}")))?;
259
260 core_workspace.id = team_workspace.id.to_string();
262 core_workspace.name.clone_from(&team_workspace.name);
263 core_workspace.description.clone_from(&team_workspace.description);
264
265 self.update_workspace_state(team_workspace, &core_workspace)
267 }
268
269 pub fn create_empty_workspace(&self, name: String, owner_id: Uuid) -> Result<TeamWorkspace> {
277 let core_workspace = CoreWorkspace::new(name);
278 self.core_to_team(&core_workspace, owner_id)
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use super::*;
285
286 #[test]
287 fn test_team_to_core_conversion() {
288 let bridge = CoreBridge::new("/tmp/test");
289 let owner_id = Uuid::new_v4();
290
291 let core_workspace = CoreWorkspace::new("Test Workspace".to_string());
293 let team_workspace = bridge.core_to_team(&core_workspace, owner_id).unwrap();
294
295 let restored = bridge.team_to_core(&team_workspace).unwrap();
297
298 assert_eq!(restored.name, core_workspace.name);
299 assert_eq!(restored.folders.len(), core_workspace.folders.len());
300 assert_eq!(restored.requests.len(), core_workspace.requests.len());
301 }
302
303 #[test]
304 fn test_state_json_roundtrip() {
305 let bridge = CoreBridge::new("/tmp/test");
306 let owner_id = Uuid::new_v4();
307
308 let core_workspace = CoreWorkspace::new("Test".to_string());
310 let mut team_workspace = bridge.core_to_team(&core_workspace, owner_id).unwrap();
311
312 let state_json = bridge.get_workspace_state_json(&team_workspace).unwrap();
314
315 bridge
317 .update_workspace_state_from_json(&mut team_workspace, &state_json)
318 .unwrap();
319
320 let restored = bridge.team_to_core(&team_workspace).unwrap();
322 assert_eq!(restored.name, "Test");
323 }
324
325 #[test]
326 fn test_invalid_uuid_returns_error() {
327 let bridge = CoreBridge::new("/tmp/test");
328 let owner_id = Uuid::new_v4();
329
330 let mut core_workspace = CoreWorkspace::new("Test Invalid UUID".to_string());
332 core_workspace.id = "not-a-valid-uuid".to_string();
333
334 let result = bridge.core_to_team(&core_workspace, owner_id);
336 assert!(result.is_err(), "Expected error for invalid UUID, but conversion succeeded");
337
338 if let Err(e) = result {
340 let error_msg = format!("{e}");
341 assert!(
342 error_msg.contains("not-a-valid-uuid"),
343 "Error message should contain the invalid UUID: {error_msg}",
344 );
345 }
346 }
347
348 #[test]
349 fn test_valid_uuid_conversion() {
350 let bridge = CoreBridge::new("/tmp/test");
351 let owner_id = Uuid::new_v4();
352 let workspace_uuid = Uuid::new_v4();
353
354 let mut core_workspace = CoreWorkspace::new("Test Valid UUID".to_string());
356 core_workspace.id = workspace_uuid.to_string();
357
358 let team_workspace = bridge.core_to_team(&core_workspace, owner_id).unwrap();
360
361 assert_eq!(team_workspace.id, workspace_uuid);
363 }
364}