Skip to main content

docbox_http/routes/
mod.rs

1use axum::{
2    Router,
3    routing::{delete, get, post},
4};
5
6use crate::error::{HttpCommonError, HttpStatusResult};
7
8use super::middleware::tenant::tenant_auth_middleware;
9
10pub mod admin;
11pub mod document_box;
12pub mod file;
13pub mod folder;
14pub mod link;
15pub mod task;
16pub mod utils;
17
18pub fn router<
19    const DIRECT_FILE_UPLOAD: bool,
20    const REPROCESS_OCTET_STREAM_FILES: bool,
21    const REBUILD_SEARCH_INDEX: bool,
22>() -> Router {
23    Router::new()
24        .nest(
25            "/admin",
26            admin_router::<REPROCESS_OCTET_STREAM_FILES, REBUILD_SEARCH_INDEX>(),
27        )
28        .nest("/box", document_box_router::<DIRECT_FILE_UPLOAD>())
29        .route("/options", get(utils::get_options))
30        .route("/health", get(utils::health))
31        .route("/server-details", get(utils::server_details))
32        .route("/webhook/s3", post(utils::webhook_s3))
33}
34
35/// Routes for /admin/
36pub fn admin_router<const REPROCESS_OCTET_STREAM_FILES: bool, const REBUILD_SEARCH_INDEX: bool>()
37-> Router {
38    let rebuild_search_index_tenant = if REBUILD_SEARCH_INDEX {
39        post(admin::rebuild_search_index_tenant)
40    } else {
41        post(unsupported)
42    };
43
44    let reprocess_octet_stream_files_tenant = if REPROCESS_OCTET_STREAM_FILES {
45        post(admin::reprocess_octet_stream_files_tenant)
46    } else {
47        post(unsupported)
48    };
49
50    Router::new()
51        // Routes that target the server as a whole
52        .route("/flush-db-cache", post(admin::flush_database_pool_cache))
53        .route("/flush-tenant-cache", post(admin::flush_tenant_cache))
54        .route(
55            "/purge-expired-presigned-tasks",
56            post(admin::http_purge_expired_presigned_tasks),
57        )
58        // Routes that require a target tenant
59        .merge(
60            Router::new()
61                .route("/tenant-stats", get(admin::tenant_stats))
62                .route("/rebuild-search-index", rebuild_search_index_tenant)
63                .route("/boxes", post(admin::tenant_boxes))
64                .route("/search", post(admin::search_tenant))
65                .route(
66                    "/reprocess_octet_stream_files_tenant",
67                    reprocess_octet_stream_files_tenant,
68                )
69                .nest(
70                    "/users",
71                    Router::new()
72                        .route("/", post(admin::list_users))
73                        .route("/{id}", delete(admin::delete_user)),
74                )
75                .layer(axum::middleware::from_fn(tenant_auth_middleware)),
76        )
77}
78
79/// Routes for /box/
80pub fn document_box_router<const DIRECT_FILE_UPLOAD: bool>() -> Router {
81    Router::new()
82        .route("/", post(document_box::create))
83        .nest(
84            "/{scope}",
85            Router::new()
86                .route("/", get(document_box::get).delete(document_box::delete))
87                .route("/stats", get(document_box::stats))
88                .route("/search", post(document_box::search))
89                .nest("/file", file_router::<DIRECT_FILE_UPLOAD>())
90                .nest("/task", task_router())
91                .nest("/link", link_router())
92                .nest("/folder", folder_router()),
93        )
94        // Layer to authorize requests
95        .layer(axum::middleware::from_fn(tenant_auth_middleware))
96}
97
98/// Routes for /box/:scope/folder/
99pub fn folder_router() -> Router {
100    Router::new().route("/", post(folder::create)).nest(
101        "/{folder_id}",
102        Router::new()
103            .route(
104                "/",
105                get(folder::get).put(folder::update).delete(folder::delete),
106            )
107            .route("/edit-history", get(folder::get_edit_history))
108            .route("/zip", post(folder::create_zip)),
109    )
110}
111
112/// Routes for /box/:scope/file/
113pub fn file_router<const DIRECT_FILE_UPLOAD: bool>() -> Router {
114    Router::new()
115        .route(
116            "/",
117            if DIRECT_FILE_UPLOAD {
118                post(file::upload)
119            } else {
120                post(unsupported)
121            },
122        )
123        .nest(
124            "/presigned",
125            Router::new()
126                .route("/", post(file::create_presigned))
127                .route("/{task_id}", get(file::get_presigned)),
128        )
129        .nest(
130            "/{file_id}",
131            Router::new()
132                .route("/", get(file::get).put(file::update).delete(file::delete))
133                .route("/raw", get(file::get_raw))
134                .route("/raw-presigned", post(file::get_raw_presigned))
135                // Named access endpoint, allows specifying some file name after the URL
136                // (Used to work around a Chromium bug which makes inline viewers not respect the filename)
137                .route("/raw/{*name}", get(file::get_raw_named))
138                .route("/children", get(file::get_children))
139                .route("/edit-history", get(file::get_edit_history))
140                .route("/search", post(file::search))
141                // Generated file instance
142                .nest(
143                    "/generated",
144                    Router::new().nest(
145                        "/{generated_type}",
146                        Router::new()
147                            .route("/", get(file::get_generated))
148                            .route("/raw", get(file::get_generated_raw))
149                            .route("/raw-presigned", post(file::get_generated_raw_presigned))
150                            // Named access endpoint, allows specifying some file name after the URL
151                            // (Used to work around a Chromium bug which makes inline viewers not respect the filename)
152                            .route("/raw/{*name}", get(file::get_generated_raw_named)),
153                    ),
154                ),
155        )
156}
157
158/// Routes for /box/:scope/task/
159pub fn task_router() -> Router {
160    Router::new().nest("/{task_id}", Router::new().route("/", get(task::get)))
161}
162
163/// Routes for /box/:scope/link/
164pub fn link_router() -> Router {
165    Router::new().route("/", post(link::create)).nest(
166        "/{link_id}",
167        Router::new()
168            .route("/", get(link::get).put(link::update).delete(link::delete))
169            .route("/metadata", get(link::get_metadata))
170            .route("/favicon", get(link::get_favicon))
171            .route("/image", get(link::get_image))
172            .route("/edit-history", get(link::get_edit_history)),
173    )
174}
175
176/// Fallback handler for routes that are unsupported
177pub async fn unsupported() -> HttpStatusResult {
178    Err(HttpCommonError::Unsupported.into())
179}