summaryrefslogtreecommitdiff
path: root/crates/vcs_data/src/data/vault.rs
blob: 15be1e9db5ecfd58c513e6d5e088b6be43447ce3 (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
use std::{env::current_dir, path::PathBuf, sync::Arc};

use tokio::fs::create_dir_all;
use vcs_docs::docs::READMES_VAULT_README;

use crate::{
    constants::{
        REF_SHEET_NAME, SERVER_FILE_README, SERVER_FILE_VAULT, SERVER_PATH_MEMBER_PUB,
        SERVER_PATH_MEMBERS, SERVER_PATH_SHEETS, SERVER_PATH_VF_ROOT, VAULT_HOST_NAME,
    },
    current::{current_vault_path, find_vault_path},
    data::{member::Member, vault::config::VaultConfig},
};

pub mod config;
pub mod member;
pub mod service;
pub mod sheets;
pub mod virtual_file;

pub struct Vault {
    config: Arc<VaultConfig>,
    vault_path: PathBuf,
}

impl Vault {
    /// Get vault path
    pub fn vault_path(&self) -> &PathBuf {
        &self.vault_path
    }

    /// Initialize vault
    pub fn init(config: VaultConfig, vault_path: impl Into<PathBuf>) -> Option<Self> {
        let vault_path = find_vault_path(vault_path)?;
        Some(Self {
            config: Arc::new(config),
            vault_path,
        })
    }

    /// Initialize vault
    pub fn init_current_dir(config: VaultConfig) -> Option<Self> {
        let vault_path = current_vault_path()?;
        Some(Self {
            config: Arc::new(config),
            vault_path,
        })
    }

    /// Setup vault
    pub async fn setup_vault(
        vault_path: impl Into<PathBuf>,
        vault_name: impl AsRef<str>,
    ) -> Result<(), std::io::Error> {
        let vault_path: PathBuf = vault_path.into();

        // Ensure directory is empty
        if vault_path.exists() && vault_path.read_dir()?.next().is_some() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::DirectoryNotEmpty,
                "DirectoryNotEmpty",
            ));
        }

        // 1. Setup main config
        let config = VaultConfig::default();

        // NOTE:
        // Do not use the write_to method provided by the ConfigFile trait to store the Vault configuration file
        // Instead, use the PROFILES_VAULT content provided by the Documents Repository for writing

        // VaultConfig::write_to(&config, vault_path.join(SERVER_FILE_VAULT)).await?;
        let config_content = vcs_docs::docs::PROFILES_VAULT
            .replace("{vault_name}", vault_name.as_ref())
            .replace("{user_name}", whoami::username().as_str())
            .replace(
                "{date_format}",
                chrono::Local::now()
                    .format("%Y-%m-%d %H:%M")
                    .to_string()
                    .as_str(),
            )
            .replace("{vault_uuid}", &config.vault_uuid().to_string());
        tokio::fs::write(vault_path.join(SERVER_FILE_VAULT), config_content).await?;

        // 2. Setup sheets directory
        create_dir_all(vault_path.join(SERVER_PATH_SHEETS)).await?;

        // 3. Setup key directory
        create_dir_all(vault_path.join(SERVER_PATH_MEMBER_PUB)).await?;

        // 4. Setup member directory
        create_dir_all(vault_path.join(SERVER_PATH_MEMBERS)).await?;

        // 5. Setup storage directory
        create_dir_all(vault_path.join(SERVER_PATH_VF_ROOT)).await?;

        let Some(vault) = Vault::init(config, &vault_path) else {
            return Err(std::io::Error::other("Failed to initialize vault"));
        };

        // 6. Create host member
        vault
            .register_member_to_vault(Member::new(VAULT_HOST_NAME))
            .await?;

        // 7. Setup reference sheet
        vault
            .create_sheet(&REF_SHEET_NAME.to_string(), &VAULT_HOST_NAME.to_string())
            .await?;

        // Final, generate README.md
        let readme_content = READMES_VAULT_README;
        tokio::fs::write(vault_path.join(SERVER_FILE_README), readme_content).await?;

        Ok(())
    }

    /// Setup vault in current directory
    pub async fn setup_vault_current_dir(
        vault_name: impl AsRef<str>,
    ) -> Result<(), std::io::Error> {
        Self::setup_vault(current_dir()?, vault_name).await?;
        Ok(())
    }

    /// Get vault configuration
    pub fn config(&self) -> &Arc<VaultConfig> {
        &self.config
    }
}