diff options
| author | 魏曹先生 <1992414357@qq.com> | 2025-11-03 18:48:52 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2025-11-03 18:48:52 +0800 |
| commit | 5416c501e61e591cea85c1f30daa53818baa5f23 (patch) | |
| tree | 4d7d156404da206b064231890a1e4862dd911f92 /crates | |
| parent | ffb5805291343ba1cd4bb4f38788d9ce6e3e2ba6 (diff) | |
feat: Add sheet creation action
- Implement make_sheet_action for creating sheets
- Add sheet-related constants
- Update sheet data structures
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/vcs_actions/src/actions/sheet_actions.rs | 79 | ||||
| -rw-r--r-- | crates/vcs_data/src/constants.rs | 4 | ||||
| -rw-r--r-- | crates/vcs_data/src/data/sheet.rs | 39 |
3 files changed, 110 insertions, 12 deletions
diff --git a/crates/vcs_actions/src/actions/sheet_actions.rs b/crates/vcs_actions/src/actions/sheet_actions.rs index e69de29..b6ea51d 100644 --- a/crates/vcs_actions/src/actions/sheet_actions.rs +++ b/crates/vcs_actions/src/actions/sheet_actions.rs @@ -0,0 +1,79 @@ +use action_system::{action::ActionContext, macros::action_gen}; +use serde::{Deserialize, Serialize}; +use tcp_connection::error::TcpTargetError; +use vcs_data::data::sheet::SheetName; + +use crate::actions::{auth_member, check_connection_instance, try_get_vault}; + +#[derive(Default, Serialize, Deserialize)] +pub enum MakeSheetActionResult { + Success, + + // Fail + AuthorizeFailed(String), + SheetAlreadyExists, + SheetCreationFailed(String), + + #[default] + Unknown, +} + +/// Build a sheet with context +#[action_gen] +pub async fn make_sheet_action( + ctx: ActionContext, + sheet_name: SheetName, +) -> Result<MakeSheetActionResult, TcpTargetError> { + let instance = check_connection_instance(&ctx)?; + + // Auth Member + let member_id = match auth_member(&ctx, instance).await { + Ok(id) => id, + Err(e) => return Ok(MakeSheetActionResult::AuthorizeFailed(e.to_string())), + }; + + if ctx.is_proc_on_remote() { + let vault = try_get_vault(&ctx)?; + + // Check if the sheet already exists + if vault.sheet(&sheet_name).await.is_ok() { + instance + .lock() + .await + .write(MakeSheetActionResult::SheetAlreadyExists) + .await?; + return Ok(MakeSheetActionResult::SheetAlreadyExists); + } else { + // Create the sheet + match vault.create_sheet(&sheet_name, &member_id).await { + Ok(_) => { + instance + .lock() + .await + .write(MakeSheetActionResult::Success) + .await?; + return Ok(MakeSheetActionResult::Success); + } + Err(e) => { + instance + .lock() + .await + .write(MakeSheetActionResult::SheetCreationFailed(e.to_string())) + .await?; + return Ok(MakeSheetActionResult::SheetCreationFailed(e.to_string())); + } + } + } + } + + if ctx.is_proc_on_local() { + let result = instance + .lock() + .await + .read::<MakeSheetActionResult>() + .await?; + return Ok(result); + } + + Err(TcpTargetError::NoResult("No result.".to_string())) +} diff --git a/crates/vcs_data/src/constants.rs b/crates/vcs_data/src/constants.rs index cd6eaa3..1d17927 100644 --- a/crates/vcs_data/src/constants.rs +++ b/crates/vcs_data/src/constants.rs @@ -42,6 +42,7 @@ pub const SERVER_FILE_README: &str = "./README.md"; // Client pub const CLIENT_PATH_WORKSPACE_ROOT: &str = "./.jv/"; +pub const CLIENT_FOLDER_WORKSPACE_ROOT_NAME: &str = ".jv"; // Client - Workspace (Main) pub const CLIENT_FILE_WORKSPACE: &str = "./.jv/workspace.toml"; @@ -52,6 +53,9 @@ pub const CLIENT_FILE_LATEST_INFO: &str = "./.jv/latest.json"; // Client - Sheets pub const CLIENT_FILE_SHEET_COPY: &str = "./.jv/sheets/{sheet_name}.copy.json"; +// Client - Local Draft +pub const CLIENT_PATH_LOCAL_DRAFT: &str = "./.jv/drafts/{sheet_name}/"; + // Client - Other pub const CLIENT_FILE_IGNOREFILES: &str = "IGNORE_RULES.toml"; pub const CLIENT_FILE_README: &str = "./README.md"; diff --git a/crates/vcs_data/src/data/sheet.rs b/crates/vcs_data/src/data/sheet.rs index b558c0d..ce450a6 100644 --- a/crates/vcs_data/src/data/sheet.rs +++ b/crates/vcs_data/src/data/sheet.rs @@ -51,7 +51,7 @@ pub struct Sheet<'a> { #[derive(Default, Serialize, Deserialize, ConfigFile, Clone)] pub struct SheetData { /// The holder of the current sheet, who has full operation rights to the sheet mapping - pub(crate) holder: MemberId, + pub(crate) holder: Option<MemberId>, /// Inputs pub(crate) inputs: Vec<InputPackage>, @@ -66,8 +66,8 @@ impl<'a> Sheet<'a> { } /// Get the holder of this sheet - pub fn holder(&self) -> &MemberId { - &self.data.holder + pub fn holder(&self) -> Option<&MemberId> { + self.data.holder.as_ref() } /// Get the inputs of this sheet @@ -143,10 +143,11 @@ impl<'a> Sheet<'a> { /// Add (or Edit) a mapping entry to the sheet /// /// This operation performs safety checks to ensure the member has the right to add the mapping: - /// 1. If the virtual file ID doesn't exist in the vault, the mapping is added directly - /// 2. If the virtual file exists, check if the member has edit rights to the virtual file - /// 3. If member has edit rights, the mapping is not allowed to be modified and returns an error - /// 4. If member doesn't have edit rights, the mapping is allowed (member is giving up the file) + /// 1. The sheet must have a holder (member) to perform this operation + /// 2. If the virtual file ID doesn't exist in the vault, the mapping is added directly + /// 3. If the virtual file exists, check if the member has edit rights to the virtual file + /// 4. If member has edit rights, the mapping is not allowed to be modified and returns an error + /// 5. If member doesn't have edit rights, the mapping is allowed (member is giving up the file) /// /// Note: Full validation adds overhead - avoid frequent calls pub async fn add_mapping( @@ -161,10 +162,18 @@ impl<'a> Sheet<'a> { return Ok(()); } + // Check if the sheet has a holder + let Some(holder) = self.holder() else { + return Err(std::io::Error::new( + std::io::ErrorKind::PermissionDenied, + "This sheet has no holder", + )); + }; + // Check if the holder has edit rights to the virtual file match self .vault_reference - .has_virtual_file_edit_right(self.holder(), &virtual_file_id) + .has_virtual_file_edit_right(holder, &virtual_file_id) .await { Ok(false) => { @@ -191,9 +200,10 @@ impl<'a> Sheet<'a> { /// Remove a mapping entry from the sheet /// /// This operation performs safety checks to ensure the member has the right to remove the mapping: - /// 1. Member must NOT have edit rights to the virtual file to release it (ensuring clear ownership) - /// 2. If the virtual file doesn't exist, the mapping is removed but no ID is returned - /// 3. If member has no edit rights and the file exists, returns the removed virtual file ID + /// 1. The sheet must have a holder (member) to perform this operation + /// 2. Member must NOT have edit rights to the virtual file to release it (ensuring clear ownership) + /// 3. If the virtual file doesn't exist, the mapping is removed but no ID is returned + /// 4. If member has no edit rights and the file exists, returns the removed virtual file ID /// /// Note: Full validation adds overhead - avoid frequent calls pub async fn remove_mapping(&mut self, sheet_path: &SheetPathBuf) -> Option<VirtualFileId> { @@ -212,10 +222,15 @@ impl<'a> Sheet<'a> { return None; } + // Check if the sheet has a holder + let Some(holder) = self.holder() else { + return None; + }; + // Check if the holder has edit rights to the virtual file match self .vault_reference - .has_virtual_file_edit_right(self.holder(), virtual_file_id) + .has_virtual_file_edit_right(holder, virtual_file_id) .await { Ok(false) => { |
