diff options
| -rw-r--r-- | rust/fatcat-openapi/Cargo.toml | 2 | ||||
| -rw-r--r-- | rust/fatcat-openapi/README.md | 7 | ||||
| -rw-r--r-- | rust/fatcat-openapi/api.yaml | 49 | ||||
| -rw-r--r-- | rust/fatcat-openapi/api/swagger.yaml | 92 | ||||
| -rw-r--r-- | rust/fatcat-openapi/examples/client.rs | 33 | ||||
| -rw-r--r-- | rust/fatcat-openapi/examples/server_lib/server.rs | 38 | ||||
| -rw-r--r-- | rust/fatcat-openapi/src/client.rs | 109 | ||||
| -rw-r--r-- | rust/fatcat-openapi/src/lib.rs | 22 | ||||
| -rw-r--r-- | rust/fatcat-openapi/src/mimetypes.rs | 20 | ||||
| -rw-r--r-- | rust/fatcat-openapi/src/models.rs | 12 | ||||
| -rw-r--r-- | rust/fatcat-openapi/src/server.rs | 134 | 
11 files changed, 460 insertions, 58 deletions
| diff --git a/rust/fatcat-openapi/Cargo.toml b/rust/fatcat-openapi/Cargo.toml index 835b9a8b..a07b1424 100644 --- a/rust/fatcat-openapi/Cargo.toml +++ b/rust/fatcat-openapi/Cargo.toml @@ -1,6 +1,6 @@  [package]  name = "fatcat-openapi" -version = "0.3.0" +version = "0.3.1"  authors = ["Bryan Newbold <bnewbold@archive.org>"]  description = "HTTP API models, endpoints, and other auto-generated types"  license = "CC-0" diff --git a/rust/fatcat-openapi/README.md b/rust/fatcat-openapi/README.md index d4cd91d1..1e02e033 100644 --- a/rust/fatcat-openapi/README.md +++ b/rust/fatcat-openapi/README.md @@ -12,8 +12,8 @@ To see how to make this your own, look here:  [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) -- API version: 0.3.0 -- Build date: 2019-09-13T18:30:17.409Z +- API version: 0.3.1 +- Build date: 2019-09-19T00:21:33.977Z  For more information, please visit [https://fatcat.wiki](https://fatcat.wiki)  This autogenerated project defines an API crate `fatcat` which contains: @@ -59,6 +59,7 @@ To run a client, follow one of the following simple steps:  ```  cargo run --example client AuthCheck  cargo run --example client AuthOidc +cargo run --example client CreateAuthToken  cargo run --example client GetChangelog  cargo run --example client GetChangelogEntry  cargo run --example client CreateContainer @@ -170,7 +171,7 @@ The server example is designed to form the basis for implementing your own serve  * Set up a new Rust project, e.g., with `cargo init --bin`.  * Insert `fatcat` into the `members` array under [workspace] in the root `Cargo.toml`, e.g., `members = [ "fatcat" ]`. -* Add `fatcat = {version = "0.3.0", path = "fatcat"}` under `[dependencies]` in the root `Cargo.toml`. +* Add `fatcat = {version = "0.3.1", path = "fatcat"}` under `[dependencies]` in the root `Cargo.toml`.  * Copy the `[dependencies]` and `[dev-dependencies]` from `fatcat/Cargo.toml` into the root `Cargo.toml`'s `[dependencies]` section.    * Copy all of the `[dev-dependencies]`, but only the `[dependencies]` that are required by the example server. These should be clearly indicated by comments.    * Remove `"optional = true"` from each of these lines if present. diff --git a/rust/fatcat-openapi/api.yaml b/rust/fatcat-openapi/api.yaml index 3de72126..1b533a30 100644 --- a/rust/fatcat-openapi/api.yaml +++ b/rust/fatcat-openapi/api.yaml @@ -2,7 +2,7 @@  swagger: "2.0"  info:    title: fatcat -  version: 0.3.0 +  version: 0.3.1    description: |      Fatcat is a scalable, versioned, API-oriented catalog of bibliographic      entities and file metadata. @@ -1392,6 +1392,14 @@ definitions:        token:          type: string          example: "AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=" +  auth_token_result: +    type: object +    required: +      - token +    properties: +      token: +        type: string +        example: "AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug="  x-auth-responses: &AUTHRESPONSES    401: @@ -4024,4 +4032,43 @@ paths:            schema:              $ref: "#/definitions/error_response"          <<: *AUTHRESPONSES +  /auth/token/{editor_id}: +    parameters: +      - name: editor_id +        in: path +        type: string +        required: true +    post: +      operationId: "create_auth_token" +      tags: # TAGLINE +        - auth  # TAGLINE +      description: | +        Generate a new auth token for a given editor (internal method). +        This method is used by the web interface to generate API tokens for +        users. It can not be called by editors (human or bot) to generate new +        tokens for themselves, at least at this time. +      security: +        # required admin privs +        - Bearer: [] +      parameters: +        - name: duration_seconds +          in: query +          type: integer +          example: 86400 +          required: false +          description: "How long API token should be valid for (in seconds)" +      responses: +        200: +          description: Success +          schema: +            $ref: "#/definitions/auth_token_result" +        400: +          description: Bad Request +          schema: +            $ref: "#/definitions/error_response" +        500: +          description: Generic Error +          schema: +            $ref: "#/definitions/error_response" +        <<: *AUTHRESPONSES diff --git a/rust/fatcat-openapi/api/swagger.yaml b/rust/fatcat-openapi/api/swagger.yaml index 296570af..effedcda 100644 --- a/rust/fatcat-openapi/api/swagger.yaml +++ b/rust/fatcat-openapi/api/swagger.yaml @@ -42,7 +42,7 @@ info:      \ all API\nauthentication. The web interface includes macaroons in browser cookies\      \ and\npasses them through to the API to authenticate editor actions.\n\n<!--\      \ ReDoc-Inject: <security-definitions> -->\n<!-- ENDLONGDESCRIPTION -->\n" -  version: "0.3.0" +  version: "0.3.1"    title: "fatcat"    termsOfService: "https://guide.fatcat.wiki/policies.html"    contact: @@ -7521,6 +7521,85 @@ paths:        path: "/auth/check"        HttpMethod: "Get"        httpmethod: "get" +  /auth/token/{editor_id}: +    post: +      tags: +      - "auth" +      description: "Generate a new auth token for a given editor (internal method).\n\ +        \nThis method is used by the web interface to generate API tokens for\nusers.\ +        \ It can not be called by editors (human or bot) to generate new\ntokens for\ +        \ themselves, at least at this time.\n" +      operationId: "create_auth_token" +      parameters: +      - name: "editor_id" +        in: "path" +        required: true +        type: "string" +        formatString: "\\\"{}\\\"" +        example: "\"editor_id_example\".to_string()" +      - name: "duration_seconds" +        in: "query" +        description: "How long API token should be valid for (in seconds)" +        required: false +        type: "integer" +        formatString: "{:?}" +        example: "Some(56)" +      responses: +        200: +          description: "Success" +          schema: +            $ref: "#/definitions/auth_token_result" +          x-responseId: "Success" +          x-uppercaseResponseId: "SUCCESS" +          uppercase_operation_id: "CREATE_AUTH_TOKEN" +          uppercase_data_type: "AUTHTOKENRESULT" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "CREATE_AUTH_TOKEN" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        401: +          description: "Not Authorized" +          schema: +            $ref: "#/definitions/error_response" +          headers: +            WWW_Authenticate: +              type: "string" +          x-responseId: "NotAuthorized" +          x-uppercaseResponseId: "NOT_AUTHORIZED" +          uppercase_operation_id: "CREATE_AUTH_TOKEN" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        403: +          description: "Forbidden" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "Forbidden" +          x-uppercaseResponseId: "FORBIDDEN" +          uppercase_operation_id: "CREATE_AUTH_TOKEN" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        500: +          description: "Generic Error" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "GenericError" +          x-uppercaseResponseId: "GENERIC_ERROR" +          uppercase_operation_id: "CREATE_AUTH_TOKEN" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      security: +      - Bearer: [] +      operation_id: "create_auth_token" +      uppercase_operation_id: "CREATE_AUTH_TOKEN" +      path: "/auth/token/:editor_id" +      HttpMethod: "Post" +      httpmethod: "post"  securityDefinitions:    Bearer:      description: "The only current API authentication mechanism is HTTP bearer\nauthentication\ @@ -9951,6 +10030,17 @@ definitions:          username: "zerocool93"        token: "AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug="      upperCaseName: "AUTH_OIDC_RESULT" +  auth_token_result: +    type: "object" +    required: +    - "token" +    properties: +      token: +        type: "string" +        example: "AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=" +    example: +      token: "AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=" +    upperCaseName: "AUTH_TOKEN_RESULT"    editgroup_edits:      properties:        containers: diff --git a/rust/fatcat-openapi/examples/client.rs b/rust/fatcat-openapi/examples/client.rs index 502d8ee6..d7b3965f 100644 --- a/rust/fatcat-openapi/examples/client.rs +++ b/rust/fatcat-openapi/examples/client.rs @@ -12,19 +12,20 @@ extern crate uuid;  use clap::{App, Arg};  #[allow(unused_imports)]  use fatcat::{ -    AcceptEditgroupResponse, ApiError, ApiNoContext, AuthCheckResponse, AuthOidcResponse, ContextWrapperExt, CreateContainerAutoBatchResponse, CreateContainerResponse, CreateCreatorAutoBatchResponse, -    CreateCreatorResponse, CreateEditgroupAnnotationResponse, CreateEditgroupResponse, CreateFileAutoBatchResponse, CreateFileResponse, CreateFilesetAutoBatchResponse, CreateFilesetResponse, -    CreateReleaseAutoBatchResponse, CreateReleaseResponse, CreateWebcaptureAutoBatchResponse, CreateWebcaptureResponse, CreateWorkAutoBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, -    DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, -    DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, -    GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, -    GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupAnnotationsResponse, GetEditgroupResponse, GetEditgroupsReviewableResponse, -    GetEditorAnnotationsResponse, GetEditorEditgroupsResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, -    GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, -    GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, -    GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, -    GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, -    UpdateCreatorResponse, UpdateEditgroupResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, +    AcceptEditgroupResponse, ApiError, ApiNoContext, AuthCheckResponse, AuthOidcResponse, ContextWrapperExt, CreateAuthTokenResponse, CreateContainerAutoBatchResponse, CreateContainerResponse, +    CreateCreatorAutoBatchResponse, CreateCreatorResponse, CreateEditgroupAnnotationResponse, CreateEditgroupResponse, CreateFileAutoBatchResponse, CreateFileResponse, CreateFilesetAutoBatchResponse, +    CreateFilesetResponse, CreateReleaseAutoBatchResponse, CreateReleaseResponse, CreateWebcaptureAutoBatchResponse, CreateWebcaptureResponse, CreateWorkAutoBatchResponse, CreateWorkResponse, +    DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, +    DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, +    GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, +    GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupAnnotationsResponse, +    GetEditgroupResponse, GetEditgroupsReviewableResponse, GetEditorAnnotationsResponse, GetEditorEditgroupsResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, +    GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, +    GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, +    GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, +    GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, +    LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateEditgroupResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, +    UpdateWebcaptureResponse, UpdateWorkResponse,  };  #[allow(unused_imports)]  use futures::{future, stream, Future, Stream}; @@ -36,6 +37,7 @@ fn main() {                  .help("Sets the operation to run")                  .possible_values(&[                      "AuthCheck", +                    "CreateAuthToken",                      "GetChangelog",                      "GetChangelogEntry",                      "DeleteContainer", @@ -141,6 +143,11 @@ fn main() {          //     let result = client.auth_oidc(???).wait();          //     println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          //  }, +        Some("CreateAuthToken") => { +            let result = client.create_auth_token("editor_id_example".to_string(), Some(56)).wait(); +            println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        } +          Some("GetChangelog") => {              let result = client.get_changelog(Some(789)).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); diff --git a/rust/fatcat-openapi/examples/server_lib/server.rs b/rust/fatcat-openapi/examples/server_lib/server.rs index e0f9045f..966381e4 100644 --- a/rust/fatcat-openapi/examples/server_lib/server.rs +++ b/rust/fatcat-openapi/examples/server_lib/server.rs @@ -11,19 +11,20 @@ use swagger;  use fatcat::models;  use fatcat::{ -    AcceptEditgroupResponse, Api, ApiError, AuthCheckResponse, AuthOidcResponse, Context, CreateContainerAutoBatchResponse, CreateContainerResponse, CreateCreatorAutoBatchResponse, -    CreateCreatorResponse, CreateEditgroupAnnotationResponse, CreateEditgroupResponse, CreateFileAutoBatchResponse, CreateFileResponse, CreateFilesetAutoBatchResponse, CreateFilesetResponse, -    CreateReleaseAutoBatchResponse, CreateReleaseResponse, CreateWebcaptureAutoBatchResponse, CreateWebcaptureResponse, CreateWorkAutoBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, -    DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, -    DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, -    GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, -    GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupAnnotationsResponse, GetEditgroupResponse, GetEditgroupsReviewableResponse, -    GetEditorAnnotationsResponse, GetEditorEditgroupsResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, -    GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, -    GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, -    GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, -    GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, -    UpdateCreatorResponse, UpdateEditgroupResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, +    AcceptEditgroupResponse, Api, ApiError, AuthCheckResponse, AuthOidcResponse, Context, CreateAuthTokenResponse, CreateContainerAutoBatchResponse, CreateContainerResponse, +    CreateCreatorAutoBatchResponse, CreateCreatorResponse, CreateEditgroupAnnotationResponse, CreateEditgroupResponse, CreateFileAutoBatchResponse, CreateFileResponse, CreateFilesetAutoBatchResponse, +    CreateFilesetResponse, CreateReleaseAutoBatchResponse, CreateReleaseResponse, CreateWebcaptureAutoBatchResponse, CreateWebcaptureResponse, CreateWorkAutoBatchResponse, CreateWorkResponse, +    DeleteContainerEditResponse, DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, +    DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, +    GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, +    GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupAnnotationsResponse, +    GetEditgroupResponse, GetEditgroupsReviewableResponse, GetEditorAnnotationsResponse, GetEditorEditgroupsResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, +    GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, +    GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, +    GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, +    GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, +    LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateEditgroupResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, +    UpdateWebcaptureResponse, UpdateWorkResponse,  };  #[derive(Copy, Clone)] @@ -42,6 +43,17 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn create_auth_token(&self, editor_id: String, duration_seconds: Option<i32>, context: &Context) -> Box<Future<Item = CreateAuthTokenResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!( +            "create_auth_token(\"{}\", {:?}) - X-Span-ID: {:?}", +            editor_id, +            duration_seconds, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        ); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn get_changelog(&self, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("get_changelog({:?}) - X-Span-ID: {:?}", limit, context.x_span_id.unwrap_or(String::from("<none>")).clone()); diff --git a/rust/fatcat-openapi/src/client.rs b/rust/fatcat-openapi/src/client.rs index 65bf67a5..461b426c 100644 --- a/rust/fatcat-openapi/src/client.rs +++ b/rust/fatcat-openapi/src/client.rs @@ -35,19 +35,19 @@ use swagger::{ApiError, Context, XSpanId};  use models;  use { -    AcceptEditgroupResponse, Api, AuthCheckResponse, AuthOidcResponse, CreateContainerAutoBatchResponse, CreateContainerResponse, CreateCreatorAutoBatchResponse, CreateCreatorResponse, -    CreateEditgroupAnnotationResponse, CreateEditgroupResponse, CreateFileAutoBatchResponse, CreateFileResponse, CreateFilesetAutoBatchResponse, CreateFilesetResponse, CreateReleaseAutoBatchResponse, -    CreateReleaseResponse, CreateWebcaptureAutoBatchResponse, CreateWebcaptureResponse, CreateWorkAutoBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, -    DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, -    DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, -    GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, -    GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupAnnotationsResponse, GetEditgroupResponse, GetEditgroupsReviewableResponse, GetEditorAnnotationsResponse, -    GetEditorEditgroupsResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, -    GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, -    GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, -    GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, -    GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, -    UpdateEditgroupResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, +    AcceptEditgroupResponse, Api, AuthCheckResponse, AuthOidcResponse, CreateAuthTokenResponse, CreateContainerAutoBatchResponse, CreateContainerResponse, CreateCreatorAutoBatchResponse, +    CreateCreatorResponse, CreateEditgroupAnnotationResponse, CreateEditgroupResponse, CreateFileAutoBatchResponse, CreateFileResponse, CreateFilesetAutoBatchResponse, CreateFilesetResponse, +    CreateReleaseAutoBatchResponse, CreateReleaseResponse, CreateWebcaptureAutoBatchResponse, CreateWebcaptureResponse, CreateWorkAutoBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, +    DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, +    DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, +    GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, +    GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupAnnotationsResponse, GetEditgroupResponse, GetEditgroupsReviewableResponse, +    GetEditorAnnotationsResponse, GetEditorEditgroupsResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, +    GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, +    GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, +    GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, +    GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, +    UpdateCreatorResponse, UpdateEditgroupResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse,  };  /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. @@ -345,6 +345,89 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn create_auth_token(&self, param_editor_id: String, param_duration_seconds: Option<i32>, context: &Context) -> Box<Future<Item = CreateAuthTokenResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_duration_seconds = param_duration_seconds.map_or_else(String::new, |query| format!("duration_seconds={duration_seconds}&", duration_seconds = query.to_string())); + +        let url = format!( +            "{}/v0/auth/token/{editor_id}?{duration_seconds}", +            self.base_path, +            editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_ENCODE_SET), +            duration_seconds = utf8_percent_encode(&query_duration_seconds, QUERY_ENCODE_SET) +        ); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Post, &url); +        let mut custom_headers = hyper::header::Headers::new(); + +        context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + +        let request = request.headers(custom_headers); + +        // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). +        fn parse_response(mut response: hyper::client::response::Response) -> Result<CreateAuthTokenResponse, ApiError> { +            match response.status.to_u16() { +                200 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::AuthTokenResult>(&buf)?; + +                    Ok(CreateAuthTokenResponse::Success(body)) +                } +                400 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + +                    Ok(CreateAuthTokenResponse::BadRequest(body)) +                } +                401 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; +                    header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } +                    let response_www_authenticate = response +                        .headers +                        .get::<ResponseWwwAuthenticate>() +                        .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + +                    Ok(CreateAuthTokenResponse::NotAuthorized { +                        body: body, +                        www_authenticate: response_www_authenticate.0.clone(), +                    }) +                } +                403 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + +                    Ok(CreateAuthTokenResponse::Forbidden(body)) +                } +                500 => { +                    let mut buf = String::new(); +                    response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; +                    let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + +                    Ok(CreateAuthTokenResponse::GenericError(body)) +                } +                code => { +                    let mut buf = [0; 100]; +                    let debug_body = match response.read(&mut buf) { +                        Ok(len) => match str::from_utf8(&buf[..len]) { +                            Ok(body) => Cow::from(body), +                            Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), +                        }, +                        Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), +                    }; +                    Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) +                } +            } +        } + +        let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); +        Box::new(futures::done(result)) +    } +      fn get_changelog(&self, param_limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> {          // Query parameters          let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); diff --git a/rust/fatcat-openapi/src/lib.rs b/rust/fatcat-openapi/src/lib.rs index da4f23af..ac434c31 100644 --- a/rust/fatcat-openapi/src/lib.rs +++ b/rust/fatcat-openapi/src/lib.rs @@ -65,6 +65,20 @@ pub enum AuthOidcResponse {  }  #[derive(Debug, PartialEq)] +pub enum CreateAuthTokenResponse { +    /// Success +    Success(models::AuthTokenResult), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Authorized +    NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, +    /// Forbidden +    Forbidden(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetChangelogResponse {      /// Success      Success(Vec<models::ChangelogEntry>), @@ -1342,6 +1356,8 @@ pub trait Api {      fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send>; +    fn create_auth_token(&self, editor_id: String, duration_seconds: Option<i32>, context: &Context) -> Box<Future<Item = CreateAuthTokenResponse, Error = ApiError> + Send>; +      fn get_changelog(&self, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send>;      fn get_changelog_entry(&self, index: i64, context: &Context) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send>; @@ -1596,6 +1612,8 @@ pub trait ApiNoContext {      fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send>; +    fn create_auth_token(&self, editor_id: String, duration_seconds: Option<i32>) -> Box<Future<Item = CreateAuthTokenResponse, Error = ApiError> + Send>; +      fn get_changelog(&self, limit: Option<i64>) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send>;      fn get_changelog_entry(&self, index: i64) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send>; @@ -1850,6 +1868,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().auth_oidc(oidc_params, &self.context())      } +    fn create_auth_token(&self, editor_id: String, duration_seconds: Option<i32>) -> Box<Future<Item = CreateAuthTokenResponse, Error = ApiError> + Send> { +        self.api().create_auth_token(editor_id, duration_seconds, &self.context()) +    } +      fn get_changelog(&self, limit: Option<i64>) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> {          self.api().get_changelog(limit, &self.context())      } diff --git a/rust/fatcat-openapi/src/mimetypes.rs b/rust/fatcat-openapi/src/mimetypes.rs index ef297f69..51ff326e 100644 --- a/rust/fatcat-openapi/src/mimetypes.rs +++ b/rust/fatcat-openapi/src/mimetypes.rs @@ -52,6 +52,26 @@ pub mod responses {      lazy_static! {          pub static ref AUTH_OIDC_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for CreateAuthToken +    lazy_static! { +        pub static ref CREATE_AUTH_TOKEN_SUCCESS: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for CreateAuthToken +    lazy_static! { +        pub static ref CREATE_AUTH_TOKEN_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for CreateAuthToken +    lazy_static! { +        pub static ref CREATE_AUTH_TOKEN_NOT_AUTHORIZED: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for CreateAuthToken +    lazy_static! { +        pub static ref CREATE_AUTH_TOKEN_FORBIDDEN: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for CreateAuthToken +    lazy_static! { +        pub static ref CREATE_AUTH_TOKEN_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for GetChangelog      lazy_static! {          pub static ref GET_CHANGELOG_SUCCESS: Mime = mime!(Application / Json); diff --git a/rust/fatcat-openapi/src/models.rs b/rust/fatcat-openapi/src/models.rs index e9e527f5..2f648ccd 100644 --- a/rust/fatcat-openapi/src/models.rs +++ b/rust/fatcat-openapi/src/models.rs @@ -55,6 +55,18 @@ impl AuthOidcResult {  }  #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct AuthTokenResult { +    #[serde(rename = "token")] +    pub token: String, +} + +impl AuthTokenResult { +    pub fn new(token: String) -> AuthTokenResult { +        AuthTokenResult { token: token } +    } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]  pub struct ChangelogEntry {      /// Monotonically increasing sequence number of this changelog entry.      #[serde(rename = "index")] diff --git a/rust/fatcat-openapi/src/server.rs b/rust/fatcat-openapi/src/server.rs index 406b6789..128b6933 100644 --- a/rust/fatcat-openapi/src/server.rs +++ b/rust/fatcat-openapi/src/server.rs @@ -37,19 +37,19 @@ use swagger::{ApiError, Context, XSpanId};  #[allow(unused_imports)]  use models;  use { -    AcceptEditgroupResponse, Api, AuthCheckResponse, AuthOidcResponse, CreateContainerAutoBatchResponse, CreateContainerResponse, CreateCreatorAutoBatchResponse, CreateCreatorResponse, -    CreateEditgroupAnnotationResponse, CreateEditgroupResponse, CreateFileAutoBatchResponse, CreateFileResponse, CreateFilesetAutoBatchResponse, CreateFilesetResponse, CreateReleaseAutoBatchResponse, -    CreateReleaseResponse, CreateWebcaptureAutoBatchResponse, CreateWebcaptureResponse, CreateWorkAutoBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, DeleteContainerResponse, -    DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, DeleteReleaseResponse, -    DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerEditResponse, -    GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, GetCreatorRedirectsResponse, -    GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupAnnotationsResponse, GetEditgroupResponse, GetEditgroupsReviewableResponse, GetEditorAnnotationsResponse, -    GetEditorEditgroupsResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, GetFilesetEditResponse, -    GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, GetReleaseFilesetsResponse, -    GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, GetWebcaptureHistoryResponse, -    GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, GetWorkReleasesResponse, -    GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, -    UpdateEditgroupResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse, +    AcceptEditgroupResponse, Api, AuthCheckResponse, AuthOidcResponse, CreateAuthTokenResponse, CreateContainerAutoBatchResponse, CreateContainerResponse, CreateCreatorAutoBatchResponse, +    CreateCreatorResponse, CreateEditgroupAnnotationResponse, CreateEditgroupResponse, CreateFileAutoBatchResponse, CreateFileResponse, CreateFilesetAutoBatchResponse, CreateFilesetResponse, +    CreateReleaseAutoBatchResponse, CreateReleaseResponse, CreateWebcaptureAutoBatchResponse, CreateWebcaptureResponse, CreateWorkAutoBatchResponse, CreateWorkResponse, DeleteContainerEditResponse, +    DeleteContainerResponse, DeleteCreatorEditResponse, DeleteCreatorResponse, DeleteFileEditResponse, DeleteFileResponse, DeleteFilesetEditResponse, DeleteFilesetResponse, DeleteReleaseEditResponse, +    DeleteReleaseResponse, DeleteWebcaptureEditResponse, DeleteWebcaptureResponse, DeleteWorkEditResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, +    GetContainerEditResponse, GetContainerHistoryResponse, GetContainerRedirectsResponse, GetContainerResponse, GetContainerRevisionResponse, GetCreatorEditResponse, GetCreatorHistoryResponse, +    GetCreatorRedirectsResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetCreatorRevisionResponse, GetEditgroupAnnotationsResponse, GetEditgroupResponse, GetEditgroupsReviewableResponse, +    GetEditorAnnotationsResponse, GetEditorEditgroupsResponse, GetEditorResponse, GetFileEditResponse, GetFileHistoryResponse, GetFileRedirectsResponse, GetFileResponse, GetFileRevisionResponse, +    GetFilesetEditResponse, GetFilesetHistoryResponse, GetFilesetRedirectsResponse, GetFilesetResponse, GetFilesetRevisionResponse, GetReleaseEditResponse, GetReleaseFilesResponse, +    GetReleaseFilesetsResponse, GetReleaseHistoryResponse, GetReleaseRedirectsResponse, GetReleaseResponse, GetReleaseRevisionResponse, GetReleaseWebcapturesResponse, GetWebcaptureEditResponse, +    GetWebcaptureHistoryResponse, GetWebcaptureRedirectsResponse, GetWebcaptureResponse, GetWebcaptureRevisionResponse, GetWorkEditResponse, GetWorkHistoryResponse, GetWorkRedirectsResponse, +    GetWorkReleasesResponse, GetWorkResponse, GetWorkRevisionResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, +    UpdateCreatorResponse, UpdateEditgroupResponse, UpdateEditorResponse, UpdateFileResponse, UpdateFilesetResponse, UpdateReleaseResponse, UpdateWebcaptureResponse, UpdateWorkResponse,  };  header! { (Warning, "Warning") => [String] } @@ -339,6 +339,114 @@ where      );      let api_clone = api.clone(); +    router.post( +        "/v0/auth/token/:editor_id", +        move |req: &mut Request| { +            let mut context = Context::default(); + +            // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). +            fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> +            where +                T: Api, +            { +                context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); +                context.auth_data = req.extensions.remove::<AuthData>(); +                context.authorization = req.extensions.remove::<Authorization>(); + +                let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + +                // Path parameters +                let param_editor_id = { +                    let param = req +                        .extensions +                        .get::<Router>() +                        .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? +                        .find("editor_id") +                        .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editor_id".to_string())))?; +                    percent_decode(param.as_bytes()) +                        .decode_utf8() +                        .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? +                        .parse() +                        .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? +                }; + +                // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) +                let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); +                let param_duration_seconds = query_params.get("duration_seconds").and_then(|list| list.first()).and_then(|x| x.parse::<i32>().ok()); + +                match api.create_auth_token(param_editor_id, param_duration_seconds, context).wait() { +                    Ok(rsp) => match rsp { +                        CreateAuthTokenResponse::Success(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(200), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::CREATE_AUTH_TOKEN_SUCCESS.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        CreateAuthTokenResponse::BadRequest(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(400), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::CREATE_AUTH_TOKEN_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        CreateAuthTokenResponse::NotAuthorized { body, www_authenticate } => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(401), body_string)); +                            header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } +                            response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + +                            response.headers.set(ContentType(mimetypes::responses::CREATE_AUTH_TOKEN_NOT_AUTHORIZED.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        CreateAuthTokenResponse::Forbidden(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(403), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::CREATE_AUTH_TOKEN_FORBIDDEN.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        CreateAuthTokenResponse::GenericError(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(500), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::CREATE_AUTH_TOKEN_GENERIC_ERROR.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                    }, +                    Err(_) => { +                        // Application code returned an error. This should not happen, as the implementation should +                        // return a valid response. +                        Err(Response::with((status::InternalServerError, "An internal error occurred".to_string()))) +                    } +                } +            } + +            handle_request(req, &api_clone, &mut context).or_else(|mut response| { +                context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); +                Ok(response) +            }) +        }, +        "CreateAuthToken", +    ); + +    let api_clone = api.clone();      router.get(          "/v0/changelog",          move |req: &mut Request| { | 
