use std::path::PathBuf; use action_system::{action::ActionContext, macros::action_gen}; use serde::{Deserialize, Serialize}; use tcp_connection::error::TcpTargetError; use vcs_data::data::local::vault_modified::sign_vault_modified; use crate::actions::{ auth_member, check_connection_instance, get_current_sheet_name, try_get_vault, }; #[derive(Serialize, Deserialize)] pub enum ChangeVirtualFileEditRightResult { // Success Success { success_hold: Vec, success_throw: Vec, }, // Fail AuthorizeFailed(String), DoNothing, } #[derive(Serialize, Deserialize, PartialEq, Clone)] pub enum EditRightChangeBehaviour { Hold, Throw, } /// The server part only checks: /// 1. Whether the file exists /// 2. Whether the file has no holder /// If both conditions are met, send success information to the local client /// /// All version checks are handled locally #[action_gen] pub async fn change_virtual_file_edit_right_action( ctx: ActionContext, arguments: (Vec<(PathBuf, EditRightChangeBehaviour)>, bool), ) -> Result { let instance = check_connection_instance(&ctx)?; let (relative_paths, print_info) = arguments; // Auth Member let member_id = match auth_member(&ctx, instance).await { Ok(id) => id, Err(e) => { return Ok(ChangeVirtualFileEditRightResult::AuthorizeFailed( e.to_string(), )); } }; // Check sheet let sheet_name = get_current_sheet_name(&ctx, instance, &member_id).await?; if ctx.is_proc_on_remote() { let mut mut_instance = instance.lock().await; let mut success_hold: Vec = Vec::new(); let mut success_throw: Vec = Vec::new(); let vault = try_get_vault(&ctx)?; for (path, behaviour) in relative_paths { let Ok(sheet) = vault.sheet(&sheet_name).await else { continue; }; let Some(mapping) = sheet.mapping().get(&path) else { continue; }; let Ok(has_edit_right) = vault .has_virtual_file_edit_right(&member_id, &mapping.id) .await else { continue; }; // Hold file if !has_edit_right && behaviour == EditRightChangeBehaviour::Hold { match vault .grant_virtual_file_edit_right(&member_id, &mapping.id) .await { Ok(_) => { success_hold.push(path.clone()); } Err(_) => continue, } } else // Throw file if has_edit_right && behaviour == EditRightChangeBehaviour::Throw { match vault.revoke_virtual_file_edit_right(&mapping.id).await { Ok(_) => { success_throw.push(path.clone()); } Err(_) => continue, } } } // Write success list mut_instance .write_large_msgpack::<(Vec, Vec)>( (success_hold.clone(), success_throw.clone()), 4096u16, ) .await?; return Ok(ChangeVirtualFileEditRightResult::Success { success_hold, success_throw, }); } if ctx.is_proc_on_local() { let mut mut_instance = instance.lock().await; let (success_hold, success_throw) = mut_instance .read_large_msgpack::<(Vec, Vec)>(4096u16) .await?; // If there are any successful items, mark as modified if success_hold.len() + success_throw.len() > 0 { sign_vault_modified(true).await; } // Print info if print_info { success_hold .iter() .for_each(|s| println!("--> {}", s.display())); success_throw .iter() .for_each(|s| println!("<-- {}", s.display())); } return Ok(ChangeVirtualFileEditRightResult::Success { success_hold, success_throw, }); } Ok(ChangeVirtualFileEditRightResult::DoNothing) }