summaryrefslogtreecommitdiff
path: root/crates/vcs_actions/src/actions/user_actions.rs
blob: febfeeb5dcce86c484a9a803d598dc0ba928f902 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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<PathBuf>,
        success_throw: Vec<PathBuf>,
    },

    // 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<ChangeVirtualFileEditRightResult, TcpTargetError> {
    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<PathBuf> = Vec::new();
        let mut success_throw: Vec<PathBuf> = 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<PathBuf>, Vec<PathBuf>)>(
                (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<PathBuf>, Vec<PathBuf>)>(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)
}