use std::sync::Arc; use futures_util::{future::LocalBoxFuture, FutureExt}; use giterated_models::{ authenticated::UserAuthenticationToken, error::{ GetValueError, InstanceError, IntoInternalError, OperationError, RepositoryError, UserError, }, instance::{ AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest, }, object_backend::ObjectBackend, repository::{ Commit, DefaultBranch, Description, LatestCommit, Repository, RepositoryBranch, RepositoryBranchesRequest, RepositoryCommitBeforeRequest, RepositoryCommitFromIdRequest, RepositoryDiff, RepositoryDiffPatchRequest, RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest, RepositoryFileFromPathRequest, RepositoryFileInspectRequest, RepositoryInfoRequest, RepositoryLastCommitOfFileRequest, RepositoryStatistics, RepositoryStatisticsRequest, RepositorySummary, RepositoryView, Visibility, }, settings::{GetSetting, GetSettingError}, user::{Bio, DisplayName, User, UserRepositoriesRequest}, value::{AnyValue, GetValueTyped}, }; use giterated_stack::{AuthenticatedUser, AuthorizedInstance, GiteratedStack, StackOperationState}; use serde_json::Value; use super::DatabaseBackend; pub fn user_get_repositories( object: &User, _operation: UserRepositoriesRequest, state: DatabaseBackend, _operation_state: StackOperationState, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; 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 .as_internal_error()? { repositories.push(repository); } } Ok(repositories) } .boxed_local() } pub fn user_get_value( object: &User, operation: GetValueTyped>, state: DatabaseBackend, ) -> LocalBoxFuture<'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 .as_internal_error()?; Ok(value) } .boxed_local() } pub fn user_get_setting( object: &User, operation: GetSetting, state: DatabaseBackend, ) -> LocalBoxFuture<'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 .as_internal_error()?; Ok(value.0) } .boxed_local() } pub fn repository_info( object: &Repository, operation: RepositoryInfoRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; let statistics = repository_backend .repository_get_statistics( &requester, object.object(), &RepositoryStatisticsRequest { rev: operation.rev.clone(), }, ) .await .as_internal_error()?; 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 .as_internal_error()?, default_branch: object .get::(&operation_state) .await .as_internal_error()?, // 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_local() } pub fn repository_get_statistics( object: &Repository, operation: RepositoryStatisticsRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(statistics) } .boxed_local() } pub fn repository_get_branches( object: &Repository, operation: RepositoryBranchesRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(branches) } .boxed_local() } pub fn repository_file_from_id( object: &Repository, operation: RepositoryFileFromIdRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(file) } .boxed_local() } pub fn repository_file_from_path( object: &Repository, operation: RepositoryFileFromPathRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(file) } .boxed_local() } pub fn repository_last_commit_of_file( object: &Repository, operation: RepositoryLastCommitOfFileRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(commit) } .boxed_local() } pub fn repository_commit_by_id( object: &Repository, operation: RepositoryCommitFromIdRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(commit) } .boxed_local() } pub fn repository_diff( object: &Repository, operation: RepositoryDiffRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(diff) } .boxed_local() } pub fn repository_diff_patch( object: &Repository, operation: RepositoryDiffPatchRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(patch) } .boxed_local() } pub fn repository_commit_before( object: &Repository, operation: RepositoryCommitBeforeRequest, state: DatabaseBackend, operation_state: StackOperationState, backend: Arc, requester: Option, ) -> LocalBoxFuture<'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 .as_internal_error()?; drop(repository_backend); Ok(file) } .boxed_local() } pub fn repository_get_value( object: &Repository, operation: GetValueTyped>, state: DatabaseBackend, ) -> LocalBoxFuture<'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 .as_internal_error()?; Ok(value) } .boxed_local() } pub fn repository_get_setting( object: &Repository, operation: GetSetting, state: DatabaseBackend, ) -> LocalBoxFuture<'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 .as_internal_error()?; Ok(value.0) } .boxed_local() } pub fn instance_authentication_request( object: &Instance, operation: AuthenticationTokenRequest, state: DatabaseBackend, // Authorizes the request for SAME-INSTANCE _authorized_instance: AuthorizedInstance, ) -> LocalBoxFuture<'static, Result>> { let object = object.clone(); async move { let mut backend = state.user_backend.lock().await; backend.login(&object, operation).await.as_internal_error() } .boxed_local() } pub fn instance_registration_request( _object: &Instance, operation: RegisterAccountRequest, state: DatabaseBackend, // Authorizes the request for SAME-INSTANCE _authorized_instance: AuthorizedInstance, ) -> LocalBoxFuture<'static, Result>> { async move { let mut backend = state.user_backend.lock().await; backend.register(operation).await.as_internal_error() } .boxed_local() } pub fn instance_create_repository_request( _object: &Instance, operation: RepositoryCreateRequest, state: DatabaseBackend, requester: AuthenticatedUser, // Authorizes the request for SAME-INSTANCE _authorized_instance: AuthorizedInstance, ) -> LocalBoxFuture<'static, Result>> { async move { let mut backend = state.repository_backend.lock().await; backend .create_repository(&requester, &operation) .await .as_internal_error() } .boxed_local() } pub fn user_get_value_display_name( object: &User, operation: GetValueTyped, state: DatabaseBackend, // _requester: AuthorizedUser, ) -> LocalBoxFuture<'static, Result>> { let object = object.clone(); async move { let mut backend = state.user_backend.lock().await; let raw_value = backend .get_value(&object, &operation.value_name) .await .as_internal_error()?; Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) } .boxed_local() } pub fn user_get_value_bio( object: &User, operation: GetValueTyped, state: DatabaseBackend, ) -> LocalBoxFuture<'static, Result>> { let object = object.clone(); async move { let mut backend = state.user_backend.lock().await; let raw_value = backend .get_value(&object, &operation.value_name) .await .as_internal_error()?; Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) } .boxed_local() } pub fn repository_get_value_description( object: &Repository, operation: GetValueTyped, state: DatabaseBackend, ) -> LocalBoxFuture<'static, Result>> { let object = object.clone(); async move { let mut backend = state.repository_backend.lock().await; let raw_value = backend .get_value(&object, &operation.value_name) .await .as_internal_error()?; Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) } .boxed_local() } pub fn repository_get_value_visibility( object: &Repository, operation: GetValueTyped, state: DatabaseBackend, ) -> LocalBoxFuture<'static, Result>> { let object = object.clone(); async move { let mut backend = state.repository_backend.lock().await; let raw_value = backend .get_value(&object, &operation.value_name) .await .as_internal_error()?; Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) } .boxed_local() } pub fn repository_get_default_branch( object: &Repository, operation: GetValueTyped, state: DatabaseBackend, ) -> LocalBoxFuture<'static, Result>> { let object = object.clone(); async move { let mut backend = state.repository_backend.lock().await; let raw_value = backend .get_value(&object, &operation.value_name) .await .as_internal_error()?; Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) } .boxed_local() } pub fn repository_get_latest_commit( object: &Repository, operation: GetValueTyped, state: DatabaseBackend, ) -> LocalBoxFuture<'static, Result>> { let object = object.clone(); async move { let mut backend = state.repository_backend.lock().await; let raw_value = backend .get_value(&object, &operation.value_name) .await .as_internal_error()?; Ok(serde_json::from_value(raw_value.into_inner()).as_internal_error()?) } .boxed_local() }