docbox_core/folders/
delete_folder.rs1use crate::files::delete_file::delete_file;
2use crate::links::delete_link::delete_link;
3use crate::{
4 events::{TenantEventMessage, TenantEventPublisher},
5 storage::TenantStorageLayer,
6};
7use docbox_database::{
8 DbPool,
9 models::{
10 document_box::WithScope,
11 file::File,
12 folder::{Folder, ResolvedFolder},
13 link::Link,
14 },
15};
16use docbox_search::TenantSearchIndex;
17use std::collections::VecDeque;
18
19pub enum RemoveStackItem {
21 Folder(Folder),
23 EmptyFolder(Folder),
26 File(File),
28 Link(Link),
30}
31
32pub async fn delete_folder(
35 db: &DbPool,
36 storage: &TenantStorageLayer,
37 search: &TenantSearchIndex,
38 events: &TenantEventPublisher,
39 folder: Folder,
40) -> anyhow::Result<()> {
41 let mut stack = VecDeque::new();
43
44 let document_box = folder.document_box.clone();
45
46 stack.push_back(RemoveStackItem::Folder(folder));
48
49 while let Some(item) = stack.pop_front() {
50 match item {
51 RemoveStackItem::Folder(folder) => {
52 let resolved = ResolvedFolder::resolve(db, &folder).await?;
54
55 stack.push_front(RemoveStackItem::EmptyFolder(folder));
57
58 for item in resolved.folders {
60 stack.push_front(RemoveStackItem::Folder(item));
61 }
62
63 for item in resolved.files {
64 stack.push_front(RemoveStackItem::File(item));
65 }
66
67 for item in resolved.links {
68 stack.push_front(RemoveStackItem::Link(item));
69 }
70 }
71 RemoveStackItem::EmptyFolder(folder) => {
72 internal_delete_folder(db, search, events, folder).await?;
73 }
74 RemoveStackItem::File(file) => {
75 delete_file(db, storage, search, events, file, document_box.clone()).await?;
76 }
77 RemoveStackItem::Link(link) => {
78 delete_link(db, search, events, link, document_box.clone()).await?;
79 }
80 }
81 }
82
83 Ok(())
84}
85
86async fn internal_delete_folder(
89 db: &DbPool,
90 search: &TenantSearchIndex,
91 events: &TenantEventPublisher,
92 folder: Folder,
93) -> anyhow::Result<()> {
94 search.delete_data(folder.id).await?;
96
97 let result = folder
98 .delete(db)
99 .await
100 .inspect_err(|error| tracing::error!(?error, "failed to delete folder"))?;
101
102 let document_box = folder.document_box.clone();
103
104 if result.rows_affected() < 1 {
106 return Ok(());
107 }
108
109 events.publish_event(TenantEventMessage::FolderDeleted(WithScope::new(
111 folder,
112 document_box,
113 )));
114
115 Ok(())
116}