use std::error::Error; use futures_util::{future::BoxFuture, FutureExt}; use giterated_models::{ authenticated::UserAuthenticationToken, error::{GetValueError, InstanceError, OperationError, RepositoryError, UserError}, instance::{ AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest, }, object_backend::ObjectBackend, repository::{ Commit, DefaultBranch, Description, LatestCommit, Repository, RepositoryCommitBeforeRequest, RepositoryDiff, RepositoryDiffPatchRequest, RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest, RepositoryFileFromPathRequest, RepositoryFileInspectRequest, RepositoryInfoRequest, RepositorySummary, RepositoryView, Visibility, RepositoryCommitFromIdRequest, RepositoryLastCommitOfFileRequest, RepositoryStatisticsRequest, RepositoryStatistics, RepositoryBranchesRequest, RepositoryBranch, }, settings::{AnySetting, GetSetting, GetSettingError, SetSetting, SetSettingError}, user::{User, UserRepositoriesRequest}, value::{AnyValue, GetValue}, }; use giterated_stack::{AuthenticatedUser, AuthorizedInstance, BackendWrapper, StackOperationState}; use super::DatabaseBackend; pub fn user_get_repositories( object: &User, _operation: UserRepositoriesRequest, state: DatabaseBackend, operation_state: StackOperationState, requester: Option, ) -> BoxFuture<'static, Result, OperationError>> { let object = object.clone(); async move { let mut user_backend = state.user_backend.lock().await; let repositories_response = user_backend .repositories_for_user(&requester, &object) .await .map_err(|e| OperationError::Internal(e.to_string()))?; drop(user_backend); let mut repositories_backend = state.repository_backend.lock().await; let mut repositories = vec![]; for repository in repositories_response { if repositories_backend.exists(&requester, &repository.repository).await.map_err(|e| OperationError::Internal(e.to_string()))? { repositories.push(repository); } } Ok(repositories) } .boxed() } pub fn user_get_value( object: &User, operation: GetValue>, state: DatabaseBackend, ) -> BoxFuture<'static, Result, OperationError>> { let object = object.clone(); async move { let mut user_backend = state.user_backend.lock().await; let value = user_backend .get_value(&object, &operation.value_name) .await .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(value) } .boxed() } pub fn user_get_setting( object: &User, operation: GetSetting, state: DatabaseBackend, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let mut user_backend = state.user_backend.lock().await; let value = user_backend .get_setting(&object, &operation.setting_name) .await .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(value) } .boxed() } pub fn user_set_setting( object: &User, operation: SetSetting, state: DatabaseBackend, ) -> BoxFuture<'static, Result<(), OperationError>> { let object = object.clone(); async move { let mut user_backend = state.user_backend.lock().await; let value = user_backend .write_setting(&object, &operation.setting_name, &operation.value.0) .await .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(value) } .boxed() } pub fn repository_info( object: &Repository, operation: RepositoryInfoRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let mut object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let tree = repository_backend .repository_file_inspect( &requester, object.object(), &RepositoryFileInspectRequest { extra_metadata: operation.extra_metadata, path: operation.path, rev: operation.rev.clone(), }, ) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; let statistics = repository_backend .repository_get_statistics( &requester, object.object(), &RepositoryStatisticsRequest { rev: operation.rev.clone() }, ) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); let info = RepositoryView { name: object.object().name.clone(), owner: object.object().owner.clone(), description: object.get::(&operation_state).await.ok(), visibility: object .get::(&operation_state) .await .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?, default_branch: object .get::(&operation_state) .await .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?, // TODO: Can't be a simple get function, this needs to be returned alongside the tree as this differs depending on the rev and path. latest_commit: object.get::(&operation_state).await.ok(), stats: statistics, tree_rev: operation.rev, tree, }; Ok(info) } .boxed() } pub fn repository_get_statistics( object: &Repository, operation: RepositoryStatisticsRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let statistics = repository_backend .repository_get_statistics( &requester, object.object(), &RepositoryStatisticsRequest { rev: operation.rev, }, ) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(statistics) } .boxed() } pub fn repository_get_branches( object: &Repository, operation: RepositoryBranchesRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result, OperationError>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let branches = repository_backend .repository_get_branches( &requester, object.object(), &operation, ) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(branches) } .boxed() } pub fn repository_file_from_id( object: &Repository, operation: RepositoryFileFromIdRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let file = repository_backend .repository_file_from_id( &requester, object.object(), &RepositoryFileFromIdRequest(operation.0), ) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(file) } .boxed() } pub fn repository_file_from_path( object: &Repository, operation: RepositoryFileFromPathRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result<(RepositoryFile, String), OperationError>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let file = repository_backend .repository_file_from_path( &requester, object.object(), &RepositoryFileFromPathRequest { rev: operation.rev, path: operation.path, }, ) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(file) } .boxed() } pub fn repository_last_commit_of_file( object: &Repository, operation: RepositoryLastCommitOfFileRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let commit = repository_backend .repository_last_commit_of_file( &requester, object.object(), &RepositoryLastCommitOfFileRequest { start_commit: operation.start_commit, path: operation.path, }, ) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(commit) } .boxed() } pub fn repository_commit_by_id( object: &Repository, operation: RepositoryCommitFromIdRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let commit = repository_backend .repository_commit_from_id( &requester, object.object(), &RepositoryCommitFromIdRequest(operation.0), ) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(commit) } .boxed() } pub fn repository_diff( object: &Repository, operation: RepositoryDiffRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let diff = repository_backend .repository_diff(&requester, object.object(), &operation) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(diff) } .boxed() } pub fn repository_diff_patch( object: &Repository, operation: RepositoryDiffPatchRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let patch = repository_backend .repository_diff_patch(&requester, object.object(), &operation) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(patch) } .boxed() } pub fn repository_commit_before( object: &Repository, operation: RepositoryCommitBeforeRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let object = backend .get_object::(&object.to_string(), &operation_state) .await .unwrap(); let mut repository_backend = state.repository_backend.lock().await; let file = repository_backend .repository_commit_before(&requester, object.object(), &operation) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); Ok(file) } .boxed() } pub fn repository_get_value( object: &Repository, operation: GetValue>, state: DatabaseBackend, ) -> BoxFuture<'static, Result, OperationError>> { let object = object.clone(); async move { let mut repository_backend = state.repository_backend.lock().await; let value = repository_backend .get_value(&object, &operation.value_name) .await .map_err(|e| { OperationError::Internal(format!("error getting value: {}", e.to_string())) })?; Ok(value) } .boxed() } pub fn repository_get_setting( object: &Repository, operation: GetSetting, state: DatabaseBackend, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let mut repository_backend = state.repository_backend.lock().await; let value = repository_backend .get_setting(&object, &operation.setting_name) .await .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(value) } .boxed() } pub fn repository_set_setting( object: &Repository, operation: SetSetting, state: DatabaseBackend, ) -> BoxFuture<'static, Result<(), OperationError>> { let object = object.clone(); async move { let mut repository_backend = state.repository_backend.lock().await; let value = repository_backend .write_setting(&object, &operation.setting_name, &operation.value.0) .await .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(value) } .boxed() } pub fn instance_authentication_request( object: &Instance, operation: AuthenticationTokenRequest, state: DatabaseBackend, // Authorizes the request for SAME-INSTANCE _authorized_instance: AuthorizedInstance, ) -> BoxFuture<'static, Result>> { let object = object.clone(); async move { let mut backend = state.user_backend.lock().await; backend .login(&object, operation) .await .map_err(|e| OperationError::Internal(e.to_string())) } .boxed() } pub fn instance_registration_request( _object: &Instance, operation: RegisterAccountRequest, state: DatabaseBackend, // Authorizes the request for SAME-INSTANCE _authorized_instance: AuthorizedInstance, ) -> BoxFuture<'static, Result>> { async move { let mut backend = state.user_backend.lock().await; backend .register(operation) .await .map_err(|e| OperationError::Internal(e.to_string())) } .boxed() } pub fn instance_create_repository_request( _object: &Instance, operation: RepositoryCreateRequest, state: DatabaseBackend, requester: AuthenticatedUser, // Authorizes the request for SAME-INSTANCE _authorized_instance: AuthorizedInstance, ) -> BoxFuture<'static, Result>> { async move { let mut backend = state.repository_backend.lock().await; backend .create_repository(&requester, &operation) .await .map_err(|e| OperationError::Internal(e.to_string())) } .boxed() }