diff options
Diffstat (limited to 'rust/fatcat-openapi')
-rw-r--r-- | rust/fatcat-openapi/README.md | 25 | ||||
-rw-r--r-- | rust/fatcat-openapi/api.yaml | 1068 | ||||
-rw-r--r-- | rust/fatcat-openapi/api/swagger.yaml | 1052 | ||||
-rw-r--r-- | rust/fatcat-openapi/examples/client.rs | 112 | ||||
-rw-r--r-- | rust/fatcat-openapi/examples/server_lib/server.rs | 182 | ||||
-rw-r--r-- | rust/fatcat-openapi/src/client.rs | 1210 | ||||
-rw-r--r-- | rust/fatcat-openapi/src/lib.rs | 432 | ||||
-rw-r--r-- | rust/fatcat-openapi/src/mimetypes.rs | 420 | ||||
-rw-r--r-- | rust/fatcat-openapi/src/models.rs | 173 | ||||
-rw-r--r-- | rust/fatcat-openapi/src/server.rs | 1856 |
10 files changed, 4074 insertions, 2456 deletions
diff --git a/rust/fatcat-openapi/README.md b/rust/fatcat-openapi/README.md index 9565e2c7..d4cd91d1 100644 --- a/rust/fatcat-openapi/README.md +++ b/rust/fatcat-openapi/README.md @@ -1,6 +1,6 @@ # Rust API for fatcat -A scalable, versioned, API-oriented catalog of bibliographic entities and file metadata +Fatcat is a scalable, versioned, API-oriented catalog of bibliographic entities and file metadata. <!-- STARTLONGDESCRIPTION --> These API reference documents, along with client software libraries, are generated automatically from an OpenAPI 2.0 (\"Swagger\") definition file. ## Introduction A higher-level introduction to the API, as well as a description of the fatcat data model, are available in [\"The Fatcat Guide\"](https://guide.fatcat.wiki/). The guide also includes a [Cookbook](https://guide.fatcat.wiki/cookbook.html) section demonstrating end-to-end tasks like creating entities as part of editgroups, or safely merging duplicate entities. ### Expectations and Best Practices A test/staging QA API instance of fatcat is available at <https://api.qa.fatcat.wiki/v0>. The database backing this instance is separate from the production interface, and is periodically rebuilt from snapshots of the full production database, meaning that edits on the QA server will *NOT* persist, and that semantics like the changelog index monotonically increasing *MAY* be broken. Developers are expexcted to test their scripts and tools against the QA instance before running against production. Fatcat is made available as a gratis (no cost) and libre (freedom preserving) service to the public, with limited funding and resources. We welcome new and unforseen uses and contributions, but may need to impose restrictions (like rate-limits) to keep the service functional for other users, and in extreme cases reserve the option to block accounts and IP ranges if necessary to keep the service operational. The Internet Archive owns and operates it's own server equipment and data centers, and operations are optimized for low-cost, not high-availability. Users and partners should expect some downtime on the fatcat API, on the order of hours a month. Periodic metadata exports are available for batch processing, and database snapshots can be used to create locally-hosted mirrors of the service for more intensive and reliable querying. ### Other Nitty Gritties Cross-origin requests are allowed for the API service, to enable third parties to bulid in-browser applications. A metadata search service is available at <https://search.fatcat.wiki> (and <https://search.qa.fatcat.wiki>). The API is currently the raw elasticsearch API, with only GET (read) requests allowed. This public service is experimental and may be removed or limited in the future. ## Authentication The API allows basic read-only \"GET\" HTTP requests with no authentication. Proposing changes to the metadata, or other mutating requests (\"PUT\", \"POST\", \"DELETE\") all require authentication, and some operations require additional account permissions. End-user account creation and login happens through the web interface. From a logged-in editor profile page, you can generate a API token. Tokens are \"macaroons\", similar to JWT tokens, and are used for all API authentication. The web interface includes macaroons in browser cookies and passes them through to the API to authenticate editor actions. <!-- ReDoc-Inject: <security-definitions> --> <!-- ENDLONGDESCRIPTION --> ## Overview This client/server was generated by the [swagger-codegen] @@ -13,7 +13,8 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.3.0 -- Build date: 2019-09-06T02:00:55.433Z +- Build date: 2019-09-13T18:30:17.409Z +For more information, please visit [https://fatcat.wiki](https://fatcat.wiki) This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. @@ -56,6 +57,10 @@ cargo run --example server To run a client, follow one of the following simple steps: ``` +cargo run --example client AuthCheck +cargo run --example client AuthOidc +cargo run --example client GetChangelog +cargo run --example client GetChangelogEntry cargo run --example client CreateContainer cargo run --example client CreateContainerAutoBatch cargo run --example client DeleteContainer @@ -79,21 +84,17 @@ cargo run --example client GetCreatorReleases cargo run --example client GetCreatorRevision cargo run --example client LookupCreator cargo run --example client UpdateCreator -cargo run --example client AuthCheck -cargo run --example client AuthOidc -cargo run --example client GetEditgroupsReviewable -cargo run --example client GetEditor -cargo run --example client GetEditorEditgroups -cargo run --example client UpdateEditgroup -cargo run --example client UpdateEditor cargo run --example client AcceptEditgroup cargo run --example client CreateEditgroup cargo run --example client CreateEditgroupAnnotation -cargo run --example client GetChangelog -cargo run --example client GetChangelogEntry cargo run --example client GetEditgroup cargo run --example client GetEditgroupAnnotations +cargo run --example client GetEditgroupsReviewable +cargo run --example client UpdateEditgroup +cargo run --example client GetEditor cargo run --example client GetEditorAnnotations +cargo run --example client GetEditorEditgroups +cargo run --example client UpdateEditor cargo run --example client CreateFile cargo run --example client CreateFileAutoBatch cargo run --example client DeleteFile @@ -117,7 +118,6 @@ cargo run --example client GetFilesetRevision cargo run --example client UpdateFileset cargo run --example client CreateRelease cargo run --example client CreateReleaseAutoBatch -cargo run --example client CreateWork cargo run --example client DeleteRelease cargo run --example client DeleteReleaseEdit cargo run --example client GetRelease @@ -140,6 +140,7 @@ cargo run --example client GetWebcaptureHistory cargo run --example client GetWebcaptureRedirects cargo run --example client GetWebcaptureRevision cargo run --example client UpdateWebcapture +cargo run --example client CreateWork cargo run --example client CreateWorkAutoBatch cargo run --example client DeleteWork cargo run --example client DeleteWorkEdit diff --git a/rust/fatcat-openapi/api.yaml b/rust/fatcat-openapi/api.yaml index 95ef4c6b..3de72126 100644 --- a/rust/fatcat-openapi/api.yaml +++ b/rust/fatcat-openapi/api.yaml @@ -2,9 +2,86 @@ swagger: "2.0" info: title: fatcat - description: A scalable, versioned, API-oriented catalog of bibliographic entities - and file metadata version: 0.3.0 + description: | + Fatcat is a scalable, versioned, API-oriented catalog of bibliographic + entities and file metadata. + + <!-- STARTLONGDESCRIPTION --> + These API reference documents, along with client software libraries, are + generated automatically from an OpenAPI 2.0 ("Swagger") definition file. + + ## Introduction + + + A higher-level introduction to the API, as well as a description of the + fatcat data model, are available in ["The Fatcat Guide"](https://guide.fatcat.wiki/). + The guide also includes a [Cookbook](https://guide.fatcat.wiki/cookbook.html) + section demonstrating end-to-end tasks like creating entities as part of + editgroups, or safely merging duplicate entities. + + ### Expectations and Best Practices + + A test/staging QA API instance of fatcat is available at + <https://api.qa.fatcat.wiki/v0>. The database backing this instance is + separate from the production interface, and is periodically rebuilt from + snapshots of the full production database, meaning that edits on the QA + server will *NOT* persist, and that semantics like the changelog index + monotonically increasing *MAY* be broken. Developers are expexcted to test + their scripts and tools against the QA instance before running against + production. + + Fatcat is made available as a gratis (no cost) and libre (freedom + preserving) service to the public, with limited funding and resources. We + welcome new and unforseen uses and contributions, but may need to impose + restrictions (like rate-limits) to keep the service functional for other + users, and in extreme cases reserve the option to block accounts and IP + ranges if necessary to keep the service operational. + + The Internet Archive owns and operates it's own server equipment and data + centers, and operations are optimized for low-cost, not high-availability. + Users and partners should expect some downtime on the fatcat API, on the + order of hours a month. + + Periodic metadata exports are available for batch processing, and database + snapshots can be used to create locally-hosted mirrors of the service for + more intensive and reliable querying. + + ### Other Nitty Gritties + + Cross-origin requests are allowed for the API service, to enable third + parties to bulid in-browser applications. + + A metadata search service is available at <https://search.fatcat.wiki> (and + <https://search.qa.fatcat.wiki>). The API is currently the raw + elasticsearch API, with only GET (read) requests allowed. This public + service is experimental and may be removed or limited in the future. + + ## Authentication + + The API allows basic read-only "GET" HTTP requests with no authentication. + Proposing changes to the metadata, or other mutating requests ("PUT", + "POST", "DELETE") all require authentication, and some operations require + additional account permissions. + + End-user account creation and login happens through the web interface. From + a logged-in editor profile page, you can generate a API token. Tokens are + "macaroons", similar to JWT tokens, and are used for all API + authentication. The web interface includes macaroons in browser cookies and + passes them through to the API to authenticate editor actions. + + <!-- ReDoc-Inject: <security-definitions> --> + <!-- ENDLONGDESCRIPTION --> + + termsOfService: "https://guide.fatcat.wiki/policies.html" + contact: + name: "Internet Archive Web Group" + email: "webservices@archive.org" + url: "https://fatcat.wiki" + x-logo: + url: "https://fatcat.wiki/static/paper_man_confused.gif" + altText: "Confused Papers Man (Logo)" + backgroundColor: "#FFFFFF" schemes: [https] basePath: /v0 host: api.fatcat.wiki @@ -13,92 +90,252 @@ consumes: produces: - application/json +x-servers: +- url: https://api.fatcat.wiki/v0 + description: "Production Server" +- url: https://api.qa.fatcat.wiki/v0 + description: "QA Server" + securityDefinitions: Bearer: type: apiKey name: Authorization in: header + description: | + The only current API authentication mechanism is HTTP bearer + authentication using the `Authorization` HTTP header. The header should + be formatted as the string "Bearer", then a space, then API token (in the + usual base64 string encoding). + + An example HTTP request would look on the wire like: + + GET /v0/auth/check HTTP/1.1 + Accept: */* + Accept-Encoding: gzip, deflate + Authorization: Bearer AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug= + Connection: keep-alive + Host: api.qa.fatcat.wiki + User-Agent: HTTPie/0.9.8 + + Headers can be passed on the command line using `http` (HTTPie) like: + + http get https://api.qa.fatcat.wiki/v0/auth/check Authorization:"Bearer AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=" + + Or with `curl`: + + curl -H "Authorization: Bearer AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=" https://qa.fatcat.wiki/v0/auth/check tags: # TAGLINE - name: containers # TAGLINE - descriptions: "Container entities: such as journals, conferences, book series" # TAGLINE + x-displayName: "Containers" # TAGLINE + description: | # TAGLINE + **Container** entities represent publication venues like journals, # TAGLINE + conference proceedings, book series, or blogs. They group publications # TAGLINE + ("releases"). # TAGLINE + + See the "Catalog Style Guide" section of the guide for details and # TAGLINE + semantics of what should be included in specific entity fields. # TAGLINE + Specifically, the # TAGLINE + [Container Entity Reference](https://guide.fatcat.wiki/entity_container.html). # TAGLINE - name: creators # TAGLINE - descriptions: "Creator entities: such as authors" # TAGLINE + x-displayName: "Creators" # TAGLINE + description: | # TAGLINE + **Creator** entities represent individuals (or organizations, or other # TAGLINE + agents) who contribute to the creation of specific releases # TAGLINE + (publications). # TAGLINE + + See the "Catalog Style Guide" section of the guide for details and # TAGLINE + semantics of what should be included in specific entity fields. # TAGLINE + Specifically, the # TAGLINE + [Creator Entity Reference](https://guide.fatcat.wiki/entity_creator.html). # TAGLINE - name: files # TAGLINE - descriptions: "File entities" # TAGLINE + x-displayName: "Files" # TAGLINE + description: | # TAGLINE + **File** entities represent unique digital files which are full # TAGLINE + manifestations of specific releases (publications), such as fulltext PDF # TAGLINE + files, JATS XML documents, or video files. File entities also include a # TAGLINE + set of locations where they can be found on the public web. # TAGLINE + + See the "Catalog Style Guide" section of the guide for details and # TAGLINE + semantics of what should be included in specific entity fields. # TAGLINE + Specifically, the # TAGLINE + [File Entity Reference](https://guide.fatcat.wiki/entity_file.html). # TAGLINE - name: filesets # TAGLINE - descriptions: "Fileset entities" # TAGLINE + x-displayName: "Filesets" # TAGLINE + description: | # TAGLINE + **Fileset** entities represent sets of digital files, as well as locations # TAGLINE + where they can be found on the public web. Filesets most commonly # TAGLINE + represent datasets consisting of serveral data and metadata files. # TAGLINE + + See the "Catalog Style Guide" section of the guide for details and # TAGLINE + semantics of what should be included in specific entity fields. # TAGLINE + Specifically, the # TAGLINE + [Fileset Entity Reference](https://guide.fatcat.wiki/entity_fileset.html). # TAGLINE - name: webcaptures # TAGLINE - descriptions: "Webcapture entities" # TAGLINE + x-displayName: "Webcaptures" # TAGLINE + description: | # TAGLINE + **Web Capture** entities represent archival snapshots of web pages (or # TAGLINE + other web resources), which are usually complete manifestations of a # TAGLINE + specific release entity. Web Captures also include a set of locations # TAGLINE + (wayback replay instances or WARC files) where the capture can be found. # TAGLINE + + See the "Catalog Style Guide" section of the guide for details and # TAGLINE + semantics of what should be included in specific entity fields. # TAGLINE + Specifically, the # TAGLINE + [Web Capture Entity Reference](https://guide.fatcat.wiki/entity_webcapture.html). # TAGLINE - name: releases # TAGLINE - descriptions: "Release entities: individual articles, pre-prints, books" # TAGLINE + x-displayName: "Releases" # TAGLINE + description: | # TAGLINE + **Release** entities represent specific published versions of a research # TAGLINE + work, such as a pre-print, a journal article, a book (or chapter), or a # TAGLINE + scholarly blog post. Releases are always grouped together under Works; # TAGLINE + they may be published in a specific Container; they may have known # TAGLINE + Creators; and there may exist known File/Fileset/WebCapture digital copies # TAGLINE + of the release. # TAGLINE + + See the "Catalog Style Guide" section of the guide for details and # TAGLINE + semantics of what should be included in specific entity fields. # TAGLINE + Specifically, the # TAGLINE + [Release Entity Reference](https://guide.fatcat.wiki/entity_release.html). # TAGLINE - name: works # TAGLINE - descriptions: "Work entities: grouping releases which are variants of the same work" # TAGLINE - - name: edit-lifecycle # TAGLINE - descriptions: "Endpoints relating to global edit submission and history" # TAGLINE + x-displayName: "Works" # TAGLINE + description: | # TAGLINE + **Work** entities group several Release entities which are different # TAGLINE + versions of the same abstract piece of research. For example, three # TAGLINE + release entities representing the pre-print, published article, and # TAGLINE + retraction stages of the same journal paper would be grouped under a # TAGLINE + single work. # TAGLINE + + See the "Catalog Style Guide" section of the guide for details and # TAGLINE + semantics of what should be included in specific entity fields. # TAGLINE + Specifically, the # TAGLINE + [Work Entity Reference](https://guide.fatcat.wiki/entity_work.html). # TAGLINE + - name: editgroups # TAGLINE + x-displayName: "Editgroups" # TAGLINE + description: | # TAGLINE + **Editgroups** are sets of changes, each to individual entities in the # TAGLINE + catalog. Every edit must be part of an editgroup which is reviewed and # TAGLINE + accepted (merged) as a whole. # TAGLINE + - name: editors # TAGLINE + x-displayName: "Editors" # TAGLINE + description: | # TAGLINE + **Editors** are human user accounts and bots that make changes to the # TAGLINE + Fatcat catalog. # TAGLINE + + The API allows fetching (and updating) metadata about individual editors, # TAGLINE + as well as fetching editor's annotation and edit history. # TAGLINE + - name: changelog # TAGLINE + x-displayName: "Changelog" # TAGLINE + description: | # TAGLINE + The **Changelog** is the ordered feed of editgroups which have been # TAGLINE + accepted into the catalog. # TAGLINE + - name: auth # TAGLINE + x-displayName: "Auth Methods" # TAGLINE + description: | # TAGLINE + Helper methods and internal APIs for editor authentication. # TAGLINE + +x-tagGroups: + - name: Entities + tags: + - containers + - creators + - files + - filesets + - webcaptures + - releases + - works + - name: Editing + tags: + - editors + - editgroups + - changelog + - name: Other + tags: + - auth # don't want these to be rust types (at least for now) x-fatcat-ident: &FATCATIDENT type: string - example: "q3nouwy3nnbsvo3h5klxsx4a7y" pattern: "[a-zA-Z2-7]{26}" minLength: 26 maxLength: 26 description: "base32-encoded unique identifier" +x-fatcat-ident-example: &FATCATIDENTEXAMPLE + example: "q3nouwy3nnbsvo3h5klxsx4a7y" x-fatcat-uuid: &FATCATUUID type: string - example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" pattern: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" minLength: 36 maxLength: 36 description: "UUID (lower-case, dash-separated, hex-encoded 128-bit)" +x-fatcat-uuid-example: &FATCATUUIDEXAMPLE + example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" x-issn: &FATCATISSN type: string - example: "1234-5678" pattern: "\\d{4}-\\d{3}[0-9X]" minLength: 9 maxLength: 9 +x-issn-example: &FATCATISSNEXAMPLE + example: "1234-5678" x-orcid: &FATCATORCID type: string - example: "0000-0002-1825-0097" pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]" minLength: 19 maxLength: 19 + description: "ORCiD (https://orcid.org) identifier" +x-orcid-example: &FATCATORCIDEXAMPLE + example: "0000-0002-1825-0097" x-md5: &FATCATMD5 type: string - example: "1b39813549077b2347c0f370c3864b40" pattern: "[a-f0-9]{32}" minLength: 32 maxLength: 32 + description: "MD5 hash of data, in hex encoding" +x-md5-example: &FATCATMD5EXAMPLE + example: "1b39813549077b2347c0f370c3864b40" x-sha1: &FATCATSHA1 type: string - example: "e9dd75237c94b209dc3ccd52722de6931a310ba3" pattern: "[a-f0-9]{40}" minLength: 40 maxLength: 40 + description: "SHA-1 hash of data, in hex encoding" +x-sha1-example: &FATCATSHA1EXAMPLE + example: "e9dd75237c94b209dc3ccd52722de6931a310ba3" x-sha256: &FATCATSHA256 type: string - example: "cb1c378f464d5935ddaa8de28446d82638396c61f042295d7fb85e3cccc9e452" pattern: "[a-f0-9]{64}" minLength: 64 maxLength: 64 + description: "SHA-256 hash of data, in hex encoding" +x-sha256-example: &FATCATSHA256EXAMPLE + example: "cb1c378f464d5935ddaa8de28446d82638396c61f042295d7fb85e3cccc9e452" # Common properties across entities x-entity-props: &ENTITYPROPS state: type: string enum: ["wip", "active", "redirect", "deleted"] + example: "active" ident: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE revision: <<: *FATCATUUID + <<: *FATCATUUIDEXAMPLE redirect: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE extra: type: object + description: | + Free-form JSON metadata that will be stored with the other entity + metadata. See guide for (unenforced) schema conventions. additionalProperties: {} edit_extra: type: object + description: | + Free-form JSON metadata that will be stored with specific entity edits + (eg, creation/update/delete). additionalProperties: {} definitions: @@ -111,8 +348,10 @@ definitions: properties: success: type: boolean + example: false error: type: string + example: "unexpected-thing" message: type: string example: "A really confusing, totally unexpected thing happened" @@ -124,6 +363,7 @@ definitions: properties: success: type: boolean + example: true message: type: string example: "The computers did the thing successfully!" @@ -134,18 +374,25 @@ definitions: <<: *ENTITYPROPS name: type: string + description: "Name of the container (eg, Journal title). Required for entity creation." example: "Journal of Important Results" - description: "Required for valid entities" container_type: type: string - description: "Eg, 'journal'" + description: "Type of container, eg 'journal' or 'proceedings'. See Guide for list of valid types." + example: "journal" publisher: type: string + description: | + Name of the organization or entity responsible for publication. Not + the complete imprint/brand. example: "Society of Curious Students" issnl: + description: "Linking ISSN number (ISSN-L). Should be valid and registered with issn.org" <<: *FATCATISSN + <<: *FATCATISSNEXAMPLE wikidata_qid: type: string + example: "Q42812" creator_entity: type: object # required for creation: display_name @@ -154,15 +401,26 @@ definitions: display_name: type: string example: "Grace Hopper" - description: "Required for valid entities" + description: | + Name as should be displayed in web interface or in author lists (not + index/sorted). Required for valid entities. given_name: type: string + description: | + In English commonly the first name, but ordering is context and + culture specific. surname: type: string + description: | + In English commonly the last, or family name, but ordering is context + and culture specific. orcid: <<: *FATCATORCID + <<: *FATCATORCIDEXAMPLE wikidata_qid: type: string + example: "Q42812" + description: "Wikidata entity QID" file_entity: type: object properties: @@ -171,12 +429,16 @@ definitions: type: integer example: 1048576 format: int64 + description: "Size of file in bytes. Non-zero." md5: <<: *FATCATMD5 + <<: *FATCATMD5EXAMPLE sha1: <<: *FATCATSHA1 + <<: *FATCATSHA1EXAMPLE sha256: <<: *FATCATSHA256 + <<: *FATCATSHA256EXAMPLE urls: type: array items: @@ -188,8 +450,16 @@ definitions: type: array items: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Set of identifier of release entities this file represents a full + manifestation of. Usually a single release, but some files contain + content of multiple full releases (eg, an issue of a journal). releases: - description: "Optional; GET-only" + description: | + Full release entities, included in GET responses when `releases` + included in `expand` parameter. Ignored if included in PUT or POST + requests. type: array items: $ref: "#/definitions/release_entity" @@ -203,9 +473,15 @@ definitions: type: string format: url example: "https://example.edu/~frau/prcding.pdf" + description: | + URL/URI pointing directly to a machine retrievable copy of this exact + file. rel: type: string - example: "webarchive" + example: "web" + description: | + Indicates type of host this URL points to. Eg, "publisher", + "repository", "webarchive". See guide for list of acceptable values. fileset_entity: type: object properties: @@ -223,11 +499,18 @@ definitions: type: array items: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Set of identifier of release entities this fileset represents a full + manifestation of. Usually a single release. releases: - description: "Optional; GET-only" type: array items: $ref: "#/definitions/release_entity" + description: | + Full release entities, included in GET responses when `releases` + included in `expand` parameter. Ignored if included in PUT or POST + requests. fileset_url: type: object required: @@ -241,6 +524,9 @@ definitions: rel: type: string example: "webarchive" + description: | + Indicates type of host this URL points to. See guide for list of + acceptable values. fileset_file: type: object required: @@ -250,19 +536,29 @@ definitions: path: type: string example: "img/cat.png" + description: | + Path name of file within this fileset (eg, directory) size: type: integer example: 1048576 format: int64 + description: "File size in bytes" md5: <<: *FATCATMD5 + <<: *FATCATMD5EXAMPLE sha1: <<: *FATCATSHA1 + <<: *FATCATSHA1EXAMPLE sha256: <<: *FATCATSHA256 + <<: *FATCATSHA256EXAMPLE extra: type: object additionalProperties: {} + description: | + Free-form additional metadata about this specific file in the set. + Eg, `mimetype`. See guide for nomative (but unenforced) schema + fields. webcapture_entity: type: object properties: @@ -280,19 +576,30 @@ definitions: type: string format: url example: "http://asheesh.org" + description: "Base URL of the primary resource this is a capture of" timestamp: type: string format: date-time - description: "same format as CDX line timestamp (UTC, etc). Corresponds to the overall capture timestamp. Can be the earliest or average of CDX timestamps if that makes sense." + description: | + Same format as CDX line timestamp (UTC, etc). Corresponds to the + overall capture timestamp. Should generally be the timestamp of + capture of the primary resource URL. release_ids: type: array items: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Set of identifier of release entities this fileset represents a full + manifestation of. Usually a single release. releases: - description: "Optional; GET-only" type: array items: $ref: "#/definitions/release_entity" + description: | + Full release entities, included in GET responses when `releases` + included in `expand` parameter. Ignored if included in PUT or POST + requests. webcapture_cdx_line: type: object required: @@ -304,30 +611,46 @@ definitions: surt: type: string example: "org,asheesh)/apus/ch1/node15.html" + description: | + "Sortable URL" format. See guide for details. timestamp: type: string format: date-time example: "2016-09-19T17:20:24Z" - description: "UTC, 'Z'-terminated, second (or better) precision" + description: | + Date and time of capture, in ISO format. UTC, 'Z'-terminated, second + (or better) precision. url: type: string # NOTE: not format:url to allow alternatives example: "http://www.asheesh.org:80/APUS/ch1/node15.html" + description: | + Full URL/URI of resource captured. mimetype: type: string example: "text/html" + description: | + Mimetype of the resource at this URL. May be the Content-Type header, + or the actually sniffed file type. status_code: type: integer example: 200 format: int64 + description: | + HTTP status code. Should generally be 200, especially for the primary + resource, but may be 3xx (redirect) or even error codes if embedded + resources can not be fetched successfully. size: type: integer example: 1048576 format: int64 + description: "Resource (file) size in bytes" sha1: <<: *FATCATSHA1 + <<: *FATCATSHA1EXAMPLE sha256: <<: *FATCATSHA256 + <<: *FATCATSHA256EXAMPLE webcapture_url: type: object required: @@ -338,9 +661,15 @@ definitions: type: string format: url example: "https://web.archive.org/web/" + description: | + URL/URI pointing to archive of this web resource. rel: type: string example: "wayback" + description: | + Type of archive endpoint. Usually `wayback` (WBM replay of primary + resource), or `warc` (direct URL to a WARC file containing all + resources of the capture). See guide for full list. release_entity: type: object # required for creation: title @@ -350,80 +679,167 @@ definitions: <<: *ENTITYPROPS title: type: string - description: "Required for valid entities. The title used in citations and for display; usually English" + description: | + Required for valid entities. The title used in citations and for + display. Sometimes the English translation of title e even if release + content is not English. subtitle: type: string - description: "Avoid this field if possible, and merge with title; usually English" + description: | + Subtitle of release. In many cases, better to merge with title than + include as separate field (unless combined title would be very long). + See guide for details. original_title: type: string - description: "Title in original language (or, the language of the full text of this release)" + description: | + Title in original language if `title` field has been translated. See + guide for details. work_id: type: string example: "q3nouwy3nnbsvo3h5klxsx4a7y" + description: | + Identifier of work this release is part of. In creation (POST) + requests, a work entity will be created automatically if this field + is not set. container: $ref: "#/definitions/container_entity" - description: "Optional; GET-only" + description: | + Complete container entity identified by `container_id` field. Only + included in GET reponses when `container` included in `expand` + parameter; ignored in PUT or POST requests. files: - description: "Optional; GET-only" type: array items: $ref: "#/definitions/file_entity" + description: | + Complete file entities identified by `file_ids` field. Only + included in GET responses when `files` included in `expand` parameter; + ignored in PUT or POST requests. filesets: - description: "Optional; GET-only" type: array items: $ref: "#/definitions/fileset_entity" + description: | + Complete file entities identified by `filesets_ids` field. Only + included in GET responses when `filesets` included in `expand` + parameter; ignored in PUT or POST requests. webcaptures: - description: "Optional; GET-only" type: array items: $ref: "#/definitions/webcapture_entity" + description: | + Complete webcapture entities identified by `webcapture_ids` field. + Only included in GET responses when `webcaptures` included in `expand` + parameter; ignored in PUT or POST requests. container_id: type: string example: "q3nouwy3nnbsvo3h5klxsx4a7y" + description: | + Used to link this release to a container entity that the release was + published as part of. release_type: type: string example: "book" + description: | + "Type" or "medium" that this release is published as. See guide for + valid values. release_stage: type: string - example: "preprint, retracted" + example: "preprint" + description: | + The stage of publication of this specific release. See guide for + valid values and semantics. release_date: type: string format: date + description: | + Full date when this release was formally published. ISO format, like + `2019-03-05`. See guide for semantics. release_year: type: integer example: 2014 format: int64 + description: | + Year when this release was formally published. Must match + `release_date` if that field is set; this field exists because + sometimes only the year is known. withdrawn_status: type: string + example: "retracted" + description: | + Type of withdrawl or retraction of this release, if applicable. If + release has not been withdrawn, should be `null` (aka, not set, not + the string "null" or an empty string). withdrawn_date: type: string format: date + description: | + Full date when this release was formally withdrawn (if applicable). + ISO format, like `release_date`. withdrawn_year: type: integer example: 2014 format: int64 + description: | + Year corresponding with `withdrawn_date` like + `release_year`/`release_date`. ext_ids: $ref: "#/definitions/release_ext_ids" + description: | + Set of external identifiers for this release. volume: type: string + example: "3" + description: | + Volume number of container that this release was published in. Often + corresponds to the "Nth" year of publication, but can be any string. + See guide. issue: type: string example: "12" + description: | + Issue number of volume/container that this release was published in. + Sometimes coresponds to a month number in the year, but can be any + string. See guide. pages: type: string + example: "340-345" + description: | + Either a single page number ("first page") or a range of pages + separated by a dash ("-"). See guide for details. number: type: string + example: "RFC1337" + description: | + For, eg, technical reports, which are published in series or + assigned some other institutional or container-specific identifier. version: type: string + example: "3" + description: | + For, eg, updated technical reports or software packages, where + the version string may be the only field disambiguating between + releases. publisher: type: string + example: "Elsevier" + description: | + Name, usually English, of the entity or institution responsible for + publication of this release. Not necessarily the imprint/brand. See + guide. language: - description: "Two-letter RFC1766/ISO639-1 language code, with extensions" type: string + example: "en" + description: | + Primary language of the content of the full release. Two-letter + RFC1766/ISO639-1 language code, with some custom + extensions/additions. See guide. license_slug: type: string - description: "Short version of license name. Eg, 'CC-BY'" + example: "CC-BY" + description: | + Short string (slug) name of license under which release is openly + published (if applicable). contribs: type: array items: @@ -443,40 +859,67 @@ definitions: type: string #format: custom example: "10.1234/abcde.789" + description: | + Digital Object Identifier (DOI), mostly for published papers and + datasets. Should be registered and resolvable via https://doi.org/ wikidata_qid: type: string + example: "Q42812" + description: "Wikidata entity QID" isbn13: type: string #format: custom + description: | + ISBN-13, for books. Usually not set for chapters. ISBN-10 should be + converted to ISBN-13. pmid: type: string + example: "482132" + description: "PubMed Identifier" pmcid: + example: "PMC7391" type: string + description: "PubMed Central Identifier" core: + exmaple: "9234592" type: string #format: custom + description: "CORE (https://core.ac.uk) identifier" arxiv: type: string + description: "arXiv (https://arxiv.org) identifier; must include version" jstor: type: string + description: "JSTOR work identifier" ark: type: string + description: "ARK identifier" mag: type: string + description: "Microsoft Academic Graph identifier" release_abstract: type: object properties: sha1: <<: *FATCATSHA1 + <<: *FATCATSHA1EXAMPLE content: type: string example: "<jats:p>Some abstract thing goes here</jats:p>" + description: | + Abstract content. May be encoded, as per `mimetype` field, but only + string/text content may be included. mimetype: type: string example: "application/xml+jats" + description: | + Mimetype of abstract contents. `text/plain` is the default if content + isn't encoded. lang: type: string example: "en" + description: | + ISO language code of the abstract. Same semantics as release `language` field. work_entity: type: object properties: @@ -503,16 +946,37 @@ definitions: properties: edit_id: <<: *FATCATUUID + <<: *FATCATUUIDEXAMPLE + description: | + Unique UUID for this specific edit object. ident: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Fatcat identifier of the entity this edit is mutating. revision: <<: *FATCATUUID + <<: *FATCATUUIDEXAMPLE + description: | + Entity revision that this edit will set the entity to. May be + `null` in the case of deletions. prev_revision: <<: *FATCATUUID + <<: *FATCATUUIDEXAMPLE + description: | + Revision of entity just before this edit. May be used in the future + to prevent edit race conditions. redirect_ident: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + When an edit is to merge entities (redirect one to another), this + is the entity fatcat identifier for the target entity. editgroup_id: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Editgroup identifier that this edit is part of. extra: type: object additionalProperties: {} @@ -523,45 +987,94 @@ definitions: properties: editor_id: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Fatcat identifier for the editor. Can not be changed. username: type: string example: "zerocool93" + description: | + Username/handle (short slug-like string) to identify this editor. May + be changed at any time by the editor; use the `editor_id` as a + persistend identifer. is_admin: type: boolean + example: false + description: | + Whether this editor has the `admin` role. is_bot: type: boolean + example: false + description: | + Whether this editor is a bot (as opposed to a human making manual + edits) is_active: type: boolean + example: true + description: | + Whether this editor's account is enabled (if not API tokens and web + logins will not work). editgroup: type: object properties: editgroup_id: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Fatcat identifier for this editgroup. Assigned on creation. editor_id: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Fatcat identifer of editor that created this editgroup. editor: $ref: "#/definitions/editor" + description: | + Complete editor object identified by `container_id` field. Only + included in GET responses. changelog_index: # not returned in all contexts... type: integer example: 1048576 format: int64 + description: | + For accepted/merged editgroups, the changelog index that the accept + occured at. WARNING: not populated in all contexts that an editgroup + could be included in a response. created: type: string format: date-time + description: | + Timestamp when this editgroup was first created. submitted: type: string format: date-time + description: | + Timestamp when this editgroup was most recently submitted for review. + If withdrawn, or never submitted, will be `null`. description: type: string + description: | + Comment describing the changes in this editgroup. Can be updated with + PUT request. extra: type: object additionalProperties: {} + description: | + Free-form JSON metadata attached to this editgroup. Eg, metadata + provenance, or script user-agent details. See guide for (unenforced) + schema norms. annotations: type: array items: $ref: "#/definitions/editgroup_annotation" + description: | + Only included in GET responses, and not in all contexts. Do not + include this field in PUT or POST requests. edits: type: object + description: | + Only included in GET responses, and not in all contexts. Do not + include this field in PUT or POST requests. properties: containers: type: array @@ -596,20 +1109,36 @@ definitions: properties: annotation_id: <<: *FATCATUUID + <<: *FATCATUUIDEXAMPLE editgroup_id: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Editgroup that this annotation applies to. Set automatically in + creations based on URL parameter. editor_id: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Defaults to editor created the annotation via POST request. editor: $ref: "#/definitions/editor" + description: | + Only included in GET responses; ignored in PUT or POST requests. created: type: string format: date-time + description: | + Timestamp when annotation was first created. comment_markdown: type: string extra: type: object additionalProperties: {} + description: | + Additional free-form JSON metadata that can be included as part of + the annotation (or even as the primary annotation itself). See guide + for details. changelog_entry: type: object required: @@ -620,12 +1149,18 @@ definitions: index: type: integer format: int64 + description: | + Monotonically increasing sequence number of this changelog entry. editgroup_id: type: string example: "q3nouwy3nnbsvo3h5klxsx4a7y" + description: | + Identifier of editgroup accepted/merged in this changelog entry. timestamp: type: string format: date-time + description: | + Date and time when the editgroup was accpeted. editgroup: $ref: "#/definitions/editgroup" release_ref: @@ -634,48 +1169,104 @@ definitions: index: type: integer format: int64 + description: | + Zero-indexed sequence number of this reference in the list of + references. Assigned automatically and used internally; don't confuse + with `key`. target_release_id: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + Optional, fatcat identifier of release entity that this reference is + citing. extra: type: object additionalProperties: {} + description: | + Additional free-form JSON metadata about this citation. Generally + follows Citation Style Language (CSL) JSON schema. See guide for + details. key: type: string + example: "SMITH2016" + description: | + Short string used to indicate this reference from within the release + text; or numbering of references as typeset in the release itself. + Optional; don't confuse with `index` field. year: type: integer format: int64 + example: 1972 + description: | + Year that the cited work was published in. container_name: type: string + description: | + Name of the container (eg, journal) that the citation work was + published as part of. May be an acronym or full name. title: type: string + description: + Name of the work being cited. locator: type: string example: "p123" + description: | + Page number or other indicator of the specific subset of a work being + cited. Not to be confused with the first page (or page range) of an + entire paper or chapter being cited. release_contrib: type: object properties: index: type: integer format: int64 + example: 0 + description: | + Internally assigned zero-indexed sequence number of contribution. + Authors should come first; this encodes the order of attriubtion. creator_id: <<: *FATCATIDENT + <<: *FATCATIDENTEXAMPLE + description: | + If known, indicates the creator entity this contribution was made by. creator: $ref: "#/definitions/creator_entity" - description: "Optional; GET-only" + description: | + Complete creator entity. Only returned in GET responses, and only if + `contribs` included in the `expand` query parameter. raw_name: type: string + example: "Jane K. Doe" + description: | + Full name of the contributor as typeset in the release. given_name: type: string + example: "Jane" + description: | + In English commonly the first name, but ordering is context and + culture specific. surname: type: string + example: "Doe" + description: | + In English commonly the last, or family name, but ordering is context + and culture specific. role: type: string + example: "author" + description: | + Short string (slug) indicating type of contribution (eg, "author", + "translator"). See guide for list of accpeted values. raw_affiliation: type: string description: "Raw affiliation string as displayed in text" extra: type: object additionalProperties: {} + description: | + Additional free-form JSON metadata about this + contributor/contribution. See guide for normative schema. container_auto_batch: type: object required: @@ -770,12 +1361,26 @@ definitions: properties: provider: type: string + example: "orcid" + description: | + Fatcat-specific short name (slug) for remote service being used for + authentication. sub: type: string + description: "`SUB` from OIDC protocol. Usually a URL." + example: "https://orcid.org" iss: type: string + description: "`ISS` from OIDC protocol. Usually a stable account username, number, or identifier." + example: "0000-0002-8593-9468" preferred_username: type: string + description: | + What it sounds like; returned by OIDC, and used as a hint when + creating new editor accounts. Fatcat usernames are usually this + string with the `provider` slug as a suffix, though some munging may + occur. + example: "bnewbold" auth_oidc_result: type: object required: @@ -786,6 +1391,7 @@ definitions: $ref: "#/definitions/editor" token: type: string + example: "AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=" x-auth-responses: &AUTHRESPONSES 401: @@ -824,6 +1430,11 @@ paths: operationId: "create_container" tags: # TAGLINE - containers # TAGLINE + description: | + Create a single Container entity as part of an existing editgroup. + + Editgroup must be mutable (aka, not accepted) and editor must have + permission (aka, have created the editgrou p or have `admin` role). parameters: - name: entity in: body @@ -844,6 +1455,15 @@ paths: operationId: "create_container_auto_batch" tags: # TAGLINE - containers # TAGLINE + description: | + Create a set of Container entities as part of a new editgroup, and + accept that editgroup in the same atomic request. + + This method is mostly useful for bulk import of new entities by + carefully written bots. This method is more efficient than creating an + editgroup, several entities, then accepting the editgroup, both in + terms of API requests required and database load. Requires `admin` + role. parameters: - name: auto_batch in: body @@ -869,6 +1489,8 @@ paths: operationId: "get_container" tags: # TAGLINE - containers # TAGLINE + description: | + Fetches a single container entity from the catalog. parameters: - name: expand in: query @@ -900,6 +1522,16 @@ paths: operationId: "update_container" tags: # TAGLINE - containers # TAGLINE + description: | + Updates an existing entity as part of a specific (existing) editgroup. + The editgroup must be open for updates (aka, not accepted/merged), and + the editor making the requiest must have permissions (aka, must have + created the editgroup or have `admin` role). + + This method can also be used to update an existing entity edit as part + of an editgroup. For example, if an entity was created in this + editgroup, an editor could make changes to the new entity's metadata + before merging. parameters: - name: entity in: body @@ -919,6 +1551,12 @@ paths: operationId: "delete_container" tags: # TAGLINE - containers # TAGLINE + description: | + Creates a new "deletion" edit for a specific entity as part of an + existing editgroup. + + This is not the method to use to remove an edit from an editgroup; for + that use `delete_container_edit`. security: - Bearer: [] responses: @@ -938,17 +1576,24 @@ paths: operationId: "get_container_revision" tags: # TAGLINE - containers # TAGLINE + description: | + Fetches a specific entity revision. Note that the returned revision + will not be associated with any particular fatcat identifier (even if + one or more identifiers do currently point to this revision). The + revision may even be part of an un-merged editgroup. + + Revisions are immutable and can not be deleted or updated. parameters: - name: expand in: query type: string required: false - description: "List of sub-entities to expand in response. For containers, none accepted (yet)." + description: "List of sub-entities to expand in response. See `get_container`." - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For containers, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_container`." responses: 200: description: Found Entity Revision @@ -966,9 +1611,13 @@ paths: type: integer format: int64 required: false + description: "Maximum number of changelog entries to return" get: tags: # TAGLINE - containers # TAGLINE + description: | + Fetches the history of accepted edits (changelog entries) for a + specific entity fatcat identifier. operationId: "get_container_history" responses: 200: @@ -985,9 +1634,12 @@ paths: type: string required: true get: + operationId: "get_container_redirects" tags: # TAGLINE - containers # TAGLINE - operationId: "get_container_redirects" + description: | + Returns the set of entity identifiers which currently redirect to this + identifier. responses: 200: description: Found Entity Redirects @@ -1001,6 +1653,14 @@ paths: operationId: "lookup_container" tags: # TAGLINE - containers # TAGLINE + description: | + Looks for an active entity with the given external identifier. If any + such entity is found, returns a single complete entity. If multiple + entities have the same external identifier, this is considered a soft + catalog error, and the behavior of which entity is returned is + undefined. + + One (and only one) external identifier should be specified per request. parameters: - name: issnl in: query @@ -1008,17 +1668,18 @@ paths: <<: *FATCATISSN - name: wikidata_qid in: query + type: string required: false - name: expand in: query type: string required: false - description: "List of sub-entities to expand in response." + description: "List of sub-entities to expand in response. See `get_container`." - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For container, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_container`." responses: 200: description: Found Entity @@ -1030,6 +1691,9 @@ paths: operationId: "get_container_edit" tags: # TAGLINE - containers # TAGLINE + description: | + Returns the entity edit object with the given identifier. This method + is expected to be used rarely. parameters: - name: edit_id in: path @@ -1055,6 +1719,14 @@ paths: operationId: "delete_container_edit" tags: # TAGLINE - containers # TAGLINE + description: | + Removes a single edit from the specified editgroup. The editgroup must + be mutable (aka, not accepted/merged), and the editor making this + request must have permission (aka, have created the editgroup or hold + the `admin` role). + + Not to be confused with the `delete_container` method, which *creates* + a new edit in the given editgroup. security: - Bearer: [] responses: @@ -1064,6 +1736,7 @@ paths: $ref: "#/definitions/success" <<: *ENTITYRESPONSES <<: *AUTHRESPONSES + /editgroup/{editgroup_id}/creator: parameters: - name: editgroup_id @@ -1129,7 +1802,7 @@ paths: in: query type: string required: false - description: "List of entity fields to elide in response. For containers, none accepted (yet)." + description: "List of entity fields to elide in response. For creators, none accepted (yet)." responses: 200: description: Found Entity @@ -1193,12 +1866,15 @@ paths: in: query type: string required: false - description: "List of sub-entities to expand in response. For creators, none accepted (yet)." + description: | + List of sub-entities to expand in response. See `get_creator`, + though note that identifier-based expansions (like `releases`) will + always be empty for revisions. - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For creators, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_creator`." responses: 200: description: Found Entity Revision @@ -1238,11 +1914,14 @@ paths: in: query type: string required: false - description: "List of entity fields to elide in response. For creators, none implemented yet." + description: "List of entity fields to elide in response. See `get_release`." get: operationId: "get_creator_releases" tags: # TAGLINE - creators # TAGLINE + description: | + Returns the set of Release entities having a `contrib` entry pointing + to the creator entity. responses: 200: description: Found @@ -1258,9 +1937,9 @@ paths: type: string required: true get: + operationId: "get_creator_redirects" tags: # TAGLINE - creators # TAGLINE - operationId: "get_creator_redirects" responses: 200: description: Found Entity Redirects @@ -1281,17 +1960,18 @@ paths: <<: *FATCATORCID - name: wikidata_qid in: query + type: string required: false - name: expand in: query type: string required: false - description: "List of sub-entities to expand in response." + description: "List of sub-entities to expand in response. See `get_creator`." - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For creator, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_creator`." responses: 200: description: Found Entity @@ -1337,6 +2017,7 @@ paths: $ref: "#/definitions/success" <<: *ENTITYRESPONSES <<: *AUTHRESPONSES + /editgroup/{editgroup_id}/file: parameters: - name: editgroup_id @@ -1466,12 +2147,12 @@ paths: in: query type: string required: false - description: "List of sub-entities to expand in response. For files, none accepted (yet)." + description: "List of sub-entities to expand in response. See `get_file`." - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For files, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_file`." responses: 200: description: Found Entity Revision @@ -1508,9 +2189,9 @@ paths: type: string required: true get: + operationId: "get_file_redirects" tags: # TAGLINE - files # TAGLINE - operationId: "get_file_redirects" responses: 200: description: Found Entity Redirects @@ -1541,12 +2222,12 @@ paths: in: query type: string required: false - description: "List of sub-entities to expand in response." + description: "List of sub-entities to expand in response. See `get_file`." - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For files, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_file`." responses: 200: description: Found Entity @@ -1592,6 +2273,7 @@ paths: $ref: "#/definitions/success" <<: *ENTITYRESPONSES <<: *AUTHRESPONSES + /editgroup/{editgroup_id}/fileset: parameters: - name: editgroup_id @@ -1721,12 +2403,12 @@ paths: in: query type: string required: false - description: "List of sub-entities to expand in response. For filesets, none accepted (yet)." + description: "List of sub-entities to expand in response. See `get_fileset`." - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For filesets, 'manifest' is accepted." + description: "List of entity fields to elide in response. See `get_fileset`." responses: 200: description: Found Entity Revision @@ -1763,9 +2445,9 @@ paths: type: string required: true get: + operationId: "get_fileset_redirects" tags: # TAGLINE - filesets # TAGLINE - operationId: "get_fileset_redirects" responses: 200: description: Found Entity Redirects @@ -1813,6 +2495,7 @@ paths: $ref: "#/definitions/success" <<: *ENTITYRESPONSES <<: *AUTHRESPONSES + /editgroup/{editgroup_id}/webcapture: parameters: - name: editgroup_id @@ -1942,12 +2625,12 @@ paths: in: query type: string required: false - description: "List of sub-entities to expand in response. For webcaptures, none accepted (yet)." + description: "List of sub-entities to expand in response. See `get_webcapture`." - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For webcaptures, 'cdx' is accepted." + description: "List of entity fields to elide in response. See `get_webcapture`." responses: 200: description: Found Entity Revision @@ -1984,9 +2667,9 @@ paths: type: string required: true get: + operationId: "get_webcapture_redirects" tags: # TAGLINE - webcaptures # TAGLINE - operationId: "get_webcapture_redirects" responses: 200: description: Found Entity Redirects @@ -2034,6 +2717,7 @@ paths: $ref: "#/definitions/success" <<: *ENTITYRESPONSES <<: *AUTHRESPONSES + /editgroup/{editgroup_id}/release: parameters: - name: editgroup_id @@ -2044,6 +2728,13 @@ paths: operationId: "create_release" tags: # TAGLINE - releases # TAGLINE + description: | + Create a single Release entity as part of an existing editgroup. If the + `work_id` field is not set, a work entity will be created automatically + and this field set pointing to the new work. + + Editgroup must be mutable (aka, not accepted) and editor must have + permission (aka, have created the editgrou p or have `admin` role). parameters: - name: entity in: body @@ -2064,6 +2755,15 @@ paths: operationId: "create_release_auto_batch" tags: # TAGLINE - releases # TAGLINE + description: | + Create a set of Release entities as part of a new editgroup, and + accept that editgroup in the same atomic request. + + This method is mostly useful for bulk import of new entities by + carefully written bots. This method is more efficient than creating an + editgroup, several entities, then accepting the editgroup, both in + terms of API requests required and database load. Requires `admin` + role. parameters: - name: auto_batch in: body @@ -2089,17 +2789,23 @@ paths: operationId: "get_release" tags: # TAGLINE - releases # TAGLINE + description: | + Fetches a single Release entity from the catalog. parameters: - name: expand in: query type: string required: false - description: "List of sub-entities to expand in response. For releases, 'files', 'filesets, 'webcaptures', 'container', and 'creators' are valid." + description: | + List of sub-entities to expand in response. For releases, 'files', + 'filesets, 'webcaptures', 'container', and 'creators' are valid. - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For releases, 'abstracts', 'refs', and 'contribs' are valid." + description: | + List of entity fields to elide in response (for efficiency). For + releases, 'abstracts', 'refs', and 'contribs' are valid. responses: 200: description: Found Entity @@ -2120,6 +2826,16 @@ paths: operationId: "update_release" tags: # TAGLINE - releases # TAGLINE + description: | + Updates an existing entity as part of a specific (existing) editgroup. + The editgroup must be open for updates (aka, not accepted/merged), and + the editor making the requiest must have permissions (aka, must have + created the editgroup or have `admin` role). + + This method can also be used to update an existing entity edit as part + of an editgroup. For example, if an entity was created in this + editgroup, an editor could make changes to the new entity's metadata + before merging. parameters: - name: entity in: body @@ -2139,6 +2855,12 @@ paths: operationId: "delete_release" tags: # TAGLINE - releases # TAGLINE + description: | + Creates a new "deletion" edit for a specific entity as part of an + existing editgroup. + + This is not the method to use to remove an edit from an editgroup; for + that use `delete_release_edit`. security: - Bearer: [] responses: @@ -2158,17 +2880,27 @@ paths: operationId: "get_release_revision" tags: # TAGLINE - releases # TAGLINE + description: | + Fetches a specific entity revision. Note that the returned revision + will not be associated with any particular fatcat identifier (even if + one or more identifiers do currently point to this revision). The + revision may even be part of an un-merged editgroup. + + Revisions are immutable and can not be deleted or updated. parameters: - name: expand in: query type: string required: false - description: "List of sub-entities to expand in response. For releases, none accepted (yet)." + description: + List of sub-entities to expand in response. See `get_release`, + though note that identifier-based exapansions like `file` will + always be empty for revisions. - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For releases, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_release`." responses: 200: description: Found Entity Revision @@ -2190,6 +2922,9 @@ paths: operationId: "get_release_history" tags: # TAGLINE - releases # TAGLINE + description: | + Fetches the history of accepted edits (changelog entries) for a + specific entity fatcat identifier. responses: 200: description: Found Entity History @@ -2208,11 +2943,14 @@ paths: in: query type: string required: false - description: "List of entity fields to elide in response. For files, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_file`." get: operationId: "get_release_files" tags: # TAGLINE - releases # TAGLINE + description: | + Returns the set of File entities that have a `release_id` pointing to + this release entity. responses: 200: description: Found @@ -2231,11 +2969,14 @@ paths: in: query type: string required: false - description: "List of entity fields to elide in response. For filesets, 'manifest' is valid." + description: "List of entity fields to elide in response. See `get_fileset`." get: operationId: "get_release_filesets" tags: # TAGLINE - releases # TAGLINE + description: | + Returns the set of Fileset entities that have a `release_id` pointing to + this release entity. responses: 200: description: Found @@ -2254,11 +2995,14 @@ paths: in: query type: string required: false - description: "List of entity fields to elide in response. For webcaptures, 'cdx' is valid." + description: "List of entity fields to elide in response. See `get_webcapture`." get: operationId: "get_release_webcaptures" tags: # TAGLINE - releases # TAGLINE + description: | + Returns the set of Web Capture entities that have a `release_id` + pointing to this release entity. responses: 200: description: Found @@ -2274,9 +3018,12 @@ paths: type: string required: true get: + operationId: "get_release_redirects" tags: # TAGLINE - releases # TAGLINE - operationId: "get_release_redirects" + description: | + Returns the set of entity identifiers which currently redirect to this + identifier. responses: 200: description: Found Entity Redirects @@ -2290,7 +3037,16 @@ paths: operationId: "lookup_release" tags: # TAGLINE - releases # TAGLINE + description: | + Looks for an active entity with the given external identifier. If any + such entity is found, returns a single complete entity. If multiple + entities have the same external identifier, this is considered a soft + catalog error, and the behavior of which entity is returned is + undefined. + + One (and only one) external identifier should be specified per request. parameters: + # TODO: use identifier types here - name: doi in: query type: string @@ -2335,12 +3091,12 @@ paths: in: query type: string required: false - description: "List of sub-entities to expand in response." + description: "List of sub-entities to expand in response. See `get_release`." - name: hide in: query type: string required: false - description: "List of sub-entities to expand in response. For releases, 'files', 'filesets, 'webcaptures', 'container', and 'creators' are valid." + description: "List of sub-entities to elide in response. See `get_release`." responses: 200: description: Found Entity @@ -2352,6 +3108,9 @@ paths: operationId: "get_release_edit" tags: # TAGLINE - releases # TAGLINE + description: | + Returns the entity edit object with the given identifier. This method + is expected to be used rarely. parameters: - name: edit_id in: path @@ -2377,6 +3136,14 @@ paths: operationId: "delete_release_edit" tags: # TAGLINE - releases # TAGLINE + description: | + Removes a single edit from the specified editgroup. The editgroup must + be mutable (aka, not accepted/merged), and the editor making this + request must have permission (aka, have created the editgroup or hold + the `admin` role). + + Not to be confused with the `delete_container` method, which *creates* + a new edit in the given editgroup. security: - Bearer: [] responses: @@ -2386,6 +3153,7 @@ paths: $ref: "#/definitions/success" <<: *ENTITYRESPONSES <<: *AUTHRESPONSES + /editgroup/{editgroup_id}/work: parameters: - name: editgroup_id @@ -2395,7 +3163,7 @@ paths: post: operationId: "create_work" tags: # TAGLINE - - releases # TAGLINE + - works # TAGLINE parameters: - name: entity in: body @@ -2515,12 +3283,15 @@ paths: in: query type: string required: false - description: "List of sub-entities to expand in response. For works, none accepted (yet)." + description: + List of sub-entities to expand in response. See `get_work`, though + note that identifier-based expansions like `releases` will always + be empty for revisions. - name: hide in: query type: string required: false - description: "List of entity fields to elide in response. For works, none accepted (yet)." + description: "List of entity fields to elide in response. See `get_work`." responses: 200: description: Found Entity Revision @@ -2557,9 +3328,9 @@ paths: type: string required: true get: + operationId: "get_work_redirects" tags: # TAGLINE - works # TAGLINE - operationId: "get_work_redirects" responses: 200: description: Found Entity Redirects @@ -2578,11 +3349,14 @@ paths: in: query type: string required: false - description: "List of entity fields to elide in response. For works, none implemented yet." + description: "List of entity fields to elide in response. See `get_release`." get: operationId: "get_work_releases" tags: # TAGLINE - works # TAGLINE + description: | + Returns the set of release entities that are part of this work (aka, + have `work_id` pointing to this work entity). responses: 200: description: Found @@ -2630,6 +3404,7 @@ paths: $ref: "#/definitions/success" <<: *ENTITYRESPONSES <<: *AUTHRESPONSES + /editor/{editor_id}: parameters: - name: editor_id @@ -2638,6 +3413,11 @@ paths: required: true get: operationId: "get_editor" + tags: # TAGLINE + - editors # TAGLINE + description: | + Returns an editor object, including metadata such as the username, + type, and role of editor. responses: 200: description: Found @@ -2657,6 +3437,14 @@ paths: $ref: "#/definitions/error_response" put: operationId: "update_editor" + tags: # TAGLINE + - editors # TAGLINE + description: | + Allows metadata changes to some editor fields, such as the username. + + Changes require authentication and permissions. An editor can change + their own username; changes to role flags require the `admin` role by + the editor making the request. parameters: - name: editor in: body @@ -2691,6 +3479,11 @@ paths: required: true get: operationId: "get_editor_editgroups" + tags: # TAGLINE + - editors # TAGLINE + description: | + Returns a set of editgroups created by the given editor, regardless of + the status (accepted/submitted) of the editgroups. parameters: - name: limit in: query @@ -2702,11 +3495,19 @@ paths: type: string format: date-time required: false + description: | + Return only editgroups created *before* the given timestamp (not + inclusive). Editgroups will be sorted by creation time in + descending order (most recent first). For use in pagination. - name: since in: query type: string format: date-time required: false + description: | + Return only editgroups created *after* the given timestamp (not + inclusive). Editgroups will be sorted by creation time in ascending + order (most recent last). For use in pagination. responses: 200: description: Found @@ -2735,23 +3536,34 @@ paths: get: operationId: "get_editor_annotations" tags: # TAGLINE - - edit-lifecycle # TAGLINE + - editors # TAGLINE + description: | + Fetches a list of annotations made by a particular editor. parameters: - name: limit in: query type: integer format: int64 required: false + description: "Maximum number (count) of annotations to return in response" - name: before in: query type: string format: date-time required: false + description: | + Return only annotations made *before* the given timestamp (not + inclusive). Annotations will be sorted by creation time in + descending order (most recent first). For use in pagination. - name: since in: query type: string format: date-time required: false + description: | + Return only annotations made *after* the given timestamp (not + inclusive). Annotations will be sorted by creation time in + ascending order (most recent last). For use in pagination. responses: 200: description: Success @@ -2772,11 +3584,15 @@ paths: schema: $ref: "#/definitions/error_response" <<: *AUTHRESPONSES + /editgroup: post: operationId: "create_editgroup" tags: # TAGLINE - - edit-lifecycle # TAGLINE + - editgroups # TAGLINE + description: | + Creates a new editgroup. By default the editor making this request will + be the author of the editgroup. parameters: - name: editgroup in: body @@ -2812,7 +3628,13 @@ paths: get: operationId: "get_editgroup" tags: # TAGLINE - - edit-lifecycle # TAGLINE + - editgroups # TAGLINE + description: | + Returns a single editgroup object. + + Unlike some similar methods, this method will return a full/expanded + editgroup object, which includes edit lists of each entity type (though + will not include the complete entity objects). responses: 200: description: Found @@ -2832,6 +3654,14 @@ paths: $ref: "#/definitions/error_response" put: operationId: "update_editgroup" + tags: # TAGLINE + - editgroups # TAGLINE + description: | + Updates metadata for a single editgroup object. Note that only metadata + fields such as the `description` or `extra` metadata can be changed + with this method; it does not allow adding or removing edits to the + editgroup (for that use the individual entity create/update/delete + methods). security: - Bearer: [] parameters: @@ -2871,7 +3701,11 @@ paths: post: operationId: "accept_editgroup" tags: # TAGLINE - - edit-lifecycle # TAGLINE + - editgroups # TAGLINE + description: | + Accept ("merge") the given editgroup into the catalog. The editgroup + must be open (not already accepted), and the editor making this request + must have the `admin` role. security: - Bearer: [] responses: @@ -2905,13 +3739,15 @@ paths: get: operationId: "get_editgroup_annotations" tags: # TAGLINE - - edit-lifecycle # TAGLINE + - editgroups # TAGLINE + description: + Returns a list of annotations made to a specific editgroup. parameters: - name: expand in: query type: string required: false - description: "List of sub-entities to expand in response. For editgroups: 'editors'" + description: "List of sub-entities to expand in response. For editgroup annotations: 'editors'" responses: 200: description: Success @@ -2941,7 +3777,12 @@ paths: post: operationId: "create_editgroup_annotation" tags: # TAGLINE - - edit-lifecycle # TAGLINE + - editgroups # TAGLINE + description: | + Submits a new annotation to the specified editgroup. + + The editgroup must be open (not already accepted). The annotation will + automatically have authorship of the editor making this request. security: - Bearer: [] parameters: @@ -2971,6 +3812,12 @@ paths: /editgroup/reviewable: get: operationId: "get_editgroups_reviewable" + tags: # TAGLINE + - editgroups # TAGLINE + description: | + Returns a set of editgroups which have been submitted but not yet accepted. + + Query parameters can be used to sort and paginate the list returned. parameters: - name: expand in: query @@ -2982,16 +3829,25 @@ paths: type: integer format: int64 required: false + description: "Maximum number of reviewable editgroups to return in response" - name: before in: query type: string format: date-time required: false + description: | + Return only reviewable editgroups submitted *before* the given + timestamp (not inclusive). Editgroups will be sorted by submission + time in descending order (most recent first). For use in pagination. - name: since in: query type: string format: date-time required: false + description: | + Return only reviewable editgroups submitted *after* the given + timestamp (not inclusive). Editgroups will be sorted by submission + time in ascending order (most recent last). For use in pagination. responses: 200: description: Found @@ -3018,10 +3874,27 @@ paths: type: integer format: int64 required: false + description: "Maximum count of changelog entries to return in response" get: operationId: "get_changelog" tags: # TAGLINE - - edit-lifecycle # TAGLINE + - changelog # TAGLINE + description: | + Returns a list of the most recent changelog entries accepted (merged) + into the catalog. + + List is sorted by changelog index in descending order. Note that the + accepted timestamp roughly corresponds to order, but not strictly; + there exist out-of-order timestamps on the order of several seconds. + + As a known database issue, it is technically possible for there to be a + gap in changelog index numbers (aka, a missing changelog entry). There + are no currently known gaps and this is considered a bug that will be + addressed. + + There are millions of entries; to paginate through all of them, use + this method to discover the highest existing entry number, then request + the entries using `get_changelog_entry` one at a time. responses: 200: description: Success @@ -3044,10 +3917,18 @@ paths: type: integer format: int64 required: true + description: "Changelog index of entry to return" get: operationId: "get_changelog_entry" tags: # TAGLINE - - edit-lifecycle # TAGLINE + - changelog # TAGLINE + description: | + Returns a single changelog entry. + + As a known database issue, it is technically possible for there to be a + gap in changelog index numbers (aka, a missing changelog entry). There + are no currently known gaps and this is considered a bug that will be + addressed. responses: 200: description: Found Changelog Entry @@ -3069,6 +3950,18 @@ paths: post: operationId: "auth_oidc" tags: # TAGLINE + - auth # TAGLINE + description: | + Login or create editor account using OIDC metadata (internal method). + + This method is used by privileged front-end tools (like the web + interface service) to process editor logins using OpenID Connect (OIDC) + and/or OAuth. Most accounts (including tool and bot accounts) do not + have sufficient privileges to call this method, which requires the + `admin` role. + + The method returns an API token; the HTTP status code indicates whether + an existing account was logged in, or a new account was created. security: # required admin privs - Bearer: [] @@ -3104,6 +3997,11 @@ paths: get: operationId: "auth_check" tags: # TAGLINE + - auth # TAGLINE + description: | + Verify that authentication (API token) is working as expected. The + optional `role` parameter can be used to verify that the current + account (editor) has permissions for the given role. security: # required admin privs - Bearer: [] diff --git a/rust/fatcat-openapi/api/swagger.yaml b/rust/fatcat-openapi/api/swagger.yaml index b4c5e657..296570af 100644 --- a/rust/fatcat-openapi/api/swagger.yaml +++ b/rust/fatcat-openapi/api/swagger.yaml @@ -1,21 +1,146 @@ --- swagger: "2.0" info: - description: "A scalable, versioned, API-oriented catalog of bibliographic entities\ - \ and file metadata" + description: "Fatcat is a scalable, versioned, API-oriented catalog of bibliographic\n\ + entities and file metadata.\n\n<!-- STARTLONGDESCRIPTION -->\nThese API reference\ + \ documents, along with client software libraries, are\ngenerated automatically\ + \ from an OpenAPI 2.0 (\"Swagger\") definition file.\n\n## Introduction\n\n\n\ + A higher-level introduction to the API, as well as a description of the\nfatcat\ + \ data model, are available in [\"The Fatcat Guide\"](https://guide.fatcat.wiki/).\n\ + The guide also includes a [Cookbook](https://guide.fatcat.wiki/cookbook.html)\n\ + section demonstrating end-to-end tasks like creating entities as part of\neditgroups,\ + \ or safely merging duplicate entities.\n\n### Expectations and Best Practices\n\ + \nA test/staging QA API instance of fatcat is available at\n<https://api.qa.fatcat.wiki/v0>.\ + \ The database backing this instance is\nseparate from the production interface,\ + \ and is periodically rebuilt from\nsnapshots of the full production database,\ + \ meaning that edits on the QA\nserver will *NOT* persist, and that semantics\ + \ like the changelog index\nmonotonically increasing *MAY* be broken. Developers\ + \ are expexcted to test\ntheir scripts and tools against the QA instance before\ + \ running against\nproduction.\n\nFatcat is made available as a gratis (no cost)\ + \ and libre (freedom\npreserving) service to the public, with limited funding\ + \ and resources. We\nwelcome new and unforseen uses and contributions, but may\ + \ need to impose\nrestrictions (like rate-limits) to keep the service functional\ + \ for other\nusers, and in extreme cases reserve the option to block accounts\ + \ and IP\nranges if necessary to keep the service operational.\n\nThe Internet\ + \ Archive owns and operates it's own server equipment and data\ncenters, and operations\ + \ are optimized for low-cost, not high-availability.\nUsers and partners should\ + \ expect some downtime on the fatcat API, on the\norder of hours a month.\n\n\ + Periodic metadata exports are available for batch processing, and database\nsnapshots\ + \ can be used to create locally-hosted mirrors of the service for\nmore intensive\ + \ and reliable querying.\n\n### Other Nitty Gritties\n\nCross-origin requests\ + \ are allowed for the API service, to enable third\nparties to bulid in-browser\ + \ applications.\n\nA metadata search service is available at <https://search.fatcat.wiki>\ + \ (and\n<https://search.qa.fatcat.wiki>). The API is currently the raw\nelasticsearch\ + \ API, with only GET (read) requests allowed. This public\nservice is experimental\ + \ and may be removed or limited in the future.\n\n## Authentication\n\nThe API\ + \ allows basic read-only \"GET\" HTTP requests with no authentication.\nProposing\ + \ changes to the metadata, or other mutating requests (\"PUT\",\n\"POST\", \"\ + DELETE\") all require authentication, and some operations require\nadditional\ + \ account permissions.\n\nEnd-user account creation and login happens through\ + \ the web interface. From\na logged-in editor profile page, you can generate a\ + \ API token. Tokens are\n\"macaroons\", similar to JWT tokens, and are used for\ + \ all API\nauthentication. The web interface includes macaroons in browser cookies\ + \ and\npasses them through to the API to authenticate editor actions.\n\n<!--\ + \ ReDoc-Inject: <security-definitions> -->\n<!-- ENDLONGDESCRIPTION -->\n" version: "0.3.0" title: "fatcat" + termsOfService: "https://guide.fatcat.wiki/policies.html" + contact: + name: "Internet Archive Web Group" + url: "https://fatcat.wiki" + email: "webservices@archive.org" + x-logo: + url: "https://fatcat.wiki/static/paper_man_confused.gif" + altText: "Confused Papers Man (Logo)" + backgroundColor: "#FFFFFF" host: "api.fatcat.wiki" basePath: "/v0" tags: - name: "containers" + description: "**Container** entities represent publication venues like journals,\ + \ # TAGLINE\nconference proceedings, book series, or blogs. They group publications\ + \ # TAGLINE\n(\"releases\"). # TAGLINE\n\nSee the \"Catalog Style Guide\" section\ + \ of the guide for details and # TAGLINE\nsemantics of what should be included\ + \ in specific entity fields. # TAGLINE\nSpecifically, the # TAGLINE\n[Container\ + \ Entity Reference](https://guide.fatcat.wiki/entity_container.html). # TAGLINE\n" + x-displayName: "Containers" - name: "creators" + description: "**Creator** entities represent individuals (or organizations, or other\ + \ # TAGLINE\nagents) who contribute to the creation of specific releases # TAGLINE\n\ + (publications). # TAGLINE\n\nSee the \"Catalog Style Guide\" section of the guide\ + \ for details and # TAGLINE\nsemantics of what should be included in specific\ + \ entity fields. # TAGLINE\nSpecifically, the # TAGLINE\n[Creator Entity Reference](https://guide.fatcat.wiki/entity_creator.html).\ + \ # TAGLINE\n" + x-displayName: "Creators" - name: "files" + description: "**File** entities represent unique digital files which are full #\ + \ TAGLINE\nmanifestations of specific releases (publications), such as fulltext\ + \ PDF # TAGLINE\nfiles, JATS XML documents, or video files. File entities also\ + \ include a # TAGLINE\nset of locations where they can be found on the public\ + \ web. # TAGLINE\n\nSee the \"Catalog Style Guide\" section of the guide for\ + \ details and # TAGLINE\nsemantics of what should be included in specific entity\ + \ fields. # TAGLINE\nSpecifically, the # TAGLINE\n[File Entity Reference](https://guide.fatcat.wiki/entity_file.html).\ + \ # TAGLINE\n" + x-displayName: "Files" - name: "filesets" + description: "**Fileset** entities represent sets of digital files, as well as locations\ + \ # TAGLINE\nwhere they can be found on the public web. Filesets most commonly\ + \ # TAGLINE\nrepresent datasets consisting of serveral data and metadata files.\ + \ # TAGLINE\n\nSee the \"Catalog Style Guide\" section of the guide for details\ + \ and # TAGLINE\nsemantics of what should be included in specific entity fields.\ + \ # TAGLINE\nSpecifically, the # TAGLINE\n[Fileset Entity Reference](https://guide.fatcat.wiki/entity_fileset.html).\ + \ # TAGLINE\n" + x-displayName: "Filesets" - name: "webcaptures" + description: "**Web Capture** entities represent archival snapshots of web pages\ + \ (or # TAGLINE\nother web resources), which are usually complete manifestations\ + \ of a # TAGLINE\nspecific release entity. Web Captures also include a set of\ + \ locations # TAGLINE\n(wayback replay instances or WARC files) where the capture\ + \ can be found. # TAGLINE\n\nSee the \"Catalog Style Guide\" section of the guide\ + \ for details and # TAGLINE\nsemantics of what should be included in specific\ + \ entity fields. # TAGLINE\nSpecifically, the # TAGLINE\n[Web Capture Entity\ + \ Reference](https://guide.fatcat.wiki/entity_webcapture.html). # TAGLINE\n" + x-displayName: "Webcaptures" - name: "releases" + description: "**Release** entities represent specific published versions of a research\ + \ # TAGLINE\nwork, such as a pre-print, a journal article, a book (or chapter),\ + \ or a # TAGLINE\nscholarly blog post. Releases are always grouped together under\ + \ Works; # TAGLINE\nthey may be published in a specific Container; they may have\ + \ known # TAGLINE\nCreators; and there may exist known File/Fileset/WebCapture\ + \ digital copies # TAGLINE\nof the release. # TAGLINE\n\nSee the \"Catalog Style\ + \ Guide\" section of the guide for details and # TAGLINE\nsemantics of what should\ + \ be included in specific entity fields. # TAGLINE\nSpecifically, the # TAGLINE\n\ + [Release Entity Reference](https://guide.fatcat.wiki/entity_release.html). #\ + \ TAGLINE\n" + x-displayName: "Releases" - name: "works" -- name: "edit-lifecycle" + description: "**Work** entities group several Release entities which are different\ + \ # TAGLINE\nversions of the same abstract piece of research. For example, three\ + \ # TAGLINE\nrelease entities representing the pre-print, published article,\ + \ and # TAGLINE\nretraction stages of the same journal paper would be grouped\ + \ under a # TAGLINE\nsingle work. # TAGLINE\n\nSee the \"Catalog Style Guide\"\ + \ section of the guide for details and # TAGLINE\nsemantics of what should be\ + \ included in specific entity fields. # TAGLINE\nSpecifically, the # TAGLINE\n\ + [Work Entity Reference](https://guide.fatcat.wiki/entity_work.html). # TAGLINE\n" + x-displayName: "Works" +- name: "editgroups" + description: "**Editgroups** are sets of changes, each to individual entities in\ + \ the # TAGLINE\ncatalog. Every edit must be part of an editgroup which is reviewed\ + \ and # TAGLINE\naccepted (merged) as a whole. # TAGLINE\n" + x-displayName: "Editgroups" +- name: "editors" + description: "**Editors** are human user accounts and bots that make changes to\ + \ the # TAGLINE\nFatcat catalog. # TAGLINE\n\nThe API allows fetching (and updating)\ + \ metadata about individual editors, # TAGLINE\nas well as fetching editor's\ + \ annotation and edit history. # TAGLINE\n" + x-displayName: "Editors" +- name: "changelog" + description: "The **Changelog** is the ordered feed of editgroups which have been\ + \ # TAGLINE\naccepted into the catalog. # TAGLINE\n" + x-displayName: "Changelog" +- name: "auth" + description: "Helper methods and internal APIs for editor authentication. # TAGLINE\n" + x-displayName: "Auth Methods" schemes: - "https" consumes: @@ -27,6 +152,9 @@ paths: post: tags: - "containers" + description: "Create a single Container entity as part of an existing editgroup.\n\ + \nEditgroup must be mutable (aka, not accepted) and editor must have\npermission\ + \ (aka, have created the editgrou p or have `admin` role).\n" operationId: "create_container" parameters: - name: "editgroup_id" @@ -117,6 +245,12 @@ paths: post: tags: - "containers" + description: "Create a set of Container entities as part of a new editgroup,\ + \ and\naccept that editgroup in the same atomic request.\n\nThis method is\ + \ mostly useful for bulk import of new entities by\ncarefully written bots.\ + \ This method is more efficient than creating an\neditgroup, several entities,\ + \ then accepting the editgroup, both in\nterms of API requests required and\ + \ database load. Requires `admin`\nrole.\n" operationId: "create_container_auto_batch" parameters: - in: "body" @@ -201,6 +335,7 @@ paths: get: tags: - "containers" + description: "Fetches a single container entity from the catalog.\n" operationId: "get_container" parameters: - name: "ident" @@ -271,6 +406,13 @@ paths: put: tags: - "containers" + description: "Updates an existing entity as part of a specific (existing) editgroup.\n\ + The editgroup must be open for updates (aka, not accepted/merged), and\nthe\ + \ editor making the requiest must have permissions (aka, must have\ncreated\ + \ the editgroup or have `admin` role).\n\nThis method can also be used to\ + \ update an existing entity edit as part\nof an editgroup. For example, if\ + \ an entity was created in this\neditgroup, an editor could make changes to\ + \ the new entity's metadata\nbefore merging.\n" operationId: "update_container" parameters: - name: "editgroup_id" @@ -366,6 +508,9 @@ paths: delete: tags: - "containers" + description: "Creates a new \"deletion\" edit for a specific entity as part\ + \ of an\nexisting editgroup.\n\nThis is not the method to use to remove an\ + \ edit from an editgroup; for\nthat use `delete_container_edit`.\n" operationId: "delete_container" parameters: - name: "editgroup_id" @@ -449,6 +594,11 @@ paths: get: tags: - "containers" + description: "Fetches a specific entity revision. Note that the returned revision\n\ + will not be associated with any particular fatcat identifier (even if\none\ + \ or more identifiers do currently point to this revision). The\nrevision\ + \ may even be part of an un-merged editgroup.\n\nRevisions are immutable and\ + \ can not be deleted or updated.\n" operationId: "get_container_revision" parameters: - name: "rev_id" @@ -463,16 +613,14 @@ paths: example: "\"rev_id_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For containers,\ - \ none accepted (yet)." + description: "List of sub-entities to expand in response. See `get_container`." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For containers,\ - \ none accepted (yet)." + description: "List of entity fields to elide in response. See `get_container`." required: false type: "string" formatString: "{:?}" @@ -523,6 +671,8 @@ paths: get: tags: - "containers" + description: "Fetches the history of accepted edits (changelog entries) for\ + \ a\nspecific entity fatcat identifier.\n" operationId: "get_container_history" parameters: - name: "ident" @@ -533,6 +683,7 @@ paths: example: "\"ident_example\".to_string()" - name: "limit" in: "query" + description: "Maximum number of changelog entries to return" required: false type: "integer" format: "int64" @@ -586,6 +737,8 @@ paths: get: tags: - "containers" + description: "Returns the set of entity identifiers which currently redirect\ + \ to this\nidentifier.\n" operationId: "get_container_redirects" parameters: - name: "ident" @@ -601,7 +754,6 @@ paths: type: "array" items: type: "string" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" description: "base32-encoded unique identifier" minLength: 26 maxLength: 26 @@ -647,6 +799,11 @@ paths: get: tags: - "containers" + description: "Looks for an active entity with the given external identifier.\ + \ If any\nsuch entity is found, returns a single complete entity. If multiple\n\ + entities have the same external identifier, this is considered a soft\ncatalog\ + \ error, and the behavior of which entity is returned is\nundefined.\n\nOne\ + \ (and only one) external identifier should be specified per request.\n" operationId: "lookup_container" parameters: - name: "issnl" @@ -661,19 +818,19 @@ paths: - name: "wikidata_qid" in: "query" required: false + type: "string" formatString: "{:?}" example: "Some(\"wikidata_qid_example\".to_string())" - name: "expand" in: "query" - description: "List of sub-entities to expand in response." + description: "List of sub-entities to expand in response. See `get_container`." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For container, none\ - \ accepted (yet)." + description: "List of entity fields to elide in response. See `get_container`." required: false type: "string" formatString: "{:?}" @@ -724,6 +881,8 @@ paths: get: tags: - "containers" + description: "Returns the entity edit object with the given identifier. This\ + \ method\nis expected to be used rarely.\n" operationId: "get_container_edit" parameters: - name: "edit_id" @@ -782,6 +941,11 @@ paths: delete: tags: - "containers" + description: "Removes a single edit from the specified editgroup. The editgroup\ + \ must\nbe mutable (aka, not accepted/merged), and the editor making this\n\ + request must have permission (aka, have created the editgroup or hold\nthe\ + \ `admin` role).\n\nNot to be confused with the `delete_container` method,\ + \ which *creates*\na new edit in the given editgroup.\n" operationId: "delete_container_edit" parameters: - name: "editgroup_id" @@ -1061,8 +1225,8 @@ paths: example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For containers,\ - \ none accepted (yet)." + description: "List of entity fields to elide in response. For creators, none\ + \ accepted (yet)." required: false type: "string" formatString: "{:?}" @@ -1305,16 +1469,16 @@ paths: example: "\"rev_id_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For creators, none\ - \ accepted (yet)." + description: "List of sub-entities to expand in response. See `get_creator`,\n\ + though note that identifier-based expansions (like `releases`) will\nalways\ + \ be empty for revisions.\n" required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For creators, none\ - \ accepted (yet)." + description: "List of entity fields to elide in response. See `get_creator`." required: false type: "string" formatString: "{:?}" @@ -1428,6 +1592,8 @@ paths: get: tags: - "creators" + description: "Returns the set of Release entities having a `contrib` entry pointing\n\ + to the creator entity.\n" operationId: "get_creator_releases" parameters: - name: "ident" @@ -1438,8 +1604,7 @@ paths: example: "\"ident_example\".to_string()" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For creators, none\ - \ implemented yet." + description: "List of entity fields to elide in response. See `get_release`." required: false type: "string" formatString: "{:?}" @@ -1507,7 +1672,6 @@ paths: type: "array" items: type: "string" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" description: "base32-encoded unique identifier" minLength: 26 maxLength: 26 @@ -1557,6 +1721,7 @@ paths: parameters: - name: "orcid" in: "query" + description: "ORCiD (https://orcid.org) identifier" required: false type: "string" maxLength: 19 @@ -1567,19 +1732,19 @@ paths: - name: "wikidata_qid" in: "query" required: false + type: "string" formatString: "{:?}" example: "Some(\"wikidata_qid_example\".to_string())" - name: "expand" in: "query" - description: "List of sub-entities to expand in response." + description: "List of sub-entities to expand in response. See `get_creator`." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For creator, none\ - \ accepted (yet)." + description: "List of entity fields to elide in response. See `get_creator`." required: false type: "string" formatString: "{:?}" @@ -2211,16 +2376,14 @@ paths: example: "\"rev_id_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For files, none\ - \ accepted (yet)." + description: "List of sub-entities to expand in response. See `get_file`." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For files, none\ - \ accepted (yet)." + description: "List of entity fields to elide in response. See `get_file`." required: false type: "string" formatString: "{:?}" @@ -2349,7 +2512,6 @@ paths: type: "array" items: type: "string" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" description: "base32-encoded unique identifier" minLength: 26 maxLength: 26 @@ -2399,6 +2561,7 @@ paths: parameters: - name: "md5" in: "query" + description: "MD5 hash of data, in hex encoding" required: false type: "string" maxLength: 32 @@ -2408,6 +2571,7 @@ paths: example: "Some(\"md5_example\".to_string())" - name: "sha1" in: "query" + description: "SHA-1 hash of data, in hex encoding" required: false type: "string" maxLength: 40 @@ -2417,6 +2581,7 @@ paths: example: "Some(\"sha1_example\".to_string())" - name: "sha256" in: "query" + description: "SHA-256 hash of data, in hex encoding" required: false type: "string" maxLength: 64 @@ -2426,15 +2591,14 @@ paths: example: "Some(\"sha256_example\".to_string())" - name: "expand" in: "query" - description: "List of sub-entities to expand in response." + description: "List of sub-entities to expand in response. See `get_file`." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For files, none\ - \ accepted (yet)." + description: "List of entity fields to elide in response. See `get_file`." required: false type: "string" formatString: "{:?}" @@ -3066,16 +3230,14 @@ paths: example: "\"rev_id_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For filesets, none\ - \ accepted (yet)." + description: "List of sub-entities to expand in response. See `get_fileset`." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For filesets, 'manifest'\ - \ is accepted." + description: "List of entity fields to elide in response. See `get_fileset`." required: false type: "string" formatString: "{:?}" @@ -3204,7 +3366,6 @@ paths: type: "array" items: type: "string" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" description: "base32-encoded unique identifier" minLength: 26 maxLength: 26 @@ -3831,16 +3992,14 @@ paths: example: "\"rev_id_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For webcaptures,\ - \ none accepted (yet)." + description: "List of sub-entities to expand in response. See `get_webcapture`." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For webcaptures,\ - \ 'cdx' is accepted." + description: "List of entity fields to elide in response. See `get_webcapture`." required: false type: "string" formatString: "{:?}" @@ -3969,7 +4128,6 @@ paths: type: "array" items: type: "string" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" description: "base32-encoded unique identifier" minLength: 26 maxLength: 26 @@ -4160,6 +4318,11 @@ paths: post: tags: - "releases" + description: "Create a single Release entity as part of an existing editgroup.\ + \ If the\n`work_id` field is not set, a work entity will be created automatically\n\ + and this field set pointing to the new work.\n\nEditgroup must be mutable\ + \ (aka, not accepted) and editor must have\npermission (aka, have created\ + \ the editgrou p or have `admin` role).\n" operationId: "create_release" parameters: - name: "editgroup_id" @@ -4250,6 +4413,12 @@ paths: post: tags: - "releases" + description: "Create a set of Release entities as part of a new editgroup, and\n\ + accept that editgroup in the same atomic request.\n\nThis method is mostly\ + \ useful for bulk import of new entities by\ncarefully written bots. This\ + \ method is more efficient than creating an\neditgroup, several entities,\ + \ then accepting the editgroup, both in\nterms of API requests required and\ + \ database load. Requires `admin`\nrole.\n" operationId: "create_release_auto_batch" parameters: - in: "body" @@ -4334,6 +4503,7 @@ paths: get: tags: - "releases" + description: "Fetches a single Release entity from the catalog.\n" operationId: "get_release" parameters: - name: "ident" @@ -4344,16 +4514,16 @@ paths: example: "\"ident_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For releases, 'files',\ - \ 'filesets, 'webcaptures', 'container', and 'creators' are valid." + description: "List of sub-entities to expand in response. For releases, 'files',\n\ + 'filesets, 'webcaptures', 'container', and 'creators' are valid.\n" required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For releases, 'abstracts',\ - \ 'refs', and 'contribs' are valid." + description: "List of entity fields to elide in response (for efficiency).\ + \ For\nreleases, 'abstracts', 'refs', and 'contribs' are valid.\n" required: false type: "string" formatString: "{:?}" @@ -4404,6 +4574,13 @@ paths: put: tags: - "releases" + description: "Updates an existing entity as part of a specific (existing) editgroup.\n\ + The editgroup must be open for updates (aka, not accepted/merged), and\nthe\ + \ editor making the requiest must have permissions (aka, must have\ncreated\ + \ the editgroup or have `admin` role).\n\nThis method can also be used to\ + \ update an existing entity edit as part\nof an editgroup. For example, if\ + \ an entity was created in this\neditgroup, an editor could make changes to\ + \ the new entity's metadata\nbefore merging.\n" operationId: "update_release" parameters: - name: "editgroup_id" @@ -4499,6 +4676,9 @@ paths: delete: tags: - "releases" + description: "Creates a new \"deletion\" edit for a specific entity as part\ + \ of an\nexisting editgroup.\n\nThis is not the method to use to remove an\ + \ edit from an editgroup; for\nthat use `delete_release_edit`.\n" operationId: "delete_release" parameters: - name: "editgroup_id" @@ -4582,6 +4762,11 @@ paths: get: tags: - "releases" + description: "Fetches a specific entity revision. Note that the returned revision\n\ + will not be associated with any particular fatcat identifier (even if\none\ + \ or more identifiers do currently point to this revision). The\nrevision\ + \ may even be part of an un-merged editgroup.\n\nRevisions are immutable and\ + \ can not be deleted or updated.\n" operationId: "get_release_revision" parameters: - name: "rev_id" @@ -4596,16 +4781,16 @@ paths: example: "\"rev_id_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For releases, none\ - \ accepted (yet)." + description: "List of sub-entities to expand in response. See `get_release`,\ + \ though note that identifier-based exapansions like `file` will always\ + \ be empty for revisions." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For releases, none\ - \ accepted (yet)." + description: "List of entity fields to elide in response. See `get_release`." required: false type: "string" formatString: "{:?}" @@ -4656,6 +4841,8 @@ paths: get: tags: - "releases" + description: "Fetches the history of accepted edits (changelog entries) for\ + \ a\nspecific entity fatcat identifier.\n" operationId: "get_release_history" parameters: - name: "ident" @@ -4719,6 +4906,8 @@ paths: get: tags: - "releases" + description: "Returns the set of File entities that have a `release_id` pointing\ + \ to\nthis release entity.\n" operationId: "get_release_files" parameters: - name: "ident" @@ -4729,8 +4918,7 @@ paths: example: "\"ident_example\".to_string()" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For files, none\ - \ accepted (yet)." + description: "List of entity fields to elide in response. See `get_file`." required: false type: "string" formatString: "{:?}" @@ -4783,6 +4971,8 @@ paths: get: tags: - "releases" + description: "Returns the set of Fileset entities that have a `release_id` pointing\ + \ to\nthis release entity.\n" operationId: "get_release_filesets" parameters: - name: "ident" @@ -4793,8 +4983,7 @@ paths: example: "\"ident_example\".to_string()" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For filesets, 'manifest'\ - \ is valid." + description: "List of entity fields to elide in response. See `get_fileset`." required: false type: "string" formatString: "{:?}" @@ -4847,6 +5036,8 @@ paths: get: tags: - "releases" + description: "Returns the set of Web Capture entities that have a `release_id`\n\ + pointing to this release entity.\n" operationId: "get_release_webcaptures" parameters: - name: "ident" @@ -4857,8 +5048,7 @@ paths: example: "\"ident_example\".to_string()" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For webcaptures,\ - \ 'cdx' is valid." + description: "List of entity fields to elide in response. See `get_webcapture`." required: false type: "string" formatString: "{:?}" @@ -4911,6 +5101,8 @@ paths: get: tags: - "releases" + description: "Returns the set of entity identifiers which currently redirect\ + \ to this\nidentifier.\n" operationId: "get_release_redirects" parameters: - name: "ident" @@ -4926,7 +5118,6 @@ paths: type: "array" items: type: "string" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" description: "base32-encoded unique identifier" minLength: 26 maxLength: 26 @@ -4972,6 +5163,11 @@ paths: get: tags: - "releases" + description: "Looks for an active entity with the given external identifier.\ + \ If any\nsuch entity is found, returns a single complete entity. If multiple\n\ + entities have the same external identifier, this is considered a soft\ncatalog\ + \ error, and the behavior of which entity is returned is\nundefined.\n\nOne\ + \ (and only one) external identifier should be specified per request.\n" operationId: "lookup_release" parameters: - name: "doi" @@ -5036,15 +5232,14 @@ paths: example: "Some(\"mag_example\".to_string())" - name: "expand" in: "query" - description: "List of sub-entities to expand in response." + description: "List of sub-entities to expand in response. See `get_release`." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of sub-entities to expand in response. For releases, 'files',\ - \ 'filesets, 'webcaptures', 'container', and 'creators' are valid." + description: "List of sub-entities to elide in response. See `get_release`." required: false type: "string" formatString: "{:?}" @@ -5095,6 +5290,8 @@ paths: get: tags: - "releases" + description: "Returns the entity edit object with the given identifier. This\ + \ method\nis expected to be used rarely.\n" operationId: "get_release_edit" parameters: - name: "edit_id" @@ -5153,6 +5350,11 @@ paths: delete: tags: - "releases" + description: "Removes a single edit from the specified editgroup. The editgroup\ + \ must\nbe mutable (aka, not accepted/merged), and the editor making this\n\ + request must have permission (aka, have created the editgroup or hold\nthe\ + \ `admin` role).\n\nNot to be confused with the `delete_container` method,\ + \ which *creates*\na new edit in the given editgroup.\n" operationId: "delete_release_edit" parameters: - name: "editgroup_id" @@ -5239,7 +5441,7 @@ paths: /editgroup/{editgroup_id}/work: post: tags: - - "releases" + - "works" operationId: "create_work" parameters: - name: "editgroup_id" @@ -5676,16 +5878,16 @@ paths: example: "\"rev_id_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For works, none\ - \ accepted (yet)." + description: "List of sub-entities to expand in response. See `get_work`,\ + \ though note that identifier-based expansions like `releases` will always\ + \ be empty for revisions." required: false type: "string" formatString: "{:?}" example: "Some(\"expand_example\".to_string())" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For works, none\ - \ accepted (yet)." + description: "List of entity fields to elide in response. See `get_work`." required: false type: "string" formatString: "{:?}" @@ -5814,7 +6016,6 @@ paths: type: "array" items: type: "string" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" description: "base32-encoded unique identifier" minLength: 26 maxLength: 26 @@ -5860,6 +6061,8 @@ paths: get: tags: - "works" + description: "Returns the set of release entities that are part of this work\ + \ (aka,\nhave `work_id` pointing to this work entity).\n" operationId: "get_work_releases" parameters: - name: "ident" @@ -5870,8 +6073,7 @@ paths: example: "\"ident_example\".to_string()" - name: "hide" in: "query" - description: "List of entity fields to elide in response. For works, none\ - \ implemented yet." + description: "List of entity fields to elide in response. See `get_release`." required: false type: "string" formatString: "{:?}" @@ -6067,6 +6269,10 @@ paths: httpmethod: "delete" /editor/{editor_id}: get: + tags: + - "editors" + description: "Returns an editor object, including metadata such as the username,\n\ + type, and role of editor.\n" operationId: "get_editor" parameters: - name: "editor_id" @@ -6118,6 +6324,12 @@ paths: HttpMethod: "Get" httpmethod: "get" put: + tags: + - "editors" + description: "Allows metadata changes to some editor fields, such as the username.\n\ + \nChanges require authentication and permissions. An editor can change\ntheir\ + \ own username; changes to role flags require the `admin` role by\nthe editor\ + \ making the request.\n" operationId: "update_editor" parameters: - name: "editor_id" @@ -6206,6 +6418,10 @@ paths: noClientExample: true /editor/{editor_id}/editgroups: get: + tags: + - "editors" + description: "Returns a set of editgroups created by the given editor, regardless\ + \ of\nthe status (accepted/submitted) of the editgroups.\n" operationId: "get_editor_editgroups" parameters: - name: "editor_id" @@ -6223,6 +6439,9 @@ paths: example: "Some(789)" - name: "before" in: "query" + description: "Return only editgroups created *before* the given timestamp\ + \ (not\ninclusive). Editgroups will be sorted by creation time in\ndescending\ + \ order (most recent first). For use in pagination.\n" required: false type: "string" format: "date-time" @@ -6230,6 +6449,9 @@ paths: example: "None" - name: "since" in: "query" + description: "Return only editgroups created *after* the given timestamp (not\n\ + inclusive). Editgroups will be sorted by creation time in ascending\norder\ + \ (most recent last). For use in pagination.\n" required: false type: "string" format: "date-time" @@ -6282,7 +6504,8 @@ paths: /editor/{editor_id}/annotations: get: tags: - - "edit-lifecycle" + - "editors" + description: "Fetches a list of annotations made by a particular editor.\n" operationId: "get_editor_annotations" parameters: - name: "editor_id" @@ -6297,6 +6520,7 @@ paths: example: "\"editor_id_example\".to_string()" - name: "limit" in: "query" + description: "Maximum number (count) of annotations to return in response" required: false type: "integer" format: "int64" @@ -6304,6 +6528,9 @@ paths: example: "Some(789)" - name: "before" in: "query" + description: "Return only annotations made *before* the given timestamp (not\n\ + inclusive). Annotations will be sorted by creation time in\ndescending order\ + \ (most recent first). For use in pagination.\n" required: false type: "string" format: "date-time" @@ -6311,6 +6538,9 @@ paths: example: "None" - name: "since" in: "query" + description: "Return only annotations made *after* the given timestamp (not\n\ + inclusive). Annotations will be sorted by creation time in\nascending order\ + \ (most recent last). For use in pagination.\n" required: false type: "string" format: "date-time" @@ -6384,7 +6614,9 @@ paths: /editgroup: post: tags: - - "edit-lifecycle" + - "editgroups" + description: "Creates a new editgroup. By default the editor making this request\ + \ will\nbe the author of the editgroup.\n" operationId: "create_editgroup" parameters: - in: "body" @@ -6468,7 +6700,11 @@ paths: /editgroup/{editgroup_id}: get: tags: - - "edit-lifecycle" + - "editgroups" + description: "Returns a single editgroup object.\n\nUnlike some similar methods,\ + \ this method will return a full/expanded\neditgroup object, which includes\ + \ edit lists of each entity type (though\nwill not include the complete entity\ + \ objects).\n" operationId: "get_editgroup" parameters: - name: "editgroup_id" @@ -6524,6 +6760,12 @@ paths: HttpMethod: "Get" httpmethod: "get" put: + tags: + - "editgroups" + description: "Updates metadata for a single editgroup object. Note that only\ + \ metadata\nfields such as the `description` or `extra` metadata can be changed\n\ + with this method; it does not allow adding or removing edits to the\neditgroup\ + \ (for that use the individual entity create/update/delete\nmethods).\n" operationId: "update_editgroup" parameters: - name: "editgroup_id" @@ -6623,7 +6865,10 @@ paths: /editgroup/{editgroup_id}/accept: post: tags: - - "edit-lifecycle" + - "editgroups" + description: "Accept (\"merge\") the given editgroup into the catalog. The editgroup\n\ + must be open (not already accepted), and the editor making this request\n\ + must have the `admin` role.\n" operationId: "accept_editgroup" parameters: - name: "editgroup_id" @@ -6713,7 +6958,8 @@ paths: /editgroup/{editgroup_id}/annotations: get: tags: - - "edit-lifecycle" + - "editgroups" + description: "Returns a list of annotations made to a specific editgroup." operationId: "get_editgroup_annotations" parameters: - name: "editgroup_id" @@ -6728,7 +6974,7 @@ paths: example: "\"editgroup_id_example\".to_string()" - name: "expand" in: "query" - description: "List of sub-entities to expand in response. For editgroups:\ + description: "List of sub-entities to expand in response. For editgroup annotations:\ \ 'editors'" required: false type: "string" @@ -6802,7 +7048,10 @@ paths: /editgroup/{editgroup_id}/annotation: post: tags: - - "edit-lifecycle" + - "editgroups" + description: "Submits a new annotation to the specified editgroup.\n\nThe editgroup\ + \ must be open (not already accepted). The annotation will\nautomatically\ + \ have authorship of the editor making this request.\n" operationId: "create_editgroup_annotation" parameters: - name: "editgroup_id" @@ -6895,6 +7144,11 @@ paths: noClientExample: true /editgroup/reviewable: get: + tags: + - "editgroups" + description: "Returns a set of editgroups which have been submitted but not\ + \ yet accepted.\n\nQuery parameters can be used to sort and paginate the list\ + \ returned.\n" operationId: "get_editgroups_reviewable" parameters: - name: "expand" @@ -6907,6 +7161,7 @@ paths: example: "Some(\"expand_example\".to_string())" - name: "limit" in: "query" + description: "Maximum number of reviewable editgroups to return in response" required: false type: "integer" format: "int64" @@ -6914,6 +7169,9 @@ paths: example: "Some(789)" - name: "before" in: "query" + description: "Return only reviewable editgroups submitted *before* the given\n\ + timestamp (not inclusive). Editgroups will be sorted by submission\ntime\ + \ in descending order (most recent first). For use in pagination.\n" required: false type: "string" format: "date-time" @@ -6921,6 +7179,9 @@ paths: example: "None" - name: "since" in: "query" + description: "Return only reviewable editgroups submitted *after* the given\n\ + timestamp (not inclusive). Editgroups will be sorted by submission\ntime\ + \ in ascending order (most recent last). For use in pagination.\n" required: false type: "string" format: "date-time" @@ -6973,11 +7234,22 @@ paths: /changelog: get: tags: - - "edit-lifecycle" + - "changelog" + description: "Returns a list of the most recent changelog entries accepted (merged)\n\ + into the catalog.\n\nList is sorted by changelog index in descending order.\ + \ Note that the\naccepted timestamp roughly corresponds to order, but not\ + \ strictly;\nthere exist out-of-order timestamps on the order of several seconds.\n\ + \nAs a known database issue, it is technically possible for there to be a\n\ + gap in changelog index numbers (aka, a missing changelog entry). There\nare\ + \ no currently known gaps and this is considered a bug that will be\naddressed.\n\ + \nThere are millions of entries; to paginate through all of them, use\nthis\ + \ method to discover the highest existing entry number, then request\nthe\ + \ entries using `get_changelog_entry` one at a time.\n" operationId: "get_changelog" parameters: - name: "limit" in: "query" + description: "Maximum count of changelog entries to return in response" required: false type: "integer" format: "int64" @@ -7021,11 +7293,16 @@ paths: /changelog/{index}: get: tags: - - "edit-lifecycle" + - "changelog" + description: "Returns a single changelog entry.\n\nAs a known database issue,\ + \ it is technically possible for there to be a\ngap in changelog index numbers\ + \ (aka, a missing changelog entry). There\nare no currently known gaps and\ + \ this is considered a bug that will be\naddressed.\n" operationId: "get_changelog_entry" parameters: - name: "index" in: "path" + description: "Changelog index of entry to return" required: true type: "integer" format: "int64" @@ -7075,6 +7352,15 @@ paths: httpmethod: "get" /auth/oidc: post: + tags: + - "auth" + description: "Login or create editor account using OIDC metadata (internal method).\n\ + \nThis method is used by privileged front-end tools (like the web\ninterface\ + \ service) to process editor logins using OpenID Connect (OIDC)\nand/or OAuth.\ + \ Most accounts (including tool and bot accounts) do not\nhave sufficient\ + \ privileges to call this method, which requires the\n`admin` role.\n\nThe\ + \ method returns an API token; the HTTP status code indicates whether\nan\ + \ existing account was logged in, or a new account was created.\n" operationId: "auth_oidc" parameters: - in: "body" @@ -7166,6 +7452,11 @@ paths: noClientExample: true /auth/check: get: + tags: + - "auth" + description: "Verify that authentication (API token) is working as expected.\ + \ The\noptional `role` parameter can be used to verify that the current\n\ + account (editor) has permissions for the given role.\n" operationId: "auth_check" parameters: - name: "role" @@ -7232,6 +7523,18 @@ paths: httpmethod: "get" securityDefinitions: Bearer: + description: "The only current API authentication mechanism is HTTP bearer\nauthentication\ + \ using the `Authorization` HTTP header. The header should\nbe formatted as\ + \ the string \"Bearer\", then a space, then API token (in the\nusual base64\ + \ string encoding).\n\nAn example HTTP request would look on the wire like:\n\ + \n GET /v0/auth/check HTTP/1.1\n Accept: */*\n Accept-Encoding: gzip,\ + \ deflate\n Authorization: Bearer AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=\n\ + \ Connection: keep-alive\n Host: api.qa.fatcat.wiki\n User-Agent: HTTPie/0.9.8\n\ + \nHeaders can be passed on the command line using `http` (HTTPie) like:\n\n\ + \ http get https://api.qa.fatcat.wiki/v0/auth/check Authorization:\"Bearer\ + \ AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=\"\ + \n\nOr with `curl`:\n\n curl -H \"Authorization: Bearer AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=\"\ + \ https://qa.fatcat.wiki/v0/auth/check\n" type: "apiKey" name: "Authorization" in: "header" @@ -7245,8 +7548,10 @@ definitions: properties: success: type: "boolean" + example: false error: type: "string" + example: "unexpected-thing" message: type: "string" example: "A really confusing, totally unexpected thing happened" @@ -7259,6 +7564,7 @@ definitions: properties: success: type: "boolean" + example: true message: type: "string" example: "The computers did the thing successfully!" @@ -7271,26 +7577,38 @@ definitions: properties: wikidata_qid: type: "string" + example: "Q42812" issnl: type: "string" example: "1234-5678" + description: "Linking ISSN number (ISSN-L). Should be valid and registered\ + \ with issn.org" minLength: 9 maxLength: 9 pattern: "\\d{4}-\\d{3}[0-9X]" publisher: type: "string" example: "Society of Curious Students" + description: "Name of the organization or entity responsible for publication.\ + \ Not\nthe complete imprint/brand.\n" container_type: type: "string" - description: "Eg, 'journal'" + example: "journal" + description: "Type of container, eg 'journal' or 'proceedings'. See Guide\ + \ for list of valid types." name: type: "string" example: "Journal of Important Results" - description: "Required for valid entities" + description: "Name of the container (eg, Journal title). Required for entity\ + \ creation." edit_extra: type: "object" + description: "Free-form JSON metadata that will be stored with specific entity\ + \ edits\n(eg, creation/update/delete).\n" extra: type: "object" + description: "Free-form JSON metadata that will be stored with the other entity\n\ + metadata. See guide for (unenforced) schema conventions.\n" redirect: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7314,6 +7632,7 @@ definitions: pattern: "[a-zA-Z2-7]{26}" state: type: "string" + example: "active" enum: - "wip" - "active" @@ -7323,12 +7642,12 @@ definitions: redirect: "q3nouwy3nnbsvo3h5klxsx4a7y" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - container_type: "container_type" + container_type: "journal" name: "Journal of Important Results" publisher: "Society of Curious Students" issnl: "1234-5678" - wikidata_qid: "wikidata_qid" - state: "wip" + wikidata_qid: "Q42812" + state: "active" edit_extra: "{}" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" upperCaseName: "CONTAINER_ENTITY" @@ -7337,22 +7656,31 @@ definitions: properties: wikidata_qid: type: "string" + example: "Q42812" + description: "Wikidata entity QID" orcid: type: "string" example: "0000-0002-1825-0097" + description: "ORCiD (https://orcid.org) identifier" minLength: 19 maxLength: 19 pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]" surname: type: "string" + description: "In English commonly the last, or family name, but ordering is\ + \ context\nand culture specific.\n" given_name: type: "string" + description: "In English commonly the first name, but ordering is context\ + \ and\nculture specific.\n" display_name: type: "string" example: "Grace Hopper" - description: "Required for valid entities" + description: "Name as should be displayed in web interface or in author lists\ + \ (not\nindex/sorted). Required for valid entities.\n" state: type: "string" + example: "active" enum: - "wip" - "active" @@ -7381,16 +7709,20 @@ definitions: pattern: "[a-zA-Z2-7]{26}" extra: type: "object" + description: "Free-form JSON metadata that will be stored with the other entity\n\ + metadata. See guide for (unenforced) schema conventions.\n" edit_extra: type: "object" + description: "Free-form JSON metadata that will be stored with specific entity\ + \ edits\n(eg, creation/update/delete).\n" example: redirect: "q3nouwy3nnbsvo3h5klxsx4a7y" surname: "surname" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" orcid: "0000-0002-1825-0097" - wikidata_qid: "wikidata_qid" - state: "wip" + wikidata_qid: "Q42812" + state: "active" given_name: "given_name" display_name: "Grace Hopper" edit_extra: "{}" @@ -7401,11 +7733,15 @@ definitions: properties: releases: type: "array" - description: "Optional; GET-only" + description: "Full release entities, included in GET responses when `releases`\n\ + included in `expand` parameter. Ignored if included in PUT or POST\nrequests.\n" items: $ref: "#/definitions/release_entity" release_ids: type: "array" + description: "Set of identifier of release entities this file represents a\ + \ full\nmanifestation of. Usually a single release, but some files contain\n\ + content of multiple full releases (eg, an issue of a journal).\n" items: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7423,18 +7759,21 @@ definitions: sha256: type: "string" example: "cb1c378f464d5935ddaa8de28446d82638396c61f042295d7fb85e3cccc9e452" + description: "SHA-256 hash of data, in hex encoding" minLength: 64 maxLength: 64 pattern: "[a-f0-9]{64}" sha1: type: "string" example: "e9dd75237c94b209dc3ccd52722de6931a310ba3" + description: "SHA-1 hash of data, in hex encoding" minLength: 40 maxLength: 40 pattern: "[a-f0-9]{40}" md5: type: "string" example: "1b39813549077b2347c0f370c3864b40" + description: "MD5 hash of data, in hex encoding" minLength: 32 maxLength: 32 pattern: "[a-f0-9]{32}" @@ -7442,10 +7781,15 @@ definitions: type: "integer" format: "int64" example: 1048576 + description: "Size of file in bytes. Non-zero." edit_extra: type: "object" + description: "Free-form JSON metadata that will be stored with specific entity\ + \ edits\n(eg, creation/update/delete).\n" extra: type: "object" + description: "Free-form JSON metadata that will be stored with the other entity\n\ + metadata. See guide for (unenforced) schema conventions.\n" redirect: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7469,6 +7813,7 @@ definitions: pattern: "[a-zA-Z2-7]{26}" state: type: "string" + example: "active" enum: - "wip" - "active" @@ -7484,14 +7829,14 @@ definitions: revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" sha1: "e9dd75237c94b209dc3ccd52722de6931a310ba3" urls: - - rel: "webarchive" + - rel: "web" url: "https://example.edu/~frau/prcding.pdf" - - rel: "webarchive" + - rel: "web" url: "https://example.edu/~frau/prcding.pdf" size: 1048576 extra: "{}" mimetype: "application/pdf" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7508,11 +7853,15 @@ definitions: type: "string" format: "url" example: "https://example.edu/~frau/prcding.pdf" + description: "URL/URI pointing directly to a machine retrievable copy of this\ + \ exact\nfile.\n" rel: type: "string" - example: "webarchive" + example: "web" + description: "Indicates type of host this URL points to. Eg, \"publisher\"\ + ,\n\"repository\", \"webarchive\". See guide for list of acceptable values.\n" example: - rel: "webarchive" + rel: "web" url: "https://example.edu/~frau/prcding.pdf" upperCaseName: "FILE_URL" fileset_entity: @@ -7520,11 +7869,14 @@ definitions: properties: releases: type: "array" - description: "Optional; GET-only" + description: "Full release entities, included in GET responses when `releases`\n\ + included in `expand` parameter. Ignored if included in PUT or POST\nrequests.\n" items: $ref: "#/definitions/release_entity" release_ids: type: "array" + description: "Set of identifier of release entities this fileset represents\ + \ a full\nmanifestation of. Usually a single release.\n" items: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7542,6 +7894,7 @@ definitions: $ref: "#/definitions/fileset_file" state: type: "string" + example: "active" enum: - "wip" - "active" @@ -7570,8 +7923,12 @@ definitions: pattern: "[a-zA-Z2-7]{26}" extra: type: "object" + description: "Free-form JSON metadata that will be stored with the other entity\n\ + metadata. See guide for (unenforced) schema conventions.\n" edit_extra: type: "object" + description: "Free-form JSON metadata that will be stored with specific entity\ + \ edits\n(eg, creation/update/delete).\n" example: redirect: "q3nouwy3nnbsvo3h5klxsx4a7y" urls: @@ -7594,7 +7951,7 @@ definitions: md5: "1b39813549077b2347c0f370c3864b40" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7617,6 +7974,8 @@ definitions: rel: type: "string" example: "webarchive" + description: "Indicates type of host this URL points to. See guide for list\ + \ of\nacceptable values.\n" example: rel: "webarchive" url: "https://example.edu/~frau/prcding.pdf" @@ -7630,30 +7989,38 @@ definitions: path: type: "string" example: "img/cat.png" + description: "Path name of file within this fileset (eg, directory)\n" size: type: "integer" format: "int64" example: 1048576 + description: "File size in bytes" md5: type: "string" example: "1b39813549077b2347c0f370c3864b40" + description: "MD5 hash of data, in hex encoding" minLength: 32 maxLength: 32 pattern: "[a-f0-9]{32}" sha1: type: "string" example: "e9dd75237c94b209dc3ccd52722de6931a310ba3" + description: "SHA-1 hash of data, in hex encoding" minLength: 40 maxLength: 40 pattern: "[a-f0-9]{40}" sha256: type: "string" example: "cb1c378f464d5935ddaa8de28446d82638396c61f042295d7fb85e3cccc9e452" + description: "SHA-256 hash of data, in hex encoding" minLength: 64 maxLength: 64 pattern: "[a-f0-9]{64}" extra: type: "object" + description: "Free-form additional metadata about this specific file in the\ + \ set.\nEg, `mimetype`. See guide for nomative (but unenforced) schema\n\ + fields.\n" example: sha1: "e9dd75237c94b209dc3ccd52722de6931a310ba3" path: "img/cat.png" @@ -7667,11 +8034,14 @@ definitions: properties: releases: type: "array" - description: "Optional; GET-only" + description: "Full release entities, included in GET responses when `releases`\n\ + included in `expand` parameter. Ignored if included in PUT or POST\nrequests.\n" items: $ref: "#/definitions/release_entity" release_ids: type: "array" + description: "Set of identifier of release entities this fileset represents\ + \ a full\nmanifestation of. Usually a single release.\n" items: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7682,13 +8052,14 @@ definitions: timestamp: type: "string" format: "date-time" - description: "same format as CDX line timestamp (UTC, etc). Corresponds to\ - \ the overall capture timestamp. Can be the earliest or average of CDX timestamps\ - \ if that makes sense." + description: "Same format as CDX line timestamp (UTC, etc). Corresponds to\ + \ the\noverall capture timestamp. Should generally be the timestamp of\n\ + capture of the primary resource URL.\n" original_url: type: "string" format: "url" example: "http://asheesh.org" + description: "Base URL of the primary resource this is a capture of" archive_urls: type: "array" items: @@ -7699,8 +8070,12 @@ definitions: $ref: "#/definitions/webcapture_cdx_line" edit_extra: type: "object" + description: "Free-form JSON metadata that will be stored with specific entity\ + \ edits\n(eg, creation/update/delete).\n" extra: type: "object" + description: "Free-form JSON metadata that will be stored with the other entity\n\ + metadata. See guide for (unenforced) schema conventions.\n" redirect: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7724,6 +8099,7 @@ definitions: pattern: "[a-zA-Z2-7]{26}" state: type: "string" + example: "active" enum: - "wip" - "active" @@ -7756,7 +8132,7 @@ definitions: timestamp: "2016-09-19T17:20:24Z" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -7778,34 +8154,45 @@ definitions: surt: type: "string" example: "org,asheesh)/apus/ch1/node15.html" + description: "\"Sortable URL\" format. See guide for details.\n" timestamp: type: "string" format: "date-time" example: "2016-09-19T17:20:24Z" - description: "UTC, 'Z'-terminated, second (or better) precision" + description: "Date and time of capture, in ISO format. UTC, 'Z'-terminated,\ + \ second\n(or better) precision.\n" url: type: "string" example: "http://www.asheesh.org:80/APUS/ch1/node15.html" + description: "Full URL/URI of resource captured.\n" mimetype: type: "string" example: "text/html" + description: "Mimetype of the resource at this URL. May be the Content-Type\ + \ header,\nor the actually sniffed file type.\n" status_code: type: "integer" format: "int64" example: 200 + description: "HTTP status code. Should generally be 200, especially for the\ + \ primary\nresource, but may be 3xx (redirect) or even error codes if embedded\n\ + resources can not be fetched successfully.\n" size: type: "integer" format: "int64" example: 1048576 + description: "Resource (file) size in bytes" sha1: type: "string" example: "e9dd75237c94b209dc3ccd52722de6931a310ba3" + description: "SHA-1 hash of data, in hex encoding" minLength: 40 maxLength: 40 pattern: "[a-f0-9]{40}" sha256: type: "string" example: "cb1c378f464d5935ddaa8de28446d82638396c61f042295d7fb85e3cccc9e452" + description: "SHA-256 hash of data, in hex encoding" minLength: 64 maxLength: 64 pattern: "[a-f0-9]{64}" @@ -7829,9 +8216,13 @@ definitions: type: "string" format: "url" example: "https://web.archive.org/web/" + description: "URL/URI pointing to archive of this web resource.\n" rel: type: "string" example: "wayback" + description: "Type of archive endpoint. Usually `wayback` (WBM replay of primary\n\ + resource), or `warc` (direct URL to a WARC file containing all\nresources\ + \ of the capture). See guide for full list.\n" example: rel: "wayback" url: "https://web.archive.org/web/" @@ -7855,85 +8246,143 @@ definitions: $ref: "#/definitions/release_contrib" license_slug: type: "string" - description: "Short version of license name. Eg, 'CC-BY'" + example: "CC-BY" + description: "Short string (slug) name of license under which release is openly\n\ + published (if applicable).\n" language: type: "string" - description: "Two-letter RFC1766/ISO639-1 language code, with extensions" + example: "en" + description: "Primary language of the content of the full release. Two-letter\n\ + RFC1766/ISO639-1 language code, with some custom\nextensions/additions.\ + \ See guide.\n" publisher: type: "string" + example: "Elsevier" + description: "Name, usually English, of the entity or institution responsible\ + \ for\npublication of this release. Not necessarily the imprint/brand. See\n\ + guide.\n" version: type: "string" + example: "3" + description: "For, eg, updated technical reports or software packages, where\n\ + the version string may be the only field disambiguating between\nreleases.\n" number: type: "string" + example: "RFC1337" + description: "For, eg, technical reports, which are published in series or\n\ + assigned some other institutional or container-specific identifier.\n" pages: type: "string" + example: "340-345" + description: "Either a single page number (\"first page\") or a range of pages\n\ + separated by a dash (\"-\"). See guide for details.\n" issue: type: "string" example: "12" + description: "Issue number of volume/container that this release was published\ + \ in.\nSometimes coresponds to a month number in the year, but can be any\n\ + string. See guide.\n" volume: type: "string" + example: "3" + description: "Volume number of container that this release was published in.\ + \ Often\ncorresponds to the \"Nth\" year of publication, but can be any\ + \ string.\nSee guide.\n" ext_ids: + description: "Set of external identifiers for this release.\n" $ref: "#/definitions/release_ext_ids" withdrawn_year: type: "integer" format: "int64" example: 2014 + description: "Year corresponding with `withdrawn_date` like\n`release_year`/`release_date`.\n" withdrawn_date: type: "string" format: "date" + description: "Full date when this release was formally withdrawn (if applicable).\n\ + ISO format, like `release_date`.\n" withdrawn_status: type: "string" + example: "retracted" + description: "Type of withdrawl or retraction of this release, if applicable.\ + \ If\nrelease has not been withdrawn, should be `null` (aka, not set, not\n\ + the string \"null\" or an empty string).\n" release_year: type: "integer" format: "int64" example: 2014 + description: "Year when this release was formally published. Must match\n\ + `release_date` if that field is set; this field exists because\nsometimes\ + \ only the year is known.\n" release_date: type: "string" format: "date" + description: "Full date when this release was formally published. ISO format,\ + \ like\n`2019-03-05`. See guide for semantics.\n" release_stage: type: "string" - example: "preprint, retracted" + example: "preprint" + description: "The stage of publication of this specific release. See guide\ + \ for\nvalid values and semantics.\n" release_type: type: "string" example: "book" + description: "\"Type\" or \"medium\" that this release is published as. See\ + \ guide for\nvalid values.\n" container_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" + description: "Used to link this release to a container entity that the release\ + \ was\npublished as part of.\n" webcaptures: type: "array" - description: "Optional; GET-only" + description: "Complete webcapture entities identified by `webcapture_ids`\ + \ field.\nOnly included in GET responses when `webcaptures` included in\ + \ `expand`\nparameter; ignored in PUT or POST requests.\n" items: $ref: "#/definitions/webcapture_entity" filesets: type: "array" - description: "Optional; GET-only" + description: "Complete file entities identified by `filesets_ids` field. Only\n\ + included in GET responses when `filesets` included in `expand`\nparameter;\ + \ ignored in PUT or POST requests.\n" items: $ref: "#/definitions/fileset_entity" files: type: "array" - description: "Optional; GET-only" + description: "Complete file entities identified by `file_ids` field. Only\n\ + included in GET responses when `files` included in `expand` parameter;\n\ + ignored in PUT or POST requests.\n" items: $ref: "#/definitions/file_entity" container: - description: "Optional; GET-only" + description: "Complete container entity identified by `container_id` field.\ + \ Only\nincluded in GET reponses when `container` included in `expand`\n\ + parameter; ignored in PUT or POST requests.\n" $ref: "#/definitions/container_entity" work_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" + description: "Identifier of work this release is part of. In creation (POST)\n\ + requests, a work entity will be created automatically if this field\nis\ + \ not set.\n" original_title: type: "string" - description: "Title in original language (or, the language of the full text\ - \ of this release)" + description: "Title in original language if `title` field has been translated.\ + \ See\nguide for details.\n" subtitle: type: "string" - description: "Avoid this field if possible, and merge with title; usually\ - \ English" + description: "Subtitle of release. In many cases, better to merge with title\ + \ than\ninclude as separate field (unless combined title would be very long).\n\ + See guide for details.\n" title: type: "string" description: "Required for valid entities. The title used in citations and\ - \ for display; usually English" + \ for\ndisplay. Sometimes the English translation of title e even if release\n\ + content is not English.\n" state: type: "string" + example: "active" enum: - "wip" - "active" @@ -7962,19 +8411,23 @@ definitions: pattern: "[a-zA-Z2-7]{26}" extra: type: "object" + description: "Free-form JSON metadata that will be stored with the other entity\n\ + metadata. See guide for (unenforced) schema conventions.\n" edit_extra: type: "object" + description: "Free-form JSON metadata that will be stored with specific entity\ + \ edits\n(eg, creation/update/delete).\n" example: container: redirect: "q3nouwy3nnbsvo3h5klxsx4a7y" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - container_type: "container_type" + container_type: "journal" name: "Journal of Important Results" publisher: "Society of Curious Students" issnl: "1234-5678" - wikidata_qid: "wikidata_qid" - state: "wip" + wikidata_qid: "Q42812" + state: "active" edit_extra: "{}" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" webcaptures: @@ -8004,7 +8457,7 @@ definitions: timestamp: "2016-09-19T17:20:24Z" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8040,7 +8493,7 @@ definitions: timestamp: "2016-09-19T17:20:24Z" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8051,8 +8504,8 @@ definitions: timestamp: "2000-01-23T04:56:07.000+00:00" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" - withdrawn_status: "withdrawn_status" - language: "language" + withdrawn_status: "retracted" + language: "en" title: "title" contribs: - raw_affiliation: "raw_affiliation" @@ -8062,19 +8515,19 @@ definitions: ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" orcid: "0000-0002-1825-0097" - wikidata_qid: "wikidata_qid" - state: "wip" + wikidata_qid: "Q42812" + state: "active" given_name: "given_name" display_name: "Grace Hopper" edit_extra: "{}" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" - raw_name: "raw_name" - role: "role" - surname: "surname" + raw_name: "Jane K. Doe" + role: "author" + surname: "Doe" extra: "{}" creator_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - index: 1 - given_name: "given_name" + index: 0 + given_name: "Jane" - raw_affiliation: "raw_affiliation" creator: redirect: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8082,23 +8535,23 @@ definitions: ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" orcid: "0000-0002-1825-0097" - wikidata_qid: "wikidata_qid" - state: "wip" + wikidata_qid: "Q42812" + state: "active" given_name: "given_name" display_name: "Grace Hopper" edit_extra: "{}" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" - raw_name: "raw_name" - role: "role" - surname: "surname" + raw_name: "Jane K. Doe" + role: "author" + surname: "Doe" extra: "{}" creator_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - index: 1 - given_name: "given_name" - number: "number" - pages: "pages" + index: 0 + given_name: "Jane" + number: "RFC1337" + pages: "340-345" extra: "{}" - state: "wip" + state: "active" edit_extra: "{}" withdrawn_year: 2014 redirect: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8116,43 +8569,43 @@ definitions: content: "<jats:p>Some abstract thing goes here</jats:p>" release_year: 2014 release_type: "book" - version: "version" + version: "3" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" - volume: "volume" + volume: "3" ext_ids: core: "core" mag: "mag" jstor: "jstor" isbn13: "isbn13" arxiv: "arxiv" - wikidata_qid: "wikidata_qid" + wikidata_qid: "Q42812" ark: "ark" - pmid: "pmid" - pmcid: "pmcid" + pmid: "482132" + pmcid: "PMC7391" doi: "10.1234/abcde.789" - release_stage: "preprint, retracted" - license_slug: "license_slug" + release_stage: "preprint" + license_slug: "CC-BY" withdrawn_date: "2000-01-23" refs: - target_release_id: "q3nouwy3nnbsvo3h5klxsx4a7y" container_name: "container_name" - year: 6 + year: 1972 extra: "{}" index: 0 title: "title" locator: "p123" - key: "key" + key: "SMITH2016" - target_release_id: "q3nouwy3nnbsvo3h5klxsx4a7y" container_name: "container_name" - year: 6 + year: 1972 extra: "{}" index: 0 title: "title" locator: "p123" - key: "key" + key: "SMITH2016" release_date: "2000-01-23" subtitle: "subtitle" - publisher: "publisher" + publisher: "Elsevier" files: - redirect: "q3nouwy3nnbsvo3h5klxsx4a7y" sha256: "cb1c378f464d5935ddaa8de28446d82638396c61f042295d7fb85e3cccc9e452" @@ -8163,14 +8616,14 @@ definitions: revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" sha1: "e9dd75237c94b209dc3ccd52722de6931a310ba3" urls: - - rel: "webarchive" + - rel: "web" url: "https://example.edu/~frau/prcding.pdf" - - rel: "webarchive" + - rel: "web" url: "https://example.edu/~frau/prcding.pdf" size: 1048576 extra: "{}" mimetype: "application/pdf" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8185,14 +8638,14 @@ definitions: revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" sha1: "e9dd75237c94b209dc3ccd52722de6931a310ba3" urls: - - rel: "webarchive" + - rel: "web" url: "https://example.edu/~frau/prcding.pdf" - - rel: "webarchive" + - rel: "web" url: "https://example.edu/~frau/prcding.pdf" size: 1048576 extra: "{}" mimetype: "application/pdf" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8220,7 +8673,7 @@ definitions: md5: "1b39813549077b2347c0f370c3864b40" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8250,7 +8703,7 @@ definitions: md5: "1b39813549077b2347c0f370c3864b40" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - state: "wip" + state: "active" release_ids: - "q3nouwy3nnbsvo3h5klxsx4a7y" - "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8267,34 +8720,49 @@ definitions: doi: type: "string" example: "10.1234/abcde.789" + description: "Digital Object Identifier (DOI), mostly for published papers\ + \ and\ndatasets. Should be registered and resolvable via https://doi.org/\n" wikidata_qid: type: "string" + example: "Q42812" + description: "Wikidata entity QID" isbn13: type: "string" + description: "ISBN-13, for books. Usually not set for chapters. ISBN-10 should\ + \ be\nconverted to ISBN-13.\n" pmid: type: "string" + example: "482132" + description: "PubMed Identifier" pmcid: type: "string" + example: "PMC7391" + description: "PubMed Central Identifier" core: type: "string" + description: "CORE (https://core.ac.uk) identifier" arxiv: type: "string" + description: "arXiv (https://arxiv.org) identifier; must include version" jstor: type: "string" + description: "JSTOR work identifier" ark: type: "string" + description: "ARK identifier" mag: type: "string" + description: "Microsoft Academic Graph identifier" example: core: "core" mag: "mag" jstor: "jstor" isbn13: "isbn13" arxiv: "arxiv" - wikidata_qid: "wikidata_qid" + wikidata_qid: "Q42812" ark: "ark" - pmid: "pmid" - pmcid: "pmcid" + pmid: "482132" + pmcid: "PMC7391" doi: "10.1234/abcde.789" upperCaseName: "RELEASE_EXT_IDS" release_abstract: @@ -8303,18 +8771,25 @@ definitions: sha1: type: "string" example: "e9dd75237c94b209dc3ccd52722de6931a310ba3" + description: "SHA-1 hash of data, in hex encoding" minLength: 40 maxLength: 40 pattern: "[a-f0-9]{40}" content: type: "string" example: "<jats:p>Some abstract thing goes here</jats:p>" + description: "Abstract content. May be encoded, as per `mimetype` field, but\ + \ only\nstring/text content may be included.\n" mimetype: type: "string" example: "application/xml+jats" + description: "Mimetype of abstract contents. `text/plain` is the default if\ + \ content\nisn't encoded.\n" lang: type: "string" example: "en" + description: "ISO language code of the abstract. Same semantics as release\ + \ `language` field.\n" example: sha1: "e9dd75237c94b209dc3ccd52722de6931a310ba3" mimetype: "application/xml+jats" @@ -8326,8 +8801,12 @@ definitions: properties: edit_extra: type: "object" + description: "Free-form JSON metadata that will be stored with specific entity\ + \ edits\n(eg, creation/update/delete).\n" extra: type: "object" + description: "Free-form JSON metadata that will be stored with the other entity\n\ + metadata. See guide for (unenforced) schema conventions.\n" redirect: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -8351,6 +8830,7 @@ definitions: pattern: "[a-zA-Z2-7]{26}" state: type: "string" + example: "active" enum: - "wip" - "active" @@ -8360,7 +8840,7 @@ definitions: redirect: "q3nouwy3nnbsvo3h5klxsx4a7y" ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" - state: "wip" + state: "active" edit_extra: "{}" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" upperCaseName: "WORK_ENTITY" @@ -8380,10 +8860,10 @@ definitions: example: editgroup: editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" changelog_index: 1048576 submitted: "2000-01-23T04:56:07.000+00:00" @@ -8500,10 +8980,10 @@ definitions: annotations: - annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -8512,10 +8992,10 @@ definitions: comment_markdown: "comment_markdown" - annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -8534,10 +9014,10 @@ definitions: changelog_entry: editgroup: editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" changelog_index: 1048576 submitted: "2000-01-23T04:56:07.000+00:00" @@ -8654,10 +9134,10 @@ definitions: annotations: - annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -8666,10 +9146,10 @@ definitions: comment_markdown: "comment_markdown" - annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -8691,42 +9171,45 @@ definitions: edit_id: type: "string" example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" - description: "UUID (lower-case, dash-separated, hex-encoded 128-bit)" + description: "Unique UUID for this specific edit object.\n" minLength: 36 maxLength: 36 pattern: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" ident: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "Fatcat identifier of the entity this edit is mutating.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" revision: type: "string" example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" - description: "UUID (lower-case, dash-separated, hex-encoded 128-bit)" + description: "Entity revision that this edit will set the entity to. May be\n\ + `null` in the case of deletions.\n" minLength: 36 maxLength: 36 pattern: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" prev_revision: type: "string" example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" - description: "UUID (lower-case, dash-separated, hex-encoded 128-bit)" + description: "Revision of entity just before this edit. May be used in the\ + \ future\nto prevent edit race conditions.\n" minLength: 36 maxLength: 36 pattern: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" redirect_ident: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "When an edit is to merge entities (redirect one to another),\ + \ this\nis the entity fatcat identifier for the target entity.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" editgroup_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "Editgroup identifier that this edit is part of.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" @@ -8749,24 +9232,35 @@ definitions: editor_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "Fatcat identifier for the editor. Can not be changed.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" username: type: "string" example: "zerocool93" + description: "Username/handle (short slug-like string) to identify this editor.\ + \ May\nbe changed at any time by the editor; use the `editor_id` as a\n\ + persistend identifer.\n" is_admin: type: "boolean" + example: false + description: "Whether this editor has the `admin` role.\n" is_bot: type: "boolean" + example: false + description: "Whether this editor is a bot (as opposed to a human making manual\n\ + edits)\n" is_active: type: "boolean" + example: true + description: "Whether this editor's account is enabled (if not API tokens\ + \ and web\nlogins will not work).\n" example: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" upperCaseName: "EDITOR" editgroup: @@ -8775,45 +9269,60 @@ definitions: editgroup_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "Fatcat identifier for this editgroup. Assigned on creation.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" editor_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "Fatcat identifer of editor that created this editgroup.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" editor: + description: "Complete editor object identified by `container_id` field. Only\n\ + included in GET responses.\n" $ref: "#/definitions/editor" changelog_index: type: "integer" format: "int64" example: 1048576 + description: "For accepted/merged editgroups, the changelog index that the\ + \ accept\noccured at. WARNING: not populated in all contexts that an editgroup\n\ + could be included in a response.\n" created: type: "string" format: "date-time" + description: "Timestamp when this editgroup was first created.\n" submitted: type: "string" format: "date-time" + description: "Timestamp when this editgroup was most recently submitted for\ + \ review.\nIf withdrawn, or never submitted, will be `null`.\n" description: type: "string" + description: "Comment describing the changes in this editgroup. Can be updated\ + \ with\nPUT request.\n" extra: type: "object" + description: "Free-form JSON metadata attached to this editgroup. Eg, metadata\n\ + provenance, or script user-agent details. See guide for (unenforced)\nschema\ + \ norms.\n" annotations: type: "array" + description: "Only included in GET responses, and not in all contexts. Do\ + \ not\ninclude this field in PUT or POST requests.\n" items: $ref: "#/definitions/editgroup_annotation" edits: $ref: "#/definitions/editgroup_edits" example: editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" changelog_index: 1048576 submitted: "2000-01-23T04:56:07.000+00:00" @@ -8930,10 +9439,10 @@ definitions: annotations: - annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -8942,10 +9451,10 @@ definitions: comment_markdown: "comment_markdown" - annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -8967,33 +9476,39 @@ definitions: editgroup_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "Editgroup that this annotation applies to. Set automatically\ + \ in\ncreations based on URL parameter.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" editor_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "Defaults to editor created the annotation via POST request.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" editor: + description: "Only included in GET responses; ignored in PUT or POST requests.\n" $ref: "#/definitions/editor" created: type: "string" format: "date-time" + description: "Timestamp when annotation was first created.\n" comment_markdown: type: "string" extra: type: "object" + description: "Additional free-form JSON metadata that can be included as part\ + \ of\nthe annotation (or even as the primary annotation itself). See guide\n\ + for details.\n" example: annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -9011,21 +9526,24 @@ definitions: index: type: "integer" format: "int64" + description: "Monotonically increasing sequence number of this changelog entry.\n" editgroup_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" + description: "Identifier of editgroup accepted/merged in this changelog entry.\n" timestamp: type: "string" format: "date-time" + description: "Date and time when the editgroup was accpeted.\n" editgroup: $ref: "#/definitions/editgroup" example: editgroup: editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" changelog_index: 1048576 submitted: "2000-01-23T04:56:07.000+00:00" @@ -9142,10 +9660,10 @@ definitions: annotations: - annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -9154,10 +9672,10 @@ definitions: comment_markdown: "comment_markdown" - annotation_id: "86daea5b-1b6b-432a-bb67-ea97795f80fe" editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" created: "2000-01-23T04:56:07.000+00:00" extra: "{}" @@ -9175,36 +9693,54 @@ definitions: index: type: "integer" format: "int64" + description: "Zero-indexed sequence number of this reference in the list of\n\ + references. Assigned automatically and used internally; don't confuse\n\ + with `key`.\n" target_release_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "Optional, fatcat identifier of release entity that this reference\ + \ is\nciting.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" extra: type: "object" + description: "Additional free-form JSON metadata about this citation. Generally\n\ + follows Citation Style Language (CSL) JSON schema. See guide for\ndetails.\n" key: type: "string" + example: "SMITH2016" + description: "Short string used to indicate this reference from within the\ + \ release\ntext; or numbering of references as typeset in the release itself.\n\ + Optional; don't confuse with `index` field.\n" year: type: "integer" format: "int64" + example: 1972 + description: "Year that the cited work was published in.\n" container_name: type: "string" + description: "Name of the container (eg, journal) that the citation work was\n\ + published as part of. May be an acronym or full name.\n" title: type: "string" + description: "Name of the work being cited." locator: type: "string" example: "p123" + description: "Page number or other indicator of the specific subset of a work\ + \ being\ncited. Not to be confused with the first page (or page range) of\ + \ an\nentire paper or chapter being cited.\n" example: target_release_id: "q3nouwy3nnbsvo3h5klxsx4a7y" container_name: "container_name" - year: 6 + year: 1972 extra: "{}" index: 0 title: "title" locator: "p123" - key: "key" + key: "SMITH2016" upperCaseName: "RELEASE_REF" release_contrib: type: "object" @@ -9212,29 +9748,47 @@ definitions: index: type: "integer" format: "int64" + example: 0 + description: "Internally assigned zero-indexed sequence number of contribution.\n\ + Authors should come first; this encodes the order of attriubtion.\n" creator_id: type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" - description: "base32-encoded unique identifier" + description: "If known, indicates the creator entity this contribution was\ + \ made by.\n" minLength: 26 maxLength: 26 pattern: "[a-zA-Z2-7]{26}" creator: - description: "Optional; GET-only" + description: "Complete creator entity. Only returned in GET responses, and\ + \ only if\n`contribs` included in the `expand` query parameter.\n" $ref: "#/definitions/creator_entity" raw_name: type: "string" + example: "Jane K. Doe" + description: "Full name of the contributor as typeset in the release.\n" given_name: type: "string" + example: "Jane" + description: "In English commonly the first name, but ordering is context\ + \ and\nculture specific.\n" surname: type: "string" + example: "Doe" + description: "In English commonly the last, or family name, but ordering is\ + \ context\nand culture specific.\n" role: type: "string" + example: "author" + description: "Short string (slug) indicating type of contribution (eg, \"\ + author\",\n\"translator\"). See guide for list of accpeted values.\n" raw_affiliation: type: "string" description: "Raw affiliation string as displayed in text" extra: type: "object" + description: "Additional free-form JSON metadata about this\ncontributor/contribution.\ + \ See guide for normative schema.\n" example: raw_affiliation: "raw_affiliation" creator: @@ -9243,19 +9797,19 @@ definitions: ident: "q3nouwy3nnbsvo3h5klxsx4a7y" extra: "{}" orcid: "0000-0002-1825-0097" - wikidata_qid: "wikidata_qid" - state: "wip" + wikidata_qid: "Q42812" + state: "active" given_name: "given_name" display_name: "Grace Hopper" edit_extra: "{}" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" - raw_name: "raw_name" - role: "role" - surname: "surname" + raw_name: "Jane K. Doe" + role: "author" + surname: "Doe" extra: "{}" creator_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - index: 1 - given_name: "given_name" + index: 0 + given_name: "Jane" upperCaseName: "RELEASE_CONTRIB" container_auto_batch: type: "object" @@ -9358,12 +9912,24 @@ definitions: properties: provider: type: "string" + example: "orcid" + description: "Fatcat-specific short name (slug) for remote service being used\ + \ for\nauthentication.\n" sub: type: "string" + example: "https://orcid.org" + description: "`SUB` from OIDC protocol. Usually a URL." iss: type: "string" + example: "0000-0002-8593-9468" + description: "`ISS` from OIDC protocol. Usually a stable account username,\ + \ number, or identifier." preferred_username: type: "string" + example: "bnewbold" + description: "What it sounds like; returned by OIDC, and used as a hint when\n\ + creating new editor accounts. Fatcat usernames are usually this\nstring\ + \ with the `provider` slug as a suffix, though some munging may\noccur.\n" upperCaseName: "AUTH_OIDC" auth_oidc_result: type: "object" @@ -9375,14 +9941,15 @@ definitions: $ref: "#/definitions/editor" token: type: "string" + example: "AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=" example: editor: - is_admin: true + is_admin: false is_active: true editor_id: "q3nouwy3nnbsvo3h5klxsx4a7y" - is_bot: true + is_bot: false username: "zerocool93" - token: "token" + token: "AgEPZGV2LmZhdGNhdC53aWtpAhYyMDE5MDEwMS1kZXYtZHVtbXkta2V5AAImZWRpdG9yX2lkID0gYWFhYWFhYWFhYWFhYmt2a2FhYWFhYWFhYWkAAht0aW1lID4gMjAxOS0wMS0wOVQwMDo1Nzo1MloAAAYgnroNha1hSftChtxHGTnLEmM/pY8MeQS/jBSV0UNvXug=" upperCaseName: "AUTH_OIDC_RESULT" editgroup_edits: properties: @@ -9414,6 +9981,8 @@ definitions: type: "array" items: $ref: "#/definitions/entity_edit" + description: "Only included in GET responses, and not in all contexts. Do not\n\ + include this field in PUT or POST requests.\n" example: works: - ident: "q3nouwy3nnbsvo3h5klxsx4a7y" @@ -9521,50 +10090,84 @@ definitions: prev_revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" revision: "86daea5b-1b6b-432a-bb67-ea97795f80fe" upperCaseName: "EDITGROUP_EDITS" +x-servers: +- url: "https://api.fatcat.wiki/v0" + description: "Production Server" +- url: "https://api.qa.fatcat.wiki/v0" + description: "QA Server" +x-tagGroups: +- name: "Entities" + tags: + - "containers" + - "creators" + - "files" + - "filesets" + - "webcaptures" + - "releases" + - "works" +- name: "Editing" + tags: + - "editors" + - "editgroups" + - "changelog" +- name: "Other" + tags: + - "auth" x-fatcat-ident: type: "string" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" pattern: "[a-zA-Z2-7]{26}" minLength: 26 maxLength: 26 description: "base32-encoded unique identifier" +x-fatcat-ident-example: + example: "q3nouwy3nnbsvo3h5klxsx4a7y" x-fatcat-uuid: type: "string" - example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" pattern: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" minLength: 36 maxLength: 36 description: "UUID (lower-case, dash-separated, hex-encoded 128-bit)" +x-fatcat-uuid-example: + example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" x-issn: type: "string" - example: "1234-5678" pattern: "\\d{4}-\\d{3}[0-9X]" minLength: 9 maxLength: 9 +x-issn-example: + example: "1234-5678" x-orcid: type: "string" - example: "0000-0002-1825-0097" pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]" minLength: 19 maxLength: 19 + description: "ORCiD (https://orcid.org) identifier" +x-orcid-example: + example: "0000-0002-1825-0097" x-md5: type: "string" - example: "1b39813549077b2347c0f370c3864b40" pattern: "[a-f0-9]{32}" minLength: 32 maxLength: 32 + description: "MD5 hash of data, in hex encoding" +x-md5-example: + example: "1b39813549077b2347c0f370c3864b40" x-sha1: type: "string" - example: "e9dd75237c94b209dc3ccd52722de6931a310ba3" pattern: "[a-f0-9]{40}" minLength: 40 maxLength: 40 + description: "SHA-1 hash of data, in hex encoding" +x-sha1-example: + example: "e9dd75237c94b209dc3ccd52722de6931a310ba3" x-sha256: type: "string" - example: "cb1c378f464d5935ddaa8de28446d82638396c61f042295d7fb85e3cccc9e452" pattern: "[a-f0-9]{64}" minLength: 64 maxLength: 64 + description: "SHA-256 hash of data, in hex encoding" +x-sha256-example: + example: "cb1c378f464d5935ddaa8de28446d82638396c61f042295d7fb85e3cccc9e452" x-entity-props: state: type: "string" @@ -9573,32 +10176,37 @@ x-entity-props: - "active" - "redirect" - "deleted" + example: "active" ident: + example: "q3nouwy3nnbsvo3h5klxsx4a7y" description: "base32-encoded unique identifier" maxLength: 26 minLength: 26 pattern: "[a-zA-Z2-7]{26}" - example: "q3nouwy3nnbsvo3h5klxsx4a7y" type: "string" revision: + example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" description: "UUID (lower-case, dash-separated, hex-encoded 128-bit)" maxLength: 36 minLength: 36 pattern: "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" - example: "86daea5b-1b6b-432a-bb67-ea97795f80fe" type: "string" redirect: - type: "string" example: "q3nouwy3nnbsvo3h5klxsx4a7y" + type: "string" pattern: "[a-zA-Z2-7]{26}" minLength: 26 maxLength: 26 description: "base32-encoded unique identifier" extra: type: "object" + description: "Free-form JSON metadata that will be stored with the other entity\n\ + metadata. See guide for (unenforced) schema conventions.\n" additionalProperties: {} edit_extra: type: "object" + description: "Free-form JSON metadata that will be stored with specific entity\ + \ edits\n(eg, creation/update/delete).\n" additionalProperties: {} x-auth-responses: 401: diff --git a/rust/fatcat-openapi/examples/client.rs b/rust/fatcat-openapi/examples/client.rs index 3cb0df50..502d8ee6 100644 --- a/rust/fatcat-openapi/examples/client.rs +++ b/rust/fatcat-openapi/examples/client.rs @@ -35,6 +35,9 @@ fn main() { Arg::with_name("operation") .help("Sets the operation to run") .possible_values(&[ + "AuthCheck", + "GetChangelog", + "GetChangelogEntry", "DeleteContainer", "DeleteContainerEdit", "GetContainer", @@ -52,16 +55,13 @@ fn main() { "GetCreatorReleases", "GetCreatorRevision", "LookupCreator", - "AuthCheck", - "GetEditgroupsReviewable", - "GetEditor", - "GetEditorEditgroups", "AcceptEditgroup", - "GetChangelog", - "GetChangelogEntry", "GetEditgroup", "GetEditgroupAnnotations", + "GetEditgroupsReviewable", + "GetEditor", "GetEditorAnnotations", + "GetEditorEditgroups", "DeleteFile", "DeleteFileEdit", "GetFile", @@ -131,6 +131,26 @@ fn main() { let client = client.with_context(fatcat::Context::new_with_span_id(self::uuid::Uuid::new_v4().to_string())); match matches.value_of("operation") { + Some("AuthCheck") => { + let result = client.auth_check(Some("role_example".to_string())).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); + } + + // Disabled because there's no example. + // Some("AuthOidc") => { + // let result = client.auth_oidc(???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); + // }, + Some("GetChangelog") => { + let result = client.get_changelog(Some(789)).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); + } + + Some("GetChangelogEntry") => { + let result = client.get_changelog_entry(789).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); + } + // Disabled because there's no example. // Some("CreateContainer") => { // let result = client.create_container("editgroup_id_example".to_string(), ???).wait(); @@ -271,42 +291,6 @@ fn main() { // let result = client.update_creator("editgroup_id_example".to_string(), "ident_example".to_string(), ???).wait(); // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); // }, - Some("AuthCheck") => { - let result = client.auth_check(Some("role_example".to_string())).wait(); - println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); - } - - // Disabled because there's no example. - // Some("AuthOidc") => { - // let result = client.auth_oidc(???).wait(); - // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); - // }, - Some("GetEditgroupsReviewable") => { - let result = client.get_editgroups_reviewable(Some("expand_example".to_string()), Some(789), None, None).wait(); - println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); - } - - Some("GetEditor") => { - let result = client.get_editor("editor_id_example".to_string()).wait(); - println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); - } - - Some("GetEditorEditgroups") => { - let result = client.get_editor_editgroups("editor_id_example".to_string(), Some(789), None, None).wait(); - println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); - } - - // Disabled because there's no example. - // Some("UpdateEditgroup") => { - // let result = client.update_editgroup("editgroup_id_example".to_string(), ???, Some(true)).wait(); - // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); - // }, - - // Disabled because there's no example. - // Some("UpdateEditor") => { - // let result = client.update_editor("editor_id_example".to_string(), ???).wait(); - // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); - // }, Some("AcceptEditgroup") => { let result = client.accept_editgroup("editgroup_id_example".to_string()).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); @@ -323,23 +307,28 @@ fn main() { // let result = client.create_editgroup_annotation("editgroup_id_example".to_string(), ???).wait(); // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); // }, - Some("GetChangelog") => { - let result = client.get_changelog(Some(789)).wait(); + Some("GetEditgroup") => { + let result = client.get_editgroup("editgroup_id_example".to_string()).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); } - Some("GetChangelogEntry") => { - let result = client.get_changelog_entry(789).wait(); + Some("GetEditgroupAnnotations") => { + let result = client.get_editgroup_annotations("editgroup_id_example".to_string(), Some("expand_example".to_string())).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); } - Some("GetEditgroup") => { - let result = client.get_editgroup("editgroup_id_example".to_string()).wait(); + Some("GetEditgroupsReviewable") => { + let result = client.get_editgroups_reviewable(Some("expand_example".to_string()), Some(789), None, None).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); } - Some("GetEditgroupAnnotations") => { - let result = client.get_editgroup_annotations("editgroup_id_example".to_string(), Some("expand_example".to_string())).wait(); + // Disabled because there's no example. + // Some("UpdateEditgroup") => { + // let result = client.update_editgroup("editgroup_id_example".to_string(), ???, Some(true)).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); + // }, + Some("GetEditor") => { + let result = client.get_editor("editor_id_example".to_string()).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); } @@ -348,6 +337,17 @@ fn main() { println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); } + Some("GetEditorEditgroups") => { + let result = client.get_editor_editgroups("editor_id_example".to_string(), Some(789), None, None).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); + } + + // Disabled because there's no example. + // Some("UpdateEditor") => { + // let result = client.update_editor("editor_id_example".to_string(), ???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); + // }, + // Disabled because there's no example. // Some("CreateFile") => { // let result = client.create_file("editgroup_id_example".to_string(), ???).wait(); @@ -484,12 +484,6 @@ fn main() { // let result = client.create_release_auto_batch(???).wait(); // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); // }, - - // Disabled because there's no example. - // Some("CreateWork") => { - // let result = client.create_work("editgroup_id_example".to_string(), ???).wait(); - // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); - // }, Some("DeleteRelease") => { let result = client.delete_release("editgroup_id_example".to_string(), "ident_example".to_string()).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); @@ -627,6 +621,12 @@ fn main() { // }, // Disabled because there's no example. + // Some("CreateWork") => { + // let result = client.create_work("editgroup_id_example".to_string(), ???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); + // }, + + // Disabled because there's no example. // Some("CreateWorkAutoBatch") => { // let result = client.create_work_auto_batch(???).wait(); // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from("<none>"))); diff --git a/rust/fatcat-openapi/examples/server_lib/server.rs b/rust/fatcat-openapi/examples/server_lib/server.rs index c9f92d33..e0f9045f 100644 --- a/rust/fatcat-openapi/examples/server_lib/server.rs +++ b/rust/fatcat-openapi/examples/server_lib/server.rs @@ -30,6 +30,30 @@ use fatcat::{ pub struct Server; impl Api for Server { + fn auth_check(&self, role: Option<String>, context: &Context) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send> { + let context = context.clone(); + println!("auth_check({:?}) - X-Span-ID: {:?}", role, context.x_span_id.unwrap_or(String::from("<none>")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { + let context = context.clone(); + println!("auth_oidc({:?}) - X-Span-ID: {:?}", oidc_params, context.x_span_id.unwrap_or(String::from("<none>")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + + fn get_changelog(&self, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> { + let context = context.clone(); + println!("get_changelog({:?}) - X-Span-ID: {:?}", limit, context.x_span_id.unwrap_or(String::from("<none>")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + + fn get_changelog_entry(&self, index: i64, context: &Context) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> { + let context = context.clone(); + println!("get_changelog_entry({}) - X-Span-ID: {:?}", index, context.x_span_id.unwrap_or(String::from("<none>")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + fn create_container(&self, editgroup_id: String, entity: models::ContainerEntity, context: &Context) -> Box<Future<Item = CreateContainerResponse, Error = ApiError> + Send> { let context = context.clone(); println!( @@ -285,56 +309,63 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn auth_check(&self, role: Option<String>, context: &Context) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send> { + fn accept_editgroup(&self, editgroup_id: String, context: &Context) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> { let context = context.clone(); - println!("auth_check({:?}) - X-Span-ID: {:?}", role, context.x_span_id.unwrap_or(String::from("<none>")).clone()); + println!("accept_editgroup(\"{}\") - X-Span-ID: {:?}", editgroup_id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); Box::new(futures::failed("Generic failure".into())) } - fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { + fn create_editgroup(&self, editgroup: models::Editgroup, context: &Context) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> { let context = context.clone(); - println!("auth_oidc({:?}) - X-Span-ID: {:?}", oidc_params, context.x_span_id.unwrap_or(String::from("<none>")).clone()); + println!("create_editgroup({:?}) - X-Span-ID: {:?}", editgroup, context.x_span_id.unwrap_or(String::from("<none>")).clone()); Box::new(futures::failed("Generic failure".into())) } - fn get_editgroups_reviewable( + fn create_editgroup_annotation( &self, - expand: Option<String>, - limit: Option<i64>, - before: Option<chrono::DateTime<chrono::Utc>>, - since: Option<chrono::DateTime<chrono::Utc>>, + editgroup_id: String, + annotation: models::EditgroupAnnotation, context: &Context, - ) -> Box<Future<Item = GetEditgroupsReviewableResponse, Error = ApiError> + Send> { + ) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send> { let context = context.clone(); println!( - "get_editgroups_reviewable({:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", - expand, - limit, - before, - since, + "create_editgroup_annotation(\"{}\", {:?}) - X-Span-ID: {:?}", + editgroup_id, + annotation, context.x_span_id.unwrap_or(String::from("<none>")).clone() ); Box::new(futures::failed("Generic failure".into())) } - fn get_editor(&self, editor_id: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> { + fn get_editgroup(&self, editgroup_id: String, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> { let context = context.clone(); - println!("get_editor(\"{}\") - X-Span-ID: {:?}", editor_id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); + println!("get_editgroup(\"{}\") - X-Span-ID: {:?}", editgroup_id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); Box::new(futures::failed("Generic failure".into())) } - fn get_editor_editgroups( + fn get_editgroup_annotations(&self, editgroup_id: String, expand: Option<String>, context: &Context) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send> { + let context = context.clone(); + println!( + "get_editgroup_annotations(\"{}\", {:?}) - X-Span-ID: {:?}", + editgroup_id, + expand, + context.x_span_id.unwrap_or(String::from("<none>")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + + fn get_editgroups_reviewable( &self, - editor_id: String, + expand: Option<String>, limit: Option<i64>, before: Option<chrono::DateTime<chrono::Utc>>, since: Option<chrono::DateTime<chrono::Utc>>, context: &Context, - ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send> { + ) -> Box<Future<Item = GetEditgroupsReviewableResponse, Error = ApiError> + Send> { let context = context.clone(); println!( - "get_editor_editgroups(\"{}\", {:?}, {:?}, {:?}) - X-Span-ID: {:?}", - editor_id, + "get_editgroups_reviewable({:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", + expand, limit, before, since, @@ -355,85 +386,43 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn update_editor(&self, editor_id: String, editor: models::Editor, context: &Context) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send> { - let context = context.clone(); - println!( - "update_editor(\"{}\", {:?}) - X-Span-ID: {:?}", - editor_id, - editor, - context.x_span_id.unwrap_or(String::from("<none>")).clone() - ); - Box::new(futures::failed("Generic failure".into())) - } - - fn accept_editgroup(&self, editgroup_id: String, context: &Context) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> { - let context = context.clone(); - println!("accept_editgroup(\"{}\") - X-Span-ID: {:?}", editgroup_id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); - Box::new(futures::failed("Generic failure".into())) - } - - fn create_editgroup(&self, editgroup: models::Editgroup, context: &Context) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> { + fn get_editor(&self, editor_id: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> { let context = context.clone(); - println!("create_editgroup({:?}) - X-Span-ID: {:?}", editgroup, context.x_span_id.unwrap_or(String::from("<none>")).clone()); + println!("get_editor(\"{}\") - X-Span-ID: {:?}", editor_id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); Box::new(futures::failed("Generic failure".into())) } - fn create_editgroup_annotation( + fn get_editor_annotations( &self, - editgroup_id: String, - annotation: models::EditgroupAnnotation, + editor_id: String, + limit: Option<i64>, + before: Option<chrono::DateTime<chrono::Utc>>, + since: Option<chrono::DateTime<chrono::Utc>>, context: &Context, - ) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send> { - let context = context.clone(); - println!( - "create_editgroup_annotation(\"{}\", {:?}) - X-Span-ID: {:?}", - editgroup_id, - annotation, - context.x_span_id.unwrap_or(String::from("<none>")).clone() - ); - Box::new(futures::failed("Generic failure".into())) - } - - fn get_changelog(&self, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> { - let context = context.clone(); - println!("get_changelog({:?}) - X-Span-ID: {:?}", limit, context.x_span_id.unwrap_or(String::from("<none>")).clone()); - Box::new(futures::failed("Generic failure".into())) - } - - fn get_changelog_entry(&self, index: i64, context: &Context) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> { - let context = context.clone(); - println!("get_changelog_entry({}) - X-Span-ID: {:?}", index, context.x_span_id.unwrap_or(String::from("<none>")).clone()); - Box::new(futures::failed("Generic failure".into())) - } - - fn get_editgroup(&self, editgroup_id: String, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> { - let context = context.clone(); - println!("get_editgroup(\"{}\") - X-Span-ID: {:?}", editgroup_id, context.x_span_id.unwrap_or(String::from("<none>")).clone()); - Box::new(futures::failed("Generic failure".into())) - } - - fn get_editgroup_annotations(&self, editgroup_id: String, expand: Option<String>, context: &Context) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send> { + ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send> { let context = context.clone(); println!( - "get_editgroup_annotations(\"{}\", {:?}) - X-Span-ID: {:?}", - editgroup_id, - expand, + "get_editor_annotations(\"{}\", {:?}, {:?}, {:?}) - X-Span-ID: {:?}", + editor_id, + limit, + before, + since, context.x_span_id.unwrap_or(String::from("<none>")).clone() ); Box::new(futures::failed("Generic failure".into())) } - fn get_editor_annotations( + fn get_editor_editgroups( &self, editor_id: String, limit: Option<i64>, before: Option<chrono::DateTime<chrono::Utc>>, since: Option<chrono::DateTime<chrono::Utc>>, context: &Context, - ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send> { + ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send> { let context = context.clone(); println!( - "get_editor_annotations(\"{}\", {:?}, {:?}, {:?}) - X-Span-ID: {:?}", + "get_editor_editgroups(\"{}\", {:?}, {:?}, {:?}) - X-Span-ID: {:?}", editor_id, limit, before, @@ -443,6 +432,17 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } + fn update_editor(&self, editor_id: String, editor: models::Editor, context: &Context) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send> { + let context = context.clone(); + println!( + "update_editor(\"{}\", {:?}) - X-Span-ID: {:?}", + editor_id, + editor, + context.x_span_id.unwrap_or(String::from("<none>")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + fn create_file(&self, editgroup_id: String, entity: models::FileEntity, context: &Context) -> Box<Future<Item = CreateFileResponse, Error = ApiError> + Send> { let context = context.clone(); println!( @@ -690,17 +690,6 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_work(&self, editgroup_id: String, entity: models::WorkEntity, context: &Context) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send> { - let context = context.clone(); - println!( - "create_work(\"{}\", {:?}) - X-Span-ID: {:?}", - editgroup_id, - entity, - context.x_span_id.unwrap_or(String::from("<none>")).clone() - ); - Box::new(futures::failed("Generic failure".into())) - } - fn delete_release(&self, editgroup_id: String, ident: String, context: &Context) -> Box<Future<Item = DeleteReleaseResponse, Error = ApiError> + Send> { let context = context.clone(); println!( @@ -953,6 +942,17 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } + fn create_work(&self, editgroup_id: String, entity: models::WorkEntity, context: &Context) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send> { + let context = context.clone(); + println!( + "create_work(\"{}\", {:?}) - X-Span-ID: {:?}", + editgroup_id, + entity, + context.x_span_id.unwrap_or(String::from("<none>")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + fn create_work_auto_batch(&self, auto_batch: models::WorkAutoBatch, context: &Context) -> Box<Future<Item = CreateWorkAutoBatchResponse, Error = ApiError> + Send> { let context = context.clone(); println!( diff --git a/rust/fatcat-openapi/src/client.rs b/rust/fatcat-openapi/src/client.rs index 378c546f..65bf67a5 100644 --- a/rust/fatcat-openapi/src/client.rs +++ b/rust/fatcat-openapi/src/client.rs @@ -173,6 +173,298 @@ impl Client { } impl Api for Client { + fn auth_check(&self, param_role: Option<String>, context: &Context) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send> { + // Query parameters + let query_role = param_role.map_or_else(String::new, |query| format!("role={role}&", role = query.to_string())); + + let url = format!("{}/v0/auth/check?{role}", self.base_path, role = utf8_percent_encode(&query_role, 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<AuthCheckResponse, ApiError> { + match response.status.to_u16() { + 200 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::Success>(&buf)?; + + Ok(AuthCheckResponse::Success(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(AuthCheckResponse::BadRequest(body)) + } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::<ResponseWwwAuthenticate>() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(AuthCheckResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(AuthCheckResponse::Forbidden(body)) + } + 500 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(AuthCheckResponse::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 auth_oidc(&self, param_oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { + let url = format!("{}/v0/auth/oidc", self.base_path); + + let body = serde_json::to_string(¶m_oidc_params).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Post, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::AUTH_OIDC.clone())); + 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<AuthOidcResponse, ApiError> { + match response.status.to_u16() { + 200 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::AuthOidcResult>(&buf)?; + + Ok(AuthOidcResponse::Found(body)) + } + 201 => { + 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::AuthOidcResult>(&buf)?; + + Ok(AuthOidcResponse::Created(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(AuthOidcResponse::BadRequest(body)) + } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::<ResponseWwwAuthenticate>() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(AuthOidcResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(AuthOidcResponse::Forbidden(body)) + } + 409 => { + 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(AuthOidcResponse::Conflict(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(AuthOidcResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + + fn get_changelog(&self, param_limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> { + // Query parameters + let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + + let url = format!("{}/v0/changelog?{limit}", self.base_path, 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<GetChangelogResponse, 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::ChangelogEntry>>(&buf)?; + + Ok(GetChangelogResponse::Success(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(GetChangelogResponse::BadRequest(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(GetChangelogResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + + fn get_changelog_entry(&self, param_index: i64, context: &Context) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> { + let url = format!( + "{}/v0/changelog/{index}", + self.base_path, + index = utf8_percent_encode(¶m_index.to_string(), PATH_SEGMENT_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<GetChangelogEntryResponse, ApiError> { + match response.status.to_u16() { + 200 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ChangelogEntry>(&buf)?; + + Ok(GetChangelogEntryResponse::FoundChangelogEntry(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(GetChangelogEntryResponse::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(GetChangelogEntryResponse::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(GetChangelogEntryResponse::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 create_container(&self, param_editgroup_id: String, param_entity: models::ContainerEntity, context: &Context) -> Box<Future<Item = CreateContainerResponse, Error = ApiError> + Send> { let url = format!( "{}/v0/editgroup/{editgroup_id}/container", @@ -1985,14 +2277,15 @@ impl Api for Client { Box::new(futures::done(result)) } - fn auth_check(&self, param_role: Option<String>, context: &Context) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send> { - // Query parameters - let query_role = param_role.map_or_else(String::new, |query| format!("role={role}&", role = query.to_string())); - - let url = format!("{}/v0/auth/check?{role}", self.base_path, role = utf8_percent_encode(&query_role, QUERY_ENCODE_SET)); + fn accept_editgroup(&self, param_editgroup_id: String, context: &Context) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> { + let url = format!( + "{}/v0/editgroup/{editgroup_id}/accept", + self.base_path, + editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Get, &url); + let request = hyper_client.request(hyper::method::Method::Post, &url); let mut custom_headers = hyper::header::Headers::new(); context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); @@ -2000,21 +2293,21 @@ impl Api for Client { 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<AuthCheckResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<AcceptEditgroupResponse, ApiError> { match response.status.to_u16() { 200 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::<models::Success>(&buf)?; - Ok(AuthCheckResponse::Success(body)) + Ok(AcceptEditgroupResponse::MergedSuccessfully(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(AuthCheckResponse::BadRequest(body)) + Ok(AcceptEditgroupResponse::BadRequest(body)) } 401 => { let mut buf = String::new(); @@ -2026,7 +2319,7 @@ impl Api for Client { .get::<ResponseWwwAuthenticate>() .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - Ok(AuthCheckResponse::NotAuthorized { + Ok(AcceptEditgroupResponse::NotAuthorized { body: body, www_authenticate: response_www_authenticate.0.clone(), }) @@ -2036,14 +2329,28 @@ impl Api for Client { 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(AuthCheckResponse::Forbidden(body)) + Ok(AcceptEditgroupResponse::Forbidden(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(AcceptEditgroupResponse::NotFound(body)) + } + 409 => { + 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(AcceptEditgroupResponse::EditConflict(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(AuthCheckResponse::GenericError(body)) + Ok(AcceptEditgroupResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2063,10 +2370,10 @@ impl Api for Client { Box::new(futures::done(result)) } - fn auth_oidc(&self, param_oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { - let url = format!("{}/v0/auth/oidc", self.base_path); + fn create_editgroup(&self, param_editgroup: models::Editgroup, context: &Context) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> { + let url = format!("{}/v0/editgroup", self.base_path); - let body = serde_json::to_string(¶m_oidc_params).expect("impossible to fail to serialize"); + let body = serde_json::to_string(¶m_editgroup).expect("impossible to fail to serialize"); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Post, &url); @@ -2074,34 +2381,27 @@ impl Api for Client { let request = request.body(&body); - custom_headers.set(ContentType(mimetypes::requests::AUTH_OIDC.clone())); + custom_headers.set(ContentType(mimetypes::requests::CREATE_EDITGROUP.clone())); 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<AuthOidcResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<CreateEditgroupResponse, ApiError> { match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::AuthOidcResult>(&buf)?; - - Ok(AuthOidcResponse::Found(body)) - } 201 => { 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::AuthOidcResult>(&buf)?; + let body = serde_json::from_str::<models::Editgroup>(&buf)?; - Ok(AuthOidcResponse::Created(body)) + Ok(CreateEditgroupResponse::SuccessfullyCreated(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(AuthOidcResponse::BadRequest(body)) + Ok(CreateEditgroupResponse::BadRequest(body)) } 401 => { let mut buf = String::new(); @@ -2113,7 +2413,7 @@ impl Api for Client { .get::<ResponseWwwAuthenticate>() .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - Ok(AuthOidcResponse::NotAuthorized { + Ok(CreateEditgroupResponse::NotAuthorized { body: body, www_authenticate: response_www_authenticate.0.clone(), }) @@ -2123,21 +2423,21 @@ impl Api for Client { 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(AuthOidcResponse::Forbidden(body)) + Ok(CreateEditgroupResponse::Forbidden(body)) } - 409 => { + 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(AuthOidcResponse::Conflict(body)) + Ok(CreateEditgroupResponse::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(AuthOidcResponse::GenericError(body)) + Ok(CreateEditgroupResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2157,131 +2457,83 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_editgroups_reviewable( + fn create_editgroup_annotation( &self, - param_expand: Option<String>, - param_limit: Option<i64>, - param_before: Option<chrono::DateTime<chrono::Utc>>, - param_since: Option<chrono::DateTime<chrono::Utc>>, + param_editgroup_id: String, + param_annotation: models::EditgroupAnnotation, context: &Context, - ) -> Box<Future<Item = GetEditgroupsReviewableResponse, Error = ApiError> + Send> { - // Query parameters - let query_expand = param_expand.map_or_else(String::new, |query| format!("expand={expand}&", expand = query.to_string())); - let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); - let query_before = param_before.map_or_else(String::new, |query| format!("before={before}&", before = query.to_string())); - let query_since = param_since.map_or_else(String::new, |query| format!("since={since}&", since = query.to_string())); - + ) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send> { let url = format!( - "{}/v0/editgroup/reviewable?{expand}{limit}{before}{since}", + "{}/v0/editgroup/{editgroup_id}/annotation", self.base_path, - expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET), - limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET), - before = utf8_percent_encode(&query_before, QUERY_ENCODE_SET), - since = utf8_percent_encode(&query_since, QUERY_ENCODE_SET) + editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET) ); + let body = serde_json::to_string(¶m_annotation).expect("impossible to fail to serialize"); + let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Get, &url); + let request = hyper_client.request(hyper::method::Method::Post, &url); let mut custom_headers = hyper::header::Headers::new(); + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::CREATE_EDITGROUP_ANNOTATION.clone())); 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<GetEditgroupsReviewableResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<CreateEditgroupAnnotationResponse, ApiError> { match response.status.to_u16() { - 200 => { + 201 => { 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::Editgroup>>(&buf)?; + let body = serde_json::from_str::<models::EditgroupAnnotation>(&buf)?; - Ok(GetEditgroupsReviewableResponse::Found(body)) + Ok(CreateEditgroupAnnotationResponse::Created(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(GetEditgroupsReviewableResponse::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(GetEditgroupsReviewableResponse::NotFound(body)) + Ok(CreateEditgroupAnnotationResponse::BadRequest(body)) } - 500 => { + 401 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::<ResponseWwwAuthenticate>() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - Ok(GetEditgroupsReviewableResponse::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_editor(&self, param_editor_id: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> { - let url = format!( - "{}/v0/editor/{editor_id}", - self.base_path, - editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_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<GetEditorResponse, ApiError> { - match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::Editor>(&buf)?; - - Ok(GetEditorResponse::Found(body)) + Ok(CreateEditgroupAnnotationResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) } - 400 => { + 403 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - Ok(GetEditorResponse::BadRequest(body)) + Ok(CreateEditgroupAnnotationResponse::Forbidden(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(GetEditorResponse::NotFound(body)) + Ok(CreateEditgroupAnnotationResponse::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(GetEditorResponse::GenericError(body)) + Ok(CreateEditgroupAnnotationResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2301,26 +2553,11 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_editor_editgroups( - &self, - param_editor_id: String, - param_limit: Option<i64>, - param_before: Option<chrono::DateTime<chrono::Utc>>, - param_since: Option<chrono::DateTime<chrono::Utc>>, - context: &Context, - ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send> { - // Query parameters - let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); - let query_before = param_before.map_or_else(String::new, |query| format!("before={before}&", before = query.to_string())); - let query_since = param_since.map_or_else(String::new, |query| format!("since={since}&", since = query.to_string())); - + fn get_editgroup(&self, param_editgroup_id: String, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> { let url = format!( - "{}/v0/editor/{editor_id}/editgroups?{limit}{before}{since}", + "{}/v0/editgroup/{editgroup_id}", self.base_path, - editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_ENCODE_SET), - limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET), - before = utf8_percent_encode(&query_before, QUERY_ENCODE_SET), - since = utf8_percent_encode(&query_since, QUERY_ENCODE_SET) + editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET) ); let hyper_client = (self.hyper_client)(); @@ -2332,35 +2569,35 @@ impl Api for Client { 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<GetEditorEditgroupsResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<GetEditgroupResponse, 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::Editgroup>>(&buf)?; + let body = serde_json::from_str::<models::Editgroup>(&buf)?; - Ok(GetEditorEditgroupsResponse::Found(body)) + Ok(GetEditgroupResponse::Found(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(GetEditorEditgroupsResponse::BadRequest(body)) + Ok(GetEditgroupResponse::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(GetEditorEditgroupsResponse::NotFound(body)) + Ok(GetEditgroupResponse::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(GetEditorEditgroupsResponse::GenericError(body)) + Ok(GetEditgroupResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2380,52 +2617,41 @@ impl Api for Client { Box::new(futures::done(result)) } - fn update_editgroup( - &self, - param_editgroup_id: String, - param_editgroup: models::Editgroup, - param_submit: Option<bool>, - context: &Context, - ) -> Box<Future<Item = UpdateEditgroupResponse, Error = ApiError> + Send> { + fn get_editgroup_annotations(&self, param_editgroup_id: String, param_expand: Option<String>, context: &Context) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send> { // Query parameters - let query_submit = param_submit.map_or_else(String::new, |query| format!("submit={submit}&", submit = query.to_string())); + let query_expand = param_expand.map_or_else(String::new, |query| format!("expand={expand}&", expand = query.to_string())); let url = format!( - "{}/v0/editgroup/{editgroup_id}?{submit}", + "{}/v0/editgroup/{editgroup_id}/annotations?{expand}", self.base_path, editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET), - submit = utf8_percent_encode(&query_submit, QUERY_ENCODE_SET) + expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET) ); - let body = serde_json::to_string(¶m_editgroup).expect("impossible to fail to serialize"); - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Put, &url); + let request = hyper_client.request(hyper::method::Method::Get, &url); let mut custom_headers = hyper::header::Headers::new(); - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::UPDATE_EDITGROUP.clone())); 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<UpdateEditgroupResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<GetEditgroupAnnotationsResponse, ApiError> { match response.status.to_u16() { 200 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::Editgroup>(&buf)?; + let body = serde_json::from_str::<Vec<models::EditgroupAnnotation>>(&buf)?; - Ok(UpdateEditgroupResponse::UpdatedEditgroup(body)) + Ok(GetEditgroupAnnotationsResponse::Success(body)) } 400 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - Ok(UpdateEditgroupResponse::BadRequest(body)) + Ok(GetEditgroupAnnotationsResponse::BadRequest(body)) } 401 => { let mut buf = String::new(); @@ -2437,7 +2663,7 @@ impl Api for Client { .get::<ResponseWwwAuthenticate>() .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - Ok(UpdateEditgroupResponse::NotAuthorized { + Ok(GetEditgroupAnnotationsResponse::NotAuthorized { body: body, www_authenticate: response_www_authenticate.0.clone(), }) @@ -2447,21 +2673,21 @@ impl Api for Client { 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(UpdateEditgroupResponse::Forbidden(body)) + Ok(GetEditgroupAnnotationsResponse::Forbidden(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(UpdateEditgroupResponse::NotFound(body)) + Ok(GetEditgroupAnnotationsResponse::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(UpdateEditgroupResponse::GenericError(body)) + Ok(GetEditgroupAnnotationsResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2481,78 +2707,67 @@ impl Api for Client { Box::new(futures::done(result)) } - fn update_editor(&self, param_editor_id: String, param_editor: models::Editor, context: &Context) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send> { + fn get_editgroups_reviewable( + &self, + param_expand: Option<String>, + param_limit: Option<i64>, + param_before: Option<chrono::DateTime<chrono::Utc>>, + param_since: Option<chrono::DateTime<chrono::Utc>>, + context: &Context, + ) -> Box<Future<Item = GetEditgroupsReviewableResponse, Error = ApiError> + Send> { + // Query parameters + let query_expand = param_expand.map_or_else(String::new, |query| format!("expand={expand}&", expand = query.to_string())); + let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + let query_before = param_before.map_or_else(String::new, |query| format!("before={before}&", before = query.to_string())); + let query_since = param_since.map_or_else(String::new, |query| format!("since={since}&", since = query.to_string())); + let url = format!( - "{}/v0/editor/{editor_id}", + "{}/v0/editgroup/reviewable?{expand}{limit}{before}{since}", self.base_path, - editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_ENCODE_SET) + expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET), + limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET), + before = utf8_percent_encode(&query_before, QUERY_ENCODE_SET), + since = utf8_percent_encode(&query_since, QUERY_ENCODE_SET) ); - let body = serde_json::to_string(¶m_editor).expect("impossible to fail to serialize"); - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Put, &url); + let request = hyper_client.request(hyper::method::Method::Get, &url); let mut custom_headers = hyper::header::Headers::new(); - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::UPDATE_EDITOR.clone())); 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<UpdateEditorResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<GetEditgroupsReviewableResponse, ApiError> { match response.status.to_u16() { 200 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::Editor>(&buf)?; + let body = serde_json::from_str::<Vec<models::Editgroup>>(&buf)?; - Ok(UpdateEditorResponse::UpdatedEditor(body)) + Ok(GetEditgroupsReviewableResponse::Found(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(UpdateEditorResponse::BadRequest(body)) - } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::<ResponseWwwAuthenticate>() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(UpdateEditorResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } - 403 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - - Ok(UpdateEditorResponse::Forbidden(body)) + Ok(GetEditgroupsReviewableResponse::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(UpdateEditorResponse::NotFound(body)) + Ok(GetEditgroupsReviewableResponse::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(UpdateEditorResponse::GenericError(body)) + Ok(GetEditgroupsReviewableResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2572,37 +2787,52 @@ impl Api for Client { Box::new(futures::done(result)) } - fn accept_editgroup(&self, param_editgroup_id: String, context: &Context) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> { + fn update_editgroup( + &self, + param_editgroup_id: String, + param_editgroup: models::Editgroup, + param_submit: Option<bool>, + context: &Context, + ) -> Box<Future<Item = UpdateEditgroupResponse, Error = ApiError> + Send> { + // Query parameters + let query_submit = param_submit.map_or_else(String::new, |query| format!("submit={submit}&", submit = query.to_string())); + let url = format!( - "{}/v0/editgroup/{editgroup_id}/accept", + "{}/v0/editgroup/{editgroup_id}?{submit}", self.base_path, - editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET) + editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET), + submit = utf8_percent_encode(&query_submit, QUERY_ENCODE_SET) ); + let body = serde_json::to_string(¶m_editgroup).expect("impossible to fail to serialize"); + let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); + let request = hyper_client.request(hyper::method::Method::Put, &url); let mut custom_headers = hyper::header::Headers::new(); + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::UPDATE_EDITGROUP.clone())); 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<AcceptEditgroupResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<UpdateEditgroupResponse, ApiError> { match response.status.to_u16() { 200 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::Success>(&buf)?; + let body = serde_json::from_str::<models::Editgroup>(&buf)?; - Ok(AcceptEditgroupResponse::MergedSuccessfully(body)) + Ok(UpdateEditgroupResponse::UpdatedEditgroup(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(AcceptEditgroupResponse::BadRequest(body)) + Ok(UpdateEditgroupResponse::BadRequest(body)) } 401 => { let mut buf = String::new(); @@ -2614,7 +2844,7 @@ impl Api for Client { .get::<ResponseWwwAuthenticate>() .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - Ok(AcceptEditgroupResponse::NotAuthorized { + Ok(UpdateEditgroupResponse::NotAuthorized { body: body, www_authenticate: response_www_authenticate.0.clone(), }) @@ -2624,28 +2854,21 @@ impl Api for Client { 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(AcceptEditgroupResponse::Forbidden(body)) + Ok(UpdateEditgroupResponse::Forbidden(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(AcceptEditgroupResponse::NotFound(body)) - } - 409 => { - 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(AcceptEditgroupResponse::EditConflict(body)) + Ok(UpdateEditgroupResponse::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(AcceptEditgroupResponse::GenericError(body)) + Ok(UpdateEditgroupResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2665,74 +2888,51 @@ impl Api for Client { Box::new(futures::done(result)) } - fn create_editgroup(&self, param_editgroup: models::Editgroup, context: &Context) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> { - let url = format!("{}/v0/editgroup", self.base_path); - - let body = serde_json::to_string(¶m_editgroup).expect("impossible to fail to serialize"); + fn get_editor(&self, param_editor_id: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> { + let url = format!( + "{}/v0/editor/{editor_id}", + self.base_path, + editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); + let request = hyper_client.request(hyper::method::Method::Get, &url); let mut custom_headers = hyper::header::Headers::new(); - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::CREATE_EDITGROUP.clone())); 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<CreateEditgroupResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<GetEditorResponse, ApiError> { match response.status.to_u16() { - 201 => { + 200 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::Editgroup>(&buf)?; + let body = serde_json::from_str::<models::Editor>(&buf)?; - Ok(CreateEditgroupResponse::SuccessfullyCreated(body)) + Ok(GetEditorResponse::Found(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(CreateEditgroupResponse::BadRequest(body)) - } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::<ResponseWwwAuthenticate>() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(CreateEditgroupResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } - 403 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - - Ok(CreateEditgroupResponse::Forbidden(body)) + Ok(GetEditorResponse::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(CreateEditgroupResponse::NotFound(body)) + Ok(GetEditorResponse::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(CreateEditgroupResponse::GenericError(body)) + Ok(GetEditorResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2752,47 +2952,52 @@ impl Api for Client { Box::new(futures::done(result)) } - fn create_editgroup_annotation( + fn get_editor_annotations( &self, - param_editgroup_id: String, - param_annotation: models::EditgroupAnnotation, + param_editor_id: String, + param_limit: Option<i64>, + param_before: Option<chrono::DateTime<chrono::Utc>>, + param_since: Option<chrono::DateTime<chrono::Utc>>, context: &Context, - ) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send> { + ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send> { + // Query parameters + let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + let query_before = param_before.map_or_else(String::new, |query| format!("before={before}&", before = query.to_string())); + let query_since = param_since.map_or_else(String::new, |query| format!("since={since}&", since = query.to_string())); + let url = format!( - "{}/v0/editgroup/{editgroup_id}/annotation", + "{}/v0/editor/{editor_id}/annotations?{limit}{before}{since}", self.base_path, - editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET) + editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_ENCODE_SET), + limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET), + before = utf8_percent_encode(&query_before, QUERY_ENCODE_SET), + since = utf8_percent_encode(&query_since, QUERY_ENCODE_SET) ); - let body = serde_json::to_string(¶m_annotation).expect("impossible to fail to serialize"); - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); + let request = hyper_client.request(hyper::method::Method::Get, &url); let mut custom_headers = hyper::header::Headers::new(); - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::CREATE_EDITGROUP_ANNOTATION.clone())); 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<CreateEditgroupAnnotationResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<GetEditorAnnotationsResponse, ApiError> { match response.status.to_u16() { - 201 => { + 200 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::EditgroupAnnotation>(&buf)?; + let body = serde_json::from_str::<Vec<models::EditgroupAnnotation>>(&buf)?; - Ok(CreateEditgroupAnnotationResponse::Created(body)) + Ok(GetEditorAnnotationsResponse::Success(body)) } 400 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - Ok(CreateEditgroupAnnotationResponse::BadRequest(body)) + Ok(GetEditorAnnotationsResponse::BadRequest(body)) } 401 => { let mut buf = String::new(); @@ -2804,7 +3009,7 @@ impl Api for Client { .get::<ResponseWwwAuthenticate>() .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - Ok(CreateEditgroupAnnotationResponse::NotAuthorized { + Ok(GetEditorAnnotationsResponse::NotAuthorized { body: body, www_authenticate: response_www_authenticate.0.clone(), }) @@ -2814,21 +3019,21 @@ impl Api for Client { 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(CreateEditgroupAnnotationResponse::Forbidden(body)) + Ok(GetEditorAnnotationsResponse::Forbidden(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(CreateEditgroupAnnotationResponse::NotFound(body)) + Ok(GetEditorAnnotationsResponse::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(CreateEditgroupAnnotationResponse::GenericError(body)) + Ok(GetEditorAnnotationsResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2848,67 +3053,26 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_changelog(&self, param_limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> { + fn get_editor_editgroups( + &self, + param_editor_id: String, + param_limit: Option<i64>, + param_before: Option<chrono::DateTime<chrono::Utc>>, + param_since: Option<chrono::DateTime<chrono::Utc>>, + context: &Context, + ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send> { // Query parameters let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + let query_before = param_before.map_or_else(String::new, |query| format!("before={before}&", before = query.to_string())); + let query_since = param_since.map_or_else(String::new, |query| format!("since={since}&", since = query.to_string())); - let url = format!("{}/v0/changelog?{limit}", self.base_path, 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<GetChangelogResponse, 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::ChangelogEntry>>(&buf)?; - - Ok(GetChangelogResponse::Success(body)) - } - 400 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - - Ok(GetChangelogResponse::BadRequest(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(GetChangelogResponse::GenericError(body)) - } - code => { - let mut buf = [0; 100]; - let debug_body = match response.read(&mut buf) { - Ok(len) => match str::from_utf8(&buf[..len]) { - Ok(body) => Cow::from(body), - Err(_) => Cow::from(format!("<Body was not UTF8: {:?}>", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("<Failed to read body: {}>", e)), - }; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) - } - } - } - - let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); - Box::new(futures::done(result)) - } - - fn get_changelog_entry(&self, param_index: i64, context: &Context) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> { let url = format!( - "{}/v0/changelog/{index}", + "{}/v0/editor/{editor_id}/editgroups?{limit}{before}{since}", self.base_path, - index = utf8_percent_encode(¶m_index.to_string(), PATH_SEGMENT_ENCODE_SET) + editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_ENCODE_SET), + limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET), + before = utf8_percent_encode(&query_before, QUERY_ENCODE_SET), + since = utf8_percent_encode(&query_since, QUERY_ENCODE_SET) ); let hyper_client = (self.hyper_client)(); @@ -2920,35 +3084,35 @@ impl Api for Client { 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<GetChangelogEntryResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<GetEditorEditgroupsResponse, ApiError> { match response.status.to_u16() { 200 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ChangelogEntry>(&buf)?; + let body = serde_json::from_str::<Vec<models::Editgroup>>(&buf)?; - Ok(GetChangelogEntryResponse::FoundChangelogEntry(body)) + Ok(GetEditorEditgroupsResponse::Found(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(GetChangelogEntryResponse::BadRequest(body)) + Ok(GetEditorEditgroupsResponse::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(GetChangelogEntryResponse::NotFound(body)) + Ok(GetEditorEditgroupsResponse::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(GetChangelogEntryResponse::GenericError(body)) + Ok(GetEditorEditgroupsResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2968,206 +3132,42 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_editgroup(&self, param_editgroup_id: String, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> { + fn update_editor(&self, param_editor_id: String, param_editor: models::Editor, context: &Context) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send> { let url = format!( - "{}/v0/editgroup/{editgroup_id}", + "{}/v0/editor/{editor_id}", self.base_path, - editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET) + editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_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<GetEditgroupResponse, ApiError> { - match response.status.to_u16() { - 200 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::Editgroup>(&buf)?; - - Ok(GetEditgroupResponse::Found(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(GetEditgroupResponse::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(GetEditgroupResponse::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(GetEditgroupResponse::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_editgroup_annotations(&self, param_editgroup_id: String, param_expand: Option<String>, context: &Context) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send> { - // Query parameters - let query_expand = param_expand.map_or_else(String::new, |query| format!("expand={expand}&", expand = query.to_string())); - - let url = format!( - "{}/v0/editgroup/{editgroup_id}/annotations?{expand}", - self.base_path, - editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET), - expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET) - ); + let body = serde_json::to_string(¶m_editor).expect("impossible to fail to serialize"); let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Get, &url); + let request = hyper_client.request(hyper::method::Method::Put, &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<GetEditgroupAnnotationsResponse, 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::EditgroupAnnotation>>(&buf)?; - - Ok(GetEditgroupAnnotationsResponse::Success(body)) - } - 400 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - - Ok(GetEditgroupAnnotationsResponse::BadRequest(body)) - } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::<ResponseWwwAuthenticate>() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(GetEditgroupAnnotationsResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } - 403 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - - Ok(GetEditgroupAnnotationsResponse::Forbidden(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(GetEditgroupAnnotationsResponse::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(GetEditgroupAnnotationsResponse::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_editor_annotations( - &self, - param_editor_id: String, - param_limit: Option<i64>, - param_before: Option<chrono::DateTime<chrono::Utc>>, - param_since: Option<chrono::DateTime<chrono::Utc>>, - context: &Context, - ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send> { - // Query parameters - let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); - let query_before = param_before.map_or_else(String::new, |query| format!("before={before}&", before = query.to_string())); - let query_since = param_since.map_or_else(String::new, |query| format!("since={since}&", since = query.to_string())); - - let url = format!( - "{}/v0/editor/{editor_id}/annotations?{limit}{before}{since}", - self.base_path, - editor_id = utf8_percent_encode(¶m_editor_id.to_string(), PATH_SEGMENT_ENCODE_SET), - limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET), - before = utf8_percent_encode(&query_before, QUERY_ENCODE_SET), - since = utf8_percent_encode(&query_since, 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(); + let request = request.body(&body); + custom_headers.set(ContentType(mimetypes::requests::UPDATE_EDITOR.clone())); 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<GetEditorAnnotationsResponse, ApiError> { + fn parse_response(mut response: hyper::client::response::Response) -> Result<UpdateEditorResponse, 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::EditgroupAnnotation>>(&buf)?; + let body = serde_json::from_str::<models::Editor>(&buf)?; - Ok(GetEditorAnnotationsResponse::Success(body)) + Ok(UpdateEditorResponse::UpdatedEditor(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(GetEditorAnnotationsResponse::BadRequest(body)) + Ok(UpdateEditorResponse::BadRequest(body)) } 401 => { let mut buf = String::new(); @@ -3179,7 +3179,7 @@ impl Api for Client { .get::<ResponseWwwAuthenticate>() .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - Ok(GetEditorAnnotationsResponse::NotAuthorized { + Ok(UpdateEditorResponse::NotAuthorized { body: body, www_authenticate: response_www_authenticate.0.clone(), }) @@ -3189,21 +3189,21 @@ impl Api for Client { 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(GetEditorAnnotationsResponse::Forbidden(body)) + Ok(UpdateEditorResponse::Forbidden(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(GetEditorAnnotationsResponse::NotFound(body)) + Ok(UpdateEditorResponse::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(GetEditorAnnotationsResponse::GenericError(body)) + Ok(UpdateEditorResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -5062,97 +5062,6 @@ impl Api for Client { Box::new(futures::done(result)) } - fn create_work(&self, param_editgroup_id: String, param_entity: models::WorkEntity, context: &Context) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send> { - let url = format!( - "{}/v0/editgroup/{editgroup_id}/work", - self.base_path, - editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET) - ); - - let body = serde_json::to_string(¶m_entity).expect("impossible to fail to serialize"); - - let hyper_client = (self.hyper_client)(); - let request = hyper_client.request(hyper::method::Method::Post, &url); - let mut custom_headers = hyper::header::Headers::new(); - - let request = request.body(&body); - - custom_headers.set(ContentType(mimetypes::requests::CREATE_WORK.clone())); - 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<CreateWorkResponse, ApiError> { - match response.status.to_u16() { - 201 => { - 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::EntityEdit>(&buf)?; - - Ok(CreateWorkResponse::CreatedEntity(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(CreateWorkResponse::BadRequest(body)) - } - 401 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - let response_www_authenticate = response - .headers - .get::<ResponseWwwAuthenticate>() - .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; - - Ok(CreateWorkResponse::NotAuthorized { - body: body, - www_authenticate: response_www_authenticate.0.clone(), - }) - } - 403 => { - let mut buf = String::new(); - response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; - - Ok(CreateWorkResponse::Forbidden(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(CreateWorkResponse::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(CreateWorkResponse::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 delete_release(&self, param_editgroup_id: String, param_ident: String, context: &Context) -> Box<Future<Item = DeleteReleaseResponse, Error = ApiError> + Send> { let url = format!( "{}/v0/editgroup/{editgroup_id}/release/{ident}", @@ -6867,6 +6776,97 @@ impl Api for Client { Box::new(futures::done(result)) } + fn create_work(&self, param_editgroup_id: String, param_entity: models::WorkEntity, context: &Context) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send> { + let url = format!( + "{}/v0/editgroup/{editgroup_id}/work", + self.base_path, + editgroup_id = utf8_percent_encode(¶m_editgroup_id.to_string(), PATH_SEGMENT_ENCODE_SET) + ); + + let body = serde_json::to_string(¶m_entity).expect("impossible to fail to serialize"); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Post, &url); + let mut custom_headers = hyper::header::Headers::new(); + + let request = request.body(&body); + + custom_headers.set(ContentType(mimetypes::requests::CREATE_WORK.clone())); + 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<CreateWorkResponse, ApiError> { + match response.status.to_u16() { + 201 => { + 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::EntityEdit>(&buf)?; + + Ok(CreateWorkResponse::CreatedEntity(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(CreateWorkResponse::BadRequest(body)) + } + 401 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + let response_www_authenticate = response + .headers + .get::<ResponseWwwAuthenticate>() + .ok_or_else(|| "Required response header WWW_Authenticate for response 401 was not found.")?; + + Ok(CreateWorkResponse::NotAuthorized { + body: body, + www_authenticate: response_www_authenticate.0.clone(), + }) + } + 403 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::<models::ErrorResponse>(&buf)?; + + Ok(CreateWorkResponse::Forbidden(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(CreateWorkResponse::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(CreateWorkResponse::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 create_work_auto_batch(&self, param_auto_batch: models::WorkAutoBatch, context: &Context) -> Box<Future<Item = CreateWorkAutoBatchResponse, Error = ApiError> + Send> { let url = format!("{}/v0/editgroup/auto/work/batch", self.base_path); diff --git a/rust/fatcat-openapi/src/lib.rs b/rust/fatcat-openapi/src/lib.rs index b19b5793..da4f23af 100644 --- a/rust/fatcat-openapi/src/lib.rs +++ b/rust/fatcat-openapi/src/lib.rs @@ -33,6 +33,60 @@ mod mimetypes; pub use swagger::{ApiError, Context, ContextWrapper}; #[derive(Debug, PartialEq)] +pub enum AuthCheckResponse { + /// Success + Success(models::Success), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum AuthOidcResponse { + /// Found + Found(models::AuthOidcResult), + /// Created + Created(models::AuthOidcResult), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), + /// Conflict + Conflict(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum GetChangelogResponse { + /// Success + Success(Vec<models::ChangelogEntry>), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum GetChangelogEntryResponse { + /// Found Changelog Entry + FoundChangelogEntry(models::ChangelogEntry), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] pub enum CreateContainerResponse { /// Created Entity CreatedEntity(models::EntityEdit), @@ -349,43 +403,33 @@ pub enum UpdateCreatorResponse { } #[derive(Debug, PartialEq)] -pub enum AuthCheckResponse { - /// Success - Success(models::Success), +pub enum AcceptEditgroupResponse { + /// Merged Successfully + MergedSuccessfully(models::Success), /// Bad Request BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Forbidden Forbidden(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Edit Conflict + EditConflict(models::ErrorResponse), /// Generic Error GenericError(models::ErrorResponse), } #[derive(Debug, PartialEq)] -pub enum AuthOidcResponse { - /// Found - Found(models::AuthOidcResult), - /// Created - Created(models::AuthOidcResult), +pub enum CreateEditgroupResponse { + /// Successfully Created + SuccessfullyCreated(models::Editgroup), /// Bad Request BadRequest(models::ErrorResponse), /// Not Authorized NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, /// Forbidden Forbidden(models::ErrorResponse), - /// Conflict - Conflict(models::ErrorResponse), - /// Generic Error - GenericError(models::ErrorResponse), -} - -#[derive(Debug, PartialEq)] -pub enum GetEditgroupsReviewableResponse { - /// Found - Found(Vec<models::Editgroup>), - /// Bad Request - BadRequest(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -393,11 +437,15 @@ pub enum GetEditgroupsReviewableResponse { } #[derive(Debug, PartialEq)] -pub enum GetEditorResponse { - /// Found - Found(models::Editor), +pub enum CreateEditgroupAnnotationResponse { + /// Created + Created(models::EditgroupAnnotation), /// Bad Request BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -405,9 +453,9 @@ pub enum GetEditorResponse { } #[derive(Debug, PartialEq)] -pub enum GetEditorEditgroupsResponse { +pub enum GetEditgroupResponse { /// Found - Found(Vec<models::Editgroup>), + Found(models::Editgroup), /// Bad Request BadRequest(models::ErrorResponse), /// Not Found @@ -417,9 +465,9 @@ pub enum GetEditorEditgroupsResponse { } #[derive(Debug, PartialEq)] -pub enum UpdateEditgroupResponse { - /// Updated Editgroup - UpdatedEditgroup(models::Editgroup), +pub enum GetEditgroupAnnotationsResponse { + /// Success + Success(Vec<models::EditgroupAnnotation>), /// Bad Request BadRequest(models::ErrorResponse), /// Not Authorized @@ -433,15 +481,11 @@ pub enum UpdateEditgroupResponse { } #[derive(Debug, PartialEq)] -pub enum UpdateEditorResponse { - /// Updated Editor - UpdatedEditor(models::Editor), +pub enum GetEditgroupsReviewableResponse { + /// Found + Found(Vec<models::Editgroup>), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, - /// Forbidden - Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -449,9 +493,9 @@ pub enum UpdateEditorResponse { } #[derive(Debug, PartialEq)] -pub enum AcceptEditgroupResponse { - /// Merged Successfully - MergedSuccessfully(models::Success), +pub enum UpdateEditgroupResponse { + /// Updated Editgroup + UpdatedEditgroup(models::Editgroup), /// Bad Request BadRequest(models::ErrorResponse), /// Not Authorized @@ -460,22 +504,16 @@ pub enum AcceptEditgroupResponse { Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), - /// Edit Conflict - EditConflict(models::ErrorResponse), /// Generic Error GenericError(models::ErrorResponse), } #[derive(Debug, PartialEq)] -pub enum CreateEditgroupResponse { - /// Successfully Created - SuccessfullyCreated(models::Editgroup), +pub enum GetEditorResponse { + /// Found + Found(models::Editor), /// Bad Request BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, - /// Forbidden - Forbidden(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error @@ -483,9 +521,9 @@ pub enum CreateEditgroupResponse { } #[derive(Debug, PartialEq)] -pub enum CreateEditgroupAnnotationResponse { - /// Created - Created(models::EditgroupAnnotation), +pub enum GetEditorAnnotationsResponse { + /// Success + Success(Vec<models::EditgroupAnnotation>), /// Bad Request BadRequest(models::ErrorResponse), /// Not Authorized @@ -499,31 +537,9 @@ pub enum CreateEditgroupAnnotationResponse { } #[derive(Debug, PartialEq)] -pub enum GetChangelogResponse { - /// Success - Success(Vec<models::ChangelogEntry>), - /// Bad Request - BadRequest(models::ErrorResponse), - /// Generic Error - GenericError(models::ErrorResponse), -} - -#[derive(Debug, PartialEq)] -pub enum GetChangelogEntryResponse { - /// Found Changelog Entry - FoundChangelogEntry(models::ChangelogEntry), - /// Bad Request - BadRequest(models::ErrorResponse), - /// Not Found - NotFound(models::ErrorResponse), - /// Generic Error - GenericError(models::ErrorResponse), -} - -#[derive(Debug, PartialEq)] -pub enum GetEditgroupResponse { +pub enum GetEditorEditgroupsResponse { /// Found - Found(models::Editgroup), + Found(Vec<models::Editgroup>), /// Bad Request BadRequest(models::ErrorResponse), /// Not Found @@ -533,25 +549,9 @@ pub enum GetEditgroupResponse { } #[derive(Debug, PartialEq)] -pub enum GetEditgroupAnnotationsResponse { - /// Success - Success(Vec<models::EditgroupAnnotation>), - /// Bad Request - BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, - /// Forbidden - Forbidden(models::ErrorResponse), - /// Not Found - NotFound(models::ErrorResponse), - /// Generic Error - GenericError(models::ErrorResponse), -} - -#[derive(Debug, PartialEq)] -pub enum GetEditorAnnotationsResponse { - /// Success - Success(Vec<models::EditgroupAnnotation>), +pub enum UpdateEditorResponse { + /// Updated Editor + UpdatedEditor(models::Editor), /// Bad Request BadRequest(models::ErrorResponse), /// Not Authorized @@ -889,22 +889,6 @@ pub enum CreateReleaseAutoBatchResponse { } #[derive(Debug, PartialEq)] -pub enum CreateWorkResponse { - /// Created Entity - CreatedEntity(models::EntityEdit), - /// Bad Request - BadRequest(models::ErrorResponse), - /// Not Authorized - NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, - /// Forbidden - Forbidden(models::ErrorResponse), - /// Not Found - NotFound(models::ErrorResponse), - /// Generic Error - GenericError(models::ErrorResponse), -} - -#[derive(Debug, PartialEq)] pub enum DeleteReleaseResponse { /// Deleted Entity DeletedEntity(models::EntityEdit), @@ -1201,6 +1185,22 @@ pub enum UpdateWebcaptureResponse { } #[derive(Debug, PartialEq)] +pub enum CreateWorkResponse { + /// Created Entity + CreatedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Authorized + NotAuthorized { body: models::ErrorResponse, www_authenticate: String }, + /// Forbidden + Forbidden(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] pub enum CreateWorkAutoBatchResponse { /// Created Editgroup CreatedEditgroup(models::Editgroup), @@ -1338,6 +1338,14 @@ pub enum UpdateWorkResponse { /// API pub trait Api { + fn auth_check(&self, role: Option<String>, context: &Context) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send>; + + fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send>; + + fn get_changelog(&self, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send>; + + fn get_changelog_entry(&self, index: i64, context: &Context) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send>; + fn create_container(&self, editgroup_id: String, entity: models::ContainerEntity, context: &Context) -> Box<Future<Item = CreateContainerResponse, Error = ApiError> + Send>; fn create_container_auto_batch(&self, auto_batch: models::ContainerAutoBatch, context: &Context) -> Box<Future<Item = CreateContainerAutoBatchResponse, Error = ApiError> + Send>; @@ -1398,9 +1406,20 @@ pub trait Api { fn update_creator(&self, editgroup_id: String, ident: String, entity: models::CreatorEntity, context: &Context) -> Box<Future<Item = UpdateCreatorResponse, Error = ApiError> + Send>; - fn auth_check(&self, role: Option<String>, context: &Context) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send>; + fn accept_editgroup(&self, editgroup_id: String, context: &Context) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send>; - fn auth_oidc(&self, oidc_params: models::AuthOidc, context: &Context) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send>; + fn create_editgroup(&self, editgroup: models::Editgroup, context: &Context) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send>; + + fn create_editgroup_annotation( + &self, + editgroup_id: String, + annotation: models::EditgroupAnnotation, + context: &Context, + ) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send>; + + fn get_editgroup(&self, editgroup_id: String, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send>; + + fn get_editgroup_annotations(&self, editgroup_id: String, expand: Option<String>, context: &Context) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send>; fn get_editgroups_reviewable( &self, @@ -1411,48 +1430,29 @@ pub trait Api { context: &Context, ) -> Box<Future<Item = GetEditgroupsReviewableResponse, Error = ApiError> + Send>; + fn update_editgroup(&self, editgroup_id: String, editgroup: models::Editgroup, submit: Option<bool>, context: &Context) -> Box<Future<Item = UpdateEditgroupResponse, Error = ApiError> + Send>; + fn get_editor(&self, editor_id: String, context: &Context) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send>; - fn get_editor_editgroups( + fn get_editor_annotations( &self, editor_id: String, limit: Option<i64>, before: Option<chrono::DateTime<chrono::Utc>>, since: Option<chrono::DateTime<chrono::Utc>>, context: &Context, - ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send>; - - fn update_editgroup(&self, editgroup_id: String, editgroup: models::Editgroup, submit: Option<bool>, context: &Context) -> Box<Future<Item = UpdateEditgroupResponse, Error = ApiError> + Send>; - - fn update_editor(&self, editor_id: String, editor: models::Editor, context: &Context) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send>; - - fn accept_editgroup(&self, editgroup_id: String, context: &Context) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send>; - - fn create_editgroup(&self, editgroup: models::Editgroup, context: &Context) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send>; - - fn create_editgroup_annotation( - &self, - editgroup_id: String, - annotation: models::EditgroupAnnotation, - context: &Context, - ) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send>; - - fn get_changelog(&self, limit: Option<i64>, context: &Context) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send>; - - fn get_changelog_entry(&self, index: i64, context: &Context) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send>; - - fn get_editgroup(&self, editgroup_id: String, context: &Context) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send>; - - fn get_editgroup_annotations(&self, editgroup_id: String, expand: Option<String>, context: &Context) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send>; + ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send>; - fn get_editor_annotations( + fn get_editor_editgroups( &self, editor_id: String, limit: Option<i64>, before: Option<chrono::DateTime<chrono::Utc>>, since: Option<chrono::DateTime<chrono::Utc>>, context: &Context, - ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send>; + ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send>; + + fn update_editor(&self, editor_id: String, editor: models::Editor, context: &Context) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send>; fn create_file(&self, editgroup_id: String, entity: models::FileEntity, context: &Context) -> Box<Future<Item = CreateFileResponse, Error = ApiError> + Send>; @@ -1508,8 +1508,6 @@ pub trait Api { fn create_release_auto_batch(&self, auto_batch: models::ReleaseAutoBatch, context: &Context) -> Box<Future<Item = CreateReleaseAutoBatchResponse, Error = ApiError> + Send>; - fn create_work(&self, editgroup_id: String, entity: models::WorkEntity, context: &Context) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send>; - fn delete_release(&self, editgroup_id: String, ident: String, context: &Context) -> Box<Future<Item = DeleteReleaseResponse, Error = ApiError> + Send>; fn delete_release_edit(&self, editgroup_id: String, edit_id: String, context: &Context) -> Box<Future<Item = DeleteReleaseEditResponse, Error = ApiError> + Send>; @@ -1569,6 +1567,8 @@ pub trait Api { fn update_webcapture(&self, editgroup_id: String, ident: String, entity: models::WebcaptureEntity, context: &Context) -> Box<Future<Item = UpdateWebcaptureResponse, Error = ApiError> + Send>; + fn create_work(&self, editgroup_id: String, entity: models::WorkEntity, context: &Context) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send>; + fn create_work_auto_batch(&self, auto_batch: models::WorkAutoBatch, context: &Context) -> Box<Future<Item = CreateWorkAutoBatchResponse, Error = ApiError> + Send>; fn delete_work(&self, editgroup_id: String, ident: String, context: &Context) -> Box<Future<Item = DeleteWorkResponse, Error = ApiError> + Send>; @@ -1592,6 +1592,14 @@ pub trait Api { /// API without a `Context` pub trait ApiNoContext { + fn auth_check(&self, role: Option<String>) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send>; + + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send>; + + fn get_changelog(&self, limit: Option<i64>) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send>; + + fn get_changelog_entry(&self, index: i64) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send>; + fn create_container(&self, editgroup_id: String, entity: models::ContainerEntity) -> Box<Future<Item = CreateContainerResponse, Error = ApiError> + Send>; fn create_container_auto_batch(&self, auto_batch: models::ContainerAutoBatch) -> Box<Future<Item = CreateContainerAutoBatchResponse, Error = ApiError> + Send>; @@ -1644,9 +1652,15 @@ pub trait ApiNoContext { fn update_creator(&self, editgroup_id: String, ident: String, entity: models::CreatorEntity) -> Box<Future<Item = UpdateCreatorResponse, Error = ApiError> + Send>; - fn auth_check(&self, role: Option<String>) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send>; + fn accept_editgroup(&self, editgroup_id: String) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send>; - fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send>; + fn create_editgroup(&self, editgroup: models::Editgroup) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send>; + + fn create_editgroup_annotation(&self, editgroup_id: String, annotation: models::EditgroupAnnotation) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send>; + + fn get_editgroup(&self, editgroup_id: String) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send>; + + fn get_editgroup_annotations(&self, editgroup_id: String, expand: Option<String>) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send>; fn get_editgroups_reviewable( &self, @@ -1656,41 +1670,27 @@ pub trait ApiNoContext { since: Option<chrono::DateTime<chrono::Utc>>, ) -> Box<Future<Item = GetEditgroupsReviewableResponse, Error = ApiError> + Send>; + fn update_editgroup(&self, editgroup_id: String, editgroup: models::Editgroup, submit: Option<bool>) -> Box<Future<Item = UpdateEditgroupResponse, Error = ApiError> + Send>; + fn get_editor(&self, editor_id: String) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send>; - fn get_editor_editgroups( + fn get_editor_annotations( &self, editor_id: String, limit: Option<i64>, before: Option<chrono::DateTime<chrono::Utc>>, since: Option<chrono::DateTime<chrono::Utc>>, - ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send>; - - fn update_editgroup(&self, editgroup_id: String, editgroup: models::Editgroup, submit: Option<bool>) -> Box<Future<Item = UpdateEditgroupResponse, Error = ApiError> + Send>; - - fn update_editor(&self, editor_id: String, editor: models::Editor) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send>; - - fn accept_editgroup(&self, editgroup_id: String) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send>; - - fn create_editgroup(&self, editgroup: models::Editgroup) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send>; - - fn create_editgroup_annotation(&self, editgroup_id: String, annotation: models::EditgroupAnnotation) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send>; - - fn get_changelog(&self, limit: Option<i64>) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send>; - - fn get_changelog_entry(&self, index: i64) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send>; - - fn get_editgroup(&self, editgroup_id: String) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send>; - - fn get_editgroup_annotations(&self, editgroup_id: String, expand: Option<String>) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send>; + ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send>; - fn get_editor_annotations( + fn get_editor_editgroups( &self, editor_id: String, limit: Option<i64>, before: Option<chrono::DateTime<chrono::Utc>>, since: Option<chrono::DateTime<chrono::Utc>>, - ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send>; + ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send>; + + fn update_editor(&self, editor_id: String, editor: models::Editor) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send>; fn create_file(&self, editgroup_id: String, entity: models::FileEntity) -> Box<Future<Item = CreateFileResponse, Error = ApiError> + Send>; @@ -1745,8 +1745,6 @@ pub trait ApiNoContext { fn create_release_auto_batch(&self, auto_batch: models::ReleaseAutoBatch) -> Box<Future<Item = CreateReleaseAutoBatchResponse, Error = ApiError> + Send>; - fn create_work(&self, editgroup_id: String, entity: models::WorkEntity) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send>; - fn delete_release(&self, editgroup_id: String, ident: String) -> Box<Future<Item = DeleteReleaseResponse, Error = ApiError> + Send>; fn delete_release_edit(&self, editgroup_id: String, edit_id: String) -> Box<Future<Item = DeleteReleaseEditResponse, Error = ApiError> + Send>; @@ -1805,6 +1803,8 @@ pub trait ApiNoContext { fn update_webcapture(&self, editgroup_id: String, ident: String, entity: models::WebcaptureEntity) -> Box<Future<Item = UpdateWebcaptureResponse, Error = ApiError> + Send>; + fn create_work(&self, editgroup_id: String, entity: models::WorkEntity) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send>; + fn create_work_auto_batch(&self, auto_batch: models::WorkAutoBatch) -> Box<Future<Item = CreateWorkAutoBatchResponse, Error = ApiError> + Send>; fn delete_work(&self, editgroup_id: String, ident: String) -> Box<Future<Item = DeleteWorkResponse, Error = ApiError> + Send>; @@ -1842,6 +1842,22 @@ impl<'a, T: Api + Sized> ContextWrapperExt<'a> for T { } impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { + fn auth_check(&self, role: Option<String>) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send> { + self.api().auth_check(role, &self.context()) + } + + fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { + self.api().auth_oidc(oidc_params, &self.context()) + } + + fn get_changelog(&self, limit: Option<i64>) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> { + self.api().get_changelog(limit, &self.context()) + } + + fn get_changelog_entry(&self, index: i64) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> { + self.api().get_changelog_entry(index, &self.context()) + } + fn create_container(&self, editgroup_id: String, entity: models::ContainerEntity) -> Box<Future<Item = CreateContainerResponse, Error = ApiError> + Send> { self.api().create_container(editgroup_id, entity, &self.context()) } @@ -1940,12 +1956,24 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().update_creator(editgroup_id, ident, entity, &self.context()) } - fn auth_check(&self, role: Option<String>) -> Box<Future<Item = AuthCheckResponse, Error = ApiError> + Send> { - self.api().auth_check(role, &self.context()) + fn accept_editgroup(&self, editgroup_id: String) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> { + self.api().accept_editgroup(editgroup_id, &self.context()) } - fn auth_oidc(&self, oidc_params: models::AuthOidc) -> Box<Future<Item = AuthOidcResponse, Error = ApiError> + Send> { - self.api().auth_oidc(oidc_params, &self.context()) + fn create_editgroup(&self, editgroup: models::Editgroup) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> { + self.api().create_editgroup(editgroup, &self.context()) + } + + fn create_editgroup_annotation(&self, editgroup_id: String, annotation: models::EditgroupAnnotation) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send> { + self.api().create_editgroup_annotation(editgroup_id, annotation, &self.context()) + } + + fn get_editgroup(&self, editgroup_id: String) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> { + self.api().get_editgroup(editgroup_id, &self.context()) + } + + fn get_editgroup_annotations(&self, editgroup_id: String, expand: Option<String>) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send> { + self.api().get_editgroup_annotations(editgroup_id, expand, &self.context()) } fn get_editgroups_reviewable( @@ -1958,64 +1986,36 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().get_editgroups_reviewable(expand, limit, before, since, &self.context()) } + fn update_editgroup(&self, editgroup_id: String, editgroup: models::Editgroup, submit: Option<bool>) -> Box<Future<Item = UpdateEditgroupResponse, Error = ApiError> + Send> { + self.api().update_editgroup(editgroup_id, editgroup, submit, &self.context()) + } + fn get_editor(&self, editor_id: String) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> { self.api().get_editor(editor_id, &self.context()) } - fn get_editor_editgroups( + fn get_editor_annotations( &self, editor_id: String, limit: Option<i64>, before: Option<chrono::DateTime<chrono::Utc>>, since: Option<chrono::DateTime<chrono::Utc>>, - ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send> { - self.api().get_editor_editgroups(editor_id, limit, before, since, &self.context()) - } - - fn update_editgroup(&self, editgroup_id: String, editgroup: models::Editgroup, submit: Option<bool>) -> Box<Future<Item = UpdateEditgroupResponse, Error = ApiError> + Send> { - self.api().update_editgroup(editgroup_id, editgroup, submit, &self.context()) - } - - fn update_editor(&self, editor_id: String, editor: models::Editor) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send> { - self.api().update_editor(editor_id, editor, &self.context()) - } - - fn accept_editgroup(&self, editgroup_id: String) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> { - self.api().accept_editgroup(editgroup_id, &self.context()) - } - - fn create_editgroup(&self, editgroup: models::Editgroup) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> { - self.api().create_editgroup(editgroup, &self.context()) - } - - fn create_editgroup_annotation(&self, editgroup_id: String, annotation: models::EditgroupAnnotation) -> Box<Future<Item = CreateEditgroupAnnotationResponse, Error = ApiError> + Send> { - self.api().create_editgroup_annotation(editgroup_id, annotation, &self.context()) - } - - fn get_changelog(&self, limit: Option<i64>) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> { - self.api().get_changelog(limit, &self.context()) - } - - fn get_changelog_entry(&self, index: i64) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> { - self.api().get_changelog_entry(index, &self.context()) - } - - fn get_editgroup(&self, editgroup_id: String) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> { - self.api().get_editgroup(editgroup_id, &self.context()) - } - - fn get_editgroup_annotations(&self, editgroup_id: String, expand: Option<String>) -> Box<Future<Item = GetEditgroupAnnotationsResponse, Error = ApiError> + Send> { - self.api().get_editgroup_annotations(editgroup_id, expand, &self.context()) + ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send> { + self.api().get_editor_annotations(editor_id, limit, before, since, &self.context()) } - fn get_editor_annotations( + fn get_editor_editgroups( &self, editor_id: String, limit: Option<i64>, before: Option<chrono::DateTime<chrono::Utc>>, since: Option<chrono::DateTime<chrono::Utc>>, - ) -> Box<Future<Item = GetEditorAnnotationsResponse, Error = ApiError> + Send> { - self.api().get_editor_annotations(editor_id, limit, before, since, &self.context()) + ) -> Box<Future<Item = GetEditorEditgroupsResponse, Error = ApiError> + Send> { + self.api().get_editor_editgroups(editor_id, limit, before, since, &self.context()) + } + + fn update_editor(&self, editor_id: String, editor: models::Editor) -> Box<Future<Item = UpdateEditorResponse, Error = ApiError> + Send> { + self.api().update_editor(editor_id, editor, &self.context()) } fn create_file(&self, editgroup_id: String, entity: models::FileEntity) -> Box<Future<Item = CreateFileResponse, Error = ApiError> + Send> { @@ -2117,10 +2117,6 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().create_release_auto_batch(auto_batch, &self.context()) } - fn create_work(&self, editgroup_id: String, entity: models::WorkEntity) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send> { - self.api().create_work(editgroup_id, entity, &self.context()) - } - fn delete_release(&self, editgroup_id: String, ident: String) -> Box<Future<Item = DeleteReleaseResponse, Error = ApiError> + Send> { self.api().delete_release(editgroup_id, ident, &self.context()) } @@ -2224,6 +2220,10 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().update_webcapture(editgroup_id, ident, entity, &self.context()) } + fn create_work(&self, editgroup_id: String, entity: models::WorkEntity) -> Box<Future<Item = CreateWorkResponse, Error = ApiError> + Send> { + self.api().create_work(editgroup_id, entity, &self.context()) + } + fn create_work_auto_batch(&self, auto_batch: models::WorkAutoBatch) -> Box<Future<Item = CreateWorkAutoBatchResponse, Error = ApiError> + Send> { self.api().create_work_auto_batch(auto_batch, &self.context()) } diff --git a/rust/fatcat-openapi/src/mimetypes.rs b/rust/fatcat-openapi/src/mimetypes.rs index 0676f63b..ef297f69 100644 --- a/rust/fatcat-openapi/src/mimetypes.rs +++ b/rust/fatcat-openapi/src/mimetypes.rs @@ -4,6 +4,82 @@ pub mod responses { use hyper::mime::*; // The macro is called per-operation to beat the recursion limit + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_SUCCESS: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthCheck + lazy_static! { + pub static ref AUTH_CHECK_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_CREATED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_CONFLICT: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetChangelog + lazy_static! { + pub static ref GET_CHANGELOG_SUCCESS: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetChangelog + lazy_static! { + pub static ref GET_CHANGELOG_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetChangelog + lazy_static! { + pub static ref GET_CHANGELOG_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetChangelogEntry + lazy_static! { + pub static ref GET_CHANGELOG_ENTRY_FOUND_CHANGELOG_ENTRY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetChangelogEntry + lazy_static! { + pub static ref GET_CHANGELOG_ENTRY_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetChangelogEntry + lazy_static! { + pub static ref GET_CHANGELOG_ENTRY_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetChangelogEntry + lazy_static! { + pub static ref GET_CHANGELOG_ENTRY_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for CreateContainer lazy_static! { pub static ref CREATE_CONTAINER_CREATED_ENTITY: Mime = mime!(Application / Json); @@ -452,150 +528,6 @@ pub mod responses { lazy_static! { pub static ref UPDATE_CREATOR_GENERIC_ERROR: Mime = mime!(Application / Json); } - /// Create Mime objects for the response content types for AuthCheck - lazy_static! { - pub static ref AUTH_CHECK_SUCCESS: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthCheck - lazy_static! { - pub static ref AUTH_CHECK_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthCheck - lazy_static! { - pub static ref AUTH_CHECK_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthCheck - lazy_static! { - pub static ref AUTH_CHECK_FORBIDDEN: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthCheck - lazy_static! { - pub static ref AUTH_CHECK_GENERIC_ERROR: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthOidc - lazy_static! { - pub static ref AUTH_OIDC_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthOidc - lazy_static! { - pub static ref AUTH_OIDC_CREATED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthOidc - lazy_static! { - pub static ref AUTH_OIDC_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthOidc - lazy_static! { - pub static ref AUTH_OIDC_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthOidc - lazy_static! { - pub static ref AUTH_OIDC_FORBIDDEN: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthOidc - lazy_static! { - pub static ref AUTH_OIDC_CONFLICT: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for AuthOidc - lazy_static! { - pub static ref AUTH_OIDC_GENERIC_ERROR: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditgroupsReviewable - lazy_static! { - pub static ref GET_EDITGROUPS_REVIEWABLE_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditgroupsReviewable - lazy_static! { - pub static ref GET_EDITGROUPS_REVIEWABLE_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditgroupsReviewable - lazy_static! { - pub static ref GET_EDITGROUPS_REVIEWABLE_NOT_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditgroupsReviewable - lazy_static! { - pub static ref GET_EDITGROUPS_REVIEWABLE_GENERIC_ERROR: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditor - lazy_static! { - pub static ref GET_EDITOR_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditor - lazy_static! { - pub static ref GET_EDITOR_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditor - lazy_static! { - pub static ref GET_EDITOR_NOT_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditor - lazy_static! { - pub static ref GET_EDITOR_GENERIC_ERROR: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditorEditgroups - lazy_static! { - pub static ref GET_EDITOR_EDITGROUPS_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditorEditgroups - lazy_static! { - pub static ref GET_EDITOR_EDITGROUPS_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditorEditgroups - lazy_static! { - pub static ref GET_EDITOR_EDITGROUPS_NOT_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetEditorEditgroups - lazy_static! { - pub static ref GET_EDITOR_EDITGROUPS_GENERIC_ERROR: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditgroup - lazy_static! { - pub static ref UPDATE_EDITGROUP_UPDATED_EDITGROUP: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditgroup - lazy_static! { - pub static ref UPDATE_EDITGROUP_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditgroup - lazy_static! { - pub static ref UPDATE_EDITGROUP_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditgroup - lazy_static! { - pub static ref UPDATE_EDITGROUP_FORBIDDEN: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditgroup - lazy_static! { - pub static ref UPDATE_EDITGROUP_NOT_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditgroup - lazy_static! { - pub static ref UPDATE_EDITGROUP_GENERIC_ERROR: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditor - lazy_static! { - pub static ref UPDATE_EDITOR_UPDATED_EDITOR: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditor - lazy_static! { - pub static ref UPDATE_EDITOR_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditor - lazy_static! { - pub static ref UPDATE_EDITOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditor - lazy_static! { - pub static ref UPDATE_EDITOR_FORBIDDEN: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditor - lazy_static! { - pub static ref UPDATE_EDITOR_NOT_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for UpdateEditor - lazy_static! { - pub static ref UPDATE_EDITOR_GENERIC_ERROR: Mime = mime!(Application / Json); - } /// Create Mime objects for the response content types for AcceptEditgroup lazy_static! { pub static ref ACCEPT_EDITGROUP_MERGED_SUCCESSFULLY: Mime = mime!(Application / Json); @@ -672,34 +604,6 @@ pub mod responses { lazy_static! { pub static ref CREATE_EDITGROUP_ANNOTATION_GENERIC_ERROR: Mime = mime!(Application / Json); } - /// Create Mime objects for the response content types for GetChangelog - lazy_static! { - pub static ref GET_CHANGELOG_SUCCESS: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetChangelog - lazy_static! { - pub static ref GET_CHANGELOG_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetChangelog - lazy_static! { - pub static ref GET_CHANGELOG_GENERIC_ERROR: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetChangelogEntry - lazy_static! { - pub static ref GET_CHANGELOG_ENTRY_FOUND_CHANGELOG_ENTRY: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetChangelogEntry - lazy_static! { - pub static ref GET_CHANGELOG_ENTRY_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetChangelogEntry - lazy_static! { - pub static ref GET_CHANGELOG_ENTRY_NOT_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for GetChangelogEntry - lazy_static! { - pub static ref GET_CHANGELOG_ENTRY_GENERIC_ERROR: Mime = mime!(Application / Json); - } /// Create Mime objects for the response content types for GetEditgroup lazy_static! { pub static ref GET_EDITGROUP_FOUND: Mime = mime!(Application / Json); @@ -740,6 +644,62 @@ pub mod responses { lazy_static! { pub static ref GET_EDITGROUP_ANNOTATIONS_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for GetEditgroupsReviewable + lazy_static! { + pub static ref GET_EDITGROUPS_REVIEWABLE_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditgroupsReviewable + lazy_static! { + pub static ref GET_EDITGROUPS_REVIEWABLE_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditgroupsReviewable + lazy_static! { + pub static ref GET_EDITGROUPS_REVIEWABLE_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditgroupsReviewable + lazy_static! { + pub static ref GET_EDITGROUPS_REVIEWABLE_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditgroup + lazy_static! { + pub static ref UPDATE_EDITGROUP_UPDATED_EDITGROUP: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditgroup + lazy_static! { + pub static ref UPDATE_EDITGROUP_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditgroup + lazy_static! { + pub static ref UPDATE_EDITGROUP_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditgroup + lazy_static! { + pub static ref UPDATE_EDITGROUP_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditgroup + lazy_static! { + pub static ref UPDATE_EDITGROUP_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditgroup + lazy_static! { + pub static ref UPDATE_EDITGROUP_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditor + lazy_static! { + pub static ref GET_EDITOR_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditor + lazy_static! { + pub static ref GET_EDITOR_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditor + lazy_static! { + pub static ref GET_EDITOR_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditor + lazy_static! { + pub static ref GET_EDITOR_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for GetEditorAnnotations lazy_static! { pub static ref GET_EDITOR_ANNOTATIONS_SUCCESS: Mime = mime!(Application / Json); @@ -764,6 +724,46 @@ pub mod responses { lazy_static! { pub static ref GET_EDITOR_ANNOTATIONS_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for GetEditorEditgroups + lazy_static! { + pub static ref GET_EDITOR_EDITGROUPS_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditorEditgroups + lazy_static! { + pub static ref GET_EDITOR_EDITGROUPS_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditorEditgroups + lazy_static! { + pub static ref GET_EDITOR_EDITGROUPS_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for GetEditorEditgroups + lazy_static! { + pub static ref GET_EDITOR_EDITGROUPS_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_UPDATED_EDITOR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateEditor + lazy_static! { + pub static ref UPDATE_EDITOR_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for CreateFile lazy_static! { pub static ref CREATE_FILE_CREATED_ENTITY: Mime = mime!(Application / Json); @@ -1228,30 +1228,6 @@ pub mod responses { lazy_static! { pub static ref CREATE_RELEASE_AUTO_BATCH_GENERIC_ERROR: Mime = mime!(Application / Json); } - /// Create Mime objects for the response content types for CreateWork - lazy_static! { - pub static ref CREATE_WORK_CREATED_ENTITY: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for CreateWork - lazy_static! { - pub static ref CREATE_WORK_BAD_REQUEST: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for CreateWork - lazy_static! { - pub static ref CREATE_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for CreateWork - lazy_static! { - pub static ref CREATE_WORK_FORBIDDEN: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for CreateWork - lazy_static! { - pub static ref CREATE_WORK_NOT_FOUND: Mime = mime!(Application / Json); - } - /// Create Mime objects for the response content types for CreateWork - lazy_static! { - pub static ref CREATE_WORK_GENERIC_ERROR: Mime = mime!(Application / Json); - } /// Create Mime objects for the response content types for DeleteRelease lazy_static! { pub static ref DELETE_RELEASE_DELETED_ENTITY: Mime = mime!(Application / Json); @@ -1668,6 +1644,30 @@ pub mod responses { lazy_static! { pub static ref UPDATE_WEBCAPTURE_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK_CREATED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK_NOT_AUTHORIZED: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK_FORBIDDEN: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK_GENERIC_ERROR: Mime = mime!(Application / Json); + } /// Create Mime objects for the response content types for CreateWorkAutoBatch lazy_static! { pub static ref CREATE_WORK_AUTO_BATCH_CREATED_EDITGROUP: Mime = mime!(Application / Json); @@ -1865,6 +1865,10 @@ pub mod responses { pub mod requests { use hyper::mime::*; + /// Create Mime objects for the request content types for AuthOidc + lazy_static! { + pub static ref AUTH_OIDC: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for CreateContainer lazy_static! { pub static ref CREATE_CONTAINER: Mime = mime!(Application / Json); @@ -1889,9 +1893,13 @@ pub mod requests { lazy_static! { pub static ref UPDATE_CREATOR: Mime = mime!(Application / Json); } - /// Create Mime objects for the request content types for AuthOidc + /// Create Mime objects for the request content types for CreateEditgroup lazy_static! { - pub static ref AUTH_OIDC: Mime = mime!(Application / Json); + pub static ref CREATE_EDITGROUP: Mime = mime!(Application / Json); + } + /// Create Mime objects for the request content types for CreateEditgroupAnnotation + lazy_static! { + pub static ref CREATE_EDITGROUP_ANNOTATION: Mime = mime!(Application / Json); } /// Create Mime objects for the request content types for UpdateEditgroup lazy_static! { @@ -1901,14 +1909,6 @@ pub mod requests { lazy_static! { pub static ref UPDATE_EDITOR: Mime = mime!(Application / Json); } - /// Create Mime objects for the request content types for CreateEditgroup - lazy_static! { - pub static ref CREATE_EDITGROUP: Mime = mime!(Application / Json); - } - /// Create Mime objects for the request content types for CreateEditgroupAnnotation - lazy_static! { - pub static ref CREATE_EDITGROUP_ANNOTATION: Mime = mime!(Application / Json); - } /// Create Mime objects for the request content types for CreateFile lazy_static! { pub static ref CREATE_FILE: Mime = mime!(Application / Json); @@ -1941,10 +1941,6 @@ pub mod requests { lazy_static! { pub static ref CREATE_RELEASE_AUTO_BATCH: Mime = mime!(Application / Json); } - /// Create Mime objects for the request content types for CreateWork - lazy_static! { - pub static ref CREATE_WORK: Mime = mime!(Application / Json); - } /// Create Mime objects for the request content types for UpdateRelease lazy_static! { pub static ref UPDATE_RELEASE: Mime = mime!(Application / Json); @@ -1961,6 +1957,10 @@ pub mod requests { lazy_static! { pub static ref UPDATE_WEBCAPTURE: Mime = mime!(Application / Json); } + /// Create Mime objects for the request content types for CreateWork + lazy_static! { + pub static ref CREATE_WORK: Mime = mime!(Application / Json); + } /// Create Mime objects for the request content types for CreateWorkAutoBatch lazy_static! { pub static ref CREATE_WORK_AUTO_BATCH: Mime = mime!(Application / Json); diff --git a/rust/fatcat-openapi/src/models.rs b/rust/fatcat-openapi/src/models.rs index c8b68328..e9e527f5 100644 --- a/rust/fatcat-openapi/src/models.rs +++ b/rust/fatcat-openapi/src/models.rs @@ -11,15 +11,19 @@ use swagger; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct AuthOidc { + /// Fatcat-specific short name (slug) for remote service being used for authentication. #[serde(rename = "provider")] pub provider: String, + /// `SUB` from OIDC protocol. Usually a URL. #[serde(rename = "sub")] pub sub: String, + /// `ISS` from OIDC protocol. Usually a stable account username, number, or identifier. #[serde(rename = "iss")] pub iss: String, + /// What it sounds like; returned by OIDC, and used as a hint when creating new editor accounts. Fatcat usernames are usually this string with the `provider` slug as a suffix, though some munging may occur. #[serde(rename = "preferred_username")] pub preferred_username: String, } @@ -52,12 +56,15 @@ impl AuthOidcResult { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ChangelogEntry { + /// Monotonically increasing sequence number of this changelog entry. #[serde(rename = "index")] pub index: i64, + /// Identifier of editgroup accepted/merged in this changelog entry. #[serde(rename = "editgroup_id")] pub editgroup_id: String, + /// Date and time when the editgroup was accpeted. #[serde(rename = "timestamp")] pub timestamp: chrono::DateTime<chrono::Utc>, @@ -101,28 +108,32 @@ pub struct ContainerEntity { #[serde(skip_serializing_if = "Option::is_none")] pub wikidata_qid: Option<String>, + /// Linking ISSN number (ISSN-L). Should be valid and registered with issn.org #[serde(rename = "issnl")] #[serde(skip_serializing_if = "Option::is_none")] pub issnl: Option<String>, + /// Name of the organization or entity responsible for publication. Not the complete imprint/brand. #[serde(rename = "publisher")] #[serde(skip_serializing_if = "Option::is_none")] pub publisher: Option<String>, - /// Eg, 'journal' + /// Type of container, eg 'journal' or 'proceedings'. See Guide for list of valid types. #[serde(rename = "container_type")] #[serde(skip_serializing_if = "Option::is_none")] pub container_type: Option<String>, - /// Required for valid entities + /// Name of the container (eg, Journal title). Required for entity creation. #[serde(rename = "name")] #[serde(skip_serializing_if = "Option::is_none")] pub name: Option<String>, + /// Free-form JSON metadata that will be stored with specific entity edits (eg, creation/update/delete). #[serde(rename = "edit_extra")] #[serde(skip_serializing_if = "Option::is_none")] pub edit_extra: Option<serde_json::Value>, + /// Free-form JSON metadata that will be stored with the other entity metadata. See guide for (unenforced) schema conventions. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, @@ -186,23 +197,27 @@ impl CreatorAutoBatch { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct CreatorEntity { + /// Wikidata entity QID #[serde(rename = "wikidata_qid")] #[serde(skip_serializing_if = "Option::is_none")] pub wikidata_qid: Option<String>, + /// ORCiD (https://orcid.org) identifier #[serde(rename = "orcid")] #[serde(skip_serializing_if = "Option::is_none")] pub orcid: Option<String>, + /// In English commonly the last, or family name, but ordering is context and culture specific. #[serde(rename = "surname")] #[serde(skip_serializing_if = "Option::is_none")] pub surname: Option<String>, + /// In English commonly the first name, but ordering is context and culture specific. #[serde(rename = "given_name")] #[serde(skip_serializing_if = "Option::is_none")] pub given_name: Option<String>, - /// Required for valid entities + /// Name as should be displayed in web interface or in author lists (not index/sorted). Required for valid entities. #[serde(rename = "display_name")] #[serde(skip_serializing_if = "Option::is_none")] pub display_name: Option<String>, @@ -227,10 +242,12 @@ pub struct CreatorEntity { #[serde(skip_serializing_if = "Option::is_none")] pub redirect: Option<String>, + /// Free-form JSON metadata that will be stored with the other entity metadata. See guide for (unenforced) schema conventions. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, + /// Free-form JSON metadata that will be stored with specific entity edits (eg, creation/update/delete). #[serde(rename = "edit_extra")] #[serde(skip_serializing_if = "Option::is_none")] pub edit_extra: Option<serde_json::Value>, @@ -256,40 +273,47 @@ impl CreatorEntity { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Editgroup { - /// base32-encoded unique identifier + /// Fatcat identifier for this editgroup. Assigned on creation. #[serde(rename = "editgroup_id")] #[serde(skip_serializing_if = "Option::is_none")] pub editgroup_id: Option<String>, - /// base32-encoded unique identifier + /// Fatcat identifer of editor that created this editgroup. #[serde(rename = "editor_id")] #[serde(skip_serializing_if = "Option::is_none")] pub editor_id: Option<String>, + /// Complete editor object identified by `container_id` field. Only included in GET responses. #[serde(rename = "editor")] #[serde(skip_serializing_if = "Option::is_none")] pub editor: Option<models::Editor>, + /// For accepted/merged editgroups, the changelog index that the accept occured at. WARNING: not populated in all contexts that an editgroup could be included in a response. #[serde(rename = "changelog_index")] #[serde(skip_serializing_if = "Option::is_none")] pub changelog_index: Option<i64>, + /// Timestamp when this editgroup was first created. #[serde(rename = "created")] #[serde(skip_serializing_if = "Option::is_none")] pub created: Option<chrono::DateTime<chrono::Utc>>, + /// Timestamp when this editgroup was most recently submitted for review. If withdrawn, or never submitted, will be `null`. #[serde(rename = "submitted")] #[serde(skip_serializing_if = "Option::is_none")] pub submitted: Option<chrono::DateTime<chrono::Utc>>, + /// Comment describing the changes in this editgroup. Can be updated with PUT request. #[serde(rename = "description")] #[serde(skip_serializing_if = "Option::is_none")] pub description: Option<String>, + /// Free-form JSON metadata attached to this editgroup. Eg, metadata provenance, or script user-agent details. See guide for (unenforced) schema norms. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, + /// Only included in GET responses, and not in all contexts. Do not include this field in PUT or POST requests. #[serde(rename = "annotations")] #[serde(skip_serializing_if = "Option::is_none")] pub annotations: Option<Vec<models::EditgroupAnnotation>>, @@ -323,20 +347,22 @@ pub struct EditgroupAnnotation { #[serde(skip_serializing_if = "Option::is_none")] pub annotation_id: Option<String>, - /// base32-encoded unique identifier + /// Editgroup that this annotation applies to. Set automatically in creations based on URL parameter. #[serde(rename = "editgroup_id")] #[serde(skip_serializing_if = "Option::is_none")] pub editgroup_id: Option<String>, - /// base32-encoded unique identifier + /// Defaults to editor created the annotation via POST request. #[serde(rename = "editor_id")] #[serde(skip_serializing_if = "Option::is_none")] pub editor_id: Option<String>, + /// Only included in GET responses; ignored in PUT or POST requests. #[serde(rename = "editor")] #[serde(skip_serializing_if = "Option::is_none")] pub editor: Option<models::Editor>, + /// Timestamp when annotation was first created. #[serde(rename = "created")] #[serde(skip_serializing_if = "Option::is_none")] pub created: Option<chrono::DateTime<chrono::Utc>>, @@ -345,6 +371,7 @@ pub struct EditgroupAnnotation { #[serde(skip_serializing_if = "Option::is_none")] pub comment_markdown: Option<String>, + /// Additional free-form JSON metadata that can be included as part of the annotation (or even as the primary annotation itself). See guide for details. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, @@ -364,6 +391,7 @@ impl EditgroupAnnotation { } } +/// Only included in GET responses, and not in all contexts. Do not include this field in PUT or POST requests. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct EditgroupEdits { #[serde(rename = "containers")] @@ -411,22 +439,26 @@ impl EditgroupEdits { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Editor { - /// base32-encoded unique identifier + /// Fatcat identifier for the editor. Can not be changed. #[serde(rename = "editor_id")] #[serde(skip_serializing_if = "Option::is_none")] pub editor_id: Option<String>, + /// Username/handle (short slug-like string) to identify this editor. May be changed at any time by the editor; use the `editor_id` as a persistend identifer. #[serde(rename = "username")] pub username: String, + /// Whether this editor has the `admin` role. #[serde(rename = "is_admin")] #[serde(skip_serializing_if = "Option::is_none")] pub is_admin: Option<bool>, + /// Whether this editor is a bot (as opposed to a human making manual edits) #[serde(rename = "is_bot")] #[serde(skip_serializing_if = "Option::is_none")] pub is_bot: Option<bool>, + /// Whether this editor's account is enabled (if not API tokens and web logins will not work). #[serde(rename = "is_active")] #[serde(skip_serializing_if = "Option::is_none")] pub is_active: Option<bool>, @@ -446,30 +478,30 @@ impl Editor { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct EntityEdit { - /// UUID (lower-case, dash-separated, hex-encoded 128-bit) + /// Unique UUID for this specific edit object. #[serde(rename = "edit_id")] pub edit_id: String, - /// base32-encoded unique identifier + /// Fatcat identifier of the entity this edit is mutating. #[serde(rename = "ident")] pub ident: String, - /// UUID (lower-case, dash-separated, hex-encoded 128-bit) + /// Entity revision that this edit will set the entity to. May be `null` in the case of deletions. #[serde(rename = "revision")] #[serde(skip_serializing_if = "Option::is_none")] pub revision: Option<String>, - /// UUID (lower-case, dash-separated, hex-encoded 128-bit) + /// Revision of entity just before this edit. May be used in the future to prevent edit race conditions. #[serde(rename = "prev_revision")] #[serde(skip_serializing_if = "Option::is_none")] pub prev_revision: Option<String>, - /// base32-encoded unique identifier + /// When an edit is to merge entities (redirect one to another), this is the entity fatcat identifier for the target entity. #[serde(rename = "redirect_ident")] #[serde(skip_serializing_if = "Option::is_none")] pub redirect_ident: Option<String>, - /// base32-encoded unique identifier + /// Editgroup identifier that this edit is part of. #[serde(rename = "editgroup_id")] pub editgroup_id: String, @@ -556,11 +588,12 @@ impl FileAutoBatch { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct FileEntity { - /// Optional; GET-only + /// Full release entities, included in GET responses when `releases` included in `expand` parameter. Ignored if included in PUT or POST requests. #[serde(rename = "releases")] #[serde(skip_serializing_if = "Option::is_none")] pub releases: Option<Vec<models::ReleaseEntity>>, + /// Set of identifier of release entities this file represents a full manifestation of. Usually a single release, but some files contain content of multiple full releases (eg, an issue of a journal). #[serde(rename = "release_ids")] #[serde(skip_serializing_if = "Option::is_none")] pub release_ids: Option<Vec<String>>, @@ -573,26 +606,32 @@ pub struct FileEntity { #[serde(skip_serializing_if = "Option::is_none")] pub urls: Option<Vec<models::FileUrl>>, + /// SHA-256 hash of data, in hex encoding #[serde(rename = "sha256")] #[serde(skip_serializing_if = "Option::is_none")] pub sha256: Option<String>, + /// SHA-1 hash of data, in hex encoding #[serde(rename = "sha1")] #[serde(skip_serializing_if = "Option::is_none")] pub sha1: Option<String>, + /// MD5 hash of data, in hex encoding #[serde(rename = "md5")] #[serde(skip_serializing_if = "Option::is_none")] pub md5: Option<String>, + /// Size of file in bytes. Non-zero. #[serde(rename = "size")] #[serde(skip_serializing_if = "Option::is_none")] pub size: Option<i64>, + /// Free-form JSON metadata that will be stored with specific entity edits (eg, creation/update/delete). #[serde(rename = "edit_extra")] #[serde(skip_serializing_if = "Option::is_none")] pub edit_extra: Option<serde_json::Value>, + /// Free-form JSON metadata that will be stored with the other entity metadata. See guide for (unenforced) schema conventions. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, @@ -641,9 +680,11 @@ impl FileEntity { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct FileUrl { + /// URL/URI pointing directly to a machine retrievable copy of this exact file. #[serde(rename = "url")] pub url: String, + /// Indicates type of host this URL points to. Eg, \"publisher\", \"repository\", \"webarchive\". See guide for list of acceptable values. #[serde(rename = "rel")] pub rel: String, } @@ -674,11 +715,12 @@ impl FilesetAutoBatch { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct FilesetEntity { - /// Optional; GET-only + /// Full release entities, included in GET responses when `releases` included in `expand` parameter. Ignored if included in PUT or POST requests. #[serde(rename = "releases")] #[serde(skip_serializing_if = "Option::is_none")] pub releases: Option<Vec<models::ReleaseEntity>>, + /// Set of identifier of release entities this fileset represents a full manifestation of. Usually a single release. #[serde(rename = "release_ids")] #[serde(skip_serializing_if = "Option::is_none")] pub release_ids: Option<Vec<String>>, @@ -711,10 +753,12 @@ pub struct FilesetEntity { #[serde(skip_serializing_if = "Option::is_none")] pub redirect: Option<String>, + /// Free-form JSON metadata that will be stored with the other entity metadata. See guide for (unenforced) schema conventions. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, + /// Free-form JSON metadata that will be stored with specific entity edits (eg, creation/update/delete). #[serde(rename = "edit_extra")] #[serde(skip_serializing_if = "Option::is_none")] pub edit_extra: Option<serde_json::Value>, @@ -739,24 +783,30 @@ impl FilesetEntity { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct FilesetFile { + /// Path name of file within this fileset (eg, directory) #[serde(rename = "path")] pub path: String, + /// File size in bytes #[serde(rename = "size")] pub size: i64, + /// MD5 hash of data, in hex encoding #[serde(rename = "md5")] #[serde(skip_serializing_if = "Option::is_none")] pub md5: Option<String>, + /// SHA-1 hash of data, in hex encoding #[serde(rename = "sha1")] #[serde(skip_serializing_if = "Option::is_none")] pub sha1: Option<String>, + /// SHA-256 hash of data, in hex encoding #[serde(rename = "sha256")] #[serde(skip_serializing_if = "Option::is_none")] pub sha256: Option<String>, + /// Free-form additional metadata about this specific file in the set. Eg, `mimetype`. See guide for nomative (but unenforced) schema fields. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, @@ -780,6 +830,7 @@ pub struct FilesetUrl { #[serde(rename = "url")] pub url: String, + /// Indicates type of host this URL points to. See guide for list of acceptable values. #[serde(rename = "rel")] pub rel: String, } @@ -792,18 +843,22 @@ impl FilesetUrl { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ReleaseAbstract { + /// SHA-1 hash of data, in hex encoding #[serde(rename = "sha1")] #[serde(skip_serializing_if = "Option::is_none")] pub sha1: Option<String>, + /// Abstract content. May be encoded, as per `mimetype` field, but only string/text content may be included. #[serde(rename = "content")] #[serde(skip_serializing_if = "Option::is_none")] pub content: Option<String>, + /// Mimetype of abstract contents. `text/plain` is the default if content isn't encoded. #[serde(rename = "mimetype")] #[serde(skip_serializing_if = "Option::is_none")] pub mimetype: Option<String>, + /// ISO language code of the abstract. Same semantics as release `language` field. #[serde(rename = "lang")] #[serde(skip_serializing_if = "Option::is_none")] pub lang: Option<String>, @@ -840,32 +895,37 @@ impl ReleaseAutoBatch { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ReleaseContrib { + /// Internally assigned zero-indexed sequence number of contribution. Authors should come first; this encodes the order of attriubtion. #[serde(rename = "index")] #[serde(skip_serializing_if = "Option::is_none")] pub index: Option<i64>, - /// base32-encoded unique identifier + /// If known, indicates the creator entity this contribution was made by. #[serde(rename = "creator_id")] #[serde(skip_serializing_if = "Option::is_none")] pub creator_id: Option<String>, - /// Optional; GET-only + /// Complete creator entity. Only returned in GET responses, and only if `contribs` included in the `expand` query parameter. #[serde(rename = "creator")] #[serde(skip_serializing_if = "Option::is_none")] pub creator: Option<models::CreatorEntity>, + /// Full name of the contributor as typeset in the release. #[serde(rename = "raw_name")] #[serde(skip_serializing_if = "Option::is_none")] pub raw_name: Option<String>, + /// In English commonly the first name, but ordering is context and culture specific. #[serde(rename = "given_name")] #[serde(skip_serializing_if = "Option::is_none")] pub given_name: Option<String>, + /// In English commonly the last, or family name, but ordering is context and culture specific. #[serde(rename = "surname")] #[serde(skip_serializing_if = "Option::is_none")] pub surname: Option<String>, + /// Short string (slug) indicating type of contribution (eg, \"author\", \"translator\"). See guide for list of accpeted values. #[serde(rename = "role")] #[serde(skip_serializing_if = "Option::is_none")] pub role: Option<String>, @@ -875,6 +935,7 @@ pub struct ReleaseContrib { #[serde(skip_serializing_if = "Option::is_none")] pub raw_affiliation: Option<String>, + /// Additional free-form JSON metadata about this contributor/contribution. See guide for normative schema. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, @@ -910,110 +971,126 @@ pub struct ReleaseEntity { #[serde(skip_serializing_if = "Option::is_none")] pub contribs: Option<Vec<models::ReleaseContrib>>, - /// Short version of license name. Eg, 'CC-BY' + /// Short string (slug) name of license under which release is openly published (if applicable). #[serde(rename = "license_slug")] #[serde(skip_serializing_if = "Option::is_none")] pub license_slug: Option<String>, - /// Two-letter RFC1766/ISO639-1 language code, with extensions + /// Primary language of the content of the full release. Two-letter RFC1766/ISO639-1 language code, with some custom extensions/additions. See guide. #[serde(rename = "language")] #[serde(skip_serializing_if = "Option::is_none")] pub language: Option<String>, + /// Name, usually English, of the entity or institution responsible for publication of this release. Not necessarily the imprint/brand. See guide. #[serde(rename = "publisher")] #[serde(skip_serializing_if = "Option::is_none")] pub publisher: Option<String>, + /// For, eg, updated technical reports or software packages, where the version string may be the only field disambiguating between releases. #[serde(rename = "version")] #[serde(skip_serializing_if = "Option::is_none")] pub version: Option<String>, + /// For, eg, technical reports, which are published in series or assigned some other institutional or container-specific identifier. #[serde(rename = "number")] #[serde(skip_serializing_if = "Option::is_none")] pub number: Option<String>, + /// Either a single page number (\"first page\") or a range of pages separated by a dash (\"-\"). See guide for details. #[serde(rename = "pages")] #[serde(skip_serializing_if = "Option::is_none")] pub pages: Option<String>, + /// Issue number of volume/container that this release was published in. Sometimes coresponds to a month number in the year, but can be any string. See guide. #[serde(rename = "issue")] #[serde(skip_serializing_if = "Option::is_none")] pub issue: Option<String>, + /// Volume number of container that this release was published in. Often corresponds to the \"Nth\" year of publication, but can be any string. See guide. #[serde(rename = "volume")] #[serde(skip_serializing_if = "Option::is_none")] pub volume: Option<String>, + /// Set of external identifiers for this release. #[serde(rename = "ext_ids")] pub ext_ids: models::ReleaseExtIds, + /// Year corresponding with `withdrawn_date` like `release_year`/`release_date`. #[serde(rename = "withdrawn_year")] #[serde(skip_serializing_if = "Option::is_none")] pub withdrawn_year: Option<i64>, + /// Full date when this release was formally withdrawn (if applicable). ISO format, like `release_date`. #[serde(rename = "withdrawn_date")] #[serde(skip_serializing_if = "Option::is_none")] pub withdrawn_date: Option<chrono::NaiveDate>, + /// Type of withdrawl or retraction of this release, if applicable. If release has not been withdrawn, should be `null` (aka, not set, not the string \"null\" or an empty string). #[serde(rename = "withdrawn_status")] #[serde(skip_serializing_if = "Option::is_none")] pub withdrawn_status: Option<String>, + /// Year when this release was formally published. Must match `release_date` if that field is set; this field exists because sometimes only the year is known. #[serde(rename = "release_year")] #[serde(skip_serializing_if = "Option::is_none")] pub release_year: Option<i64>, + /// Full date when this release was formally published. ISO format, like `2019-03-05`. See guide for semantics. #[serde(rename = "release_date")] #[serde(skip_serializing_if = "Option::is_none")] pub release_date: Option<chrono::NaiveDate>, + /// The stage of publication of this specific release. See guide for valid values and semantics. #[serde(rename = "release_stage")] #[serde(skip_serializing_if = "Option::is_none")] pub release_stage: Option<String>, + /// \"Type\" or \"medium\" that this release is published as. See guide for valid values. #[serde(rename = "release_type")] #[serde(skip_serializing_if = "Option::is_none")] pub release_type: Option<String>, + /// Used to link this release to a container entity that the release was published as part of. #[serde(rename = "container_id")] #[serde(skip_serializing_if = "Option::is_none")] pub container_id: Option<String>, - /// Optional; GET-only + /// Complete webcapture entities identified by `webcapture_ids` field. Only included in GET responses when `webcaptures` included in `expand` parameter; ignored in PUT or POST requests. #[serde(rename = "webcaptures")] #[serde(skip_serializing_if = "Option::is_none")] pub webcaptures: Option<Vec<models::WebcaptureEntity>>, - /// Optional; GET-only + /// Complete file entities identified by `filesets_ids` field. Only included in GET responses when `filesets` included in `expand` parameter; ignored in PUT or POST requests. #[serde(rename = "filesets")] #[serde(skip_serializing_if = "Option::is_none")] pub filesets: Option<Vec<models::FilesetEntity>>, - /// Optional; GET-only + /// Complete file entities identified by `file_ids` field. Only included in GET responses when `files` included in `expand` parameter; ignored in PUT or POST requests. #[serde(rename = "files")] #[serde(skip_serializing_if = "Option::is_none")] pub files: Option<Vec<models::FileEntity>>, - /// Optional; GET-only + /// Complete container entity identified by `container_id` field. Only included in GET reponses when `container` included in `expand` parameter; ignored in PUT or POST requests. #[serde(rename = "container")] #[serde(skip_serializing_if = "Option::is_none")] pub container: Option<models::ContainerEntity>, + /// Identifier of work this release is part of. In creation (POST) requests, a work entity will be created automatically if this field is not set. #[serde(rename = "work_id")] #[serde(skip_serializing_if = "Option::is_none")] pub work_id: Option<String>, - /// Title in original language (or, the language of the full text of this release) + /// Title in original language if `title` field has been translated. See guide for details. #[serde(rename = "original_title")] #[serde(skip_serializing_if = "Option::is_none")] pub original_title: Option<String>, - /// Avoid this field if possible, and merge with title; usually English + /// Subtitle of release. In many cases, better to merge with title than include as separate field (unless combined title would be very long). See guide for details. #[serde(rename = "subtitle")] #[serde(skip_serializing_if = "Option::is_none")] pub subtitle: Option<String>, - /// Required for valid entities. The title used in citations and for display; usually English + /// Required for valid entities. The title used in citations and for display. Sometimes the English translation of title e even if release content is not English. #[serde(rename = "title")] #[serde(skip_serializing_if = "Option::is_none")] pub title: Option<String>, @@ -1038,10 +1115,12 @@ pub struct ReleaseEntity { #[serde(skip_serializing_if = "Option::is_none")] pub redirect: Option<String>, + /// Free-form JSON metadata that will be stored with the other entity metadata. See guide for (unenforced) schema conventions. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, + /// Free-form JSON metadata that will be stored with specific entity edits (eg, creation/update/delete). #[serde(rename = "edit_extra")] #[serde(skip_serializing_if = "Option::is_none")] pub edit_extra: Option<serde_json::Value>, @@ -1090,42 +1169,52 @@ impl ReleaseEntity { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ReleaseExtIds { + /// Digital serde_json::Value Identifier (DOI), mostly for published papers and datasets. Should be registered and resolvable via https://doi.org/ #[serde(rename = "doi")] #[serde(skip_serializing_if = "Option::is_none")] pub doi: Option<String>, + /// Wikidata entity QID #[serde(rename = "wikidata_qid")] #[serde(skip_serializing_if = "Option::is_none")] pub wikidata_qid: Option<String>, + /// ISBN-13, for books. Usually not set for chapters. ISBN-10 should be converted to ISBN-13. #[serde(rename = "isbn13")] #[serde(skip_serializing_if = "Option::is_none")] pub isbn13: Option<String>, + /// PubMed Identifier #[serde(rename = "pmid")] #[serde(skip_serializing_if = "Option::is_none")] pub pmid: Option<String>, + /// PubMed Central Identifier #[serde(rename = "pmcid")] #[serde(skip_serializing_if = "Option::is_none")] pub pmcid: Option<String>, + /// CORE (https://core.ac.uk) identifier #[serde(rename = "core")] #[serde(skip_serializing_if = "Option::is_none")] pub core: Option<String>, + /// arXiv (https://arxiv.org) identifier; must include version #[serde(rename = "arxiv")] #[serde(skip_serializing_if = "Option::is_none")] pub arxiv: Option<String>, + /// JSTOR work identifier #[serde(rename = "jstor")] #[serde(skip_serializing_if = "Option::is_none")] pub jstor: Option<String>, + /// ARK identifier #[serde(rename = "ark")] #[serde(skip_serializing_if = "Option::is_none")] pub ark: Option<String>, + /// Microsoft Academic Graph identifier #[serde(rename = "mag")] #[serde(skip_serializing_if = "Option::is_none")] pub mag: Option<String>, @@ -1150,35 +1239,42 @@ impl ReleaseExtIds { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ReleaseRef { + /// Zero-indexed sequence number of this reference in the list of references. Assigned automatically and used internally; don't confuse with `key`. #[serde(rename = "index")] #[serde(skip_serializing_if = "Option::is_none")] pub index: Option<i64>, - /// base32-encoded unique identifier + /// Optional, fatcat identifier of release entity that this reference is citing. #[serde(rename = "target_release_id")] #[serde(skip_serializing_if = "Option::is_none")] pub target_release_id: Option<String>, + /// Additional free-form JSON metadata about this citation. Generally follows Citation Style Language (CSL) JSON schema. See guide for details. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, + /// Short string used to indicate this reference from within the release text; or numbering of references as typeset in the release itself. Optional; don't confuse with `index` field. #[serde(rename = "key")] #[serde(skip_serializing_if = "Option::is_none")] pub key: Option<String>, + /// Year that the cited work was published in. #[serde(rename = "year")] #[serde(skip_serializing_if = "Option::is_none")] pub year: Option<i64>, + /// Name of the container (eg, journal) that the citation work was published as part of. May be an acronym or full name. #[serde(rename = "container_name")] #[serde(skip_serializing_if = "Option::is_none")] pub container_name: Option<String>, + /// Name of the work being cited. #[serde(rename = "title")] #[serde(skip_serializing_if = "Option::is_none")] pub title: Option<String>, + /// Page number or other indicator of the specific subset of a work being cited. Not to be confused with the first page (or page range) of an entire paper or chapter being cited. #[serde(rename = "locator")] #[serde(skip_serializing_if = "Option::is_none")] pub locator: Option<String>, @@ -1234,31 +1330,38 @@ impl WebcaptureAutoBatch { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct WebcaptureCdxLine { + /// \"Sortable URL\" format. See guide for details. #[serde(rename = "surt")] pub surt: String, - /// UTC, 'Z'-terminated, second (or better) precision + /// Date and time of capture, in ISO format. UTC, 'Z'-terminated, second (or better) precision. #[serde(rename = "timestamp")] pub timestamp: chrono::DateTime<chrono::Utc>, + /// Full URL/URI of resource captured. #[serde(rename = "url")] pub url: String, + /// Mimetype of the resource at this URL. May be the Content-Type header, or the actually sniffed file type. #[serde(rename = "mimetype")] #[serde(skip_serializing_if = "Option::is_none")] pub mimetype: Option<String>, + /// HTTP status code. Should generally be 200, especially for the primary resource, but may be 3xx (redirect) or even error codes if embedded resources can not be fetched successfully. #[serde(rename = "status_code")] #[serde(skip_serializing_if = "Option::is_none")] pub status_code: Option<i64>, + /// Resource (file) size in bytes #[serde(rename = "size")] #[serde(skip_serializing_if = "Option::is_none")] pub size: Option<i64>, + /// SHA-1 hash of data, in hex encoding #[serde(rename = "sha1")] pub sha1: String, + /// SHA-256 hash of data, in hex encoding #[serde(rename = "sha256")] #[serde(skip_serializing_if = "Option::is_none")] pub sha256: Option<String>, @@ -1281,20 +1384,22 @@ impl WebcaptureCdxLine { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct WebcaptureEntity { - /// Optional; GET-only + /// Full release entities, included in GET responses when `releases` included in `expand` parameter. Ignored if included in PUT or POST requests. #[serde(rename = "releases")] #[serde(skip_serializing_if = "Option::is_none")] pub releases: Option<Vec<models::ReleaseEntity>>, + /// Set of identifier of release entities this fileset represents a full manifestation of. Usually a single release. #[serde(rename = "release_ids")] #[serde(skip_serializing_if = "Option::is_none")] pub release_ids: Option<Vec<String>>, - /// same format as CDX line timestamp (UTC, etc). Corresponds to the overall capture timestamp. Can be the earliest or average of CDX timestamps if that makes sense. + /// Same format as CDX line timestamp (UTC, etc). Corresponds to the overall capture timestamp. Should generally be the timestamp of capture of the primary resource URL. #[serde(rename = "timestamp")] #[serde(skip_serializing_if = "Option::is_none")] pub timestamp: Option<chrono::DateTime<chrono::Utc>>, + /// Base URL of the primary resource this is a capture of #[serde(rename = "original_url")] #[serde(skip_serializing_if = "Option::is_none")] pub original_url: Option<String>, @@ -1307,10 +1412,12 @@ pub struct WebcaptureEntity { #[serde(skip_serializing_if = "Option::is_none")] pub cdx: Option<Vec<models::WebcaptureCdxLine>>, + /// Free-form JSON metadata that will be stored with specific entity edits (eg, creation/update/delete). #[serde(rename = "edit_extra")] #[serde(skip_serializing_if = "Option::is_none")] pub edit_extra: Option<serde_json::Value>, + /// Free-form JSON metadata that will be stored with the other entity metadata. See guide for (unenforced) schema conventions. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, @@ -1357,9 +1464,11 @@ impl WebcaptureEntity { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct WebcaptureUrl { + /// URL/URI pointing to archive of this web resource. #[serde(rename = "url")] pub url: String, + /// Type of archive endpoint. Usually `wayback` (WBM replay of primary resource), or `warc` (direct URL to a WARC file containing all resources of the capture). See guide for full list. #[serde(rename = "rel")] pub rel: String, } @@ -1390,10 +1499,12 @@ impl WorkAutoBatch { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct WorkEntity { + /// Free-form JSON metadata that will be stored with specific entity edits (eg, creation/update/delete). #[serde(rename = "edit_extra")] #[serde(skip_serializing_if = "Option::is_none")] pub edit_extra: Option<serde_json::Value>, + /// Free-form JSON metadata that will be stored with the other entity metadata. See guide for (unenforced) schema conventions. #[serde(rename = "extra")] #[serde(skip_serializing_if = "Option::is_none")] pub extra: Option<serde_json::Value>, diff --git a/rust/fatcat-openapi/src/server.rs b/rust/fatcat-openapi/src/server.rs index 102b6e41..406b6789 100644 --- a/rust/fatcat-openapi/src/server.rs +++ b/rust/fatcat-openapi/src/server.rs @@ -98,6 +98,409 @@ where T: Api + Send + Sync + Clone + 'static, { let api_clone = api.clone(); + router.get( + "/v0/auth/check", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> + where + T: Api, + { + context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::<AuthData>(); + context.authorization = req.extensions.remove::<Authorization>(); + + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + + // 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_role = query_params.get("role").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); + + match api.auth_check(param_role, context).wait() { + Ok(rsp) => match rsp { + AuthCheckResponse::Success(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(200), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_SUCCESS.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::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::AUTH_CHECK_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AuthCheckResponse::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::AUTH_CHECK_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) + }) + }, + "AuthCheck", + ); + + let api_clone = api.clone(); + router.post( + "/v0/auth/oidc", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> + where + T: Api, + { + context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::<AuthData>(); + context.authorization = req.extensions.remove::<Authorization>(); + + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_oidc_params = req + .get::<bodyparser::Raw>() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter oidc_params - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_oidc_params = if let Some(param_oidc_params_raw) = param_oidc_params { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_oidc_params_raw); + + let param_oidc_params: Option<models::AuthOidc> = serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter oidc_params - doesn't match schema: {}", e))))?; + + param_oidc_params + } else { + None + }; + let param_oidc_params = param_oidc_params.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter oidc_params".to_string())))?; + + match api.auth_oidc(param_oidc_params, context).wait() { + Ok(rsp) => match rsp { + AuthOidcResponse::Found(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::AUTH_OIDC_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::Created(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_CREATED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::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::AUTH_OIDC_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::Conflict(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(409), body_string)); + response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_CONFLICT.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + AuthOidcResponse::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::AUTH_OIDC_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + 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) + }) + }, + "AuthOidc", + ); + + let api_clone = api.clone(); + router.get( + "/v0/changelog", + 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>(); + + // 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| Some(x.parse::<i64>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected integer)".to_string())))?; + + match api.get_changelog(param_limit, context).wait() { + Ok(rsp) => match rsp { + GetChangelogResponse::Success(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(200), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_CHANGELOG_SUCCESS.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetChangelogResponse::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_CHANGELOG_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetChangelogResponse::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_CHANGELOG_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) + }) + }, + "GetChangelog", + ); + + let api_clone = api.clone(); + router.get( + "/v0/changelog/:index", + 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_index = { + let param = req + .extensions + .get::<Router>() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("index") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter index".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 index: {}", e))))? + }; + + match api.get_changelog_entry(param_index, context).wait() { + Ok(rsp) => match rsp { + GetChangelogEntryResponse::FoundChangelogEntry(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_CHANGELOG_ENTRY_FOUND_CHANGELOG_ENTRY.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetChangelogEntryResponse::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_CHANGELOG_ENTRY_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetChangelogEntryResponse::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_CHANGELOG_ENTRY_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetChangelogEntryResponse::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_CHANGELOG_ENTRY_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) + }) + }, + "GetChangelogEntry", + ); + + let api_clone = api.clone(); router.post( "/v0/editgroup/:editgroup_id/container", move |req: &mut Request| { @@ -2691,8 +3094,8 @@ where ); let api_clone = api.clone(); - router.get( - "/v0/auth/check", + router.post( + "/v0/editgroup/:editgroup_id/accept", move |req: &mut Request| { let mut context = Context::default(); @@ -2707,60 +3110,91 @@ where let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) - let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); - let param_role = query_params.get("role").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); + // Path parameters + let param_editgroup_id = { + let param = req + .extensions + .get::<Router>() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("editgroup_id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editgroup_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 editgroup_id: {}", e))))? + }; - match api.auth_check(param_role, context).wait() { + match api.accept_editgroup(param_editgroup_id, context).wait() { Ok(rsp) => match rsp { - AuthCheckResponse::Success(body) => { + AcceptEditgroupResponse::MergedSuccessfully(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::AUTH_CHECK_SUCCESS.clone())); + response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_MERGED_SUCCESSFULLY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AuthCheckResponse::BadRequest(body) => { + AcceptEditgroupResponse::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::AUTH_CHECK_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AuthCheckResponse::NotAuthorized { body, www_authenticate } => { + AcceptEditgroupResponse::NotAuthorized { body, www_authenticate } => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(401), body_string)); header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_NOT_AUTHORIZED.clone())); + response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_NOT_AUTHORIZED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AuthCheckResponse::Forbidden(body) => { + AcceptEditgroupResponse::Forbidden(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::AUTH_CHECK_FORBIDDEN.clone())); + response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_FORBIDDEN.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AuthCheckResponse::GenericError(body) => { + AcceptEditgroupResponse::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::ACCEPT_EDITGROUP_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AcceptEditgroupResponse::EditConflict(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(409), body_string)); + response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_EDIT_CONFLICT.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + AcceptEditgroupResponse::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::AUTH_CHECK_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2780,12 +3214,12 @@ where Ok(response) }) }, - "AuthCheck", + "AcceptEditgroup", ); let api_clone = api.clone(); router.post( - "/v0/auth/oidc", + "/v0/editgroup", move |req: &mut Request| { let mut context = Context::default(); @@ -2804,46 +3238,34 @@ where // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let param_oidc_params = req + let param_editgroup = req .get::<bodyparser::Raw>() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter oidc_params - not valid UTF-8: {}", e))))?; + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editgroup - not valid UTF-8: {}", e))))?; let mut unused_elements = Vec::new(); - let param_oidc_params = if let Some(param_oidc_params_raw) = param_oidc_params { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_oidc_params_raw); + let param_editgroup = if let Some(param_editgroup_raw) = param_editgroup { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_editgroup_raw); - let param_oidc_params: Option<models::AuthOidc> = serde_ignored::deserialize(deserializer, |path| { + let param_editgroup: Option<models::Editgroup> = serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter oidc_params - doesn't match schema: {}", e))))?; + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editgroup - doesn't match schema: {}", e))))?; - param_oidc_params + param_editgroup } else { None }; - let param_oidc_params = param_oidc_params.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter oidc_params".to_string())))?; + let param_editgroup = param_editgroup.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter editgroup".to_string())))?; - match api.auth_oidc(param_oidc_params, context).wait() { + match api.create_editgroup(param_editgroup, context).wait() { Ok(rsp) => match rsp { - AuthOidcResponse::Found(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::AUTH_OIDC_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - AuthOidcResponse::Created(body) => { + CreateEditgroupResponse::SuccessfullyCreated(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(201), body_string)); - response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_CREATED.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_SUCCESSFULLY_CREATED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -2851,11 +3273,11 @@ where } Ok(response) } - AuthOidcResponse::BadRequest(body) => { + CreateEditgroupResponse::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::AUTH_OIDC_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -2863,14 +3285,14 @@ where } Ok(response) } - AuthOidcResponse::NotAuthorized { body, www_authenticate } => { + CreateEditgroupResponse::NotAuthorized { body, www_authenticate } => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(401), body_string)); header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_NOT_AUTHORIZED.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_NOT_AUTHORIZED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -2878,11 +3300,11 @@ where } Ok(response) } - AuthOidcResponse::Forbidden(body) => { + CreateEditgroupResponse::Forbidden(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_FORBIDDEN.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_FORBIDDEN.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -2890,11 +3312,11 @@ where } Ok(response) } - AuthOidcResponse::Conflict(body) => { + CreateEditgroupResponse::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(409), body_string)); - response.headers.set(ContentType(mimetypes::responses::AUTH_OIDC_CONFLICT.clone())); + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -2902,11 +3324,11 @@ where } Ok(response) } - AuthOidcResponse::GenericError(body) => { + CreateEditgroupResponse::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::AUTH_OIDC_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -2928,307 +3350,12 @@ where Ok(response) }) }, - "AuthOidc", - ); - - let api_clone = api.clone(); - router.get( - "/v0/editgroup/reviewable", - 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>(); - - // 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_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); - let param_limit = query_params - .get("limit") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<i64>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected integer)".to_string())))?; - let param_before = query_params - .get("before") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; - let param_since = query_params - .get("since") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; - - match api.get_editgroups_reviewable(param_expand, param_limit, param_before, param_since, context).wait() { - Ok(rsp) => match rsp { - GetEditgroupsReviewableResponse::Found(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_EDITGROUPS_REVIEWABLE_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditgroupsReviewableResponse::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_EDITGROUPS_REVIEWABLE_BAD_REQUEST.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditgroupsReviewableResponse::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_EDITGROUPS_REVIEWABLE_NOT_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditgroupsReviewableResponse::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_EDITGROUPS_REVIEWABLE_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) - }) - }, - "GetEditgroupsReviewable", - ); - - let api_clone = api.clone(); - router.get( - "/v0/editor/:editor_id", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> - where - T: Api, - { - context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::<AuthData>(); - context.authorization = req.extensions.remove::<Authorization>(); - - // Path parameters - let param_editor_id = { - let param = req - .extensions - .get::<Router>() - .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("editor_id") - .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editor_id".to_string())))?; - percent_decode(param.as_bytes()) - .decode_utf8() - .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? - .parse() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? - }; - - match api.get_editor(param_editor_id, context).wait() { - Ok(rsp) => match rsp { - GetEditorResponse::Found(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_EDITOR_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditorResponse::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_EDITOR_BAD_REQUEST.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditorResponse::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_EDITOR_NOT_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditorResponse::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_EDITOR_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) - }) - }, - "GetEditor", - ); - - let api_clone = api.clone(); - router.get( - "/v0/editor/:editor_id/editgroups", - 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_editor_id = { - let param = req - .extensions - .get::<Router>() - .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("editor_id") - .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editor_id".to_string())))?; - percent_decode(param.as_bytes()) - .decode_utf8() - .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? - .parse() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? - }; - - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) - let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); - let param_limit = query_params - .get("limit") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<i64>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected integer)".to_string())))?; - let param_before = query_params - .get("before") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; - let param_since = query_params - .get("since") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; - - match api.get_editor_editgroups(param_editor_id, param_limit, param_before, param_since, context).wait() { - Ok(rsp) => match rsp { - GetEditorEditgroupsResponse::Found(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_EDITOR_EDITGROUPS_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditorEditgroupsResponse::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_EDITOR_EDITGROUPS_BAD_REQUEST.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditorEditgroupsResponse::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_EDITOR_EDITGROUPS_NOT_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditorEditgroupsResponse::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_EDITOR_EDITGROUPS_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) - }) - }, - "GetEditorEditgroups", + "CreateEditgroup", ); let api_clone = api.clone(); - router.put( - "/v0/editgroup/:editgroup_id", + router.post( + "/v0/editgroup/:editgroup_id/annotation", move |req: &mut Request| { let mut context = Context::default(); @@ -3258,47 +3385,38 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editgroup_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_submit = query_params - .get("submit") - .and_then(|list| list.first()) - .and_then(|x| Some(x.to_lowercase().parse::<bool>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected boolean)".to_string())))?; - // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let param_editgroup = req + let param_annotation = req .get::<bodyparser::Raw>() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editgroup - not valid UTF-8: {}", e))))?; + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter annotation - not valid UTF-8: {}", e))))?; let mut unused_elements = Vec::new(); - let param_editgroup = if let Some(param_editgroup_raw) = param_editgroup { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_editgroup_raw); + let param_annotation = if let Some(param_annotation_raw) = param_annotation { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_annotation_raw); - let param_editgroup: Option<models::Editgroup> = serde_ignored::deserialize(deserializer, |path| { + let param_annotation: Option<models::EditgroupAnnotation> = serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editgroup - doesn't match schema: {}", e))))?; + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter annotation - doesn't match schema: {}", e))))?; - param_editgroup + param_annotation } else { None }; - let param_editgroup = param_editgroup.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter editgroup".to_string())))?; + let param_annotation = param_annotation.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter annotation".to_string())))?; - match api.update_editgroup(param_editgroup_id, param_editgroup, param_submit, context).wait() { + match api.create_editgroup_annotation(param_editgroup_id, param_annotation, context).wait() { Ok(rsp) => match rsp { - UpdateEditgroupResponse::UpdatedEditgroup(body) => { + CreateEditgroupAnnotationResponse::Created(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::UPDATE_EDITGROUP_UPDATED_EDITGROUP.clone())); + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_CREATED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3306,11 +3424,11 @@ where } Ok(response) } - UpdateEditgroupResponse::BadRequest(body) => { + CreateEditgroupAnnotationResponse::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::UPDATE_EDITGROUP_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3318,14 +3436,14 @@ where } Ok(response) } - UpdateEditgroupResponse::NotAuthorized { body, www_authenticate } => { + CreateEditgroupAnnotationResponse::NotAuthorized { body, www_authenticate } => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(401), body_string)); header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITGROUP_NOT_AUTHORIZED.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_NOT_AUTHORIZED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3333,11 +3451,11 @@ where } Ok(response) } - UpdateEditgroupResponse::Forbidden(body) => { + CreateEditgroupAnnotationResponse::Forbidden(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITGROUP_FORBIDDEN.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_FORBIDDEN.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3345,11 +3463,11 @@ where } Ok(response) } - UpdateEditgroupResponse::NotFound(body) => { + CreateEditgroupAnnotationResponse::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::UPDATE_EDITGROUP_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3357,11 +3475,11 @@ where } Ok(response) } - UpdateEditgroupResponse::GenericError(body) => { + CreateEditgroupAnnotationResponse::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::UPDATE_EDITGROUP_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3383,12 +3501,12 @@ where Ok(response) }) }, - "UpdateEditgroup", + "CreateEditgroupAnnotation", ); let api_clone = api.clone(); - router.put( - "/v0/editor/:editor_id", + router.get( + "/v0/editgroup/:editgroup_id", move |req: &mut Request| { let mut context = Context::default(); @@ -3401,123 +3519,61 @@ where context.auth_data = req.extensions.remove::<AuthData>(); context.authorization = req.extensions.remove::<Authorization>(); - let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; - // Path parameters - let param_editor_id = { + let param_editgroup_id = { let param = req .extensions .get::<Router>() .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("editor_id") - .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editor_id".to_string())))?; + .find("editgroup_id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editgroup_id".to_string())))?; percent_decode(param.as_bytes()) .decode_utf8() .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? .parse() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? - }; - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_editor = req - .get::<bodyparser::Raw>() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editor - not valid UTF-8: {}", e))))?; - - let mut unused_elements = Vec::new(); - - let param_editor = if let Some(param_editor_raw) = param_editor { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_editor_raw); - - let param_editor: Option<models::Editor> = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editor - doesn't match schema: {}", e))))?; - - param_editor - } else { - None + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editgroup_id: {}", e))))? }; - let param_editor = param_editor.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter editor".to_string())))?; - match api.update_editor(param_editor_id, param_editor, context).wait() { + match api.get_editgroup(param_editgroup_id, context).wait() { Ok(rsp) => match rsp { - UpdateEditorResponse::UpdatedEditor(body) => { + GetEditgroupResponse::Found(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::UPDATE_EDITOR_UPDATED_EDITOR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - UpdateEditorResponse::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::UPDATE_EDITOR_BAD_REQUEST.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } Ok(response) } - UpdateEditorResponse::NotAuthorized { body, www_authenticate } => { + GetEditgroupResponse::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(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_NOT_AUTHORIZED.clone())); + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - UpdateEditorResponse::Forbidden(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_FORBIDDEN.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } Ok(response) } - UpdateEditorResponse::NotFound(body) => { + GetEditgroupResponse::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::UPDATE_EDITOR_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } + Ok(response) } - UpdateEditorResponse::GenericError(body) => { + GetEditgroupResponse::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::UPDATE_EDITOR_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } + Ok(response) } }, @@ -3534,12 +3590,12 @@ where Ok(response) }) }, - "UpdateEditor", + "GetEditgroup", ); let api_clone = api.clone(); - router.post( - "/v0/editgroup/:editgroup_id/accept", + router.get( + "/v0/editgroup/:editgroup_id/annotations", move |req: &mut Request| { let mut context = Context::default(); @@ -3552,8 +3608,6 @@ where context.auth_data = req.extensions.remove::<AuthData>(); context.authorization = req.extensions.remove::<Authorization>(); - let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; - // Path parameters let param_editgroup_id = { let param = req @@ -3569,76 +3623,70 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editgroup_id: {}", e))))? }; - match api.accept_editgroup(param_editgroup_id, context).wait() { + // 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_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); + + match api.get_editgroup_annotations(param_editgroup_id, param_expand, context).wait() { Ok(rsp) => match rsp { - AcceptEditgroupResponse::MergedSuccessfully(body) => { + GetEditgroupAnnotationsResponse::Success(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_MERGED_SUCCESSFULLY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_ANNOTATIONS_SUCCESS.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AcceptEditgroupResponse::BadRequest(body) => { + GetEditgroupAnnotationsResponse::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::ACCEPT_EDITGROUP_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_ANNOTATIONS_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AcceptEditgroupResponse::NotAuthorized { body, www_authenticate } => { + GetEditgroupAnnotationsResponse::NotAuthorized { body, www_authenticate } => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(401), body_string)); header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_NOT_AUTHORIZED.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_ANNOTATIONS_NOT_AUTHORIZED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AcceptEditgroupResponse::Forbidden(body) => { + GetEditgroupAnnotationsResponse::Forbidden(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_FORBIDDEN.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_ANNOTATIONS_FORBIDDEN.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AcceptEditgroupResponse::NotFound(body) => { + GetEditgroupAnnotationsResponse::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::ACCEPT_EDITGROUP_NOT_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - AcceptEditgroupResponse::EditConflict(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(409), body_string)); - response.headers.set(ContentType(mimetypes::responses::ACCEPT_EDITGROUP_EDIT_CONFLICT.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_ANNOTATIONS_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - AcceptEditgroupResponse::GenericError(body) => { + GetEditgroupAnnotationsResponse::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::ACCEPT_EDITGROUP_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_ANNOTATIONS_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -3658,12 +3706,12 @@ where Ok(response) }) }, - "AcceptEditgroup", + "GetEditgroupAnnotations", ); let api_clone = api.clone(); - router.post( - "/v0/editgroup", + router.get( + "/v0/editgroup/reviewable", move |req: &mut Request| { let mut context = Context::default(); @@ -3676,108 +3724,68 @@ where context.auth_data = req.extensions.remove::<AuthData>(); context.authorization = req.extensions.remove::<Authorization>(); - let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_editgroup = req - .get::<bodyparser::Raw>() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editgroup - not valid UTF-8: {}", e))))?; - - let mut unused_elements = Vec::new(); - - let param_editgroup = if let Some(param_editgroup_raw) = param_editgroup { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_editgroup_raw); - - let param_editgroup: Option<models::Editgroup> = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editgroup - doesn't match schema: {}", e))))?; - - param_editgroup - } else { - None - }; - let param_editgroup = param_editgroup.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter editgroup".to_string())))?; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); + let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); + let param_limit = query_params + .get("limit") + .and_then(|list| list.first()) + .and_then(|x| Some(x.parse::<i64>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected integer)".to_string())))?; + let param_before = query_params + .get("before") + .and_then(|list| list.first()) + .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; + let param_since = query_params + .get("since") + .and_then(|list| list.first()) + .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; - match api.create_editgroup(param_editgroup, context).wait() { + match api.get_editgroups_reviewable(param_expand, param_limit, param_before, param_since, context).wait() { Ok(rsp) => match rsp { - CreateEditgroupResponse::SuccessfullyCreated(body) => { + GetEditgroupsReviewableResponse::Found(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - let mut response = Response::with((status::Status::from_u16(201), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_SUCCESSFULLY_CREATED.clone())); + let mut response = Response::with((status::Status::from_u16(200), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUPS_REVIEWABLE_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - CreateEditgroupResponse::BadRequest(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_BAD_REQUEST.clone())); - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } Ok(response) } - CreateEditgroupResponse::NotAuthorized { body, www_authenticate } => { + GetEditgroupsReviewableResponse::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(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_NOT_AUTHORIZED.clone())); + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUPS_REVIEWABLE_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - CreateEditgroupResponse::Forbidden(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_FORBIDDEN.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } Ok(response) } - CreateEditgroupResponse::NotFound(body) => { + GetEditgroupsReviewableResponse::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::CREATE_EDITGROUP_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUPS_REVIEWABLE_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } + Ok(response) } - CreateEditgroupResponse::GenericError(body) => { + GetEditgroupsReviewableResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUPS_REVIEWABLE_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } + Ok(response) } }, @@ -3794,12 +3802,12 @@ where Ok(response) }) }, - "CreateEditgroup", + "GetEditgroupsReviewable", ); let api_clone = api.clone(); - router.post( - "/v0/editgroup/:editgroup_id/annotation", + router.put( + "/v0/editgroup/:editgroup_id", move |req: &mut Request| { let mut context = Context::default(); @@ -3829,38 +3837,47 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editgroup_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_submit = query_params + .get("submit") + .and_then(|list| list.first()) + .and_then(|x| Some(x.to_lowercase().parse::<bool>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected boolean)".to_string())))?; + // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let param_annotation = req + let param_editgroup = req .get::<bodyparser::Raw>() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter annotation - not valid UTF-8: {}", e))))?; + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editgroup - not valid UTF-8: {}", e))))?; let mut unused_elements = Vec::new(); - let param_annotation = if let Some(param_annotation_raw) = param_annotation { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_annotation_raw); + let param_editgroup = if let Some(param_editgroup_raw) = param_editgroup { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_editgroup_raw); - let param_annotation: Option<models::EditgroupAnnotation> = serde_ignored::deserialize(deserializer, |path| { + let param_editgroup: Option<models::Editgroup> = serde_ignored::deserialize(deserializer, |path| { warn!("Ignoring unknown field in body: {}", path); unused_elements.push(path.to_string()); }) - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter annotation - doesn't match schema: {}", e))))?; + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editgroup - doesn't match schema: {}", e))))?; - param_annotation + param_editgroup } else { None }; - let param_annotation = param_annotation.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter annotation".to_string())))?; + let param_editgroup = param_editgroup.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter editgroup".to_string())))?; - match api.create_editgroup_annotation(param_editgroup_id, param_annotation, context).wait() { + match api.update_editgroup(param_editgroup_id, param_editgroup, param_submit, context).wait() { Ok(rsp) => match rsp { - CreateEditgroupAnnotationResponse::Created(body) => { + UpdateEditgroupResponse::UpdatedEditgroup(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - let mut response = Response::with((status::Status::from_u16(201), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_CREATED.clone())); + let mut response = Response::with((status::Status::from_u16(200), body_string)); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITGROUP_UPDATED_EDITGROUP.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3868,11 +3885,11 @@ where } Ok(response) } - CreateEditgroupAnnotationResponse::BadRequest(body) => { + UpdateEditgroupResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITGROUP_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3880,14 +3897,14 @@ where } Ok(response) } - CreateEditgroupAnnotationResponse::NotAuthorized { body, www_authenticate } => { + UpdateEditgroupResponse::NotAuthorized { body, www_authenticate } => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(401), body_string)); header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_NOT_AUTHORIZED.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITGROUP_NOT_AUTHORIZED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3895,11 +3912,11 @@ where } Ok(response) } - CreateEditgroupAnnotationResponse::Forbidden(body) => { + UpdateEditgroupResponse::Forbidden(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_FORBIDDEN.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITGROUP_FORBIDDEN.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3907,11 +3924,11 @@ where } Ok(response) } - CreateEditgroupAnnotationResponse::NotFound(body) => { + UpdateEditgroupResponse::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::CREATE_EDITGROUP_ANNOTATION_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITGROUP_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3919,11 +3936,11 @@ where } Ok(response) } - CreateEditgroupAnnotationResponse::GenericError(body) => { + UpdateEditgroupResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_EDITGROUP_ANNOTATION_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITGROUP_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); if !unused_elements.is_empty() { @@ -3945,85 +3962,12 @@ where Ok(response) }) }, - "CreateEditgroupAnnotation", - ); - - let api_clone = api.clone(); - router.get( - "/v0/changelog", - 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>(); - - // 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| Some(x.parse::<i64>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected integer)".to_string())))?; - - match api.get_changelog(param_limit, context).wait() { - Ok(rsp) => match rsp { - GetChangelogResponse::Success(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_CHANGELOG_SUCCESS.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetChangelogResponse::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_CHANGELOG_BAD_REQUEST.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetChangelogResponse::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_CHANGELOG_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) - }) - }, - "GetChangelog", + "UpdateEditgroup", ); let api_clone = api.clone(); router.get( - "/v0/changelog/:index", + "/v0/editor/:editor_id", move |req: &mut Request| { let mut context = Context::default(); @@ -4037,57 +3981,57 @@ where context.authorization = req.extensions.remove::<Authorization>(); // Path parameters - let param_index = { + let param_editor_id = { let param = req .extensions .get::<Router>() .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("index") - .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter index".to_string())))?; + .find("editor_id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editor_id".to_string())))?; percent_decode(param.as_bytes()) .decode_utf8() .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? .parse() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter index: {}", e))))? + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? }; - match api.get_changelog_entry(param_index, context).wait() { + match api.get_editor(param_editor_id, context).wait() { Ok(rsp) => match rsp { - GetChangelogEntryResponse::FoundChangelogEntry(body) => { + GetEditorResponse::Found(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_CHANGELOG_ENTRY_FOUND_CHANGELOG_ENTRY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetChangelogEntryResponse::BadRequest(body) => { + GetEditorResponse::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_CHANGELOG_ENTRY_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetChangelogEntryResponse::NotFound(body) => { + GetEditorResponse::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_CHANGELOG_ENTRY_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetChangelogEntryResponse::GenericError(body) => { + GetEditorResponse::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_CHANGELOG_ENTRY_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -4107,12 +4051,12 @@ where Ok(response) }) }, - "GetChangelogEntry", + "GetEditor", ); let api_clone = api.clone(); router.get( - "/v0/editgroup/:editgroup_id", + "/v0/editor/:editor_id/annotations", move |req: &mut Request| { let mut context = Context::default(); @@ -4126,57 +4070,101 @@ where context.authorization = req.extensions.remove::<Authorization>(); // Path parameters - let param_editgroup_id = { + let param_editor_id = { let param = req .extensions .get::<Router>() .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("editgroup_id") - .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editgroup_id".to_string())))?; + .find("editor_id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editor_id".to_string())))?; percent_decode(param.as_bytes()) .decode_utf8() .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? .parse() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editgroup_id: {}", e))))? + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? }; - match api.get_editgroup(param_editgroup_id, context).wait() { + // 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| Some(x.parse::<i64>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected integer)".to_string())))?; + let param_before = query_params + .get("before") + .and_then(|list| list.first()) + .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; + let param_since = query_params + .get("since") + .and_then(|list| list.first()) + .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; + + match api.get_editor_annotations(param_editor_id, param_limit, param_before, param_since, context).wait() { Ok(rsp) => match rsp { - GetEditgroupResponse::Found(body) => { + GetEditorAnnotationsResponse::Success(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_ANNOTATIONS_SUCCESS.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupResponse::BadRequest(body) => { + GetEditorAnnotationsResponse::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_EDITGROUP_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_ANNOTATIONS_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupResponse::NotFound(body) => { + GetEditorAnnotationsResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_ANNOTATIONS_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetEditorAnnotationsResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_ANNOTATIONS_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetEditorAnnotationsResponse::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_EDITGROUP_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_ANNOTATIONS_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupResponse::GenericError(body) => { + GetEditorAnnotationsResponse::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_EDITGROUP_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_ANNOTATIONS_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -4196,12 +4184,12 @@ where Ok(response) }) }, - "GetEditgroup", + "GetEditorAnnotations", ); let api_clone = api.clone(); router.get( - "/v0/editgroup/:editgroup_id/annotations", + "/v0/editor/:editor_id/editgroups", move |req: &mut Request| { let mut context = Context::default(); @@ -4215,84 +4203,78 @@ where context.authorization = req.extensions.remove::<Authorization>(); // Path parameters - let param_editgroup_id = { + let param_editor_id = { let param = req .extensions .get::<Router>() .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("editgroup_id") - .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editgroup_id".to_string())))?; + .find("editor_id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editor_id".to_string())))?; percent_decode(param.as_bytes()) .decode_utf8() .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? .parse() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editgroup_id: {}", e))))? + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? }; // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); - let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::<String>().ok()); + let param_limit = query_params + .get("limit") + .and_then(|list| list.first()) + .and_then(|x| Some(x.parse::<i64>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected integer)".to_string())))?; + let param_before = query_params + .get("before") + .and_then(|list| list.first()) + .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; + let param_since = query_params + .get("since") + .and_then(|list| list.first()) + .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) + .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) + .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; - match api.get_editgroup_annotations(param_editgroup_id, param_expand, context).wait() { + match api.get_editor_editgroups(param_editor_id, param_limit, param_before, param_since, context).wait() { Ok(rsp) => match rsp { - GetEditgroupAnnotationsResponse::Success(body) => { + GetEditorEditgroupsResponse::Found(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_EDITGROUP_ANNOTATIONS_SUCCESS.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_EDITGROUPS_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupAnnotationsResponse::BadRequest(body) => { + GetEditorEditgroupsResponse::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_EDITGROUP_ANNOTATIONS_BAD_REQUEST.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditgroupAnnotationsResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_ANNOTATIONS_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetEditgroupAnnotationsResponse::Forbidden(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_ANNOTATIONS_FORBIDDEN.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_EDITGROUPS_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupAnnotationsResponse::NotFound(body) => { + GetEditorEditgroupsResponse::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_EDITGROUP_ANNOTATIONS_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_EDITGROUPS_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupAnnotationsResponse::GenericError(body) => { + GetEditorEditgroupsResponse::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_EDITGROUP_ANNOTATIONS_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_EDITGROUPS_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -4312,12 +4294,12 @@ where Ok(response) }) }, - "GetEditgroupAnnotations", + "GetEditorEditgroups", ); let api_clone = api.clone(); - router.get( - "/v0/editor/:editor_id/annotations", + router.put( + "/v0/editor/:editor_id", move |req: &mut Request| { let mut context = Context::default(); @@ -4330,6 +4312,8 @@ where context.auth_data = req.extensions.remove::<AuthData>(); context.authorization = req.extensions.remove::<Authorization>(); + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + // Path parameters let param_editor_id = { let param = req @@ -4345,90 +4329,106 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter editor_id: {}", e))))? }; - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) - let query_params = req.get::<UrlEncodedQuery>().unwrap_or_default(); - let param_limit = query_params - .get("limit") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<i64>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected integer)".to_string())))?; - let param_before = query_params - .get("before") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; - let param_since = query_params - .get("since") - .and_then(|list| list.first()) - .and_then(|x| Some(x.parse::<chrono::DateTime<chrono::Utc>>())) - .map_or_else(|| Ok(None), |x| x.map(|v| Some(v))) - .map_err(|x| Response::with((status::BadRequest, "unparsable query parameter (expected UTC datetime in ISO/RFC format)".to_string())))?; + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. - match api.get_editor_annotations(param_editor_id, param_limit, param_before, param_since, context).wait() { + let param_editor = req + .get::<bodyparser::Raw>() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editor - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_editor = if let Some(param_editor_raw) = param_editor { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_editor_raw); + + let param_editor: Option<models::Editor> = serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter editor - doesn't match schema: {}", e))))?; + + param_editor + } else { + None + }; + let param_editor = param_editor.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter editor".to_string())))?; + + match api.update_editor(param_editor_id, param_editor, context).wait() { Ok(rsp) => match rsp { - GetEditorAnnotationsResponse::Success(body) => { + UpdateEditorResponse::UpdatedEditor(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_EDITOR_ANNOTATIONS_SUCCESS.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_UPDATED_EDITOR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } Ok(response) } - GetEditorAnnotationsResponse::BadRequest(body) => { + UpdateEditorResponse::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_EDITOR_ANNOTATIONS_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } Ok(response) } - GetEditorAnnotationsResponse::NotAuthorized { body, www_authenticate } => { + UpdateEditorResponse::NotAuthorized { body, www_authenticate } => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(401), body_string)); header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_ANNOTATIONS_NOT_AUTHORIZED.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_NOT_AUTHORIZED.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } Ok(response) } - GetEditorAnnotationsResponse::Forbidden(body) => { + UpdateEditorResponse::Forbidden(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_ANNOTATIONS_FORBIDDEN.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_FORBIDDEN.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } Ok(response) } - GetEditorAnnotationsResponse::NotFound(body) => { + UpdateEditorResponse::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_EDITOR_ANNOTATIONS_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } Ok(response) } - GetEditorAnnotationsResponse::GenericError(body) => { + UpdateEditorResponse::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_EDITOR_ANNOTATIONS_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::UPDATE_EDITOR_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } Ok(response) } }, @@ -4445,7 +4445,7 @@ where Ok(response) }) }, - "GetEditorAnnotations", + "UpdateEditor", ); let api_clone = api.clone(); @@ -7156,157 +7156,6 @@ where ); let api_clone = api.clone(); - router.post( - "/v0/editgroup/:editgroup_id/work", - move |req: &mut Request| { - let mut context = Context::default(); - - // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). - fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> - where - T: Api, - { - context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); - context.auth_data = req.extensions.remove::<AuthData>(); - context.authorization = req.extensions.remove::<Authorization>(); - - let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; - - // Path parameters - let param_editgroup_id = { - let param = req - .extensions - .get::<Router>() - .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("editgroup_id") - .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editgroup_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 editgroup_id: {}", e))))? - }; - - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - - let param_entity = req - .get::<bodyparser::Raw>() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity - not valid UTF-8: {}", e))))?; - - let mut unused_elements = Vec::new(); - - let param_entity = if let Some(param_entity_raw) = param_entity { - let deserializer = &mut serde_json::Deserializer::from_str(¶m_entity_raw); - - let param_entity: Option<models::WorkEntity> = serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity - doesn't match schema: {}", e))))?; - - param_entity - } else { - None - }; - let param_entity = param_entity.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity".to_string())))?; - - match api.create_work(param_editgroup_id, param_entity, context).wait() { - Ok(rsp) => match rsp { - CreateWorkResponse::CreatedEntity(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(201), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_CREATED_ENTITY.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - CreateWorkResponse::BadRequest(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_BAD_REQUEST.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - CreateWorkResponse::NotAuthorized { body, www_authenticate } => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(401), body_string)); - header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } - response.headers.set(ResponseWwwAuthenticate(www_authenticate)); - - response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_NOT_AUTHORIZED.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - CreateWorkResponse::Forbidden(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(403), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_FORBIDDEN.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - CreateWorkResponse::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::CREATE_WORK_NOT_FOUND.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - Ok(response) - } - CreateWorkResponse::GenericError(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_GENERIC_ERROR.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - if !unused_elements.is_empty() { - response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); - } - 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) - }) - }, - "CreateWork", - ); - - let api_clone = api.clone(); router.delete( "/v0/editgroup/:editgroup_id/release/:ident", move |req: &mut Request| { @@ -9744,6 +9593,157 @@ where let api_clone = api.clone(); router.post( + "/v0/editgroup/:editgroup_id/work", + move |req: &mut Request| { + let mut context = Context::default(); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn handle_request<T>(req: &mut Request, api: &T, context: &mut Context) -> Result<Response, Response> + where + T: Api, + { + context.x_span_id = Some(req.headers.get::<XSpanId>().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::<AuthData>(); + context.authorization = req.extensions.remove::<Authorization>(); + + let authorization = context.authorization.as_ref().ok_or_else(|| Response::with((status::Forbidden, "Unauthenticated".to_string())))?; + + // Path parameters + let param_editgroup_id = { + let param = req + .extensions + .get::<Router>() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("editgroup_id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter editgroup_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 editgroup_id: {}", e))))? + }; + + // Body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + + let param_entity = req + .get::<bodyparser::Raw>() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity - not valid UTF-8: {}", e))))?; + + let mut unused_elements = Vec::new(); + + let param_entity = if let Some(param_entity_raw) = param_entity { + let deserializer = &mut serde_json::Deserializer::from_str(¶m_entity_raw); + + let param_entity: Option<models::WorkEntity> = serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {}", path); + unused_elements.push(path.to_string()); + }) + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse body parameter entity - doesn't match schema: {}", e))))?; + + param_entity + } else { + None + }; + let param_entity = param_entity.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity".to_string())))?; + + match api.create_work(param_editgroup_id, param_entity, context).wait() { + Ok(rsp) => match rsp { + CreateWorkResponse::CreatedEntity(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(201), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_CREATED_ENTITY.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreateWorkResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreateWorkResponse::NotAuthorized { body, www_authenticate } => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(401), body_string)); + header! { (ResponseWwwAuthenticate, "WWW_Authenticate") => [String] } + response.headers.set(ResponseWwwAuthenticate(www_authenticate)); + + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_NOT_AUTHORIZED.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreateWorkResponse::Forbidden(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(403), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_FORBIDDEN.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreateWorkResponse::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::CREATE_WORK_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + Ok(response) + } + CreateWorkResponse::GenericError(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(500), body_string)); + response.headers.set(ContentType(mimetypes::responses::CREATE_WORK_GENERIC_ERROR.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + if !unused_elements.is_empty() { + response.headers.set(Warning(format!("Ignoring unknown fields in body: {:?}", unused_elements))); + } + 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) + }) + }, + "CreateWork", + ); + + let api_clone = api.clone(); + router.post( "/v0/editgroup/auto/work/batch", move |req: &mut Request| { let mut context = Context::default(); |