aboutsummaryrefslogtreecommitdiff
path: root/actions/src/remote_actions/mapping_manage/share_mapping.rs
blob: 5c77e532f895780ef31dc2406c47801e62938375 (plain) (blame)
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
use action_system::{action::ActionContext, macros::action_gen};
use serde::{Deserialize, Serialize};
use tcp_connection::error::TcpTargetError;
use vcs_data::{
    constants::VAULT_HOST_NAME,
    data::{local::workspace_analyzer::FromRelativePathBuf, sheet::SheetName},
};

use crate::{
    remote_actions::{
        auth_member, check_connection_instance, get_current_sheet_name, try_get_vault,
    },
    write_and_return,
};

#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct ShareMappingArguments {
    pub mappings: Vec<FromRelativePathBuf>,
    pub description: String,
    // None = current sheet,
    // Some(sheet_name) = other ref(public) sheet
    pub from_sheet: Option<SheetName>,
    pub to_sheet: SheetName,
}

#[derive(Serialize, Deserialize, Default)]
pub enum ShareMappingActionResult {
    Success,

    // Fail
    AuthorizeFailed(String),
    TargetSheetNotFound(SheetName),
    TargetIsSelf,
    MappingNotFound(FromRelativePathBuf),

    #[default]
    Unknown,
}

#[action_gen]
pub async fn share_mapping_action(
    ctx: ActionContext,
    args: ShareMappingArguments,
) -> Result<ShareMappingActionResult, TcpTargetError> {
    let instance = check_connection_instance(&ctx)?;

    // Auth Member
    let (member_id, _is_host_mode) = match auth_member(&ctx, instance).await {
        Ok(id) => id,
        Err(e) => {
            return Ok(ShareMappingActionResult::AuthorizeFailed(e.to_string()));
        }
    };

    // Check sheet
    let sheet_name = args.from_sheet.unwrap_or(
        get_current_sheet_name(&ctx, instance, &member_id, true)
            .await?
            .0,
    );

    if ctx.is_proc_on_remote() {
        let vault = try_get_vault(&ctx)?;
        let sheet = vault.sheet(&sheet_name).await?;

        // Tip: Because sheet_name may specify a sheet that does not belong to the user,
        // a secondary verification is required.

        // Check if the sheet holder is Some and matches the member_id or is the host
        let Some(holder) = sheet.holder() else {
            // If there's no holder, the sheet cannot be shared from
            write_and_return!(
                instance,
                ShareMappingActionResult::AuthorizeFailed("Sheet has no holder".to_string())
            );
        };

        // Verify the holder is either the current member or the host
        if holder != &member_id && holder != VAULT_HOST_NAME {
            write_and_return!(
                instance,
                ShareMappingActionResult::AuthorizeFailed(
                    "Not sheet holder or ref sheet".to_string()
                )
            );
        }

        let to_sheet_name = args.to_sheet;

        // Verify target sheet exists
        if !vault.sheet_names()?.contains(&to_sheet_name) {
            // Does not exist
            write_and_return!(
                instance,
                ShareMappingActionResult::TargetSheetNotFound(to_sheet_name.clone())
            );
        }

        // Verify sheet is not self
        if sheet_name == to_sheet_name {
            // Is self
            write_and_return!(instance, ShareMappingActionResult::TargetIsSelf);
        }

        // Verify all mappings are correct
        for mapping in args.mappings.iter() {
            if !sheet.mapping().contains_key(mapping) {
                // If any mapping is invalid, indicate failure
                write_and_return!(
                    instance,
                    ShareMappingActionResult::MappingNotFound(mapping.clone())
                );
            }
        }

        // Execute sharing logic
        sheet
            .share_mappings(&to_sheet_name, args.mappings, &member_id, args.description)
            .await?;

        // Sharing successful
        write_and_return!(instance, ShareMappingActionResult::Success);
    }

    if ctx.is_proc_on_local() {
        let result = instance
            .lock()
            .await
            .read::<ShareMappingActionResult>()
            .await?;
        return Ok(result);
    }

    Ok(ShareMappingActionResult::Success)
}