diff options
Diffstat (limited to 'rust/fatcat-cli/src/api.rs')
-rw-r--r-- | rust/fatcat-cli/src/api.rs | 365 |
1 files changed, 300 insertions, 65 deletions
diff --git a/rust/fatcat-cli/src/api.rs b/rust/fatcat-cli/src/api.rs index 41718ea..3fa67e9 100644 --- a/rust/fatcat-cli/src/api.rs +++ b/rust/fatcat-cli/src/api.rs @@ -1,14 +1,18 @@ - -use hyper::client::ResponseFuture; -use fatcat_openapi::{ApiNoContext, ContextWrapperExt}; +use crate::{parse_macaroon_editor_id, ClientStatus, EntityType, Specifier}; +use anyhow::{anyhow, Context, Result}; use fatcat_openapi::client::Client; use fatcat_openapi::models; -use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString, auth}; -use anyhow::{Result, anyhow, Context}; -use crate::{ClientStatus,parse_macaroon_editor_id,Specifier, EntityType}; +use fatcat_openapi::{ApiNoContext, ContextWrapperExt}; +use hyper::client::ResponseFuture; +use swagger::{auth, AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; use tokio::runtime::current_thread::Runtime; -type FatcatApiContextType = swagger::make_context_ty!( ContextBuilder, EmptyContext, Option<AuthData>, XSpanIdString); +type FatcatApiContextType = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option<AuthData>, + XSpanIdString +); pub struct FatcatApiClient<'a> { pub api: fatcat_openapi::ContextWrapper<'a, Client<ResponseFuture>, FatcatApiContextType>, @@ -19,11 +23,15 @@ pub struct FatcatApiClient<'a> { } impl<'a> FatcatApiClient<'a> { - - pub fn new(client: &'a fatcat_openapi::client::Client<ResponseFuture>, api_host: String, api_token: Option<String>) -> Result<Self> { - + pub fn new( + client: &'a fatcat_openapi::client::Client<ResponseFuture>, + api_host: String, + api_token: Option<String>, + ) -> Result<Self> { let auth_data = match api_token { - Some(ref token) => Some(AuthData::Bearer(auth::Bearer{ token: token.clone() })), + Some(ref token) => Some(AuthData::Bearer(auth::Bearer { + token: token.clone(), + })), None => None, }; //info!("{:?}", auth_data); @@ -34,14 +42,19 @@ impl<'a> FatcatApiClient<'a> { XSpanIdString::default() ); - let wrapped_client: fatcat_openapi::ContextWrapper<Client<ResponseFuture>, FatcatApiContextType> = client.with_context(context); + let wrapped_client: fatcat_openapi::ContextWrapper< + Client<ResponseFuture>, + FatcatApiContextType, + > = client.with_context(context); let rt: 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")?), + Some(ref token) => { + Some(parse_macaroon_editor_id(token).context("parse API auth token")?) + } None => None, }; - + Ok(FatcatApiClient { api: wrapped_client, rt, @@ -53,20 +66,40 @@ impl<'a> FatcatApiClient<'a> { pub fn status(&mut self) -> Result<ClientStatus> { let last_changelog = match self.rt.block_on(self.api.get_changelog(Some(1))) { - Ok(fatcat_openapi::GetChangelogResponse::Success(entry_vec)) => Some(entry_vec[0].index), + Ok(fatcat_openapi::GetChangelogResponse::Success(entry_vec)) => { + Some(entry_vec[0].index) + } Ok(_) | Err(_) => None, }; let has_api_token = self.api_token.is_some(); let account: Option<models::Editor> = if has_api_token && last_changelog.is_some() { - match self.rt.block_on(self.api.auth_check(None)).context("check auth token")? { + match self + .rt + .block_on(self.api.auth_check(None)) + .context("check auth token")? + { fatcat_openapi::AuthCheckResponse::Success(_) => Ok(()), - fatcat_openapi::AuthCheckResponse::Forbidden(err) => Err(anyhow!("Forbidden ({}): {}", err.error, err.message)), - fatcat_openapi::AuthCheckResponse::NotAuthorized{body: err, ..} => Err(anyhow!("Bad Request ({}): {}", err.error, err.message)), + fatcat_openapi::AuthCheckResponse::Forbidden(err) => { + Err(anyhow!("Forbidden ({}): {}", err.error, err.message)) + } + fatcat_openapi::AuthCheckResponse::NotAuthorized { body: err, .. } => { + Err(anyhow!("Bad Request ({}): {}", err.error, err.message)) + } resp => return Err(anyhow!("{:?}", resp)).context("auth check failed"), - }.context("check auth token")?; - match self.rt.block_on(self.api.get_editor(self.editor_id.as_ref().unwrap().to_string())).context("fetching editor account info")? { + } + .context("check auth token")?; + match self + .rt + .block_on( + self.api + .get_editor(self.editor_id.as_ref().unwrap().to_string()), + ) + .context("fetching editor account info")? + { fatcat_openapi::GetEditorResponse::Found(editor) => Some(editor), - fatcat_openapi::GetEditorResponse::NotFound(err) => return Err(anyhow!("Not Found: {}", err.message)), + fatcat_openapi::GetEditorResponse::NotFound(err) => { + return Err(anyhow!("Not Found: {}", err.message)) + } resp => return Err(anyhow!("{:?}", resp)).context("editor fetch failed"), } } else { @@ -80,18 +113,29 @@ impl<'a> FatcatApiClient<'a> { }) } - pub fn update_editgroup_submit(&mut self, editgroup_id: String, submit: bool) -> Result<models::Editgroup> { - let result = self.rt.block_on( - self.api.get_editgroup(editgroup_id.clone()) - ).context("fetch editgroups")?; + pub fn update_editgroup_submit( + &mut self, + editgroup_id: String, + submit: bool, + ) -> Result<models::Editgroup> { + 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)), + 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")?; + 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)) @@ -99,11 +143,18 @@ impl<'a> FatcatApiClient<'a> { } } - pub fn delete_entity(&mut self, specifier: Specifier, editgroup_id: String) -> Result<models::EntityEdit> { + pub fn delete_entity( + &mut self, + specifier: Specifier, + editgroup_id: String, + ) -> Result<models::EntityEdit> { 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))? { + 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)), }, @@ -111,11 +162,17 @@ impl<'a> FatcatApiClient<'a> { 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))? { + 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))? { + 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)), }, @@ -123,104 +180,282 @@ impl<'a> FatcatApiClient<'a> { 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))? { + 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))? { + 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)) + 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<models::EntityEdit> { + pub fn create_entity_from_json( + &mut self, + entity_type: EntityType, + json_str: &str, + editgroup_id: String, + ) -> Result<models::EntityEdit> { match entity_type { EntityType::Release => { - match self.rt.block_on(self.api.create_release(editgroup_id, serde_json::from_str(&json_str)?))? { + 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)?))? { + 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)?))? { + 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)?))? { + 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)?))? { + 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)?))? { + 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)?))? { + 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<models::EntityEdit> { + 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)), }, - }.with_context(|| format!("parsing and creating {:?} entity", entity_type)) + 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<models::EntityEdit> { + pub fn update_entity_from_json( + &mut self, + specifier: Specifier, + json_str: &str, + editgroup_id: String, + ) -> Result<models::EntityEdit> { 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)?))? { + 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)?))? { + 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)?))? { + 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)?))? { + 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)?))? { + 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)?))? { + 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)?))? { + 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)) + EditorUsername(..) | ReleaseLookup(..) | ContainerLookup(..) | FileLookup(..) + | CreatorLookup(..) => return Err(anyhow!("into_entity_specifier() didn't work?")), + } + .with_context(|| format!("failed to update {:?}", specifier)) } } |