1#![recursion_limit = "1024"]
18#![allow(unused_imports)]
19
20pub mod domain;
22pub mod infrastructure;
23pub mod application;
24pub mod presentation;
25pub mod seeders;
26pub mod exports;
27pub mod error;
29pub mod storage;
30pub mod auth;
31pub mod config;
32
33pub use error::{BucketError, BucketResult};
35pub use config::{BucketConfig, ConfigEnvError, S3Config, ServingConfig, ServingMode, StorageConfig};
36
37pub use storage::{ObjectMeta, ObjectStorage, LocalStorage};
41#[cfg(feature = "s3")]
42pub use storage::S3Storage;
43#[cfg(feature = "test-utils")]
44pub use storage::InMemoryStorage;
45
46pub use auth::{
48 ArcAuthzPolicy, AuthExtractor, AuthzDecision, AuthzPolicy, DefaultOwnerOnlyPolicy, HasOwnerId,
49};
50
51pub use application::service::{FileMeta, FileService};
53
54pub use presentation::http::{lookup_by_key as lookup_file_by_key, serving_router, ServingContext};
56pub use presentation::http::{
57 upload_router, UploadConfig, UploadContext, DEFAULT_CHUNK_BODY_LIMIT, DEFAULT_UPLOAD_BODY_LIMIT,
58};
59pub use domain::entity::*;
63
64pub use domain::state_machine::*;
66
67pub use domain::computed::{HasComputedFields, ComputedFieldValues};
69
70pub use domain::permission::{Action, FieldRestriction, PermissionChecker, PermissionError, PermissionResult};
72
73pub use infrastructure::persistence::*;
75
76pub use application::service::AccessLogService;
78pub use application::service::BucketService;
79pub use application::service::ContentHashService;
80pub use application::service::ConversionJobService;
81pub use application::service::FileCommentService;
82pub use application::service::FileLockService;
83pub use application::service::FileShareService;
84pub use application::service::FileVersionService;
85pub use application::service::ProcessingJobService;
86pub use application::service::StoredFileService;
87pub use application::service::ThumbnailService;
88pub use application::service::UploadSessionService;
89pub use application::service::UserQuotaService;
90
91pub use application::service::LockingService;
93pub use application::service::DeduplicationService;
94pub use application::service::MultipartUploadService;
95pub use application::service::ConversionService;
96#[allow(deprecated)]
97pub use application::service::CdnService;
98pub use application::service::VideoThumbnailService;
99pub use application::service::DocumentPreviewService;
100mod bucket_module; pub use bucket_module::RouterOptions;
102pub use application::validator::{ValidationError, ValidationResult};
105
106pub use application::triggers::*;
108
109pub use application::workflows::*;
111
112use std::sync::Arc;
113use axum::Router;
114use sqlx::PgPool;
115
116pub struct BucketModule {
129 pub(crate) access_log_service: Arc<AccessLogService>,
130 pub(crate) bucket_service: Arc<BucketService>,
131 pub(crate) content_hash_service: Arc<ContentHashService>,
132 pub(crate) conversion_job_service: Arc<ConversionJobService>,
133 pub(crate) file_comment_service: Arc<FileCommentService>,
134 pub(crate) file_lock_service: Arc<FileLockService>,
135 pub(crate) file_share_service: Arc<FileShareService>,
136 pub(crate) file_version_service: Arc<FileVersionService>,
137 pub(crate) processing_job_service: Arc<ProcessingJobService>,
138 pub(crate) stored_file_service: Arc<StoredFileService>,
139 pub(crate) thumbnail_service: Arc<ThumbnailService>,
140 pub(crate) upload_session_service: Arc<UploadSessionService>,
141 pub(crate) user_quota_service: Arc<UserQuotaService>,
142 pub locking_service: Arc<LockingService>,
145 pub deduplication_service: Arc<DeduplicationService>,
146 pub multipart_upload_service: Arc<MultipartUploadService>,
147 pub conversion_service: Arc<ConversionService>,
148 #[allow(deprecated)]
149 pub cdn_service: Arc<CdnService>,
150 pub video_thumbnail_service: Arc<VideoThumbnailService>,
151 pub document_preview_service: Arc<DocumentPreviewService>,
152 pub storage: Option<Arc<dyn ObjectStorage>>,
154 pub bucket_config: Option<Arc<BucketConfig>>,
156 pub file_service: Option<Arc<FileService>>,
158 pub stored_file_repository: Arc<infrastructure::persistence::StoredFileRepository>,
161 }
163
164impl BucketModule {
165 pub fn builder() -> BucketModuleBuilder {
167 BucketModuleBuilder::new()
168 }
169
170 pub fn all_crud_routes(&self) -> Router {
176 use presentation::http::{
177 create_bucket_routes,
178 create_content_hash_routes,
179 create_conversion_job_routes,
180 create_file_comment_routes,
181 create_file_lock_routes,
182 create_file_share_routes,
183 create_processing_job_routes,
184 create_stored_file_routes,
185 create_upload_session_routes,
186 create_user_quota_routes,
187 };
188
189 Router::new()
190 .merge(create_bucket_routes(self.bucket_service.clone()))
191 .merge(create_content_hash_routes(self.content_hash_service.clone()))
192 .merge(create_conversion_job_routes(self.conversion_job_service.clone()))
193 .merge(create_file_comment_routes(self.file_comment_service.clone()))
194 .merge(create_file_lock_routes(self.file_lock_service.clone()))
195 .merge(create_file_share_routes(self.file_share_service.clone()))
196 .merge(create_processing_job_routes(self.processing_job_service.clone()))
197 .merge(create_stored_file_routes(self.stored_file_service.clone()))
198 .merge(create_upload_session_routes(self.upload_session_service.clone()))
199 .merge(create_user_quota_routes(self.user_quota_service.clone()))
200 }
201
202 #[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
208 pub fn routes(&self) -> Router {
209 self.all_crud_routes()
210 }
211
212 pub fn readonly_routes(&self) -> Router {
218 use presentation::http::{
219 create_bucket_read_routes,
220 create_content_hash_read_routes,
221 create_conversion_job_read_routes,
222 create_file_comment_read_routes,
223 create_file_lock_read_routes,
224 create_file_share_read_routes,
225 create_processing_job_read_routes,
226 create_stored_file_read_routes,
227 create_upload_session_read_routes,
228 create_user_quota_read_routes,
229 };
230
231 Router::new()
232 .merge(create_bucket_read_routes(self.bucket_service.clone()))
233 .merge(create_content_hash_read_routes(self.content_hash_service.clone()))
234 .merge(create_conversion_job_read_routes(self.conversion_job_service.clone()))
235 .merge(create_file_comment_read_routes(self.file_comment_service.clone()))
236 .merge(create_file_lock_read_routes(self.file_lock_service.clone()))
237 .merge(create_file_share_read_routes(self.file_share_service.clone()))
238 .merge(create_processing_job_read_routes(self.processing_job_service.clone()))
239 .merge(create_stored_file_read_routes(self.stored_file_service.clone()))
240 .merge(create_upload_session_read_routes(self.upload_session_service.clone()))
241 .merge(create_user_quota_read_routes(self.user_quota_service.clone()))
242 }
243
244 pub fn upload_context(&self) -> Option<UploadContext> {
252 Some(UploadContext {
253 file_service: self.file_service.clone()?,
254 multipart_service: self.multipart_upload_service.clone(),
255 bucket_service: self.bucket_service.clone(),
256 storage: self.storage.clone()?,
257 })
258 }
259 }
261
262pub struct BucketModuleBuilder {
264 db_pool: Option<PgPool>,
265 storage: Option<Arc<dyn ObjectStorage>>,
268 bucket_config: Option<BucketConfig>,
269 }
271
272impl BucketModuleBuilder {
273 pub fn new() -> Self {
275 Self {
276 db_pool: None,
277 storage: None,
279 bucket_config: None,
280 }
282 }
283
284 pub fn with_database(mut self, pool: PgPool) -> Self {
286 self.db_pool = Some(pool);
287 self
288 }
289
290 pub fn with_config(mut self, config: BucketConfig) -> Self {
295 self.bucket_config = Some(config);
296 self
297 }
298
299 pub fn with_storage(mut self, storage: Arc<dyn ObjectStorage>) -> Self {
301 self.storage = Some(storage);
302 self
303 }
304
305 pub fn build(self) -> anyhow::Result<BucketModule> {
309 let db_pool = self.db_pool
310 .ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;
311
312 let access_log_repository = Arc::new(AccessLogRepository::new(db_pool.clone()));
314 let access_log_service = Arc::new(AccessLogService::with_repository(access_log_repository.clone()));
315
316 let bucket_repository = Arc::new(BucketRepository::new(db_pool.clone()));
318 let bucket_service = Arc::new(BucketService::with_repository(bucket_repository.clone()));
319
320 let content_hash_repository = Arc::new(ContentHashRepository::new(db_pool.clone()));
322 let content_hash_service = Arc::new(ContentHashService::with_repository(content_hash_repository.clone()));
323
324 let conversion_job_repository = Arc::new(ConversionJobRepository::new(db_pool.clone()));
326 let conversion_job_service = Arc::new(ConversionJobService::with_repository(conversion_job_repository.clone()));
327
328 let file_comment_repository = Arc::new(FileCommentRepository::new(db_pool.clone()));
330 let file_comment_service = Arc::new(FileCommentService::with_repository(file_comment_repository.clone()));
331
332 let file_lock_repository = Arc::new(FileLockRepository::new(db_pool.clone()));
334 let file_lock_service = Arc::new(FileLockService::with_repository(file_lock_repository.clone()));
335
336 let file_share_repository = Arc::new(FileShareRepository::new(db_pool.clone()));
338 let file_share_service = Arc::new(FileShareService::with_repository(file_share_repository.clone()));
339
340 let file_version_repository = Arc::new(FileVersionRepository::new(db_pool.clone()));
342 let file_version_service = Arc::new(FileVersionService::with_repository(file_version_repository.clone()));
343
344 let processing_job_repository = Arc::new(ProcessingJobRepository::new(db_pool.clone()));
346 let processing_job_service = Arc::new(ProcessingJobService::with_repository(processing_job_repository.clone()));
347
348 let stored_file_repository = Arc::new(StoredFileRepository::new(db_pool.clone()));
350 let stored_file_service = Arc::new(StoredFileService::with_repository(stored_file_repository.clone()));
351
352 let thumbnail_repository = Arc::new(ThumbnailRepository::new(db_pool.clone()));
354 let thumbnail_service = Arc::new(ThumbnailService::with_repository(thumbnail_repository.clone()));
355
356 let upload_session_repository = Arc::new(UploadSessionRepository::new(db_pool.clone()));
358 let upload_session_service = Arc::new(UploadSessionService::with_repository(upload_session_repository.clone()));
359
360 let user_quota_repository = Arc::new(UserQuotaRepository::new(db_pool.clone()));
362 let user_quota_service = Arc::new(UserQuotaService::with_repository(user_quota_repository.clone()));
363
364 let locking_service = Arc::new(LockingService::new(
367 file_lock_repository, stored_file_repository.clone(),
368 ));
369 let deduplication_service = Arc::new(DeduplicationService::new(
370 content_hash_repository, stored_file_repository.clone(),
371 ));
372 let multipart_upload_service = Arc::new(MultipartUploadService::new(
373 upload_session_repository, bucket_repository.clone(), user_quota_repository,
374 ));
375 let conversion_service = Arc::new(ConversionService::new(
376 conversion_job_repository, stored_file_repository.clone(),
377 ));
378 #[allow(deprecated)]
379 let cdn_service = Arc::new(CdnService::new(
380 stored_file_repository.clone(), bucket_repository,
381 ));
382 let video_thumbnail_service = Arc::new(VideoThumbnailService::new(
383 processing_job_repository.clone(), thumbnail_repository.clone(), stored_file_repository.clone(),
384 ));
385 let document_preview_service = Arc::new(DocumentPreviewService::new(
386 processing_job_repository, thumbnail_repository, stored_file_repository.clone(),
387 ));
388
389 let bucket_config = self.bucket_config.map(Arc::new);
391 let storage = self.storage;
392 let file_service = match (&storage, &bucket_config) {
393 (Some(s), Some(c)) => Some(Arc::new(FileService::new(
394 s.clone(),
395 stored_file_repository.clone(),
396 c.clone(),
397 ))),
398 _ => None,
399 };
400 Ok(BucketModule {
403 access_log_service,
404 bucket_service,
405 content_hash_service,
406 conversion_job_service,
407 file_comment_service,
408 file_lock_service,
409 file_share_service,
410 file_version_service,
411 processing_job_service,
412 stored_file_service,
413 thumbnail_service,
414 upload_session_service,
415 user_quota_service,
416 locking_service,
418 deduplication_service,
419 multipart_upload_service,
420 conversion_service,
421 cdn_service,
422 video_thumbnail_service,
423 document_preview_service,
424 storage,
425 bucket_config,
426 file_service,
427 stored_file_repository,
428 })
430 }
431}
432
433impl Default for BucketModuleBuilder {
434 fn default() -> Self {
435 Self::new()
436 }
437}