#![recursion_limit = "1024"]
#![allow(unused_imports)]
pub mod domain;
pub mod infrastructure;
pub mod application;
pub mod presentation;
pub mod seeders;
pub mod exports;
pub mod error;
pub mod storage;
pub mod auth;
pub mod config;
pub use error::{BucketError, BucketResult};
pub use config::{BucketConfig, ConfigEnvError, S3Config, ServingConfig, ServingMode, StorageConfig};
pub use storage::{ObjectMeta, ObjectStorage, LocalStorage};
#[cfg(feature = "s3")]
pub use storage::S3Storage;
#[cfg(feature = "test-utils")]
pub use storage::InMemoryStorage;
pub use auth::{
ArcAuthzPolicy, AuthExtractor, AuthzDecision, AuthzPolicy, DefaultOwnerOnlyPolicy, HasOwnerId,
};
pub use application::service::{FileMeta, FileService};
pub use presentation::http::{lookup_by_key as lookup_file_by_key, serving_router, ServingContext};
pub use presentation::http::{
upload_router, UploadConfig, UploadContext, DEFAULT_CHUNK_BODY_LIMIT, DEFAULT_UPLOAD_BODY_LIMIT,
};
pub use domain::entity::*;
pub use domain::state_machine::*;
pub use domain::computed::{HasComputedFields, ComputedFieldValues};
pub use domain::permission::{Action, FieldRestriction, PermissionChecker, PermissionError, PermissionResult};
pub use infrastructure::persistence::*;
pub use application::service::AccessLogService;
pub use application::service::BucketService;
pub use application::service::ContentHashService;
pub use application::service::ConversionJobService;
pub use application::service::FileCommentService;
pub use application::service::FileLockService;
pub use application::service::FileShareService;
pub use application::service::FileVersionService;
pub use application::service::ProcessingJobService;
pub use application::service::StoredFileService;
pub use application::service::ThumbnailService;
pub use application::service::UploadSessionService;
pub use application::service::UserQuotaService;
pub use application::service::LockingService;
pub use application::service::DeduplicationService;
pub use application::service::MultipartUploadService;
pub use application::service::ConversionService;
#[allow(deprecated)]
pub use application::service::CdnService;
pub use application::service::VideoThumbnailService;
pub use application::service::DocumentPreviewService;
mod bucket_module; pub use bucket_module::RouterOptions;
pub use application::validator::{ValidationError, ValidationResult};
pub use application::triggers::*;
pub use application::workflows::*;
use std::sync::Arc;
use axum::Router;
use sqlx::PgPool;
pub struct BucketModule {
#[allow(dead_code)]
pub(crate) access_log_service: Arc<AccessLogService>,
pub(crate) bucket_service: Arc<BucketService>,
pub(crate) content_hash_service: Arc<ContentHashService>,
pub(crate) conversion_job_service: Arc<ConversionJobService>,
pub(crate) file_comment_service: Arc<FileCommentService>,
pub(crate) file_lock_service: Arc<FileLockService>,
pub(crate) file_share_service: Arc<FileShareService>,
#[allow(dead_code)]
pub(crate) file_version_service: Arc<FileVersionService>,
pub(crate) processing_job_service: Arc<ProcessingJobService>,
pub(crate) stored_file_service: Arc<StoredFileService>,
#[allow(dead_code)]
pub(crate) thumbnail_service: Arc<ThumbnailService>,
pub(crate) upload_session_service: Arc<UploadSessionService>,
pub(crate) user_quota_service: Arc<UserQuotaService>,
pub locking_service: Arc<LockingService>,
pub deduplication_service: Arc<DeduplicationService>,
pub multipart_upload_service: Arc<MultipartUploadService>,
pub conversion_service: Arc<ConversionService>,
#[allow(deprecated)]
pub cdn_service: Arc<CdnService>,
pub video_thumbnail_service: Arc<VideoThumbnailService>,
pub document_preview_service: Arc<DocumentPreviewService>,
pub storage: Option<Arc<dyn ObjectStorage>>,
pub bucket_config: Option<Arc<BucketConfig>>,
pub file_service: Option<Arc<FileService>>,
pub stored_file_repository: Arc<infrastructure::persistence::StoredFileRepository>,
}
impl BucketModule {
pub fn builder() -> BucketModuleBuilder {
BucketModuleBuilder::new()
}
pub fn all_crud_routes(&self) -> Router {
use presentation::http::{
create_bucket_routes,
create_content_hash_routes,
create_conversion_job_routes,
create_file_comment_routes,
create_file_lock_routes,
create_file_share_routes,
create_processing_job_routes,
create_stored_file_routes,
create_upload_session_routes,
create_user_quota_routes,
};
Router::new()
.merge(create_bucket_routes(self.bucket_service.clone()))
.merge(create_content_hash_routes(self.content_hash_service.clone()))
.merge(create_conversion_job_routes(self.conversion_job_service.clone()))
.merge(create_file_comment_routes(self.file_comment_service.clone()))
.merge(create_file_lock_routes(self.file_lock_service.clone()))
.merge(create_file_share_routes(self.file_share_service.clone()))
.merge(create_processing_job_routes(self.processing_job_service.clone()))
.merge(create_stored_file_routes(self.stored_file_service.clone()))
.merge(create_upload_session_routes(self.upload_session_service.clone()))
.merge(create_user_quota_routes(self.user_quota_service.clone()))
}
#[deprecated(note = "mounts unvalidated generic CRUD; prefer readonly_routes() + validated writes, or all_crud_routes() for the full/unguarded surface")]
pub fn routes(&self) -> Router {
self.all_crud_routes()
}
pub fn readonly_routes(&self) -> Router {
use presentation::http::{
create_bucket_read_routes,
create_content_hash_read_routes,
create_conversion_job_read_routes,
create_file_comment_read_routes,
create_file_lock_read_routes,
create_file_share_read_routes,
create_processing_job_read_routes,
create_stored_file_read_routes,
create_upload_session_read_routes,
create_user_quota_read_routes,
};
Router::new()
.merge(create_bucket_read_routes(self.bucket_service.clone()))
.merge(create_content_hash_read_routes(self.content_hash_service.clone()))
.merge(create_conversion_job_read_routes(self.conversion_job_service.clone()))
.merge(create_file_comment_read_routes(self.file_comment_service.clone()))
.merge(create_file_lock_read_routes(self.file_lock_service.clone()))
.merge(create_file_share_read_routes(self.file_share_service.clone()))
.merge(create_processing_job_read_routes(self.processing_job_service.clone()))
.merge(create_stored_file_read_routes(self.stored_file_service.clone()))
.merge(create_upload_session_read_routes(self.upload_session_service.clone()))
.merge(create_user_quota_read_routes(self.user_quota_service.clone()))
}
pub fn upload_context(&self) -> Option<UploadContext> {
Some(UploadContext {
file_service: self.file_service.clone()?,
multipart_service: self.multipart_upload_service.clone(),
bucket_service: self.bucket_service.clone(),
storage: self.storage.clone()?,
})
}
}
pub struct BucketModuleBuilder {
db_pool: Option<PgPool>,
storage: Option<Arc<dyn ObjectStorage>>,
bucket_config: Option<BucketConfig>,
}
impl BucketModuleBuilder {
pub fn new() -> Self {
Self {
db_pool: None,
storage: None,
bucket_config: None,
}
}
pub fn with_database(mut self, pool: PgPool) -> Self {
self.db_pool = Some(pool);
self
}
pub fn with_config(mut self, config: BucketConfig) -> Self {
self.bucket_config = Some(config);
self
}
pub fn with_storage(mut self, storage: Arc<dyn ObjectStorage>) -> Self {
self.storage = Some(storage);
self
}
pub fn build(self) -> anyhow::Result<BucketModule> {
let db_pool = self.db_pool
.ok_or_else(|| anyhow::anyhow!("Database pool not configured"))?;
let access_log_repository = Arc::new(AccessLogRepository::new(db_pool.clone()));
let access_log_service = Arc::new(AccessLogService::with_repository(access_log_repository.clone()));
let bucket_repository = Arc::new(BucketRepository::new(db_pool.clone()));
let bucket_service = Arc::new(BucketService::with_repository(bucket_repository.clone()));
let content_hash_repository = Arc::new(ContentHashRepository::new(db_pool.clone()));
let content_hash_service = Arc::new(ContentHashService::with_repository(content_hash_repository.clone()));
let conversion_job_repository = Arc::new(ConversionJobRepository::new(db_pool.clone()));
let conversion_job_service = Arc::new(ConversionJobService::with_repository(conversion_job_repository.clone()));
let file_comment_repository = Arc::new(FileCommentRepository::new(db_pool.clone()));
let file_comment_service = Arc::new(FileCommentService::with_repository(file_comment_repository.clone()));
let file_lock_repository = Arc::new(FileLockRepository::new(db_pool.clone()));
let file_lock_service = Arc::new(FileLockService::with_repository(file_lock_repository.clone()));
let file_share_repository = Arc::new(FileShareRepository::new(db_pool.clone()));
let file_share_service = Arc::new(FileShareService::with_repository(file_share_repository.clone()));
let file_version_repository = Arc::new(FileVersionRepository::new(db_pool.clone()));
let file_version_service = Arc::new(FileVersionService::with_repository(file_version_repository.clone()));
let processing_job_repository = Arc::new(ProcessingJobRepository::new(db_pool.clone()));
let processing_job_service = Arc::new(ProcessingJobService::with_repository(processing_job_repository.clone()));
let stored_file_repository = Arc::new(StoredFileRepository::new(db_pool.clone()));
let stored_file_service = Arc::new(StoredFileService::with_repository(stored_file_repository.clone()));
let thumbnail_repository = Arc::new(ThumbnailRepository::new(db_pool.clone()));
let thumbnail_service = Arc::new(ThumbnailService::with_repository(thumbnail_repository.clone()));
let upload_session_repository = Arc::new(UploadSessionRepository::new(db_pool.clone()));
let upload_session_service = Arc::new(UploadSessionService::with_repository(upload_session_repository.clone()));
let user_quota_repository = Arc::new(UserQuotaRepository::new(db_pool.clone()));
let user_quota_service = Arc::new(UserQuotaService::with_repository(user_quota_repository.clone()));
let locking_service = Arc::new(LockingService::new(
file_lock_repository, stored_file_repository.clone(),
));
let deduplication_service = Arc::new(DeduplicationService::new(
content_hash_repository, stored_file_repository.clone(),
));
let multipart_upload_service = Arc::new(MultipartUploadService::new(
upload_session_repository, bucket_repository.clone(), user_quota_repository,
));
let conversion_service = Arc::new(ConversionService::new(
conversion_job_repository, stored_file_repository.clone(),
));
#[allow(deprecated)]
let cdn_service = Arc::new(CdnService::new(
stored_file_repository.clone(), bucket_repository,
));
let video_thumbnail_service = Arc::new(VideoThumbnailService::new(
processing_job_repository.clone(), thumbnail_repository.clone(), stored_file_repository.clone(),
));
let document_preview_service = Arc::new(DocumentPreviewService::new(
processing_job_repository, thumbnail_repository, stored_file_repository.clone(),
));
let bucket_config = self.bucket_config.map(Arc::new);
let storage = self.storage;
let file_service = match (&storage, &bucket_config) {
(Some(s), Some(c)) => Some(Arc::new(FileService::new(
s.clone(),
stored_file_repository.clone(),
c.clone(),
))),
_ => None,
};
Ok(BucketModule {
access_log_service,
bucket_service,
content_hash_service,
conversion_job_service,
file_comment_service,
file_lock_service,
file_share_service,
file_version_service,
processing_job_service,
stored_file_service,
thumbnail_service,
upload_session_service,
user_quota_service,
locking_service,
deduplication_service,
multipart_upload_service,
conversion_service,
cdn_service,
video_thumbnail_service,
document_preview_service,
storage,
bucket_config,
file_service,
stored_file_repository,
})
}
}
impl Default for BucketModuleBuilder {
fn default() -> Self {
Self::new()
}
}