diff options
Diffstat (limited to 'rust/fatcat-api/src')
-rw-r--r-- | rust/fatcat-api/src/client/mod.rs | 2573 | ||||
-rw-r--r-- | rust/fatcat-api/src/lib.rs | 599 | ||||
-rw-r--r-- | rust/fatcat-api/src/mimetypes.rs | 313 | ||||
-rw-r--r-- | rust/fatcat-api/src/models.rs | 392 | ||||
-rw-r--r-- | rust/fatcat-api/src/server/auth.rs | 93 | ||||
-rw-r--r-- | rust/fatcat-api/src/server/mod.rs | 2485 |
6 files changed, 6455 insertions, 0 deletions
diff --git a/rust/fatcat-api/src/client/mod.rs b/rust/fatcat-api/src/client/mod.rs new file mode 100644 index 00000000..361fd390 --- /dev/null +++ b/rust/fatcat-api/src/client/mod.rs @@ -0,0 +1,2573 @@ +#![allow(unused_extern_crates)] +extern crate chrono; +extern crate hyper_tls; +extern crate mime; +extern crate native_tls; +extern crate openssl; +extern crate tokio_core; +extern crate url; + +use self::tokio_core::reactor::Handle; +use self::url::percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, QUERY_ENCODE_SET}; +use futures; +use futures::{Future, Stream}; +use futures::{future, stream}; +use hyper; +use hyper::Uri; +use hyper::header::{ContentType, Headers}; +use std::borrow::Cow; +use std::error; +use std::fmt; +use std::io::{Error, ErrorKind, Read}; +use std::path::Path; +use std::str; +use std::str::FromStr; +use std::sync::Arc; + +use mimetypes; + +use serde_json; + +#[allow(unused_imports)] +use std::collections::{BTreeMap, HashMap}; +#[allow(unused_imports)] +use swagger; + +use swagger::{ApiError, Context, XSpanId}; + +use models; +use {Api, ContainerIdGetResponse, ContainerLookupGetResponse, ContainerPostResponse, + CreatorIdGetResponse, CreatorLookupGetResponse, CreatorPostResponse, + EditgroupIdAcceptPostResponse, EditgroupIdGetResponse, EditgroupPostResponse, + EditorUsernameChangelogGetResponse, EditorUsernameGetResponse, FileIdGetResponse, + FileLookupGetResponse, FilePostResponse, ReleaseIdGetResponse, ReleaseLookupGetResponse, + ReleasePostResponse, WorkIdGetResponse, WorkPostResponse}; + +/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. +fn into_base_path( + input: &str, + correct_scheme: Option<&'static str>, +) -> Result<String, ClientInitError> { + // First convert to Uri, since a base path is a subset of Uri. + let uri = Uri::from_str(input)?; + + let scheme = uri.scheme().ok_or(ClientInitError::InvalidScheme)?; + + // Check the scheme if necessary + if let Some(correct_scheme) = correct_scheme { + if scheme != correct_scheme { + return Err(ClientInitError::InvalidScheme); + } + } + + let host = uri.host().ok_or_else(|| ClientInitError::MissingHost)?; + let port = uri.port().map(|x| format!(":{}", x)).unwrap_or_default(); + Ok(format!("{}://{}{}", scheme, host, port)) +} + +/// A client that implements the API by making HTTP calls out to a server. +#[derive(Clone)] +pub struct Client { + hyper_client: Arc< + Fn( + &Handle + ) -> Box< + hyper::client::Service< + Request = hyper::Request<hyper::Body>, + Response = hyper::Response, + Error = hyper::Error, + Future = hyper::client::FutureResponse, + >, + > + + Sync + + Send, + >, + handle: Arc<Handle>, + base_path: String, +} + +impl fmt::Debug for Client { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Client {{ base_path: {} }}", self.base_path) + } +} + +impl Client { + /// Create an HTTP client. + /// + /// # Arguments + /// * `handle` - tokio reactor handle to use for execution + /// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com" + pub fn try_new_http(handle: Handle, base_path: &str) -> Result<Client, ClientInitError> { + let http_connector = swagger::http_connector(); + Self::try_new_with_connector::<hyper::client::HttpConnector>( + handle, + base_path, + Some("http"), + http_connector, + ) + } + + /// Create a client with a TLS connection to the server. + /// + /// # Arguments + /// * `handle` - tokio reactor handle to use for execution + /// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com" + /// * `ca_certificate` - Path to CA certificate used to authenticate the server + pub fn try_new_https<CA>( + handle: Handle, + base_path: &str, + ca_certificate: CA, + ) -> Result<Client, ClientInitError> + where + CA: AsRef<Path>, + { + let https_connector = swagger::https_connector(ca_certificate); + Self::try_new_with_connector::<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>( + handle, + base_path, + Some("https"), + https_connector, + ) + } + + /// Create a client with a mutually authenticated TLS connection to the server. + /// + /// # Arguments + /// * `handle` - tokio reactor handle to use for execution + /// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com" + /// * `ca_certificate` - Path to CA certificate used to authenticate the server + /// * `client_key` - Path to the client private key + /// * `client_certificate` - Path to the client's public certificate associated with the private key + pub fn try_new_https_mutual<CA, K, C, T>( + handle: Handle, + base_path: &str, + ca_certificate: CA, + client_key: K, + client_certificate: C, + ) -> Result<Client, ClientInitError> + where + CA: AsRef<Path>, + K: AsRef<Path>, + C: AsRef<Path>, + { + let https_connector = + swagger::https_mutual_connector(ca_certificate, client_key, client_certificate); + Self::try_new_with_connector::<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>( + handle, + base_path, + Some("https"), + https_connector, + ) + } + + /// Create a client with a custom implementation of hyper::client::Connect. + /// + /// Intended for use with custom implementations of connect for e.g. protocol logging + /// or similar functionality which requires wrapping the transport layer. When wrapping a TCP connection, + /// this function should be used in conjunction with + /// `swagger::{http_connector, https_connector, https_mutual_connector}`. + /// + /// For ordinary tcp connections, prefer the use of `try_new_http`, `try_new_https` + /// and `try_new_https_mutual`, to avoid introducing a dependency on the underlying transport layer. + /// + /// # Arguments + /// + /// * `handle` - tokio reactor handle to use for execution + /// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com" + /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` + /// * `connector_fn` - Function which returns an implementation of `hyper::client::Connect` + pub fn try_new_with_connector<C>( + handle: Handle, + base_path: &str, + protocol: Option<&'static str>, + connector_fn: Box<Fn(&Handle) -> C + Send + Sync>, + ) -> Result<Client, ClientInitError> + where + C: hyper::client::Connect + hyper::client::Service, + { + let hyper_client = { + move |handle: &Handle| -> Box< + hyper::client::Service< + Request = hyper::Request<hyper::Body>, + Response = hyper::Response, + Error = hyper::Error, + Future = hyper::client::FutureResponse, + >, + > { + let connector = connector_fn(handle); + Box::new( + hyper::Client::configure() + .connector(connector) + .build(handle), + ) + } + }; + + Ok(Client { + hyper_client: Arc::new(hyper_client), + handle: Arc::new(handle), + base_path: into_base_path(base_path, protocol)?, + }) + } + + /// Constructor for creating a `Client` by passing in a pre-made `hyper` client. + /// + /// One should avoid relying on this function if possible, since it adds a dependency on the underlying transport + /// implementation, which it would be better to abstract away. Therefore, using this function may lead to a loss of + /// code generality, which may make it harder to move the application to a serverless environment, for example. + /// + /// The reason for this function's existence is to support legacy test code, which did mocking at the hyper layer. + /// This is not a recommended way to write new tests. If other reasons are found for using this function, they + /// should be mentioned here. + pub fn try_new_with_hyper_client( + hyper_client: Arc< + Fn( + &Handle + ) -> Box< + hyper::client::Service< + Request = hyper::Request<hyper::Body>, + Response = hyper::Response, + Error = hyper::Error, + Future = hyper::client::FutureResponse, + >, + > + + Sync + + Send, + >, + handle: Handle, + base_path: &str, + ) -> Result<Client, ClientInitError> { + Ok(Client { + hyper_client: hyper_client, + handle: Arc::new(handle), + base_path: into_base_path(base_path, None)?, + }) + } +} + +impl Api for Client { + fn container_id_get( + &self, + param_id: String, + context: &Context, + ) -> Box<Future<Item = ContainerIdGetResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/container/{id}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::ContainerEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + ContainerIdGetResponse::FetchASingleContainerById(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ContainerIdGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + ContainerIdGetResponse::GenericErrorResponse(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn container_lookup_get( + &self, + param_issn: String, + context: &Context, + ) -> Box<Future<Item = ContainerLookupGetResponse, Error = ApiError>> { + // Query parameters + let query_issn = format!("issn={issn}&", issn = param_issn.to_string()); + + let uri = format!( + "{}/v0/container/lookup?{issn}", + self.base_path, + issn = utf8_percent_encode(&query_issn, QUERY_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::ContainerEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + ContainerLookupGetResponse::FindASingleContainerByExternalIdentifer(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ContainerLookupGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 404 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ContainerLookupGetResponse::NoSuchContainer(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + ContainerLookupGetResponse::GenericErrorResponse(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn container_post( + &self, + param_body: Option<models::ContainerEntity>, + context: &Context, + ) -> Box<Future<Item = ContainerPostResponse, Error = ApiError>> { + let uri = format!("{}/v0/container", self.base_path); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Post, uri); + + let body = param_body + .map(|ref body| serde_json::to_string(body).expect("impossible to fail to serialize")); + + if let Some(body) = body { + request.set_body(body.into_bytes()); + } + + request + .headers_mut() + .set(ContentType(mimetypes::requests::CONTAINER_POST.clone())); + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 201 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::EntityEdit>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ContainerPostResponse::Created(body)), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ContainerPostResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ContainerPostResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn creator_id_get( + &self, + param_id: String, + context: &Context, + ) -> Box<Future<Item = CreatorIdGetResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/creator/{id}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::CreatorEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + CreatorIdGetResponse::FetchASingleCreatorById(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| CreatorIdGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| CreatorIdGetResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn creator_lookup_get( + &self, + param_orcid: String, + context: &Context, + ) -> Box<Future<Item = CreatorLookupGetResponse, Error = ApiError>> { + // Query parameters + let query_orcid = format!("orcid={orcid}&", orcid = param_orcid.to_string()); + + let uri = format!( + "{}/v0/creator/lookup?{orcid}", + self.base_path, + orcid = utf8_percent_encode(&query_orcid, QUERY_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::CreatorEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + CreatorLookupGetResponse::FindASingleCreatorByExternalIdentifer( + body, + ) + }), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| CreatorLookupGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 404 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| CreatorLookupGetResponse::NoSuchCreator(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + CreatorLookupGetResponse::GenericErrorResponse(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn creator_post( + &self, + param_body: Option<models::CreatorEntity>, + context: &Context, + ) -> Box<Future<Item = CreatorPostResponse, Error = ApiError>> { + let uri = format!("{}/v0/creator", self.base_path); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Post, uri); + + let body = param_body + .map(|ref body| serde_json::to_string(body).expect("impossible to fail to serialize")); + + if let Some(body) = body { + request.set_body(body.into_bytes()); + } + + request + .headers_mut() + .set(ContentType(mimetypes::requests::CREATOR_POST.clone())); + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 201 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::EntityEdit>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| CreatorPostResponse::Created(body)), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| CreatorPostResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| CreatorPostResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn editgroup_id_accept_post( + &self, + param_id: i32, + context: &Context, + ) -> Box<Future<Item = EditgroupIdAcceptPostResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/editgroup/{id}/accept", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Post, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Success>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditgroupIdAcceptPostResponse::MergedEditgroupSuccessfully_( + body, + ) + }), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditgroupIdAcceptPostResponse::EditgroupIsInAnUnmergableState( + body, + ) + }), + ) as Box<Future<Item = _, Error = _>> + } + 404 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditgroupIdAcceptPostResponse::NoSuchEditgroup(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditgroupIdAcceptPostResponse::GenericErrorResponse(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn editgroup_id_get( + &self, + param_id: i32, + context: &Context, + ) -> Box<Future<Item = EditgroupIdGetResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/editgroup/{id}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Editgroup>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditgroupIdGetResponse::FetchEditgroupByIdentifier(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 404 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| EditgroupIdGetResponse::NoSuchEditgroup(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditgroupIdGetResponse::GenericErrorResponse(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn editgroup_post( + &self, + context: &Context, + ) -> Box<Future<Item = EditgroupPostResponse, Error = ApiError>> { + let uri = format!("{}/v0/editgroup", self.base_path); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Post, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 201 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Editgroup>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| EditgroupPostResponse::SuccessfullyCreated(body)), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditgroupPostResponse::InvalidRequestParameters(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| EditgroupPostResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn editor_username_changelog_get( + &self, + param_username: String, + context: &Context, + ) -> Box<Future<Item = EditorUsernameChangelogGetResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/editor/{username}/changelog", + self.base_path, + username = utf8_percent_encode(¶m_username.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Changelogentry>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditorUsernameChangelogGetResponse::FindChanges_(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 404 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditorUsernameChangelogGetResponse::UsernameNotFound(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditorUsernameChangelogGetResponse::GenericErrorResponse(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn editor_username_get( + &self, + param_username: String, + context: &Context, + ) -> Box<Future<Item = EditorUsernameGetResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/editor/{username}", + self.base_path, + username = utf8_percent_encode(¶m_username.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Editor>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditorUsernameGetResponse::FetchGenericInformationAboutAnEditor( + body, + ) + }), + ) as Box<Future<Item = _, Error = _>> + } + 404 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| EditorUsernameGetResponse::UsernameNotFound(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + EditorUsernameGetResponse::GenericErrorResponse(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn file_id_get( + &self, + param_id: String, + context: &Context, + ) -> Box<Future<Item = FileIdGetResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/file/{id}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::FileEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FileIdGetResponse::FetchASingleFileById(body)), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FileIdGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FileIdGetResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn file_lookup_get( + &self, + param_sha1: String, + context: &Context, + ) -> Box<Future<Item = FileLookupGetResponse, Error = ApiError>> { + // Query parameters + let query_sha1 = format!("sha1={sha1}&", sha1 = param_sha1.to_string()); + + let uri = format!( + "{}/v0/file/lookup?{sha1}", + self.base_path, + sha1 = utf8_percent_encode(&query_sha1, QUERY_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::FileEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + FileLookupGetResponse::FindASingleFileByExternalIdentifer(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FileLookupGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 404 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FileLookupGetResponse::NoSuchFile(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FileLookupGetResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn file_post( + &self, + param_body: Option<models::FileEntity>, + context: &Context, + ) -> Box<Future<Item = FilePostResponse, Error = ApiError>> { + let uri = format!("{}/v0/file", self.base_path); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Post, uri); + + let body = param_body + .map(|ref body| serde_json::to_string(body).expect("impossible to fail to serialize")); + + if let Some(body) = body { + request.set_body(body.into_bytes()); + } + + request + .headers_mut() + .set(ContentType(mimetypes::requests::FILE_POST.clone())); + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 201 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::EntityEdit>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FilePostResponse::Created(body)), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FilePostResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| FilePostResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn release_id_get( + &self, + param_id: String, + context: &Context, + ) -> Box<Future<Item = ReleaseIdGetResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/release/{id}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::ReleaseEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + ReleaseIdGetResponse::FetchASingleReleaseById(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ReleaseIdGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ReleaseIdGetResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn release_lookup_get( + &self, + param_doi: String, + context: &Context, + ) -> Box<Future<Item = ReleaseLookupGetResponse, Error = ApiError>> { + // Query parameters + let query_doi = format!("doi={doi}&", doi = param_doi.to_string()); + + let uri = format!( + "{}/v0/release/lookup?{doi}", + self.base_path, + doi = utf8_percent_encode(&query_doi, QUERY_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::ReleaseEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + ReleaseLookupGetResponse::FindASingleReleaseByExternalIdentifer( + body, + ) + }), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ReleaseLookupGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 404 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ReleaseLookupGetResponse::NoSuchRelease(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| { + ReleaseLookupGetResponse::GenericErrorResponse(body) + }), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn release_post( + &self, + param_body: Option<models::ReleaseEntity>, + context: &Context, + ) -> Box<Future<Item = ReleasePostResponse, Error = ApiError>> { + let uri = format!("{}/v0/release", self.base_path); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Post, uri); + + let body = param_body + .map(|ref body| serde_json::to_string(body).expect("impossible to fail to serialize")); + + if let Some(body) = body { + request.set_body(body.into_bytes()); + } + + request + .headers_mut() + .set(ContentType(mimetypes::requests::RELEASE_POST.clone())); + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 201 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::EntityEdit>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ReleasePostResponse::Created(body)), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ReleasePostResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| ReleasePostResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn work_id_get( + &self, + param_id: String, + context: &Context, + ) -> Box<Future<Item = WorkIdGetResponse, Error = ApiError>> { + let uri = format!( + "{}/v0/work/{id}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Get, uri); + + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 200 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::WorkEntity>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| WorkIdGetResponse::FetchASingleWorkById(body)), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| WorkIdGetResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| WorkIdGetResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } + + fn work_post( + &self, + param_body: Option<models::WorkEntity>, + context: &Context, + ) -> Box<Future<Item = WorkPostResponse, Error = ApiError>> { + let uri = format!("{}/v0/work", self.base_path); + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => { + return Box::new(futures::done(Err(ApiError(format!( + "Unable to build URI: {}", + err + ))))) + } + }; + + let mut request = hyper::Request::new(hyper::Method::Post, uri); + + let body = param_body + .map(|ref body| serde_json::to_string(body).expect("impossible to fail to serialize")); + + if let Some(body) = body { + request.set_body(body.into_bytes()); + } + + request + .headers_mut() + .set(ContentType(mimetypes::requests::WORK_POST.clone())); + context + .x_span_id + .as_ref() + .map(|header| request.headers_mut().set(XSpanId(header.clone()))); + + let hyper_client = (self.hyper_client)(&*self.handle); + Box::new( + hyper_client + .call(request) + .map_err(|e| ApiError(format!("No response received: {}", e))) + .and_then(|mut response| match response.status().as_u16() { + 201 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::EntityEdit>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| WorkPostResponse::Created(body)), + ) as Box<Future<Item = _, Error = _>> + } + 400 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| WorkPostResponse::BadRequest(body)), + ) as Box<Future<Item = _, Error = _>> + } + 0 => { + let body = response.body(); + Box::new( + body.concat2() + .map_err(|e| ApiError(format!("Failed to read response: {}", e))) + .and_then(|body| { + str::from_utf8(&body) + .map_err(|e| { + ApiError(format!("Response was not valid UTF8: {}", e)) + }) + .and_then(|body| { + serde_json::from_str::<models::Error>(body) + .map_err(|e| e.into()) + }) + }) + .map(move |body| WorkPostResponse::GenericErrorResponse(body)), + ) as Box<Future<Item = _, Error = _>> + } + code => { + let headers = response.headers().clone(); + Box::new(response.body().take(100).concat2().then(move |body| { + future::err(ApiError(format!( + "Unexpected response code {}:\n{:?}\n\n{}", + code, + headers, + match body { + Ok(ref body) => match str::from_utf8(body) { + Ok(body) => Cow::from(body), + Err(e) => { + Cow::from(format!("<Body was not UTF8: {:?}>", e)) + } + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + } + ))) + })) as Box<Future<Item = _, Error = _>> + } + }), + ) + } +} + +#[derive(Debug)] +pub enum ClientInitError { + InvalidScheme, + InvalidUri(hyper::error::UriError), + MissingHost, + SslError(openssl::error::ErrorStack), +} + +impl From<hyper::error::UriError> for ClientInitError { + fn from(err: hyper::error::UriError) -> ClientInitError { + ClientInitError::InvalidUri(err) + } +} + +impl From<openssl::error::ErrorStack> for ClientInitError { + fn from(err: openssl::error::ErrorStack) -> ClientInitError { + ClientInitError::SslError(err) + } +} + +impl fmt::Display for ClientInitError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (self as &fmt::Debug).fmt(f) + } +} + +impl error::Error for ClientInitError { + fn description(&self) -> &str { + "Failed to produce a hyper client." + } +} diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs new file mode 100644 index 00000000..36573537 --- /dev/null +++ b/rust/fatcat-api/src/lib.rs @@ -0,0 +1,599 @@ +#![allow(missing_docs, trivial_casts, unused_variables, unused_mut, unused_imports, + unused_extern_crates, non_camel_case_types)] +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; + +extern crate chrono; +extern crate futures; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; + +// Logically this should be in the client and server modules, but rust doesn't allow `macro_use` from a module. +#[cfg(any(feature = "client", feature = "server"))] +#[macro_use] +extern crate hyper; + +extern crate swagger; + +use futures::Stream; +use std::io::Error; + +#[allow(unused_imports)] +use std::collections::HashMap; + +pub use futures::Future; + +#[cfg(any(feature = "client", feature = "server"))] +mod mimetypes; + +pub use swagger::{ApiError, Context, ContextWrapper}; + +pub const BASE_PATH: &'static str = "/v0"; +pub const API_VERSION: &'static str = "0.1.0"; + +#[derive(Debug, PartialEq)] +pub enum ContainerIdGetResponse { + /// fetch a single container by id + FetchASingleContainerById(models::ContainerEntity), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum ContainerLookupGetResponse { + /// find a single container by external identifer + FindASingleContainerByExternalIdentifer(models::ContainerEntity), + /// bad request + BadRequest(models::Error), + /// no such container + NoSuchContainer(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum ContainerPostResponse { + /// created + Created(models::EntityEdit), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum CreatorIdGetResponse { + /// fetch a single creator by id + FetchASingleCreatorById(models::CreatorEntity), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum CreatorLookupGetResponse { + /// find a single creator by external identifer + FindASingleCreatorByExternalIdentifer(models::CreatorEntity), + /// bad request + BadRequest(models::Error), + /// no such creator + NoSuchCreator(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum CreatorPostResponse { + /// created + Created(models::EntityEdit), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum EditgroupIdAcceptPostResponse { + /// merged editgroup successfully (\"live\") + MergedEditgroupSuccessfully_(models::Success), + /// editgroup is in an unmergable state + EditgroupIsInAnUnmergableState(models::Error), + /// no such editgroup + NoSuchEditgroup(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum EditgroupIdGetResponse { + /// fetch editgroup by identifier + FetchEditgroupByIdentifier(models::Editgroup), + /// no such editgroup + NoSuchEditgroup(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum EditgroupPostResponse { + /// successfully created + SuccessfullyCreated(models::Editgroup), + /// invalid request parameters + InvalidRequestParameters(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum EditorUsernameChangelogGetResponse { + /// find changes (editgroups) by this editor which have been merged + FindChanges_(models::Changelogentry), + /// username not found + UsernameNotFound(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum EditorUsernameGetResponse { + /// fetch generic information about an editor + FetchGenericInformationAboutAnEditor(models::Editor), + /// username not found + UsernameNotFound(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum FileIdGetResponse { + /// fetch a single file by id + FetchASingleFileById(models::FileEntity), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum FileLookupGetResponse { + /// find a single file by external identifer + FindASingleFileByExternalIdentifer(models::FileEntity), + /// bad request + BadRequest(models::Error), + /// no such file + NoSuchFile(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum FilePostResponse { + /// created + Created(models::EntityEdit), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum ReleaseIdGetResponse { + /// fetch a single release by id + FetchASingleReleaseById(models::ReleaseEntity), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum ReleaseLookupGetResponse { + /// find a single release by external identifer + FindASingleReleaseByExternalIdentifer(models::ReleaseEntity), + /// bad request + BadRequest(models::Error), + /// no such release + NoSuchRelease(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum ReleasePostResponse { + /// created + Created(models::EntityEdit), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum WorkIdGetResponse { + /// fetch a single work by id + FetchASingleWorkById(models::WorkEntity), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +#[derive(Debug, PartialEq)] +pub enum WorkPostResponse { + /// created + Created(models::EntityEdit), + /// bad request + BadRequest(models::Error), + /// generic error response + GenericErrorResponse(models::Error), +} + +/// API +pub trait Api { + fn container_id_get( + &self, + id: String, + context: &Context, + ) -> Box<Future<Item = ContainerIdGetResponse, Error = ApiError>>; + + fn container_lookup_get( + &self, + issn: String, + context: &Context, + ) -> Box<Future<Item = ContainerLookupGetResponse, Error = ApiError>>; + + fn container_post( + &self, + body: Option<models::ContainerEntity>, + context: &Context, + ) -> Box<Future<Item = ContainerPostResponse, Error = ApiError>>; + + fn creator_id_get( + &self, + id: String, + context: &Context, + ) -> Box<Future<Item = CreatorIdGetResponse, Error = ApiError>>; + + fn creator_lookup_get( + &self, + orcid: String, + context: &Context, + ) -> Box<Future<Item = CreatorLookupGetResponse, Error = ApiError>>; + + fn creator_post( + &self, + body: Option<models::CreatorEntity>, + context: &Context, + ) -> Box<Future<Item = CreatorPostResponse, Error = ApiError>>; + + fn editgroup_id_accept_post( + &self, + id: i32, + context: &Context, + ) -> Box<Future<Item = EditgroupIdAcceptPostResponse, Error = ApiError>>; + + fn editgroup_id_get( + &self, + id: i32, + context: &Context, + ) -> Box<Future<Item = EditgroupIdGetResponse, Error = ApiError>>; + + fn editgroup_post( + &self, + context: &Context, + ) -> Box<Future<Item = EditgroupPostResponse, Error = ApiError>>; + + fn editor_username_changelog_get( + &self, + username: String, + context: &Context, + ) -> Box<Future<Item = EditorUsernameChangelogGetResponse, Error = ApiError>>; + + fn editor_username_get( + &self, + username: String, + context: &Context, + ) -> Box<Future<Item = EditorUsernameGetResponse, Error = ApiError>>; + + fn file_id_get( + &self, + id: String, + context: &Context, + ) -> Box<Future<Item = FileIdGetResponse, Error = ApiError>>; + + fn file_lookup_get( + &self, + sha1: String, + context: &Context, + ) -> Box<Future<Item = FileLookupGetResponse, Error = ApiError>>; + + fn file_post( + &self, + body: Option<models::FileEntity>, + context: &Context, + ) -> Box<Future<Item = FilePostResponse, Error = ApiError>>; + + fn release_id_get( + &self, + id: String, + context: &Context, + ) -> Box<Future<Item = ReleaseIdGetResponse, Error = ApiError>>; + + fn release_lookup_get( + &self, + doi: String, + context: &Context, + ) -> Box<Future<Item = ReleaseLookupGetResponse, Error = ApiError>>; + + fn release_post( + &self, + body: Option<models::ReleaseEntity>, + context: &Context, + ) -> Box<Future<Item = ReleasePostResponse, Error = ApiError>>; + + fn work_id_get( + &self, + id: String, + context: &Context, + ) -> Box<Future<Item = WorkIdGetResponse, Error = ApiError>>; + + fn work_post( + &self, + body: Option<models::WorkEntity>, + context: &Context, + ) -> Box<Future<Item = WorkPostResponse, Error = ApiError>>; +} + +/// API without a `Context` +pub trait ApiNoContext { + fn container_id_get( + &self, + id: String, + ) -> Box<Future<Item = ContainerIdGetResponse, Error = ApiError>>; + + fn container_lookup_get( + &self, + issn: String, + ) -> Box<Future<Item = ContainerLookupGetResponse, Error = ApiError>>; + + fn container_post( + &self, + body: Option<models::ContainerEntity>, + ) -> Box<Future<Item = ContainerPostResponse, Error = ApiError>>; + + fn creator_id_get( + &self, + id: String, + ) -> Box<Future<Item = CreatorIdGetResponse, Error = ApiError>>; + + fn creator_lookup_get( + &self, + orcid: String, + ) -> Box<Future<Item = CreatorLookupGetResponse, Error = ApiError>>; + + fn creator_post( + &self, + body: Option<models::CreatorEntity>, + ) -> Box<Future<Item = CreatorPostResponse, Error = ApiError>>; + + fn editgroup_id_accept_post( + &self, + id: i32, + ) -> Box<Future<Item = EditgroupIdAcceptPostResponse, Error = ApiError>>; + + fn editgroup_id_get( + &self, + id: i32, + ) -> Box<Future<Item = EditgroupIdGetResponse, Error = ApiError>>; + + fn editgroup_post(&self) -> Box<Future<Item = EditgroupPostResponse, Error = ApiError>>; + + fn editor_username_changelog_get( + &self, + username: String, + ) -> Box<Future<Item = EditorUsernameChangelogGetResponse, Error = ApiError>>; + + fn editor_username_get( + &self, + username: String, + ) -> Box<Future<Item = EditorUsernameGetResponse, Error = ApiError>>; + + fn file_id_get(&self, id: String) -> Box<Future<Item = FileIdGetResponse, Error = ApiError>>; + + fn file_lookup_get( + &self, + sha1: String, + ) -> Box<Future<Item = FileLookupGetResponse, Error = ApiError>>; + + fn file_post( + &self, + body: Option<models::FileEntity>, + ) -> Box<Future<Item = FilePostResponse, Error = ApiError>>; + + fn release_id_get( + &self, + id: String, + ) -> Box<Future<Item = ReleaseIdGetResponse, Error = ApiError>>; + + fn release_lookup_get( + &self, + doi: String, + ) -> Box<Future<Item = ReleaseLookupGetResponse, Error = ApiError>>; + + fn release_post( + &self, + body: Option<models::ReleaseEntity>, + ) -> Box<Future<Item = ReleasePostResponse, Error = ApiError>>; + + fn work_id_get(&self, id: String) -> Box<Future<Item = WorkIdGetResponse, Error = ApiError>>; + + fn work_post( + &self, + body: Option<models::WorkEntity>, + ) -> Box<Future<Item = WorkPostResponse, Error = ApiError>>; +} + +/// Trait to extend an API to make it easy to bind it to a context. +pub trait ContextWrapperExt<'a> +where + Self: Sized, +{ + /// Binds this API to a context. + fn with_context(self: &'a Self, context: Context) -> ContextWrapper<'a, Self>; +} + +impl<'a, T: Api + Sized> ContextWrapperExt<'a> for T { + fn with_context(self: &'a T, context: Context) -> ContextWrapper<'a, T> { + ContextWrapper::<T>::new(self, context) + } +} + +impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { + fn container_id_get( + &self, + id: String, + ) -> Box<Future<Item = ContainerIdGetResponse, Error = ApiError>> { + self.api().container_id_get(id, &self.context()) + } + + fn container_lookup_get( + &self, + issn: String, + ) -> Box<Future<Item = ContainerLookupGetResponse, Error = ApiError>> { + self.api().container_lookup_get(issn, &self.context()) + } + + fn container_post( + &self, + body: Option<models::ContainerEntity>, + ) -> Box<Future<Item = ContainerPostResponse, Error = ApiError>> { + self.api().container_post(body, &self.context()) + } + + fn creator_id_get( + &self, + id: String, + ) -> Box<Future<Item = CreatorIdGetResponse, Error = ApiError>> { + self.api().creator_id_get(id, &self.context()) + } + + fn creator_lookup_get( + &self, + orcid: String, + ) -> Box<Future<Item = CreatorLookupGetResponse, Error = ApiError>> { + self.api().creator_lookup_get(orcid, &self.context()) + } + + fn creator_post( + &self, + body: Option<models::CreatorEntity>, + ) -> Box<Future<Item = CreatorPostResponse, Error = ApiError>> { + self.api().creator_post(body, &self.context()) + } + + fn editgroup_id_accept_post( + &self, + id: i32, + ) -> Box<Future<Item = EditgroupIdAcceptPostResponse, Error = ApiError>> { + self.api().editgroup_id_accept_post(id, &self.context()) + } + + fn editgroup_id_get( + &self, + id: i32, + ) -> Box<Future<Item = EditgroupIdGetResponse, Error = ApiError>> { + self.api().editgroup_id_get(id, &self.context()) + } + + fn editgroup_post(&self) -> Box<Future<Item = EditgroupPostResponse, Error = ApiError>> { + self.api().editgroup_post(&self.context()) + } + + fn editor_username_changelog_get( + &self, + username: String, + ) -> Box<Future<Item = EditorUsernameChangelogGetResponse, Error = ApiError>> { + self.api() + .editor_username_changelog_get(username, &self.context()) + } + + fn editor_username_get( + &self, + username: String, + ) -> Box<Future<Item = EditorUsernameGetResponse, Error = ApiError>> { + self.api().editor_username_get(username, &self.context()) + } + + fn file_id_get(&self, id: String) -> Box<Future<Item = FileIdGetResponse, Error = ApiError>> { + self.api().file_id_get(id, &self.context()) + } + + fn file_lookup_get( + &self, + sha1: String, + ) -> Box<Future<Item = FileLookupGetResponse, Error = ApiError>> { + self.api().file_lookup_get(sha1, &self.context()) + } + + fn file_post( + &self, + body: Option<models::FileEntity>, + ) -> Box<Future<Item = FilePostResponse, Error = ApiError>> { + self.api().file_post(body, &self.context()) + } + + fn release_id_get( + &self, + id: String, + ) -> Box<Future<Item = ReleaseIdGetResponse, Error = ApiError>> { + self.api().release_id_get(id, &self.context()) + } + + fn release_lookup_get( + &self, + doi: String, + ) -> Box<Future<Item = ReleaseLookupGetResponse, Error = ApiError>> { + self.api().release_lookup_get(doi, &self.context()) + } + + fn release_post( + &self, + body: Option<models::ReleaseEntity>, + ) -> Box<Future<Item = ReleasePostResponse, Error = ApiError>> { + self.api().release_post(body, &self.context()) + } + + fn work_id_get(&self, id: String) -> Box<Future<Item = WorkIdGetResponse, Error = ApiError>> { + self.api().work_id_get(id, &self.context()) + } + + fn work_post( + &self, + body: Option<models::WorkEntity>, + ) -> Box<Future<Item = WorkPostResponse, Error = ApiError>> { + self.api().work_post(body, &self.context()) + } +} + +#[cfg(feature = "client")] +pub mod client; + +// Re-export Client as a top-level name +#[cfg(feature = "client")] +pub use self::client::Client; + +#[cfg(feature = "server")] +pub mod server; + +// Re-export router() as a top-level name +#[cfg(feature = "server")] +pub use self::server::Service; + +pub mod models; diff --git a/rust/fatcat-api/src/mimetypes.rs b/rust/fatcat-api/src/mimetypes.rs new file mode 100644 index 00000000..dfbff890 --- /dev/null +++ b/rust/fatcat-api/src/mimetypes.rs @@ -0,0 +1,313 @@ +/// mime types for requests and responses + +pub mod responses { + use hyper::mime::*; + + // The macro is called per-operation to beat the recursion limit + /// Create Mime objects for the response content types for ContainerIdGet + lazy_static! { + pub static ref CONTAINER_ID_GET_FETCH_A_SINGLE_CONTAINER_BY_ID: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerIdGet + lazy_static! { + pub static ref CONTAINER_ID_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerIdGet + lazy_static! { + pub static ref CONTAINER_ID_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerLookupGet + lazy_static! { + pub static ref CONTAINER_LOOKUP_GET_FIND_A_SINGLE_CONTAINER_BY_EXTERNAL_IDENTIFER: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerLookupGet + lazy_static! { + pub static ref CONTAINER_LOOKUP_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerLookupGet + lazy_static! { + pub static ref CONTAINER_LOOKUP_GET_NO_SUCH_CONTAINER: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerLookupGet + lazy_static! { + pub static ref CONTAINER_LOOKUP_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerPost + lazy_static! { + pub static ref CONTAINER_POST_CREATED: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerPost + lazy_static! { + pub static ref CONTAINER_POST_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ContainerPost + lazy_static! { + pub static ref CONTAINER_POST_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorIdGet + lazy_static! { + pub static ref CREATOR_ID_GET_FETCH_A_SINGLE_CREATOR_BY_ID: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorIdGet + lazy_static! { + pub static ref CREATOR_ID_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorIdGet + lazy_static! { + pub static ref CREATOR_ID_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorLookupGet + lazy_static! { + pub static ref CREATOR_LOOKUP_GET_FIND_A_SINGLE_CREATOR_BY_EXTERNAL_IDENTIFER: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorLookupGet + lazy_static! { + pub static ref CREATOR_LOOKUP_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorLookupGet + lazy_static! { + pub static ref CREATOR_LOOKUP_GET_NO_SUCH_CREATOR: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorLookupGet + lazy_static! { + pub static ref CREATOR_LOOKUP_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorPost + lazy_static! { + pub static ref CREATOR_POST_CREATED: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorPost + lazy_static! { + pub static ref CREATOR_POST_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for CreatorPost + lazy_static! { + pub static ref CREATOR_POST_GENERIC_ERROR_RESPONSE: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupIdAcceptPost + lazy_static! { + pub static ref EDITGROUP_ID_ACCEPT_POST_MERGED_EDITGROUP_SUCCESSFULLY_: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupIdAcceptPost + lazy_static! { + pub static ref EDITGROUP_ID_ACCEPT_POST_EDITGROUP_IS_IN_AN_UNMERGABLE_STATE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupIdAcceptPost + lazy_static! { + pub static ref EDITGROUP_ID_ACCEPT_POST_NO_SUCH_EDITGROUP: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupIdAcceptPost + lazy_static! { + pub static ref EDITGROUP_ID_ACCEPT_POST_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupIdGet + lazy_static! { + pub static ref EDITGROUP_ID_GET_FETCH_EDITGROUP_BY_IDENTIFIER: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupIdGet + lazy_static! { + pub static ref EDITGROUP_ID_GET_NO_SUCH_EDITGROUP: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupIdGet + lazy_static! { + pub static ref EDITGROUP_ID_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupPost + lazy_static! { + pub static ref EDITGROUP_POST_SUCCESSFULLY_CREATED: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupPost + lazy_static! { + pub static ref EDITGROUP_POST_INVALID_REQUEST_PARAMETERS: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditgroupPost + lazy_static! { + pub static ref EDITGROUP_POST_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditorUsernameChangelogGet + lazy_static! { + pub static ref EDITOR_USERNAME_CHANGELOG_GET_FIND_CHANGES_: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditorUsernameChangelogGet + lazy_static! { + pub static ref EDITOR_USERNAME_CHANGELOG_GET_USERNAME_NOT_FOUND: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditorUsernameChangelogGet + lazy_static! { + pub static ref EDITOR_USERNAME_CHANGELOG_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditorUsernameGet + lazy_static! { + pub static ref EDITOR_USERNAME_GET_FETCH_GENERIC_INFORMATION_ABOUT_AN_EDITOR: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditorUsernameGet + lazy_static! { + pub static ref EDITOR_USERNAME_GET_USERNAME_NOT_FOUND: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for EditorUsernameGet + lazy_static! { + pub static ref EDITOR_USERNAME_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FileIdGet + lazy_static! { + pub static ref FILE_ID_GET_FETCH_A_SINGLE_FILE_BY_ID: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FileIdGet + lazy_static! { + pub static ref FILE_ID_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FileIdGet + lazy_static! { + pub static ref FILE_ID_GET_GENERIC_ERROR_RESPONSE: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FileLookupGet + lazy_static! { + pub static ref FILE_LOOKUP_GET_FIND_A_SINGLE_FILE_BY_EXTERNAL_IDENTIFER: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FileLookupGet + lazy_static! { + pub static ref FILE_LOOKUP_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FileLookupGet + lazy_static! { + pub static ref FILE_LOOKUP_GET_NO_SUCH_FILE: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FileLookupGet + lazy_static! { + pub static ref FILE_LOOKUP_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FilePost + lazy_static! { + pub static ref FILE_POST_CREATED: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FilePost + lazy_static! { + pub static ref FILE_POST_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for FilePost + lazy_static! { + pub static ref FILE_POST_GENERIC_ERROR_RESPONSE: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleaseIdGet + lazy_static! { + pub static ref RELEASE_ID_GET_FETCH_A_SINGLE_RELEASE_BY_ID: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleaseIdGet + lazy_static! { + pub static ref RELEASE_ID_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleaseIdGet + lazy_static! { + pub static ref RELEASE_ID_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleaseLookupGet + lazy_static! { + pub static ref RELEASE_LOOKUP_GET_FIND_A_SINGLE_RELEASE_BY_EXTERNAL_IDENTIFER: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleaseLookupGet + lazy_static! { + pub static ref RELEASE_LOOKUP_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleaseLookupGet + lazy_static! { + pub static ref RELEASE_LOOKUP_GET_NO_SUCH_RELEASE: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleaseLookupGet + lazy_static! { + pub static ref RELEASE_LOOKUP_GET_GENERIC_ERROR_RESPONSE: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleasePost + lazy_static! { + pub static ref RELEASE_POST_CREATED: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleasePost + lazy_static! { + pub static ref RELEASE_POST_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for ReleasePost + lazy_static! { + pub static ref RELEASE_POST_GENERIC_ERROR_RESPONSE: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for WorkIdGet + lazy_static! { + pub static ref WORK_ID_GET_FETCH_A_SINGLE_WORK_BY_ID: Mime = + "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for WorkIdGet + lazy_static! { + pub static ref WORK_ID_GET_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for WorkIdGet + lazy_static! { + pub static ref WORK_ID_GET_GENERIC_ERROR_RESPONSE: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for WorkPost + lazy_static! { + pub static ref WORK_POST_CREATED: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for WorkPost + lazy_static! { + pub static ref WORK_POST_BAD_REQUEST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the response content types for WorkPost + lazy_static! { + pub static ref WORK_POST_GENERIC_ERROR_RESPONSE: Mime = "application/json".parse().unwrap(); + } + +} + +pub mod requests { + use hyper::mime::*; + /// Create Mime objects for the request content types for ContainerPost + lazy_static! { + pub static ref CONTAINER_POST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the request content types for CreatorPost + lazy_static! { + pub static ref CREATOR_POST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the request content types for FilePost + lazy_static! { + pub static ref FILE_POST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the request content types for ReleasePost + lazy_static! { + pub static ref RELEASE_POST: Mime = "application/json".parse().unwrap(); + } + /// Create Mime objects for the request content types for WorkPost + lazy_static! { + pub static ref WORK_POST: Mime = "application/json".parse().unwrap(); + } + +} diff --git a/rust/fatcat-api/src/models.rs b/rust/fatcat-api/src/models.rs new file mode 100644 index 00000000..3d104b78 --- /dev/null +++ b/rust/fatcat-api/src/models.rs @@ -0,0 +1,392 @@ +#![allow(unused_imports, unused_qualifications, unused_extern_crates)] +extern crate chrono; +extern crate uuid; + +use serde::ser::Serializer; + +use models; +use std::collections::HashMap; +use swagger; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Changelogentry { + #[serde(rename = "index")] + pub index: isize, + + #[serde(rename = "editgroup_id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub editgroup_id: Option<isize>, + + #[serde(rename = "timestamp")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timestamp: Option<chrono::DateTime<chrono::Utc>>, +} + +impl Changelogentry { + pub fn new(index: isize) -> Changelogentry { + Changelogentry { + index: index, + editgroup_id: None, + timestamp: None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ContainerEntity { + #[serde(rename = "issn")] + #[serde(skip_serializing_if = "Option::is_none")] + pub issn: Option<String>, + + #[serde(rename = "publisher")] + #[serde(skip_serializing_if = "Option::is_none")] + pub publisher: Option<String>, + + #[serde(rename = "parent")] + #[serde(skip_serializing_if = "Option::is_none")] + pub parent: Option<String>, + + #[serde(rename = "name")] + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option<String>, + + // Note: inline enums are not fully supported by swagger-codegen + #[serde(rename = "state")] + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option<String>, + + #[serde(rename = "ident")] + #[serde(skip_serializing_if = "Option::is_none")] + pub ident: Option<String>, + + #[serde(rename = "revision")] + #[serde(skip_serializing_if = "Option::is_none")] + pub revision: Option<isize>, + + #[serde(rename = "redirect")] + #[serde(skip_serializing_if = "Option::is_none")] + pub redirect: Option<String>, + + #[serde(rename = "editgroup")] + #[serde(skip_serializing_if = "Option::is_none")] + pub editgroup: Option<isize>, +} + +impl ContainerEntity { + pub fn new() -> ContainerEntity { + ContainerEntity { + issn: None, + publisher: None, + parent: None, + name: None, + state: None, + ident: None, + revision: None, + redirect: None, + editgroup: None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CreatorEntity { + #[serde(rename = "orcid")] + #[serde(skip_serializing_if = "Option::is_none")] + pub orcid: Option<String>, + + #[serde(rename = "name")] + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option<String>, + + #[serde(rename = "editgroup")] + #[serde(skip_serializing_if = "Option::is_none")] + pub editgroup: Option<isize>, + + #[serde(rename = "redirect")] + #[serde(skip_serializing_if = "Option::is_none")] + pub redirect: Option<String>, + + #[serde(rename = "revision")] + #[serde(skip_serializing_if = "Option::is_none")] + pub revision: Option<isize>, + + #[serde(rename = "ident")] + #[serde(skip_serializing_if = "Option::is_none")] + pub ident: Option<String>, + + // Note: inline enums are not fully supported by swagger-codegen + #[serde(rename = "state")] + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option<String>, +} + +impl CreatorEntity { + pub fn new() -> CreatorEntity { + CreatorEntity { + orcid: None, + name: None, + editgroup: None, + redirect: None, + revision: None, + ident: None, + state: None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Editgroup { + #[serde(rename = "id")] + pub id: isize, + + #[serde(rename = "editor_id")] + pub editor_id: isize, +} + +impl Editgroup { + pub fn new(id: isize, editor_id: isize) -> Editgroup { + Editgroup { + id: id, + editor_id: editor_id, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Editor { + #[serde(rename = "username")] + pub username: String, +} + +impl Editor { + pub fn new(username: String) -> Editor { + Editor { username: username } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct EntityEdit { + #[serde(rename = "editgroup_id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub editgroup_id: Option<isize>, + + #[serde(rename = "revision")] + #[serde(skip_serializing_if = "Option::is_none")] + pub revision: Option<isize>, + + #[serde(rename = "ident")] + #[serde(skip_serializing_if = "Option::is_none")] + pub ident: Option<String>, + + #[serde(rename = "id")] + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option<isize>, +} + +impl EntityEdit { + pub fn new() -> EntityEdit { + EntityEdit { + editgroup_id: None, + revision: None, + ident: None, + id: None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Error { + #[serde(rename = "message")] + pub message: String, +} + +impl Error { + pub fn new(message: String) -> Error { + Error { message: message } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct FileEntity { + #[serde(rename = "url")] + #[serde(skip_serializing_if = "Option::is_none")] + pub url: Option<String>, + + #[serde(rename = "sha1")] + #[serde(skip_serializing_if = "Option::is_none")] + pub sha1: Option<String>, + + #[serde(rename = "size")] + #[serde(skip_serializing_if = "Option::is_none")] + pub size: Option<isize>, + + #[serde(rename = "editgroup")] + #[serde(skip_serializing_if = "Option::is_none")] + pub editgroup: Option<isize>, + + #[serde(rename = "redirect")] + #[serde(skip_serializing_if = "Option::is_none")] + pub redirect: Option<String>, + + #[serde(rename = "revision")] + #[serde(skip_serializing_if = "Option::is_none")] + pub revision: Option<isize>, + + #[serde(rename = "ident")] + #[serde(skip_serializing_if = "Option::is_none")] + pub ident: Option<String>, + + // Note: inline enums are not fully supported by swagger-codegen + #[serde(rename = "state")] + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option<String>, +} + +impl FileEntity { + pub fn new() -> FileEntity { + FileEntity { + url: None, + sha1: None, + size: None, + editgroup: None, + redirect: None, + revision: None, + ident: None, + state: None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ReleaseEntity { + #[serde(rename = "issue")] + #[serde(skip_serializing_if = "Option::is_none")] + pub issue: Option<String>, + + #[serde(rename = "pages")] + #[serde(skip_serializing_if = "Option::is_none")] + pub pages: Option<String>, + + #[serde(rename = "volume")] + #[serde(skip_serializing_if = "Option::is_none")] + pub volume: Option<String>, + + #[serde(rename = "doi")] + #[serde(skip_serializing_if = "Option::is_none")] + pub doi: Option<String>, + + #[serde(rename = "release_type")] + #[serde(skip_serializing_if = "Option::is_none")] + pub release_type: Option<String>, + + #[serde(rename = "license")] + #[serde(skip_serializing_if = "Option::is_none")] + pub license: Option<String>, + + #[serde(rename = "container")] + #[serde(skip_serializing_if = "Option::is_none")] + pub container: Option<String>, + + #[serde(rename = "work")] + #[serde(skip_serializing_if = "Option::is_none")] + pub work: Option<String>, + + // Note: inline enums are not fully supported by swagger-codegen + #[serde(rename = "state")] + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option<String>, + + #[serde(rename = "ident")] + #[serde(skip_serializing_if = "Option::is_none")] + pub ident: Option<String>, + + #[serde(rename = "revision")] + #[serde(skip_serializing_if = "Option::is_none")] + pub revision: Option<isize>, + + #[serde(rename = "redirect")] + #[serde(skip_serializing_if = "Option::is_none")] + pub redirect: Option<String>, + + #[serde(rename = "editgroup")] + #[serde(skip_serializing_if = "Option::is_none")] + pub editgroup: Option<isize>, +} + +impl ReleaseEntity { + pub fn new() -> ReleaseEntity { + ReleaseEntity { + issue: None, + pages: None, + volume: None, + doi: None, + release_type: None, + license: None, + container: None, + work: None, + state: None, + ident: None, + revision: None, + redirect: None, + editgroup: None, + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Success { + #[serde(rename = "message")] + pub message: String, +} + +impl Success { + pub fn new(message: String) -> Success { + Success { message: message } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct WorkEntity { + #[serde(rename = "work_type")] + #[serde(skip_serializing_if = "Option::is_none")] + pub work_type: Option<String>, + + #[serde(rename = "title")] + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option<String>, + + #[serde(rename = "editgroup")] + #[serde(skip_serializing_if = "Option::is_none")] + pub editgroup: Option<isize>, + + #[serde(rename = "redirect")] + #[serde(skip_serializing_if = "Option::is_none")] + pub redirect: Option<String>, + + #[serde(rename = "revision")] + #[serde(skip_serializing_if = "Option::is_none")] + pub revision: Option<isize>, + + #[serde(rename = "ident")] + #[serde(skip_serializing_if = "Option::is_none")] + pub ident: Option<String>, + + // Note: inline enums are not fully supported by swagger-codegen + #[serde(rename = "state")] + #[serde(skip_serializing_if = "Option::is_none")] + pub state: Option<String>, +} + +impl WorkEntity { + pub fn new() -> WorkEntity { + WorkEntity { + work_type: None, + title: None, + editgroup: None, + redirect: None, + revision: None, + ident: None, + state: None, + } + } +} diff --git a/rust/fatcat-api/src/server/auth.rs b/rust/fatcat-api/src/server/auth.rs new file mode 100644 index 00000000..48dfd7d6 --- /dev/null +++ b/rust/fatcat-api/src/server/auth.rs @@ -0,0 +1,93 @@ +use Api; +use hyper; +use hyper::{Error, Request, Response, StatusCode}; +use server::url::form_urlencoded; +use std::io; +use swagger::auth::{AuthData, Authorization, Scopes}; + +pub struct NewService<T> +where + T: hyper::server::NewService< + Request = (Request, Option<AuthData>), + Response = Response, + Error = Error, + >, +{ + inner: T, +} + +impl<T> NewService<T> +where + T: hyper::server::NewService< + Request = (Request, Option<AuthData>), + Response = Response, + Error = Error, + > + + 'static, +{ + pub fn new(inner: T) -> NewService<T> { + NewService { inner } + } +} + +impl<T> hyper::server::NewService for NewService<T> +where + T: hyper::server::NewService< + Request = (Request, Option<AuthData>), + Response = Response, + Error = Error, + > + + 'static, +{ + type Request = Request; + type Response = Response; + type Error = Error; + type Instance = Service<T::Instance>; + + fn new_service(&self) -> Result<Self::Instance, io::Error> { + self.inner.new_service().map(|s| Service::new(s)) + } +} + +/// Middleware to extract authentication data from request +pub struct Service<T> +where + T: hyper::server::Service< + Request = (Request, Option<AuthData>), + Response = Response, + Error = Error, + >, +{ + inner: T, +} + +impl<T> Service<T> +where + T: hyper::server::Service< + Request = (Request, Option<AuthData>), + Response = Response, + Error = Error, + >, +{ + pub fn new(inner: T) -> Service<T> { + Service { inner } + } +} + +impl<T> hyper::server::Service for Service<T> +where + T: hyper::server::Service< + Request = (Request, Option<AuthData>), + Response = Response, + Error = Error, + >, +{ + type Request = Request; + type Response = Response; + type Error = Error; + type Future = T::Future; + + fn call(&self, req: Self::Request) -> Self::Future { + return self.inner.call((req, None)); + } +} diff --git a/rust/fatcat-api/src/server/mod.rs b/rust/fatcat-api/src/server/mod.rs new file mode 100644 index 00000000..186f8272 --- /dev/null +++ b/rust/fatcat-api/src/server/mod.rs @@ -0,0 +1,2485 @@ +#![allow(unused_extern_crates)] +extern crate chrono; +extern crate hyper_tls; +extern crate mime; +extern crate native_tls; +extern crate openssl; +extern crate serde_ignored; +extern crate tokio_core; +extern crate uuid; + +extern crate percent_encoding; +extern crate url; + +use self::url::form_urlencoded; +use futures::{future, stream, Future, Stream}; +use hyper; +use hyper::header::{ContentType, Headers}; +use hyper::{Error, Request, Response, StatusCode}; +use mimetypes; +use std::sync::Arc; + +use serde_json; + +#[allow(unused_imports)] +use std::collections::{BTreeMap, HashMap}; +use std::io; +#[allow(unused_imports)] +use swagger; + +#[allow(unused_imports)] +use std::collections::BTreeSet; + +pub use swagger::auth::Authorization; +use swagger::auth::Scopes; +use swagger::{ApiError, Context, XSpanId}; + +#[allow(unused_imports)] +use models; +use {Api, ContainerIdGetResponse, ContainerLookupGetResponse, ContainerPostResponse, + CreatorIdGetResponse, CreatorLookupGetResponse, CreatorPostResponse, + EditgroupIdAcceptPostResponse, EditgroupIdGetResponse, EditgroupPostResponse, + EditorUsernameChangelogGetResponse, EditorUsernameGetResponse, FileIdGetResponse, + FileLookupGetResponse, FilePostResponse, ReleaseIdGetResponse, ReleaseLookupGetResponse, + ReleasePostResponse, WorkIdGetResponse, WorkPostResponse}; + +pub mod auth; + +header! { (Warning, "Warning") => [String] } + +mod paths { + extern crate regex; + + lazy_static! { + pub static ref GLOBAL_REGEX_SET: regex::RegexSet = regex::RegexSet::new(&[ + r"^/v0/container$", + r"^/v0/container/lookup$", + r"^/v0/container/(?P<id>[^/?#]*)$", + r"^/v0/creator$", + r"^/v0/creator/lookup$", + r"^/v0/creator/(?P<id>[^/?#]*)$", + r"^/v0/editgroup$", + r"^/v0/editgroup/(?P<id>[^/?#]*)$", + r"^/v0/editgroup/(?P<id>[^/?#]*)/accept$", + r"^/v0/editor/(?P<username>[^/?#]*)$", + r"^/v0/editor/(?P<username>[^/?#]*)/changelog$", + r"^/v0/file$", + r"^/v0/file/lookup$", + r"^/v0/file/(?P<id>[^/?#]*)$", + r"^/v0/release$", + r"^/v0/release/lookup$", + r"^/v0/release/(?P<id>[^/?#]*)$", + r"^/v0/work$", + r"^/v0/work/(?P<id>[^/?#]*)$" + ]).unwrap(); + } + pub static ID_CONTAINER: usize = 0; + pub static ID_CONTAINER_LOOKUP: usize = 1; + pub static ID_CONTAINER_ID: usize = 2; + lazy_static! { + pub static ref REGEX_CONTAINER_ID: regex::Regex = + regex::Regex::new(r"^/v0/container/(?P<id>[^/?#]*)$").unwrap(); + } + pub static ID_CREATOR: usize = 3; + pub static ID_CREATOR_LOOKUP: usize = 4; + pub static ID_CREATOR_ID: usize = 5; + lazy_static! { + pub static ref REGEX_CREATOR_ID: regex::Regex = + regex::Regex::new(r"^/v0/creator/(?P<id>[^/?#]*)$").unwrap(); + } + pub static ID_EDITGROUP: usize = 6; + pub static ID_EDITGROUP_ID: usize = 7; + lazy_static! { + pub static ref REGEX_EDITGROUP_ID: regex::Regex = + regex::Regex::new(r"^/v0/editgroup/(?P<id>[^/?#]*)$").unwrap(); + } + pub static ID_EDITGROUP_ID_ACCEPT: usize = 8; + lazy_static! { + pub static ref REGEX_EDITGROUP_ID_ACCEPT: regex::Regex = + regex::Regex::new(r"^/v0/editgroup/(?P<id>[^/?#]*)/accept$").unwrap(); + } + pub static ID_EDITOR_USERNAME: usize = 9; + lazy_static! { + pub static ref REGEX_EDITOR_USERNAME: regex::Regex = + regex::Regex::new(r"^/v0/editor/(?P<username>[^/?#]*)$").unwrap(); + } + pub static ID_EDITOR_USERNAME_CHANGELOG: usize = 10; + lazy_static! { + pub static ref REGEX_EDITOR_USERNAME_CHANGELOG: regex::Regex = + regex::Regex::new(r"^/v0/editor/(?P<username>[^/?#]*)/changelog$").unwrap(); + } + pub static ID_FILE: usize = 11; + pub static ID_FILE_LOOKUP: usize = 12; + pub static ID_FILE_ID: usize = 13; + lazy_static! { + pub static ref REGEX_FILE_ID: regex::Regex = + regex::Regex::new(r"^/v0/file/(?P<id>[^/?#]*)$").unwrap(); + } + pub static ID_RELEASE: usize = 14; + pub static ID_RELEASE_LOOKUP: usize = 15; + pub static ID_RELEASE_ID: usize = 16; + lazy_static! { + pub static ref REGEX_RELEASE_ID: regex::Regex = + regex::Regex::new(r"^/v0/release/(?P<id>[^/?#]*)$").unwrap(); + } + pub static ID_WORK: usize = 17; + pub static ID_WORK_ID: usize = 18; + lazy_static! { + pub static ref REGEX_WORK_ID: regex::Regex = + regex::Regex::new(r"^/v0/work/(?P<id>[^/?#]*)$").unwrap(); + } +} + +pub struct NewService<T> { + api_impl: Arc<T>, +} + +impl<T> NewService<T> +where + T: Api + Clone + 'static, +{ + pub fn new<U: Into<Arc<T>>>(api_impl: U) -> NewService<T> { + NewService { + api_impl: api_impl.into(), + } + } +} + +impl<T> hyper::server::NewService for NewService<T> +where + T: Api + Clone + 'static, +{ + type Request = (Request, Context); + type Response = Response; + type Error = Error; + type Instance = Service<T>; + + fn new_service(&self) -> Result<Self::Instance, io::Error> { + Ok(Service::new(self.api_impl.clone())) + } +} + +pub struct Service<T> { + api_impl: Arc<T>, +} + +impl<T> Service<T> +where + T: Api + Clone + 'static, +{ + pub fn new<U: Into<Arc<T>>>(api_impl: U) -> Service<T> { + Service { + api_impl: api_impl.into(), + } + } +} + +impl<T> hyper::server::Service for Service<T> +where + T: Api + Clone + 'static, +{ + type Request = (Request, Context); + type Response = Response; + type Error = Error; + type Future = Box<Future<Item = Response, Error = Error>>; + + fn call(&self, (req, mut context): Self::Request) -> Self::Future { + let api_impl = self.api_impl.clone(); + let (method, uri, _, headers, body) = req.deconstruct(); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + match &method { + // ContainerIdGet - GET /container/{id} + &hyper::Method::Get if path.matched(paths::ID_CONTAINER_ID) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_CONTAINER_ID + .captures(&path) + .unwrap_or_else(|| { + panic!("Path {} matched RE CONTAINER_ID in set but failed match against \"{}\"", path, paths::REGEX_CONTAINER_ID.as_str()) + }); + + let param_id = match percent_encoding::percent_decode(path_params["id"].as_bytes()) + .decode_utf8() + { + Ok(param_id) => match param_id.parse::<String>() { + Ok(param_id) => param_id, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't parse path parameter id: {}", e)), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["id"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.container_id_get(param_id, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + ContainerIdGetResponse::FetchASingleContainerById + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_ID_GET_FETCH_A_SINGLE_CONTAINER_BY_ID.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + ContainerIdGetResponse::BadRequest + + (body) + + + => { + response.set_status(StatusCode::try_from(400).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_ID_GET_BAD_REQUEST.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + ContainerIdGetResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_ID_GET_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // ContainerLookupGet - GET /container/lookup + &hyper::Method::Get if path.matched(paths::ID_CONTAINER_LOOKUP) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = form_urlencoded::parse( + uri.query().unwrap_or_default().as_bytes(), + ).collect::<Vec<_>>(); + let param_issn = query_params + .iter() + .filter(|e| e.0 == "issn") + .map(|e| e.1.to_owned()) + .nth(0); + let param_issn = match param_issn { + Some(param_issn) => match param_issn.parse::<String>() { + Ok(param_issn) => param_issn, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't parse query parameter issn - doesn't match schema: {}", + e + )), + )) + } + }, + None => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body("Missing required query parameter issn"), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.container_lookup_get(param_issn, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + ContainerLookupGetResponse::FindASingleContainerByExternalIdentifer + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_LOOKUP_GET_FIND_A_SINGLE_CONTAINER_BY_EXTERNAL_IDENTIFER.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + ContainerLookupGetResponse::BadRequest + + (body) + + + => { + response.set_status(StatusCode::try_from(400).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_LOOKUP_GET_BAD_REQUEST.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + ContainerLookupGetResponse::NoSuchContainer + + (body) + + + => { + response.set_status(StatusCode::try_from(404).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_LOOKUP_GET_NO_SUCH_CONTAINER.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + ContainerLookupGetResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_LOOKUP_GET_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // ContainerPost - POST /container + &hyper::Method::Post if path.matched(paths::ID_CONTAINER) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2().then( + move |result| -> Box<Future<Item = Response, Error = Error>> { + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option< + models::ContainerEntity, + > = if !body.is_empty() { + let deserializer = + &mut serde_json::Deserializer::from_slice(&*body); + + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + + Err(_) => None, + } + } else { + None + }; + + Box::new(api_impl.container_post(param_body, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + if !unused_elements.is_empty() { + response.headers_mut().set(Warning(format!( + "Ignoring unknown fields in body: {:?}", + unused_elements + ))); + } + + match result { + Ok(rsp) => match rsp { + ContainerPostResponse::Created(body) => { + response.set_status( + StatusCode::try_from(201).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_POST_CREATED.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + ContainerPostResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_POST_BAD_REQUEST.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + ContainerPostResponse::GenericErrorResponse( + body, + ) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::CONTAINER_POST_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + Err(e) => Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't read body parameter body: {}", e)), + )), + } + }, + )) as Box<Future<Item = Response, Error = Error>> + } + + // CreatorIdGet - GET /creator/{id} + &hyper::Method::Get if path.matched(paths::ID_CREATOR_ID) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_CREATOR_ID.captures(&path).unwrap_or_else(|| { + panic!( + "Path {} matched RE CREATOR_ID in set but failed match against \"{}\"", + path, + paths::REGEX_CREATOR_ID.as_str() + ) + }); + + let param_id = match percent_encoding::percent_decode(path_params["id"].as_bytes()) + .decode_utf8() + { + Ok(param_id) => match param_id.parse::<String>() { + Ok(param_id) => param_id, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't parse path parameter id: {}", e)), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["id"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.creator_id_get(param_id, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + CreatorIdGetResponse::FetchASingleCreatorById( + body, + ) => { + response.set_status( + StatusCode::try_from(200).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_ID_GET_FETCH_A_SINGLE_CREATOR_BY_ID.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + CreatorIdGetResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_ID_GET_BAD_REQUEST.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + CreatorIdGetResponse::GenericErrorResponse( + body, + ) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_ID_GET_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // CreatorLookupGet - GET /creator/lookup + &hyper::Method::Get if path.matched(paths::ID_CREATOR_LOOKUP) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = form_urlencoded::parse( + uri.query().unwrap_or_default().as_bytes(), + ).collect::<Vec<_>>(); + let param_orcid = query_params + .iter() + .filter(|e| e.0 == "orcid") + .map(|e| e.1.to_owned()) + .nth(0); + let param_orcid = match param_orcid { + Some(param_orcid) => match param_orcid.parse::<String>() { + Ok(param_orcid) => param_orcid, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't parse query parameter orcid - doesn't match schema: {}", + e + )), + )) + } + }, + None => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body("Missing required query parameter orcid"), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.creator_lookup_get(param_orcid, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + CreatorLookupGetResponse::FindASingleCreatorByExternalIdentifer + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_LOOKUP_GET_FIND_A_SINGLE_CREATOR_BY_EXTERNAL_IDENTIFER.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + CreatorLookupGetResponse::BadRequest + + (body) + + + => { + response.set_status(StatusCode::try_from(400).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_LOOKUP_GET_BAD_REQUEST.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + CreatorLookupGetResponse::NoSuchCreator + + (body) + + + => { + response.set_status(StatusCode::try_from(404).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_LOOKUP_GET_NO_SUCH_CREATOR.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + CreatorLookupGetResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_LOOKUP_GET_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // CreatorPost - POST /creator + &hyper::Method::Post if path.matched(paths::ID_CREATOR) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2().then( + move |result| -> Box<Future<Item = Response, Error = Error>> { + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option< + models::CreatorEntity, + > = if !body.is_empty() { + let deserializer = + &mut serde_json::Deserializer::from_slice(&*body); + + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + + Err(_) => None, + } + } else { + None + }; + + Box::new(api_impl.creator_post(param_body, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + if !unused_elements.is_empty() { + response.headers_mut().set(Warning(format!( + "Ignoring unknown fields in body: {:?}", + unused_elements + ))); + } + + match result { + Ok(rsp) => match rsp { + CreatorPostResponse::Created(body) => { + response.set_status( + StatusCode::try_from(201).unwrap(), + ); + + response.headers_mut().set(ContentType( + mimetypes::responses::CREATOR_POST_CREATED + .clone(), + )); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + CreatorPostResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_POST_BAD_REQUEST.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + CreatorPostResponse::GenericErrorResponse(body) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::CREATOR_POST_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + Err(e) => Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't read body parameter body: {}", e)), + )), + } + }, + )) as Box<Future<Item = Response, Error = Error>> + } + + // EditgroupIdAcceptPost - POST /editgroup/{id}/accept + &hyper::Method::Post if path.matched(paths::ID_EDITGROUP_ID_ACCEPT) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_EDITGROUP_ID_ACCEPT + .captures(&path) + .unwrap_or_else(|| { + panic!("Path {} matched RE EDITGROUP_ID_ACCEPT in set but failed match against \"{}\"", path, paths::REGEX_EDITGROUP_ID_ACCEPT.as_str()) + }); + + let param_id = match percent_encoding::percent_decode(path_params["id"].as_bytes()) + .decode_utf8() + { + Ok(param_id) => match param_id.parse::<i32>() { + Ok(param_id) => param_id, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't parse path parameter id: {}", e)), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["id"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new( + api_impl.editgroup_id_accept_post(param_id, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + EditgroupIdAcceptPostResponse::MergedEditgroupSuccessfully_ + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_ID_ACCEPT_POST_MERGED_EDITGROUP_SUCCESSFULLY_.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditgroupIdAcceptPostResponse::EditgroupIsInAnUnmergableState + + (body) + + + => { + response.set_status(StatusCode::try_from(400).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_ID_ACCEPT_POST_EDITGROUP_IS_IN_AN_UNMERGABLE_STATE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditgroupIdAcceptPostResponse::NoSuchEditgroup + + (body) + + + => { + response.set_status(StatusCode::try_from(404).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_ID_ACCEPT_POST_NO_SUCH_EDITGROUP.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditgroupIdAcceptPostResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_ID_ACCEPT_POST_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }, + ), + ) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // EditgroupIdGet - GET /editgroup/{id} + &hyper::Method::Get if path.matched(paths::ID_EDITGROUP_ID) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_EDITGROUP_ID + .captures(&path) + .unwrap_or_else(|| { + panic!("Path {} matched RE EDITGROUP_ID in set but failed match against \"{}\"", path, paths::REGEX_EDITGROUP_ID.as_str()) + }); + + let param_id = match percent_encoding::percent_decode(path_params["id"].as_bytes()) + .decode_utf8() + { + Ok(param_id) => match param_id.parse::<i32>() { + Ok(param_id) => param_id, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't parse path parameter id: {}", e)), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["id"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.editgroup_id_get(param_id, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + EditgroupIdGetResponse::FetchEditgroupByIdentifier + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_ID_GET_FETCH_EDITGROUP_BY_IDENTIFIER.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditgroupIdGetResponse::NoSuchEditgroup + + (body) + + + => { + response.set_status(StatusCode::try_from(404).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_ID_GET_NO_SUCH_EDITGROUP.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditgroupIdGetResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_ID_GET_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // EditgroupPost - POST /editgroup + &hyper::Method::Post if path.matched(paths::ID_EDITGROUP) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + Box::new( + ({ + { + { + Box::new(api_impl.editgroup_post(&context).then(move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + EditgroupPostResponse::SuccessfullyCreated(body) => { + response + .set_status(StatusCode::try_from(201).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_POST_SUCCESSFULLY_CREATED.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + EditgroupPostResponse::InvalidRequestParameters( + body, + ) => { + response + .set_status(StatusCode::try_from(400).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_POST_INVALID_REQUEST_PARAMETERS.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + EditgroupPostResponse::GenericErrorResponse(body) => { + response + .set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITGROUP_POST_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + })) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // EditorUsernameChangelogGet - GET /editor/{username}/changelog + &hyper::Method::Get if path.matched(paths::ID_EDITOR_USERNAME_CHANGELOG) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_EDITOR_USERNAME_CHANGELOG + .captures(&path) + .unwrap_or_else(|| { + panic!("Path {} matched RE EDITOR_USERNAME_CHANGELOG in set but failed match against \"{}\"", path, paths::REGEX_EDITOR_USERNAME_CHANGELOG.as_str()) + }); + + let param_username = match percent_encoding::percent_decode( + path_params["username"].as_bytes(), + ).decode_utf8() + { + Ok(param_username) => match param_username.parse::<String>() { + Ok(param_username) => param_username, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't parse path parameter username: {}", + e + )), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["username"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new( + api_impl + .editor_username_changelog_get(param_username, &context) + .then(move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + EditorUsernameChangelogGetResponse::FindChanges_ + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITOR_USERNAME_CHANGELOG_GET_FIND_CHANGES_.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditorUsernameChangelogGetResponse::UsernameNotFound + + (body) + + + => { + response.set_status(StatusCode::try_from(404).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITOR_USERNAME_CHANGELOG_GET_USERNAME_NOT_FOUND.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditorUsernameChangelogGetResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITOR_USERNAME_CHANGELOG_GET_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }), + ) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // EditorUsernameGet - GET /editor/{username} + &hyper::Method::Get if path.matched(paths::ID_EDITOR_USERNAME) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_EDITOR_USERNAME.captures(&path).unwrap_or_else( + || { + panic!("Path {} matched RE EDITOR_USERNAME in set but failed match against \"{}\"", path, paths::REGEX_EDITOR_USERNAME.as_str()) + }, + ); + + let param_username = match percent_encoding::percent_decode( + path_params["username"].as_bytes(), + ).decode_utf8() + { + Ok(param_username) => match param_username.parse::<String>() { + Ok(param_username) => param_username, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't parse path parameter username: {}", + e + )), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["username"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new( + api_impl.editor_username_get(param_username, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + EditorUsernameGetResponse::FetchGenericInformationAboutAnEditor + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITOR_USERNAME_GET_FETCH_GENERIC_INFORMATION_ABOUT_AN_EDITOR.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditorUsernameGetResponse::UsernameNotFound + + (body) + + + => { + response.set_status(StatusCode::try_from(404).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITOR_USERNAME_GET_USERNAME_NOT_FOUND.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + EditorUsernameGetResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::EDITOR_USERNAME_GET_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }, + ), + ) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // FileIdGet - GET /file/{id} + &hyper::Method::Get if path.matched(paths::ID_FILE_ID) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_FILE_ID.captures(&path).unwrap_or_else(|| { + panic!( + "Path {} matched RE FILE_ID in set but failed match against \"{}\"", + path, + paths::REGEX_FILE_ID.as_str() + ) + }); + + let param_id = match percent_encoding::percent_decode(path_params["id"].as_bytes()) + .decode_utf8() + { + Ok(param_id) => match param_id.parse::<String>() { + Ok(param_id) => param_id, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't parse path parameter id: {}", e)), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["id"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.file_id_get(param_id, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + FileIdGetResponse::FetchASingleFileById(body) => { + response.set_status( + StatusCode::try_from(200).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::FILE_ID_GET_FETCH_A_SINGLE_FILE_BY_ID.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + FileIdGetResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::FILE_ID_GET_BAD_REQUEST.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + FileIdGetResponse::GenericErrorResponse(body) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::FILE_ID_GET_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // FileLookupGet - GET /file/lookup + &hyper::Method::Get if path.matched(paths::ID_FILE_LOOKUP) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = form_urlencoded::parse( + uri.query().unwrap_or_default().as_bytes(), + ).collect::<Vec<_>>(); + let param_sha1 = query_params + .iter() + .filter(|e| e.0 == "sha1") + .map(|e| e.1.to_owned()) + .nth(0); + let param_sha1 = match param_sha1 { + Some(param_sha1) => match param_sha1.parse::<String>() { + Ok(param_sha1) => param_sha1, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't parse query parameter sha1 - doesn't match schema: {}", + e + )), + )) + } + }, + None => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body("Missing required query parameter sha1"), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.file_lookup_get(param_sha1, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + FileLookupGetResponse::FindASingleFileByExternalIdentifer + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::FILE_LOOKUP_GET_FIND_A_SINGLE_FILE_BY_EXTERNAL_IDENTIFER.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + FileLookupGetResponse::BadRequest + + (body) + + + => { + response.set_status(StatusCode::try_from(400).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::FILE_LOOKUP_GET_BAD_REQUEST.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + FileLookupGetResponse::NoSuchFile + + (body) + + + => { + response.set_status(StatusCode::try_from(404).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::FILE_LOOKUP_GET_NO_SUCH_FILE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + FileLookupGetResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::FILE_LOOKUP_GET_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // FilePost - POST /file + &hyper::Method::Post if path.matched(paths::ID_FILE) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2().then( + move |result| -> Box<Future<Item = Response, Error = Error>> { + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option< + models::FileEntity, + > = if !body.is_empty() { + let deserializer = + &mut serde_json::Deserializer::from_slice(&*body); + + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + + Err(_) => None, + } + } else { + None + }; + + Box::new(api_impl.file_post(param_body, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + if !unused_elements.is_empty() { + response.headers_mut().set(Warning(format!( + "Ignoring unknown fields in body: {:?}", + unused_elements + ))); + } + + match result { + Ok(rsp) => match rsp { + FilePostResponse::Created(body) => { + response.set_status( + StatusCode::try_from(201).unwrap(), + ); + + response.headers_mut().set(ContentType( + mimetypes::responses::FILE_POST_CREATED + .clone(), + )); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + FilePostResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType( + mimetypes::responses::FILE_POST_BAD_REQUEST + .clone(), + )); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + FilePostResponse::GenericErrorResponse(body) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::FILE_POST_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + Err(e) => Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't read body parameter body: {}", e)), + )), + } + }, + )) as Box<Future<Item = Response, Error = Error>> + } + + // ReleaseIdGet - GET /release/{id} + &hyper::Method::Get if path.matched(paths::ID_RELEASE_ID) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_RELEASE_ID.captures(&path).unwrap_or_else(|| { + panic!( + "Path {} matched RE RELEASE_ID in set but failed match against \"{}\"", + path, + paths::REGEX_RELEASE_ID.as_str() + ) + }); + + let param_id = match percent_encoding::percent_decode(path_params["id"].as_bytes()) + .decode_utf8() + { + Ok(param_id) => match param_id.parse::<String>() { + Ok(param_id) => param_id, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't parse path parameter id: {}", e)), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["id"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.release_id_get(param_id, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + ReleaseIdGetResponse::FetchASingleReleaseById( + body, + ) => { + response.set_status( + StatusCode::try_from(200).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_ID_GET_FETCH_A_SINGLE_RELEASE_BY_ID.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + ReleaseIdGetResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_ID_GET_BAD_REQUEST.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + ReleaseIdGetResponse::GenericErrorResponse( + body, + ) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_ID_GET_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // ReleaseLookupGet - GET /release/lookup + &hyper::Method::Get if path.matched(paths::ID_RELEASE_LOOKUP) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = form_urlencoded::parse( + uri.query().unwrap_or_default().as_bytes(), + ).collect::<Vec<_>>(); + let param_doi = query_params + .iter() + .filter(|e| e.0 == "doi") + .map(|e| e.1.to_owned()) + .nth(0); + let param_doi = match param_doi { + Some(param_doi) => match param_doi.parse::<String>() { + Ok(param_doi) => param_doi, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't parse query parameter doi - doesn't match schema: {}", + e + )), + )) + } + }, + None => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body("Missing required query parameter doi"), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.release_lookup_get(param_doi, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + ReleaseLookupGetResponse::FindASingleReleaseByExternalIdentifer + + (body) + + + => { + response.set_status(StatusCode::try_from(200).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_LOOKUP_GET_FIND_A_SINGLE_RELEASE_BY_EXTERNAL_IDENTIFER.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + ReleaseLookupGetResponse::BadRequest + + (body) + + + => { + response.set_status(StatusCode::try_from(400).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_LOOKUP_GET_BAD_REQUEST.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + ReleaseLookupGetResponse::NoSuchRelease + + (body) + + + => { + response.set_status(StatusCode::try_from(404).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_LOOKUP_GET_NO_SUCH_RELEASE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + ReleaseLookupGetResponse::GenericErrorResponse + + (body) + + + => { + response.set_status(StatusCode::try_from(0).unwrap()); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_LOOKUP_GET_GENERIC_ERROR_RESPONSE.clone())); + + + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + response.set_body(body); + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response.set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + }, + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // ReleasePost - POST /release + &hyper::Method::Post if path.matched(paths::ID_RELEASE) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2().then( + move |result| -> Box<Future<Item = Response, Error = Error>> { + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option< + models::ReleaseEntity, + > = if !body.is_empty() { + let deserializer = + &mut serde_json::Deserializer::from_slice(&*body); + + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + + Err(_) => None, + } + } else { + None + }; + + Box::new(api_impl.release_post(param_body, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + if !unused_elements.is_empty() { + response.headers_mut().set(Warning(format!( + "Ignoring unknown fields in body: {:?}", + unused_elements + ))); + } + + match result { + Ok(rsp) => match rsp { + ReleasePostResponse::Created(body) => { + response.set_status( + StatusCode::try_from(201).unwrap(), + ); + + response.headers_mut().set(ContentType( + mimetypes::responses::RELEASE_POST_CREATED + .clone(), + )); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + ReleasePostResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_POST_BAD_REQUEST.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + ReleasePostResponse::GenericErrorResponse(body) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::RELEASE_POST_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + Err(e) => Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't read body parameter body: {}", e)), + )), + } + }, + )) as Box<Future<Item = Response, Error = Error>> + } + + // WorkIdGet - GET /work/{id} + &hyper::Method::Get if path.matched(paths::ID_WORK_ID) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Path parameters + let path = uri.path().to_string(); + let path_params = paths::REGEX_WORK_ID.captures(&path).unwrap_or_else(|| { + panic!( + "Path {} matched RE WORK_ID in set but failed match against \"{}\"", + path, + paths::REGEX_WORK_ID.as_str() + ) + }); + + let param_id = match percent_encoding::percent_decode(path_params["id"].as_bytes()) + .decode_utf8() + { + Ok(param_id) => match param_id.parse::<String>() { + Ok(param_id) => param_id, + Err(e) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't parse path parameter id: {}", e)), + )) + } + }, + Err(_) => { + return Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!( + "Couldn't percent-decode path parameter as UTF-8: {}", + &path_params["id"] + )), + )) + } + }; + + Box::new( + ({ + { + { + Box::new(api_impl.work_id_get(param_id, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + match result { + Ok(rsp) => match rsp { + WorkIdGetResponse::FetchASingleWorkById(body) => { + response.set_status( + StatusCode::try_from(200).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::WORK_ID_GET_FETCH_A_SINGLE_WORK_BY_ID.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + WorkIdGetResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::WORK_ID_GET_BAD_REQUEST.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + WorkIdGetResponse::GenericErrorResponse(body) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::WORK_ID_GET_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + } + }), + ) as Box<Future<Item = Response, Error = Error>> + } + + // WorkPost - POST /work + &hyper::Method::Post if path.matched(paths::ID_WORK) => { + if context.x_span_id.is_none() { + context.x_span_id = Some( + headers + .get::<XSpanId>() + .map(XSpanId::to_string) + .unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string()), + ); + } + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + Box::new(body.concat2().then( + move |result| -> Box<Future<Item = Response, Error = Error>> { + match result { + Ok(body) => { + let mut unused_elements = Vec::new(); + let param_body: Option< + models::WorkEntity, + > = if !body.is_empty() { + let deserializer = + &mut serde_json::Deserializer::from_slice(&*body); + + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + + Err(_) => None, + } + } else { + None + }; + + Box::new(api_impl.work_post(param_body, &context).then( + move |result| { + let mut response = Response::new(); + context.x_span_id.as_ref().map(|header| { + response.headers_mut().set(XSpanId(header.clone())) + }); + + if !unused_elements.is_empty() { + response.headers_mut().set(Warning(format!( + "Ignoring unknown fields in body: {:?}", + unused_elements + ))); + } + + match result { + Ok(rsp) => match rsp { + WorkPostResponse::Created(body) => { + response.set_status( + StatusCode::try_from(201).unwrap(), + ); + + response.headers_mut().set(ContentType( + mimetypes::responses::WORK_POST_CREATED + .clone(), + )); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + WorkPostResponse::BadRequest(body) => { + response.set_status( + StatusCode::try_from(400).unwrap(), + ); + + response.headers_mut().set(ContentType( + mimetypes::responses::WORK_POST_BAD_REQUEST + .clone(), + )); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + WorkPostResponse::GenericErrorResponse(body) => { + response.set_status( + StatusCode::try_from(0).unwrap(), + ); + + response.headers_mut().set(ContentType(mimetypes::responses::WORK_POST_GENERIC_ERROR_RESPONSE.clone())); + + let body = serde_json::to_string(&body) + .expect("impossible to fail to serialize"); + + response.set_body(body); + } + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + response + .set_status(StatusCode::InternalServerError); + response.set_body("An internal error occurred"); + } + } + + future::ok(response) + }, + )) + } + Err(e) => Box::new(future::ok( + Response::new() + .with_status(StatusCode::BadRequest) + .with_body(format!("Couldn't read body parameter body: {}", e)), + )), + } + }, + )) as Box<Future<Item = Response, Error = Error>> + } + + _ => Box::new(future::ok( + Response::new().with_status(StatusCode::NotFound), + )) as Box<Future<Item = Response, Error = Error>>, + } + } +} |