use std::{error::Error, sync::Arc}; use futures_util::{future::LocalBoxFuture, 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, }, settings::{AnySetting, GetSetting, GetSettingError}, user::{Bio, DisplayName, User, UserRepositoriesRequest}, value::{AnyValue, GetValueTyped}, }; use giterated_stack::{AuthenticatedUser, AuthorizedInstance, GiteratedStack, StackOperationState}; 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 .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_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 .map_err(|e| OperationError::Internal(e.to_string()))?; 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 .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(value) } .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 .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(), tree_rev: operation.rev, tree, }; Ok(info) } .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 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; 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>> { 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_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 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; 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 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; 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 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; 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 .map_err(|e| { OperationError::Internal(format!("error getting value: {}", e.to_string())) })?; 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 .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(value) } .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 .map_err(|e| OperationError::Internal(e.to_string())) } .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 .map_err(|e| OperationError::Internal(e.to_string())) } .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 .map_err(|e| OperationError::Internal(e.to_string())) } .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 .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(serde_json::from_value(raw_value.into_inner()) .map_err(|e| OperationError::Internal(e.to_string()))?) } .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 .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(serde_json::from_value(raw_value.into_inner()) .map_err(|e| OperationError::Internal(e.to_string()))?) } .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 .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(serde_json::from_value(raw_value.into_inner()) .map_err(|e| OperationError::Internal(e.to_string()))?) } .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 .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(serde_json::from_value(raw_value.into_inner()) .map_err(|e| OperationError::Internal(e.to_string()))?) } .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 .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(serde_json::from_value(raw_value.into_inner()) .map_err(|e| OperationError::Internal(e.to_string()))?) } .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 .map_err(|e| OperationError::Internal(e.to_string()))?; Ok(serde_json::from_value(raw_value.into_inner()) .map_err(|e| OperationError::Internal(e.to_string()))?) } .boxed_local() }