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(
33 db: &DbPool,
34 storage: &TenantStorageLayer,
35 search: &TenantSearchIndex,
36 events: &TenantEventPublisher,
37 folder: Folder,
38) -> anyhow::Result<()> {
39 let mut stack = VecDeque::new();
41
42 let document_box = folder.document_box.clone();
43
44 stack.push_back(RemoveStackItem::Folder(folder));
46
47 while let Some(item) = stack.pop_front() {
48 match item {
49 RemoveStackItem::Folder(folder) => {
50 let resolved = ResolvedFolder::resolve(db, &folder).await?;
52
53 stack.push_front(RemoveStackItem::EmptyFolder(folder));
55
56 for item in resolved.folders {
58 stack.push_front(RemoveStackItem::Folder(item));
59 }
60
61 for item in resolved.files {
62 stack.push_front(RemoveStackItem::File(item));
63 }
64
65 for item in resolved.links {
66 stack.push_front(RemoveStackItem::Link(item));
67 }
68 }
69 RemoveStackItem::EmptyFolder(folder) => {
70 internal_delete_folder(db, search, events, folder).await?;
71 }
72 RemoveStackItem::File(file) => {
73 delete_file(db, storage, search, events, file, document_box.clone()).await?;
74 }
75 RemoveStackItem::Link(link) => {
76 delete_link(db, search, events, link, document_box.clone()).await?;
77 }
78 }
79 }
80
81 Ok(())
82}
83
84async fn internal_delete_folder(
87 db: &DbPool,
88 search: &TenantSearchIndex,
89 events: &TenantEventPublisher,
90 folder: Folder,
91) -> anyhow::Result<()> {
92 search.delete_data(folder.id).await?;
94
95 let result = folder
96 .delete(db)
97 .await
98 .inspect_err(|error| tracing::error!(?error, "failed to delete folder"))?;
99
100 let document_box = folder.document_box.clone();
101
102 if result.rows_affected() < 1 {
104 return Ok(());
105 }
106
107 events.publish_event(TenantEventMessage::FolderDeleted(WithScope::new(
109 folder,
110 document_box,
111 )));
112
113 Ok(())
114}