1use crate::Lb;
2use crate::model::errors::{LbErrKind, LbResult};
3use crate::model::file_like::FileLike;
4use crate::model::tree_like::TreeLike;
5use crate::service::events::Actor;
6use uuid::Uuid;
7
8impl Lb {
9 #[instrument(level = "debug", skip(self), err(Debug))]
10 pub async fn pin_file(&self, id: Uuid) -> LbResult<()> {
11 let mut tx = self.begin_tx().await;
12 let db = tx.db();
13
14 let mut tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
15
16 let file = tree.maybe_find(&id).ok_or(LbErrKind::FileNonexistent)?;
17
18 if !file.is_document() {
19 return Err(LbErrKind::FileNotDocument.into());
20 }
21
22 if tree.calculate_deleted(&id)? {
23 return Err(LbErrKind::FileNonexistent.into());
24 }
25
26 if db.pinned_files.as_slice().contains(&id) {
27 return Ok(());
28 }
29
30 db.pinned_files.push(id)?;
31 tx.end();
32 self.events.meta_changed(Actor::User(None));
33 Ok(())
34 }
35
36 #[instrument(level = "debug", skip(self), err(Debug))]
37 pub async fn unpin_file(&self, id: Uuid) -> LbResult<()> {
38 let mut tx = self.begin_tx().await;
39 let db = tx.db();
40
41 let entries: Vec<Uuid> = db
42 .pinned_files
43 .as_slice()
44 .iter()
45 .filter(|pinned| **pinned != id)
46 .copied()
47 .collect();
48 if entries.len() == db.pinned_files.as_slice().len() {
49 return Ok(());
50 }
51
52 db.pinned_files.clear()?;
53 for entry in entries {
54 db.pinned_files.push(entry)?;
55 }
56 tx.end();
57 self.events.meta_changed(Actor::User(None));
58
59 Ok(())
60 }
61
62 #[instrument(level = "debug", skip(self), err(Debug))]
63 pub async fn list_pinned(&self) -> LbResult<Vec<Uuid>> {
64 let db = self.ro_tx().await;
65 let db = db.db();
66
67 let mut tree = (&db.base_metadata).to_staged(&db.local_metadata).to_lazy();
68
69 let mut result = Vec::new();
70 for id in db.pinned_files.as_slice().iter() {
71 if tree.maybe_find(id).is_none() {
72 continue;
73 }
74 if tree.calculate_deleted(id)? {
75 continue;
76 }
77 if tree.in_pending_share(id)? {
78 continue;
79 }
80 result.push(*id);
81 }
82
83 Ok(result)
84 }
85}