diff options
| -rw-r--r-- | fatcat-openapi2.yml | 88 | ||||
| -rw-r--r-- | rust/fatcat-api/README.md | 6 | ||||
| -rw-r--r-- | rust/fatcat-api/api.yaml | 88 | ||||
| -rw-r--r-- | rust/fatcat-api/api/swagger.yaml | 250 | ||||
| -rw-r--r-- | rust/fatcat-api/examples/client.rs | 30 | ||||
| -rw-r--r-- | rust/fatcat-api/examples/server_lib/server.rs | 49 | ||||
| -rw-r--r-- | rust/fatcat-api/src/client.rs | 279 | ||||
| -rw-r--r-- | rust/fatcat-api/src/lib.rs | 80 | ||||
| -rw-r--r-- | rust/fatcat-api/src/mimetypes.rs | 64 | ||||
| -rw-r--r-- | rust/fatcat-api/src/models.rs | 8 | ||||
| -rw-r--r-- | rust/fatcat-api/src/server.rs | 375 | ||||
| -rw-r--r-- | rust/src/api_server.rs | 187 | ||||
| -rw-r--r-- | rust/tests/test_api_server.rs | 3 | 
13 files changed, 1400 insertions, 107 deletions
| diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index bdcb3ca8..3d0690c6 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -186,13 +186,13 @@ definitions:      required:        - edit        - editgroup -      - changelog +      - changelog_entry      properties:        edit:          $ref: "#/definitions/entity_edit"        editgroup:          $ref: "#/definitions/editgroup" -      changelog: +      changelog_entry:          $ref: "#/definitions/changelog_entry"    entity_edit:      type: object @@ -475,6 +475,27 @@ paths:            schema:              $ref: "#/definitions/creator_entity"          <<: *ENTITYRESPONSES +  /creator/{id}/history: +    parameters: +      - name: id +        in: path +        type: string +        required: true +      - name: limit +        in: query +        type: integer +        format: int64 +        required: false +    get: +      operationId: "get_creator_history" +      responses: +        200: +          description: Found Entity History +          schema: +            type: array +            items: +              $ref: "#/definitions/entity_history_entry" +        <<: *ENTITYRESPONSES    /creator/{id}/releases:      parameters:        - name: id @@ -553,6 +574,27 @@ paths:            schema:              $ref: "#/definitions/file_entity"          <<: *ENTITYRESPONSES +  /file/{id}/history: +    parameters: +      - name: id +        in: path +        type: string +        required: true +      - name: limit +        in: query +        type: integer +        format: int64 +        required: false +    get: +      operationId: "get_file_history" +      responses: +        200: +          description: Found Entity History +          schema: +            type: array +            items: +              $ref: "#/definitions/entity_history_entry" +        <<: *ENTITYRESPONSES    /file/lookup:      get:        operationId: "lookup_file" @@ -615,6 +657,27 @@ paths:            schema:              $ref: "#/definitions/release_entity"          <<: *ENTITYRESPONSES +  /release/{id}/history: +    parameters: +      - name: id +        in: path +        type: string +        required: true +      - name: limit +        in: query +        type: integer +        format: int64 +        required: false +    get: +      operationId: "get_release_history" +      responses: +        200: +          description: Found Entity History +          schema: +            type: array +            items: +              $ref: "#/definitions/entity_history_entry" +        <<: *ENTITYRESPONSES    /release/{id}/files:      parameters:        - name: id @@ -693,6 +756,27 @@ paths:            schema:              $ref: "#/definitions/work_entity"          <<: *ENTITYRESPONSES +  /work/{id}/history: +    parameters: +      - name: id +        in: path +        type: string +        required: true +      - name: limit +        in: query +        type: integer +        format: int64 +        required: false +    get: +      operationId: "get_work_history" +      responses: +        200: +          description: Found Entity History +          schema: +            type: array +            items: +              $ref: "#/definitions/entity_history_entry" +        <<: *ENTITYRESPONSES    /work/{id}/releases:      parameters:        - name: id diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index 9a444e87..12673cfe 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -13,7 +13,7 @@ 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.1.0 -- Build date: 2018-07-01T00:33:31.410Z +- Build date: 2018-07-01T00:51:27.691Z  This autogenerated project defines an API crate `fatcat` which contains:  * An `Api` trait defining the API in Rust. @@ -71,15 +71,19 @@ cargo run --example client CreateWorkBatch  cargo run --example client GetContainer  cargo run --example client GetContainerHistory  cargo run --example client GetCreator +cargo run --example client GetCreatorHistory  cargo run --example client GetCreatorReleases  cargo run --example client GetEditgroup  cargo run --example client GetEditor  cargo run --example client GetEditorChangelog  cargo run --example client GetFile +cargo run --example client GetFileHistory  cargo run --example client GetRelease  cargo run --example client GetReleaseFiles +cargo run --example client GetReleaseHistory  cargo run --example client GetStats  cargo run --example client GetWork +cargo run --example client GetWorkHistory  cargo run --example client GetWorkReleases  cargo run --example client LookupContainer  cargo run --example client LookupCreator diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index bdcb3ca8..3d0690c6 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -186,13 +186,13 @@ definitions:      required:        - edit        - editgroup -      - changelog +      - changelog_entry      properties:        edit:          $ref: "#/definitions/entity_edit"        editgroup:          $ref: "#/definitions/editgroup" -      changelog: +      changelog_entry:          $ref: "#/definitions/changelog_entry"    entity_edit:      type: object @@ -475,6 +475,27 @@ paths:            schema:              $ref: "#/definitions/creator_entity"          <<: *ENTITYRESPONSES +  /creator/{id}/history: +    parameters: +      - name: id +        in: path +        type: string +        required: true +      - name: limit +        in: query +        type: integer +        format: int64 +        required: false +    get: +      operationId: "get_creator_history" +      responses: +        200: +          description: Found Entity History +          schema: +            type: array +            items: +              $ref: "#/definitions/entity_history_entry" +        <<: *ENTITYRESPONSES    /creator/{id}/releases:      parameters:        - name: id @@ -553,6 +574,27 @@ paths:            schema:              $ref: "#/definitions/file_entity"          <<: *ENTITYRESPONSES +  /file/{id}/history: +    parameters: +      - name: id +        in: path +        type: string +        required: true +      - name: limit +        in: query +        type: integer +        format: int64 +        required: false +    get: +      operationId: "get_file_history" +      responses: +        200: +          description: Found Entity History +          schema: +            type: array +            items: +              $ref: "#/definitions/entity_history_entry" +        <<: *ENTITYRESPONSES    /file/lookup:      get:        operationId: "lookup_file" @@ -615,6 +657,27 @@ paths:            schema:              $ref: "#/definitions/release_entity"          <<: *ENTITYRESPONSES +  /release/{id}/history: +    parameters: +      - name: id +        in: path +        type: string +        required: true +      - name: limit +        in: query +        type: integer +        format: int64 +        required: false +    get: +      operationId: "get_release_history" +      responses: +        200: +          description: Found Entity History +          schema: +            type: array +            items: +              $ref: "#/definitions/entity_history_entry" +        <<: *ENTITYRESPONSES    /release/{id}/files:      parameters:        - name: id @@ -693,6 +756,27 @@ paths:            schema:              $ref: "#/definitions/work_entity"          <<: *ENTITYRESPONSES +  /work/{id}/history: +    parameters: +      - name: id +        in: path +        type: string +        required: true +      - name: limit +        in: query +        type: integer +        format: int64 +        required: false +    get: +      operationId: "get_work_history" +      responses: +        200: +          description: Found Entity History +          schema: +            type: array +            items: +              $ref: "#/definitions/entity_history_entry" +        <<: *ENTITYRESPONSES    /work/{id}/releases:      parameters:        - name: id diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index c333e60f..15ea229a 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -468,6 +468,67 @@ paths:        path: "/creator/:id"        HttpMethod: "Get"        httpmethod: "get" +  /creator/{id}/history: +    get: +      operationId: "get_creator_history" +      parameters: +      - name: "id" +        in: "path" +        required: true +        type: "string" +        formatString: "\\\"{}\\\"" +        example: "\"id_example\".to_string()" +      - name: "limit" +        in: "query" +        required: false +        type: "integer" +        format: "int64" +        formatString: "{:?}" +        example: "Some(789)" +      responses: +        200: +          description: "Found Entity History" +          schema: +            type: "array" +            items: +              $ref: "#/definitions/entity_history_entry" +          x-responseId: "FoundEntityHistory" +          x-uppercaseResponseId: "FOUND_ENTITY_HISTORY" +          uppercase_operation_id: "GET_CREATOR_HISTORY" +          uppercase_data_type: "VEC<ENTITYHISTORYENTRY>" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "GET_CREATOR_HISTORY" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        404: +          description: "Not Found" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "NotFound" +          x-uppercaseResponseId: "NOT_FOUND" +          uppercase_operation_id: "GET_CREATOR_HISTORY" +          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: "GET_CREATOR_HISTORY" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      operation_id: "get_creator_history" +      uppercase_operation_id: "GET_CREATOR_HISTORY" +      path: "/creator/:id/history" +      HttpMethod: "Get" +      httpmethod: "get"    /creator/{id}/releases:      get:        operationId: "get_creator_releases" @@ -745,6 +806,67 @@ paths:        path: "/file/:id"        HttpMethod: "Get"        httpmethod: "get" +  /file/{id}/history: +    get: +      operationId: "get_file_history" +      parameters: +      - name: "id" +        in: "path" +        required: true +        type: "string" +        formatString: "\\\"{}\\\"" +        example: "\"id_example\".to_string()" +      - name: "limit" +        in: "query" +        required: false +        type: "integer" +        format: "int64" +        formatString: "{:?}" +        example: "Some(789)" +      responses: +        200: +          description: "Found Entity History" +          schema: +            type: "array" +            items: +              $ref: "#/definitions/entity_history_entry" +          x-responseId: "FoundEntityHistory" +          x-uppercaseResponseId: "FOUND_ENTITY_HISTORY" +          uppercase_operation_id: "GET_FILE_HISTORY" +          uppercase_data_type: "VEC<ENTITYHISTORYENTRY>" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "GET_FILE_HISTORY" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        404: +          description: "Not Found" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "NotFound" +          x-uppercaseResponseId: "NOT_FOUND" +          uppercase_operation_id: "GET_FILE_HISTORY" +          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: "GET_FILE_HISTORY" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      operation_id: "get_file_history" +      uppercase_operation_id: "GET_FILE_HISTORY" +      path: "/file/:id/history" +      HttpMethod: "Get" +      httpmethod: "get"    /file/lookup:      get:        operationId: "lookup_file" @@ -968,6 +1090,67 @@ paths:        path: "/release/:id"        HttpMethod: "Get"        httpmethod: "get" +  /release/{id}/history: +    get: +      operationId: "get_release_history" +      parameters: +      - name: "id" +        in: "path" +        required: true +        type: "string" +        formatString: "\\\"{}\\\"" +        example: "\"id_example\".to_string()" +      - name: "limit" +        in: "query" +        required: false +        type: "integer" +        format: "int64" +        formatString: "{:?}" +        example: "Some(789)" +      responses: +        200: +          description: "Found Entity History" +          schema: +            type: "array" +            items: +              $ref: "#/definitions/entity_history_entry" +          x-responseId: "FoundEntityHistory" +          x-uppercaseResponseId: "FOUND_ENTITY_HISTORY" +          uppercase_operation_id: "GET_RELEASE_HISTORY" +          uppercase_data_type: "VEC<ENTITYHISTORYENTRY>" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "GET_RELEASE_HISTORY" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        404: +          description: "Not Found" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "NotFound" +          x-uppercaseResponseId: "NOT_FOUND" +          uppercase_operation_id: "GET_RELEASE_HISTORY" +          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: "GET_RELEASE_HISTORY" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      operation_id: "get_release_history" +      uppercase_operation_id: "GET_RELEASE_HISTORY" +      path: "/release/:id/history" +      HttpMethod: "Get" +      httpmethod: "get"    /release/{id}/files:      get:        operationId: "get_release_files" @@ -1245,6 +1428,67 @@ paths:        path: "/work/:id"        HttpMethod: "Get"        httpmethod: "get" +  /work/{id}/history: +    get: +      operationId: "get_work_history" +      parameters: +      - name: "id" +        in: "path" +        required: true +        type: "string" +        formatString: "\\\"{}\\\"" +        example: "\"id_example\".to_string()" +      - name: "limit" +        in: "query" +        required: false +        type: "integer" +        format: "int64" +        formatString: "{:?}" +        example: "Some(789)" +      responses: +        200: +          description: "Found Entity History" +          schema: +            type: "array" +            items: +              $ref: "#/definitions/entity_history_entry" +          x-responseId: "FoundEntityHistory" +          x-uppercaseResponseId: "FOUND_ENTITY_HISTORY" +          uppercase_operation_id: "GET_WORK_HISTORY" +          uppercase_data_type: "VEC<ENTITYHISTORYENTRY>" +          producesJson: true +        400: +          description: "Bad Request" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "BadRequest" +          x-uppercaseResponseId: "BAD_REQUEST" +          uppercase_operation_id: "GET_WORK_HISTORY" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +        404: +          description: "Not Found" +          schema: +            $ref: "#/definitions/error_response" +          x-responseId: "NotFound" +          x-uppercaseResponseId: "NOT_FOUND" +          uppercase_operation_id: "GET_WORK_HISTORY" +          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: "GET_WORK_HISTORY" +          uppercase_data_type: "ERRORRESPONSE" +          producesJson: true +      operation_id: "get_work_history" +      uppercase_operation_id: "GET_WORK_HISTORY" +      path: "/work/:id/history" +      HttpMethod: "Get" +      httpmethod: "get"    /work/{id}/releases:      get:        operationId: "get_work_releases" @@ -1926,7 +2170,7 @@ definitions:    entity_history_entry:      type: "object"      required: -    - "changelog" +    - "changelog_entry"      - "edit"      - "editgroup"      properties: @@ -1934,7 +2178,7 @@ definitions:          $ref: "#/definitions/entity_edit"        editgroup:          $ref: "#/definitions/editgroup" -      changelog: +      changelog_entry:          $ref: "#/definitions/changelog_entry"      example:        editgroup: @@ -2015,7 +2259,7 @@ definitions:          redirect_ident: "00000000-0000-0000-adce-000000000002"          editgroup_id: 16          revision: 42 -      changelog: +      changelog_entry:          index: 1          editgroup_id: 5          timestamp: "2000-01-23T04:56:07.000+00:00" diff --git a/rust/fatcat-api/examples/client.rs b/rust/fatcat-api/examples/client.rs index 93b2d21d..eecb0c58 100644 --- a/rust/fatcat-api/examples/client.rs +++ b/rust/fatcat-api/examples/client.rs @@ -13,9 +13,9 @@ use clap::{App, Arg};  #[allow(unused_imports)]  use fatcat::{AcceptEditgroupResponse, ApiError, ApiNoContext, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse,               CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, -             GetContainerHistoryResponse, GetContainerResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, -             GetReleaseFilesResponse, GetReleaseResponse, GetStatsResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, -             LookupReleaseResponse}; +             GetContainerHistoryResponse, GetContainerResponse, GetCreatorHistoryResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, +             GetEditorResponse, GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, +             GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  #[allow(unused_imports)]  use futures::{future, stream, Future, Stream}; @@ -34,15 +34,19 @@ fn main() {                      "GetContainer",                      "GetContainerHistory",                      "GetCreator", +                    "GetCreatorHistory",                      "GetCreatorReleases",                      "GetEditgroup",                      "GetEditor",                      "GetEditorChangelog",                      "GetFile", +                    "GetFileHistory",                      "GetRelease",                      "GetReleaseFiles", +                    "GetReleaseHistory",                      "GetStats",                      "GetWork", +                    "GetWorkHistory",                      "GetWorkReleases",                      "LookupContainer",                      "LookupCreator", @@ -152,6 +156,11 @@ fn main() {              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } +        Some("GetCreatorHistory") => { +            let result = client.get_creator_history("id_example".to_string(), Some(789)).wait(); +            println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        } +          Some("GetCreatorReleases") => {              let result = client.get_creator_releases("id_example".to_string()).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); @@ -177,6 +186,11 @@ fn main() {              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } +        Some("GetFileHistory") => { +            let result = client.get_file_history("id_example".to_string(), Some(789)).wait(); +            println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        } +          Some("GetRelease") => {              let result = client.get_release("id_example".to_string()).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); @@ -187,6 +201,11 @@ fn main() {              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } +        Some("GetReleaseHistory") => { +            let result = client.get_release_history("id_example".to_string(), Some(789)).wait(); +            println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        } +          Some("GetStats") => {              let result = client.get_stats(Some("more_example".to_string())).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); @@ -197,6 +216,11 @@ fn main() {              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>")));          } +        Some("GetWorkHistory") => { +            let result = client.get_work_history("id_example".to_string(), Some(789)).wait(); +            println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); +        } +          Some("GetWorkReleases") => {              let result = client.get_work_releases("id_example".to_string()).wait();              println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); diff --git a/rust/fatcat-api/examples/server_lib/server.rs b/rust/fatcat-api/examples/server_lib/server.rs index 0155782b..062fca02 100644 --- a/rust/fatcat-api/examples/server_lib/server.rs +++ b/rust/fatcat-api/examples/server_lib/server.rs @@ -12,8 +12,9 @@ use swagger;  use fatcat::models;  use fatcat::{AcceptEditgroupResponse, Api, ApiError, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse,               CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerHistoryResponse, -             GetContainerResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, -             GetReleaseResponse, GetStatsResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse}; +             GetContainerResponse, GetCreatorHistoryResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, +             GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, +             GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse};  #[derive(Copy, Clone)]  pub struct Server; @@ -118,6 +119,17 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn get_creator_history(&self, id: String, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetCreatorHistoryResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!( +            "get_creator_history(\"{}\", {:?}) - X-Span-ID: {:?}", +            id, +            limit, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        ); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn get_creator_releases(&self, id: String, context: &Context) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("get_creator_releases(\"{}\") - X-Span-ID: {:?}", id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); @@ -148,6 +160,17 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn get_file_history(&self, id: String, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetFileHistoryResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!( +            "get_file_history(\"{}\", {:?}) - X-Span-ID: {:?}", +            id, +            limit, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        ); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn get_release(&self, id: String, context: &Context) -> Box<Future<Item = GetReleaseResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("get_release(\"{}\") - X-Span-ID: {:?}", id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); @@ -160,6 +183,17 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn get_release_history(&self, id: String, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetReleaseHistoryResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!( +            "get_release_history(\"{}\", {:?}) - X-Span-ID: {:?}", +            id, +            limit, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        ); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn get_stats(&self, more: Option<String>, context: &Context) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("get_stats({:?}) - X-Span-ID: {:?}", more, context.x_span_id.unwrap_or(String::from("<none>")).clone()); @@ -172,6 +206,17 @@ impl Api for Server {          Box::new(futures::failed("Generic failure".into()))      } +    fn get_work_history(&self, id: String, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetWorkHistoryResponse, Error = ApiError> + Send> { +        let context = context.clone(); +        println!( +            "get_work_history(\"{}\", {:?}) - X-Span-ID: {:?}", +            id, +            limit, +            context.x_span_id.unwrap_or(String::from("<none>")).clone() +        ); +        Box::new(futures::failed("Generic failure".into())) +    } +      fn get_work_releases(&self, id: String, context: &Context) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send> {          let context = context.clone();          println!("get_work_releases(\"{}\") - X-Span-ID: {:?}", id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index 02f0e155..54e8b86c 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -35,9 +35,10 @@ use swagger::{ApiError, Context, XSpanId};  use models;  use {AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, -     CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerHistoryResponse, GetContainerResponse, -     GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, -     GetStatsResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse}; +     CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerHistoryResponse, GetContainerResponse, GetCreatorHistoryResponse, +     GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, +     GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, +     LookupFileResponse, LookupReleaseResponse};  /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes.  fn into_base_path<T: IntoUrl>(input: T, correct_scheme: Option<&'static str>) -> Result<String, ClientInitError> { @@ -1118,6 +1119,74 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn get_creator_history(&self, param_id: String, param_limit: Option<i64>, context: &Context) -> Box<Future<Item = GetCreatorHistoryResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + +        let url = format!( +            "{}/v0/creator/{id}/history?{limit}", +            self.base_path, +            id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), +            limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) +        ); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Get, &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<GetCreatorHistoryResponse, 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::<Vec<models::EntityHistoryEntry>>(&buf)?; + +                    Ok(GetCreatorHistoryResponse::FoundEntityHistory(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(GetCreatorHistoryResponse::BadRequest(body)) +                } +                404 => { +                    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(GetCreatorHistoryResponse::NotFound(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(GetCreatorHistoryResponse::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_creator_releases(&self, param_id: String, context: &Context) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send> {          let url = format!("{}/v0/creator/{id}/releases", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); @@ -1412,6 +1481,74 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn get_file_history(&self, param_id: String, param_limit: Option<i64>, context: &Context) -> Box<Future<Item = GetFileHistoryResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + +        let url = format!( +            "{}/v0/file/{id}/history?{limit}", +            self.base_path, +            id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), +            limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) +        ); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Get, &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<GetFileHistoryResponse, 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::<Vec<models::EntityHistoryEntry>>(&buf)?; + +                    Ok(GetFileHistoryResponse::FoundEntityHistory(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(GetFileHistoryResponse::BadRequest(body)) +                } +                404 => { +                    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(GetFileHistoryResponse::NotFound(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(GetFileHistoryResponse::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_release(&self, param_id: String, context: &Context) -> Box<Future<Item = GetReleaseResponse, Error = ApiError> + Send> {          let url = format!("{}/v0/release/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); @@ -1532,6 +1669,74 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn get_release_history(&self, param_id: String, param_limit: Option<i64>, context: &Context) -> Box<Future<Item = GetReleaseHistoryResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + +        let url = format!( +            "{}/v0/release/{id}/history?{limit}", +            self.base_path, +            id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), +            limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) +        ); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Get, &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<GetReleaseHistoryResponse, 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::<Vec<models::EntityHistoryEntry>>(&buf)?; + +                    Ok(GetReleaseHistoryResponse::FoundEntityHistory(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(GetReleaseHistoryResponse::BadRequest(body)) +                } +                404 => { +                    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(GetReleaseHistoryResponse::NotFound(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(GetReleaseHistoryResponse::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_stats(&self, param_more: Option<String>, context: &Context) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> {          // Query parameters          let query_more = param_more.map_or_else(String::new, |query| format!("more={more}&", more = query.to_string())); @@ -1641,6 +1846,74 @@ impl Api for Client {          Box::new(futures::done(result))      } +    fn get_work_history(&self, param_id: String, param_limit: Option<i64>, context: &Context) -> Box<Future<Item = GetWorkHistoryResponse, Error = ApiError> + Send> { +        // Query parameters +        let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + +        let url = format!( +            "{}/v0/work/{id}/history?{limit}", +            self.base_path, +            id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), +            limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) +        ); + +        let hyper_client = (self.hyper_client)(); +        let request = hyper_client.request(hyper::method::Method::Get, &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<GetWorkHistoryResponse, 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::<Vec<models::EntityHistoryEntry>>(&buf)?; + +                    Ok(GetWorkHistoryResponse::FoundEntityHistory(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(GetWorkHistoryResponse::BadRequest(body)) +                } +                404 => { +                    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(GetWorkHistoryResponse::NotFound(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(GetWorkHistoryResponse::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_work_releases(&self, param_id: String, context: &Context) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send> {          let url = format!("{}/v0/work/{id}/releases", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index 291dcaf4..28636d47 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -211,6 +211,18 @@ pub enum GetCreatorResponse {  }  #[derive(Debug, PartialEq)] +pub enum GetCreatorHistoryResponse { +    /// Found Entity History +    FoundEntityHistory(Vec<models::EntityHistoryEntry>), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Found +    NotFound(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetCreatorReleasesResponse {      /// Found Entity      FoundEntity(Vec<models::ReleaseEntity>), @@ -267,6 +279,18 @@ pub enum GetFileResponse {  }  #[derive(Debug, PartialEq)] +pub enum GetFileHistoryResponse { +    /// Found Entity History +    FoundEntityHistory(Vec<models::EntityHistoryEntry>), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Found +    NotFound(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetReleaseResponse {      /// Found Entity      FoundEntity(models::ReleaseEntity), @@ -291,6 +315,18 @@ pub enum GetReleaseFilesResponse {  }  #[derive(Debug, PartialEq)] +pub enum GetReleaseHistoryResponse { +    /// Found Entity History +    FoundEntityHistory(Vec<models::EntityHistoryEntry>), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Found +    NotFound(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetStatsResponse {      /// Success      Success(models::StatsResponse), @@ -311,6 +347,18 @@ pub enum GetWorkResponse {  }  #[derive(Debug, PartialEq)] +pub enum GetWorkHistoryResponse { +    /// Found Entity History +    FoundEntityHistory(Vec<models::EntityHistoryEntry>), +    /// Bad Request +    BadRequest(models::ErrorResponse), +    /// Not Found +    NotFound(models::ErrorResponse), +    /// Generic Error +    GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)]  pub enum GetWorkReleasesResponse {      /// Found Entity      FoundEntity(Vec<models::ReleaseEntity>), @@ -402,6 +450,8 @@ pub trait Api {      fn get_creator(&self, id: String, context: &Context) -> Box<Future<Item = GetCreatorResponse, Error = ApiError> + Send>; +    fn get_creator_history(&self, id: String, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetCreatorHistoryResponse, Error = ApiError> + Send>; +      fn get_creator_releases(&self, id: String, context: &Context) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send>;      fn get_editgroup(&self, id: i64, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send>; @@ -412,14 +462,20 @@ pub trait Api {      fn get_file(&self, id: String, context: &Context) -> Box<Future<Item = GetFileResponse, Error = ApiError> + Send>; +    fn get_file_history(&self, id: String, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetFileHistoryResponse, Error = ApiError> + Send>; +      fn get_release(&self, id: String, context: &Context) -> Box<Future<Item = GetReleaseResponse, Error = ApiError> + Send>;      fn get_release_files(&self, id: String, context: &Context) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send>; +    fn get_release_history(&self, id: String, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetReleaseHistoryResponse, Error = ApiError> + Send>; +      fn get_stats(&self, more: Option<String>, context: &Context) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send>;      fn get_work(&self, id: String, context: &Context) -> Box<Future<Item = GetWorkResponse, Error = ApiError> + Send>; +    fn get_work_history(&self, id: String, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetWorkHistoryResponse, Error = ApiError> + Send>; +      fn get_work_releases(&self, id: String, context: &Context) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send>;      fn lookup_container(&self, issnl: String, context: &Context) -> Box<Future<Item = LookupContainerResponse, Error = ApiError> + Send>; @@ -463,6 +519,8 @@ pub trait ApiNoContext {      fn get_creator(&self, id: String) -> Box<Future<Item = GetCreatorResponse, Error = ApiError> + Send>; +    fn get_creator_history(&self, id: String, limit: Option<i64>) -> Box<Future<Item = GetCreatorHistoryResponse, Error = ApiError> + Send>; +      fn get_creator_releases(&self, id: String) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send>;      fn get_editgroup(&self, id: i64) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send>; @@ -473,14 +531,20 @@ pub trait ApiNoContext {      fn get_file(&self, id: String) -> Box<Future<Item = GetFileResponse, Error = ApiError> + Send>; +    fn get_file_history(&self, id: String, limit: Option<i64>) -> Box<Future<Item = GetFileHistoryResponse, Error = ApiError> + Send>; +      fn get_release(&self, id: String) -> Box<Future<Item = GetReleaseResponse, Error = ApiError> + Send>;      fn get_release_files(&self, id: String) -> Box<Future<Item = GetReleaseFilesResponse, Error = ApiError> + Send>; +    fn get_release_history(&self, id: String, limit: Option<i64>) -> Box<Future<Item = GetReleaseHistoryResponse, Error = ApiError> + Send>; +      fn get_stats(&self, more: Option<String>) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send>;      fn get_work(&self, id: String) -> Box<Future<Item = GetWorkResponse, Error = ApiError> + Send>; +    fn get_work_history(&self, id: String, limit: Option<i64>) -> Box<Future<Item = GetWorkHistoryResponse, Error = ApiError> + Send>; +      fn get_work_releases(&self, id: String) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send>;      fn lookup_container(&self, issnl: String) -> Box<Future<Item = LookupContainerResponse, Error = ApiError> + Send>; @@ -568,6 +632,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().get_creator(id, &self.context())      } +    fn get_creator_history(&self, id: String, limit: Option<i64>) -> Box<Future<Item = GetCreatorHistoryResponse, Error = ApiError> + Send> { +        self.api().get_creator_history(id, limit, &self.context()) +    } +      fn get_creator_releases(&self, id: String) -> Box<Future<Item = GetCreatorReleasesResponse, Error = ApiError> + Send> {          self.api().get_creator_releases(id, &self.context())      } @@ -588,6 +656,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().get_file(id, &self.context())      } +    fn get_file_history(&self, id: String, limit: Option<i64>) -> Box<Future<Item = GetFileHistoryResponse, Error = ApiError> + Send> { +        self.api().get_file_history(id, limit, &self.context()) +    } +      fn get_release(&self, id: String) -> Box<Future<Item = GetReleaseResponse, Error = ApiError> + Send> {          self.api().get_release(id, &self.context())      } @@ -596,6 +668,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().get_release_files(id, &self.context())      } +    fn get_release_history(&self, id: String, limit: Option<i64>) -> Box<Future<Item = GetReleaseHistoryResponse, Error = ApiError> + Send> { +        self.api().get_release_history(id, limit, &self.context()) +    } +      fn get_stats(&self, more: Option<String>) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> {          self.api().get_stats(more, &self.context())      } @@ -604,6 +680,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> {          self.api().get_work(id, &self.context())      } +    fn get_work_history(&self, id: String, limit: Option<i64>) -> Box<Future<Item = GetWorkHistoryResponse, Error = ApiError> + Send> { +        self.api().get_work_history(id, limit, &self.context()) +    } +      fn get_work_releases(&self, id: String) -> Box<Future<Item = GetWorkReleasesResponse, Error = ApiError> + Send> {          self.api().get_work_releases(id, &self.context())      } diff --git a/rust/fatcat-api/src/mimetypes.rs b/rust/fatcat-api/src/mimetypes.rs index 0384b319..8d67551a 100644 --- a/rust/fatcat-api/src/mimetypes.rs +++ b/rust/fatcat-api/src/mimetypes.rs @@ -240,6 +240,22 @@ pub mod responses {      lazy_static! {          pub static ref GET_CREATOR_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for GetCreatorHistory +    lazy_static! { +        pub static ref GET_CREATOR_HISTORY_FOUND_ENTITY_HISTORY: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetCreatorHistory +    lazy_static! { +        pub static ref GET_CREATOR_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetCreatorHistory +    lazy_static! { +        pub static ref GET_CREATOR_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetCreatorHistory +    lazy_static! { +        pub static ref GET_CREATOR_HISTORY_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for GetCreatorReleases      lazy_static! {          pub static ref GET_CREATOR_RELEASES_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -312,6 +328,22 @@ pub mod responses {      lazy_static! {          pub static ref GET_FILE_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for GetFileHistory +    lazy_static! { +        pub static ref GET_FILE_HISTORY_FOUND_ENTITY_HISTORY: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetFileHistory +    lazy_static! { +        pub static ref GET_FILE_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetFileHistory +    lazy_static! { +        pub static ref GET_FILE_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetFileHistory +    lazy_static! { +        pub static ref GET_FILE_HISTORY_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for GetRelease      lazy_static! {          pub static ref GET_RELEASE_FOUND_ENTITY: Mime = mime!(Application / Json); @@ -344,6 +376,22 @@ pub mod responses {      lazy_static! {          pub static ref GET_RELEASE_FILES_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for GetReleaseHistory +    lazy_static! { +        pub static ref GET_RELEASE_HISTORY_FOUND_ENTITY_HISTORY: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetReleaseHistory +    lazy_static! { +        pub static ref GET_RELEASE_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetReleaseHistory +    lazy_static! { +        pub static ref GET_RELEASE_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetReleaseHistory +    lazy_static! { +        pub static ref GET_RELEASE_HISTORY_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for GetStats      lazy_static! {          pub static ref GET_STATS_SUCCESS: Mime = mime!(Application / Json); @@ -368,6 +416,22 @@ pub mod responses {      lazy_static! {          pub static ref GET_WORK_GENERIC_ERROR: Mime = mime!(Application / Json);      } +    /// Create Mime objects for the response content types for GetWorkHistory +    lazy_static! { +        pub static ref GET_WORK_HISTORY_FOUND_ENTITY_HISTORY: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetWorkHistory +    lazy_static! { +        pub static ref GET_WORK_HISTORY_BAD_REQUEST: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetWorkHistory +    lazy_static! { +        pub static ref GET_WORK_HISTORY_NOT_FOUND: Mime = mime!(Application / Json); +    } +    /// Create Mime objects for the response content types for GetWorkHistory +    lazy_static! { +        pub static ref GET_WORK_HISTORY_GENERIC_ERROR: Mime = mime!(Application / Json); +    }      /// Create Mime objects for the response content types for GetWorkReleases      lazy_static! {          pub static ref GET_WORK_RELEASES_FOUND_ENTITY: Mime = mime!(Application / Json); diff --git a/rust/fatcat-api/src/models.rs b/rust/fatcat-api/src/models.rs index f33ed9db..94edf5c0 100644 --- a/rust/fatcat-api/src/models.rs +++ b/rust/fatcat-api/src/models.rs @@ -282,16 +282,16 @@ pub struct EntityHistoryEntry {      #[serde(rename = "editgroup")]      pub editgroup: models::Editgroup, -    #[serde(rename = "changelog")] -    pub changelog: models::ChangelogEntry, +    #[serde(rename = "changelog_entry")] +    pub changelog_entry: models::ChangelogEntry,  }  impl EntityHistoryEntry { -    pub fn new(edit: models::EntityEdit, editgroup: models::Editgroup, changelog: models::ChangelogEntry) -> EntityHistoryEntry { +    pub fn new(edit: models::EntityEdit, editgroup: models::Editgroup, changelog_entry: models::ChangelogEntry) -> EntityHistoryEntry {          EntityHistoryEntry {              edit: edit,              editgroup: editgroup, -            changelog: changelog, +            changelog_entry: changelog_entry,          }      }  } diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index f01dde1b..e881b313 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -37,9 +37,10 @@ use swagger::{ApiError, Context, XSpanId};  #[allow(unused_imports)]  use models;  use {AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, -     CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerHistoryResponse, GetContainerResponse, -     GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseResponse, -     GetStatsResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse}; +     CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetContainerHistoryResponse, GetContainerResponse, GetCreatorHistoryResponse, +     GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, +     GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, +     LookupFileResponse, LookupReleaseResponse};  header! { (Warning, "Warning") => [String] } @@ -1597,6 +1598,98 @@ where      let api_clone = api.clone();      router.get( +        "/v0/creator/:id/history", +        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>(); + +                // Path parameters +                let param_id = { +                    let param = req.extensions +                        .get::<Router>() +                        .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? +                        .find("id") +                        .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter 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 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_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::<i64>().ok()); + +                match api.get_creator_history(param_id, param_limit, context).wait() { +                    Ok(rsp) => match rsp { +                        GetCreatorHistoryResponse::FoundEntityHistory(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::GET_CREATOR_HISTORY_FOUND_ENTITY_HISTORY.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetCreatorHistoryResponse::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::GET_CREATOR_HISTORY_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetCreatorHistoryResponse::NotFound(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(404), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_NOT_FOUND.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetCreatorHistoryResponse::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::GET_CREATOR_HISTORY_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) +            }) +        }, +        "GetCreatorHistory", +    ); + +    let api_clone = api.clone(); +    router.get(          "/v0/creator/:id/releases",          move |req: &mut Request| {              let mut context = Context::default(); @@ -2017,6 +2110,98 @@ where      let api_clone = api.clone();      router.get( +        "/v0/file/:id/history", +        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>(); + +                // Path parameters +                let param_id = { +                    let param = req.extensions +                        .get::<Router>() +                        .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? +                        .find("id") +                        .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter 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 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_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::<i64>().ok()); + +                match api.get_file_history(param_id, param_limit, context).wait() { +                    Ok(rsp) => match rsp { +                        GetFileHistoryResponse::FoundEntityHistory(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::GET_FILE_HISTORY_FOUND_ENTITY_HISTORY.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetFileHistoryResponse::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::GET_FILE_HISTORY_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetFileHistoryResponse::NotFound(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(404), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_NOT_FOUND.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetFileHistoryResponse::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::GET_FILE_HISTORY_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) +            }) +        }, +        "GetFileHistory", +    ); + +    let api_clone = api.clone(); +    router.get(          "/v0/release/:id",          move |req: &mut Request| {              let mut context = Context::default(); @@ -2193,6 +2378,98 @@ where      let api_clone = api.clone();      router.get( +        "/v0/release/:id/history", +        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>(); + +                // Path parameters +                let param_id = { +                    let param = req.extensions +                        .get::<Router>() +                        .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? +                        .find("id") +                        .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter 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 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_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::<i64>().ok()); + +                match api.get_release_history(param_id, param_limit, context).wait() { +                    Ok(rsp) => match rsp { +                        GetReleaseHistoryResponse::FoundEntityHistory(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::GET_RELEASE_HISTORY_FOUND_ENTITY_HISTORY.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetReleaseHistoryResponse::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::GET_RELEASE_HISTORY_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetReleaseHistoryResponse::NotFound(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(404), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_NOT_FOUND.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetReleaseHistoryResponse::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::GET_RELEASE_HISTORY_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) +            }) +        }, +        "GetReleaseHistory", +    ); + +    let api_clone = api.clone(); +    router.get(          "/v0/stats",          move |req: &mut Request| {              let mut context = Context::default(); @@ -2339,6 +2616,98 @@ where      let api_clone = api.clone();      router.get( +        "/v0/work/:id/history", +        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>(); + +                // Path parameters +                let param_id = { +                    let param = req.extensions +                        .get::<Router>() +                        .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? +                        .find("id") +                        .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter 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 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_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::<i64>().ok()); + +                match api.get_work_history(param_id, param_limit, context).wait() { +                    Ok(rsp) => match rsp { +                        GetWorkHistoryResponse::FoundEntityHistory(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::GET_WORK_HISTORY_FOUND_ENTITY_HISTORY.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetWorkHistoryResponse::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::GET_WORK_HISTORY_BAD_REQUEST.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetWorkHistoryResponse::NotFound(body) => { +                            let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + +                            let mut response = Response::with((status::Status::from_u16(404), body_string)); +                            response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_NOT_FOUND.clone())); + +                            context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + +                            Ok(response) +                        } +                        GetWorkHistoryResponse::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::GET_WORK_HISTORY_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) +            }) +        }, +        "GetWorkHistory", +    ); + +    let api_clone = api.clone(); +    router.get(          "/v0/work/:id/releases",          move |req: &mut Request| {              let mut context = Context::default(); diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index efe40165..d05c00d4 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -29,7 +29,9 @@ macro_rules! wrap_entity_handlers {      // The only stable approach I know of would be: https://github.com/dtolnay/mashup      ($get_fn:ident, $get_handler:ident, $get_resp:ident, $post_fn:ident, $post_handler:ident,              $post_resp:ident, $post_batch_fn:ident, $post_batch_handler:ident, -            $post_batch_resp:ident, $model:ident) => { +            $post_batch_resp:ident, $get_history_fn:ident, $get_history_handler:ident, +            $get_history_resp:ident, $model:ident) => { +          fn $get_fn(              &self,              id: String, @@ -89,20 +91,26 @@ macro_rules! wrap_entity_handlers {              };              Box::new(futures::done(Ok(ret)))          } -    } -} -macro_rules! entity_batch_handler { -    ($post_handler:ident, $post_batch_handler:ident, $model:ident) => { -        fn $post_batch_handler(&self, entity_list: &Vec<models::$model>) -> -                Result<Vec<EntityEdit>> { -            let conn = self.db_pool.get().expect("db_pool error"); -            // TODO: start a transaction -            let mut ret: Vec<EntityEdit> = vec![]; -            for entity in entity_list.into_iter() { -                ret.push(self.$post_handler(entity.clone(), Some(&conn))?); -            } -            Ok(ret) +        fn $get_history_fn( +            &self, +            id: String, +            limit: Option<i64>, +            _context: &Context, +        ) -> Box<Future<Item = $get_history_resp, Error = ApiError> + Send> { +            let ret = match self.$get_history_handler(id.clone(), limit) { +                Ok(history) => +                    $get_history_resp::FoundEntityHistory(history), +                Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => +                    $get_history_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }), +                Err(Error(ErrorKind::Uuid(e), _)) => +                    $get_history_resp::BadRequest(ErrorResponse { message: e.to_string() }), +                Err(e) => { +                    error!("{}", e); +                    $get_history_resp::GenericError(ErrorResponse { message: e.to_string() }) +                }, +            }; +            Box::new(futures::done(Ok(ret)))          }      }  } @@ -129,27 +137,48 @@ macro_rules! wrap_lookup_handler {      }  } -macro_rules! wrap_history_handler { -    ($get_fn:ident, $get_handler:ident, $get_resp:ident) => { -        fn $get_fn( +macro_rules! entity_batch_handler { +    ($post_handler:ident, $post_batch_handler:ident, $model:ident) => { +        fn $post_batch_handler(&self, entity_list: &Vec<models::$model>) -> +                Result<Vec<EntityEdit>> { +            let conn = self.db_pool.get().expect("db_pool error"); +            // TODO: start a transaction +            let mut ret: Vec<EntityEdit> = vec![]; +            for entity in entity_list.into_iter() { +                ret.push(self.$post_handler(entity.clone(), Some(&conn))?); +            } +            Ok(ret) +        } +    } +} + +macro_rules! entity_history_handler { +    ($history_handler:ident, $edit_row_type:ident, $edit_table:ident) => { +        fn $history_handler(              &self,              id: String,              limit: Option<i64>, -            _context: &Context, -        ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> { -            let ret = match self.$get_handler(id.clone(), limit) { -                Ok(history) => -                    $get_resp::FoundEntityHistory(history), -                Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => -                    $get_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }), -                Err(Error(ErrorKind::Uuid(e), _)) => -                    $get_resp::BadRequest(ErrorResponse { message: e.to_string() }), -                Err(e) => { -                    error!("{}", e); -                    $get_resp::GenericError(ErrorResponse { message: e.to_string() }) -                }, -            }; -            Box::new(futures::done(Ok(ret))) +        ) -> Result<Vec<EntityHistoryEntry>> { +            let conn = self.db_pool.get().expect("db_pool error"); +            let id = uuid::Uuid::parse_str(&id)?; +            let limit = limit.unwrap_or(50); + +            let rows: Vec<(EditgroupRow, ChangelogRow, $edit_row_type)> = editgroup::table +                .inner_join(changelog::table) +                .inner_join($edit_table::table) +                .filter($edit_table::ident_id.eq(id)) +                .order(changelog::id.desc()) +                .limit(limit) +                .get_results(&conn)?; + +            let history: Vec<EntityHistoryEntry> = rows.into_iter() +                .map(|(eg_row, cl_row, e_row)| EntityHistoryEntry { +                    edit: e_row.to_model().expect("edit row to model"), +                    editgroup: eg_row.to_model_partial(), +                    changelog_entry: cl_row.to_model(), +                }) +                .collect(); +            Ok(history)          }      }  } @@ -375,32 +404,6 @@ impl Server {          container_row2entity(Some(ident), rev)      } -    fn get_container_history_handler( -        &self, -        id: String, -        limit: Option<i64>, -    ) -> Result<Vec<EntityHistoryEntry>> { -        let conn = self.db_pool.get().expect("db_pool error"); -        let id = uuid::Uuid::parse_str(&id)?; -        let limit = limit.unwrap_or(50); - -        let rows: Vec<(EditgroupRow, ChangelogRow, ContainerEditRow)> = editgroup::table -            .inner_join(changelog::table) -            .inner_join(container_edit::table) -            .filter(container_edit::ident_id.eq(id)) -            .limit(limit) -            .get_results(&conn)?; - -        let history: Vec<EntityHistoryEntry> = rows.into_iter() -            .map(|(eg_row, cl_row, ce_row)| EntityHistoryEntry { -                edit: ce_row.to_model().expect("edit row to model"), -                editgroup: eg_row.to_model_partial(), -                changelog_entry: cl_row.to_model(), -            }) -            .collect(); -        Ok(history) -    } -      fn get_creator_handler(&self, id: String) -> Result<CreatorEntity> {          let conn = self.db_pool.get().expect("db_pool error");          let id = uuid::Uuid::parse_str(&id)?; @@ -582,24 +585,6 @@ impl Server {          edit.to_model()      } -    entity_batch_handler!( -        create_container_handler, -        create_container_batch_handler, -        ContainerEntity -    ); -    entity_batch_handler!( -        create_creator_handler, -        create_creator_batch_handler, -        CreatorEntity -    ); -    entity_batch_handler!(create_file_handler, create_file_batch_handler, FileEntity); -    entity_batch_handler!( -        create_release_handler, -        create_release_batch_handler, -        ReleaseEntity -    ); -    entity_batch_handler!(create_work_handler, create_work_batch_handler, WorkEntity); -      fn create_creator_handler(          &self,          entity: models::CreatorEntity, @@ -1043,6 +1028,34 @@ impl Server {          });          Ok(StatsResponse { extra: Some(val) })      } + +    entity_batch_handler!( +        create_container_handler, +        create_container_batch_handler, +        ContainerEntity +    ); +    entity_batch_handler!( +        create_creator_handler, +        create_creator_batch_handler, +        CreatorEntity +    ); +    entity_batch_handler!(create_file_handler, create_file_batch_handler, FileEntity); +    entity_batch_handler!( +        create_release_handler, +        create_release_batch_handler, +        ReleaseEntity +    ); +    entity_batch_handler!(create_work_handler, create_work_batch_handler, WorkEntity); + +    entity_history_handler!( +        get_container_history_handler, +        ContainerEditRow, +        container_edit +    ); +    entity_history_handler!(get_creator_history_handler, CreatorEditRow, creator_edit); +    entity_history_handler!(get_file_history_handler, FileEditRow, file_edit); +    entity_history_handler!(get_release_history_handler, ReleaseEditRow, release_edit); +    entity_history_handler!(get_work_history_handler, WorkEditRow, work_edit);  }  impl Api for Server { @@ -1056,8 +1069,12 @@ impl Api for Server {          create_container_batch,          create_container_batch_handler,          CreateContainerBatchResponse, +        get_container_history, +        get_container_history_handler, +        GetContainerHistoryResponse,          ContainerEntity      ); +      wrap_entity_handlers!(          get_creator,          get_creator_handler, @@ -1068,6 +1085,9 @@ impl Api for Server {          create_creator_batch,          create_creator_batch_handler,          CreateCreatorBatchResponse, +        get_creator_history, +        get_creator_history_handler, +        GetCreatorHistoryResponse,          CreatorEntity      );      wrap_entity_handlers!( @@ -1080,6 +1100,9 @@ impl Api for Server {          create_file_batch,          create_file_batch_handler,          CreateFileBatchResponse, +        get_file_history, +        get_file_history_handler, +        GetFileHistoryResponse,          FileEntity      );      wrap_entity_handlers!( @@ -1092,6 +1115,9 @@ impl Api for Server {          create_release_batch,          create_release_batch_handler,          CreateReleaseBatchResponse, +        get_release_history, +        get_release_history_handler, +        GetReleaseHistoryResponse,          ReleaseEntity      );      wrap_entity_handlers!( @@ -1104,6 +1130,9 @@ impl Api for Server {          create_work_batch,          create_work_batch_handler,          CreateWorkBatchResponse, +        get_work_history, +        get_work_history_handler, +        GetWorkHistoryResponse,          WorkEntity      ); @@ -1135,13 +1164,7 @@ impl Api for Server {          doi,          String      ); -    wrap_history_handler!( -        get_container_history, -        get_container_history_handler, -        GetContainerHistoryResponse -    ); -    // Rename "wrap_lookup_handler"?      wrap_lookup_handler!(          get_release_files,          get_release_files_handler, diff --git a/rust/tests/test_api_server.rs b/rust/tests/test_api_server.rs index aadd65af..ac03c3c1 100644 --- a/rust/tests/test_api_server.rs +++ b/rust/tests/test_api_server.rs @@ -124,7 +124,7 @@ fn test_entity_history() {          status::Ok,          Some("changelog"),      ); -    /* +      check_response(          request::get(              "http://localhost:9411/v0/creator/00000000-0000-0000-2222-000000000001/history", @@ -164,7 +164,6 @@ fn test_entity_history() {          status::Ok,          Some("changelog"),      ); -*/  }  #[test] | 
