use crate::{parse_macaroon_editor_id, EntityType, Specifier}; use anyhow::{anyhow, Context, Result}; use fatcat_openapi::models; use fatcat_openapi::{ApiNoContext, ContextWrapperExt}; use swagger::{auth, AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; type FatcatApiContextType = swagger::make_context_ty!( ContextBuilder, EmptyContext, Option, XSpanIdString ); pub struct FatcatApiClient { pub api: Box>, pub rt: tokio::runtime::Runtime, pub api_token: Option, pub api_host: String, pub editor_id: Option, } impl FatcatApiClient { pub fn new(api_host: String, api_token: Option) -> Result { let auth_data = match api_token { Some(ref token) => Some(AuthData::Bearer(auth::Bearer { token: token.clone(), })), None => None, }; //info!("{:?}", auth_data); let context: FatcatApiContextType = swagger::make_context!( ContextBuilder, EmptyContext, auth_data, XSpanIdString::default() ); //let wrapped_client: swagger::ContextWrapper< let client = fatcat_openapi::client::Client::try_new(&api_host) .context("failed to create HTTP(S) client")?; let wrapped_client = Box::new(client.with_context(context)); let rt: tokio::runtime::Runtime = tokio::runtime::Runtime::new().expect("create tokio runtime"); let editor_id = match api_token { Some(ref token) => { Some(parse_macaroon_editor_id(token).context("parse API auth token")?) } None => None, }; Ok(FatcatApiClient { api: wrapped_client, rt, api_token, editor_id, api_host, }) } pub fn update_editgroup_submit( &mut self, editgroup_id: String, submit: bool, ) -> Result { let result = self .rt .block_on(self.api.get_editgroup(editgroup_id.clone())) .context("fetch editgroups")?; let eg = match result { fatcat_openapi::GetEditgroupResponse::Found(eg) => eg, other => { return Err(anyhow!("{:?}", other)) .with_context(|| format!("failed to fetch editgroup {}", editgroup_id)) } }; let result = self .rt .block_on( self.api .update_editgroup(editgroup_id.clone(), eg, Some(submit)), ) .context("submit editgroup")?; match result { fatcat_openapi::UpdateEditgroupResponse::UpdatedEditgroup(eg) => Ok(eg), other => Err(anyhow!("{:?}", other)) .with_context(|| format!("failed to submit editgroup {}", editgroup_id)), } } pub fn delete_entity( &mut self, specifier: Specifier, editgroup_id: String, ) -> Result { use Specifier::*; let specifier = specifier.into_entity_specifier(self)?; match specifier.clone() { Release(fcid) => match self .rt .block_on(self.api.delete_release(editgroup_id, fcid))? { fatcat_openapi::DeleteReleaseResponse::DeletedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, Work(fcid) => match self.rt.block_on(self.api.delete_work(editgroup_id, fcid))? { fatcat_openapi::DeleteWorkResponse::DeletedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, Container(fcid) => match self .rt .block_on(self.api.delete_container(editgroup_id, fcid))? { fatcat_openapi::DeleteContainerResponse::DeletedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, Creator(fcid) => match self .rt .block_on(self.api.delete_creator(editgroup_id, fcid))? { fatcat_openapi::DeleteCreatorResponse::DeletedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, File(fcid) => match self.rt.block_on(self.api.delete_file(editgroup_id, fcid))? { fatcat_openapi::DeleteFileResponse::DeletedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, FileSet(fcid) => match self .rt .block_on(self.api.delete_fileset(editgroup_id, fcid))? { fatcat_openapi::DeleteFilesetResponse::DeletedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, WebCapture(fcid) => match self .rt .block_on(self.api.delete_webcapture(editgroup_id, fcid))? { fatcat_openapi::DeleteWebcaptureResponse::DeletedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, Editgroup(..) | Editor(..) => unimplemented!("deletion for this entity type"), Changelog(..) => return Err(anyhow!("mutating this entity type doesn't make sense")), EditorUsername(..) | ReleaseLookup(..) | ContainerLookup(..) | FileLookup(..) | CreatorLookup(..) => return Err(anyhow!("into_entity_specifier() didn't work?")), } .with_context(|| format!("failed to delete {:?}", specifier)) } pub fn create_entity_from_json( &mut self, entity_type: EntityType, json_str: &str, editgroup_id: String, ) -> Result { match entity_type { EntityType::Release => { match self.rt.block_on( self.api .create_release(editgroup_id, serde_json::from_str(&json_str)?), )? { fatcat_openapi::CreateReleaseResponse::CreatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), } } EntityType::Work => { match self.rt.block_on( self.api .create_work(editgroup_id, serde_json::from_str(&json_str)?), )? { fatcat_openapi::CreateWorkResponse::CreatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), } } EntityType::Creator => { match self.rt.block_on( self.api .create_creator(editgroup_id, serde_json::from_str(&json_str)?), )? { fatcat_openapi::CreateCreatorResponse::CreatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), } } EntityType::Container => { match self.rt.block_on( self.api .create_container(editgroup_id, serde_json::from_str(&json_str)?), )? { fatcat_openapi::CreateContainerResponse::CreatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), } } EntityType::File => { match self.rt.block_on( self.api .create_file(editgroup_id, serde_json::from_str(&json_str)?), )? { fatcat_openapi::CreateFileResponse::CreatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), } } EntityType::FileSet => { match self.rt.block_on( self.api .create_fileset(editgroup_id, serde_json::from_str(&json_str)?), )? { fatcat_openapi::CreateFilesetResponse::CreatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), } } EntityType::WebCapture => { match self.rt.block_on( self.api .create_webcapture(editgroup_id, serde_json::from_str(&json_str)?), )? { fatcat_openapi::CreateWebcaptureResponse::CreatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), } } } .with_context(|| format!("parsing and creating {:?} entity", entity_type)) } pub fn existing_edit_in_editgroup( &mut self, editgroup: &models::Editgroup, specifier: &Specifier, ) -> Option { use Specifier::*; let (fcid, edit_list) = match specifier.clone() { Release(fcid) => (fcid, editgroup.edits.as_ref().unwrap().releases.clone()), Work(fcid) => (fcid, editgroup.edits.as_ref().unwrap().works.clone()), Container(fcid) => (fcid, editgroup.edits.as_ref().unwrap().containers.clone()), Creator(fcid) => (fcid, editgroup.edits.as_ref().unwrap().creators.clone()), File(fcid) => (fcid, editgroup.edits.as_ref().unwrap().files.clone()), FileSet(fcid) => (fcid, editgroup.edits.as_ref().unwrap().filesets.clone()), WebCapture(fcid) => (fcid, editgroup.edits.as_ref().unwrap().webcaptures.clone()), EditorUsername(..) | ReleaseLookup(..) | ContainerLookup(..) | FileLookup(..) | CreatorLookup(..) | Editgroup(..) | Editor(..) | Changelog(..) => { panic!("this entity type doesn't exist in editgroups") } }; for entity_edit in edit_list.unwrap() { if entity_edit.ident == fcid { return Some(entity_edit); } } None } pub fn delete_editgroup_edit( &mut self, editgroup: &models::Editgroup, specifier: &Specifier, edit: &models::EntityEdit, ) -> Result<()> { use Specifier::*; let editgroup_id = editgroup.editgroup_id.clone().unwrap(); let edit_id = edit.edit_id.clone(); match specifier.clone() { Release(..) => match self .rt .block_on(self.api.delete_release_edit(editgroup_id, edit_id))? { fatcat_openapi::DeleteReleaseEditResponse::DeletedEdit(..) => Ok(()), other => Err(anyhow!("{:?}", other)), }, Work(..) => match self .rt .block_on(self.api.delete_work_edit(editgroup_id, edit_id))? { fatcat_openapi::DeleteWorkEditResponse::DeletedEdit(..) => Ok(()), other => Err(anyhow!("{:?}", other)), }, Container(..) => match self .rt .block_on(self.api.delete_container_edit(editgroup_id, edit_id))? { fatcat_openapi::DeleteContainerEditResponse::DeletedEdit(..) => Ok(()), other => Err(anyhow!("{:?}", other)), }, Creator(..) => match self .rt .block_on(self.api.delete_creator_edit(editgroup_id, edit_id))? { fatcat_openapi::DeleteCreatorEditResponse::DeletedEdit(..) => Ok(()), other => Err(anyhow!("{:?}", other)), }, File(..) => match self .rt .block_on(self.api.delete_file_edit(editgroup_id, edit_id))? { fatcat_openapi::DeleteFileEditResponse::DeletedEdit(..) => Ok(()), other => Err(anyhow!("{:?}", other)), }, FileSet(..) => match self .rt .block_on(self.api.delete_fileset_edit(editgroup_id, edit_id))? { fatcat_openapi::DeleteFilesetEditResponse::DeletedEdit(..) => Ok(()), other => Err(anyhow!("{:?}", other)), }, WebCapture(..) => match self .rt .block_on(self.api.delete_webcapture_edit(editgroup_id, edit_id))? { fatcat_openapi::DeleteWebcaptureEditResponse::DeletedEdit(..) => Ok(()), other => Err(anyhow!("{:?}", other)), }, EditorUsername(..) | ReleaseLookup(..) | ContainerLookup(..) | FileLookup(..) | CreatorLookup(..) | Editgroup(..) | Editor(..) | Changelog(..) => { panic!("this entity type doesn't exist in editgroups") } } } pub fn update_entity_from_json( &mut self, specifier: Specifier, json_str: &str, editgroup_id: String, ) -> Result { use Specifier::*; let specifier = specifier.into_entity_specifier(self)?; let eg = match self .rt .block_on(self.api.get_editgroup(editgroup_id.clone()))? { fatcat_openapi::GetEditgroupResponse::Found(model) => Ok(model), fatcat_openapi::GetEditgroupResponse::BadRequest(err) => { Err(anyhow!("Bad Request ({}): {}", err.error, err.message)) } fatcat_openapi::GetEditgroupResponse::NotFound(err) => { Err(anyhow!("Not Found: {}", err.message)) } resp => Err(anyhow!("{:?}", resp)) .with_context(|| format!("API GET failed: editgroup_{:?}", editgroup_id)), }?; if let Some(entity_edit) = self.existing_edit_in_editgroup(&eg, &specifier) { self.delete_editgroup_edit(&eg, &specifier, &entity_edit)?; }; match specifier.clone() { Release(fcid) => match self.rt.block_on(self.api.update_release( editgroup_id, fcid, serde_json::from_str(&json_str)?, ))? { fatcat_openapi::UpdateReleaseResponse::UpdatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, Work(fcid) => match self.rt.block_on(self.api.update_work( editgroup_id, fcid, serde_json::from_str(&json_str)?, ))? { fatcat_openapi::UpdateWorkResponse::UpdatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, Container(fcid) => match self.rt.block_on(self.api.update_container( editgroup_id, fcid, serde_json::from_str(&json_str)?, ))? { fatcat_openapi::UpdateContainerResponse::UpdatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, Creator(fcid) => match self.rt.block_on(self.api.update_creator( editgroup_id, fcid, serde_json::from_str(&json_str)?, ))? { fatcat_openapi::UpdateCreatorResponse::UpdatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, File(fcid) => match self.rt.block_on(self.api.update_file( editgroup_id, fcid, serde_json::from_str(&json_str)?, ))? { fatcat_openapi::UpdateFileResponse::UpdatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, FileSet(fcid) => match self.rt.block_on(self.api.update_fileset( editgroup_id, fcid, serde_json::from_str(&json_str)?, ))? { fatcat_openapi::UpdateFilesetResponse::UpdatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, WebCapture(fcid) => match self.rt.block_on(self.api.update_webcapture( editgroup_id, fcid, serde_json::from_str(&json_str)?, ))? { fatcat_openapi::UpdateWebcaptureResponse::UpdatedEntity(ee) => Ok(ee), other => Err(anyhow!("{:?}", other)), }, Editgroup(..) | Editor(..) => unimplemented!("updates for this entity type"), Changelog(..) => return Err(anyhow!("deleting this entity type doesn't make sense")), EditorUsername(..) | ReleaseLookup(..) | ContainerLookup(..) | FileLookup(..) | CreatorLookup(..) => return Err(anyhow!("into_entity_specifier() didn't work?")), } .with_context(|| format!("failed to update {:?}", specifier)) } pub fn create_editgroup(&mut self, description: Option) -> Result { let mut eg = models::Editgroup::new(); eg.description = description; eg.extra = Some({ let mut extra = std::collections::HashMap::new(); extra.insert( "agent".to_string(), serde_json::Value::String("fatcat-cli".to_string()), ); extra.insert( "agent_version".to_string(), serde_json::Value::String(env!("CARGO_PKG_VERSION").to_string()), ); extra }); let result = self.rt.block_on(self.api.create_editgroup(eg))?; match result { fatcat_openapi::CreateEditgroupResponse::SuccessfullyCreated(eg) => Ok(eg), other => Err(anyhow!("{:?}", other)).context("failed to create editgroup"), } } pub fn accept_editgroup(&mut self, editgroup_id: String) -> Result { let result = self .rt .block_on(self.api.accept_editgroup(editgroup_id.clone())) .context("accept editgroup")?; match result { fatcat_openapi::AcceptEditgroupResponse::MergedSuccessfully(msg) => Ok(msg), other => Err(anyhow!( "failed to accept editgroup {}: {:?}", editgroup_id, other )), } } }