1use crate::LocalLb;
2use crate::model::access_info::UserAccessMode;
3use crate::model::errors::{LbErrKind, LbResult};
4use crate::model::file::File;
5use crate::model::file_like::FileLike;
6use crate::model::file_metadata::{FileType, Owner};
7use crate::model::filename::MAX_FILENAME_LENGTH;
8use crate::model::symkey;
9use crate::model::tree_like::TreeLike;
10use crate::service::events::Actor;
11use std::iter;
12use uuid::Uuid;
13
14impl LocalLb {
15 #[instrument(level = "debug", skip(self), err(Debug))]
16 pub async fn create_file(
17 &self, name: &str, parent: &Uuid, file_type: FileType,
18 ) -> LbResult<File> {
19 let mut tx = self.begin_tx().await;
20 let db = tx.db();
21
22 if name.len() > MAX_FILENAME_LENGTH {
24 return Err(LbErrKind::FileNameTooLong.into());
25 }
26 let mut tree = (&db.base_metadata)
27 .to_staged(&mut db.local_metadata)
28 .to_lazy();
29
30 let id = tree.create(
31 Uuid::new_v4(),
32 symkey::generate_key(),
33 parent,
34 name,
35 file_type,
36 &self.keychain,
37 )?;
38
39 let ui_file = tree.decrypt(&self.keychain, &id, &db.pub_key_lookup)?;
40
41 tx.end();
42
43 self.events.meta_changed(Actor::User);
44 Ok(ui_file)
45 }
46
47 #[instrument(level = "debug", skip(self), err(Debug))]
48 pub async fn rename_file(&self, id: &Uuid, new_name: &str) -> LbResult<()> {
49 let mut tx = self.begin_tx().await;
50 let db = tx.db();
51
52 if new_name.len() > MAX_FILENAME_LENGTH {
53 return Err(LbErrKind::FileNameTooLong.into());
54 }
55 let mut tree = (&db.base_metadata)
56 .to_staged(&mut db.local_metadata)
57 .to_lazy();
58
59 let id = &tree.linked_by(id)?.unwrap_or(*id);
60
61 tree.rename(id, new_name, &self.keychain)?;
62
63 tx.end();
64
65 self.events.meta_changed(Actor::User);
66
67 Ok(())
68 }
69
70 #[instrument(level = "debug", skip(self), err(Debug))]
71 pub async fn move_file(&self, id: &Uuid, new_parent: &Uuid) -> LbResult<()> {
72 let mut tx = self.begin_tx().await;
73 let db = tx.db();
74
75 let mut tree = (&db.base_metadata)
76 .to_staged(&mut db.local_metadata)
77 .to_lazy();
78
79 let id = &tree.linked_by(id)?.unwrap_or(*id);
80
81 tree.move_file(id, new_parent, &self.keychain)?;
82 tx.end();
83
84 self.events.meta_changed(Actor::User);
85
86 Ok(())
87 }
88
89 #[instrument(level = "debug", skip(self), err(Debug))]
90 pub async fn delete(&self, id: &Uuid) -> LbResult<()> {
91 let mut tx = self.begin_tx().await;
92 let db = tx.db();
93
94 let mut tree = (&db.base_metadata)
95 .to_staged(&mut db.local_metadata)
96 .to_lazy();
97
98 let id = &tree.linked_by(id)?.unwrap_or(*id);
99
100 tree.delete(id, &self.keychain)?;
101
102 tx.end();
103
104 self.events.meta_changed(Actor::User);
105
106 Ok(())
107 }
108
109 #[instrument(level = "debug", skip(self), err(Debug))]
111 pub async fn root(&self) -> LbResult<File> {
112 let tx = self.ro_tx().await;
113 let db = tx.db();
114
115 let mut tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
116
117 let root_id = db.root.get().ok_or(LbErrKind::RootNonexistent)?;
118
119 let root = tree.decrypt(&self.keychain, root_id, &db.pub_key_lookup)?;
120
121 Ok(root)
122 }
123
124 #[instrument(level = "debug", skip(self), err(Debug))]
125 pub async fn list_metadatas(&self) -> LbResult<Vec<File>> {
126 let tx = self.ro_tx().await;
127 let db = tx.db();
128
129 let mut tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
130
131 let ids = tree.ids().into_iter();
132
133 tree.decrypt_all(&self.keychain, ids, &db.pub_key_lookup, true)
134 }
135
136 #[instrument(level = "debug", skip(self), err(Debug))]
137 pub async fn get_children(&self, id: &Uuid) -> LbResult<Vec<File>> {
138 let tx = self.ro_tx().await;
139 let db = tx.db();
140
141 let mut tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
142
143 let ids = tree.children_using_links(id)?.into_iter();
144
145 tree.decrypt_all(&self.keychain, ids, &db.pub_key_lookup, true)
146 }
147
148 #[instrument(level = "debug", skip(self), err(Debug))]
149 pub async fn get_and_get_children_recursively(&self, id: &Uuid) -> LbResult<Vec<File>> {
150 let tx = self.ro_tx().await;
151 let db = tx.db();
152
153 let mut tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
154
155 let descendants = tree.descendants_using_links(id)?;
156
157 tree.decrypt_all(
158 &self.keychain,
159 descendants.into_iter().chain(iter::once(*id)),
160 &db.pub_key_lookup,
161 true,
162 )
163 }
164
165 #[instrument(level = "debug", skip(self), err(Debug))]
166 pub async fn get_file_by_id(&self, id: Uuid) -> LbResult<File> {
167 let tx = self.ro_tx().await;
168 let db = tx.db();
169
170 let mut tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
171
172 if tree.calculate_deleted(&id)? {
173 return Err(LbErrKind::FileNonexistent.into());
174 }
175 if tree.access_mode(Owner(self.keychain.get_pk()?), &id)? < Some(UserAccessMode::Read) {
176 return Err(LbErrKind::FileNonexistent.into());
177 }
178
179 let file = tree.decrypt(&self.keychain, &id, &db.pub_key_lookup)?;
180
181 Ok(file)
182 }
183
184 #[instrument(level = "debug", skip(self), err(Debug))]
185 pub async fn get_file_link_url(&self, id: Uuid) -> LbResult<String> {
186 let tx = self.ro_tx().await;
187 let db = tx.db();
188
189 let tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
190
191 let id = tree.find(&id)?.id();
193
194 let account = self.get_account()?;
195 let link_url = match account.api_url.as_str() {
196 "https://api.prod.lockbook.net" => "https://app.lockbook.net",
198 other => other,
199 };
200
201 Ok(format!("{}/open/{}", link_url, id))
202 }
203
204 pub async fn local_changes(&self) -> Vec<Uuid> {
205 let tx = self.ro_tx().await;
206 let db = tx.db();
207 db.local_metadata.get().keys().copied().collect()
208 }
209}