From b83347388d17dfd58c9f3d123d3d96d050ca6e9b Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 16 Aug 2018 09:42:55 -0700 Subject: ORCIDs can end in X character --- rust/fatcat-api/README.md | 2 +- rust/fatcat-api/api.yaml | 2 +- rust/fatcat-api/api/swagger.yaml | 6 +++--- rust/src/api_helpers.rs | 10 +++++++++- 4 files changed, 14 insertions(+), 6 deletions(-) (limited to 'rust') diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index af4e6a5b..1e382370 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-08-15T00:04:03.771Z +- Build date: 2018-08-16T16:42:27.600Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index 7ec91bad..524333ce 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -37,7 +37,7 @@ x-issn: &FATCATISSN x-orcid: &FATCATORCID type: string example: "0000-0002-1825-0097" - pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{4}" + pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]" minLength: 19 maxLength: 19 diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index c572fd29..021594c0 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -612,7 +612,7 @@ paths: type: "string" maxLength: 19 minLength: 19 - pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{4}" + pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]" formatString: "\\\"{}\\\"" example: "\"orcid_example\".to_string()" responses: @@ -2061,7 +2061,7 @@ definitions: example: "0000-0002-1825-0097" minLength: 19 maxLength: 19 - pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{4}" + pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]" surname: type: "string" given_name: @@ -3180,7 +3180,7 @@ x-issn: x-orcid: type: "string" example: "0000-0002-1825-0097" - pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{4}" + pattern: "\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]" minLength: 19 maxLength: 19 x-entity-props: diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 489631b3..020aad76 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -181,7 +181,7 @@ pub fn check_issn(raw: &str) -> Result<()> { pub fn check_orcid(raw: &str) -> Result<()> { lazy_static! { - static ref RE: Regex = Regex::new(r"^\d{4}-\d{4}-\d{4}-\d{4}$").unwrap(); + static ref RE: Regex = Regex::new(r"^\d{4}-\d{4}-\d{4}-\d{3}[\dX]$").unwrap(); } if RE.is_match(raw) { Ok(()) @@ -193,6 +193,14 @@ pub fn check_orcid(raw: &str) -> Result<()> { } } +#[test] +fn test_check_orcid() { + assert!(check_orcid("0123-4567-3456-6789").is_ok()); + assert!(check_orcid("0123-4567-3456-678X").is_ok()); + assert!(check_orcid("01234567-3456-6780").is_err()); + assert!(check_orcid("0x23-4567-3456-6780").is_err()); +} + // TODO: make the above checks "more correct" // TODO: check ISBN-13 // TODO: check hashes (SHA-1, etc) -- cgit v1.2.3 From 21fd7bd5d15850da942991bcdb7c00c3332231cc Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sat, 18 Aug 2018 01:16:14 -0700 Subject: create index on release_rev_abstracts --- rust/migrations/2018-05-12-001226_init/up.sql | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index 783d2f94..960623a3 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -209,6 +209,8 @@ CREATE TABLE release_rev_abstract ( lang TEXT ); +CREATE INDEX release_rev_abstract_rev_idx ON release_rev_abstract(release_rev); + CREATE TABLE release_ident ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), is_live BOOL NOT NULL DEFAULT false, -- cgit v1.2.3 From bed06d8726a063e177ccd8a40554a799e0fdb1f1 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sun, 19 Aug 2018 16:45:51 -0700 Subject: add index on file_rev_url file_rev --- rust/migrations/2018-05-12-001226_init/up.sql | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index 960623a3..a1de656d 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -145,6 +145,8 @@ CREATE TABLE file_rev_url ( url TEXT NOT NULL ); +CREATE INDEX file_rev_url_rev_idx ON file_rev_url(file_rev); + CREATE TABLE file_ident ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), is_live BOOL NOT NULL DEFAULT false, -- cgit v1.2.3 From 42fa2a4d01d31922de2a61881860840f2bfa80f5 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sun, 19 Aug 2018 18:27:48 -0700 Subject: add index on release_rev_abstract SHA1 column --- rust/migrations/2018-05-12-001226_init/up.sql | 1 + 1 file changed, 1 insertion(+) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index a1de656d..024273a7 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -212,6 +212,7 @@ CREATE TABLE release_rev_abstract ( ); CREATE INDEX release_rev_abstract_rev_idx ON release_rev_abstract(release_rev); +CREATE INDEX release_rev_abstract_sha1_idx ON release_rev_abstract(abstract_sha1); CREATE TABLE release_ident ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), -- cgit v1.2.3 From 582d2397004b8a55847a3fe933cc29e8b99ab8f6 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sun, 19 Aug 2018 18:31:09 -0700 Subject: add hints for postgres query planner --- rust/src/api_server.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index f7866b68..9239d63b 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -318,6 +318,9 @@ impl Server { let (ident, rev): (ContainerIdentRow, ContainerRevRow) = container_ident::table .inner_join(container_rev::table) .filter(container_rev::issnl.eq(issnl)) + // This NOT NULL is here to ensure the postgresql query planner that it can use an + // index + .filter(container_rev::issnl.is_not_null()) .filter(container_ident::is_live.eq(true)) .filter(container_ident::redirect_id.is_null()) .first(conn)?; @@ -344,6 +347,9 @@ impl Server { let (ident, rev): (CreatorIdentRow, CreatorRevRow) = creator_ident::table .inner_join(creator_rev::table) .filter(creator_rev::orcid.eq(orcid)) + // This NOT NULL is here to ensure the postgresql query planner that it can use an + // index + .filter(creator_rev::orcid.is_not_null()) .filter(creator_ident::is_live.eq(true)) .filter(creator_ident::redirect_id.is_null()) .first(conn)?; -- cgit v1.2.3 From 657c1e7d4d6f07762bc1f6a7b24e9512e0089987 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sun, 19 Aug 2018 18:42:21 -0700 Subject: add NOT NULL to other lookups --- rust/src/api_server.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 9239d63b..66e6359a 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -396,6 +396,9 @@ impl Server { let (ident, rev): (FileIdentRow, FileRevRow) = file_ident::table .inner_join(file_rev::table) .filter(file_rev::sha1.eq(sha1)) + // This NOT NULL is here to ensure the postgresql query planner that it can use an + // index + .filter(file_rev::sha1.is_not_null()) .filter(file_ident::is_live.eq(true)) .filter(file_ident::redirect_id.is_null()) .first(conn)?; @@ -434,6 +437,9 @@ impl Server { let (ident, rev): (ReleaseIdentRow, ReleaseRevRow) = release_ident::table .inner_join(release_rev::table) .filter(release_rev::doi.eq(doi)) + // This NOT NULL is here to ensure the postgresql query planner that it can use an + // index + .filter(release_rev::doi.is_not_null()) .filter(release_ident::is_live.eq(true)) .filter(release_ident::redirect_id.is_null()) .first(conn)?; -- cgit v1.2.3 From b8ca8ebdae304dcc2a694e5dfbc9070003f0df8a Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 20 Aug 2018 01:18:10 -0700 Subject: use index_val, not index, in SQL schema --- rust/migrations/2018-05-12-001226_init/up.sql | 8 ++++---- rust/src/api_server.rs | 12 ++++++------ rust/src/database_models.rs | 8 ++++---- rust/src/database_schema.rs | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'rust') diff --git a/rust/migrations/2018-05-12-001226_init/up.sql b/rust/migrations/2018-05-12-001226_init/up.sql index 024273a7..b0733576 100644 --- a/rust/migrations/2018-05-12-001226_init/up.sql +++ b/rust/migrations/2018-05-12-001226_init/up.sql @@ -276,7 +276,7 @@ CREATE TABLE release_contrib ( creator_ident_id UUID REFERENCES creator_ident(id), raw_name TEXT, role TEXT, -- TODO: enum? - index BIGINT, + index_val BIGINT, extra_json JSON ); @@ -287,7 +287,7 @@ CREATE TABLE release_ref ( id BIGSERIAL PRIMARY KEY, release_rev UUID REFERENCES release_rev(id) NOT NULL, target_release_ident_id UUID REFERENCES release_ident(id), -- or work? - index BIGINT, + index_val BIGINT, key TEXT, extra_json JSON, -- title, year, container_title, locator (aka, page), oci_id container_title TEXT, @@ -432,12 +432,12 @@ INSERT INTO release_rev_abstract (release_rev, abstract_sha1, mimetype, lang) VA ('00000000-0000-0000-4444-FFF000000001', '1ba86bf8c2979a62d29b18b537e50b2b093be27e', 'text/plain', 'en'), ('00000000-0000-0000-4444-FFF000000002', '0da908ab584b5e445a06beb172e3fab8cb5169e3', 'application/xml+jats', 'en'); -INSERT INTO release_contrib (release_rev, creator_ident_id, raw_name, role, index) VALUES +INSERT INTO release_contrib (release_rev, creator_ident_id, raw_name, role, index_val) VALUES ('00000000-0000-0000-4444-FFF000000002', null, null, null, null), ('00000000-0000-0000-4444-FFF000000002', '00000000-0000-0000-2222-000000000002', 'some contrib', 'editor', 4), ('00000000-0000-0000-4444-FFF000000003', '00000000-0000-0000-2222-000000000003', 'John P. A. Ioannidis', 'author', 0); -INSERT INTO release_ref (release_rev, target_release_ident_id, index, extra_json) VALUES +INSERT INTO release_ref (release_rev, target_release_ident_id, index_val, extra_json) VALUES ('00000000-0000-0000-4444-FFF000000002', null, null, null), ('00000000-0000-0000-4444-FFF000000002', '00000000-0000-0000-4444-000000000001', 4, '{"unstructured":"citation note"}'), ('00000000-0000-0000-4444-FFF000000003', null, 0, '{"unstructured": "Ioannidis JP, Haidich AB, Lau J. Any casualties in the clash of randomised and observational evidence? BMJ. 2001;322:879–880"}'), diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 66e6359a..b0dff173 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -198,12 +198,12 @@ fn release_row2entity( let refs: Vec = release_ref::table .filter(release_ref::release_rev.eq(rev.id)) - .order(release_ref::index.asc()) + .order(release_ref::index_val.asc()) .get_results(conn) .expect("fetch release refs") .into_iter() .map(|r: ReleaseRefRow| ReleaseRef { - index: r.index, + index: r.index_val, key: r.key, extra: r.extra_json, container_title: r.container_title, @@ -216,12 +216,12 @@ fn release_row2entity( let contribs: Vec = release_contrib::table .filter(release_contrib::release_rev.eq(rev.id)) - .order((release_contrib::role.asc(), release_contrib::index.asc())) + .order((release_contrib::role.asc(), release_contrib::index_val.asc())) .get_results(conn) .expect("fetch release refs") .into_iter() .map(|c: ReleaseContribRow| ReleaseContrib { - index: c.index, + index: c.index_val, raw_name: c.raw_name, role: c.role, extra: c.extra_json, @@ -741,7 +741,7 @@ impl Server { target_release_ident_id: r.target_release_id .clone() .map(|v| fcid2uuid(&v).expect("valid fatcat identifier")), - index: r.index, + index_val: r.index, key: r.key.clone(), container_title: r.container_title.clone(), year: r.year, @@ -773,7 +773,7 @@ impl Server { .clone() .map(|v| fcid2uuid(&v).expect("valid fatcat identifier")), raw_name: c.raw_name.clone(), - index: c.index, + index_val: c.index, role: c.role.clone(), extra_json: c.extra.clone(), }) diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index 258bcab7..47e00bcf 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -228,7 +228,7 @@ pub struct ReleaseContribRow { pub creator_ident_id: Option, pub raw_name: Option, pub role: Option, - pub index: Option, + pub index_val: Option, pub extra_json: Option, } @@ -239,7 +239,7 @@ pub struct ReleaseContribNewRow { pub creator_ident_id: Option, pub raw_name: Option, pub role: Option, - pub index: Option, + pub index_val: Option, pub extra_json: Option, } @@ -249,7 +249,7 @@ pub struct ReleaseRefRow { pub id: i64, pub release_rev: Uuid, pub target_release_ident_id: Option, - pub index: Option, + pub index_val: Option, pub key: Option, pub extra_json: Option, pub container_title: Option, @@ -263,7 +263,7 @@ pub struct ReleaseRefRow { pub struct ReleaseRefNewRow { pub release_rev: Uuid, pub target_release_ident_id: Option, - pub index: Option, + pub index_val: Option, pub key: Option, pub extra_json: Option, pub container_title: Option, diff --git a/rust/src/database_schema.rs b/rust/src/database_schema.rs index 3a8fe901..a6605d81 100644 --- a/rust/src/database_schema.rs +++ b/rust/src/database_schema.rs @@ -159,7 +159,7 @@ table! { creator_ident_id -> Nullable, raw_name -> Nullable, role -> Nullable, - index -> Nullable, + index_val -> Nullable, extra_json -> Nullable, } } @@ -191,7 +191,7 @@ table! { id -> Int8, release_rev -> Uuid, target_release_ident_id -> Nullable, - index -> Nullable, + index_val -> Nullable, key -> Nullable, extra_json -> Nullable, container_title -> Nullable, -- cgit v1.2.3 From bf4a949f83b30a8e9bb501871bc62224472c59aa Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 20 Aug 2018 02:15:50 -0700 Subject: codegen --- rust/fatcat-api/README.md | 2 +- rust/fatcat-api/api.yaml | 29 +++++++++++ rust/fatcat-api/api/swagger.yaml | 40 +++++++++++++++ rust/fatcat-api/examples/client.rs | 10 ++-- rust/fatcat-api/examples/server_lib/server.rs | 46 +++++++++++++---- rust/fatcat-api/src/client.rs | 72 +++++++++++++++++++++++---- rust/fatcat-api/src/lib.rs | 45 +++++++++-------- rust/fatcat-api/src/server.rs | 30 +++++++++-- 8 files changed, 223 insertions(+), 51 deletions(-) (limited to 'rust') diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index 1e382370..d0b266aa 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-08-16T16:42:27.600Z +- Build date: 2018-08-20T08:47:01.260Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index 524333ce..fda630dd 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -57,6 +57,10 @@ x-entity-props: &ENTITYPROPS extra: type: object additionalProperties: {} +# TODO: +# edit_extra: +# type: object +# additionalProperties: {} definitions: error_response: @@ -438,6 +442,11 @@ paths: post: operationId: "create_container_batch" parameters: + - name: autoaccept + in: query + type: boolean + required: false + description: "If true, and editor is authorized, batch is accepted all at once" - name: entity_list in: body required: true @@ -526,6 +535,11 @@ paths: post: operationId: "create_creator_batch" parameters: + - name: autoaccept + in: query + type: boolean + required: false + description: "If true, and editor is authorized, batch is accepted all at once" - name: entity_list in: body required: true @@ -630,6 +644,11 @@ paths: post: operationId: "create_file_batch" parameters: + - name: autoaccept + in: query + type: boolean + required: false + description: "If true, and editor is authorized, batch is accepted all at once" - name: entity_list in: body required: true @@ -718,6 +737,11 @@ paths: post: operationId: "create_release_batch" parameters: + - name: autoaccept + in: query + type: boolean + required: false + description: "If true, and editor is authorized, batch is accepted all at once" - name: entity_list in: body required: true @@ -822,6 +846,11 @@ paths: post: operationId: "create_work_batch" parameters: + - name: autoaccept + in: query + type: boolean + required: false + description: "If true, and editor is authorized, batch is accepted all at once" - name: entity_list in: body required: true diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index 021594c0..11f789dc 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -76,6 +76,14 @@ paths: post: operationId: "create_container_batch" parameters: + - name: "autoaccept" + in: "query" + description: "If true, and editor is authorized, batch is accepted all at\ + \ once" + required: false + type: "boolean" + formatString: "{:?}" + example: "Some(true)" - in: "body" name: "entity_list" required: true @@ -371,6 +379,14 @@ paths: post: operationId: "create_creator_batch" parameters: + - name: "autoaccept" + in: "query" + description: "If true, and editor is authorized, batch is accepted all at\ + \ once" + required: false + type: "boolean" + formatString: "{:?}" + example: "Some(true)" - in: "body" name: "entity_list" required: true @@ -720,6 +736,14 @@ paths: post: operationId: "create_file_batch" parameters: + - name: "autoaccept" + in: "query" + description: "If true, and editor is authorized, batch is accepted all at\ + \ once" + required: false + type: "boolean" + formatString: "{:?}" + example: "Some(true)" - in: "body" name: "entity_list" required: true @@ -1012,6 +1036,14 @@ paths: post: operationId: "create_release_batch" parameters: + - name: "autoaccept" + in: "query" + description: "If true, and editor is authorized, batch is accepted all at\ + \ once" + required: false + type: "boolean" + formatString: "{:?}" + example: "Some(true)" - in: "body" name: "entity_list" required: true @@ -1358,6 +1390,14 @@ paths: post: operationId: "create_work_batch" parameters: + - name: "autoaccept" + in: "query" + description: "If true, and editor is authorized, batch is accepted all at\ + \ once" + required: false + type: "boolean" + formatString: "{:?}" + example: "Some(true)" - in: "body" name: "entity_list" required: true diff --git a/rust/fatcat-api/examples/client.rs b/rust/fatcat-api/examples/client.rs index f98518cc..06519232 100644 --- a/rust/fatcat-api/examples/client.rs +++ b/rust/fatcat-api/examples/client.rs @@ -95,7 +95,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateContainerBatch") => { - let result = client.create_container_batch(&Vec::new()).wait(); + let result = client.create_container_batch(&Vec::new(), Some(true)).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } @@ -105,7 +105,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateCreatorBatch") => { - let result = client.create_creator_batch(&Vec::new()).wait(); + let result = client.create_creator_batch(&Vec::new(), Some(true)).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } @@ -121,7 +121,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateFileBatch") => { - let result = client.create_file_batch(&Vec::new()).wait(); + let result = client.create_file_batch(&Vec::new(), Some(true)).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } @@ -131,7 +131,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateReleaseBatch") => { - let result = client.create_release_batch(&Vec::new()).wait(); + let result = client.create_release_batch(&Vec::new(), Some(true)).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } @@ -141,7 +141,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateWorkBatch") => { - let result = client.create_work_batch(&Vec::new()).wait(); + let result = client.create_work_batch(&Vec::new(), Some(true)).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } diff --git a/rust/fatcat-api/examples/server_lib/server.rs b/rust/fatcat-api/examples/server_lib/server.rs index 572025f0..32c7e97f 100644 --- a/rust/fatcat-api/examples/server_lib/server.rs +++ b/rust/fatcat-api/examples/server_lib/server.rs @@ -34,11 +34,17 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_container_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send> { + fn create_container_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + context: &Context, + ) -> Box + Send> { let context = context.clone(); println!( - "create_container_batch({:?}) - X-Span-ID: {:?}", + "create_container_batch({:?}, {:?}) - X-Span-ID: {:?}", entity_list, + autoaccept, context.x_span_id.unwrap_or(String::from("")).clone() ); Box::new(futures::failed("Generic failure".into())) @@ -50,9 +56,14 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_creator_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send> { + fn create_creator_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send> { let context = context.clone(); - println!("create_creator_batch({:?}) - X-Span-ID: {:?}", entity_list, context.x_span_id.unwrap_or(String::from("")).clone()); + println!( + "create_creator_batch({:?}, {:?}) - X-Span-ID: {:?}", + entity_list, + autoaccept, + context.x_span_id.unwrap_or(String::from("")).clone() + ); Box::new(futures::failed("Generic failure".into())) } @@ -68,9 +79,14 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_file_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send> { + fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send> { let context = context.clone(); - println!("create_file_batch({:?}) - X-Span-ID: {:?}", entity_list, context.x_span_id.unwrap_or(String::from("")).clone()); + println!( + "create_file_batch({:?}, {:?}) - X-Span-ID: {:?}", + entity_list, + autoaccept, + context.x_span_id.unwrap_or(String::from("")).clone() + ); Box::new(futures::failed("Generic failure".into())) } @@ -80,9 +96,14 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_release_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send> { + fn create_release_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send> { let context = context.clone(); - println!("create_release_batch({:?}) - X-Span-ID: {:?}", entity_list, context.x_span_id.unwrap_or(String::from("")).clone()); + println!( + "create_release_batch({:?}, {:?}) - X-Span-ID: {:?}", + entity_list, + autoaccept, + context.x_span_id.unwrap_or(String::from("")).clone() + ); Box::new(futures::failed("Generic failure".into())) } @@ -92,9 +113,14 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_work_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send> { + fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send> { let context = context.clone(); - println!("create_work_batch({:?}) - X-Span-ID: {:?}", entity_list, context.x_span_id.unwrap_or(String::from("")).clone()); + println!( + "create_work_batch({:?}, {:?}) - X-Span-ID: {:?}", + entity_list, + autoaccept, + context.x_span_id.unwrap_or(String::from("")).clone() + ); Box::new(futures::failed("Generic failure".into())) } diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index bc1992de..d71c9dab 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -290,8 +290,20 @@ impl Api for Client { Box::new(futures::done(result)) } - fn create_container_batch(&self, param_entity_list: &Vec, context: &Context) -> Box + Send> { - let url = format!("{}/v0/container/batch", self.base_path); + fn create_container_batch( + &self, + param_entity_list: &Vec, + param_autoaccept: Option, + context: &Context, + ) -> Box + Send> { + // Query parameters + let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + + let url = format!( + "{}/v0/container/batch?{autoaccept}", + self.base_path, + autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET) + ); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -420,8 +432,20 @@ impl Api for Client { Box::new(futures::done(result)) } - fn create_creator_batch(&self, param_entity_list: &Vec, context: &Context) -> Box + Send> { - let url = format!("{}/v0/creator/batch", self.base_path); + fn create_creator_batch( + &self, + param_entity_list: &Vec, + param_autoaccept: Option, + context: &Context, + ) -> Box + Send> { + // Query parameters + let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + + let url = format!( + "{}/v0/creator/batch?{autoaccept}", + self.base_path, + autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET) + ); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -608,8 +632,16 @@ impl Api for Client { Box::new(futures::done(result)) } - fn create_file_batch(&self, param_entity_list: &Vec, context: &Context) -> Box + Send> { - let url = format!("{}/v0/file/batch", self.base_path); + fn create_file_batch( + &self, + param_entity_list: &Vec, + param_autoaccept: Option, + context: &Context, + ) -> Box + Send> { + // Query parameters + let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + + let url = format!("{}/v0/file/batch?{autoaccept}", self.base_path, autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET)); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -738,8 +770,20 @@ impl Api for Client { Box::new(futures::done(result)) } - fn create_release_batch(&self, param_entity_list: &Vec, context: &Context) -> Box + Send> { - let url = format!("{}/v0/release/batch", self.base_path); + fn create_release_batch( + &self, + param_entity_list: &Vec, + param_autoaccept: Option, + context: &Context, + ) -> Box + Send> { + // Query parameters + let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + + let url = format!( + "{}/v0/release/batch?{autoaccept}", + self.base_path, + autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET) + ); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -868,8 +912,16 @@ impl Api for Client { Box::new(futures::done(result)) } - fn create_work_batch(&self, param_entity_list: &Vec, context: &Context) -> Box + Send> { - let url = format!("{}/v0/work/batch", self.base_path); + fn create_work_batch( + &self, + param_entity_list: &Vec, + param_autoaccept: Option, + context: &Context, + ) -> Box + Send> { + // Query parameters + let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + + let url = format!("{}/v0/work/batch?{autoaccept}", self.base_path, autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET)); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index fac8ecac..044b934b 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -442,25 +442,30 @@ pub trait Api { fn create_container(&self, entity: models::ContainerEntity, context: &Context) -> Box + Send>; - fn create_container_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send>; + fn create_container_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + context: &Context, + ) -> Box + Send>; fn create_creator(&self, entity: models::CreatorEntity, context: &Context) -> Box + Send>; - fn create_creator_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send>; + fn create_creator_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send>; fn create_editgroup(&self, entity: models::Editgroup, context: &Context) -> Box + Send>; fn create_file(&self, entity: models::FileEntity, context: &Context) -> Box + Send>; - fn create_file_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send>; + fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send>; fn create_release(&self, entity: models::ReleaseEntity, context: &Context) -> Box + Send>; - fn create_release_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send>; + fn create_release_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send>; fn create_work(&self, entity: models::WorkEntity, context: &Context) -> Box + Send>; - fn create_work_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send>; + fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send>; fn get_changelog(&self, limit: Option, context: &Context) -> Box + Send>; @@ -515,25 +520,25 @@ pub trait ApiNoContext { fn create_container(&self, entity: models::ContainerEntity) -> Box + Send>; - fn create_container_batch(&self, entity_list: &Vec) -> Box + Send>; + fn create_container_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; fn create_creator(&self, entity: models::CreatorEntity) -> Box + Send>; - fn create_creator_batch(&self, entity_list: &Vec) -> Box + Send>; + fn create_creator_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; fn create_editgroup(&self, entity: models::Editgroup) -> Box + Send>; fn create_file(&self, entity: models::FileEntity) -> Box + Send>; - fn create_file_batch(&self, entity_list: &Vec) -> Box + Send>; + fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; fn create_release(&self, entity: models::ReleaseEntity) -> Box + Send>; - fn create_release_batch(&self, entity_list: &Vec) -> Box + Send>; + fn create_release_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; fn create_work(&self, entity: models::WorkEntity) -> Box + Send>; - fn create_work_batch(&self, entity_list: &Vec) -> Box + Send>; + fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; fn get_changelog(&self, limit: Option) -> Box + Send>; @@ -606,16 +611,16 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().create_container(entity, &self.context()) } - fn create_container_batch(&self, entity_list: &Vec) -> Box + Send> { - self.api().create_container_batch(entity_list, &self.context()) + fn create_container_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { + self.api().create_container_batch(entity_list, autoaccept, &self.context()) } fn create_creator(&self, entity: models::CreatorEntity) -> Box + Send> { self.api().create_creator(entity, &self.context()) } - fn create_creator_batch(&self, entity_list: &Vec) -> Box + Send> { - self.api().create_creator_batch(entity_list, &self.context()) + fn create_creator_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { + self.api().create_creator_batch(entity_list, autoaccept, &self.context()) } fn create_editgroup(&self, entity: models::Editgroup) -> Box + Send> { @@ -626,24 +631,24 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().create_file(entity, &self.context()) } - fn create_file_batch(&self, entity_list: &Vec) -> Box + Send> { - self.api().create_file_batch(entity_list, &self.context()) + fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { + self.api().create_file_batch(entity_list, autoaccept, &self.context()) } fn create_release(&self, entity: models::ReleaseEntity) -> Box + Send> { self.api().create_release(entity, &self.context()) } - fn create_release_batch(&self, entity_list: &Vec) -> Box + Send> { - self.api().create_release_batch(entity_list, &self.context()) + fn create_release_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { + self.api().create_release_batch(entity_list, autoaccept, &self.context()) } fn create_work(&self, entity: models::WorkEntity) -> Box + Send> { self.api().create_work(entity, &self.context()) } - fn create_work_batch(&self, entity_list: &Vec) -> Box + Send> { - self.api().create_work_batch(entity_list, &self.context()) + fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { + self.api().create_work_batch(entity_list, autoaccept, &self.context()) } fn get_changelog(&self, limit: Option) -> Box + Send> { diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index 68e08515..4e41b5e9 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -298,6 +298,10 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // 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::().unwrap_or_default(); + let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + // 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. @@ -322,7 +326,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_container_batch(param_entity_list.as_ref(), context).wait() { + match api.create_container_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { Ok(rsp) => match rsp { CreateContainerBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -510,6 +514,10 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // 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::().unwrap_or_default(); + let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + // 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. @@ -534,7 +542,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_creator_batch(param_entity_list.as_ref(), context).wait() { + match api.create_creator_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { Ok(rsp) => match rsp { CreateCreatorBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -815,6 +823,10 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // 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::().unwrap_or_default(); + let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + // 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. @@ -839,7 +851,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_file_batch(param_entity_list.as_ref(), context).wait() { + match api.create_file_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { Ok(rsp) => match rsp { CreateFileBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1027,6 +1039,10 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // 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::().unwrap_or_default(); + let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + // 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. @@ -1051,7 +1067,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_release_batch(param_entity_list.as_ref(), context).wait() { + match api.create_release_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { Ok(rsp) => match rsp { CreateReleaseBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1239,6 +1255,10 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // 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::().unwrap_or_default(); + let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + // 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. @@ -1263,7 +1283,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_work_batch(param_entity_list.as_ref(), context).wait() { + match api.create_work_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { Ok(rsp) => match rsp { CreateWorkBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); -- cgit v1.2.3 From 2f7cff3c597af42c8dd02313bdceb98a11c2e414 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 20 Aug 2018 02:16:08 -0700 Subject: implement autoaccept Need to review: - changelog creation - clobbering of existing editgroup flag --- rust/src/api_server.rs | 61 ++++++++++++++++++++++++++++++++++-------------- rust/src/api_wrappers.rs | 5 ++-- 2 files changed, 46 insertions(+), 20 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index b0dff173..0cb07e81 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -25,11 +25,23 @@ macro_rules! entity_batch_handler { pub fn $post_batch_handler( &self, entity_list: &[models::$model], + autoaccept: bool, conn: &DbConn, ) -> Result> { let mut ret: Vec = vec![]; + let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth + let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) + .values((editgroup::editor_id.eq(editor_id),)) + .get_result(conn)?; for entity in entity_list { - ret.push(self.$post_handler(entity.clone(), conn)?); + let mut e = entity.clone(); + e.editgroup_id = Some(uuid2fcid(&eg_row.id)); + ret.push(self.$post_handler(e, autoaccept, conn)?); + } + if autoaccept { + let _clr: ChangelogRow = diesel::insert_into(changelog::table) + .values((changelog::editgroup_id.eq(eg_row.id),)) + .get_result(conn)?; } Ok(ret) } @@ -216,7 +228,10 @@ fn release_row2entity( let contribs: Vec = release_contrib::table .filter(release_contrib::release_rev.eq(rev.id)) - .order((release_contrib::role.asc(), release_contrib::index_val.asc())) + .order(( + release_contrib::role.asc(), + release_contrib::index_val.asc(), + )) .get_results(conn) .expect("fetch release refs") .into_iter() @@ -495,6 +510,7 @@ impl Server { pub fn create_container_handler( &self, entity: models::ContainerEntity, + autoaccept: bool, conn: &DbConn, ) -> Result { let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth @@ -513,11 +529,11 @@ impl Server { "WITH rev AS ( INSERT INTO container_rev (name, publisher, issnl, wikidata_qid, abbrev, coden, extra_json) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id ), - ident AS ( INSERT INTO container_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) + ident AS ( INSERT INTO container_ident (is_live, rev_id) + VALUES ($8, (SELECT rev.id FROM rev)) RETURNING id ) INSERT INTO container_edit (editgroup_id, ident_id, rev_id) VALUES - ($8, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) + ($9, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) RETURNING *", ).bind::(entity.name) .bind::, _>(entity.publisher) @@ -526,6 +542,7 @@ impl Server { .bind::, _>(entity.abbrev) .bind::, _>(entity.coden) .bind::, _>(entity.extra) + .bind::(autoaccept) .bind::(editgroup_id) .get_result(conn)?; @@ -535,6 +552,7 @@ impl Server { pub fn create_creator_handler( &self, entity: models::CreatorEntity, + autoaccept: bool, conn: &DbConn, ) -> Result { let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth @@ -553,11 +571,11 @@ impl Server { "WITH rev AS ( INSERT INTO creator_rev (display_name, given_name, surname, orcid, wikidata_qid, extra_json) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id ), - ident AS ( INSERT INTO creator_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) + ident AS ( INSERT INTO creator_ident (is_live, rev_id) + VALUES ($7, (SELECT rev.id FROM rev)) RETURNING id ) INSERT INTO creator_edit (editgroup_id, ident_id, rev_id) VALUES - ($7, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) + ($8, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) RETURNING *", ).bind::(entity.display_name) .bind::, _>(entity.given_name) @@ -565,6 +583,7 @@ impl Server { .bind::, _>(entity.orcid) .bind::, _>(entity.wikidata_qid) .bind::, _>(entity.extra) + .bind::(autoaccept) .bind::(editgroup_id) .get_result(conn)?; @@ -574,6 +593,7 @@ impl Server { pub fn create_file_handler( &self, entity: models::FileEntity, + autoaccept: bool, conn: &DbConn, ) -> Result { let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth @@ -587,11 +607,11 @@ impl Server { "WITH rev AS ( INSERT INTO file_rev (size, sha1, sha256, md5, mimetype, extra_json) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id ), - ident AS ( INSERT INTO file_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) + ident AS ( INSERT INTO file_ident (is_live, rev_id) + VALUES ($7, (SELECT rev.id FROM rev)) RETURNING id ) INSERT INTO file_edit (editgroup_id, ident_id, rev_id) VALUES - ($7, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) + ($8, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) RETURNING *", ).bind::, _>(entity.size) .bind::, _>(entity.sha1) @@ -599,6 +619,7 @@ impl Server { .bind::, _>(entity.md5) .bind::, _>(entity.mimetype) .bind::, _>(entity.extra) + .bind::(autoaccept) .bind::(editgroup_id) .get_result(conn)?; @@ -654,6 +675,7 @@ impl Server { pub fn create_release_handler( &self, entity: models::ReleaseEntity, + autoaccept: bool, conn: &DbConn, ) -> Result { let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth @@ -686,7 +708,7 @@ impl Server { editgroup_id: Some(uuid2fcid(&editgroup_id)), extra: None, }; - let new_entity = self.create_work_handler(work_model, conn)?; + let new_entity = self.create_work_handler(work_model, autoaccept, conn)?; fcid2uuid(&new_entity.ident)? } }; @@ -700,11 +722,11 @@ impl Server { "WITH rev AS ( INSERT INTO release_rev (title, release_type, release_status, release_date, doi, pmid, pmcid, wikidata_qid, isbn13, core_id, volume, issue, pages, work_ident_id, container_ident_id, publisher, language, extra_json) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) RETURNING id ), - ident AS ( INSERT INTO release_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) + ident AS ( INSERT INTO release_ident (is_live, rev_id) + VALUES ($19, (SELECT rev.id FROM rev)) RETURNING id ) INSERT INTO release_edit (editgroup_id, ident_id, rev_id) VALUES - ($19, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) + ($20, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) RETURNING *", ).bind::(entity.title) .bind::, _>(entity.release_type) @@ -725,6 +747,7 @@ impl Server { .bind::, _>(entity.publisher) .bind::, _>(entity.language) .bind::, _>(entity.extra) + .bind::(autoaccept) .bind::(editgroup_id) .get_result(conn)?; @@ -829,6 +852,7 @@ impl Server { pub fn create_work_handler( &self, entity: models::WorkEntity, + autoaccept: bool, conn: &DbConn, ) -> Result { let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth @@ -842,13 +866,14 @@ impl Server { "WITH rev AS ( INSERT INTO work_rev (extra_json) VALUES ($1) RETURNING id ), - ident AS ( INSERT INTO work_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) + ident AS ( INSERT INTO work_ident (is_live, rev_id) + VALUES ($2, (SELECT rev.id FROM rev)) RETURNING id ) INSERT INTO work_edit (editgroup_id, ident_id, rev_id) VALUES - ($2, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) + ($3, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) RETURNING *", ).bind::, _>(entity.extra) + .bind::(autoaccept) .bind::(editgroup_id) .get_result(conn)?; diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 95336d3f..4f126385 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -60,7 +60,7 @@ macro_rules! wrap_entity_handlers { _context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); - let ret = match conn.transaction(|| self.$post_handler(entity, &conn)) { + let ret = match conn.transaction(|| self.$post_handler(entity, false, &conn)) { Ok(edit) => $post_resp::CreatedEntity(edit), Err(Error(ErrorKind::Diesel(e), _)) => @@ -83,10 +83,11 @@ macro_rules! wrap_entity_handlers { fn $post_batch_fn( &self, entity_list: &Vec, + autoaccept: Option, _context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); - let ret = match conn.transaction(|| self.$post_batch_handler(entity_list, &conn)) { + let ret = match conn.transaction(|| self.$post_batch_handler(entity_list, autoaccept.unwrap_or(false), &conn)) { Ok(edit) => $post_batch_resp::CreatedEntities(edit), Err(Error(ErrorKind::Diesel(e), _)) => -- cgit v1.2.3 From 8528f06157b0e60842c860f81e3f2a69aa07aae9 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 24 Aug 2018 12:59:28 -0700 Subject: WIP: autoaccept --- TODO | 34 +++++----- fatcat-openapi2.yml | 25 +++++++ notes/cloud_instances.txt | 2 + rust/fatcat-api/README.md | 2 +- rust/fatcat-api/api.yaml | 25 +++++++ rust/fatcat-api/api/swagger.yaml | 40 ++++++++++++ rust/fatcat-api/examples/client.rs | 10 +-- rust/fatcat-api/examples/server_lib/server.rs | 48 +++++++++++--- rust/fatcat-api/src/client.rs | 39 ++++++++--- rust/fatcat-api/src/lib.rs | 93 +++++++++++++++++++++------ rust/fatcat-api/src/server.rs | 15 +++-- 11 files changed, 269 insertions(+), 64 deletions(-) (limited to 'rust') diff --git a/TODO b/TODO index d5e10629..b7aa470a 100644 --- a/TODO +++ b/TODO @@ -1,38 +1,43 @@ ## Next Up -- some significant slow-down has happened? transactions, or regexes? +summer roadmap: +- PUT/UPDATE, DELETE, and merge code paths +- faster UPDATE-free bulk import code path +- container import (extra?): lang, region, subject +- basic API+webface creation, editing, merging, editgroup approval +- elastic schema/transform for releases; bulk and continuous scripts features: - fast database dump command: both changelog-based and entity-based (rust) => lighter, more complete dumps for each entity type? +- guide skeleton (mdbook; guide.fatcat.wiki) importers: +- CORE +- wikidata cross-ref (if they have a dump) - manifest: multiple URLs per SHA1 -- pubmed (medline) +- pubmed (medline), if not in CORE => and/or, use pubmed ID lookups on crossref import -- core - semantic scholar (up to 39 million; author de-dupe) -- wikidata (if they have a dump) bugs: - test: release pointing to a collection that has been deleted/redirected => UI crash? -july roadmap: -- complete and test this round of schema changes -- container import (extra?): lang, region, subject -- re-run imports -- basic API+webface creation, editing, merging, editgroup approval -- elastic schema/transform for releases; bulk and continuous scripts - ## Schema / Alignment / Scope - "container" -> "venue"? -- release_type, release_status, url.rel enums (and others?) +- release_type, release_status, url.rel write-time schema(and others?) name ref: https://www.w3.org/International/questions/qa-personal-names +## API + +- how to send edit "extra" metadata? +- hydrate entities in API + ? "expand" query param + ## High-Level Priorities - full database dump (export) @@ -50,11 +55,6 @@ name ref: https://www.w3.org/International/questions/qa-personal-names - batch inserts automerge: create editgroup and changelog, mark all edits as accepted, all in a single transaction -## API - -- hydrate entities in API - ? "expand" query param - ## Other - basic python hbase/elastic matcher diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index fda630dd..ea17e982 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -447,6 +447,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true @@ -540,6 +545,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true @@ -649,6 +659,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true @@ -742,6 +757,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true @@ -851,6 +871,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true diff --git a/notes/cloud_instances.txt b/notes/cloud_instances.txt index 4582c431..b7071758 100644 --- a/notes/cloud_instances.txt +++ b/notes/cloud_instances.txt @@ -6,3 +6,5 @@ digital ocean aws i3.2xlarge 61 GB RAM, 8 cores, 1900 GB NVMe, $455/month +OVH + MG-128 128 GB RAM, 16 cores, 2880 GB SSD (RAID), 500mbps unlimited b/w, $315/month diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index d0b266aa..7e4a2ec8 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-08-20T08:47:01.260Z +- Build date: 2018-08-22T00:54:09.323Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index fda630dd..ea17e982 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -447,6 +447,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true @@ -540,6 +545,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true @@ -649,6 +659,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true @@ -742,6 +757,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true @@ -851,6 +871,11 @@ paths: type: boolean required: false description: "If true, and editor is authorized, batch is accepted all at once" + - name: editgroup + in: query + type: string + required: false + description: "Editgroup to auto-accept and apply to all entities (required if 'autoaccept' is True)" - name: entity_list in: body required: true diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index 11f789dc..3b8ed6e3 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -84,6 +84,14 @@ paths: type: "boolean" formatString: "{:?}" example: "Some(true)" + - name: "editgroup" + in: "query" + description: "Editgroup to auto-accept and apply to all entities (required\ + \ if 'autoaccept' is True)" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" - in: "body" name: "entity_list" required: true @@ -387,6 +395,14 @@ paths: type: "boolean" formatString: "{:?}" example: "Some(true)" + - name: "editgroup" + in: "query" + description: "Editgroup to auto-accept and apply to all entities (required\ + \ if 'autoaccept' is True)" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" - in: "body" name: "entity_list" required: true @@ -744,6 +760,14 @@ paths: type: "boolean" formatString: "{:?}" example: "Some(true)" + - name: "editgroup" + in: "query" + description: "Editgroup to auto-accept and apply to all entities (required\ + \ if 'autoaccept' is True)" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" - in: "body" name: "entity_list" required: true @@ -1044,6 +1068,14 @@ paths: type: "boolean" formatString: "{:?}" example: "Some(true)" + - name: "editgroup" + in: "query" + description: "Editgroup to auto-accept and apply to all entities (required\ + \ if 'autoaccept' is True)" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" - in: "body" name: "entity_list" required: true @@ -1398,6 +1430,14 @@ paths: type: "boolean" formatString: "{:?}" example: "Some(true)" + - name: "editgroup" + in: "query" + description: "Editgroup to auto-accept and apply to all entities (required\ + \ if 'autoaccept' is True)" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" - in: "body" name: "entity_list" required: true diff --git a/rust/fatcat-api/examples/client.rs b/rust/fatcat-api/examples/client.rs index 06519232..34653196 100644 --- a/rust/fatcat-api/examples/client.rs +++ b/rust/fatcat-api/examples/client.rs @@ -95,7 +95,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateContainerBatch") => { - let result = client.create_container_batch(&Vec::new(), Some(true)).wait(); + let result = client.create_container_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } @@ -105,7 +105,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateCreatorBatch") => { - let result = client.create_creator_batch(&Vec::new(), Some(true)).wait(); + let result = client.create_creator_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } @@ -121,7 +121,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateFileBatch") => { - let result = client.create_file_batch(&Vec::new(), Some(true)).wait(); + let result = client.create_file_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } @@ -131,7 +131,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateReleaseBatch") => { - let result = client.create_release_batch(&Vec::new(), Some(true)).wait(); + let result = client.create_release_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } @@ -141,7 +141,7 @@ fn main() { // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); // }, Some("CreateWorkBatch") => { - let result = client.create_work_batch(&Vec::new(), Some(true)).wait(); + let result = client.create_work_batch(&Vec::new(), Some(true), Some("editgroup_example".to_string())).wait(); println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } diff --git a/rust/fatcat-api/examples/server_lib/server.rs b/rust/fatcat-api/examples/server_lib/server.rs index 32c7e97f..60e19847 100644 --- a/rust/fatcat-api/examples/server_lib/server.rs +++ b/rust/fatcat-api/examples/server_lib/server.rs @@ -38,13 +38,15 @@ impl Api for Server { &self, entity_list: &Vec, autoaccept: Option, + editgroup: Option, context: &Context, ) -> Box + Send> { let context = context.clone(); println!( - "create_container_batch({:?}, {:?}) - X-Span-ID: {:?}", + "create_container_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", entity_list, autoaccept, + editgroup, context.x_span_id.unwrap_or(String::from("")).clone() ); Box::new(futures::failed("Generic failure".into())) @@ -56,12 +58,19 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_creator_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send> { + fn create_creator_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + context: &Context, + ) -> Box + Send> { let context = context.clone(); println!( - "create_creator_batch({:?}, {:?}) - X-Span-ID: {:?}", + "create_creator_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", entity_list, autoaccept, + editgroup, context.x_span_id.unwrap_or(String::from("")).clone() ); Box::new(futures::failed("Generic failure".into())) @@ -79,12 +88,19 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send> { + fn create_file_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + context: &Context, + ) -> Box + Send> { let context = context.clone(); println!( - "create_file_batch({:?}, {:?}) - X-Span-ID: {:?}", + "create_file_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", entity_list, autoaccept, + editgroup, context.x_span_id.unwrap_or(String::from("")).clone() ); Box::new(futures::failed("Generic failure".into())) @@ -96,12 +112,19 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_release_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send> { + fn create_release_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + context: &Context, + ) -> Box + Send> { let context = context.clone(); println!( - "create_release_batch({:?}, {:?}) - X-Span-ID: {:?}", + "create_release_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", entity_list, autoaccept, + editgroup, context.x_span_id.unwrap_or(String::from("")).clone() ); Box::new(futures::failed("Generic failure".into())) @@ -113,12 +136,19 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } - fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send> { + fn create_work_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + context: &Context, + ) -> Box + Send> { let context = context.clone(); println!( - "create_work_batch({:?}, {:?}) - X-Span-ID: {:?}", + "create_work_batch({:?}, {:?}, {:?}) - X-Span-ID: {:?}", entity_list, autoaccept, + editgroup, context.x_span_id.unwrap_or(String::from("")).clone() ); Box::new(futures::failed("Generic failure".into())) diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index d71c9dab..628d8894 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -294,15 +294,18 @@ impl Api for Client { &self, param_entity_list: &Vec, param_autoaccept: Option, + param_editgroup: Option, context: &Context, ) -> Box + Send> { // Query parameters let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); let url = format!( - "{}/v0/container/batch?{autoaccept}", + "{}/v0/container/batch?{autoaccept}{editgroup}", self.base_path, - autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET) + autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), + editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) ); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -436,15 +439,18 @@ impl Api for Client { &self, param_entity_list: &Vec, param_autoaccept: Option, + param_editgroup: Option, context: &Context, ) -> Box + Send> { // Query parameters let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); let url = format!( - "{}/v0/creator/batch?{autoaccept}", + "{}/v0/creator/batch?{autoaccept}{editgroup}", self.base_path, - autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET) + autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), + editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) ); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -636,12 +642,19 @@ impl Api for Client { &self, param_entity_list: &Vec, param_autoaccept: Option, + param_editgroup: Option, context: &Context, ) -> Box + Send> { // Query parameters let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); - let url = format!("{}/v0/file/batch?{autoaccept}", self.base_path, autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET)); + let url = format!( + "{}/v0/file/batch?{autoaccept}{editgroup}", + self.base_path, + autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), + editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) + ); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -774,15 +787,18 @@ impl Api for Client { &self, param_entity_list: &Vec, param_autoaccept: Option, + param_editgroup: Option, context: &Context, ) -> Box + Send> { // Query parameters let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); let url = format!( - "{}/v0/release/batch?{autoaccept}", + "{}/v0/release/batch?{autoaccept}{editgroup}", self.base_path, - autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET) + autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), + editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) ); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); @@ -916,12 +932,19 @@ impl Api for Client { &self, param_entity_list: &Vec, param_autoaccept: Option, + param_editgroup: Option, context: &Context, ) -> Box + Send> { // Query parameters let query_autoaccept = param_autoaccept.map_or_else(String::new, |query| format!("autoaccept={autoaccept}&", autoaccept = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); - let url = format!("{}/v0/work/batch?{autoaccept}", self.base_path, autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET)); + let url = format!( + "{}/v0/work/batch?{autoaccept}{editgroup}", + self.base_path, + autoaccept = utf8_percent_encode(&query_autoaccept, QUERY_ENCODE_SET), + editgroup = utf8_percent_encode(&query_editgroup, QUERY_ENCODE_SET) + ); let body = serde_json::to_string(¶m_entity_list).expect("impossible to fail to serialize"); diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index 044b934b..5de3647b 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -446,26 +446,51 @@ pub trait Api { &self, entity_list: &Vec, autoaccept: Option, + editgroup: Option, context: &Context, ) -> Box + Send>; fn create_creator(&self, entity: models::CreatorEntity, context: &Context) -> Box + Send>; - fn create_creator_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send>; + fn create_creator_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + context: &Context, + ) -> Box + Send>; fn create_editgroup(&self, entity: models::Editgroup, context: &Context) -> Box + Send>; fn create_file(&self, entity: models::FileEntity, context: &Context) -> Box + Send>; - fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send>; + fn create_file_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + context: &Context, + ) -> Box + Send>; fn create_release(&self, entity: models::ReleaseEntity, context: &Context) -> Box + Send>; - fn create_release_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send>; + fn create_release_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + context: &Context, + ) -> Box + Send>; fn create_work(&self, entity: models::WorkEntity, context: &Context) -> Box + Send>; - fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option, context: &Context) -> Box + Send>; + fn create_work_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + context: &Context, + ) -> Box + Send>; fn get_changelog(&self, limit: Option, context: &Context) -> Box + Send>; @@ -520,25 +545,40 @@ pub trait ApiNoContext { fn create_container(&self, entity: models::ContainerEntity) -> Box + Send>; - fn create_container_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; + fn create_container_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + ) -> Box + Send>; fn create_creator(&self, entity: models::CreatorEntity) -> Box + Send>; - fn create_creator_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; + fn create_creator_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + ) -> Box + Send>; fn create_editgroup(&self, entity: models::Editgroup) -> Box + Send>; fn create_file(&self, entity: models::FileEntity) -> Box + Send>; - fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; + fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option, editgroup: Option) -> Box + Send>; fn create_release(&self, entity: models::ReleaseEntity) -> Box + Send>; - fn create_release_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; + fn create_release_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + ) -> Box + Send>; fn create_work(&self, entity: models::WorkEntity) -> Box + Send>; - fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send>; + fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option, editgroup: Option) -> Box + Send>; fn get_changelog(&self, limit: Option) -> Box + Send>; @@ -611,16 +651,26 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().create_container(entity, &self.context()) } - fn create_container_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { - self.api().create_container_batch(entity_list, autoaccept, &self.context()) + fn create_container_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + ) -> Box + Send> { + self.api().create_container_batch(entity_list, autoaccept, editgroup, &self.context()) } fn create_creator(&self, entity: models::CreatorEntity) -> Box + Send> { self.api().create_creator(entity, &self.context()) } - fn create_creator_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { - self.api().create_creator_batch(entity_list, autoaccept, &self.context()) + fn create_creator_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + ) -> Box + Send> { + self.api().create_creator_batch(entity_list, autoaccept, editgroup, &self.context()) } fn create_editgroup(&self, entity: models::Editgroup) -> Box + Send> { @@ -631,24 +681,29 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().create_file(entity, &self.context()) } - fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { - self.api().create_file_batch(entity_list, autoaccept, &self.context()) + fn create_file_batch(&self, entity_list: &Vec, autoaccept: Option, editgroup: Option) -> Box + Send> { + self.api().create_file_batch(entity_list, autoaccept, editgroup, &self.context()) } fn create_release(&self, entity: models::ReleaseEntity) -> Box + Send> { self.api().create_release(entity, &self.context()) } - fn create_release_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { - self.api().create_release_batch(entity_list, autoaccept, &self.context()) + fn create_release_batch( + &self, + entity_list: &Vec, + autoaccept: Option, + editgroup: Option, + ) -> Box + Send> { + self.api().create_release_batch(entity_list, autoaccept, editgroup, &self.context()) } fn create_work(&self, entity: models::WorkEntity) -> Box + Send> { self.api().create_work(entity, &self.context()) } - fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option) -> Box + Send> { - self.api().create_work_batch(entity_list, autoaccept, &self.context()) + fn create_work_batch(&self, entity_list: &Vec, autoaccept: Option, editgroup: Option) -> Box + Send> { + self.api().create_work_batch(entity_list, autoaccept, editgroup, &self.context()) } fn get_changelog(&self, limit: Option) -> Box + Send> { diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index 4e41b5e9..1ba9a218 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -301,6 +301,7 @@ where // 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::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for @@ -326,7 +327,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_container_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { + match api.create_container_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() { Ok(rsp) => match rsp { CreateContainerBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -517,6 +518,7 @@ where // 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::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for @@ -542,7 +544,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_creator_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { + match api.create_creator_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() { Ok(rsp) => match rsp { CreateCreatorBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -826,6 +828,7 @@ where // 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::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for @@ -851,7 +854,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_file_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { + match api.create_file_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() { Ok(rsp) => match rsp { CreateFileBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1042,6 +1045,7 @@ where // 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::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for @@ -1067,7 +1071,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_release_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { + match api.create_release_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() { Ok(rsp) => match rsp { CreateReleaseBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); @@ -1258,6 +1262,7 @@ where // 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::().unwrap_or_default(); let param_autoaccept = query_params.get("autoaccept").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); // Body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for @@ -1283,7 +1288,7 @@ where }; let param_entity_list = param_entity_list.ok_or_else(|| Response::with((status::BadRequest, "Missing required body parameter entity_list".to_string())))?; - match api.create_work_batch(param_entity_list.as_ref(), param_autoaccept, context).wait() { + match api.create_work_batch(param_entity_list.as_ref(), param_autoaccept, param_editgroup, context).wait() { Ok(rsp) => match rsp { CreateWorkBatchResponse::CreatedEntities(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); -- cgit v1.2.3 From 6a87d4b3ab252d76bb380a69ed53f21989761e9f Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 24 Aug 2018 13:23:30 -0700 Subject: NOTES => rust_libraries.txt --- notes/rust_libraries.txt | 19 +++++++++++++++++++ rust/NOTES.txt | 19 ------------------- 2 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 notes/rust_libraries.txt delete mode 100644 rust/NOTES.txt (limited to 'rust') diff --git a/notes/rust_libraries.txt b/notes/rust_libraries.txt new file mode 100644 index 00000000..7e6f33eb --- /dev/null +++ b/notes/rust_libraries.txt @@ -0,0 +1,19 @@ + +libs: +- iron_slog +- testing: keep it simple: iron-test + => if that is annoying, shiny? mockers if needed. +- sentry +- start with dotenv+clap, then config-rs? +- cadence (emits statsd) +- frank_jwt and JWT for (simple?) auth + +similar: +- https://github.com/DavidBM/templic-backend +- https://github.com/alexanderbanks/rust-api +- https://mgattozzi.com/diesel-powered-rocket +- https://www.reddit.com/r/rust/comments/8j1xbs/new_to_rust_and_gitlab_ci/ +- https://crate-ci.github.io/ + +"cool tools": +- cargo-watch diff --git a/rust/NOTES.txt b/rust/NOTES.txt deleted file mode 100644 index 7e6f33eb..00000000 --- a/rust/NOTES.txt +++ /dev/null @@ -1,19 +0,0 @@ - -libs: -- iron_slog -- testing: keep it simple: iron-test - => if that is annoying, shiny? mockers if needed. -- sentry -- start with dotenv+clap, then config-rs? -- cadence (emits statsd) -- frank_jwt and JWT for (simple?) auth - -similar: -- https://github.com/DavidBM/templic-backend -- https://github.com/alexanderbanks/rust-api -- https://mgattozzi.com/diesel-powered-rocket -- https://www.reddit.com/r/rust/comments/8j1xbs/new_to_rust_and_gitlab_ci/ -- https://crate-ci.github.io/ - -"cool tools": -- cargo-watch -- cgit v1.2.3 From f997c5bcbcc800a8780a62dc56a4b7f4e5b68c3c Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 24 Aug 2018 13:29:29 -0700 Subject: split/move docs around --- notes/database_dumps_backups.txt | 31 +++++++++++++++ rust/HACKING.md | 24 ++++++++++++ rust/INSTALL.md | 36 +++++++++++++++++ rust/README.md | 85 +--------------------------------------- 4 files changed, 92 insertions(+), 84 deletions(-) create mode 100644 notes/database_dumps_backups.txt create mode 100644 rust/HACKING.md create mode 100644 rust/INSTALL.md (limited to 'rust') diff --git a/notes/database_dumps_backups.txt b/notes/database_dumps_backups.txt new file mode 100644 index 00000000..0b05b9b8 --- /dev/null +++ b/notes/database_dumps_backups.txt @@ -0,0 +1,31 @@ + +## Dumps and Backups + +There are a few different database dump formats folks might want: + +- raw native database backups, for disaster recovery (would include + volatile/unsupported schema details, user API credentials, full history, + in-process edits, comments, etc) +- a sanitized version of the above: roughly per-table dumps of the full state + of the database. Could use per-table SQL expressions with sub-queries to pull + in small tables ("partial transform") and export JSON for each table; would + be extra work to maintain, so not pursuing for now. +- full history, full public schema exports, in a form that might be used to + mirror or enitrely fork the project. Propose supplying the full "changelog" + in API schema format, in a single file to capture all entity history, without + "hydrating" any inter-entity references. Rely on separate dumps of + non-entity, non-versioned tables (editors, abstracts, etc). Note that a + variant of this could use the public interface, in particular to do + incremental updates (though that wouldn't capture schema changes). +- transformed exports of the current state of the database (aka, without + history). Useful for data analysis, search engines, etc. Propose supplying + just the Release table in a fully "hydrated" state to start. Unclear if + should be on a work or release basis; will go with release for now. Harder to + do using public interface because of the need for transaction locking. + +Backing up the entire database using `pg_dump`, with parallelism 1 (use more on +larger machine with fast disks; try 4 or 8?), assuming the database name is +'fatcat', and the current user has access: + + pg_dump -j1 -Fd -f test-dump fatcat + diff --git a/rust/HACKING.md b/rust/HACKING.md new file mode 100644 index 00000000..a399164c --- /dev/null +++ b/rust/HACKING.md @@ -0,0 +1,24 @@ + +## Updating Schemas + +Regenerate API schemas after editing the fatcat-openapi2 schema. This will, as +a side-effect, also run `cargo fmt` on the whole project, so don't run it with +your editor open! + + cargo install cargo-swagger # uses docker + ./codegen_openapi2.sh + +Update Rust database schema (after changing raw SQL schema): + + diesel database reset + diesel print-schema > src/database_schema.rs + +Debug SQL schema errors (if diesel commands fail): + + psql fatcat_test < migrations/2018-05-12-001226_init/up.sql + +## Direct API Interaction + +Creating entities via API: + + http --json post localhost:9411/v0/container name=asdf issn=1234-5678 diff --git a/rust/INSTALL.md b/rust/INSTALL.md new file mode 100644 index 00000000..c2b86c51 --- /dev/null +++ b/rust/INSTALL.md @@ -0,0 +1,36 @@ + +Canonical IA production/QA ansible scripts are in the journal-infra repo. These +directions are likely to end up out-of-date. + +## Simple Deployment + +To install manually, on a bare server, as root: + + adduser fatcat + apt install postgresql-9.6 postgresql-contrib postgresql-client-9.6 \ + nginx build-essential git pkg-config libssl-dev libpq-dev \ + htop screen + mkdir -p /srv/fatcat + chown fatcat:fatcat /srv/fatcat + + # setup new postgres user + su - postgres + createuser -P -s fatcat # strong random password + # DELETE: createdb fatcat + + # as fatcat user + su - fatcat + ssh-keygen + curl https://sh.rustup.rs -sSf | sh + source $HOME/.cargo/env + cargo install diesel_cli --no-default-features --features "postgres" + cd /srv/fatcat + git clone git@git.archive.org:webgroup/fatcat + cd rust + cargo build + echo "DATABASE_URL=postgres://fatcat@localhost/fatcat" > .env + diesel database reset + + # as fatcat, in a screen or something + cd /srv/fatcat/fatcat/rust + cargo run diff --git a/rust/README.md b/rust/README.md index a6873345..c061a1f9 100644 --- a/rust/README.md +++ b/rust/README.md @@ -29,87 +29,4 @@ Tests: cargo test -- --test-threads 1 -## Simple Deployment - -Canonical ansible scripts are in the journal-infra repo. To install manually, -on a bare server, as root: - - adduser fatcat - apt install postgresql-9.6 postgresql-contrib postgresql-client-9.6 \ - nginx build-essential git pkg-config libssl-dev libpq-dev \ - htop screen - mkdir -p /srv/fatcat - chown fatcat:fatcat /srv/fatcat - - # setup new postgres user - su - postgres - createuser -P -s fatcat # strong random password - # DELETE: createdb fatcat - - # as fatcat user - su - fatcat - ssh-keygen - curl https://sh.rustup.rs -sSf | sh - source $HOME/.cargo/env - cargo install diesel_cli --no-default-features --features "postgres" - cd /srv/fatcat - git clone git@git.archive.org:webgroup/fatcat - cd rust - cargo build - echo "DATABASE_URL=postgres://fatcat@localhost/fatcat" > .env - diesel database reset - - # as fatcat, in a screen or something - cd /srv/fatcat/fatcat/rust - cargo run - -### Dumps and Backups - -There are a few different databaase dump formats folks might want: - -- raw native database backups, for disaster recovery (would include - volatile/unsupported schema details, user API credentials, full history, - in-process edits, comments, etc) -- a sanitized version of the above: roughly per-table dumps of the full state - of the database. Could use per-table SQL expressions with sub-queries to pull - in small tables ("partial transform") and export JSON for each table; would - be extra work to maintain, so not pursuing for now. -- full history, full public schema exports, in a form that might be used to - mirror or enitrely fork the project. Propose supplying the full "changelog" - in API schema format, in a single file to capture all entity history, without - "hydrating" any inter-entity references. Rely on separate dumps of - non-entity, non-versioned tables (editors, abstracts, etc). Note that a - variant of this could use the public interface, in particular to do - incremental updates (though that wouldn't capture schema changes). -- transformed exports of the current state of the database (aka, without - history). Useful for data analysis, search engines, etc. Propose supplying - just the Release table in a fully "hydrated" state to start. Unclear if - should be on a work or release basis; will go with release for now. Harder to - do using public interface because of the need for transaction locking. - -Backing up the entire database using `pg_dump`, with parallelism 1 (use more on -larger machine with fast disks; try 4 or 8?), assuming the database name is -'fatcat', and the current user has access: - - pg_dump -j1 -Fd -f test-dump fatcat - -### Special Tricks - -Regenerate API schemas (this will, as a side-effect, also run `cargo fmt` on -the whole project, so don't run it with your editor open): - - cargo install cargo-swagger # uses docker - ./codegen_openapi2.sh - -Regenerate SQL schema: - - diesel database reset - diesel print-schema > src/database_schema.rs - -Debugging SQL schema errors: - - psql fatcat_test < migrations/2018-05-12-001226_init/up.sql - -Creating entities via API: - - http --json post localhost:9411/v0/container name=asdf issn=1234-5678 +See `HACKING` for some more advanced tips and commands. -- cgit v1.2.3 From cc11d5000910b5fd53e40bfd01056c0db60c35aa Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 30 Aug 2018 16:52:03 -0700 Subject: editgroup parameter for batch inserts --- rust/src/api_server.rs | 24 +++++++++++++++++++----- rust/src/api_wrappers.rs | 3 ++- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 0cb07e81..e8e7d062 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -26,21 +26,35 @@ macro_rules! entity_batch_handler { &self, entity_list: &[models::$model], autoaccept: bool, + editgroup: Option, conn: &DbConn, ) -> Result> { let mut ret: Vec = vec![]; let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) - .values((editgroup::editor_id.eq(editor_id),)) - .get_result(conn)?; + // editgroup override logic based on parameters + let eg_id: Option = match (editgroup, autoaccept) { + (Some(eg_string), _) => Some(Uuid::parse_str(&eg_string)?), + (None, true) => { + let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) + .values((editgroup::editor_id.eq(editor_id),)) + .get_result(conn)?; + Some(eg_row.id) + }, + (None, false) => None + }; for entity in entity_list { let mut e = entity.clone(); - e.editgroup_id = Some(uuid2fcid(&eg_row.id)); + // override individual editgroup IDs (if set earlier) + if let Some(inner_id) = eg_id { + e.editgroup_id = Some(uuid2fcid(&inner_id)); + } + // actual wrapped function call here ret.push(self.$post_handler(e, autoaccept, conn)?); } if autoaccept { + // if autoaccept, eg_id is always Some let _clr: ChangelogRow = diesel::insert_into(changelog::table) - .values((changelog::editgroup_id.eq(eg_row.id),)) + .values((changelog::editgroup_id.eq(eg_id.unwrap()),)) .get_result(conn)?; } Ok(ret) diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 4f126385..da6139d2 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -84,10 +84,11 @@ macro_rules! wrap_entity_handlers { &self, entity_list: &Vec, autoaccept: Option, + editgroup: Option, _context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); - let ret = match conn.transaction(|| self.$post_batch_handler(entity_list, autoaccept.unwrap_or(false), &conn)) { + let ret = match conn.transaction(|| self.$post_batch_handler(entity_list, autoaccept.unwrap_or(false), editgroup, &conn)) { Ok(edit) => $post_batch_resp::CreatedEntities(edit), Err(Error(ErrorKind::Diesel(e), _)) => -- cgit v1.2.3 From 43cb2cdcd3dae5e054f093120940b9aa1e09718a Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 30 Aug 2018 19:21:08 -0700 Subject: minimal autoaccept tests --- rust/tests/test_api_server.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'rust') diff --git a/rust/tests/test_api_server.rs b/rust/tests/test_api_server.rs index 02c77413..340fb996 100644 --- a/rust/tests/test_api_server.rs +++ b/rust/tests/test_api_server.rs @@ -918,3 +918,44 @@ fn test_contribs() { None, ); } + +#[test] +fn test_post_batch_autoaccept() { + let (headers, router, _conn) = setup(); + + // "true" + check_response( + request::post( + "http://localhost:9411/v0/container/batch?autoaccept=true", + headers.clone(), + r#"[{"name": "test journal"}, {"name": "another test journal"}]"#, + &router, + ), + status::Created, + None, + ); + + // "n" + check_response( + request::post( + "http://localhost:9411/v0/container/batch?autoaccept=n", + headers.clone(), + r#"[{"name": "test journal"}, {"name": "another test journal"}]"#, + &router, + ), + status::Created, + None, + ); + + // editgroup + check_response( + request::post( + "http://localhost:9411/v0/container/batch?autoaccept=yes&editgroup=asdf", + headers.clone(), + r#"[{"name": "test journal"}, {"name": "another test journal"}]"#, + &router, + ), + status::BadRequest, + None, + ); +} -- cgit v1.2.3 From d046bee7a76576cf14a2815b787247fca8c44433 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 30 Aug 2018 19:36:33 -0700 Subject: editgroup IDs are fcid, not uuid --- rust/src/api_server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index e8e7d062..88fd7063 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -33,7 +33,7 @@ macro_rules! entity_batch_handler { let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth // editgroup override logic based on parameters let eg_id: Option = match (editgroup, autoaccept) { - (Some(eg_string), _) => Some(Uuid::parse_str(&eg_string)?), + (Some(eg_string), _) => Some(fcid2uuid(&eg_string)?), (None, true) => { let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) .values((editgroup::editor_id.eq(editor_id),)) -- cgit v1.2.3 From e53215bc0c0126b624bf92df52a897a4603e044b Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 31 Aug 2018 14:36:44 -0700 Subject: add bad request response type for eg accept --- fatcat-openapi2.yml | 4 ++++ rust/fatcat-api/README.md | 2 +- rust/fatcat-api/api.yaml | 4 ++++ rust/fatcat-api/api/swagger.yaml | 6 +++--- rust/fatcat-api/src/client.rs | 2 +- rust/fatcat-api/src/lib.rs | 4 ++-- rust/fatcat-api/src/mimetypes.rs | 2 +- rust/fatcat-api/src/server.rs | 4 ++-- 8 files changed, 18 insertions(+), 10 deletions(-) (limited to 'rust') diff --git a/fatcat-openapi2.yml b/fatcat-openapi2.yml index 524333ce..c02d4f03 100644 --- a/fatcat-openapi2.yml +++ b/fatcat-openapi2.yml @@ -1001,6 +1001,10 @@ paths: description: Unmergable schema: $ref: "#/definitions/error_response" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" 404: description: Not Found schema: diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index 1e382370..ba2f6186 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-08-16T16:42:27.600Z +- Build date: 2018-08-31T21:31:20.591Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index 524333ce..c02d4f03 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -1001,6 +1001,10 @@ paths: description: Unmergable schema: $ref: "#/definitions/error_response" + 400: + description: Bad Request + schema: + $ref: "#/definitions/error_response" 404: description: Not Found schema: diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index 021594c0..d54aafc4 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -1808,11 +1808,11 @@ paths: uppercase_data_type: "SUCCESS" producesJson: true 400: - description: "Unmergable" + description: "Bad Request" schema: $ref: "#/definitions/error_response" - x-responseId: "Unmergable" - x-uppercaseResponseId: "UNMERGABLE" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" uppercase_operation_id: "ACCEPT_EDITGROUP" uppercase_data_type: "ERRORRESPONSE" producesJson: true diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index bc1992de..4140da76 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -191,7 +191,7 @@ 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::(&buf)?; - Ok(AcceptEditgroupResponse::Unmergable(body)) + Ok(AcceptEditgroupResponse::BadRequest(body)) } 404 => { let mut buf = String::new(); diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index fac8ecac..81b2fbfa 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -36,8 +36,8 @@ pub use swagger::{ApiError, Context, ContextWrapper}; pub enum AcceptEditgroupResponse { /// Merged Successfully MergedSuccessfully(models::Success), - /// Unmergable - Unmergable(models::ErrorResponse), + /// Bad Request + BadRequest(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), /// Generic Error diff --git a/rust/fatcat-api/src/mimetypes.rs b/rust/fatcat-api/src/mimetypes.rs index 53b582dc..2af30994 100644 --- a/rust/fatcat-api/src/mimetypes.rs +++ b/rust/fatcat-api/src/mimetypes.rs @@ -10,7 +10,7 @@ pub mod responses { } /// Create Mime objects for the response content types for AcceptEditgroup lazy_static! { - pub static ref ACCEPT_EDITGROUP_UNMERGABLE: Mime = mime!(Application / Json); + pub static ref ACCEPT_EDITGROUP_BAD_REQUEST: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for AcceptEditgroup lazy_static! { diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index 68e08515..90e0f4e0 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -130,11 +130,11 @@ where Ok(response) } - AcceptEditgroupResponse::Unmergable(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::ACCEPT_EDITGROUP_UNMERGABLE.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()))); -- cgit v1.2.3 From 0053d133f8ff96aa4dedc1ff7e2754812ddfc79a Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 31 Aug 2018 14:43:58 -0700 Subject: correct EditgroupAlreadyAccepted response --- rust/src/api_helpers.rs | 5 +---- rust/src/api_server.rs | 5 ++++- rust/src/api_wrappers.rs | 5 +++++ rust/src/lib.rs | 4 ++++ 4 files changed, 14 insertions(+), 5 deletions(-) (limited to 'rust') diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 020aad76..a68ed8a9 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -34,10 +34,7 @@ pub fn accept_editgroup(editgroup_id: Uuid, conn: &PgConnection) -> Result 0 { - bail!( - "editgroup {} has already been accepted", - editgroup_id.to_string() - ); + return Err(ErrorKind::EditgroupAlreadyAccepted(uuid2fcid(&editgroup_id)).into()); } // for each entity type... diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index b0dff173..7bf3122b 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -216,7 +216,10 @@ fn release_row2entity( let contribs: Vec = release_contrib::table .filter(release_contrib::release_rev.eq(rev.id)) - .order((release_contrib::role.asc(), release_contrib::index_val.asc())) + .order(( + release_contrib::role.asc(), + release_contrib::index_val.asc(), + )) .get_results(conn) .expect("fetch release refs") .into_iter() diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 95336d3f..403c7caf 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -308,6 +308,11 @@ impl Api for Server { message: format!("No such editgroup: {}", id), }) } + Err(Error(ErrorKind::EditgroupAlreadyAccepted(e), _)) => { + AcceptEditgroupResponse::BadRequest(ErrorResponse { + message: ErrorKind::EditgroupAlreadyAccepted(e).to_string(), + }) + } Err(e) => AcceptEditgroupResponse::GenericError(ErrorResponse { message: e.to_string(), }), diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 50a7d410..12ce0973 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -47,6 +47,10 @@ mod errors { description("external identifier doesn't match required pattern") display("external identifier doesn't match required pattern") } + EditgroupAlreadyAccepted(id: String) { + description("editgroup was already accepted") + display("attempted to accept an editgroup which was already accepted: {}", id) + } } } } -- cgit v1.2.3 From 36a1fbe4ce13be3631e07a5ecfc84ffc87c74931 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 6 Sep 2018 15:02:11 -0700 Subject: codegen put/delete --- rust/fatcat-api/README.md | 12 +- rust/fatcat-api/api.yaml | 194 ++- rust/fatcat-api/api/swagger.yaml | 614 +++++++++ rust/fatcat-api/examples/client.rs | 68 +- rust/fatcat-api/examples/server_lib/server.rs | 109 +- rust/fatcat-api/src/client.rs | 1241 +++++++++++++---- rust/fatcat-api/src/lib.rs | 202 +++ rust/fatcat-api/src/mimetypes.rs | 184 +++ rust/fatcat-api/src/server.rs | 1775 ++++++++++++++++++++----- 9 files changed, 3729 insertions(+), 670 deletions(-) (limited to 'rust') diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index ba2f6186..8381b9f7 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-08-31T21:31:20.591Z +- Build date: 2018-09-01T01:21:49.948Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. @@ -68,6 +68,11 @@ cargo run --example client CreateRelease cargo run --example client CreateReleaseBatch cargo run --example client CreateWork cargo run --example client CreateWorkBatch +cargo run --example client DeleteContainer +cargo run --example client DeleteCreator +cargo run --example client DeleteFile +cargo run --example client DeleteRelease +cargo run --example client DeleteWork cargo run --example client GetChangelog cargo run --example client GetChangelogEntry cargo run --example client GetContainer @@ -91,6 +96,11 @@ cargo run --example client LookupContainer cargo run --example client LookupCreator cargo run --example client LookupFile cargo run --example client LookupRelease +cargo run --example client UpdateContainer +cargo run --example client UpdateCreator +cargo run --example client UpdateFile +cargo run --example client UpdateRelease +cargo run --example client UpdateWork ``` ### HTTPS diff --git a/rust/fatcat-api/api.yaml b/rust/fatcat-api/api.yaml index c02d4f03..d9cf8813 100644 --- a/rust/fatcat-api/api.yaml +++ b/rust/fatcat-api/api.yaml @@ -459,19 +459,47 @@ paths: in: path type: string required: true - - name: expand - in: query - type: string - required: false - description: "List of sub-entities to expand in response. For now, only 'all' accepted." get: operationId: "get_container" + parameters: + - name: expand + in: query + type: string + required: false + description: "List of sub-entities to expand in response. For now, only 'all' accepted." responses: 200: description: Found Entity schema: $ref: "#/definitions/container_entity" <<: *ENTITYRESPONSES + put: + operationId: "update_container" + parameters: + - name: entity + in: body + required: true + schema: + $ref: "#/definitions/container_entity" + responses: + 200: + description: Updated Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES + delete: + operationId: "delete_container" + parameters: + - name: editgroup + in: query + required: false + type: string + responses: + 200: + description: Deleted Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES /container/{id}/history: parameters: - name: id @@ -547,19 +575,47 @@ paths: in: path type: string required: true - - name: expand - in: query - type: string - required: false - description: "List of sub-entities to expand in response. For now, only 'all' accepted." get: operationId: "get_creator" + parameters: + - name: expand + in: query + type: string + required: false + description: "List of sub-entities to expand in response. For now, only 'all' accepted." responses: 200: description: Found Entity schema: $ref: "#/definitions/creator_entity" <<: *ENTITYRESPONSES + put: + operationId: "update_creator" + parameters: + - name: entity + in: body + required: true + schema: + $ref: "#/definitions/creator_entity" + responses: + 200: + description: Updated Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES + delete: + operationId: "delete_creator" + parameters: + - name: editgroup + in: query + required: false + type: string + responses: + 200: + description: Deleted Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES /creator/{id}/history: parameters: - name: id @@ -651,19 +707,47 @@ paths: in: path type: string required: true - - name: expand - in: query - type: string - required: false - description: "List of sub-entities to expand in response. For now, only 'all' accepted." get: operationId: "get_file" + parameters: + - name: expand + in: query + type: string + required: false + description: "List of sub-entities to expand in response. For now, only 'all' accepted." responses: 200: description: Found Entity schema: $ref: "#/definitions/file_entity" <<: *ENTITYRESPONSES + put: + operationId: "update_file" + parameters: + - name: entity + in: body + required: true + schema: + $ref: "#/definitions/file_entity" + responses: + 200: + description: Updated Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES + delete: + operationId: "delete_file" + parameters: + - name: editgroup + in: query + required: false + type: string + responses: + 200: + description: Deleted Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES /file/{id}/history: parameters: - name: id @@ -739,19 +823,47 @@ paths: in: path type: string required: true - - name: expand - in: query - type: string - required: false - description: "List of sub-entities to expand in response. For now, only 'all' accepted." get: operationId: "get_release" + parameters: + - name: expand + in: query + type: string + required: false + description: "List of sub-entities to expand in response. For now, only 'all' accepted." responses: 200: description: Found Entity schema: $ref: "#/definitions/release_entity" <<: *ENTITYRESPONSES + put: + operationId: "update_release" + parameters: + - name: entity + in: body + required: true + schema: + $ref: "#/definitions/release_entity" + responses: + 200: + description: Updated Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES + delete: + operationId: "delete_release" + parameters: + - name: editgroup + in: query + required: false + type: string + responses: + 200: + description: Deleted Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES /release/{id}/history: parameters: - name: id @@ -843,19 +955,47 @@ paths: in: path type: string required: true - - name: expand - in: query - type: string - required: false - description: "List of sub-entities to expand in response. For now, only 'all' accepted." get: operationId: "get_work" + parameters: + - name: expand + in: query + type: string + required: false + description: "List of sub-entities to expand in response. For now, only 'all' accepted." responses: 200: description: Found Entity schema: $ref: "#/definitions/work_entity" <<: *ENTITYRESPONSES + put: + operationId: "update_work" + parameters: + - name: entity + in: body + required: true + schema: + $ref: "#/definitions/work_entity" + responses: + 200: + description: Updated Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES + delete: + operationId: "delete_work" + parameters: + - name: editgroup + in: query + required: false + type: string + responses: + 200: + description: Deleted Entity + schema: + $ref: "#/definitions/entity_edit" + <<: *ENTITYRESPONSES /work/{id}/history: parameters: - name: id @@ -1009,6 +1149,10 @@ paths: description: Not Found schema: $ref: "#/definitions/error_response" + 409: + description: Edit Conflict + schema: + $ref: "#/definitions/error_response" 500: description: Generic Error schema: diff --git a/rust/fatcat-api/api/swagger.yaml b/rust/fatcat-api/api/swagger.yaml index d54aafc4..e8026c8d 100644 --- a/rust/fatcat-api/api/swagger.yaml +++ b/rust/fatcat-api/api/swagger.yaml @@ -192,6 +192,127 @@ paths: path: "/container/:id" HttpMethod: "Get" httpmethod: "get" + put: + operationId: "update_container" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - in: "body" + name: "entity" + required: true + schema: + $ref: "#/definitions/container_entity" + uppercase_data_type: "CONTAINERENTITY" + refName: "container_entity" + formatString: "{:?}" + example: "???" + model_key: "editgroup_edits" + uppercase_operation_id: "UPDATE_CONTAINER" + consumesJson: true + responses: + 200: + description: "Updated Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "UpdatedEntity" + x-uppercaseResponseId: "UPDATED_ENTITY" + uppercase_operation_id: "UPDATE_CONTAINER" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "UPDATE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "UPDATE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "UPDATE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "update_container" + uppercase_operation_id: "UPDATE_CONTAINER" + path: "/container/:id" + HttpMethod: "Put" + httpmethod: "put" + noClientExample: true + delete: + operationId: "delete_container" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - name: "editgroup" + in: "query" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" + responses: + 200: + description: "Deleted Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "DeletedEntity" + x-uppercaseResponseId: "DELETED_ENTITY" + uppercase_operation_id: "DELETE_CONTAINER" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "DELETE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "DELETE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "DELETE_CONTAINER" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "delete_container" + uppercase_operation_id: "DELETE_CONTAINER" + path: "/container/:id" + HttpMethod: "Delete" + httpmethod: "delete" /container/{id}/history: get: operationId: "get_container_history" @@ -487,6 +608,127 @@ paths: path: "/creator/:id" HttpMethod: "Get" httpmethod: "get" + put: + operationId: "update_creator" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - in: "body" + name: "entity" + required: true + schema: + $ref: "#/definitions/creator_entity" + uppercase_data_type: "CREATORENTITY" + refName: "creator_entity" + formatString: "{:?}" + example: "???" + model_key: "editgroup_edits" + uppercase_operation_id: "UPDATE_CREATOR" + consumesJson: true + responses: + 200: + description: "Updated Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "UpdatedEntity" + x-uppercaseResponseId: "UPDATED_ENTITY" + uppercase_operation_id: "UPDATE_CREATOR" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "UPDATE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "UPDATE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "UPDATE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "update_creator" + uppercase_operation_id: "UPDATE_CREATOR" + path: "/creator/:id" + HttpMethod: "Put" + httpmethod: "put" + noClientExample: true + delete: + operationId: "delete_creator" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - name: "editgroup" + in: "query" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" + responses: + 200: + description: "Deleted Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "DeletedEntity" + x-uppercaseResponseId: "DELETED_ENTITY" + uppercase_operation_id: "DELETE_CREATOR" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "DELETE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "DELETE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "DELETE_CREATOR" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "delete_creator" + uppercase_operation_id: "DELETE_CREATOR" + path: "/creator/:id" + HttpMethod: "Delete" + httpmethod: "delete" /creator/{id}/history: get: operationId: "get_creator_history" @@ -836,6 +1078,127 @@ paths: path: "/file/:id" HttpMethod: "Get" httpmethod: "get" + put: + operationId: "update_file" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - in: "body" + name: "entity" + required: true + schema: + $ref: "#/definitions/file_entity" + uppercase_data_type: "FILEENTITY" + refName: "file_entity" + formatString: "{:?}" + example: "???" + model_key: "editgroup_edits" + uppercase_operation_id: "UPDATE_FILE" + consumesJson: true + responses: + 200: + description: "Updated Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "UpdatedEntity" + x-uppercaseResponseId: "UPDATED_ENTITY" + uppercase_operation_id: "UPDATE_FILE" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "UPDATE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "UPDATE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "UPDATE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "update_file" + uppercase_operation_id: "UPDATE_FILE" + path: "/file/:id" + HttpMethod: "Put" + httpmethod: "put" + noClientExample: true + delete: + operationId: "delete_file" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - name: "editgroup" + in: "query" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" + responses: + 200: + description: "Deleted Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "DeletedEntity" + x-uppercaseResponseId: "DELETED_ENTITY" + uppercase_operation_id: "DELETE_FILE" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "DELETE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "DELETE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "DELETE_FILE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "delete_file" + uppercase_operation_id: "DELETE_FILE" + path: "/file/:id" + HttpMethod: "Delete" + httpmethod: "delete" /file/{id}/history: get: operationId: "get_file_history" @@ -1128,6 +1491,127 @@ paths: path: "/release/:id" HttpMethod: "Get" httpmethod: "get" + put: + operationId: "update_release" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - in: "body" + name: "entity" + required: true + schema: + $ref: "#/definitions/release_entity" + uppercase_data_type: "RELEASEENTITY" + refName: "release_entity" + formatString: "{:?}" + example: "???" + model_key: "editgroup_edits" + uppercase_operation_id: "UPDATE_RELEASE" + consumesJson: true + responses: + 200: + description: "Updated Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "UpdatedEntity" + x-uppercaseResponseId: "UPDATED_ENTITY" + uppercase_operation_id: "UPDATE_RELEASE" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "UPDATE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "UPDATE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "UPDATE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "update_release" + uppercase_operation_id: "UPDATE_RELEASE" + path: "/release/:id" + HttpMethod: "Put" + httpmethod: "put" + noClientExample: true + delete: + operationId: "delete_release" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - name: "editgroup" + in: "query" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" + responses: + 200: + description: "Deleted Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "DeletedEntity" + x-uppercaseResponseId: "DELETED_ENTITY" + uppercase_operation_id: "DELETE_RELEASE" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "DELETE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "DELETE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "DELETE_RELEASE" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "delete_release" + uppercase_operation_id: "DELETE_RELEASE" + path: "/release/:id" + HttpMethod: "Delete" + httpmethod: "delete" /release/{id}/history: get: operationId: "get_release_history" @@ -1474,6 +1958,127 @@ paths: path: "/work/:id" HttpMethod: "Get" httpmethod: "get" + put: + operationId: "update_work" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - in: "body" + name: "entity" + required: true + schema: + $ref: "#/definitions/work_entity" + uppercase_data_type: "WORKENTITY" + refName: "work_entity" + formatString: "{:?}" + example: "???" + model_key: "editgroup_edits" + uppercase_operation_id: "UPDATE_WORK" + consumesJson: true + responses: + 200: + description: "Updated Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "UpdatedEntity" + x-uppercaseResponseId: "UPDATED_ENTITY" + uppercase_operation_id: "UPDATE_WORK" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "UPDATE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "UPDATE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "UPDATE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "update_work" + uppercase_operation_id: "UPDATE_WORK" + path: "/work/:id" + HttpMethod: "Put" + httpmethod: "put" + noClientExample: true + delete: + operationId: "delete_work" + parameters: + - name: "id" + in: "path" + required: true + type: "string" + formatString: "\\\"{}\\\"" + example: "\"id_example\".to_string()" + - name: "editgroup" + in: "query" + required: false + type: "string" + formatString: "{:?}" + example: "Some(\"editgroup_example\".to_string())" + responses: + 200: + description: "Deleted Entity" + schema: + $ref: "#/definitions/entity_edit" + x-responseId: "DeletedEntity" + x-uppercaseResponseId: "DELETED_ENTITY" + uppercase_operation_id: "DELETE_WORK" + uppercase_data_type: "ENTITYEDIT" + producesJson: true + 400: + description: "Bad Request" + schema: + $ref: "#/definitions/error_response" + x-responseId: "BadRequest" + x-uppercaseResponseId: "BAD_REQUEST" + uppercase_operation_id: "DELETE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 404: + description: "Not Found" + schema: + $ref: "#/definitions/error_response" + x-responseId: "NotFound" + x-uppercaseResponseId: "NOT_FOUND" + uppercase_operation_id: "DELETE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + 500: + description: "Generic Error" + schema: + $ref: "#/definitions/error_response" + x-responseId: "GenericError" + x-uppercaseResponseId: "GENERIC_ERROR" + uppercase_operation_id: "DELETE_WORK" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true + operation_id: "delete_work" + uppercase_operation_id: "DELETE_WORK" + path: "/work/:id" + HttpMethod: "Delete" + httpmethod: "delete" /work/{id}/history: get: operationId: "get_work_history" @@ -1825,6 +2430,15 @@ paths: uppercase_operation_id: "ACCEPT_EDITGROUP" uppercase_data_type: "ERRORRESPONSE" producesJson: true + 409: + description: "Edit Conflict" + schema: + $ref: "#/definitions/error_response" + x-responseId: "EditConflict" + x-uppercaseResponseId: "EDIT_CONFLICT" + uppercase_operation_id: "ACCEPT_EDITGROUP" + uppercase_data_type: "ERRORRESPONSE" + producesJson: true 500: description: "Generic Error" schema: diff --git a/rust/fatcat-api/examples/client.rs b/rust/fatcat-api/examples/client.rs index f98518cc..2ee65d7e 100644 --- a/rust/fatcat-api/examples/client.rs +++ b/rust/fatcat-api/examples/client.rs @@ -13,10 +13,11 @@ use clap::{App, Arg}; #[allow(unused_imports)] use fatcat::{ AcceptEditgroupResponse, ApiError, ApiNoContext, ContextWrapperExt, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, - CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetChangelogEntryResponse, - GetChangelogResponse, GetContainerHistoryResponse, GetContainerResponse, GetCreatorHistoryResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, - GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, - GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, + CreateEditgroupResponse, CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerResponse, + DeleteCreatorResponse, DeleteFileResponse, DeleteReleaseResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerHistoryResponse, GetContainerResponse, + GetCreatorHistoryResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, GetFileResponse, + GetReleaseFilesResponse, GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, + LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateReleaseResponse, UpdateWorkResponse, }; #[allow(unused_imports)] use futures::{future, stream, Future, Stream}; @@ -33,6 +34,11 @@ fn main() { "CreateFileBatch", "CreateReleaseBatch", "CreateWorkBatch", + "DeleteContainer", + "DeleteCreator", + "DeleteFile", + "DeleteRelease", + "DeleteWork", "GetChangelog", "GetChangelogEntry", "GetContainer", @@ -145,6 +151,31 @@ fn main() { println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } + Some("DeleteContainer") => { + let result = client.delete_container("id_example".to_string(), Some("editgroup_example".to_string())).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + } + + Some("DeleteCreator") => { + let result = client.delete_creator("id_example".to_string(), Some("editgroup_example".to_string())).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + } + + Some("DeleteFile") => { + let result = client.delete_file("id_example".to_string(), Some("editgroup_example".to_string())).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + } + + Some("DeleteRelease") => { + let result = client.delete_release("id_example".to_string(), Some("editgroup_example".to_string())).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + } + + Some("DeleteWork") => { + let result = client.delete_work("id_example".to_string(), Some("editgroup_example".to_string())).wait(); + println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + } + 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(""))); @@ -260,6 +291,35 @@ fn main() { println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); } + // Disabled because there's no example. + // Some("UpdateContainer") => { + // let result = client.update_container("id_example".to_string(), ???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + // }, + + // Disabled because there's no example. + // Some("UpdateCreator") => { + // let result = client.update_creator("id_example".to_string(), ???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + // }, + + // Disabled because there's no example. + // Some("UpdateFile") => { + // let result = client.update_file("id_example".to_string(), ???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + // }, + + // Disabled because there's no example. + // Some("UpdateRelease") => { + // let result = client.update_release("id_example".to_string(), ???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + // }, + + // Disabled because there's no example. + // Some("UpdateWork") => { + // let result = client.update_work("id_example".to_string(), ???).wait(); + // println!("{:?} (X-Span-ID: {:?})", result, client.context().x_span_id.clone().unwrap_or(String::from(""))); + // }, _ => panic!("Invalid operation provided"), } } diff --git a/rust/fatcat-api/examples/server_lib/server.rs b/rust/fatcat-api/examples/server_lib/server.rs index 572025f0..af3ece12 100644 --- a/rust/fatcat-api/examples/server_lib/server.rs +++ b/rust/fatcat-api/examples/server_lib/server.rs @@ -12,10 +12,11 @@ use swagger; use fatcat::models; use fatcat::{ AcceptEditgroupResponse, Api, ApiError, Context, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, - CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, - GetContainerHistoryResponse, GetContainerResponse, GetCreatorHistoryResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, - GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, - GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, + CreateFileBatchResponse, CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerResponse, DeleteCreatorResponse, + DeleteFileResponse, DeleteReleaseResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerHistoryResponse, GetContainerResponse, GetCreatorHistoryResponse, + GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, + GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, + LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateReleaseResponse, UpdateWorkResponse, }; #[derive(Copy, Clone)] @@ -98,6 +99,61 @@ impl Api for Server { Box::new(futures::failed("Generic failure".into())) } + fn delete_container(&self, id: String, editgroup: Option, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "delete_container(\"{}\", {:?}) - X-Span-ID: {:?}", + id, + editgroup, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + + fn delete_creator(&self, id: String, editgroup: Option, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "delete_creator(\"{}\", {:?}) - X-Span-ID: {:?}", + id, + editgroup, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + + fn delete_file(&self, id: String, editgroup: Option, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "delete_file(\"{}\", {:?}) - X-Span-ID: {:?}", + id, + editgroup, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + + fn delete_release(&self, id: String, editgroup: Option, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "delete_release(\"{}\", {:?}) - X-Span-ID: {:?}", + id, + editgroup, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + + fn delete_work(&self, id: String, editgroup: Option, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "delete_work(\"{}\", {:?}) - X-Span-ID: {:?}", + id, + editgroup, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + fn get_changelog(&self, limit: Option, context: &Context) -> Box + Send> { let context = context.clone(); println!("get_changelog({:?}) - X-Span-ID: {:?}", limit, context.x_span_id.unwrap_or(String::from("")).clone()); @@ -260,4 +316,49 @@ impl Api for Server { println!("lookup_release(\"{}\") - X-Span-ID: {:?}", doi, context.x_span_id.unwrap_or(String::from("")).clone()); Box::new(futures::failed("Generic failure".into())) } + + fn update_container(&self, id: String, entity: models::ContainerEntity, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "update_container(\"{}\", {:?}) - X-Span-ID: {:?}", + id, + entity, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + + fn update_creator(&self, id: String, entity: models::CreatorEntity, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "update_creator(\"{}\", {:?}) - X-Span-ID: {:?}", + id, + entity, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + + fn update_file(&self, id: String, entity: models::FileEntity, context: &Context) -> Box + Send> { + let context = context.clone(); + println!("update_file(\"{}\", {:?}) - X-Span-ID: {:?}", id, entity, context.x_span_id.unwrap_or(String::from("")).clone()); + Box::new(futures::failed("Generic failure".into())) + } + + fn update_release(&self, id: String, entity: models::ReleaseEntity, context: &Context) -> Box + Send> { + let context = context.clone(); + println!( + "update_release(\"{}\", {:?}) - X-Span-ID: {:?}", + id, + entity, + context.x_span_id.unwrap_or(String::from("")).clone() + ); + Box::new(futures::failed("Generic failure".into())) + } + + fn update_work(&self, id: String, entity: models::WorkEntity, context: &Context) -> Box + Send> { + let context = context.clone(); + println!("update_work(\"{}\", {:?}) - X-Span-ID: {:?}", id, entity, context.x_span_id.unwrap_or(String::from("")).clone()); + Box::new(futures::failed("Generic failure".into())) + } } diff --git a/rust/fatcat-api/src/client.rs b/rust/fatcat-api/src/client.rs index 4140da76..9b2caa32 100644 --- a/rust/fatcat-api/src/client.rs +++ b/rust/fatcat-api/src/client.rs @@ -36,10 +36,11 @@ use swagger::{ApiError, Context, XSpanId}; use models; use { AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, - CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerHistoryResponse, - GetContainerResponse, GetCreatorHistoryResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, - GetFileResponse, GetReleaseFilesResponse, GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, - LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, + CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerResponse, DeleteCreatorResponse, DeleteFileResponse, + DeleteReleaseResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerHistoryResponse, GetContainerResponse, GetCreatorHistoryResponse, + GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, + GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, + LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateReleaseResponse, UpdateWorkResponse, }; /// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes. @@ -200,6 +201,13 @@ impl Api for Client { 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::(&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)))?; @@ -933,14 +941,19 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_changelog(&self, param_limit: Option, context: &Context) -> Box + Send> { + fn delete_container(&self, param_id: String, param_editgroup: Option, context: &Context) -> Box + Send> { // Query parameters - let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); - let url = format!("{}/v0/changelog?{limit}", self.base_path, limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET)); + let url = format!( + "{}/v0/container/{id}?{editgroup}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), + editgroup = utf8_percent_encode(&query_editgroup, QUERY_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::Delete, &url); let mut custom_headers = hyper::header::Headers::new(); context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); @@ -948,74 +961,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetChangelogResponse::Success(body)) + Ok(DeleteContainerResponse::DeletedEntity(body)) } - 500 => { + 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::(&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!("", &buf[..len].to_vec())), - }, - Err(e) => Cow::from(format!("", 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_id: i64, context: &Context) -> Box + Send> { - let url = format!("{}/v0/changelog/{id}", self.base_path, id = utf8_percent_encode(¶m_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 { - 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::(&buf)?; - - Ok(GetChangelogEntryResponse::FoundChangelogEntry(body)) + Ok(DeleteContainerResponse::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::(&buf)?; - Ok(GetChangelogEntryResponse::NotFound(body)) + Ok(DeleteContainerResponse::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::(&buf)?; - Ok(GetChangelogEntryResponse::GenericError(body)) + Ok(DeleteContainerResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1035,19 +1009,19 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_container(&self, param_id: String, param_expand: Option, context: &Context) -> Box + Send> { + fn delete_creator(&self, param_id: String, param_editgroup: Option, context: &Context) -> Box + Send> { // Query parameters - let query_expand = param_expand.map_or_else(String::new, |query| format!("expand={expand}&", expand = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); let url = format!( - "{}/v0/container/{id}?{expand}", + "{}/v0/creator/{id}?{editgroup}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), - expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET) + editgroup = utf8_percent_encode(&query_editgroup, QUERY_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::Delete, &url); let mut custom_headers = hyper::header::Headers::new(); context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); @@ -1055,35 +1029,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetContainerResponse::FoundEntity(body)) + Ok(DeleteCreatorResponse::DeletedEntity(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::(&buf)?; - Ok(GetContainerResponse::BadRequest(body)) + Ok(DeleteCreatorResponse::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::(&buf)?; - Ok(GetContainerResponse::NotFound(body)) + Ok(DeleteCreatorResponse::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::(&buf)?; - Ok(GetContainerResponse::GenericError(body)) + Ok(DeleteCreatorResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1103,19 +1077,19 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_container_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { + fn delete_file(&self, param_id: String, param_editgroup: Option, context: &Context) -> Box + Send> { // Query parameters - let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); let url = format!( - "{}/v0/container/{id}/history?{limit}", + "{}/v0/file/{id}?{editgroup}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), - limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) + editgroup = utf8_percent_encode(&query_editgroup, QUERY_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::Delete, &url); let mut custom_headers = hyper::header::Headers::new(); context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); @@ -1123,35 +1097,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetContainerHistoryResponse::FoundEntityHistory(body)) + Ok(DeleteFileResponse::DeletedEntity(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::(&buf)?; - Ok(GetContainerHistoryResponse::BadRequest(body)) + Ok(DeleteFileResponse::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::(&buf)?; - Ok(GetContainerHistoryResponse::NotFound(body)) + Ok(DeleteFileResponse::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::(&buf)?; - Ok(GetContainerHistoryResponse::GenericError(body)) + Ok(DeleteFileResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1171,19 +1145,19 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_creator(&self, param_id: String, param_expand: Option, context: &Context) -> Box + Send> { + fn delete_release(&self, param_id: String, param_editgroup: Option, context: &Context) -> Box + Send> { // Query parameters - let query_expand = param_expand.map_or_else(String::new, |query| format!("expand={expand}&", expand = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); let url = format!( - "{}/v0/creator/{id}?{expand}", + "{}/v0/release/{id}?{editgroup}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), - expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET) + editgroup = utf8_percent_encode(&query_editgroup, QUERY_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::Delete, &url); let mut custom_headers = hyper::header::Headers::new(); context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); @@ -1191,35 +1165,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetCreatorResponse::FoundEntity(body)) + Ok(DeleteReleaseResponse::DeletedEntity(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::(&buf)?; - Ok(GetCreatorResponse::BadRequest(body)) + Ok(DeleteReleaseResponse::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::(&buf)?; - Ok(GetCreatorResponse::NotFound(body)) + Ok(DeleteReleaseResponse::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::(&buf)?; - Ok(GetCreatorResponse::GenericError(body)) + Ok(DeleteReleaseResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1239,19 +1213,19 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_creator_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { + fn delete_work(&self, param_id: String, param_editgroup: Option, context: &Context) -> Box + Send> { // Query parameters - let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + let query_editgroup = param_editgroup.map_or_else(String::new, |query| format!("editgroup={editgroup}&", editgroup = query.to_string())); let url = format!( - "{}/v0/creator/{id}/history?{limit}", + "{}/v0/work/{id}?{editgroup}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), - limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) + editgroup = utf8_percent_encode(&query_editgroup, QUERY_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::Delete, &url); let mut custom_headers = hyper::header::Headers::new(); context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); @@ -1259,35 +1233,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetCreatorHistoryResponse::FoundEntityHistory(body)) + Ok(DeleteWorkResponse::DeletedEntity(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::(&buf)?; - Ok(GetCreatorHistoryResponse::BadRequest(body)) + Ok(DeleteWorkResponse::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::(&buf)?; - Ok(GetCreatorHistoryResponse::NotFound(body)) + Ok(DeleteWorkResponse::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::(&buf)?; - Ok(GetCreatorHistoryResponse::GenericError(body)) + Ok(DeleteWorkResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1307,8 +1281,11 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_creator_releases(&self, param_id: String, context: &Context) -> Box + Send> { - let url = format!("{}/v0/creator/{id}/releases", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + fn get_changelog(&self, param_limit: Option, context: &Context) -> Box + 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); @@ -1319,35 +1296,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; - - Ok(GetCreatorReleasesResponse::FoundEntity(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::(&buf)?; - - Ok(GetCreatorReleasesResponse::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::(&buf)?; + let body = serde_json::from_str::>(&buf)?; - Ok(GetCreatorReleasesResponse::NotFound(body)) + Ok(GetChangelogResponse::Success(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::(&buf)?; - Ok(GetCreatorReleasesResponse::GenericError(body)) + Ok(GetChangelogResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1367,8 +1330,8 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_editgroup(&self, param_id: String, context: &Context) -> Box + Send> { - let url = format!("{}/v0/editgroup/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + fn get_changelog_entry(&self, param_id: i64, context: &Context) -> Box + Send> { + let url = format!("{}/v0/changelog/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Get, &url); @@ -1379,35 +1342,28 @@ 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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; - - Ok(GetEditgroupResponse::FoundEntity(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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetEditgroupResponse::BadRequest(body)) + Ok(GetChangelogEntryResponse::FoundChangelogEntry(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::(&buf)?; - Ok(GetEditgroupResponse::NotFound(body)) + 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::(&buf)?; - Ok(GetEditgroupResponse::GenericError(body)) + Ok(GetChangelogEntryResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1427,8 +1383,16 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_editor(&self, param_id: String, context: &Context) -> Box + Send> { - let url = format!("{}/v0/editor/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + fn get_container(&self, param_id: String, param_expand: Option, context: &Context) -> Box + 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/container/{id}?{expand}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), + expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET) + ); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Get, &url); @@ -1439,28 +1403,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetEditorResponse::FoundEditor(body)) + Ok(GetContainerResponse::FoundEntity(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::(&buf)?; + + Ok(GetContainerResponse::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::(&buf)?; - Ok(GetEditorResponse::NotFound(body)) + Ok(GetContainerResponse::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::(&buf)?; - Ok(GetEditorResponse::GenericError(body)) + Ok(GetContainerResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1480,8 +1451,16 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_editor_changelog(&self, param_id: String, context: &Context) -> Box + Send> { - let url = format!("{}/v0/editor/{id}/changelog", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + fn get_container_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + 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/container/{id}/history?{limit}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), + limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) + ); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Get, &url); @@ -1492,28 +1471,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; + let body = serde_json::from_str::>(&buf)?; - Ok(GetEditorChangelogResponse::FoundMergedChanges(body)) + Ok(GetContainerHistoryResponse::FoundEntityHistory(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(GetContainerHistoryResponse::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::(&buf)?; - Ok(GetEditorChangelogResponse::NotFound(body)) + Ok(GetContainerHistoryResponse::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::(&buf)?; - Ok(GetEditorChangelogResponse::GenericError(body)) + Ok(GetContainerHistoryResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1533,12 +1519,12 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_file(&self, param_id: String, param_expand: Option, context: &Context) -> Box + Send> { + fn get_creator(&self, param_id: String, param_expand: Option, context: &Context) -> Box + 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/file/{id}?{expand}", + "{}/v0/creator/{id}?{expand}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET) @@ -1553,35 +1539,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetFileResponse::FoundEntity(body)) + Ok(GetCreatorResponse::FoundEntity(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::(&buf)?; - Ok(GetFileResponse::BadRequest(body)) + Ok(GetCreatorResponse::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::(&buf)?; - Ok(GetFileResponse::NotFound(body)) + Ok(GetCreatorResponse::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::(&buf)?; - Ok(GetFileResponse::GenericError(body)) + Ok(GetCreatorResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1601,12 +1587,12 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_file_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { + fn get_creator_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { // Query parameters let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); let url = format!( - "{}/v0/file/{id}/history?{limit}", + "{}/v0/creator/{id}/history?{limit}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) @@ -1621,35 +1607,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; - Ok(GetFileHistoryResponse::FoundEntityHistory(body)) + Ok(GetCreatorHistoryResponse::FoundEntityHistory(body)) } 400 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::(&buf)?; - Ok(GetFileHistoryResponse::BadRequest(body)) + Ok(GetCreatorHistoryResponse::BadRequest(body)) } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::(&buf)?; - Ok(GetFileHistoryResponse::NotFound(body)) + Ok(GetCreatorHistoryResponse::NotFound(body)) } 500 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::(&buf)?; - Ok(GetFileHistoryResponse::GenericError(body)) + Ok(GetCreatorHistoryResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1669,14 +1655,376 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_release(&self, param_id: String, param_expand: Option, context: &Context) -> Box + Send> { - // Query parameters - let query_expand = param_expand.map_or_else(String::new, |query| format!("expand={expand}&", expand = query.to_string())); + fn get_creator_releases(&self, param_id: String, context: &Context) -> Box + Send> { + let url = format!("{}/v0/creator/{id}/releases", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); - let url = format!( - "{}/v0/release/{id}?{expand}", - self.base_path, - id = utf8_percent_encode(¶m_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 { + 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::>(&buf)?; + + Ok(GetCreatorReleasesResponse::FoundEntity(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::(&buf)?; + + Ok(GetCreatorReleasesResponse::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::(&buf)?; + + Ok(GetCreatorReleasesResponse::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::(&buf)?; + + Ok(GetCreatorReleasesResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", 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(&self, param_id: String, context: &Context) -> Box + Send> { + let url = format!("{}/v0/editgroup/{id}", self.base_path, id = utf8_percent_encode(¶m_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 { + 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::(&buf)?; + + Ok(GetEditgroupResponse::FoundEntity(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::(&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::(&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::(&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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", 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_id: String, context: &Context) -> Box + Send> { + let url = format!("{}/v0/editor/{id}", self.base_path, id = utf8_percent_encode(¶m_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 { + 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::(&buf)?; + + Ok(GetEditorResponse::FoundEditor(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::(&buf)?; + + 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::(&buf)?; + + Ok(GetEditorResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", 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_changelog(&self, param_id: String, context: &Context) -> Box + Send> { + let url = format!("{}/v0/editor/{id}/changelog", self.base_path, id = utf8_percent_encode(¶m_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 { + 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::>(&buf)?; + + Ok(GetEditorChangelogResponse::FoundMergedChanges(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::(&buf)?; + + Ok(GetEditorChangelogResponse::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::(&buf)?; + + Ok(GetEditorChangelogResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", 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_file(&self, param_id: String, param_expand: Option, context: &Context) -> Box + 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/file/{id}?{expand}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), + expand = utf8_percent_encode(&query_expand, 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 { + 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::(&buf)?; + + Ok(GetFileResponse::FoundEntity(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::(&buf)?; + + Ok(GetFileResponse::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::(&buf)?; + + Ok(GetFileResponse::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::(&buf)?; + + Ok(GetFileResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", 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_file_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { + // Query parameters + let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + + let url = format!( + "{}/v0/file/{id}/history?{limit}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), + limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) + ); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Get, &url); + let mut custom_headers = hyper::header::Headers::new(); + + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result { + 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::>(&buf)?; + + Ok(GetFileHistoryResponse::FoundEntityHistory(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(GetFileHistoryResponse::BadRequest(body)) + } + 404 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(GetFileHistoryResponse::NotFound(body)) + } + 500 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(GetFileHistoryResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + + fn get_release(&self, param_id: String, param_expand: Option, context: &Context) -> Box + 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/release/{id}?{expand}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET) ); @@ -1689,35 +2037,348 @@ 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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { + 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::(&buf)?; + + Ok(GetReleaseResponse::FoundEntity(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::(&buf)?; + + Ok(GetReleaseResponse::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::(&buf)?; + + Ok(GetReleaseResponse::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::(&buf)?; + + Ok(GetReleaseResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + + fn get_release_files(&self, param_id: String, context: &Context) -> Box + Send> { + let url = format!("{}/v0/release/{id}/files", self.base_path, id = utf8_percent_encode(¶m_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 { + 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::>(&buf)?; + + Ok(GetReleaseFilesResponse::FoundEntity(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::(&buf)?; + + Ok(GetReleaseFilesResponse::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::(&buf)?; + + Ok(GetReleaseFilesResponse::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::(&buf)?; + + Ok(GetReleaseFilesResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + + fn get_release_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { + // Query parameters + let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + + let url = format!( + "{}/v0/release/{id}/history?{limit}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), + limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) + ); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Get, &url); + let mut custom_headers = hyper::header::Headers::new(); + + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result { + 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::>(&buf)?; + + Ok(GetReleaseHistoryResponse::FoundEntityHistory(body)) + } + 400 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(GetReleaseHistoryResponse::BadRequest(body)) + } + 404 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(GetReleaseHistoryResponse::NotFound(body)) + } + 500 => { + let mut buf = String::new(); + response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + let body = serde_json::from_str::(&buf)?; + + Ok(GetReleaseHistoryResponse::GenericError(body)) + } + code => { + let mut buf = [0; 100]; + let debug_body = match response.read(&mut buf) { + Ok(len) => match str::from_utf8(&buf[..len]) { + Ok(body) => Cow::from(body), + Err(_) => Cow::from(format!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + + fn get_stats(&self, param_more: Option, context: &Context) -> Box + Send> { + // Query parameters + let query_more = param_more.map_or_else(String::new, |query| format!("more={more}&", more = query.to_string())); + + let url = format!("{}/v0/stats?{more}", self.base_path, more = utf8_percent_encode(&query_more, 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 { + 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::(&buf)?; + + Ok(GetStatsResponse::Success(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::(&buf)?; + + Ok(GetStatsResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + + fn get_work(&self, param_id: String, param_expand: Option, context: &Context) -> Box + 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/work/{id}?{expand}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), + expand = utf8_percent_encode(&query_expand, 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 { + 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::(&buf)?; + + Ok(GetWorkResponse::FoundEntity(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::(&buf)?; + + Ok(GetWorkResponse::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::(&buf)?; + + Ok(GetWorkResponse::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::(&buf)?; + + Ok(GetWorkResponse::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!("", &buf[..len].to_vec())), + }, + Err(e) => Cow::from(format!("", e)), + }; + Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", code, response.headers, debug_body))) + } + } + } + + let result = request.send().map_err(|e| ApiError(format!("No response received: {}", e))).and_then(parse_response); + Box::new(futures::done(result)) + } + + fn get_work_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { + // Query parameters + let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + + let url = format!( + "{}/v0/work/{id}/history?{limit}", + self.base_path, + id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), + limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) + ); + + let hyper_client = (self.hyper_client)(); + let request = hyper_client.request(hyper::method::Method::Get, &url); + let mut custom_headers = hyper::header::Headers::new(); + + context.x_span_id.as_ref().map(|header| custom_headers.set(XSpanId(header.clone()))); + + let request = request.headers(custom_headers); + + // Helper function to provide a code block to use `?` in (to be replaced by the `catch` block when it exists). + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::>(&buf)?; - Ok(GetReleaseResponse::FoundEntity(body)) + Ok(GetWorkHistoryResponse::FoundEntityHistory(body)) } 400 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::(&buf)?; - Ok(GetReleaseResponse::BadRequest(body)) + Ok(GetWorkHistoryResponse::BadRequest(body)) } 404 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::(&buf)?; - Ok(GetReleaseResponse::NotFound(body)) + Ok(GetWorkHistoryResponse::NotFound(body)) } 500 => { let mut buf = String::new(); response.read_to_string(&mut buf).map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; let body = serde_json::from_str::(&buf)?; - Ok(GetReleaseResponse::GenericError(body)) + Ok(GetWorkHistoryResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1737,8 +2398,8 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_release_files(&self, param_id: String, context: &Context) -> Box + Send> { - let url = format!("{}/v0/release/{id}/files", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + fn get_work_releases(&self, param_id: String, context: &Context) -> Box + Send> { + let url = format!("{}/v0/work/{id}/releases", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Get, &url); @@ -1749,35 +2410,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; + let body = serde_json::from_str::>(&buf)?; - Ok(GetReleaseFilesResponse::FoundEntity(body)) + Ok(GetWorkReleasesResponse::FoundEntity(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::(&buf)?; - Ok(GetReleaseFilesResponse::BadRequest(body)) + Ok(GetWorkReleasesResponse::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::(&buf)?; - Ok(GetReleaseFilesResponse::NotFound(body)) + Ok(GetWorkReleasesResponse::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::(&buf)?; - Ok(GetReleaseFilesResponse::GenericError(body)) + Ok(GetWorkReleasesResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1797,16 +2458,11 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_release_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { + fn lookup_container(&self, param_issnl: String, context: &Context) -> Box + Send> { // Query parameters - let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + let query_issnl = format!("issnl={issnl}&", issnl = param_issnl.to_string()); - let url = format!( - "{}/v0/release/{id}/history?{limit}", - self.base_path, - id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), - limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) - ); + let url = format!("{}/v0/container/lookup?{issnl}", self.base_path, issnl = utf8_percent_encode(&query_issnl, QUERY_ENCODE_SET)); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Get, &url); @@ -1817,35 +2473,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetReleaseHistoryResponse::FoundEntityHistory(body)) + Ok(LookupContainerResponse::FoundEntity(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::(&buf)?; - Ok(GetReleaseHistoryResponse::BadRequest(body)) + Ok(LookupContainerResponse::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::(&buf)?; - Ok(GetReleaseHistoryResponse::NotFound(body)) + Ok(LookupContainerResponse::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::(&buf)?; - Ok(GetReleaseHistoryResponse::GenericError(body)) + Ok(LookupContainerResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1865,11 +2521,11 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_stats(&self, param_more: Option, context: &Context) -> Box + Send> { + fn lookup_creator(&self, param_orcid: String, context: &Context) -> Box + Send> { // Query parameters - let query_more = param_more.map_or_else(String::new, |query| format!("more={more}&", more = query.to_string())); + let query_orcid = format!("orcid={orcid}&", orcid = param_orcid.to_string()); - let url = format!("{}/v0/stats?{more}", self.base_path, more = utf8_percent_encode(&query_more, QUERY_ENCODE_SET)); + let url = format!("{}/v0/creator/lookup?{orcid}", self.base_path, orcid = utf8_percent_encode(&query_orcid, QUERY_ENCODE_SET)); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Get, &url); @@ -1880,21 +2536,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetStatsResponse::Success(body)) + Ok(LookupCreatorResponse::FoundEntity(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::(&buf)?; + + Ok(LookupCreatorResponse::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::(&buf)?; + + Ok(LookupCreatorResponse::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::(&buf)?; - Ok(GetStatsResponse::GenericError(body)) + Ok(LookupCreatorResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1914,16 +2584,11 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_work(&self, param_id: String, param_expand: Option, context: &Context) -> Box + Send> { + fn lookup_file(&self, param_sha1: String, context: &Context) -> Box + Send> { // Query parameters - let query_expand = param_expand.map_or_else(String::new, |query| format!("expand={expand}&", expand = query.to_string())); + let query_sha1 = format!("sha1={sha1}&", sha1 = param_sha1.to_string()); - let url = format!( - "{}/v0/work/{id}?{expand}", - self.base_path, - id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), - expand = utf8_percent_encode(&query_expand, QUERY_ENCODE_SET) - ); + let url = format!("{}/v0/file/lookup?{sha1}", self.base_path, sha1 = utf8_percent_encode(&query_sha1, QUERY_ENCODE_SET)); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Get, &url); @@ -1934,35 +2599,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetWorkResponse::FoundEntity(body)) + Ok(LookupFileResponse::FoundEntity(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::(&buf)?; - Ok(GetWorkResponse::BadRequest(body)) + Ok(LookupFileResponse::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::(&buf)?; - Ok(GetWorkResponse::NotFound(body)) + Ok(LookupFileResponse::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::(&buf)?; - Ok(GetWorkResponse::GenericError(body)) + Ok(LookupFileResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -1982,16 +2647,11 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_work_history(&self, param_id: String, param_limit: Option, context: &Context) -> Box + Send> { + fn lookup_release(&self, param_doi: String, context: &Context) -> Box + Send> { // Query parameters - let query_limit = param_limit.map_or_else(String::new, |query| format!("limit={limit}&", limit = query.to_string())); + let query_doi = format!("doi={doi}&", doi = param_doi.to_string()); - let url = format!( - "{}/v0/work/{id}/history?{limit}", - self.base_path, - id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET), - limit = utf8_percent_encode(&query_limit, QUERY_ENCODE_SET) - ); + let url = format!("{}/v0/release/lookup?{doi}", self.base_path, doi = utf8_percent_encode(&query_doi, QUERY_ENCODE_SET)); let hyper_client = (self.hyper_client)(); let request = hyper_client.request(hyper::method::Method::Get, &url); @@ -2002,35 +2662,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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetWorkHistoryResponse::FoundEntityHistory(body)) + Ok(LookupReleaseResponse::FoundEntity(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::(&buf)?; - Ok(GetWorkHistoryResponse::BadRequest(body)) + Ok(LookupReleaseResponse::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::(&buf)?; - Ok(GetWorkHistoryResponse::NotFound(body)) + Ok(LookupReleaseResponse::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::(&buf)?; - Ok(GetWorkHistoryResponse::GenericError(body)) + Ok(LookupReleaseResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2050,47 +2710,52 @@ impl Api for Client { Box::new(futures::done(result)) } - fn get_work_releases(&self, param_id: String, context: &Context) -> Box + Send> { - let url = format!("{}/v0/work/{id}/releases", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); + fn update_container(&self, param_id: String, param_entity: models::ContainerEntity, context: &Context) -> Box + Send> { + let url = format!("{}/v0/container/{id}", self.base_path, id = utf8_percent_encode(¶m_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::Get, &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_CONTAINER.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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::>(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(GetWorkReleasesResponse::FoundEntity(body)) + Ok(UpdateContainerResponse::UpdatedEntity(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::(&buf)?; - Ok(GetWorkReleasesResponse::BadRequest(body)) + Ok(UpdateContainerResponse::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::(&buf)?; - Ok(GetWorkReleasesResponse::NotFound(body)) + Ok(UpdateContainerResponse::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::(&buf)?; - Ok(GetWorkReleasesResponse::GenericError(body)) + Ok(UpdateContainerResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2110,50 +2775,52 @@ impl Api for Client { Box::new(futures::done(result)) } - fn lookup_container(&self, param_issnl: String, context: &Context) -> Box + Send> { - // Query parameters - let query_issnl = format!("issnl={issnl}&", issnl = param_issnl.to_string()); + fn update_creator(&self, param_id: String, param_entity: models::CreatorEntity, context: &Context) -> Box + Send> { + let url = format!("{}/v0/creator/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); - let url = format!("{}/v0/container/lookup?{issnl}", self.base_path, issnl = utf8_percent_encode(&query_issnl, QUERY_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::Get, &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_CREATOR.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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(LookupContainerResponse::FoundEntity(body)) + Ok(UpdateCreatorResponse::UpdatedEntity(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::(&buf)?; - Ok(LookupContainerResponse::BadRequest(body)) + Ok(UpdateCreatorResponse::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::(&buf)?; - Ok(LookupContainerResponse::NotFound(body)) + Ok(UpdateCreatorResponse::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::(&buf)?; - Ok(LookupContainerResponse::GenericError(body)) + Ok(UpdateCreatorResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2173,50 +2840,52 @@ impl Api for Client { Box::new(futures::done(result)) } - fn lookup_creator(&self, param_orcid: String, context: &Context) -> Box + Send> { - // Query parameters - let query_orcid = format!("orcid={orcid}&", orcid = param_orcid.to_string()); + fn update_file(&self, param_id: String, param_entity: models::FileEntity, context: &Context) -> Box + Send> { + let url = format!("{}/v0/file/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); - let url = format!("{}/v0/creator/lookup?{orcid}", self.base_path, orcid = utf8_percent_encode(&query_orcid, QUERY_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::Get, &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_FILE.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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(LookupCreatorResponse::FoundEntity(body)) + Ok(UpdateFileResponse::UpdatedEntity(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::(&buf)?; - Ok(LookupCreatorResponse::BadRequest(body)) + Ok(UpdateFileResponse::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::(&buf)?; - Ok(LookupCreatorResponse::NotFound(body)) + Ok(UpdateFileResponse::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::(&buf)?; - Ok(LookupCreatorResponse::GenericError(body)) + Ok(UpdateFileResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2236,50 +2905,52 @@ impl Api for Client { Box::new(futures::done(result)) } - fn lookup_file(&self, param_sha1: String, context: &Context) -> Box + Send> { - // Query parameters - let query_sha1 = format!("sha1={sha1}&", sha1 = param_sha1.to_string()); + fn update_release(&self, param_id: String, param_entity: models::ReleaseEntity, context: &Context) -> Box + Send> { + let url = format!("{}/v0/release/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); - let url = format!("{}/v0/file/lookup?{sha1}", self.base_path, sha1 = utf8_percent_encode(&query_sha1, QUERY_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::Get, &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_RELEASE.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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(LookupFileResponse::FoundEntity(body)) + Ok(UpdateReleaseResponse::UpdatedEntity(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::(&buf)?; - Ok(LookupFileResponse::BadRequest(body)) + Ok(UpdateReleaseResponse::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::(&buf)?; - Ok(LookupFileResponse::NotFound(body)) + Ok(UpdateReleaseResponse::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::(&buf)?; - Ok(LookupFileResponse::GenericError(body)) + Ok(UpdateReleaseResponse::GenericError(body)) } code => { let mut buf = [0; 100]; @@ -2299,50 +2970,52 @@ impl Api for Client { Box::new(futures::done(result)) } - fn lookup_release(&self, param_doi: String, context: &Context) -> Box + Send> { - // Query parameters - let query_doi = format!("doi={doi}&", doi = param_doi.to_string()); + fn update_work(&self, param_id: String, param_entity: models::WorkEntity, context: &Context) -> Box + Send> { + let url = format!("{}/v0/work/{id}", self.base_path, id = utf8_percent_encode(¶m_id.to_string(), PATH_SEGMENT_ENCODE_SET)); - let url = format!("{}/v0/release/lookup?{doi}", self.base_path, doi = utf8_percent_encode(&query_doi, QUERY_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::Get, &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_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 { + fn parse_response(mut response: hyper::client::response::Response) -> Result { 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::(&buf)?; + let body = serde_json::from_str::(&buf)?; - Ok(LookupReleaseResponse::FoundEntity(body)) + Ok(UpdateWorkResponse::UpdatedEntity(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::(&buf)?; - Ok(LookupReleaseResponse::BadRequest(body)) + Ok(UpdateWorkResponse::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::(&buf)?; - Ok(LookupReleaseResponse::NotFound(body)) + Ok(UpdateWorkResponse::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::(&buf)?; - Ok(LookupReleaseResponse::GenericError(body)) + Ok(UpdateWorkResponse::GenericError(body)) } code => { let mut buf = [0; 100]; diff --git a/rust/fatcat-api/src/lib.rs b/rust/fatcat-api/src/lib.rs index 81b2fbfa..8ff89b9f 100644 --- a/rust/fatcat-api/src/lib.rs +++ b/rust/fatcat-api/src/lib.rs @@ -40,6 +40,8 @@ pub enum AcceptEditgroupResponse { BadRequest(models::ErrorResponse), /// Not Found NotFound(models::ErrorResponse), + /// Edit Conflict + EditConflict(models::ErrorResponse), /// Generic Error GenericError(models::ErrorResponse), } @@ -174,6 +176,66 @@ pub enum CreateWorkBatchResponse { GenericError(models::ErrorResponse), } +#[derive(Debug, PartialEq)] +pub enum DeleteContainerResponse { + /// Deleted Entity + DeletedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum DeleteCreatorResponse { + /// Deleted Entity + DeletedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum DeleteFileResponse { + /// Deleted Entity + DeletedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum DeleteReleaseResponse { + /// Deleted Entity + DeletedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum DeleteWorkResponse { + /// Deleted Entity + DeletedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + #[derive(Debug, PartialEq)] pub enum GetChangelogResponse { /// Success @@ -436,6 +498,66 @@ pub enum LookupReleaseResponse { GenericError(models::ErrorResponse), } +#[derive(Debug, PartialEq)] +pub enum UpdateContainerResponse { + /// Updated Entity + UpdatedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum UpdateCreatorResponse { + /// Updated Entity + UpdatedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum UpdateFileResponse { + /// Updated Entity + UpdatedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum UpdateReleaseResponse { + /// Updated Entity + UpdatedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + +#[derive(Debug, PartialEq)] +pub enum UpdateWorkResponse { + /// Updated Entity + UpdatedEntity(models::EntityEdit), + /// Bad Request + BadRequest(models::ErrorResponse), + /// Not Found + NotFound(models::ErrorResponse), + /// Generic Error + GenericError(models::ErrorResponse), +} + /// API pub trait Api { fn accept_editgroup(&self, id: String, context: &Context) -> Box + Send>; @@ -462,6 +584,16 @@ pub trait Api { fn create_work_batch(&self, entity_list: &Vec, context: &Context) -> Box + Send>; + fn delete_container(&self, id: String, editgroup: Option, context: &Context) -> Box + Send>; + + fn delete_creator(&self, id: String, editgroup: Option, context: &Context) -> Box + Send>; + + fn delete_file(&self, id: String, editgroup: Option, context: &Context) -> Box + Send>; + + fn delete_release(&self, id: String, editgroup: Option, context: &Context) -> Box + Send>; + + fn delete_work(&self, id: String, editgroup: Option, context: &Context) -> Box + Send>; + fn get_changelog(&self, limit: Option, context: &Context) -> Box + Send>; fn get_changelog_entry(&self, id: i64, context: &Context) -> Box + Send>; @@ -507,6 +639,16 @@ pub trait Api { fn lookup_file(&self, sha1: String, context: &Context) -> Box + Send>; fn lookup_release(&self, doi: String, context: &Context) -> Box + Send>; + + fn update_container(&self, id: String, entity: models::ContainerEntity, context: &Context) -> Box + Send>; + + fn update_creator(&self, id: String, entity: models::CreatorEntity, context: &Context) -> Box + Send>; + + fn update_file(&self, id: String, entity: models::FileEntity, context: &Context) -> Box + Send>; + + fn update_release(&self, id: String, entity: models::ReleaseEntity, context: &Context) -> Box + Send>; + + fn update_work(&self, id: String, entity: models::WorkEntity, context: &Context) -> Box + Send>; } /// API without a `Context` @@ -535,6 +677,16 @@ pub trait ApiNoContext { fn create_work_batch(&self, entity_list: &Vec) -> Box + Send>; + fn delete_container(&self, id: String, editgroup: Option) -> Box + Send>; + + fn delete_creator(&self, id: String, editgroup: Option) -> Box + Send>; + + fn delete_file(&self, id: String, editgroup: Option) -> Box + Send>; + + fn delete_release(&self, id: String, editgroup: Option) -> Box + Send>; + + fn delete_work(&self, id: String, editgroup: Option) -> Box + Send>; + fn get_changelog(&self, limit: Option) -> Box + Send>; fn get_changelog_entry(&self, id: i64) -> Box + Send>; @@ -580,6 +732,16 @@ pub trait ApiNoContext { fn lookup_file(&self, sha1: String) -> Box + Send>; fn lookup_release(&self, doi: String) -> Box + Send>; + + fn update_container(&self, id: String, entity: models::ContainerEntity) -> Box + Send>; + + fn update_creator(&self, id: String, entity: models::CreatorEntity) -> Box + Send>; + + fn update_file(&self, id: String, entity: models::FileEntity) -> Box + Send>; + + fn update_release(&self, id: String, entity: models::ReleaseEntity) -> Box + Send>; + + fn update_work(&self, id: String, entity: models::WorkEntity) -> Box + Send>; } /// Trait to extend an API to make it easy to bind it to a context. @@ -646,6 +808,26 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { self.api().create_work_batch(entity_list, &self.context()) } + fn delete_container(&self, id: String, editgroup: Option) -> Box + Send> { + self.api().delete_container(id, editgroup, &self.context()) + } + + fn delete_creator(&self, id: String, editgroup: Option) -> Box + Send> { + self.api().delete_creator(id, editgroup, &self.context()) + } + + fn delete_file(&self, id: String, editgroup: Option) -> Box + Send> { + self.api().delete_file(id, editgroup, &self.context()) + } + + fn delete_release(&self, id: String, editgroup: Option) -> Box + Send> { + self.api().delete_release(id, editgroup, &self.context()) + } + + fn delete_work(&self, id: String, editgroup: Option) -> Box + Send> { + self.api().delete_work(id, editgroup, &self.context()) + } + fn get_changelog(&self, limit: Option) -> Box + Send> { self.api().get_changelog(limit, &self.context()) } @@ -737,6 +919,26 @@ impl<'a, T: Api> ApiNoContext for ContextWrapper<'a, T> { fn lookup_release(&self, doi: String) -> Box + Send> { self.api().lookup_release(doi, &self.context()) } + + fn update_container(&self, id: String, entity: models::ContainerEntity) -> Box + Send> { + self.api().update_container(id, entity, &self.context()) + } + + fn update_creator(&self, id: String, entity: models::CreatorEntity) -> Box + Send> { + self.api().update_creator(id, entity, &self.context()) + } + + fn update_file(&self, id: String, entity: models::FileEntity) -> Box + Send> { + self.api().update_file(id, entity, &self.context()) + } + + fn update_release(&self, id: String, entity: models::ReleaseEntity) -> Box + Send> { + self.api().update_release(id, entity, &self.context()) + } + + fn update_work(&self, id: String, entity: models::WorkEntity) -> Box + Send> { + self.api().update_work(id, entity, &self.context()) + } } #[cfg(feature = "client")] diff --git a/rust/fatcat-api/src/mimetypes.rs b/rust/fatcat-api/src/mimetypes.rs index 2af30994..2c54a313 100644 --- a/rust/fatcat-api/src/mimetypes.rs +++ b/rust/fatcat-api/src/mimetypes.rs @@ -17,6 +17,10 @@ pub mod responses { pub static ref ACCEPT_EDITGROUP_NOT_FOUND: Mime = mime!(Application / Json); } /// Create Mime objects for the response content types for AcceptEditgroup + lazy_static! { + pub static ref ACCEPT_EDITGROUP_EDIT_CONFLICT: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for AcceptEditgroup lazy_static! { pub static ref ACCEPT_EDITGROUP_GENERIC_ERROR: Mime = mime!(Application / Json); } @@ -192,6 +196,86 @@ pub mod responses { lazy_static! { pub static ref CREATE_WORK_BATCH_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for DeleteContainer + lazy_static! { + pub static ref DELETE_CONTAINER_DELETED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteContainer + lazy_static! { + pub static ref DELETE_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteContainer + lazy_static! { + pub static ref DELETE_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteContainer + lazy_static! { + pub static ref DELETE_CONTAINER_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteCreator + lazy_static! { + pub static ref DELETE_CREATOR_DELETED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteCreator + lazy_static! { + pub static ref DELETE_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteCreator + lazy_static! { + pub static ref DELETE_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteCreator + lazy_static! { + pub static ref DELETE_CREATOR_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFile + lazy_static! { + pub static ref DELETE_FILE_DELETED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFile + lazy_static! { + pub static ref DELETE_FILE_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFile + lazy_static! { + pub static ref DELETE_FILE_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteFile + lazy_static! { + pub static ref DELETE_FILE_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); + } + /// Create Mime objects for the response content types for DeleteRelease + lazy_static! { + pub static ref DELETE_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteRelease + lazy_static! { + pub static ref DELETE_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteRelease + lazy_static! { + pub static ref DELETE_RELEASE_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWork + lazy_static! { + pub static ref DELETE_WORK_DELETED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWork + lazy_static! { + pub static ref DELETE_WORK_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWork + lazy_static! { + pub static ref DELETE_WORK_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for DeleteWork + lazy_static! { + pub static ref DELETE_WORK_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); @@ -532,6 +616,86 @@ pub mod responses { lazy_static! { pub static ref LOOKUP_RELEASE_GENERIC_ERROR: Mime = mime!(Application / Json); } + /// Create Mime objects for the response content types for UpdateContainer + lazy_static! { + pub static ref UPDATE_CONTAINER_UPDATED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateContainer + lazy_static! { + pub static ref UPDATE_CONTAINER_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateContainer + lazy_static! { + pub static ref UPDATE_CONTAINER_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateContainer + lazy_static! { + pub static ref UPDATE_CONTAINER_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateCreator + lazy_static! { + pub static ref UPDATE_CREATOR_UPDATED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateCreator + lazy_static! { + pub static ref UPDATE_CREATOR_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateCreator + lazy_static! { + pub static ref UPDATE_CREATOR_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateCreator + lazy_static! { + pub static ref UPDATE_CREATOR_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateFile + lazy_static! { + pub static ref UPDATE_FILE_UPDATED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateFile + lazy_static! { + pub static ref UPDATE_FILE_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateFile + lazy_static! { + pub static ref UPDATE_FILE_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateFile + lazy_static! { + pub static ref UPDATE_FILE_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateRelease + lazy_static! { + pub static ref UPDATE_RELEASE_UPDATED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateRelease + lazy_static! { + pub static ref UPDATE_RELEASE_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateRelease + lazy_static! { + pub static ref UPDATE_RELEASE_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateRelease + lazy_static! { + pub static ref UPDATE_RELEASE_GENERIC_ERROR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateWork + lazy_static! { + pub static ref UPDATE_WORK_UPDATED_ENTITY: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateWork + lazy_static! { + pub static ref UPDATE_WORK_BAD_REQUEST: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateWork + lazy_static! { + pub static ref UPDATE_WORK_NOT_FOUND: Mime = mime!(Application / Json); + } + /// Create Mime objects for the response content types for UpdateWork + lazy_static! { + pub static ref UPDATE_WORK_GENERIC_ERROR: Mime = mime!(Application / Json); + } } @@ -581,5 +745,25 @@ pub mod requests { lazy_static! { pub static ref CREATE_WORK_BATCH: Mime = mime!(Application / Json); } + /// Create Mime objects for the request content types for UpdateContainer + lazy_static! { + pub static ref UPDATE_CONTAINER: Mime = mime!(Application / Json); + } + /// Create Mime objects for the request content types for UpdateCreator + lazy_static! { + pub static ref UPDATE_CREATOR: Mime = mime!(Application / Json); + } + /// Create Mime objects for the request content types for UpdateFile + lazy_static! { + pub static ref UPDATE_FILE: 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); + } + /// Create Mime objects for the request content types for UpdateWork + lazy_static! { + pub static ref UPDATE_WORK: Mime = mime!(Application / Json); + } } diff --git a/rust/fatcat-api/src/server.rs b/rust/fatcat-api/src/server.rs index 90e0f4e0..8db27496 100644 --- a/rust/fatcat-api/src/server.rs +++ b/rust/fatcat-api/src/server.rs @@ -38,10 +38,11 @@ use swagger::{ApiError, Context, XSpanId}; use models; use { AcceptEditgroupResponse, Api, CreateContainerBatchResponse, CreateContainerResponse, CreateCreatorBatchResponse, CreateCreatorResponse, CreateEditgroupResponse, CreateFileBatchResponse, - CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerHistoryResponse, - GetContainerResponse, GetCreatorHistoryResponse, GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, - GetFileResponse, GetReleaseFilesResponse, GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, - LookupContainerResponse, LookupCreatorResponse, LookupFileResponse, LookupReleaseResponse, + CreateFileResponse, CreateReleaseBatchResponse, CreateReleaseResponse, CreateWorkBatchResponse, CreateWorkResponse, DeleteContainerResponse, DeleteCreatorResponse, DeleteFileResponse, + DeleteReleaseResponse, DeleteWorkResponse, GetChangelogEntryResponse, GetChangelogResponse, GetContainerHistoryResponse, GetContainerResponse, GetCreatorHistoryResponse, + GetCreatorReleasesResponse, GetCreatorResponse, GetEditgroupResponse, GetEditorChangelogResponse, GetEditorResponse, GetFileHistoryResponse, GetFileResponse, GetReleaseFilesResponse, + GetReleaseHistoryResponse, GetReleaseResponse, GetStatsResponse, GetWorkHistoryResponse, GetWorkReleasesResponse, GetWorkResponse, LookupContainerResponse, LookupCreatorResponse, + LookupFileResponse, LookupReleaseResponse, UpdateContainerResponse, UpdateCreatorResponse, UpdateFileResponse, UpdateReleaseResponse, UpdateWorkResponse, }; header! { (Warning, "Warning") => [String] } @@ -150,6 +151,16 @@ where 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"); @@ -1331,8 +1342,8 @@ where ); let api_clone = api.clone(); - router.get( - "/v0/changelog", + router.delete( + "/v0/container/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -1345,27 +1356,61 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); - let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_changelog(param_limit, context).wait() { + match api.delete_container(param_id, param_editgroup, context).wait() { Ok(rsp) => match rsp { - GetChangelogResponse::Success(body) => { + DeleteContainerResponse::DeletedEntity(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())); + response.headers.set(ContentType(mimetypes::responses::DELETE_CONTAINER_DELETED_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetChangelogResponse::GenericError(body) => { + DeleteContainerResponse::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::DELETE_CONTAINER_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + DeleteContainerResponse::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::DELETE_CONTAINER_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + DeleteContainerResponse::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())); + response.headers.set(ContentType(mimetypes::responses::DELETE_CONTAINER_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -1385,12 +1430,12 @@ where Ok(response) }) }, - "GetChangelog", + "DeleteContainer", ); let api_clone = api.clone(); - router.get( - "/v0/changelog/:id", + router.delete( + "/v0/creator/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -1417,33 +1462,47 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - match api.get_changelog_entry(param_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::().unwrap_or_default(); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + + match api.delete_creator(param_id, param_editgroup, context).wait() { Ok(rsp) => match rsp { - GetChangelogEntryResponse::FoundChangelogEntry(body) => { + DeleteCreatorResponse::DeletedEntity(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::DELETE_CREATOR_DELETED_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetChangelogEntryResponse::NotFound(body) => { + DeleteCreatorResponse::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::DELETE_CREATOR_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + DeleteCreatorResponse::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::DELETE_CREATOR_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetChangelogEntryResponse::GenericError(body) => { + DeleteCreatorResponse::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::DELETE_CREATOR_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -1463,12 +1522,12 @@ where Ok(response) }) }, - "GetChangelogEntry", + "DeleteCreator", ); let api_clone = api.clone(); - router.get( - "/v0/container/:id", + router.delete( + "/v0/file/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -1497,45 +1556,45 @@ where // 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::().unwrap_or_default(); - let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_container(param_id, param_expand, context).wait() { + match api.delete_file(param_id, param_editgroup, context).wait() { Ok(rsp) => match rsp { - GetContainerResponse::FoundEntity(body) => { + DeleteFileResponse::DeletedEntity(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_CONTAINER_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_FILE_DELETED_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetContainerResponse::BadRequest(body) => { + DeleteFileResponse::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_CONTAINER_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_FILE_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetContainerResponse::NotFound(body) => { + DeleteFileResponse::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_CONTAINER_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_FILE_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetContainerResponse::GenericError(body) => { + DeleteFileResponse::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_CONTAINER_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_FILE_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -1555,12 +1614,12 @@ where Ok(response) }) }, - "GetContainer", + "DeleteFile", ); let api_clone = api.clone(); - router.get( - "/v0/container/:id/history", + router.delete( + "/v0/release/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -1589,45 +1648,45 @@ where // 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::().unwrap_or_default(); - let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_container_history(param_id, param_limit, context).wait() { + match api.delete_release(param_id, param_editgroup, context).wait() { Ok(rsp) => match rsp { - GetContainerHistoryResponse::FoundEntityHistory(body) => { + DeleteReleaseResponse::DeletedEntity(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_CONTAINER_HISTORY_FOUND_ENTITY_HISTORY.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_RELEASE_DELETED_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetContainerHistoryResponse::BadRequest(body) => { + DeleteReleaseResponse::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_CONTAINER_HISTORY_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_RELEASE_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetContainerHistoryResponse::NotFound(body) => { + DeleteReleaseResponse::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_CONTAINER_HISTORY_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_RELEASE_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetContainerHistoryResponse::GenericError(body) => { + DeleteReleaseResponse::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_CONTAINER_HISTORY_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_RELEASE_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -1647,12 +1706,12 @@ where Ok(response) }) }, - "GetContainerHistory", + "DeleteRelease", ); let api_clone = api.clone(); - router.get( - "/v0/creator/:id", + router.delete( + "/v0/work/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -1681,45 +1740,45 @@ where // 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::().unwrap_or_default(); - let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_editgroup = query_params.get("editgroup").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_creator(param_id, param_expand, context).wait() { + match api.delete_work(param_id, param_editgroup, context).wait() { Ok(rsp) => match rsp { - GetCreatorResponse::FoundEntity(body) => { + DeleteWorkResponse::DeletedEntity(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_WORK_DELETED_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetCreatorResponse::BadRequest(body) => { + DeleteWorkResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_WORK_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetCreatorResponse::NotFound(body) => { + DeleteWorkResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_WORK_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetCreatorResponse::GenericError(body) => { + DeleteWorkResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::DELETE_WORK_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -1739,12 +1798,12 @@ where Ok(response) }) }, - "GetCreator", + "DeleteWork", ); let api_clone = api.clone(); router.get( - "/v0/creator/:id/history", + "/v0/changelog", move |req: &mut Request| { let mut context = Context::default(); @@ -1757,61 +1816,27 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); - // Path parameters - let param_id = { - let param = req.extensions - .get::() - .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? - .find("id") - .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; - percent_decode(param.as_bytes()) - .decode_utf8() - .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? - .parse() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? - }; - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_creator_history(param_id, param_limit, context).wait() { + match api.get_changelog(param_limit, context).wait() { Ok(rsp) => match rsp { - GetCreatorHistoryResponse::FoundEntityHistory(body) => { + 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_CREATOR_HISTORY_FOUND_ENTITY_HISTORY.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetCreatorHistoryResponse::BadRequest(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_BAD_REQUEST.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetCreatorHistoryResponse::NotFound(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_NOT_FOUND.clone())); + 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) } - GetCreatorHistoryResponse::GenericError(body) => { + 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_CREATOR_HISTORY_GENERIC_ERROR.clone())); + 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()))); @@ -1831,12 +1856,12 @@ where Ok(response) }) }, - "GetCreatorHistory", + "GetChangelog", ); let api_clone = api.clone(); router.get( - "/v0/creator/:id/releases", + "/v0/changelog/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -1863,43 +1888,33 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - match api.get_creator_releases(param_id, context).wait() { + match api.get_changelog_entry(param_id, context).wait() { Ok(rsp) => match rsp { - GetCreatorReleasesResponse::FoundEntity(body) => { + 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_CREATOR_RELEASES_FOUND_ENTITY.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetCreatorReleasesResponse::BadRequest(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_RELEASES_BAD_REQUEST.clone())); + 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) } - GetCreatorReleasesResponse::NotFound(body) => { + 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_CREATOR_RELEASES_NOT_FOUND.clone())); + 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) } - GetCreatorReleasesResponse::GenericError(body) => { + 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_CREATOR_RELEASES_GENERIC_ERROR.clone())); + 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()))); @@ -1919,12 +1934,12 @@ where Ok(response) }) }, - "GetCreatorReleases", + "GetChangelogEntry", ); let api_clone = api.clone(); router.get( - "/v0/editgroup/:id", + "/v0/container/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -1951,43 +1966,47 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - match api.get_editgroup(param_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::().unwrap_or_default(); + let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + + match api.get_container(param_id, param_expand, context).wait() { Ok(rsp) => match rsp { - GetEditgroupResponse::FoundEntity(body) => { + GetContainerResponse::FoundEntity(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_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_FOUND_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupResponse::BadRequest(body) => { + GetContainerResponse::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_CONTAINER_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupResponse::NotFound(body) => { + GetContainerResponse::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_CONTAINER_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditgroupResponse::GenericError(body) => { + GetContainerResponse::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_CONTAINER_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2007,12 +2026,12 @@ where Ok(response) }) }, - "GetEditgroup", + "GetContainer", ); let api_clone = api.clone(); router.get( - "/v0/editor/:id", + "/v0/container/:id/history", move |req: &mut Request| { let mut context = Context::default(); @@ -2039,33 +2058,47 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - match api.get_editor(param_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::().unwrap_or_default(); + let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + + match api.get_container_history(param_id, param_limit, context).wait() { Ok(rsp) => match rsp { - GetEditorResponse::FoundEditor(body) => { + GetContainerHistoryResponse::FoundEntityHistory(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_FOUND_EDITOR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_HISTORY_FOUND_ENTITY_HISTORY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditorResponse::NotFound(body) => { + GetContainerHistoryResponse::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_CONTAINER_HISTORY_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetContainerHistoryResponse::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())); + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_HISTORY_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditorResponse::GenericError(body) => { + GetContainerHistoryResponse::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())); + response.headers.set(ContentType(mimetypes::responses::GET_CONTAINER_HISTORY_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2085,12 +2118,12 @@ where Ok(response) }) }, - "GetEditor", + "GetContainerHistory", ); let api_clone = api.clone(); router.get( - "/v0/editor/:id/changelog", + "/v0/creator/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -2117,33 +2150,47 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - match api.get_editor_changelog(param_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::().unwrap_or_default(); + let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + + match api.get_creator(param_id, param_expand, context).wait() { Ok(rsp) => match rsp { - GetEditorChangelogResponse::FoundMergedChanges(body) => { + GetCreatorResponse::FoundEntity(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_CHANGELOG_FOUND_MERGED_CHANGES.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_FOUND_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditorChangelogResponse::NotFound(body) => { + GetCreatorResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetCreatorResponse::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_CHANGELOG_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetEditorChangelogResponse::GenericError(body) => { + GetCreatorResponse::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_CHANGELOG_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2163,12 +2210,12 @@ where Ok(response) }) }, - "GetEditorChangelog", + "GetCreator", ); let api_clone = api.clone(); router.get( - "/v0/file/:id", + "/v0/creator/:id/history", move |req: &mut Request| { let mut context = Context::default(); @@ -2197,45 +2244,45 @@ where // 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::().unwrap_or_default(); - let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_file(param_id, param_expand, context).wait() { + match api.get_creator_history(param_id, param_limit, context).wait() { Ok(rsp) => match rsp { - GetFileResponse::FoundEntity(body) => { + GetCreatorHistoryResponse::FoundEntityHistory(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_FOUND_ENTITY_HISTORY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetFileResponse::BadRequest(body) => { + GetCreatorHistoryResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetFileResponse::NotFound(body) => { + GetCreatorHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetFileResponse::GenericError(body) => { + GetCreatorHistoryResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_HISTORY_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2255,12 +2302,12 @@ where Ok(response) }) }, - "GetFile", + "GetCreatorHistory", ); let api_clone = api.clone(); router.get( - "/v0/file/:id/history", + "/v0/creator/:id/releases", move |req: &mut Request| { let mut context = Context::default(); @@ -2287,47 +2334,43 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) - let query_params = req.get::().unwrap_or_default(); - let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - - match api.get_file_history(param_id, param_limit, context).wait() { + match api.get_creator_releases(param_id, context).wait() { Ok(rsp) => match rsp { - GetFileHistoryResponse::FoundEntityHistory(body) => { + GetCreatorReleasesResponse::FoundEntity(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_FOUND_ENTITY_HISTORY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_RELEASES_FOUND_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetFileHistoryResponse::BadRequest(body) => { + GetCreatorReleasesResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_RELEASES_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetFileHistoryResponse::NotFound(body) => { + GetCreatorReleasesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_RELEASES_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetFileHistoryResponse::GenericError(body) => { + GetCreatorReleasesResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_CREATOR_RELEASES_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2347,12 +2390,12 @@ where Ok(response) }) }, - "GetFileHistory", + "GetCreatorReleases", ); let api_clone = api.clone(); router.get( - "/v0/release/:id", + "/v0/editgroup/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -2379,47 +2422,43 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) - let query_params = req.get::().unwrap_or_default(); - let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - - match api.get_release(param_id, param_expand, context).wait() { + match api.get_editgroup(param_id, context).wait() { Ok(rsp) => match rsp { - GetReleaseResponse::FoundEntity(body) => { + GetEditgroupResponse::FoundEntity(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITGROUP_FOUND_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetReleaseResponse::BadRequest(body) => { + 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(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_BAD_REQUEST.clone())); + 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()))); Ok(response) } - GetReleaseResponse::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::GET_RELEASE_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()))); Ok(response) } - GetReleaseResponse::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::GET_RELEASE_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()))); @@ -2439,12 +2478,12 @@ where Ok(response) }) }, - "GetRelease", + "GetEditgroup", ); let api_clone = api.clone(); router.get( - "/v0/release/:id/files", + "/v0/editor/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -2471,43 +2510,33 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - match api.get_release_files(param_id, context).wait() { + match api.get_editor(param_id, context).wait() { Ok(rsp) => match rsp { - GetReleaseFilesResponse::FoundEntity(body) => { + GetEditorResponse::FoundEditor(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_FOUND_ENTITY.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetReleaseFilesResponse::BadRequest(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_FOUND_EDITOR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetReleaseFilesResponse::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_RELEASE_FILES_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) } - GetReleaseFilesResponse::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_RELEASE_FILES_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()))); @@ -2527,12 +2556,12 @@ where Ok(response) }) }, - "GetReleaseFiles", + "GetEditor", ); let api_clone = api.clone(); router.get( - "/v0/release/:id/history", + "/v0/editor/:id/changelog", move |req: &mut Request| { let mut context = Context::default(); @@ -2559,47 +2588,33 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) - let query_params = req.get::().unwrap_or_default(); - let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - - match api.get_release_history(param_id, param_limit, context).wait() { + match api.get_editor_changelog(param_id, context).wait() { Ok(rsp) => match rsp { - GetReleaseHistoryResponse::FoundEntityHistory(body) => { + GetEditorChangelogResponse::FoundMergedChanges(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_FOUND_ENTITY_HISTORY.clone())); - - context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); - - Ok(response) - } - GetReleaseHistoryResponse::BadRequest(body) => { - let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); - - let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_CHANGELOG_FOUND_MERGED_CHANGES.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetReleaseHistoryResponse::NotFound(body) => { + GetEditorChangelogResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_CHANGELOG_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetReleaseHistoryResponse::GenericError(body) => { + GetEditorChangelogResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_EDITOR_CHANGELOG_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2619,12 +2634,12 @@ where Ok(response) }) }, - "GetReleaseHistory", + "GetEditorChangelog", ); let api_clone = api.clone(); router.get( - "/v0/stats", + "/v0/file/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -2637,27 +2652,61 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); - let param_more = query_params.get("more").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_stats(param_more, context).wait() { + match api.get_file(param_id, param_expand, context).wait() { Ok(rsp) => match rsp { - GetStatsResponse::Success(body) => { + GetFileResponse::FoundEntity(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_STATS_SUCCESS.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_FOUND_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetStatsResponse::GenericError(body) => { + GetFileResponse::BadRequest(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(400), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetFileResponse::NotFound(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(404), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetFileResponse::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_STATS_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2677,12 +2726,12 @@ where Ok(response) }) }, - "GetStats", + "GetFile", ); let api_clone = api.clone(); router.get( - "/v0/work/:id", + "/v0/file/:id/history", move |req: &mut Request| { let mut context = Context::default(); @@ -2711,45 +2760,45 @@ where // 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::().unwrap_or_default(); - let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_work(param_id, param_expand, context).wait() { + match api.get_file_history(param_id, param_limit, context).wait() { Ok(rsp) => match rsp { - GetWorkResponse::FoundEntity(body) => { + GetFileHistoryResponse::FoundEntityHistory(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_FOUND_ENTITY_HISTORY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkResponse::BadRequest(body) => { + GetFileHistoryResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkResponse::NotFound(body) => { + GetFileHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkResponse::GenericError(body) => { + GetFileHistoryResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_FILE_HISTORY_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2769,12 +2818,12 @@ where Ok(response) }) }, - "GetWork", + "GetFileHistory", ); let api_clone = api.clone(); router.get( - "/v0/work/:id/history", + "/v0/release/:id", move |req: &mut Request| { let mut context = Context::default(); @@ -2803,45 +2852,45 @@ where // 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::().unwrap_or_default(); - let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.get_work_history(param_id, param_limit, context).wait() { + match api.get_release(param_id, param_expand, context).wait() { Ok(rsp) => match rsp { - GetWorkHistoryResponse::FoundEntityHistory(body) => { + GetReleaseResponse::FoundEntity(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_FOUND_ENTITY_HISTORY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FOUND_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkHistoryResponse::BadRequest(body) => { + GetReleaseResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkHistoryResponse::NotFound(body) => { + GetReleaseResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkHistoryResponse::GenericError(body) => { + GetReleaseResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2861,12 +2910,12 @@ where Ok(response) }) }, - "GetWorkHistory", + "GetRelease", ); let api_clone = api.clone(); router.get( - "/v0/work/:id/releases", + "/v0/release/:id/files", move |req: &mut Request| { let mut context = Context::default(); @@ -2893,43 +2942,43 @@ where .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? }; - match api.get_work_releases(param_id, context).wait() { + match api.get_release_files(param_id, context).wait() { Ok(rsp) => match rsp { - GetWorkReleasesResponse::FoundEntity(body) => { + GetReleaseFilesResponse::FoundEntity(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_FOUND_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkReleasesResponse::BadRequest(body) => { + GetReleaseFilesResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkReleasesResponse::NotFound(body) => { + GetReleaseFilesResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - GetWorkReleasesResponse::GenericError(body) => { + GetReleaseFilesResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_FILES_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -2949,12 +2998,12 @@ where Ok(response) }) }, - "GetWorkReleases", + "GetReleaseFiles", ); let api_clone = api.clone(); router.get( - "/v0/container/lookup", + "/v0/release/:id/history", move |req: &mut Request| { let mut context = Context::default(); @@ -2967,53 +3016,61 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); - let param_issnl = query_params - .get("issnl") - .ok_or_else(|| Response::with((status::BadRequest, "Missing required query parameter issnl".to_string())))? - .first() - .ok_or_else(|| Response::with((status::BadRequest, "Required query parameter issnl was empty".to_string())))? - .parse::() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse query parameter issnl - doesn't match schema: {}", e))))?; + let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.lookup_container(param_issnl, context).wait() { + match api.get_release_history(param_id, param_limit, context).wait() { Ok(rsp) => match rsp { - LookupContainerResponse::FoundEntity(body) => { + GetReleaseHistoryResponse::FoundEntityHistory(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::LOOKUP_CONTAINER_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_FOUND_ENTITY_HISTORY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupContainerResponse::BadRequest(body) => { + GetReleaseHistoryResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::LOOKUP_CONTAINER_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupContainerResponse::NotFound(body) => { + GetReleaseHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::LOOKUP_CONTAINER_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupContainerResponse::GenericError(body) => { + GetReleaseHistoryResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::LOOKUP_CONTAINER_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_RELEASE_HISTORY_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -3033,12 +3090,12 @@ where Ok(response) }) }, - "LookupContainer", + "GetReleaseHistory", ); let api_clone = api.clone(); router.get( - "/v0/creator/lookup", + "/v0/stats", move |req: &mut Request| { let mut context = Context::default(); @@ -3053,51 +3110,117 @@ where // 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::().unwrap_or_default(); - let param_orcid = query_params - .get("orcid") - .ok_or_else(|| Response::with((status::BadRequest, "Missing required query parameter orcid".to_string())))? - .first() - .ok_or_else(|| Response::with((status::BadRequest, "Required query parameter orcid was empty".to_string())))? - .parse::() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse query parameter orcid - doesn't match schema: {}", e))))?; + let param_more = query_params.get("more").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.lookup_creator(param_orcid, context).wait() { + match api.get_stats(param_more, context).wait() { Ok(rsp) => match rsp { - LookupCreatorResponse::FoundEntity(body) => { + GetStatsResponse::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::LOOKUP_CREATOR_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_STATS_SUCCESS.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupCreatorResponse::BadRequest(body) => { + GetStatsResponse::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_STATS_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) + }) + }, + "GetStats", + ); + + let api_clone = api.clone(); + router.get( + "/v0/work/: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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = req.get::().unwrap_or_default(); + let param_expand = query_params.get("expand").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); + + match api.get_work(param_id, param_expand, context).wait() { + Ok(rsp) => match rsp { + GetWorkResponse::FoundEntity(body) => { + let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); + + let mut response = Response::with((status::Status::from_u16(200), body_string)); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_FOUND_ENTITY.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + GetWorkResponse::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::LOOKUP_CREATOR_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupCreatorResponse::NotFound(body) => { + GetWorkResponse::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::LOOKUP_CREATOR_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupCreatorResponse::GenericError(body) => { + GetWorkResponse::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::LOOKUP_CREATOR_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -3117,12 +3240,12 @@ where Ok(response) }) }, - "LookupCreator", + "GetWork", ); let api_clone = api.clone(); router.get( - "/v0/file/lookup", + "/v0/work/:id/history", move |req: &mut Request| { let mut context = Context::default(); @@ -3135,53 +3258,61 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) let query_params = req.get::().unwrap_or_default(); - let param_sha1 = query_params - .get("sha1") - .ok_or_else(|| Response::with((status::BadRequest, "Missing required query parameter sha1".to_string())))? - .first() - .ok_or_else(|| Response::with((status::BadRequest, "Required query parameter sha1 was empty".to_string())))? - .parse::() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse query parameter sha1 - doesn't match schema: {}", e))))?; + let param_limit = query_params.get("limit").and_then(|list| list.first()).and_then(|x| x.parse::().ok()); - match api.lookup_file(param_sha1, context).wait() { + match api.get_work_history(param_id, param_limit, context).wait() { Ok(rsp) => match rsp { - LookupFileResponse::FoundEntity(body) => { + GetWorkHistoryResponse::FoundEntityHistory(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(200), body_string)); - response.headers.set(ContentType(mimetypes::responses::LOOKUP_FILE_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_FOUND_ENTITY_HISTORY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupFileResponse::BadRequest(body) => { + GetWorkHistoryResponse::BadRequest(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(400), body_string)); - response.headers.set(ContentType(mimetypes::responses::LOOKUP_FILE_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupFileResponse::NotFound(body) => { + GetWorkHistoryResponse::NotFound(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(404), body_string)); - response.headers.set(ContentType(mimetypes::responses::LOOKUP_FILE_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupFileResponse::GenericError(body) => { + GetWorkHistoryResponse::GenericError(body) => { let body_string = serde_json::to_string(&body).expect("impossible to fail to serialize"); let mut response = Response::with((status::Status::from_u16(500), body_string)); - response.headers.set(ContentType(mimetypes::responses::LOOKUP_FILE_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_HISTORY_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -3201,12 +3332,12 @@ where Ok(response) }) }, - "LookupFile", + "GetWorkHistory", ); let api_clone = api.clone(); router.get( - "/v0/release/lookup", + "/v0/work/:id/releases", move |req: &mut Request| { let mut context = Context::default(); @@ -3219,53 +3350,57 @@ where context.auth_data = req.extensions.remove::(); context.authorization = req.extensions.remove::(); - // 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::().unwrap_or_default(); - let param_doi = query_params - .get("doi") - .ok_or_else(|| Response::with((status::BadRequest, "Missing required query parameter doi".to_string())))? - .first() - .ok_or_else(|| Response::with((status::BadRequest, "Required query parameter doi was empty".to_string())))? - .parse::() - .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse query parameter doi - doesn't match schema: {}", e))))?; + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; - match api.lookup_release(param_doi, context).wait() { + match api.get_work_releases(param_id, context).wait() { Ok(rsp) => match rsp { - LookupReleaseResponse::FoundEntity(body) => { + GetWorkReleasesResponse::FoundEntity(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::LOOKUP_RELEASE_FOUND_ENTITY.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_FOUND_ENTITY.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupReleaseResponse::BadRequest(body) => { + GetWorkReleasesResponse::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::LOOKUP_RELEASE_BAD_REQUEST.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_BAD_REQUEST.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupReleaseResponse::NotFound(body) => { + GetWorkReleasesResponse::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::LOOKUP_RELEASE_NOT_FOUND.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_NOT_FOUND.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); Ok(response) } - LookupReleaseResponse::GenericError(body) => { + GetWorkReleasesResponse::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::LOOKUP_RELEASE_GENERIC_ERROR.clone())); + response.headers.set(ContentType(mimetypes::responses::GET_WORK_RELEASES_GENERIC_ERROR.clone())); context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); @@ -3285,7 +3420,943 @@ where Ok(response) }) }, - "LookupRelease", + "GetWorkReleases", + ); + + let api_clone = api.clone(); + router.get( + "/v0/container/lookup", + 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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // 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::().unwrap_or_default(); + let param_issnl = query_params + .get("issnl") + .ok_or_else(|| Response::with((status::BadRequest, "Missing required query parameter issnl".to_string())))? + .first() + .ok_or_else(|| Response::with((status::BadRequest, "Required query parameter issnl was empty".to_string())))? + .parse::() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse query parameter issnl - doesn't match schema: {}", e))))?; + + match api.lookup_container(param_issnl, context).wait() { + Ok(rsp) => match rsp { + LookupContainerResponse::FoundEntity(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::LOOKUP_CONTAINER_FOUND_ENTITY.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupContainerResponse::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::LOOKUP_CONTAINER_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupContainerResponse::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::LOOKUP_CONTAINER_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupContainerResponse::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::LOOKUP_CONTAINER_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) + }) + }, + "LookupContainer", + ); + + let api_clone = api.clone(); + router.get( + "/v0/creator/lookup", + 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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // 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::().unwrap_or_default(); + let param_orcid = query_params + .get("orcid") + .ok_or_else(|| Response::with((status::BadRequest, "Missing required query parameter orcid".to_string())))? + .first() + .ok_or_else(|| Response::with((status::BadRequest, "Required query parameter orcid was empty".to_string())))? + .parse::() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse query parameter orcid - doesn't match schema: {}", e))))?; + + match api.lookup_creator(param_orcid, context).wait() { + Ok(rsp) => match rsp { + LookupCreatorResponse::FoundEntity(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::LOOKUP_CREATOR_FOUND_ENTITY.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupCreatorResponse::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::LOOKUP_CREATOR_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupCreatorResponse::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::LOOKUP_CREATOR_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupCreatorResponse::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::LOOKUP_CREATOR_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) + }) + }, + "LookupCreator", + ); + + let api_clone = api.clone(); + router.get( + "/v0/file/lookup", + 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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // 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::().unwrap_or_default(); + let param_sha1 = query_params + .get("sha1") + .ok_or_else(|| Response::with((status::BadRequest, "Missing required query parameter sha1".to_string())))? + .first() + .ok_or_else(|| Response::with((status::BadRequest, "Required query parameter sha1 was empty".to_string())))? + .parse::() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse query parameter sha1 - doesn't match schema: {}", e))))?; + + match api.lookup_file(param_sha1, context).wait() { + Ok(rsp) => match rsp { + LookupFileResponse::FoundEntity(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::LOOKUP_FILE_FOUND_ENTITY.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupFileResponse::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::LOOKUP_FILE_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupFileResponse::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::LOOKUP_FILE_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupFileResponse::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::LOOKUP_FILE_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) + }) + }, + "LookupFile", + ); + + let api_clone = api.clone(); + router.get( + "/v0/release/lookup", + 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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // 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::().unwrap_or_default(); + let param_doi = query_params + .get("doi") + .ok_or_else(|| Response::with((status::BadRequest, "Missing required query parameter doi".to_string())))? + .first() + .ok_or_else(|| Response::with((status::BadRequest, "Required query parameter doi was empty".to_string())))? + .parse::() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse query parameter doi - doesn't match schema: {}", e))))?; + + match api.lookup_release(param_doi, context).wait() { + Ok(rsp) => match rsp { + LookupReleaseResponse::FoundEntity(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::LOOKUP_RELEASE_FOUND_ENTITY.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupReleaseResponse::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::LOOKUP_RELEASE_BAD_REQUEST.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupReleaseResponse::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::LOOKUP_RELEASE_NOT_FOUND.clone())); + + context.x_span_id.as_ref().map(|header| response.headers.set(XSpanId(header.clone()))); + + Ok(response) + } + LookupReleaseResponse::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::LOOKUP_RELEASE_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) + }) + }, + "LookupRelease", + ); + + let api_clone = api.clone(); + router.put( + "/v0/container/: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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + + // 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::() + .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 = + 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.update_container(param_id, param_entity, context).wait() { + Ok(rsp) => match rsp { + UpdateContainerResponse::UpdatedEntity(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_CONTAINER_UPDATED_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) + } + UpdateContainerResponse::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_CONTAINER_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) + } + UpdateContainerResponse::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_CONTAINER_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) + } + UpdateContainerResponse::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_CONTAINER_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) + }) + }, + "UpdateContainer", + ); + + let api_clone = api.clone(); + router.put( + "/v0/creator/: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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + + // 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::() + .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 = + 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.update_creator(param_id, param_entity, context).wait() { + Ok(rsp) => match rsp { + UpdateCreatorResponse::UpdatedEntity(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_CREATOR_UPDATED_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) + } + UpdateCreatorResponse::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_CREATOR_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) + } + UpdateCreatorResponse::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_CREATOR_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) + } + UpdateCreatorResponse::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_CREATOR_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) + }) + }, + "UpdateCreator", + ); + + let api_clone = api.clone(); + router.put( + "/v0/file/: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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + + // 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::() + .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 = + 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.update_file(param_id, param_entity, context).wait() { + Ok(rsp) => match rsp { + UpdateFileResponse::UpdatedEntity(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_FILE_UPDATED_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) + } + UpdateFileResponse::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_FILE_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) + } + UpdateFileResponse::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_FILE_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) + } + UpdateFileResponse::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_FILE_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) + }) + }, + "UpdateFile", + ); + + let api_clone = api.clone(); + router.put( + "/v0/release/: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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + + // 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::() + .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 = + 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.update_release(param_id, param_entity, context).wait() { + Ok(rsp) => match rsp { + UpdateReleaseResponse::UpdatedEntity(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_RELEASE_UPDATED_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) + } + UpdateReleaseResponse::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_RELEASE_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) + } + UpdateReleaseResponse::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_RELEASE_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) + } + UpdateReleaseResponse::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_RELEASE_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) + }) + }, + "UpdateRelease", + ); + + let api_clone = api.clone(); + router.put( + "/v0/work/: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(req: &mut Request, api: &T, context: &mut Context) -> Result + where + T: Api, + { + context.x_span_id = Some(req.headers.get::().map(XSpanId::to_string).unwrap_or_else(|| self::uuid::Uuid::new_v4().to_string())); + context.auth_data = req.extensions.remove::(); + context.authorization = req.extensions.remove::(); + + // Path parameters + let param_id = { + let param = req.extensions + .get::() + .ok_or_else(|| Response::with((status::InternalServerError, "An internal error occurred".to_string())))? + .find("id") + .ok_or_else(|| Response::with((status::BadRequest, "Missing path parameter id".to_string())))?; + percent_decode(param.as_bytes()) + .decode_utf8() + .map_err(|_| Response::with((status::BadRequest, format!("Couldn't percent-decode path parameter as UTF-8: {}", param))))? + .parse() + .map_err(|e| Response::with((status::BadRequest, format!("Couldn't parse path parameter id: {}", e))))? + }; + + // 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::() + .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 = + 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.update_work(param_id, param_entity, context).wait() { + Ok(rsp) => match rsp { + UpdateWorkResponse::UpdatedEntity(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_WORK_UPDATED_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) + } + UpdateWorkResponse::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_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) + } + UpdateWorkResponse::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_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) + } + UpdateWorkResponse::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_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) + }) + }, + "UpdateWork", ); } -- cgit v1.2.3 From 0f229e57965901a1230dd346fb676e8caf67ec2e Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 6 Sep 2018 15:02:57 -0700 Subject: skeleton create/delete endpoints for works Other entities just stubs --- rust/src/api_server.rs | 122 ++++++++++++++++++++++++++++++++++++++++++ rust/src/api_wrappers.rs | 108 ++++++++++++++++++++++++++++++++++++- rust/tests/test_api_server.rs | 65 ++++++++++++++++++++++ 3 files changed, 293 insertions(+), 2 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 7bf3122b..66c31f61 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -535,6 +535,19 @@ impl Server { edit.into_model() } + // XXX: + pub fn update_container_handler( + &self, + id: &Uuid, + entity: models::ContainerEntity, + conn: &DbConn, + ) -> Result { + unimplemented!() + } + pub fn delete_container_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + unimplemented!() + } + pub fn create_creator_handler( &self, entity: models::CreatorEntity, @@ -574,6 +587,19 @@ impl Server { edit.into_model() } + // XXX: + pub fn update_creator_handler( + &self, + id: &Uuid, + entity: models::CreatorEntity, + conn: &DbConn, + ) -> Result { + unimplemented!() + } + pub fn delete_creator_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + unimplemented!() + } + pub fn create_file_handler( &self, entity: models::FileEntity, @@ -654,6 +680,19 @@ impl Server { edit.into_model() } + // XXX: + pub fn update_file_handler( + &self, + id: &Uuid, + entity: models::FileEntity, + conn: &DbConn, + ) -> Result { + unimplemented!() + } + pub fn delete_file_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + unimplemented!() + } + pub fn create_release_handler( &self, entity: models::ReleaseEntity, @@ -829,6 +868,19 @@ impl Server { edit.into_model() } + // XXX: + pub fn update_release_handler( + &self, + id: &Uuid, + entity: models::ReleaseEntity, + conn: &DbConn, + ) -> Result { + unimplemented!() + } + pub fn delete_release_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + unimplemented!() + } + pub fn create_work_handler( &self, entity: models::WorkEntity, @@ -858,6 +910,76 @@ impl Server { edit.into_model() } + pub fn update_work_handler( + &self, + id: &Uuid, + entity: models::WorkEntity, + conn: &DbConn, + ) -> Result { + let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth + let editgroup_id = match entity.editgroup_id { + None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), + Some(param) => fcid2uuid(¶m)?, + }; + + // TODO: refactor this into a check on WorkIdentRow + let current: WorkIdentRow = work_ident::table.find(id).first(conn)?; + if current.is_live != true { + // TODO: what if isn't live? 4xx not 5xx + bail!("can't delete an entity that doesn't exist yet"); + } + if current.rev_id.is_none() { + // TODO: what if it's already deleted? 4xx not 5xx + bail!("entity was already deleted"); + } + + let edit: WorkEditRow = + diesel::sql_query( + "WITH rev AS ( INSERT INTO work_rev (extra_json) + VALUES ($1) + RETURNING id ), + INSERT INTO work_edit (editgroup_id, ident_id, rev_id, prev_rev) VALUES + ($2, $3, (SELECT rev.id FROM rev), $4) + RETURNING *", + ).bind::, _>(entity.extra) + .bind::(editgroup_id) + .bind::(id) + .bind::(current.rev_id.unwrap()) + .get_result(conn)?; + + edit.into_model() + } + + pub fn delete_work_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth + let editgroup_id = match editgroup_id { + Some(egid) => egid, + None => get_or_create_editgroup(editor_id, conn)? + }; + + let current: WorkIdentRow = work_ident::table.find(id).first(conn)?; + if current.is_live != true { + // TODO: what if isn't live? 4xx not 5xx + bail!("can't delete an entity that doesn't exist yet"); + } + if current.rev_id.is_none() { + // TODO: what if it's already deleted? 4xx not 5xx + bail!("entity was already deleted"); + } + let edit: WorkEditRow = insert_into(work_edit::table) + .values(( + work_edit::editgroup_id.eq(editgroup_id), + work_edit::ident_id.eq(id), + work_edit::rev_id.eq(None::), + work_edit::redirect_id.eq(None::), + work_edit::prev_rev.eq(current.rev_id), + //work_edit::extra_json.eq(extra), + )) + .get_result(conn)?; + + edit.into_model() + } + pub fn accept_editgroup_handler(&self, id: &str, conn: &DbConn) -> Result<()> { accept_editgroup(fcid2uuid(id)?, conn)?; Ok(()) diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 403c7caf..de1fc9da 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -19,8 +19,9 @@ macro_rules! wrap_entity_handlers { // The only stable approach I know of would be: https://github.com/dtolnay/mashup ($get_fn:ident, $get_handler:ident, $get_resp:ident, $post_fn:ident, $post_handler:ident, $post_resp:ident, $post_batch_fn:ident, $post_batch_handler:ident, - $post_batch_resp:ident, $get_history_fn:ident, $get_history_handler:ident, - $get_history_resp:ident, $model:ident) => { + $post_batch_resp:ident, $update_fn:ident, $update_handler:ident, $update_resp:ident, + $delete_fn:ident, $delete_handler:ident, $delete_resp:ident, $get_history_fn:ident, + $get_history_handler:ident, $get_history_resp:ident, $model:ident) => { fn $get_fn( &self, @@ -106,6 +107,79 @@ macro_rules! wrap_entity_handlers { Box::new(futures::done(Ok(ret))) } + fn $update_fn( + &self, + id: String, + entity: models::$model, + _context: &Context, + ) -> Box + Send> { + let id = if let Ok(parsed) = fcid2uuid(&id) { parsed } else { + return Box::new(futures::done(Ok($update_resp::BadRequest(ErrorResponse { + message: ErrorKind::InvalidFatcatId(id).to_string() })))); + }; + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| self.$update_handler(&id, entity, &conn)) { + Ok(edit) => + $update_resp::UpdatedEntity(edit), + Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => + $update_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }), + Err(Error(ErrorKind::Diesel(e), _)) => + $update_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::Uuid(e), _)) => + $update_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InvalidFatcatId(e), _)) => + $update_resp::BadRequest(ErrorResponse { + message: ErrorKind::InvalidFatcatId(e).to_string() }), + Err(Error(ErrorKind::MalformedExternalId(e), _)) => + $update_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(e) => { + error!("{}", e); + $update_resp::GenericError(ErrorResponse { message: e.to_string() }) + }, + }; + Box::new(futures::done(Ok(ret))) + } + + fn $delete_fn( + &self, + id: String, + editgroup_id: Option, + _context: &Context, + ) -> Box + Send> { + let id = if let Ok(parsed) = fcid2uuid(&id) { parsed } else { + return Box::new(futures::done(Ok($delete_resp::BadRequest(ErrorResponse { + message: ErrorKind::InvalidFatcatId(id).to_string() })))); + }; + let editgroup_id = match editgroup_id { + Some(raw) => if let Ok(parsed) = fcid2uuid(&raw) { Some(parsed) } else { + return Box::new(futures::done(Ok($delete_resp::BadRequest(ErrorResponse { + message: ErrorKind::InvalidFatcatId(raw).to_string() })))) + } + None => None + }; + let conn = self.db_pool.get().expect("db_pool error"); + let ret = match conn.transaction(|| self.$delete_handler(&id, editgroup_id, &conn)) { + Ok(edit) => + $delete_resp::DeletedEntity(edit), + Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => + $delete_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }), + Err(Error(ErrorKind::Diesel(e), _)) => + $delete_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::Uuid(e), _)) => + $delete_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(Error(ErrorKind::InvalidFatcatId(e), _)) => + $delete_resp::BadRequest(ErrorResponse { + message: ErrorKind::InvalidFatcatId(e).to_string() }), + Err(Error(ErrorKind::MalformedExternalId(e), _)) => + $delete_resp::BadRequest(ErrorResponse { message: e.to_string() }), + Err(e) => { + error!("{}", e); + $delete_resp::GenericError(ErrorResponse { message: e.to_string() }) + }, + }; + Box::new(futures::done(Ok(ret))) + } + fn $get_history_fn( &self, id: String, @@ -175,6 +249,12 @@ impl Api for Server { create_container_batch, create_container_batch_handler, CreateContainerBatchResponse, + update_container, + update_container_handler, + UpdateContainerResponse, + delete_container, + delete_container_handler, + DeleteContainerResponse, get_container_history, get_container_history_handler, GetContainerHistoryResponse, @@ -191,6 +271,12 @@ impl Api for Server { create_creator_batch, create_creator_batch_handler, CreateCreatorBatchResponse, + update_creator, + update_creator_handler, + UpdateCreatorResponse, + delete_creator, + delete_creator_handler, + DeleteCreatorResponse, get_creator_history, get_creator_history_handler, GetCreatorHistoryResponse, @@ -206,6 +292,12 @@ impl Api for Server { create_file_batch, create_file_batch_handler, CreateFileBatchResponse, + update_file, + update_file_handler, + UpdateFileResponse, + delete_file, + delete_file_handler, + DeleteFileResponse, get_file_history, get_file_history_handler, GetFileHistoryResponse, @@ -221,6 +313,12 @@ impl Api for Server { create_release_batch, create_release_batch_handler, CreateReleaseBatchResponse, + update_release, + update_release_handler, + UpdateReleaseResponse, + delete_release, + delete_release_handler, + DeleteReleaseResponse, get_release_history, get_release_history_handler, GetReleaseHistoryResponse, @@ -236,6 +334,12 @@ impl Api for Server { create_work_batch, create_work_batch_handler, CreateWorkBatchResponse, + update_work, + update_work_handler, + UpdateWorkResponse, + delete_work, + delete_work_handler, + DeleteWorkResponse, get_work_history, get_work_history_handler, GetWorkHistoryResponse, diff --git a/rust/tests/test_api_server.rs b/rust/tests/test_api_server.rs index 02c77413..4b181188 100644 --- a/rust/tests/test_api_server.rs +++ b/rust/tests/test_api_server.rs @@ -468,6 +468,71 @@ fn test_post_work() { ); } +#[test] +fn test_update_work() { + let (headers, router, conn) = setup(); + + check_response( + request::post( + "http://localhost:9411/v0/work", + headers.clone(), + r#"{ + "extra": { "source": "other speculation" } + }"#, + &router, + ), + status::Created, + None, + ); + + let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001").unwrap(); + let editgroup_id = get_or_create_editgroup(editor_id, &conn).unwrap(); + check_response( + request::post( + &format!( + "http://localhost:9411/v0/editgroup/{}/accept", + uuid2fcid(&editgroup_id) + ), + headers.clone(), + "", + &router, + ), + status::Ok, + None, + ); +} + +#[test] +fn test_delete_work() { + let (headers, router, conn) = setup(); + + check_response( + request::delete( + "http://localhost:9411/v0/work/aaaaaaaaaaaaavkvaaaaaaaaai", + headers.clone(), + &router, + ), + status::Ok, + None, + ); + + let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001").unwrap(); + let editgroup_id = get_or_create_editgroup(editor_id, &conn).unwrap(); + check_response( + request::post( + &format!( + "http://localhost:9411/v0/editgroup/{}/accept", + uuid2fcid(&editgroup_id) + ), + headers.clone(), + "", + &router, + ), + status::Ok, + None, + ); +} + #[test] fn test_accept_editgroup() { let (headers, router, conn) = setup(); -- cgit v1.2.3 From 1cf1061e17cb6070e4540c19b787747232eb909c Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 6 Sep 2018 15:09:07 -0700 Subject: update TODO --- rust/TODO | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'rust') diff --git a/rust/TODO b/rust/TODO index a4a6dfad..1ed580e6 100644 --- a/rust/TODO +++ b/rust/TODO @@ -1,4 +1,11 @@ +- refactor rev creation (from an entity) into it's own function, across the board + => attach to database module structs? + => should make cockroachdb compatible (single use of CTE) + => usable from both "update" and "create" +- editgroup param to update + => also for creation? for consistency + - editor_id vs. editor username; return editor_id (in addition to name?) later: -- cgit v1.2.3 From 18eae2395863e32e4b7413010adafe1ffc95076e Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 10:49:15 -0700 Subject: major CRUD refactor This is the start of a large refactor to move all entity CRUD (create, read, update, delete) model/database code into it's own file. HACKING has been updated with an overview of what happens in each file. Next steps: - split rev (and sub-table) insertion in to db_rev_insert and make create/update generic - inserts should be batch (vector) by default - move all other entities into this new trait framework - bypass api_server wrappers and call into CRUD from api_wrappers for entity ops (should be a big cleanup) --- rust/HACKING.md | 34 ++++++ rust/src/api_helpers.rs | 27 +++++ rust/src/api_server.rs | 109 ++++------------- rust/src/database_entity_crud.rs | 250 +++++++++++++++++++++++++++++++++++++++ rust/src/lib.rs | 1 + 5 files changed, 336 insertions(+), 85 deletions(-) create mode 100644 rust/src/database_entity_crud.rs (limited to 'rust') diff --git a/rust/HACKING.md b/rust/HACKING.md index a399164c..622a4b5a 100644 --- a/rust/HACKING.md +++ b/rust/HACKING.md @@ -1,4 +1,38 @@ +## Code Structure + +Almost all of the rust code is either auto-generated or "glue" between the +swagger API spec on one side and the SQL schema on the other. + +- `./migrations/*/up.sql`: SQL schema +- `./src/database_schema.rs`: autogenerated per-table Diesel schemas +- `./src/database_models.rs`: hand- and macro-generated Rust structs matching + Diesel schemas, and a small number of row-level helpers +- `./src/database_entity_crud.rs`: "struct-relational-mapping"; trait + implementations of CRUD (create, read, update, delete) actions for each + entity model, hitting the database (and building on `database_model` structs) +- `./src/api_server.rs`: one function for each API endpoint, with rust-style + arguments and return types. mostly calls in to `database_entity_crud`. +- `./src/api_wrappers.rs`: hand- and macro-generated wrapper functions, one per + API endpoint, that map between API request and return types, and + rust-idiomatic request and return types (plus API models). +- `./fatcat-api`: autogenerated API models and endpoint types/signatures +- `../fatcat-openapi2.yaml`: + +When deciding to use this structure, it wasn't expected that either +`api_wrappers.rs` or `database_models.rs` would need to hand-maintained; both +are verbose and implemented in a very mechanical fashion. The return type +mapping in `api_wrappers` might be necessary, but `database_models.rs` in +particular feels unnecessary; other projects have attempted to completely +automate generation of this file, but it doesn't sound reliable. In particular, +both regular "Row" (queriable) and "NewRow" (insertable) structs need to be +defined. + +## Test Structure + +- `./tests/test_api_server.rs`: Iron (web framework) level raw HTTP JSON + request/response tests of API endpoints. + ## Updating Schemas Regenerate API schemas after editing the fatcat-openapi2 schema. This will, as diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index a68ed8a9..6c9a4e5f 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -6,6 +6,9 @@ use diesel::prelude::*; use errors::*; use regex::Regex; use uuid::Uuid; +use std::str::FromStr; + +pub type DbConn = diesel::r2d2::PooledConnection>; /// This function should always be run within a transaction pub fn get_or_create_editgroup(editor_id: Uuid, conn: &PgConnection) -> Result { @@ -87,6 +90,30 @@ pub fn accept_editgroup(editgroup_id: Uuid, conn: &PgConnection) -> Result String { + uuid2fcid(&self.to_uuid()) + } +} + +impl FromStr for FatCatId { + type Err = Error; + fn from_str(s: &str) -> Result { + fcid2uuid(s).map(|u| FatCatId(u)) + } +} + +impl FatCatId { + pub fn to_uuid(&self) -> Uuid { + self.0 + } + pub fn from_uuid(u: &Uuid) -> FatCatId { + FatCatId(u.clone()) + } +} + /// Convert fatcat IDs (base32 strings) to UUID pub fn fcid2uuid(fcid: &str) -> Result { if fcid.len() != 26 { diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 66c31f61..20f71c7a 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -17,8 +17,8 @@ use fatcat_api::models::*; use sha1::Sha1; use uuid::Uuid; use ConnectionPool; - -type DbConn = diesel::r2d2::PooledConnection>; +use database_entity_crud::{EntityCrud, EditContext}; +use std::str::FromStr; macro_rules! entity_batch_handler { ($post_handler:ident, $post_batch_handler:ident, $model:ident) => { @@ -77,6 +77,19 @@ macro_rules! count_entity { }}; } +fn make_edit_context(conn: &DbConn, editgroup_id: Option) -> Result { + let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth + let editgroup_id = match editgroup_id { + None => FatCatId::from_uuid(&get_or_create_editgroup(editor_id, conn).expect("current editgroup")), + Some(param) => param, + }; + Ok(EditContext { + editor_id: FatCatId::from_uuid(&editor_id), + editgroup_id: editgroup_id, + extra_json: None, + }) +} + #[derive(Clone)] pub struct Server { pub db_pool: ConnectionPool, @@ -281,6 +294,7 @@ fn release_row2entity( }) } +/* XXX: fn work_row2entity(ident: Option, rev: WorkRevRow) -> Result { let (state, ident_id, redirect_id) = match ident { Some(i) => ( @@ -299,6 +313,7 @@ fn work_row2entity(ident: Option, rev: WorkRevRow) -> Result, conn: &DbConn, ) -> Result { - let (ident, rev): (WorkIdentRow, WorkRevRow) = work_ident::table - .find(id) - .inner_join(work_rev::table) - .first(conn)?; - - work_row2entity(Some(ident), rev) + WorkEntity::db_get(conn, FatCatId::from_uuid(id)) } pub fn get_work_releases_handler(&self, id: &str, conn: &DbConn) -> Result> { @@ -886,27 +896,8 @@ impl Server { entity: models::WorkEntity, conn: &DbConn, ) -> Result { - let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), - Some(param) => fcid2uuid(¶m)?, - }; - - let edit: WorkEditRow = - diesel::sql_query( - "WITH rev AS ( INSERT INTO work_rev (extra_json) - VALUES ($1) - RETURNING id ), - ident AS ( INSERT INTO work_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) - RETURNING id ) - INSERT INTO work_edit (editgroup_id, ident_id, rev_id) VALUES - ($2, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) - RETURNING *", - ).bind::, _>(entity.extra) - .bind::(editgroup_id) - .get_result(conn)?; - + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } @@ -916,66 +907,14 @@ impl Server { entity: models::WorkEntity, conn: &DbConn, ) -> Result { - let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), - Some(param) => fcid2uuid(¶m)?, - }; - - // TODO: refactor this into a check on WorkIdentRow - let current: WorkIdentRow = work_ident::table.find(id).first(conn)?; - if current.is_live != true { - // TODO: what if isn't live? 4xx not 5xx - bail!("can't delete an entity that doesn't exist yet"); - } - if current.rev_id.is_none() { - // TODO: what if it's already deleted? 4xx not 5xx - bail!("entity was already deleted"); - } - - let edit: WorkEditRow = - diesel::sql_query( - "WITH rev AS ( INSERT INTO work_rev (extra_json) - VALUES ($1) - RETURNING id ), - INSERT INTO work_edit (editgroup_id, ident_id, rev_id, prev_rev) VALUES - ($2, $3, (SELECT rev.id FROM rev), $4) - RETURNING *", - ).bind::, _>(entity.extra) - .bind::(editgroup_id) - .bind::(id) - .bind::(current.rev_id.unwrap()) - .get_result(conn)?; - + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } pub fn delete_work_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { - let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let editgroup_id = match editgroup_id { - Some(egid) => egid, - None => get_or_create_editgroup(editor_id, conn)? - }; - - let current: WorkIdentRow = work_ident::table.find(id).first(conn)?; - if current.is_live != true { - // TODO: what if isn't live? 4xx not 5xx - bail!("can't delete an entity that doesn't exist yet"); - } - if current.rev_id.is_none() { - // TODO: what if it's already deleted? 4xx not 5xx - bail!("entity was already deleted"); - } - let edit: WorkEditRow = insert_into(work_edit::table) - .values(( - work_edit::editgroup_id.eq(editgroup_id), - work_edit::ident_id.eq(id), - work_edit::rev_id.eq(None::), - work_edit::redirect_id.eq(None::), - work_edit::prev_rev.eq(current.rev_id), - //work_edit::extra_json.eq(extra), - )) - .get_result(conn)?; + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit = WorkEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs new file mode 100644 index 00000000..d532d166 --- /dev/null +++ b/rust/src/database_entity_crud.rs @@ -0,0 +1,250 @@ + +use diesel::prelude::*; +use diesel::{self, insert_into}; +use database_schema::*; +use database_models::*; +use errors::*; +use fatcat_api::models::*; +use api_helpers::{FatCatId, DbConn}; +use uuid::Uuid; +use std::marker::Sized; +use std::str::FromStr; +use serde_json; + +pub struct EditContext { + pub editor_id: FatCatId, + pub editgroup_id: FatCatId, + pub extra_json: Option, +} + +/* One goal here is to abstract the non-entity-specific bits into generic traits or functions, + * instead of macros. + * + * Notably: + * + * db_get + * db_get_rev + * db_create + * db_create_batch + * db_update + * db_delete + * db_get_history + * + * For now, these will probably be macros, until we can level up our trait/generics foo. + */ + +// Associated Type, not parametric +pub trait EntityCrud where Self: Sized { + type EditRow; // EntityEditRow + type IdentRow; // EntityIdentRow + type RevRow; + + fn parse_editgroup_id(&self) -> Result>; + + // Generic Methods + fn db_get(conn: &DbConn, ident: FatCatId) -> Result; + fn db_get_rev(conn: &DbConn, rev_id: Uuid) -> Result; + fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result; + fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[Self]) -> Result>; + fn db_update(&self, conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result; + fn db_delete(conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result; + fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option) -> Result>; + + // Entity-specific Methods + fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result; + fn db_insert_rev(&self, conn: &DbConn, edit_context: &EditContext) -> Result; +} + +// TODO: this could be a separate trait on all entities? +macro_rules! generic_parse_editgroup_id{ + () => { + fn parse_editgroup_id(&self) -> Result> { + match &self.editgroup_id { + Some(s) => Ok(Some(FatCatId::from_str(&s)?)), + None => Ok(None), + } + } + } +} + +macro_rules! generic_db_get { + ($ident_table: ident, $rev_table: ident) => { + fn db_get(conn: &DbConn, ident: FatCatId) -> Result { + let (ident, rev): (Self::IdentRow, Self::RevRow) = $ident_table::table + .find(ident.to_uuid()) + .inner_join($rev_table::table) + .first(conn)?; + + Self::db_from_row(conn, rev, Some(ident)) + } + } +} + +macro_rules! generic_db_get_rev { + ($rev_table: ident) => { + fn db_get_rev(conn: &DbConn, rev_id: Uuid) -> Result { + let rev = $rev_table::table + .find(rev_id) + .first(conn)?; + + Self::db_from_row(conn, rev, None) + } + } +} + +macro_rules! generic_db_create_batch { + () => { + fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[Self]) -> Result> { + let mut ret: Vec = vec![]; + for entity in models { + ret.push(entity.db_create(conn, edit_context)?); + } + Ok(ret) + } + } +} + +macro_rules! generic_db_delete { + ($ident_table: ident, $edit_table:ident) => { + fn db_delete(conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result { + + let current: Self::IdentRow = $ident_table::table.find(ident.to_uuid()).first(conn)?; + if current.is_live != true { + // TODO: what if isn't live? 4xx not 5xx + bail!("can't delete an entity that doesn't exist yet"); + } + if current.rev_id.is_none() { + // TODO: what if it's already deleted? 4xx not 5xx + bail!("entity was already deleted"); + } + let edit: Self::EditRow = insert_into($edit_table::table) + .values(( + $edit_table::editgroup_id.eq(edit_context.editgroup_id.to_uuid()), + $edit_table::ident_id.eq(ident.to_uuid()), + $edit_table::rev_id.eq(None::), + $edit_table::redirect_id.eq(None::), + $edit_table::prev_rev.eq(current.rev_id), + $edit_table::extra_json.eq(&edit_context.extra_json), + )) + .get_result(conn)?; + + Ok(edit) + } + } +} + +macro_rules! generic_db_get_history { + // TODO: only actually need edit table? and maybe not that? + ($edit_table:ident) => { + fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option) -> Result> { + let limit = limit.unwrap_or(50); // XXX: make a static + + let rows: Vec<(EditgroupRow, ChangelogRow, Self::EditRow)> = editgroup::table + .inner_join(changelog::table) + .inner_join($edit_table::table) + .filter($edit_table::ident_id.eq(ident.to_uuid())) + .order(changelog::id.desc()) + .limit(limit) + .get_results(conn)?; + + let history: Vec = rows.into_iter() + .map(|(eg_row, cl_row, e_row)| EntityHistoryEntry { + edit: e_row.into_model().expect("edit row to model"), + editgroup: eg_row.into_model_partial(), + changelog_entry: cl_row.into_model(), + }) + .collect(); + Ok(history) + } + } +} + +impl EntityCrud for WorkEntity { + type EditRow = WorkEditRow; + type IdentRow = WorkIdentRow; + type RevRow = WorkRevRow; + + generic_parse_editgroup_id!(); + generic_db_get!(work_ident, work_rev); + generic_db_get_rev!(work_rev); + generic_db_create_batch!(); + generic_db_delete!(work_ident, work_edit); + generic_db_get_history!(work_edit); + + fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result { + + // TODO: refactor to use insert_rev + let edit: WorkEditRow = + diesel::sql_query( + "WITH rev AS ( INSERT INTO work_rev (extra_json) + VALUES ($1) + RETURNING id ), + ident AS ( INSERT INTO work_ident (rev_id) + VALUES ((SELECT rev.id FROM rev)) + RETURNING id ) + INSERT INTO work_edit (editgroup_id, ident_id, rev_id) VALUES + ($2, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) + RETURNING *", + ).bind::, _>(&self.extra) + .bind::(edit_context.editgroup_id.to_uuid()) + .get_result(conn)?; + + Ok(edit) + } + + fn db_update(&self, conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result { + // TODO: refactor this into a check on WorkIdentRow + let current: WorkIdentRow = work_ident::table.find(ident.to_uuid()).first(conn)?; + if current.is_live != true { + // TODO: what if isn't live? 4xx not 5xx + bail!("can't delete an entity that doesn't exist yet"); + } + if current.rev_id.is_none() { + // TODO: what if it's already deleted? 4xx not 5xx + bail!("entity was already deleted"); + } + + let edit: WorkEditRow = + diesel::sql_query( + "WITH rev AS ( INSERT INTO work_rev (extra_json) + VALUES ($1) + RETURNING id ), + INSERT INTO work_edit (editgroup_id, ident_id, rev_id, prev_rev) VALUES + ($2, $3, (SELECT rev.id FROM rev), $4) + RETURNING *", + ).bind::, _>(&self.extra) + .bind::(edit_context.editgroup_id.to_uuid()) + .bind::(ident.to_uuid()) + .bind::(current.rev_id.unwrap()) + .get_result(conn)?; + + Ok(edit) + } + + + fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + + let (state, ident_id, redirect_id) = match ident_row { + Some(i) => ( + Some(i.state().unwrap().shortname()), + Some(FatCatId::from_uuid(&i.id).to_string()), + i.redirect_id.map(|u| FatCatId::from_uuid(&u).to_string()), + ), + None => (None, None, None), + }; + + Ok(WorkEntity { + state: state, + ident: ident_id, + revision: Some(rev_row.id.to_string()), + redirect: redirect_id, + editgroup_id: None, + extra: rev_row.extra_json, + }) + } + + fn db_insert_rev(&self, conn: &DbConn, edit_context: &EditContext) -> Result { + unimplemented!() + } +} + diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 12ce0973..a938486b 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -27,6 +27,7 @@ pub mod api_server; pub mod api_wrappers; pub mod database_models; pub mod database_schema; +pub mod database_entity_crud; mod errors { // Create the Error, ErrorKind, ResultExt, and Result types -- cgit v1.2.3 From 21a40354a9c0684f0bbb6f0b3211aeafc05229b3 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 14:02:47 -0700 Subject: crud: refactor to split out rev insert --- rust/src/database_entity_crud.rs | 94 ++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 43 deletions(-) (limited to 'rust') diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs index d532d166..7a5f333d 100644 --- a/rust/src/database_entity_crud.rs +++ b/rust/src/database_entity_crud.rs @@ -52,7 +52,7 @@ pub trait EntityCrud where Self: Sized { // Entity-specific Methods fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result; - fn db_insert_rev(&self, conn: &DbConn, edit_context: &EditContext) -> Result; + fn db_insert_rev(&self, conn: &DbConn) -> Result; } // TODO: this could be a separate trait on all entities? @@ -104,6 +104,35 @@ macro_rules! generic_db_create_batch { } } +macro_rules! generic_db_update { + ($ident_table: ident, $edit_table: ident) => { + fn db_update(&self, conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result { + let current: Self::IdentRow = $ident_table::table.find(ident.to_uuid()).first(conn)?; + if current.is_live != true { + // TODO: what if isn't live? 4xx not 5xx + bail!("can't delete an entity that doesn't exist yet"); + } + if current.rev_id.is_none() { + // TODO: what if it's already deleted? 4xx not 5xx + bail!("entity was already deleted"); + } + + let rev_id = self.db_insert_rev(conn)?; + let edit: Self::EditRow = insert_into($edit_table::table) + .values(( + $edit_table::editgroup_id.eq(edit_context.editgroup_id.to_uuid()), + $edit_table::ident_id.eq(&ident.to_uuid()), + $edit_table::rev_id.eq(&rev_id), + $edit_table::prev_rev.eq(current.rev_id.unwrap()), + $edit_table::extra_json.eq(&self.extra), + )) + .get_result(conn)?; + + Ok(edit) + } + } +} + macro_rules! generic_db_delete { ($ident_table: ident, $edit_table:ident) => { fn db_delete(conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result { @@ -168,60 +197,30 @@ impl EntityCrud for WorkEntity { generic_db_get!(work_ident, work_rev); generic_db_get_rev!(work_rev); generic_db_create_batch!(); + generic_db_update!(work_ident, work_edit); generic_db_delete!(work_ident, work_edit); generic_db_get_history!(work_edit); fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result { - // TODO: refactor to use insert_rev + let rev_id = self.db_insert_rev(conn)?; let edit: WorkEditRow = diesel::sql_query( - "WITH rev AS ( INSERT INTO work_rev (extra_json) - VALUES ($1) - RETURNING id ), - ident AS ( INSERT INTO work_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) - RETURNING id ) - INSERT INTO work_edit (editgroup_id, ident_id, rev_id) VALUES - ($2, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) + "WITH ident AS ( + INSERT INTO work_ident (rev_id) + VALUES ($1) + RETURNING id ) + INSERT INTO work_edit (editgroup_id, ident_id, rev_id, extra) VALUES + ($2, (SELECT ident.id FROM ident), $1, $3) RETURNING *", - ).bind::, _>(&self.extra) + ).bind::(rev_id) .bind::(edit_context.editgroup_id.to_uuid()) + .bind::, _>(&edit_context.extra_json) .get_result(conn)?; Ok(edit) } - fn db_update(&self, conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result { - // TODO: refactor this into a check on WorkIdentRow - let current: WorkIdentRow = work_ident::table.find(ident.to_uuid()).first(conn)?; - if current.is_live != true { - // TODO: what if isn't live? 4xx not 5xx - bail!("can't delete an entity that doesn't exist yet"); - } - if current.rev_id.is_none() { - // TODO: what if it's already deleted? 4xx not 5xx - bail!("entity was already deleted"); - } - - let edit: WorkEditRow = - diesel::sql_query( - "WITH rev AS ( INSERT INTO work_rev (extra_json) - VALUES ($1) - RETURNING id ), - INSERT INTO work_edit (editgroup_id, ident_id, rev_id, prev_rev) VALUES - ($2, $3, (SELECT rev.id FROM rev), $4) - RETURNING *", - ).bind::, _>(&self.extra) - .bind::(edit_context.editgroup_id.to_uuid()) - .bind::(ident.to_uuid()) - .bind::(current.rev_id.unwrap()) - .get_result(conn)?; - - Ok(edit) - } - - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { let (state, ident_id, redirect_id) = match ident_row { @@ -243,8 +242,17 @@ impl EntityCrud for WorkEntity { }) } - fn db_insert_rev(&self, conn: &DbConn, edit_context: &EditContext) -> Result { - unimplemented!() + fn db_insert_rev(&self, conn: &DbConn) -> Result { + let rev_row: WorkRevRow = insert_into(work_rev::table) + .values(( + work_rev::extra_json.eq(&self.extra) + )) + .get_result(conn)?; + /* TODO: only return id + .returning(work_rev::id) + .first(conn)?; + */ + Ok(rev_row.id) } } -- cgit v1.2.3 From cdf46b6a5246b8d750bb7aba60acebca11507540 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 14:21:38 -0700 Subject: generic create (multiple inserts) This does away entirely with the fancy CTE-based custom SQL inserts. Because performance is currently only important for batch inserts, I think this is acceptable, and will refactor to do batch inserts as actual batch SQL operations next. --- rust/src/database_entity_crud.rs | 50 +++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 26 deletions(-) (limited to 'rust') diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs index 7a5f333d..24d5277c 100644 --- a/rust/src/database_entity_crud.rs +++ b/rust/src/database_entity_crud.rs @@ -92,6 +92,26 @@ macro_rules! generic_db_get_rev { } } +macro_rules! generic_db_create { + ($ident_table: ident, $edit_table: ident) => { + fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result { + let rev_id = self.db_insert_rev(conn)?; + let ident: Uuid = insert_into($ident_table::table) + .values($ident_table::rev_id.eq(&rev_id)) + .returning($ident_table::id) + .get_result(conn)?; + let edit: Self::EditRow = insert_into($edit_table::table) + .values(( + $edit_table::editgroup_id.eq(edit_context.editgroup_id.to_uuid()), + $edit_table::rev_id.eq(&rev_id), + $edit_table::ident_id.eq(&ident), + )) + .get_result(conn)?; + Ok(edit) + } + } +} + macro_rules! generic_db_create_batch { () => { fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[Self]) -> Result> { @@ -196,31 +216,12 @@ impl EntityCrud for WorkEntity { generic_parse_editgroup_id!(); generic_db_get!(work_ident, work_rev); generic_db_get_rev!(work_rev); + generic_db_create!(work_ident, work_edit); generic_db_create_batch!(); generic_db_update!(work_ident, work_edit); generic_db_delete!(work_ident, work_edit); generic_db_get_history!(work_edit); - fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result { - - let rev_id = self.db_insert_rev(conn)?; - let edit: WorkEditRow = - diesel::sql_query( - "WITH ident AS ( - INSERT INTO work_ident (rev_id) - VALUES ($1) - RETURNING id ) - INSERT INTO work_edit (editgroup_id, ident_id, rev_id, extra) VALUES - ($2, (SELECT ident.id FROM ident), $1, $3) - RETURNING *", - ).bind::(rev_id) - .bind::(edit_context.editgroup_id.to_uuid()) - .bind::, _>(&edit_context.extra_json) - .get_result(conn)?; - - Ok(edit) - } - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { let (state, ident_id, redirect_id) = match ident_row { @@ -243,16 +244,13 @@ impl EntityCrud for WorkEntity { } fn db_insert_rev(&self, conn: &DbConn) -> Result { - let rev_row: WorkRevRow = insert_into(work_rev::table) + let rev_row: Uuid = insert_into(work_rev::table) .values(( work_rev::extra_json.eq(&self.extra) )) - .get_result(conn)?; - /* TODO: only return id .returning(work_rev::id) - .first(conn)?; - */ - Ok(rev_row.id) + .get_result(conn)?; + Ok(rev_row) } } -- cgit v1.2.3 From e73b56f9354596c556cfbb2d45584a6bb86ad60e Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 16:00:54 -0700 Subject: batch inserts by default --- rust/src/api_server.rs | 1 + rust/src/database_entity_crud.rs | 76 +++++++++++++++++++++++++++++----------- rust/src/database_models.rs | 45 ++++++++++++++++++++---- 3 files changed, 95 insertions(+), 27 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 20f71c7a..5060ba0f 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -87,6 +87,7 @@ fn make_edit_context(conn: &DbConn, editgroup_id: Option) -> Result, + pub autoapprove: bool, } /* One goal here is to abstract the non-entity-specific bits into generic traits or functions, @@ -35,8 +36,11 @@ pub struct EditContext { // Associated Type, not parametric pub trait EntityCrud where Self: Sized { + // TODO: could these be generic structs? Or do they need to be bound to a specific table? type EditRow; // EntityEditRow + type EditNewRow; type IdentRow; // EntityIdentRow + type IdentNewRow; type RevRow; fn parse_editgroup_id(&self) -> Result>; @@ -45,14 +49,15 @@ pub trait EntityCrud where Self: Sized { fn db_get(conn: &DbConn, ident: FatCatId) -> Result; fn db_get_rev(conn: &DbConn, rev_id: Uuid) -> Result; fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result; - fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[Self]) -> Result>; + fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result>; fn db_update(&self, conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result; fn db_delete(conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result; fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option) -> Result>; // Entity-specific Methods - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result; + fn from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result; fn db_insert_rev(&self, conn: &DbConn) -> Result; + fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result>; } // TODO: this could be a separate trait on all entities? @@ -75,7 +80,7 @@ macro_rules! generic_db_get { .inner_join($rev_table::table) .first(conn)?; - Self::db_from_row(conn, rev, Some(ident)) + Self::from_row(conn, rev, Some(ident)) } } } @@ -87,7 +92,7 @@ macro_rules! generic_db_get_rev { .find(rev_id) .first(conn)?; - Self::db_from_row(conn, rev, None) + Self::from_row(conn, rev, None) } } } @@ -113,13 +118,32 @@ macro_rules! generic_db_create { } macro_rules! generic_db_create_batch { - () => { - fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[Self]) -> Result> { - let mut ret: Vec = vec![]; - for entity in models { - ret.push(entity.db_create(conn, edit_context)?); - } - Ok(ret) + ($ident_table: ident, $edit_table: ident) => { + fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result> { + let rev_ids: Vec = Self::db_insert_revs(conn, models)?; + let ident_ids: Vec = insert_into($ident_table::table) + .values(rev_ids.iter() + .map(|rev_id| Self::IdentNewRow { + rev_id: Some(rev_id.clone()), + is_live: edit_context.autoapprove, + redirect_id: None, + }) + .collect::>()) + .returning($ident_table::id) + .get_results(conn)?; + let edits: Vec = insert_into($edit_table::table) + .values(rev_ids.into_iter().zip(ident_ids.into_iter()) + .map(|(rev_id, ident_id)| Self::EditNewRow { + editgroup_id: edit_context.editgroup_id.to_uuid(), + rev_id: Some(rev_id), + ident_id: ident_id, + redirect_id: None, + prev_rev: None, + extra_json: edit_context.extra_json.clone(), + }) + .collect::>()) + .get_results(conn)?; + Ok(edits) } } } @@ -183,7 +207,6 @@ macro_rules! generic_db_delete { } macro_rules! generic_db_get_history { - // TODO: only actually need edit table? and maybe not that? ($edit_table:ident) => { fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option) -> Result> { let limit = limit.unwrap_or(50); // XXX: make a static @@ -208,21 +231,32 @@ macro_rules! generic_db_get_history { } } +macro_rules! generic_db_insert_rev { + () => { + fn db_insert_rev(&self, conn: &DbConn) -> Result { + Self::db_insert_revs(conn, &vec![self]).map(|id_list| id_list[0]) + } + } +} + impl EntityCrud for WorkEntity { type EditRow = WorkEditRow; + type EditNewRow = WorkEditNewRow; type IdentRow = WorkIdentRow; + type IdentNewRow = WorkIdentNewRow; type RevRow = WorkRevRow; generic_parse_editgroup_id!(); generic_db_get!(work_ident, work_rev); generic_db_get_rev!(work_rev); generic_db_create!(work_ident, work_edit); - generic_db_create_batch!(); + generic_db_create_batch!(work_ident, work_edit); generic_db_update!(work_ident, work_edit); generic_db_delete!(work_ident, work_edit); generic_db_get_history!(work_edit); + generic_db_insert_rev!(); - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + fn from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( @@ -243,14 +277,14 @@ impl EntityCrud for WorkEntity { }) } - fn db_insert_rev(&self, conn: &DbConn) -> Result { - let rev_row: Uuid = insert_into(work_rev::table) - .values(( - work_rev::extra_json.eq(&self.extra) - )) + fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { + let rev_ids: Vec = insert_into(work_rev::table) + .values(models.iter() + .map(|model| WorkRevNewRow { extra_json: model.extra.clone() } ) + .collect::>()) .returning(work_rev::id) - .get_result(conn)?; - Ok(rev_row) + .get_results(conn)?; + Ok(rev_ids) } } diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index 47e00bcf..14215a3c 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -37,7 +37,9 @@ pub trait EntityEditRow { // Helper for constructing tables macro_rules! entity_structs { - ($edit_table:expr, $edit_struct:ident, $ident_table:expr, $ident_struct:ident) => { + ($edit_table:expr, $edit_struct:ident, $edit_new_struct:ident, $ident_table:expr, + $ident_struct:ident, $ident_new_struct:ident) => { + #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset, QueryableByName)] #[table_name = $edit_table] pub struct $edit_struct { @@ -51,6 +53,17 @@ macro_rules! entity_structs { pub extra_json: Option, } + #[derive(Debug, Associations, AsChangeset, QueryableByName, Insertable)] + #[table_name = $edit_table] + pub struct $edit_new_struct { + pub editgroup_id: Uuid, + pub ident_id: Uuid, + pub rev_id: Option, + pub redirect_id: Option, + pub prev_rev: Option, + pub extra_json: Option, + } + impl EntityEditRow for $edit_struct { /// Go from a row (SQL model) to an API model fn into_model(self) -> Result { @@ -75,6 +88,14 @@ macro_rules! entity_structs { pub redirect_id: Option, } + #[derive(Debug, Associations, AsChangeset, Insertable)] + #[table_name = $ident_table] + pub struct $ident_new_struct { + pub is_live: bool, + pub rev_id: Option, + pub redirect_id: Option, + } + impl EntityIdentRow for $ident_struct { fn state(&self) -> Result { if !self.is_live { @@ -107,8 +128,10 @@ pub struct ContainerRevRow { entity_structs!( "container_edit", ContainerEditRow, + ContainerEditNewRow, "container_ident", - ContainerIdentRow + ContainerIdentRow, + ContainerIdentNewRow ); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] @@ -126,8 +149,10 @@ pub struct CreatorRevRow { entity_structs!( "creator_edit", CreatorEditRow, + CreatorEditNewRow, "creator_ident", - CreatorIdentRow + CreatorIdentRow, + CreatorIdentNewRow ); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] @@ -159,7 +184,7 @@ pub struct FileRevRow { pub mimetype: Option, } -entity_structs!("file_edit", FileEditRow, "file_ident", FileIdentRow); +entity_structs!("file_edit", FileEditRow, FileEditNewRow, "file_ident", FileIdentRow, FileIdentNewRow); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] #[table_name = "release_rev"] @@ -188,8 +213,10 @@ pub struct ReleaseRevRow { entity_structs!( "release_edit", ReleaseEditRow, + ReleaseEditNewRow, "release_ident", - ReleaseIdentRow + ReleaseIdentRow, + ReleaseIdentNewRow ); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] @@ -199,7 +226,13 @@ pub struct WorkRevRow { pub extra_json: Option, } -entity_structs!("work_edit", WorkEditRow, "work_ident", WorkIdentRow); +#[derive(Debug, Associations, AsChangeset, Insertable)] +#[table_name = "work_rev"] +pub struct WorkRevNewRow { + pub extra_json: Option, +} + +entity_structs!("work_edit", WorkEditRow, WorkEditNewRow, "work_ident", WorkIdentRow, WorkIdentNewRow); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] #[table_name = "release_rev_abstract"] -- cgit v1.2.3 From 47cb21bdc31466dd827800898a4ad543a6297696 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 18:57:11 -0700 Subject: mostly done with CRUD refactor One failing test in this commit. --- rust/src/api_server.rs | 687 ++++----------------------------------- rust/src/database_entity_crud.rs | 626 ++++++++++++++++++++++++++++++++++- rust/src/database_models.rs | 57 ++++ 3 files changed, 745 insertions(+), 625 deletions(-) (limited to 'rust') diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 5060ba0f..ecf0c242 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -21,47 +21,16 @@ use database_entity_crud::{EntityCrud, EditContext}; use std::str::FromStr; macro_rules! entity_batch_handler { - ($post_handler:ident, $post_batch_handler:ident, $model:ident) => { + ($post_batch_handler:ident, $model:ident) => { pub fn $post_batch_handler( &self, entity_list: &[models::$model], conn: &DbConn, ) -> Result> { - let mut ret: Vec = vec![]; - for entity in entity_list { - ret.push(self.$post_handler(entity.clone(), conn)?); - } - Ok(ret) - } - } -} - -macro_rules! entity_history_handler { - ($history_handler:ident, $edit_row_type:ident, $edit_table:ident) => { - pub fn $history_handler( - &self, - id: &Uuid, - limit: Option, - conn: &DbConn, - ) -> Result> { - let limit = limit.unwrap_or(50); - - let rows: Vec<(EditgroupRow, ChangelogRow, $edit_row_type)> = editgroup::table - .inner_join(changelog::table) - .inner_join($edit_table::table) - .filter($edit_table::ident_id.eq(id)) - .order(changelog::id.desc()) - .limit(limit) - .get_results(conn)?; - - let history: Vec = rows.into_iter() - .map(|(eg_row, cl_row, e_row)| EntityHistoryEntry { - edit: e_row.into_model().expect("edit row to model"), - editgroup: eg_row.into_model_partial(), - changelog_entry: cl_row.into_model(), - }) - .collect(); - Ok(history) + let edit_context = make_edit_context(conn, None)?; + let model_list: Vec<&models::$model> = entity_list.iter().map(|e| e).collect(); + let edits = $model::db_create_batch(conn, &edit_context, model_list.as_slice())?; + edits.into_iter().map(|e| e.into_model()).collect() } } } @@ -96,226 +65,6 @@ pub struct Server { pub db_pool: ConnectionPool, } -fn container_row2entity( - ident: Option, - rev: ContainerRevRow, -) -> Result { - let (state, ident_id, redirect_id) = match ident { - Some(i) => ( - Some(i.state().unwrap().shortname()), - Some(uuid2fcid(&i.id)), - i.redirect_id.map(|u| uuid2fcid(&u)), - ), - None => (None, None, None), - }; - Ok(ContainerEntity { - issnl: rev.issnl, - wikidata_qid: rev.wikidata_qid, - publisher: rev.publisher, - name: rev.name, - abbrev: rev.abbrev, - coden: rev.coden, - state: state, - ident: ident_id, - revision: Some(rev.id.to_string()), - redirect: redirect_id, - extra: rev.extra_json, - editgroup_id: None, - }) -} - -fn creator_row2entity(ident: Option, rev: CreatorRevRow) -> Result { - let (state, ident_id, redirect_id) = match ident { - Some(i) => ( - Some(i.state().unwrap().shortname()), - Some(uuid2fcid(&i.id)), - i.redirect_id.map(|u| uuid2fcid(&u)), - ), - None => (None, None, None), - }; - Ok(CreatorEntity { - display_name: rev.display_name, - given_name: rev.given_name, - surname: rev.surname, - orcid: rev.orcid, - wikidata_qid: rev.wikidata_qid, - state: state, - ident: ident_id, - revision: Some(rev.id.to_string()), - redirect: redirect_id, - editgroup_id: None, - extra: rev.extra_json, - }) -} - -fn file_row2entity( - ident: Option, - rev: FileRevRow, - conn: &DbConn, -) -> Result { - let (state, ident_id, redirect_id) = match ident { - Some(i) => ( - Some(i.state().unwrap().shortname()), - Some(uuid2fcid(&i.id)), - i.redirect_id.map(|u| uuid2fcid(&u)), - ), - None => (None, None, None), - }; - - let releases: Vec = file_release::table - .filter(file_release::file_rev.eq(rev.id)) - .get_results(conn)? - .into_iter() - .map(|r: FileReleaseRow| uuid2fcid(&r.target_release_ident_id)) - .collect(); - - let urls: Vec = file_rev_url::table - .filter(file_rev_url::file_rev.eq(rev.id)) - .get_results(conn)? - .into_iter() - .map(|r: FileRevUrlRow| FileEntityUrls { - rel: r.rel, - url: r.url, - }) - .collect(); - - Ok(FileEntity { - sha1: rev.sha1, - sha256: rev.sha256, - md5: rev.md5, - size: rev.size.map(|v| v as i64), - urls: Some(urls), - mimetype: rev.mimetype, - releases: Some(releases), - state: state, - ident: ident_id, - revision: Some(rev.id.to_string()), - redirect: redirect_id, - editgroup_id: None, - extra: rev.extra_json, - }) -} - -fn release_row2entity( - ident: Option, - rev: ReleaseRevRow, - conn: &DbConn, -) -> Result { - let (state, ident_id, redirect_id) = match ident { - Some(i) => ( - Some(i.state().unwrap().shortname()), - Some(uuid2fcid(&i.id)), - i.redirect_id.map(|u| uuid2fcid(&u)), - ), - None => (None, None, None), - }; - - let refs: Vec = release_ref::table - .filter(release_ref::release_rev.eq(rev.id)) - .order(release_ref::index_val.asc()) - .get_results(conn) - .expect("fetch release refs") - .into_iter() - .map(|r: ReleaseRefRow| ReleaseRef { - index: r.index_val, - key: r.key, - extra: r.extra_json, - container_title: r.container_title, - year: r.year, - title: r.title, - locator: r.locator, - target_release_id: r.target_release_ident_id.map(|v| uuid2fcid(&v)), - }) - .collect(); - - let contribs: Vec = release_contrib::table - .filter(release_contrib::release_rev.eq(rev.id)) - .order(( - release_contrib::role.asc(), - release_contrib::index_val.asc(), - )) - .get_results(conn) - .expect("fetch release refs") - .into_iter() - .map(|c: ReleaseContribRow| ReleaseContrib { - index: c.index_val, - raw_name: c.raw_name, - role: c.role, - extra: c.extra_json, - creator_id: c.creator_ident_id.map(|v| uuid2fcid(&v)), - creator: None, - }) - .collect(); - - let abstracts: Vec = release_rev_abstract::table - .inner_join(abstracts::table) - .filter(release_rev_abstract::release_rev.eq(rev.id)) - .get_results(conn)? - .into_iter() - .map( - |r: (ReleaseRevAbstractRow, AbstractsRow)| ReleaseEntityAbstracts { - sha1: Some(r.0.abstract_sha1), - mimetype: r.0.mimetype, - lang: r.0.lang, - content: Some(r.1.content), - }, - ) - .collect(); - - Ok(ReleaseEntity { - title: rev.title, - release_type: rev.release_type, - release_status: rev.release_status, - release_date: rev.release_date - .map(|v| chrono::DateTime::from_utc(v.and_hms(0, 0, 0), chrono::Utc)), - doi: rev.doi, - pmid: rev.pmid, - pmcid: rev.pmcid, - isbn13: rev.isbn13, - core_id: rev.core_id, - wikidata_qid: rev.wikidata_qid, - volume: rev.volume, - issue: rev.issue, - pages: rev.pages, - files: None, - container: None, - container_id: rev.container_ident_id.map(|u| uuid2fcid(&u)), - publisher: rev.publisher, - language: rev.language, - work_id: Some(uuid2fcid(&rev.work_ident_id)), - refs: Some(refs), - contribs: Some(contribs), - abstracts: Some(abstracts), - state: state, - ident: ident_id, - revision: Some(rev.id.to_string()), - redirect: redirect_id, - editgroup_id: None, - extra: rev.extra_json, - }) -} - -/* XXX: -fn work_row2entity(ident: Option, rev: WorkRevRow) -> Result { - let (state, ident_id, redirect_id) = match ident { - Some(i) => ( - Some(i.state().unwrap().shortname()), - Some(uuid2fcid(&i.id)), - i.redirect_id.map(|u| uuid2fcid(&u)), - ), - None => (None, None, None), - }; - Ok(WorkEntity { - state: state, - ident: ident_id, - revision: Some(rev.id.to_string()), - redirect: redirect_id, - editgroup_id: None, - extra: rev.extra_json, - }) -} -*/ - impl Server { pub fn get_container_handler( &self, @@ -323,13 +72,7 @@ impl Server { _expand: Option, conn: &DbConn, ) -> Result { - // TODO: handle Deletions - let (ident, rev): (ContainerIdentRow, ContainerRevRow) = container_ident::table - .find(id) - .inner_join(container_rev::table) - .first(conn)?; - - container_row2entity(Some(ident), rev) + ContainerEntity::db_get(conn, FatCatId::from_uuid(id)) } pub fn lookup_container_handler(&self, issnl: &str, conn: &DbConn) -> Result { @@ -344,7 +87,7 @@ impl Server { .filter(container_ident::redirect_id.is_null()) .first(conn)?; - container_row2entity(Some(ident), rev) + ContainerEntity::db_from_row(conn, rev, Some(ident)) } pub fn get_creator_handler( @@ -353,12 +96,8 @@ impl Server { _expand: Option, conn: &DbConn, ) -> Result { - let (ident, rev): (CreatorIdentRow, CreatorRevRow) = creator_ident::table - .find(id) - .inner_join(creator_rev::table) - .first(conn)?; - creator_row2entity(Some(ident), rev) + CreatorEntity::db_get(conn, FatCatId::from_uuid(id)) } pub fn lookup_creator_handler(&self, orcid: &str, conn: &DbConn) -> Result { @@ -373,7 +112,7 @@ impl Server { .filter(creator_ident::redirect_id.is_null()) .first(conn)?; - creator_row2entity(Some(ident), rev) + CreatorEntity::db_from_row(conn, rev, Some(ident)) } pub fn get_creator_releases_handler( @@ -392,8 +131,9 @@ impl Server { .filter(release_ident::redirect_id.is_null()) .load(conn)?; + // TODO: from_rows, not from_row? rows.into_iter() - .map(|(rev, ident, _)| release_row2entity(Some(ident), rev, conn)) + .map(|(rev, ident, _)| ReleaseEntity::db_from_row(conn, rev, Some(ident))) .collect() } @@ -403,12 +143,7 @@ impl Server { _expand: Option, conn: &DbConn, ) -> Result { - let (ident, rev): (FileIdentRow, FileRevRow) = file_ident::table - .find(id) - .inner_join(file_rev::table) - .first(conn)?; - - file_row2entity(Some(ident), rev, conn) + FileEntity::db_get(conn, FatCatId::from_uuid(id)) } pub fn lookup_file_handler(&self, sha1: &str, conn: &DbConn) -> Result { @@ -422,7 +157,7 @@ impl Server { .filter(file_ident::redirect_id.is_null()) .first(conn)?; - file_row2entity(Some(ident), rev, conn) + FileEntity::db_from_row(conn, rev, Some(ident)) } pub fn get_release_handler( @@ -431,12 +166,8 @@ impl Server { expand: Option, conn: &DbConn, ) -> Result { - let (ident, rev): (ReleaseIdentRow, ReleaseRevRow) = release_ident::table - .find(id) - .inner_join(release_rev::table) - .first(conn)?; - let mut release = release_row2entity(Some(ident), rev, conn)?; + let mut release = ReleaseEntity::db_get(conn, FatCatId::from_uuid(id))?; // For now, if there is any expand param we do them all if expand.is_some() { @@ -447,7 +178,6 @@ impl Server { Some(self.get_container_handler(&fcid2uuid(&cid)?, None, conn)?); } } - Ok(release) } @@ -463,22 +193,23 @@ impl Server { .filter(release_ident::redirect_id.is_null()) .first(conn)?; - release_row2entity(Some(ident), rev, conn) + ReleaseEntity::db_from_row(conn, rev, Some(ident)) } pub fn get_release_files_handler(&self, id: &str, conn: &DbConn) -> Result> { - let id = fcid2uuid(&id)?; + + let ident = FatCatId::from_str(id)?; let rows: Vec<(FileRevRow, FileIdentRow, FileReleaseRow)> = file_rev::table .inner_join(file_ident::table) .inner_join(file_release::table) - .filter(file_release::target_release_ident_id.eq(&id)) + .filter(file_release::target_release_ident_id.eq(&ident.to_uuid())) .filter(file_ident::is_live.eq(true)) .filter(file_ident::redirect_id.is_null()) .load(conn)?; rows.into_iter() - .map(|(rev, ident, _)| file_row2entity(Some(ident), rev, conn)) + .map(|(rev, ident, _)| FileEntity::db_from_row(conn, rev, Some(ident))) .collect() } @@ -502,7 +233,7 @@ impl Server { .load(conn)?; rows.into_iter() - .map(|(rev, ident)| release_row2entity(Some(ident), rev, conn)) + .map(|(rev, ident)| ReleaseEntity::db_from_row(conn, rev, Some(ident))) .collect() } @@ -511,52 +242,25 @@ impl Server { entity: models::ContainerEntity, conn: &DbConn, ) -> Result { - let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let editgroup_id: Uuid = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, conn)?, - Some(param) => fcid2uuid(¶m)?, - }; - if let Some(ref extid) = entity.wikidata_qid { - check_wikidata_qid(extid)?; - } - if let Some(ref extid) = entity.issnl { - check_issn(extid)?; - } - - let edit: ContainerEditRow = diesel::sql_query( - "WITH rev AS ( INSERT INTO container_rev (name, publisher, issnl, wikidata_qid, abbrev, coden, extra_json) - VALUES ($1, $2, $3, $4, $5, $6, $7) - RETURNING id ), - ident AS ( INSERT INTO container_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) - RETURNING id ) - INSERT INTO container_edit (editgroup_id, ident_id, rev_id) VALUES - ($8, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) - RETURNING *", - ).bind::(entity.name) - .bind::, _>(entity.publisher) - .bind::, _>(entity.issnl) - .bind::, _>(entity.wikidata_qid) - .bind::, _>(entity.abbrev) - .bind::, _>(entity.coden) - .bind::, _>(entity.extra) - .bind::(editgroup_id) - .get_result(conn)?; - + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } - // XXX: pub fn update_container_handler( &self, id: &Uuid, entity: models::ContainerEntity, conn: &DbConn, ) -> Result { - unimplemented!() + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; + edit.into_model() } pub fn delete_container_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { - unimplemented!() + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit = ContainerEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; + edit.into_model() } pub fn create_creator_handler( @@ -564,51 +268,26 @@ impl Server { entity: models::CreatorEntity, conn: &DbConn, ) -> Result { - let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), - Some(param) => fcid2uuid(¶m)?, - }; - if let Some(ref extid) = entity.orcid { - check_orcid(extid)?; - } - if let Some(ref extid) = entity.wikidata_qid { - check_wikidata_qid(extid)?; - } - - let edit: CreatorEditRow = diesel::sql_query( - "WITH rev AS ( INSERT INTO creator_rev (display_name, given_name, surname, orcid, wikidata_qid, extra_json) - VALUES ($1, $2, $3, $4, $5, $6) - RETURNING id ), - ident AS ( INSERT INTO creator_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) - RETURNING id ) - INSERT INTO creator_edit (editgroup_id, ident_id, rev_id) VALUES - ($7, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) - RETURNING *", - ).bind::(entity.display_name) - .bind::, _>(entity.given_name) - .bind::, _>(entity.surname) - .bind::, _>(entity.orcid) - .bind::, _>(entity.wikidata_qid) - .bind::, _>(entity.extra) - .bind::(editgroup_id) - .get_result(conn)?; - + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_create(conn, &edit_context)?; edit.into_model() + } - // XXX: pub fn update_creator_handler( &self, id: &Uuid, entity: models::CreatorEntity, conn: &DbConn, ) -> Result { - unimplemented!() + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; + edit.into_model() } pub fn delete_creator_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { - unimplemented!() + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit = CreatorEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; + edit.into_model() } pub fn create_file_handler( @@ -616,92 +295,25 @@ impl Server { entity: models::FileEntity, conn: &DbConn, ) -> Result { - let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), - Some(param) => fcid2uuid(¶m)?, - }; - - let edit: FileEditRow = - diesel::sql_query( - "WITH rev AS ( INSERT INTO file_rev (size, sha1, sha256, md5, mimetype, extra_json) - VALUES ($1, $2, $3, $4, $5, $6) - RETURNING id ), - ident AS ( INSERT INTO file_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) - RETURNING id ) - INSERT INTO file_edit (editgroup_id, ident_id, rev_id) VALUES - ($7, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) - RETURNING *", - ).bind::, _>(entity.size) - .bind::, _>(entity.sha1) - .bind::, _>(entity.sha256) - .bind::, _>(entity.md5) - .bind::, _>(entity.mimetype) - .bind::, _>(entity.extra) - .bind::(editgroup_id) - .get_result(conn)?; - - let _releases: Option> = match entity.releases { - None => None, - Some(release_list) => { - if release_list.is_empty() { - Some(vec![]) - } else { - let release_rows: Vec = release_list - .iter() - .map(|r| FileReleaseRow { - file_rev: edit.rev_id.unwrap(), - target_release_ident_id: fcid2uuid(r) - .expect("invalid fatcat identifier"), - }) - .collect(); - let release_rows: Vec = insert_into(file_release::table) - .values(release_rows) - .get_results(conn) - .expect("error inserting file_releases"); - Some(release_rows) - } - } - }; - - let _urls: Option> = match entity.urls { - None => None, - Some(url_list) => { - if url_list.is_empty() { - Some(vec![]) - } else { - let url_rows: Vec = url_list - .into_iter() - .map(|u| FileRevUrlNewRow { - file_rev: edit.rev_id.unwrap(), - rel: u.rel, - url: u.url, - }) - .collect(); - let url_rows: Vec = insert_into(file_rev_url::table) - .values(url_rows) - .get_results(conn) - .expect("error inserting file_rev_url"); - Some(url_rows) - } - } - }; - + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } - // XXX: pub fn update_file_handler( &self, id: &Uuid, entity: models::FileEntity, conn: &DbConn, ) -> Result { - unimplemented!() + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; + edit.into_model() } pub fn delete_file_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { - unimplemented!() + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit = FileEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; + edit.into_model() } pub fn create_release_handler( @@ -709,187 +321,25 @@ impl Server { entity: models::ReleaseEntity, conn: &DbConn, ) -> Result { - let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let editgroup_id = match entity.editgroup_id { - None => get_or_create_editgroup(editor_id, conn).expect("current editgroup"), - Some(param) => fcid2uuid(¶m)?, - }; - if let Some(ref extid) = entity.doi { - check_doi(extid)?; - } - if let Some(ref extid) = entity.pmid { - check_pmid(extid)?; - } - if let Some(ref extid) = entity.pmcid { - check_pmcid(extid)?; - } - if let Some(ref extid) = entity.wikidata_qid { - check_wikidata_qid(extid)?; - } - - let work_id = match entity.work_id { - Some(work_id) => fcid2uuid(&work_id)?, - None => { - // If a work_id wasn't passed, create a new work under the current editgroup - let work_model = models::WorkEntity { - ident: None, - revision: None, - redirect: None, - state: None, - editgroup_id: Some(uuid2fcid(&editgroup_id)), - extra: None, - }; - let new_entity = self.create_work_handler(work_model, conn)?; - fcid2uuid(&new_entity.ident)? - } - }; - - let container_id: Option = match entity.container_id { - Some(id) => Some(fcid2uuid(&id)?), - None => None, - }; - - let edit: ReleaseEditRow = diesel::sql_query( - "WITH rev AS ( INSERT INTO release_rev (title, release_type, release_status, release_date, doi, pmid, pmcid, wikidata_qid, isbn13, core_id, volume, issue, pages, work_ident_id, container_ident_id, publisher, language, extra_json) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18) - RETURNING id ), - ident AS ( INSERT INTO release_ident (rev_id) - VALUES ((SELECT rev.id FROM rev)) - RETURNING id ) - INSERT INTO release_edit (editgroup_id, ident_id, rev_id) VALUES - ($19, (SELECT ident.id FROM ident), (SELECT rev.id FROM rev)) - RETURNING *", - ).bind::(entity.title) - .bind::, _>(entity.release_type) - .bind::, _>(entity.release_status) - .bind::, _>( - entity.release_date.map(|v| v.naive_utc().date())) - .bind::, _>(entity.doi) - .bind::, _>(entity.pmid) - .bind::, _>(entity.pmcid) - .bind::, _>(entity.wikidata_qid) - .bind::, _>(entity.isbn13) - .bind::, _>(entity.core_id) - .bind::, _>(entity.volume) - .bind::, _>(entity.issue) - .bind::, _>(entity.pages) - .bind::(work_id) - .bind::, _>(container_id) - .bind::, _>(entity.publisher) - .bind::, _>(entity.language) - .bind::, _>(entity.extra) - .bind::(editgroup_id) - .get_result(conn)?; - - let _refs: Option> = match entity.refs { - None => None, - Some(ref_list) => { - if ref_list.is_empty() { - Some(vec![]) - } else { - let ref_rows: Vec = ref_list - .iter() - .map(|r| ReleaseRefNewRow { - release_rev: edit.rev_id.unwrap(), - target_release_ident_id: r.target_release_id - .clone() - .map(|v| fcid2uuid(&v).expect("valid fatcat identifier")), - index_val: r.index, - key: r.key.clone(), - container_title: r.container_title.clone(), - year: r.year, - title: r.title.clone(), - locator: r.locator.clone(), - extra_json: r.extra.clone(), - }) - .collect(); - let ref_rows: Vec = insert_into(release_ref::table) - .values(ref_rows) - .get_results(conn) - .expect("error inserting release_refs"); - Some(ref_rows) - } - } - }; - - let _contribs: Option> = match entity.contribs { - None => None, - Some(contrib_list) => { - if contrib_list.is_empty() { - Some(vec![]) - } else { - let contrib_rows: Vec = contrib_list - .iter() - .map(|c| ReleaseContribNewRow { - release_rev: edit.rev_id.unwrap(), - creator_ident_id: c.creator_id - .clone() - .map(|v| fcid2uuid(&v).expect("valid fatcat identifier")), - raw_name: c.raw_name.clone(), - index_val: c.index, - role: c.role.clone(), - extra_json: c.extra.clone(), - }) - .collect(); - let contrib_rows: Vec = insert_into(release_contrib::table) - .values(contrib_rows) - .get_results(conn) - .expect("error inserting release_contribs"); - Some(contrib_rows) - } - } - }; - - if let Some(abstract_list) = entity.abstracts { - // For rows that specify content, we need to insert the abstract if it doesn't exist - // already - let new_abstracts: Vec = abstract_list - .iter() - .filter(|ea| ea.content.is_some()) - .map(|c| AbstractsRow { - sha1: Sha1::from(c.content.clone().unwrap()).hexdigest(), - content: c.content.clone().unwrap(), - }) - .collect(); - if !new_abstracts.is_empty() { - // Sort of an "upsert"; only inserts new abstract rows if they don't already exist - insert_into(abstracts::table) - .values(&new_abstracts) - .on_conflict(abstracts::sha1) - .do_nothing() - .execute(conn)?; - } - let release_abstract_rows: Vec = abstract_list - .into_iter() - .map(|c| ReleaseRevAbstractNewRow { - release_rev: edit.rev_id.unwrap(), - abstract_sha1: match c.content { - Some(ref content) => Sha1::from(content).hexdigest(), - None => c.sha1.expect("either abstract_sha1 or content is required"), - }, - lang: c.lang, - mimetype: c.mimetype, - }) - .collect(); - insert_into(release_rev_abstract::table) - .values(release_abstract_rows) - .execute(conn)?; - } - + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } - // XXX: pub fn update_release_handler( &self, id: &Uuid, entity: models::ReleaseEntity, conn: &DbConn, ) -> Result { - unimplemented!() + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; + edit.into_model() } pub fn delete_release_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { - unimplemented!() + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit = ReleaseEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; + edit.into_model() } pub fn create_work_handler( @@ -1150,30 +600,33 @@ impl Server { } entity_batch_handler!( - create_container_handler, create_container_batch_handler, ContainerEntity ); entity_batch_handler!( - create_creator_handler, create_creator_batch_handler, CreatorEntity ); - entity_batch_handler!(create_file_handler, create_file_batch_handler, FileEntity); + entity_batch_handler!(create_file_batch_handler, FileEntity); entity_batch_handler!( - create_release_handler, create_release_batch_handler, ReleaseEntity ); - entity_batch_handler!(create_work_handler, create_work_batch_handler, WorkEntity); + entity_batch_handler!(create_work_batch_handler, WorkEntity); - entity_history_handler!( - get_container_history_handler, - ContainerEditRow, - container_edit - ); - entity_history_handler!(get_creator_history_handler, CreatorEditRow, creator_edit); - entity_history_handler!(get_file_history_handler, FileEditRow, file_edit); - entity_history_handler!(get_release_history_handler, ReleaseEditRow, release_edit); - entity_history_handler!(get_work_history_handler, WorkEditRow, work_edit); + pub fn get_container_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + ContainerEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) + } + pub fn get_creator_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + CreatorEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) + } + pub fn get_file_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + FileEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) + } + pub fn get_release_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + ReleaseEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) + } + pub fn get_work_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + WorkEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) + } } diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs index e97e134b..b8ff195a 100644 --- a/rust/src/database_entity_crud.rs +++ b/rust/src/database_entity_crud.rs @@ -1,11 +1,13 @@ +use sha1::Sha1; +use chrono; use diesel::prelude::*; use diesel::{self, insert_into}; use database_schema::*; use database_models::*; use errors::*; use fatcat_api::models::*; -use api_helpers::{FatCatId, DbConn}; +use api_helpers::*; use uuid::Uuid; use std::marker::Sized; use std::str::FromStr; @@ -55,7 +57,7 @@ pub trait EntityCrud where Self: Sized { fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option) -> Result>; // Entity-specific Methods - fn from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result; + fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result; fn db_insert_rev(&self, conn: &DbConn) -> Result; fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result>; } @@ -80,7 +82,7 @@ macro_rules! generic_db_get { .inner_join($rev_table::table) .first(conn)?; - Self::from_row(conn, rev, Some(ident)) + Self::db_from_row(conn, rev, Some(ident)) } } } @@ -92,12 +94,13 @@ macro_rules! generic_db_get_rev { .find(rev_id) .first(conn)?; - Self::from_row(conn, rev, None) + Self::db_from_row(conn, rev, None) } } } macro_rules! generic_db_create { + // TODO: this path should call generic_db_create_batch ($ident_table: ident, $edit_table: ident) => { fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result { let rev_id = self.db_insert_rev(conn)?; @@ -128,7 +131,7 @@ macro_rules! generic_db_create_batch { is_live: edit_context.autoapprove, redirect_id: None, }) - .collect::>()) + .collect::>()) .returning($ident_table::id) .get_results(conn)?; let edits: Vec = insert_into($edit_table::table) @@ -141,7 +144,7 @@ macro_rules! generic_db_create_batch { prev_rev: None, extra_json: edit_context.extra_json.clone(), }) - .collect::>()) + .collect::>()) .get_results(conn)?; Ok(edits) } @@ -209,7 +212,7 @@ macro_rules! generic_db_delete { macro_rules! generic_db_get_history { ($edit_table:ident) => { fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option) -> Result> { - let limit = limit.unwrap_or(50); // XXX: make a static + let limit = limit.unwrap_or(50); // TODO: make a static let rows: Vec<(EditgroupRow, ChangelogRow, Self::EditRow)> = editgroup::table .inner_join(changelog::table) @@ -239,6 +242,613 @@ macro_rules! generic_db_insert_rev { } } +impl EntityCrud for ContainerEntity { + type EditRow = ContainerEditRow; + type EditNewRow = ContainerEditNewRow; + type IdentRow = ContainerIdentRow; + type IdentNewRow = ContainerIdentNewRow; + type RevRow = ContainerRevRow; + + generic_parse_editgroup_id!(); + generic_db_get!(container_ident, container_rev); + generic_db_get_rev!(container_rev); + generic_db_create!(container_ident, container_edit); + generic_db_create_batch!(container_ident, container_edit); + generic_db_update!(container_ident, container_edit); + generic_db_delete!(container_ident, container_edit); + generic_db_get_history!(container_edit); + generic_db_insert_rev!(); + + fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + + let (state, ident_id, redirect_id) = match ident_row { + Some(i) => ( + Some(i.state().unwrap().shortname()), + Some(FatCatId::from_uuid(&i.id).to_string()), + i.redirect_id.map(|u| FatCatId::from_uuid(&u).to_string()), + ), + None => (None, None, None), + }; + + Ok(ContainerEntity { + issnl: rev_row.issnl, + wikidata_qid: rev_row.wikidata_qid, + publisher: rev_row.publisher, + name: rev_row.name, + abbrev: rev_row.abbrev, + coden: rev_row.coden, + state: state, + ident: ident_id, + revision: Some(rev_row.id.to_string()), + redirect: redirect_id, + extra: rev_row.extra_json, + editgroup_id: None, + }) + } + + fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { + + // first verify external identifier syntax + for entity in models { + if let Some(ref extid) = entity.wikidata_qid { + check_wikidata_qid(extid)?; + } + if let Some(ref extid) = entity.issnl { + check_issn(extid)?; + } + } + + let rev_ids: Vec = insert_into(container_rev::table) + .values(models.iter() + .map(|model| ContainerRevNewRow { + name: model.name.clone(), + publisher: model.publisher.clone(), + issnl: model.issnl.clone(), + wikidata_qid: model.wikidata_qid.clone(), + abbrev: model.abbrev.clone(), + coden: model.coden.clone(), + extra_json: model.extra.clone() + }) + .collect::>()) + .returning(container_rev::id) + .get_results(conn)?; + Ok(rev_ids) + } +} + +impl EntityCrud for CreatorEntity { + type EditRow = CreatorEditRow; + type EditNewRow = CreatorEditNewRow; + type IdentRow = CreatorIdentRow; + type IdentNewRow = CreatorIdentNewRow; + type RevRow = CreatorRevRow; + + generic_parse_editgroup_id!(); + generic_db_get!(creator_ident, creator_rev); + generic_db_get_rev!(creator_rev); + generic_db_create!(creator_ident, creator_edit); + generic_db_create_batch!(creator_ident, creator_edit); + generic_db_update!(creator_ident, creator_edit); + generic_db_delete!(creator_ident, creator_edit); + generic_db_get_history!(creator_edit); + generic_db_insert_rev!(); + + fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + let (state, ident_id, redirect_id) = match ident_row { + Some(i) => ( + Some(i.state().unwrap().shortname()), + Some(FatCatId::from_uuid(&i.id).to_string()), + i.redirect_id.map(|u| FatCatId::from_uuid(&u).to_string()), + ), + None => (None, None, None), + }; + Ok(CreatorEntity { + display_name: rev_row.display_name, + given_name: rev_row.given_name, + surname: rev_row.surname, + orcid: rev_row.orcid, + wikidata_qid: rev_row.wikidata_qid, + state: state, + ident: ident_id, + revision: Some(rev_row.id.to_string()), + redirect: redirect_id, + editgroup_id: None, + extra: rev_row.extra_json, + }) + } + + fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { + + // first verify external identifier syntax + for entity in models { + if let Some(ref extid) = entity.orcid { + check_orcid(extid)?; + } + if let Some(ref extid) = entity.wikidata_qid { + check_wikidata_qid(extid)?; + } + } + + let rev_ids: Vec = insert_into(creator_rev::table) + .values(models.iter() + .map(|model| CreatorRevNewRow { + display_name: model.display_name.clone(), + given_name: model.given_name.clone(), + surname: model.surname.clone(), + orcid: model.orcid.clone(), + wikidata_qid: model.wikidata_qid.clone(), + extra_json: model.extra.clone() + }) + .collect::>()) + .returning(creator_rev::id) + .get_results(conn)?; + Ok(rev_ids) + } +} + +impl EntityCrud for FileEntity { + type EditRow = FileEditRow; + type EditNewRow = FileEditNewRow; + type IdentRow = FileIdentRow; + type IdentNewRow = FileIdentNewRow; + type RevRow = FileRevRow; + + generic_parse_editgroup_id!(); + generic_db_get!(file_ident, file_rev); + generic_db_get_rev!(file_rev); + generic_db_create!(file_ident, file_edit); + generic_db_create_batch!(file_ident, file_edit); + generic_db_update!(file_ident, file_edit); + generic_db_delete!(file_ident, file_edit); + generic_db_get_history!(file_edit); + generic_db_insert_rev!(); + + fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + let (state, ident_id, redirect_id) = match ident_row { + Some(i) => ( + Some(i.state().unwrap().shortname()), + Some(FatCatId::from_uuid(&i.id).to_string()), + i.redirect_id.map(|u| FatCatId::from_uuid(&u).to_string()), + ), + None => (None, None, None), + }; + + let releases: Vec = file_release::table + .filter(file_release::file_rev.eq(rev_row.id)) + .get_results(conn)? + .into_iter() + .map(|r: FileReleaseRow| FatCatId::from_uuid(&r.target_release_ident_id)) + .collect(); + + let urls: Vec = file_rev_url::table + .filter(file_rev_url::file_rev.eq(rev_row.id)) + .get_results(conn)? + .into_iter() + .map(|r: FileRevUrlRow| FileEntityUrls { + rel: r.rel, + url: r.url, + }) + .collect(); + + Ok(FileEntity { + sha1: rev_row.sha1, + sha256: rev_row.sha256, + md5: rev_row.md5, + size: rev_row.size.map(|v| v as i64), + urls: Some(urls), + mimetype: rev_row.mimetype, + releases: Some(releases.iter().map(|fcid| fcid.to_string()).collect()), + state: state, + ident: ident_id, + revision: Some(rev_row.id.to_string()), + redirect: redirect_id, + editgroup_id: None, + extra: rev_row.extra_json, + }) + } + + fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { + + let rev_ids: Vec = insert_into(file_rev::table) + .values(models.iter() + .map(|model| FileRevNewRow { + size: model.size, + sha1: model.sha1.clone(), + sha256: model.sha256.clone(), + md5: model.md5.clone(), + mimetype: model.mimetype.clone(), + extra_json: model.extra.clone() + }) + .collect::>()) + .returning(file_rev::id) + .get_results(conn)?; + + let mut file_release_rows: Vec = vec![]; + let mut file_url_rows: Vec = vec![]; + + for (model, rev_id) in models.iter().zip(rev_ids.iter()) { + match &model.releases { + None => (), + Some(release_list) => { + let these_release_rows: Vec = release_list + .iter() + .map(|r| FileReleaseRow { + file_rev: rev_id.clone(), + target_release_ident_id: fcid2uuid(r) + // XXX: shouldn't expect + .expect("invalid fatcat identifier"), + }) + .collect(); + file_release_rows.extend(these_release_rows); + } + }; + + match &model.urls { + None => (), + Some(url_list) => { + let these_url_rows: Vec = url_list + .into_iter() + .map(|u| FileRevUrlNewRow { + file_rev: rev_id.clone(), + rel: u.rel.clone(), + url: u.url.clone(), + }) + .collect(); + file_url_rows.extend(these_url_rows); + } + }; + } + + if !file_release_rows.is_empty() { + // TODO: shouldn't it be "file_rev_release"? + insert_into(file_release::table) + .values(file_release_rows) + .execute(conn)?; + } + + if !file_url_rows.is_empty() { + insert_into(file_rev_url::table) + .values(file_url_rows) + .execute(conn)?; + } + + Ok(rev_ids) + } +} + +impl EntityCrud for ReleaseEntity { + type EditRow = ReleaseEditRow; + type EditNewRow = ReleaseEditNewRow; + type IdentRow = ReleaseIdentRow; + type IdentNewRow = ReleaseIdentNewRow; + type RevRow = ReleaseRevRow; + + generic_parse_editgroup_id!(); + generic_db_get!(release_ident, release_rev); + generic_db_get_rev!(release_rev); + //generic_db_create!(release_ident, release_edit); + //generic_db_create_batch!(release_ident, release_edit); + generic_db_update!(release_ident, release_edit); + generic_db_delete!(release_ident, release_edit); + generic_db_get_history!(release_edit); + generic_db_insert_rev!(); + + fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result { + let mut edits = Self::db_create_batch(conn, edit_context, &vec![self])?; + // probably a more elegant way to destroy the vec and take first element + Ok(edits.pop().unwrap()) + } + + fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result> { + // This isn't the generic implementation because we need to create Work entities for each + // of the release entities passed (at least in the common case) + + // Generate the set of new work entities to insert (usually one for each release, but some + // releases might be pointed to a work already) + let mut new_work_models: Vec<&WorkEntity> = vec![]; + for entity in models { + if entity.work_id.is_none() { + new_work_models.push(&WorkEntity { + ident: None, + revision: None, + redirect: None, + state: None, + editgroup_id: None, + extra: None, + }); + }; + } + + // create the works, then pluck the list of idents from the result + let new_work_edits = WorkEntity::db_create_batch(conn, edit_context, new_work_models.as_slice())?; + let mut new_work_ids: Vec = new_work_edits.iter().map(|edit| edit.ident_id).collect(); + + // Copy all the release models, and ensure that each has work_id set, using the new work + // idents. There should be one new work ident for each release missing one. + let models_with_work_ids: Vec = models.iter().map(|model| { + let mut model = (*model).clone(); + if model.work_id.is_none() { + model.work_id = Some(FatCatId::from_uuid(&new_work_ids.pop().unwrap()).to_string()) + } + model + }).collect(); + let model_refs: Vec<&Self> = models_with_work_ids.iter().map(|s| s).collect(); + let models = model_refs.as_slice(); + + // The rest here is copy/pasta from the generic (how to avoid copypasta?) + let rev_ids: Vec = Self::db_insert_revs(conn, models)?; + let ident_ids: Vec = insert_into(release_ident::table) + .values(rev_ids.iter() + .map(|rev_id| Self::IdentNewRow { + rev_id: Some(rev_id.clone()), + is_live: edit_context.autoapprove, + redirect_id: None, + }) + .collect::>()) + .returning(release_ident::id) + .get_results(conn)?; + let edits: Vec = insert_into(release_edit::table) + .values(rev_ids.into_iter().zip(ident_ids.into_iter()) + .map(|(rev_id, ident_id)| Self::EditNewRow { + editgroup_id: edit_context.editgroup_id.to_uuid(), + rev_id: Some(rev_id), + ident_id: ident_id, + redirect_id: None, + prev_rev: None, + extra_json: edit_context.extra_json.clone(), + }) + .collect::>()) + .get_results(conn)?; + Ok(edits) + } + + fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + let (state, ident_id, redirect_id) = match ident_row { + Some(i) => ( + Some(i.state().unwrap().shortname()), + Some(FatCatId::from_uuid(&i.id).to_string()), + i.redirect_id.map(|u| FatCatId::from_uuid(&u).to_string()), + ), + None => (None, None, None), + }; + + let refs: Vec = release_ref::table + .filter(release_ref::release_rev.eq(rev_row.id)) + .order(release_ref::index_val.asc()) + .get_results(conn) + .expect("fetch release refs") + .into_iter() + .map(|r: ReleaseRefRow| ReleaseRef { + index: r.index_val, + key: r.key, + extra: r.extra_json, + container_title: r.container_title, + year: r.year, + title: r.title, + locator: r.locator, + target_release_id: r.target_release_ident_id.map(|v| FatCatId::from_uuid(&v).to_string()), + }) + .collect(); + + let contribs: Vec = release_contrib::table + .filter(release_contrib::release_rev.eq(rev_row.id)) + .order(( + release_contrib::role.asc(), + release_contrib::index_val.asc(), + )) + .get_results(conn) + .expect("fetch release refs") + .into_iter() + .map(|c: ReleaseContribRow| ReleaseContrib { + index: c.index_val, + raw_name: c.raw_name, + role: c.role, + extra: c.extra_json, + creator_id: c.creator_ident_id.map(|v| FatCatId::from_uuid(&v).to_string()), + creator: None, + }) + .collect(); + + let abstracts: Vec = release_rev_abstract::table + .inner_join(abstracts::table) + .filter(release_rev_abstract::release_rev.eq(rev_row.id)) + .get_results(conn)? + .into_iter() + .map( + |r: (ReleaseRevAbstractRow, AbstractsRow)| ReleaseEntityAbstracts { + sha1: Some(r.0.abstract_sha1), + mimetype: r.0.mimetype, + lang: r.0.lang, + content: Some(r.1.content), + }, + ) + .collect(); + + Ok(ReleaseEntity { + title: rev_row.title, + release_type: rev_row.release_type, + release_status: rev_row.release_status, + release_date: rev_row.release_date + .map(|v| chrono::DateTime::from_utc(v.and_hms(0, 0, 0), chrono::Utc)), + doi: rev_row.doi, + pmid: rev_row.pmid, + pmcid: rev_row.pmcid, + isbn13: rev_row.isbn13, + core_id: rev_row.core_id, + wikidata_qid: rev_row.wikidata_qid, + volume: rev_row.volume, + issue: rev_row.issue, + pages: rev_row.pages, + files: None, + container: None, + container_id: rev_row.container_ident_id.map(|u| FatCatId::from_uuid(&u).to_string()), + publisher: rev_row.publisher, + language: rev_row.language, + work_id: Some(FatCatId::from_uuid(&rev_row.work_ident_id).to_string()), + refs: Some(refs), + contribs: Some(contribs), + abstracts: Some(abstracts), + state: state, + ident: ident_id, + revision: Some(rev_row.id.to_string()), + redirect: redirect_id, + editgroup_id: None, + extra: rev_row.extra_json, + }) + } + + fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { + + // first verify external identifier syntax + for entity in models { + if let Some(ref extid) = entity.doi { + check_doi(extid)?; + } + if let Some(ref extid) = entity.pmid { + check_pmid(extid)?; + } + if let Some(ref extid) = entity.pmcid { + check_pmcid(extid)?; + } + if let Some(ref extid) = entity.wikidata_qid { + check_wikidata_qid(extid)?; + } + } + + let rev_ids: Vec = insert_into(release_rev::table) + .values(models.iter() + .map(|model| ReleaseRevNewRow { + title: model.title.clone(), + release_type: model.release_type.clone(), + release_status: model.release_status.clone(), + release_date: model.release_date.map(|v| v.naive_utc().date()), + doi: model.doi.clone(), + pmid: model.pmid.clone(), + pmcid: model.pmcid.clone(), + wikidata_qid: model.wikidata_qid.clone(), + isbn13: model.isbn13.clone(), + core_id: model.core_id.clone(), + volume: model.volume.clone(), + issue: model.issue.clone(), + pages: model.pages.clone(), + work_ident_id: model.work_id + .clone() + .map(|s| FatCatId::from_str(&s).expect("invalid fatcat identifier").to_uuid()) + .expect("release_revs must have a work_id by the time they are inserted; this is an internal soundness error"), + container_ident_id: model.container_id + .clone() + .map(|s| FatCatId::from_str(&s).expect("invalid fatcat identifier").to_uuid()), + publisher: model.publisher.clone(), + language: model.language.clone(), + extra_json: model.extra.clone() + }) + .collect::>()) + .returning(release_rev::id) + .get_results(conn)?; + + let mut release_ref_rows: Vec = vec![]; + let mut release_contrib_rows: Vec = vec![]; + + for (model, rev_id) in models.iter().zip(rev_ids.iter()) { + match &model.refs { + None => (), + Some(ref_list) => { + let these_ref_rows: Vec = ref_list + .iter() + .map(|r| ReleaseRefNewRow { + release_rev: rev_id.clone(), + target_release_ident_id: r.target_release_id + .clone() + .map(|v| fcid2uuid(&v).expect("valid fatcat identifier")), + index_val: r.index, + key: r.key.clone(), + container_title: r.container_title.clone(), + year: r.year, + title: r.title.clone(), + locator: r.locator.clone(), + extra_json: r.extra.clone(), + }) + .collect(); + release_ref_rows.extend(these_ref_rows); + } + }; + + match &model.contribs { + None => (), + Some(contrib_list) => { + let these_contrib_rows: Vec = contrib_list + .iter() + .map(|c| ReleaseContribNewRow { + release_rev: rev_id.clone(), + creator_ident_id: c.creator_id + .clone() + // XXX: shouldn't have these expects + .map(|v| fcid2uuid(&v).expect("valid fatcat identifier")), + raw_name: c.raw_name.clone(), + index_val: c.index, + role: c.role.clone(), + extra_json: c.extra.clone(), + }) + .collect(); + release_contrib_rows.extend(these_contrib_rows); + } + }; + + // TODO: this part still isn't parallelized + if let Some(abstract_list) = &model.abstracts { + // For rows that specify content, we need to insert the abstract if it doesn't exist + // already + let new_abstracts: Vec = abstract_list + .iter() + .filter(|ea| ea.content.is_some()) + .map(|c| AbstractsRow { + sha1: Sha1::from(c.content.clone().unwrap()).hexdigest(), + content: c.content.clone().unwrap(), + }) + .collect(); + if !new_abstracts.is_empty() { + // Sort of an "upsert"; only inserts new abstract rows if they don't already exist + insert_into(abstracts::table) + .values(&new_abstracts) + .on_conflict(abstracts::sha1) + .do_nothing() + .execute(conn)?; + } + let release_abstract_rows: Vec = abstract_list + .into_iter() + .map(|c| ReleaseRevAbstractNewRow { + release_rev: rev_id.clone(), + abstract_sha1: match c.content { + Some(ref content) => Sha1::from(content).hexdigest(), + // XXX: shouldn't have these expects + None => c.sha1.clone().expect("either abstract_sha1 or content is required"), + }, + lang: c.lang.clone(), + mimetype: c.mimetype.clone(), + }) + .collect(); + insert_into(release_rev_abstract::table) + .values(release_abstract_rows) + .execute(conn)?; + } + } + + if !release_ref_rows.is_empty() { + insert_into(release_ref::table) + .values(release_ref_rows) + .execute(conn)?; + } + + if !release_contrib_rows.is_empty() { + insert_into(release_contrib::table) + .values(release_contrib_rows) + .execute(conn)?; + } + + Ok(rev_ids) + } +} + impl EntityCrud for WorkEntity { type EditRow = WorkEditRow; type EditNewRow = WorkEditNewRow; @@ -256,7 +866,7 @@ impl EntityCrud for WorkEntity { generic_db_get_history!(work_edit); generic_db_insert_rev!(); - fn from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index 14215a3c..2d6788eb 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -125,6 +125,18 @@ pub struct ContainerRevRow { pub coden: Option, } +#[derive(Debug, Associations, AsChangeset, Insertable)] +#[table_name = "container_rev"] +pub struct ContainerRevNewRow { + pub extra_json: Option, + pub name: String, + pub publisher: Option, + pub issnl: Option, + pub wikidata_qid: Option, + pub abbrev: Option, + pub coden: Option, +} + entity_structs!( "container_edit", ContainerEditRow, @@ -146,6 +158,17 @@ pub struct CreatorRevRow { pub wikidata_qid: Option, } +#[derive(Debug, Associations, AsChangeset, Insertable)] +#[table_name = "creator_rev"] +pub struct CreatorRevNewRow { + pub extra_json: Option, + pub display_name: String, + pub given_name: Option, + pub surname: Option, + pub orcid: Option, + pub wikidata_qid: Option, +} + entity_structs!( "creator_edit", CreatorEditRow, @@ -184,6 +207,17 @@ pub struct FileRevRow { pub mimetype: Option, } +#[derive(Debug, Associations, AsChangeset, Insertable)] +#[table_name = "file_rev"] +pub struct FileRevNewRow { + pub extra_json: Option, + pub size: Option, + pub sha1: Option, + pub sha256: Option, + pub md5: Option, + pub mimetype: Option, +} + entity_structs!("file_edit", FileEditRow, FileEditNewRow, "file_ident", FileIdentRow, FileIdentNewRow); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] @@ -210,6 +244,29 @@ pub struct ReleaseRevRow { pub language: Option, } +#[derive(Debug, Associations, AsChangeset, Insertable)] +#[table_name = "release_rev"] +pub struct ReleaseRevNewRow { + pub extra_json: Option, + pub work_ident_id: Uuid, + pub container_ident_id: Option, + pub title: String, + pub release_type: Option, + pub release_status: Option, + pub release_date: Option, + pub doi: Option, + pub pmid: Option, + pub pmcid: Option, + pub wikidata_qid: Option, + pub isbn13: Option, + pub core_id: Option, + pub volume: Option, + pub issue: Option, + pub pages: Option, + pub publisher: Option, + pub language: Option, +} + entity_structs!( "release_edit", ReleaseEditRow, -- cgit v1.2.3 From 20c5cf5a8b9acf98db7487ab49de8dcbc1ddb2f9 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 19:36:11 -0700 Subject: fix/replace a lot of expect() calls --- rust/TODO | 2 + rust/src/api_server.rs | 5 +-- rust/src/database_entity_crud.rs | 88 ++++++++++++++++++++-------------------- 3 files changed, 48 insertions(+), 47 deletions(-) (limited to 'rust') diff --git a/rust/TODO b/rust/TODO index 1ed580e6..ed38b915 100644 --- a/rust/TODO +++ b/rust/TODO @@ -1,4 +1,6 @@ +- fatcat_api -> fatcat_api_schema (or spec? models? types?) +- fatcat -> fatcat-api-server - refactor rev creation (from an entity) into it's own function, across the board => attach to database module structs? => should make cockroachdb compatible (single use of CTE) diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index ecf0c242..57aeebea 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -49,7 +49,7 @@ macro_rules! count_entity { fn make_edit_context(conn: &DbConn, editgroup_id: Option) -> Result { let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth let editgroup_id = match editgroup_id { - None => FatCatId::from_uuid(&get_or_create_editgroup(editor_id, conn).expect("current editgroup")), + None => FatCatId::from_uuid(&get_or_create_editgroup(editor_id, conn)?), Some(param) => param, }; Ok(EditContext { @@ -386,8 +386,7 @@ impl Server { editgroup::description.eq(entity.description), editgroup::extra_json.eq(entity.extra), )) - .get_result(conn) - .expect("error creating edit group"); + .get_result(conn)?; Ok(Editgroup { id: Some(uuid2fcid(&row.id)), diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs index b8ff195a..0f5c5f9d 100644 --- a/rust/src/database_entity_crud.rs +++ b/rust/src/database_entity_crud.rs @@ -222,14 +222,14 @@ macro_rules! generic_db_get_history { .limit(limit) .get_results(conn)?; - let history: Vec = rows.into_iter() - .map(|(eg_row, cl_row, e_row)| EntityHistoryEntry { - edit: e_row.into_model().expect("edit row to model"), + let history: Result> = rows.into_iter() + .map(|(eg_row, cl_row, e_row)| Ok(EntityHistoryEntry { + edit: e_row.into_model()?, editgroup: eg_row.into_model_partial(), changelog_entry: cl_row.into_model(), - }) + })) .collect(); - Ok(history) + history } } } @@ -470,16 +470,14 @@ impl EntityCrud for FileEntity { match &model.releases { None => (), Some(release_list) => { - let these_release_rows: Vec = release_list + let these_release_rows: Result> = release_list .iter() - .map(|r| FileReleaseRow { + .map(|r| Ok(FileReleaseRow { file_rev: rev_id.clone(), - target_release_ident_id: fcid2uuid(r) - // XXX: shouldn't expect - .expect("invalid fatcat identifier"), - }) + target_release_ident_id: FatCatId::from_str(r)?.to_uuid(), + })) .collect(); - file_release_rows.extend(these_release_rows); + file_release_rows.extend(these_release_rows?); } }; @@ -615,8 +613,7 @@ impl EntityCrud for ReleaseEntity { let refs: Vec = release_ref::table .filter(release_ref::release_rev.eq(rev_row.id)) .order(release_ref::index_val.asc()) - .get_results(conn) - .expect("fetch release refs") + .get_results(conn)? .into_iter() .map(|r: ReleaseRefRow| ReleaseRef { index: r.index_val, @@ -636,8 +633,7 @@ impl EntityCrud for ReleaseEntity { release_contrib::role.asc(), release_contrib::index_val.asc(), )) - .get_results(conn) - .expect("fetch release refs") + .get_results(conn)? .into_iter() .map(|c: ReleaseContribRow| ReleaseContrib { index: c.index_val, @@ -717,7 +713,7 @@ impl EntityCrud for ReleaseEntity { let rev_ids: Vec = insert_into(release_rev::table) .values(models.iter() - .map(|model| ReleaseRevNewRow { + .map(|model| Ok(ReleaseRevNewRow { title: model.title.clone(), release_type: model.release_type.clone(), release_status: model.release_status.clone(), @@ -731,18 +727,19 @@ impl EntityCrud for ReleaseEntity { volume: model.volume.clone(), issue: model.issue.clone(), pages: model.pages.clone(), - work_ident_id: model.work_id - .clone() - .map(|s| FatCatId::from_str(&s).expect("invalid fatcat identifier").to_uuid()) - .expect("release_revs must have a work_id by the time they are inserted; this is an internal soundness error"), - container_ident_id: model.container_id - .clone() - .map(|s| FatCatId::from_str(&s).expect("invalid fatcat identifier").to_uuid()), + work_ident_id: match model.work_id.clone() { + None => bail!("release_revs must have a work_id by the time they are inserted; this is an internal soundness error"), + Some(s) => FatCatId::from_str(&s)?.to_uuid(), + }, + container_ident_id: match model.container_id.clone() { + None => None, + Some(s) => Some(FatCatId::from_str(&s)?.to_uuid()), + }, publisher: model.publisher.clone(), language: model.language.clone(), extra_json: model.extra.clone() - }) - .collect::>()) + })) + .collect::>>()?) .returning(release_rev::id) .get_results(conn)?; @@ -755,11 +752,12 @@ impl EntityCrud for ReleaseEntity { Some(ref_list) => { let these_ref_rows: Vec = ref_list .iter() - .map(|r| ReleaseRefNewRow { + .map(|r| Ok(ReleaseRefNewRow { release_rev: rev_id.clone(), - target_release_ident_id: r.target_release_id - .clone() - .map(|v| fcid2uuid(&v).expect("valid fatcat identifier")), + target_release_ident_id: match r.target_release_id.clone() { + None => None, + Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), + }, index_val: r.index, key: r.key.clone(), container_title: r.container_title.clone(), @@ -767,8 +765,8 @@ impl EntityCrud for ReleaseEntity { title: r.title.clone(), locator: r.locator.clone(), extra_json: r.extra.clone(), - }) - .collect(); + })) + .collect::>>()?; release_ref_rows.extend(these_ref_rows); } }; @@ -778,18 +776,18 @@ impl EntityCrud for ReleaseEntity { Some(contrib_list) => { let these_contrib_rows: Vec = contrib_list .iter() - .map(|c| ReleaseContribNewRow { + .map(|c| Ok(ReleaseContribNewRow { release_rev: rev_id.clone(), - creator_ident_id: c.creator_id - .clone() - // XXX: shouldn't have these expects - .map(|v| fcid2uuid(&v).expect("valid fatcat identifier")), + creator_ident_id: match c.creator_id.clone() { + None => None, + Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), + }, raw_name: c.raw_name.clone(), index_val: c.index, role: c.role.clone(), extra_json: c.extra.clone(), - }) - .collect(); + })) + .collect::>>()?; release_contrib_rows.extend(these_contrib_rows); } }; @@ -816,17 +814,19 @@ impl EntityCrud for ReleaseEntity { } let release_abstract_rows: Vec = abstract_list .into_iter() - .map(|c| ReleaseRevAbstractNewRow { + .map(|c| Ok(ReleaseRevAbstractNewRow { release_rev: rev_id.clone(), abstract_sha1: match c.content { Some(ref content) => Sha1::from(content).hexdigest(), - // XXX: shouldn't have these expects - None => c.sha1.clone().expect("either abstract_sha1 or content is required"), + None => match c.sha1.clone() { + Some(v) => v, + None => { bail!("either abstract_sha1 or content is required") } + }, }, lang: c.lang.clone(), mimetype: c.mimetype.clone(), - }) - .collect(); + })) + .collect::>>()?; insert_into(release_rev_abstract::table) .values(release_abstract_rows) .execute(conn)?; -- cgit v1.2.3 From a74644fe121564fb130ef1978177a39cc574e25d Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 21:53:17 -0700 Subject: fmt --- rust/src/api_helpers.rs | 5 +- rust/src/api_server.rs | 93 +++++--- rust/src/database_entity_crud.rs | 442 ++++++++++++++++++++++++--------------- rust/src/database_models.rs | 29 ++- rust/src/lib.rs | 2 +- 5 files changed, 364 insertions(+), 207 deletions(-) (limited to 'rust') diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index 6c9a4e5f..fd0ad9e7 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -5,10 +5,11 @@ use diesel; use diesel::prelude::*; use errors::*; use regex::Regex; -use uuid::Uuid; use std::str::FromStr; +use uuid::Uuid; -pub type DbConn = diesel::r2d2::PooledConnection>; +pub type DbConn = + diesel::r2d2::PooledConnection>; /// This function should always be run within a transaction pub fn get_or_create_editgroup(editor_id: Uuid, conn: &PgConnection) -> Result { diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 602fbfb7..0e68777b 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -2,6 +2,7 @@ use api_helpers::*; use chrono; +use database_entity_crud::{EditContext, EntityCrud}; use database_models::*; use database_schema::{ abstracts, changelog, container_edit, container_ident, container_rev, creator_edit, @@ -15,10 +16,9 @@ use errors::*; use fatcat_api::models; use fatcat_api::models::*; use sha1::Sha1; +use std::str::FromStr; use uuid::Uuid; use ConnectionPool; -use database_entity_crud::{EntityCrud, EditContext}; -use std::str::FromStr; macro_rules! entity_batch_handler { ($post_batch_handler:ident, $model:ident) => { @@ -125,7 +125,6 @@ impl Server { _expand: Option, conn: &DbConn, ) -> Result { - CreatorEntity::db_get(conn, FatCatId::from_uuid(id)) } @@ -195,7 +194,6 @@ impl Server { expand: Option, conn: &DbConn, ) -> Result { - let mut release = ReleaseEntity::db_get(conn, FatCatId::from_uuid(id))?; // For now, if there is any expand param we do them all @@ -226,7 +224,6 @@ impl Server { } pub fn get_release_files_handler(&self, id: &str, conn: &DbConn) -> Result> { - let ident = FatCatId::from_str(id)?; let rows: Vec<(FileRevRow, FileIdentRow, FileReleaseRow)> = file_rev::table @@ -286,7 +283,12 @@ impl Server { let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } - pub fn delete_container_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + pub fn delete_container_handler( + &self, + id: &Uuid, + editgroup_id: Option, + conn: &DbConn, + ) -> Result { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = ContainerEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() @@ -300,7 +302,6 @@ impl Server { let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; let edit = entity.db_create(conn, &edit_context)?; edit.into_model() - } pub fn update_creator_handler( @@ -313,7 +314,12 @@ impl Server { let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } - pub fn delete_creator_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + pub fn delete_creator_handler( + &self, + id: &Uuid, + editgroup_id: Option, + conn: &DbConn, + ) -> Result { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = CreatorEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() @@ -339,7 +345,12 @@ impl Server { let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } - pub fn delete_file_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + pub fn delete_file_handler( + &self, + id: &Uuid, + editgroup_id: Option, + conn: &DbConn, + ) -> Result { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = FileEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() @@ -365,7 +376,12 @@ impl Server { let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } - pub fn delete_release_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + pub fn delete_release_handler( + &self, + id: &Uuid, + editgroup_id: Option, + conn: &DbConn, + ) -> Result { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = ReleaseEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() @@ -392,7 +408,12 @@ impl Server { edit.into_model() } - pub fn delete_work_handler(&self, id: &Uuid, editgroup_id: Option, conn: &DbConn) -> Result { + pub fn delete_work_handler( + &self, + id: &Uuid, + editgroup_id: Option, + conn: &DbConn, + ) -> Result { let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; let edit = WorkEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; @@ -627,34 +648,50 @@ impl Server { Ok(StatsResponse { extra: Some(val) }) } - entity_batch_handler!( - create_container_batch_handler, - ContainerEntity - ); - entity_batch_handler!( - create_creator_batch_handler, - CreatorEntity - ); + entity_batch_handler!(create_container_batch_handler, ContainerEntity); + entity_batch_handler!(create_creator_batch_handler, CreatorEntity); entity_batch_handler!(create_file_batch_handler, FileEntity); - entity_batch_handler!( - create_release_batch_handler, - ReleaseEntity - ); + entity_batch_handler!(create_release_batch_handler, ReleaseEntity); entity_batch_handler!(create_work_batch_handler, WorkEntity); - pub fn get_container_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + pub fn get_container_history_handler( + &self, + id: &Uuid, + limit: Option, + conn: &DbConn, + ) -> Result> { ContainerEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } - pub fn get_creator_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + pub fn get_creator_history_handler( + &self, + id: &Uuid, + limit: Option, + conn: &DbConn, + ) -> Result> { CreatorEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } - pub fn get_file_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + pub fn get_file_history_handler( + &self, + id: &Uuid, + limit: Option, + conn: &DbConn, + ) -> Result> { FileEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } - pub fn get_release_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + pub fn get_release_history_handler( + &self, + id: &Uuid, + limit: Option, + conn: &DbConn, + ) -> Result> { ReleaseEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } - pub fn get_work_history_handler(&self, id: &Uuid, limit: Option, conn: &DbConn,) -> Result> { + pub fn get_work_history_handler( + &self, + id: &Uuid, + limit: Option, + conn: &DbConn, + ) -> Result> { WorkEntity::db_get_history(conn, FatCatId::from_uuid(id), limit) } } diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs index 0f5c5f9d..3f13a27d 100644 --- a/rust/src/database_entity_crud.rs +++ b/rust/src/database_entity_crud.rs @@ -1,17 +1,16 @@ - -use sha1::Sha1; +use api_helpers::*; use chrono; +use database_models::*; +use database_schema::*; use diesel::prelude::*; use diesel::{self, insert_into}; -use database_schema::*; -use database_models::*; use errors::*; use fatcat_api::models::*; -use api_helpers::*; -use uuid::Uuid; +use serde_json; +use sha1::Sha1; use std::marker::Sized; use std::str::FromStr; -use serde_json; +use uuid::Uuid; pub struct EditContext { pub editor_id: FatCatId, @@ -37,7 +36,10 @@ pub struct EditContext { */ // Associated Type, not parametric -pub trait EntityCrud where Self: Sized { +pub trait EntityCrud +where + Self: Sized, +{ // TODO: could these be generic structs? Or do they need to be bound to a specific table? type EditRow; // EntityEditRow type EditNewRow; @@ -51,13 +53,34 @@ pub trait EntityCrud where Self: Sized { fn db_get(conn: &DbConn, ident: FatCatId) -> Result; fn db_get_rev(conn: &DbConn, rev_id: Uuid) -> Result; fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result; - fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result>; - fn db_update(&self, conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result; - fn db_delete(conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result; - fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option) -> Result>; + fn db_create_batch( + conn: &DbConn, + edit_context: &EditContext, + models: &[&Self], + ) -> Result>; + fn db_update( + &self, + conn: &DbConn, + edit_context: &EditContext, + ident: FatCatId, + ) -> Result; + fn db_delete( + conn: &DbConn, + edit_context: &EditContext, + ident: FatCatId, + ) -> Result; + fn db_get_history( + conn: &DbConn, + ident: FatCatId, + limit: Option, + ) -> Result>; // Entity-specific Methods - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result; + fn db_from_row( + conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option, + ) -> Result; fn db_insert_rev(&self, conn: &DbConn) -> Result; fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result>; } @@ -75,7 +98,7 @@ macro_rules! generic_parse_editgroup_id{ } macro_rules! generic_db_get { - ($ident_table: ident, $rev_table: ident) => { + ($ident_table:ident, $rev_table:ident) => { fn db_get(conn: &DbConn, ident: FatCatId) -> Result { let (ident, rev): (Self::IdentRow, Self::RevRow) = $ident_table::table .find(ident.to_uuid()) @@ -84,19 +107,17 @@ macro_rules! generic_db_get { Self::db_from_row(conn, rev, Some(ident)) } - } + }; } macro_rules! generic_db_get_rev { - ($rev_table: ident) => { + ($rev_table:ident) => { fn db_get_rev(conn: &DbConn, rev_id: Uuid) -> Result { - let rev = $rev_table::table - .find(rev_id) - .first(conn)?; - + let rev = $rev_table::table.find(rev_id).first(conn)?; + Self::db_from_row(conn, rev, None) } - } + }; } macro_rules! generic_db_create { @@ -121,34 +142,45 @@ macro_rules! generic_db_create { } macro_rules! generic_db_create_batch { - ($ident_table: ident, $edit_table: ident) => { - fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result> { + ($ident_table:ident, $edit_table:ident) => { + fn db_create_batch( + conn: &DbConn, + edit_context: &EditContext, + models: &[&Self], + ) -> Result> { let rev_ids: Vec = Self::db_insert_revs(conn, models)?; let ident_ids: Vec = insert_into($ident_table::table) - .values(rev_ids.iter() - .map(|rev_id| Self::IdentNewRow { - rev_id: Some(rev_id.clone()), - is_live: edit_context.autoapprove, - redirect_id: None, - }) - .collect::>()) + .values( + rev_ids + .iter() + .map(|rev_id| Self::IdentNewRow { + rev_id: Some(rev_id.clone()), + is_live: edit_context.autoapprove, + redirect_id: None, + }) + .collect::>(), + ) .returning($ident_table::id) .get_results(conn)?; let edits: Vec = insert_into($edit_table::table) - .values(rev_ids.into_iter().zip(ident_ids.into_iter()) - .map(|(rev_id, ident_id)| Self::EditNewRow { - editgroup_id: edit_context.editgroup_id.to_uuid(), - rev_id: Some(rev_id), - ident_id: ident_id, - redirect_id: None, - prev_rev: None, - extra_json: edit_context.extra_json.clone(), - }) - .collect::>()) + .values( + rev_ids + .into_iter() + .zip(ident_ids.into_iter()) + .map(|(rev_id, ident_id)| Self::EditNewRow { + editgroup_id: edit_context.editgroup_id.to_uuid(), + rev_id: Some(rev_id), + ident_id: ident_id, + redirect_id: None, + prev_rev: None, + extra_json: edit_context.extra_json.clone(), + }) + .collect::>(), + ) .get_results(conn)?; Ok(edits) } - } + }; } macro_rules! generic_db_update { @@ -181,9 +213,12 @@ macro_rules! generic_db_update { } macro_rules! generic_db_delete { - ($ident_table: ident, $edit_table:ident) => { - fn db_delete(conn: &DbConn, edit_context: &EditContext, ident: FatCatId) -> Result { - + ($ident_table:ident, $edit_table:ident) => { + fn db_delete( + conn: &DbConn, + edit_context: &EditContext, + ident: FatCatId, + ) -> Result { let current: Self::IdentRow = $ident_table::table.find(ident.to_uuid()).first(conn)?; if current.is_live != true { // TODO: what if isn't live? 4xx not 5xx @@ -206,12 +241,16 @@ macro_rules! generic_db_delete { Ok(edit) } - } + }; } macro_rules! generic_db_get_history { ($edit_table:ident) => { - fn db_get_history(conn: &DbConn, ident: FatCatId, limit: Option) -> Result> { + fn db_get_history( + conn: &DbConn, + ident: FatCatId, + limit: Option, + ) -> Result> { let limit = limit.unwrap_or(50); // TODO: make a static let rows: Vec<(EditgroupRow, ChangelogRow, Self::EditRow)> = editgroup::table @@ -223,15 +262,17 @@ macro_rules! generic_db_get_history { .get_results(conn)?; let history: Result> = rows.into_iter() - .map(|(eg_row, cl_row, e_row)| Ok(EntityHistoryEntry { - edit: e_row.into_model()?, - editgroup: eg_row.into_model_partial(), - changelog_entry: cl_row.into_model(), - })) + .map(|(eg_row, cl_row, e_row)| { + Ok(EntityHistoryEntry { + edit: e_row.into_model()?, + editgroup: eg_row.into_model_partial(), + changelog_entry: cl_row.into_model(), + }) + }) .collect(); history } - } + }; } macro_rules! generic_db_insert_rev { @@ -259,8 +300,11 @@ impl EntityCrud for ContainerEntity { generic_db_get_history!(container_edit); generic_db_insert_rev!(); - fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { - + fn db_from_row( + _conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option, + ) -> Result { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -287,7 +331,6 @@ impl EntityCrud for ContainerEntity { } fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { - // first verify external identifier syntax for entity in models { if let Some(ref extid) = entity.wikidata_qid { @@ -299,17 +342,20 @@ impl EntityCrud for ContainerEntity { } let rev_ids: Vec = insert_into(container_rev::table) - .values(models.iter() - .map(|model| ContainerRevNewRow { - name: model.name.clone(), - publisher: model.publisher.clone(), - issnl: model.issnl.clone(), - wikidata_qid: model.wikidata_qid.clone(), - abbrev: model.abbrev.clone(), - coden: model.coden.clone(), - extra_json: model.extra.clone() - }) - .collect::>()) + .values( + models + .iter() + .map(|model| ContainerRevNewRow { + name: model.name.clone(), + publisher: model.publisher.clone(), + issnl: model.issnl.clone(), + wikidata_qid: model.wikidata_qid.clone(), + abbrev: model.abbrev.clone(), + coden: model.coden.clone(), + extra_json: model.extra.clone(), + }) + .collect::>(), + ) .returning(container_rev::id) .get_results(conn)?; Ok(rev_ids) @@ -333,7 +379,11 @@ impl EntityCrud for CreatorEntity { generic_db_get_history!(creator_edit); generic_db_insert_rev!(); - fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + fn db_from_row( + _conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option, + ) -> Result { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -358,7 +408,6 @@ impl EntityCrud for CreatorEntity { } fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { - // first verify external identifier syntax for entity in models { if let Some(ref extid) = entity.orcid { @@ -370,16 +419,19 @@ impl EntityCrud for CreatorEntity { } let rev_ids: Vec = insert_into(creator_rev::table) - .values(models.iter() - .map(|model| CreatorRevNewRow { - display_name: model.display_name.clone(), - given_name: model.given_name.clone(), - surname: model.surname.clone(), - orcid: model.orcid.clone(), - wikidata_qid: model.wikidata_qid.clone(), - extra_json: model.extra.clone() - }) - .collect::>()) + .values( + models + .iter() + .map(|model| CreatorRevNewRow { + display_name: model.display_name.clone(), + given_name: model.given_name.clone(), + surname: model.surname.clone(), + orcid: model.orcid.clone(), + wikidata_qid: model.wikidata_qid.clone(), + extra_json: model.extra.clone(), + }) + .collect::>(), + ) .returning(creator_rev::id) .get_results(conn)?; Ok(rev_ids) @@ -403,7 +455,11 @@ impl EntityCrud for FileEntity { generic_db_get_history!(file_edit); generic_db_insert_rev!(); - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + fn db_from_row( + conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option, + ) -> Result { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -448,18 +504,20 @@ impl EntityCrud for FileEntity { } fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { - let rev_ids: Vec = insert_into(file_rev::table) - .values(models.iter() - .map(|model| FileRevNewRow { - size: model.size, - sha1: model.sha1.clone(), - sha256: model.sha256.clone(), - md5: model.md5.clone(), - mimetype: model.mimetype.clone(), - extra_json: model.extra.clone() - }) - .collect::>()) + .values( + models + .iter() + .map(|model| FileRevNewRow { + size: model.size, + sha1: model.sha1.clone(), + sha256: model.sha256.clone(), + md5: model.md5.clone(), + mimetype: model.mimetype.clone(), + extra_json: model.extra.clone(), + }) + .collect::>(), + ) .returning(file_rev::id) .get_results(conn)?; @@ -472,10 +530,12 @@ impl EntityCrud for FileEntity { Some(release_list) => { let these_release_rows: Result> = release_list .iter() - .map(|r| Ok(FileReleaseRow { - file_rev: rev_id.clone(), - target_release_ident_id: FatCatId::from_str(r)?.to_uuid(), - })) + .map(|r| { + Ok(FileReleaseRow { + file_rev: rev_id.clone(), + target_release_ident_id: FatCatId::from_str(r)?.to_uuid(), + }) + }) .collect(); file_release_rows.extend(these_release_rows?); } @@ -537,7 +597,11 @@ impl EntityCrud for ReleaseEntity { Ok(edits.pop().unwrap()) } - fn db_create_batch(conn: &DbConn, edit_context: &EditContext, models: &[&Self]) -> Result> { + fn db_create_batch( + conn: &DbConn, + edit_context: &EditContext, + models: &[&Self], + ) -> Result> { // This isn't the generic implementation because we need to create Work entities for each // of the release entities passed (at least in the common case) @@ -558,49 +622,65 @@ impl EntityCrud for ReleaseEntity { } // create the works, then pluck the list of idents from the result - let new_work_edits = WorkEntity::db_create_batch(conn, edit_context, new_work_models.as_slice())?; + let new_work_edits = + WorkEntity::db_create_batch(conn, edit_context, new_work_models.as_slice())?; let mut new_work_ids: Vec = new_work_edits.iter().map(|edit| edit.ident_id).collect(); // Copy all the release models, and ensure that each has work_id set, using the new work // idents. There should be one new work ident for each release missing one. - let models_with_work_ids: Vec = models.iter().map(|model| { - let mut model = (*model).clone(); - if model.work_id.is_none() { - model.work_id = Some(FatCatId::from_uuid(&new_work_ids.pop().unwrap()).to_string()) - } - model - }).collect(); + let models_with_work_ids: Vec = models + .iter() + .map(|model| { + let mut model = (*model).clone(); + if model.work_id.is_none() { + model.work_id = + Some(FatCatId::from_uuid(&new_work_ids.pop().unwrap()).to_string()) + } + model + }) + .collect(); let model_refs: Vec<&Self> = models_with_work_ids.iter().map(|s| s).collect(); let models = model_refs.as_slice(); // The rest here is copy/pasta from the generic (how to avoid copypasta?) let rev_ids: Vec = Self::db_insert_revs(conn, models)?; let ident_ids: Vec = insert_into(release_ident::table) - .values(rev_ids.iter() - .map(|rev_id| Self::IdentNewRow { - rev_id: Some(rev_id.clone()), - is_live: edit_context.autoapprove, - redirect_id: None, - }) - .collect::>()) + .values( + rev_ids + .iter() + .map(|rev_id| Self::IdentNewRow { + rev_id: Some(rev_id.clone()), + is_live: edit_context.autoapprove, + redirect_id: None, + }) + .collect::>(), + ) .returning(release_ident::id) .get_results(conn)?; let edits: Vec = insert_into(release_edit::table) - .values(rev_ids.into_iter().zip(ident_ids.into_iter()) - .map(|(rev_id, ident_id)| Self::EditNewRow { - editgroup_id: edit_context.editgroup_id.to_uuid(), - rev_id: Some(rev_id), - ident_id: ident_id, - redirect_id: None, - prev_rev: None, - extra_json: edit_context.extra_json.clone(), - }) - .collect::>()) + .values( + rev_ids + .into_iter() + .zip(ident_ids.into_iter()) + .map(|(rev_id, ident_id)| Self::EditNewRow { + editgroup_id: edit_context.editgroup_id.to_uuid(), + rev_id: Some(rev_id), + ident_id: ident_id, + redirect_id: None, + prev_rev: None, + extra_json: edit_context.extra_json.clone(), + }) + .collect::>(), + ) .get_results(conn)?; Ok(edits) } - fn db_from_row(conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { + fn db_from_row( + conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option, + ) -> Result { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -623,7 +703,8 @@ impl EntityCrud for ReleaseEntity { year: r.year, title: r.title, locator: r.locator, - target_release_id: r.target_release_ident_id.map(|v| FatCatId::from_uuid(&v).to_string()), + target_release_id: r.target_release_ident_id + .map(|v| FatCatId::from_uuid(&v).to_string()), }) .collect(); @@ -640,7 +721,8 @@ impl EntityCrud for ReleaseEntity { raw_name: c.raw_name, role: c.role, extra: c.extra_json, - creator_id: c.creator_ident_id.map(|v| FatCatId::from_uuid(&v).to_string()), + creator_id: c.creator_ident_id + .map(|v| FatCatId::from_uuid(&v).to_string()), creator: None, }) .collect(); @@ -664,7 +746,8 @@ impl EntityCrud for ReleaseEntity { title: rev_row.title, release_type: rev_row.release_type, release_status: rev_row.release_status, - release_date: rev_row.release_date + release_date: rev_row + .release_date .map(|v| chrono::DateTime::from_utc(v.and_hms(0, 0, 0), chrono::Utc)), doi: rev_row.doi, pmid: rev_row.pmid, @@ -677,7 +760,9 @@ impl EntityCrud for ReleaseEntity { pages: rev_row.pages, files: None, container: None, - container_id: rev_row.container_ident_id.map(|u| FatCatId::from_uuid(&u).to_string()), + container_id: rev_row + .container_ident_id + .map(|u| FatCatId::from_uuid(&u).to_string()), publisher: rev_row.publisher, language: rev_row.language, work_id: Some(FatCatId::from_uuid(&rev_row.work_ident_id).to_string()), @@ -694,7 +779,6 @@ impl EntityCrud for ReleaseEntity { } fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { - // first verify external identifier syntax for entity in models { if let Some(ref extid) = entity.doi { @@ -712,8 +796,10 @@ impl EntityCrud for ReleaseEntity { } let rev_ids: Vec = insert_into(release_rev::table) - .values(models.iter() - .map(|model| Ok(ReleaseRevNewRow { + .values(models + .iter() + .map(|model| { + Ok(ReleaseRevNewRow { title: model.title.clone(), release_type: model.release_type.clone(), release_status: model.release_status.clone(), @@ -738,7 +824,8 @@ impl EntityCrud for ReleaseEntity { publisher: model.publisher.clone(), language: model.language.clone(), extra_json: model.extra.clone() - })) + }) + }) .collect::>>()?) .returning(release_rev::id) .get_results(conn)?; @@ -752,20 +839,22 @@ impl EntityCrud for ReleaseEntity { Some(ref_list) => { let these_ref_rows: Vec = ref_list .iter() - .map(|r| Ok(ReleaseRefNewRow { - release_rev: rev_id.clone(), - target_release_ident_id: match r.target_release_id.clone() { - None => None, - Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), - }, - index_val: r.index, - key: r.key.clone(), - container_title: r.container_title.clone(), - year: r.year, - title: r.title.clone(), - locator: r.locator.clone(), - extra_json: r.extra.clone(), - })) + .map(|r| { + Ok(ReleaseRefNewRow { + release_rev: rev_id.clone(), + target_release_ident_id: match r.target_release_id.clone() { + None => None, + Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), + }, + index_val: r.index, + key: r.key.clone(), + container_title: r.container_title.clone(), + year: r.year, + title: r.title.clone(), + locator: r.locator.clone(), + extra_json: r.extra.clone(), + }) + }) .collect::>>()?; release_ref_rows.extend(these_ref_rows); } @@ -776,17 +865,19 @@ impl EntityCrud for ReleaseEntity { Some(contrib_list) => { let these_contrib_rows: Vec = contrib_list .iter() - .map(|c| Ok(ReleaseContribNewRow { - release_rev: rev_id.clone(), - creator_ident_id: match c.creator_id.clone() { - None => None, - Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), - }, - raw_name: c.raw_name.clone(), - index_val: c.index, - role: c.role.clone(), - extra_json: c.extra.clone(), - })) + .map(|c| { + Ok(ReleaseContribNewRow { + release_rev: rev_id.clone(), + creator_ident_id: match c.creator_id.clone() { + None => None, + Some(v) => Some(FatCatId::from_str(&v)?.to_uuid()), + }, + raw_name: c.raw_name.clone(), + index_val: c.index, + role: c.role.clone(), + extra_json: c.extra.clone(), + }) + }) .collect::>>()?; release_contrib_rows.extend(these_contrib_rows); } @@ -814,18 +905,20 @@ impl EntityCrud for ReleaseEntity { } let release_abstract_rows: Vec = abstract_list .into_iter() - .map(|c| Ok(ReleaseRevAbstractNewRow { - release_rev: rev_id.clone(), - abstract_sha1: match c.content { - Some(ref content) => Sha1::from(content).hexdigest(), - None => match c.sha1.clone() { - Some(v) => v, - None => { bail!("either abstract_sha1 or content is required") } + .map(|c| { + Ok(ReleaseRevAbstractNewRow { + release_rev: rev_id.clone(), + abstract_sha1: match c.content { + Some(ref content) => Sha1::from(content).hexdigest(), + None => match c.sha1.clone() { + Some(v) => v, + None => bail!("either abstract_sha1 or content is required"), + }, }, - }, - lang: c.lang.clone(), - mimetype: c.mimetype.clone(), - })) + lang: c.lang.clone(), + mimetype: c.mimetype.clone(), + }) + }) .collect::>>()?; insert_into(release_rev_abstract::table) .values(release_abstract_rows) @@ -866,8 +959,11 @@ impl EntityCrud for WorkEntity { generic_db_get_history!(work_edit); generic_db_insert_rev!(); - fn db_from_row(_conn: &DbConn, rev_row: Self::RevRow, ident_row: Option) -> Result { - + fn db_from_row( + _conn: &DbConn, + rev_row: Self::RevRow, + ident_row: Option, + ) -> Result { let (state, ident_id, redirect_id) = match ident_row { Some(i) => ( Some(i.state().unwrap().shortname()), @@ -889,12 +985,16 @@ impl EntityCrud for WorkEntity { fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result> { let rev_ids: Vec = insert_into(work_rev::table) - .values(models.iter() - .map(|model| WorkRevNewRow { extra_json: model.extra.clone() } ) - .collect::>()) + .values( + models + .iter() + .map(|model| WorkRevNewRow { + extra_json: model.extra.clone(), + }) + .collect::>(), + ) .returning(work_rev::id) .get_results(conn)?; Ok(rev_ids) } } - diff --git a/rust/src/database_models.rs b/rust/src/database_models.rs index 2d6788eb..93e6a0fe 100644 --- a/rust/src/database_models.rs +++ b/rust/src/database_models.rs @@ -37,9 +37,14 @@ pub trait EntityEditRow { // Helper for constructing tables macro_rules! entity_structs { - ($edit_table:expr, $edit_struct:ident, $edit_new_struct:ident, $ident_table:expr, - $ident_struct:ident, $ident_new_struct:ident) => { - + ( + $edit_table:expr, + $edit_struct:ident, + $edit_new_struct:ident, + $ident_table:expr, + $ident_struct:ident, + $ident_new_struct:ident + ) => { #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset, QueryableByName)] #[table_name = $edit_table] pub struct $edit_struct { @@ -218,7 +223,14 @@ pub struct FileRevNewRow { pub mimetype: Option, } -entity_structs!("file_edit", FileEditRow, FileEditNewRow, "file_ident", FileIdentRow, FileIdentNewRow); +entity_structs!( + "file_edit", + FileEditRow, + FileEditNewRow, + "file_ident", + FileIdentRow, + FileIdentNewRow +); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] #[table_name = "release_rev"] @@ -289,7 +301,14 @@ pub struct WorkRevNewRow { pub extra_json: Option, } -entity_structs!("work_edit", WorkEditRow, WorkEditNewRow, "work_ident", WorkIdentRow, WorkIdentNewRow); +entity_structs!( + "work_edit", + WorkEditRow, + WorkEditNewRow, + "work_ident", + WorkIdentRow, + WorkIdentNewRow +); #[derive(Debug, Queryable, Identifiable, Associations, AsChangeset)] #[table_name = "release_rev_abstract"] diff --git a/rust/src/lib.rs b/rust/src/lib.rs index a938486b..38f9b343 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -25,9 +25,9 @@ extern crate sha1; pub mod api_helpers; pub mod api_server; pub mod api_wrappers; +pub mod database_entity_crud; pub mod database_models; pub mod database_schema; -pub mod database_entity_crud; mod errors { // Create the Error, ErrorKind, ResultExt, and Result types -- cgit v1.2.3 From a6c487aa9767624519bb4fa01a3cc3df254cfc70 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 21:53:36 -0700 Subject: re-codegen --- rust/fatcat-api/README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/fatcat-api/README.md b/rust/fatcat-api/README.md index 4be4939f..c971b88c 100644 --- a/rust/fatcat-api/README.md +++ b/rust/fatcat-api/README.md @@ -13,7 +13,7 @@ To see how to make this your own, look here: [README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) - API version: 0.1.0 -- Build date: 2018-09-01T01:21:49.948Z +- Build date: 2018-09-08T04:52:59.479Z This autogenerated project defines an API crate `fatcat` which contains: * An `Api` trait defining the API in Rust. @@ -68,6 +68,11 @@ cargo run --example client CreateRelease cargo run --example client CreateReleaseBatch cargo run --example client CreateWork cargo run --example client CreateWorkBatch +cargo run --example client DeleteContainer +cargo run --example client DeleteCreator +cargo run --example client DeleteFile +cargo run --example client DeleteRelease +cargo run --example client DeleteWork cargo run --example client GetChangelog cargo run --example client GetChangelogEntry cargo run --example client GetContainer @@ -91,6 +96,11 @@ cargo run --example client LookupContainer cargo run --example client LookupCreator cargo run --example client LookupFile cargo run --example client LookupRelease +cargo run --example client UpdateContainer +cargo run --example client UpdateCreator +cargo run --example client UpdateFile +cargo run --example client UpdateRelease +cargo run --example client UpdateWork ``` ### HTTPS -- cgit v1.2.3 From fc2025b8db9e058d429136f382749ade52df326c Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 22:32:20 -0700 Subject: fixes after autoaccept merge --- rust/src/api_helpers.rs | 1 + rust/src/api_server.rs | 79 ++++++++++++++++++---------------------- rust/src/api_wrappers.rs | 2 +- rust/src/database_entity_crud.rs | 8 ++-- 4 files changed, 41 insertions(+), 49 deletions(-) (limited to 'rust') diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs index fd0ad9e7..925a6073 100644 --- a/rust/src/api_helpers.rs +++ b/rust/src/api_helpers.rs @@ -91,6 +91,7 @@ pub fn accept_editgroup(editgroup_id: Uuid, conn: &PgConnection) -> Result, conn: &DbConn, ) -> Result> { - // editgroup override logic based on parameters - let eg_id: Option = match (editgroup, autoaccept) { - (Some(eg_string), _) => Some(fcid2uuid(&eg_string)?), - (None, true) => { - let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) - .values((editgroup::editor_id.eq(editor_id),)) - .get_result(conn)?; - Some(eg_row.id) - }, - (None, false) => None + + let editgroup_id: Option = match editgroup { + Some(s) => Some(FatCatId::from_str(&s)?), + None => None, }; - for entity in entity_list { - let mut e = entity.clone(); - // override individual editgroup IDs (if set earlier) - if let Some(inner_id) = eg_id { - e.editgroup_id = Some(uuid2fcid(&inner_id)); - } - // actual wrapped function call here - ret.push(self.$post_handler(e, autoaccept, conn)?); - } - let mut edit_context = make_edit_context(conn, eg_id)?; - edit_context.autoaccept = autoaccept; + let edit_context = make_edit_context(conn, editgroup_id.clone(), autoaccept)?; let model_list: Vec<&models::$model> = entity_list.iter().map(|e| e).collect(); let edits = $model::db_create_batch(conn, &edit_context, model_list.as_slice())?; + if autoaccept { - // if autoaccept, eg_id is always Some let _clr: ChangelogRow = diesel::insert_into(changelog::table) - .values((changelog::editgroup_id.eq(eg_id.unwrap()),)) + // if autoaccept, eg_id is always Some + .values((changelog::editgroup_id.eq(edit_context.editgroup_id.to_uuid()),)) .get_result(conn)?; } edits.into_iter().map(|e| e.into_model()).collect() @@ -75,17 +59,24 @@ macro_rules! count_entity { }}; } -fn make_edit_context(conn: &DbConn, editgroup_id: Option) -> Result { +fn make_edit_context(conn: &DbConn, editgroup_id: Option, autoaccept: bool) -> Result { let editor_id = Uuid::parse_str("00000000-0000-0000-AAAA-000000000001")?; // TODO: auth - let editgroup_id = match editgroup_id { - None => FatCatId::from_uuid(&get_or_create_editgroup(editor_id, conn)?), - Some(param) => param, + let editgroup_id: FatCatId = match (editgroup_id, autoaccept) { + (Some(eg), _) => eg, + // If autoaccept and no editgroup_id passed, always create a new one for this transaction + (None, true) => { + let eg_row: EditgroupRow = diesel::insert_into(editgroup::table) + .values((editgroup::editor_id.eq(editor_id),)) + .get_result(conn)?; + FatCatId::from_uuid(&eg_row.id) + }, + (None, false) => FatCatId::from_uuid(&get_or_create_editgroup(editor_id, conn)?), }; Ok(EditContext { editor_id: FatCatId::from_uuid(&editor_id), editgroup_id: editgroup_id, extra_json: None, - autoapprove: false, + autoaccept: autoaccept, }) } @@ -268,7 +259,7 @@ impl Server { entity: models::ContainerEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } @@ -279,7 +270,7 @@ impl Server { entity: models::ContainerEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -289,7 +280,7 @@ impl Server { editgroup_id: Option, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?; let edit = ContainerEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -299,7 +290,7 @@ impl Server { entity: models::CreatorEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } @@ -310,7 +301,7 @@ impl Server { entity: models::CreatorEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -320,7 +311,7 @@ impl Server { editgroup_id: Option, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?; let edit = CreatorEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -330,7 +321,7 @@ impl Server { entity: models::FileEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } @@ -341,7 +332,7 @@ impl Server { entity: models::FileEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -351,7 +342,7 @@ impl Server { editgroup_id: Option, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?; let edit = FileEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -361,7 +352,7 @@ impl Server { entity: models::ReleaseEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } @@ -372,7 +363,7 @@ impl Server { entity: models::ReleaseEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -382,7 +373,7 @@ impl Server { editgroup_id: Option, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?; let edit = ReleaseEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -392,7 +383,7 @@ impl Server { entity: models::WorkEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_create(conn, &edit_context)?; edit.into_model() } @@ -403,7 +394,7 @@ impl Server { entity: models::WorkEntity, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?)?; + let edit_context = make_edit_context(conn, entity.parse_editgroup_id()?, false)?; let edit = entity.db_update(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() } @@ -414,7 +405,7 @@ impl Server { editgroup_id: Option, conn: &DbConn, ) -> Result { - let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)))?; + let edit_context = make_edit_context(conn, editgroup_id.map(|u| FatCatId::from_uuid(&u)), false)?; let edit = WorkEntity::db_delete(conn, &edit_context, FatCatId::from_uuid(id))?; edit.into_model() diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs index 6272814e..faafe984 100644 --- a/rust/src/api_wrappers.rs +++ b/rust/src/api_wrappers.rs @@ -61,7 +61,7 @@ macro_rules! wrap_entity_handlers { _context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); - let ret = match conn.transaction(|| self.$post_handler(entity, false, &conn)) { + let ret = match conn.transaction(|| self.$post_handler(entity, &conn)) { Ok(edit) => $post_resp::CreatedEntity(edit), Err(Error(ErrorKind::Diesel(e), _)) => diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs index 3f13a27d..9a47c2de 100644 --- a/rust/src/database_entity_crud.rs +++ b/rust/src/database_entity_crud.rs @@ -3,7 +3,7 @@ use chrono; use database_models::*; use database_schema::*; use diesel::prelude::*; -use diesel::{self, insert_into}; +use diesel::insert_into; use errors::*; use fatcat_api::models::*; use serde_json; @@ -16,7 +16,7 @@ pub struct EditContext { pub editor_id: FatCatId, pub editgroup_id: FatCatId, pub extra_json: Option, - pub autoapprove: bool, + pub autoaccept: bool, } /* One goal here is to abstract the non-entity-specific bits into generic traits or functions, @@ -155,7 +155,7 @@ macro_rules! generic_db_create_batch { .iter() .map(|rev_id| Self::IdentNewRow { rev_id: Some(rev_id.clone()), - is_live: edit_context.autoapprove, + is_live: edit_context.autoaccept, redirect_id: None, }) .collect::>(), @@ -650,7 +650,7 @@ impl EntityCrud for ReleaseEntity { .iter() .map(|rev_id| Self::IdentNewRow { rev_id: Some(rev_id.clone()), - is_live: edit_context.autoapprove, + is_live: edit_context.autoaccept, redirect_id: None, }) .collect::>(), -- cgit v1.2.3 From 7354899493f6448bed5698ad6ade1dbebcf39379 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Fri, 7 Sep 2018 22:37:09 -0700 Subject: TODO and comment --- python/README_codegen.md | 10 + python/fatcat_client/api/default_api.py | 1948 ++++++++++++++++++------ python/tests/codegen_tests/test_default_api.py | 60 + rust/TODO | 2 + rust/src/api_server.rs | 1 - 5 files changed, 1561 insertions(+), 460 deletions(-) (limited to 'rust') diff --git a/python/README_codegen.md b/python/README_codegen.md index 393fae32..0d072dde 100644 --- a/python/README_codegen.md +++ b/python/README_codegen.md @@ -80,6 +80,11 @@ Class | Method | HTTP request | Description *DefaultApi* | [**create_release_batch**](docs/DefaultApi.md#create_release_batch) | **POST** /release/batch | *DefaultApi* | [**create_work**](docs/DefaultApi.md#create_work) | **POST** /work | *DefaultApi* | [**create_work_batch**](docs/DefaultApi.md#create_work_batch) | **POST** /work/batch | +*DefaultApi* | [**delete_container**](docs/DefaultApi.md#delete_container) | **DELETE** /container/{id} | +*DefaultApi* | [**delete_creator**](docs/DefaultApi.md#delete_creator) | **DELETE** /creator/{id} | +*DefaultApi* | [**delete_file**](docs/DefaultApi.md#delete_file) | **DELETE** /file/{id} | +*DefaultApi* | [**delete_release**](docs/DefaultApi.md#delete_release) | **DELETE** /release/{id} | +*DefaultApi* | [**delete_work**](docs/DefaultApi.md#delete_work) | **DELETE** /work/{id} | *DefaultApi* | [**get_changelog**](docs/DefaultApi.md#get_changelog) | **GET** /changelog | *DefaultApi* | [**get_changelog_entry**](docs/DefaultApi.md#get_changelog_entry) | **GET** /changelog/{id} | *DefaultApi* | [**get_container**](docs/DefaultApi.md#get_container) | **GET** /container/{id} | @@ -103,6 +108,11 @@ Class | Method | HTTP request | Description *DefaultApi* | [**lookup_creator**](docs/DefaultApi.md#lookup_creator) | **GET** /creator/lookup | *DefaultApi* | [**lookup_file**](docs/DefaultApi.md#lookup_file) | **GET** /file/lookup | *DefaultApi* | [**lookup_release**](docs/DefaultApi.md#lookup_release) | **GET** /release/lookup | +*DefaultApi* | [**update_container**](docs/DefaultApi.md#update_container) | **PUT** /container/{id} | +*DefaultApi* | [**update_creator**](docs/DefaultApi.md#update_creator) | **PUT** /creator/{id} | +*DefaultApi* | [**update_file**](docs/DefaultApi.md#update_file) | **PUT** /file/{id} | +*DefaultApi* | [**update_release**](docs/DefaultApi.md#update_release) | **PUT** /release/{id} | +*DefaultApi* | [**update_work**](docs/DefaultApi.md#update_work) | **PUT** /work/{id} | ## Documentation For Models diff --git a/python/fatcat_client/api/default_api.py b/python/fatcat_client/api/default_api.py index a0298750..23c8d7ca 100644 --- a/python/fatcat_client/api/default_api.py +++ b/python/fatcat_client/api/default_api.py @@ -1245,43 +1245,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_changelog(self, **kwargs): # noqa: E501 - """get_changelog # noqa: E501 + def delete_container(self, id, **kwargs): # noqa: E501 + """delete_container # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_changelog(async=True) + >>> thread = api.delete_container(id, async=True) >>> result = thread.get() :param async bool - :param int limit: - :return: list[ChangelogEntry] + :param str id: (required) + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_changelog_with_http_info(**kwargs) # noqa: E501 + return self.delete_container_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_changelog_with_http_info(**kwargs) # noqa: E501 + (data) = self.delete_container_with_http_info(id, **kwargs) # noqa: E501 return data - def get_changelog_with_http_info(self, **kwargs): # noqa: E501 - """get_changelog # noqa: E501 + def delete_container_with_http_info(self, id, **kwargs): # noqa: E501 + """delete_container # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_changelog_with_http_info(async=True) + >>> thread = api.delete_container_with_http_info(id, async=True) >>> result = thread.get() :param async bool - :param int limit: - :return: list[ChangelogEntry] + :param str id: (required) + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['limit'] # noqa: E501 + all_params = ['id', 'editgroup'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -1292,18 +1294,24 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_changelog" % key + " to method delete_container" % key ) params[key] = val del params['kwargs'] + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `delete_container`") # noqa: E501 collection_formats = {} path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'limit' in params: - query_params.append(('limit', params['limit'])) # noqa: E501 + if 'editgroup' in params: + query_params.append(('editgroup', params['editgroup'])) # noqa: E501 header_params = {} @@ -1323,14 +1331,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/changelog', 'GET', + '/container/{id}', 'DELETE', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[ChangelogEntry]', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -1338,43 +1346,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_changelog_entry(self, id, **kwargs): # noqa: E501 - """get_changelog_entry # noqa: E501 + def delete_creator(self, id, **kwargs): # noqa: E501 + """delete_creator # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_changelog_entry(id, async=True) + >>> thread = api.delete_creator(id, async=True) >>> result = thread.get() :param async bool - :param int id: (required) - :return: ChangelogEntry + :param str id: (required) + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_changelog_entry_with_http_info(id, **kwargs) # noqa: E501 + return self.delete_creator_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_changelog_entry_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.delete_creator_with_http_info(id, **kwargs) # noqa: E501 return data - def get_changelog_entry_with_http_info(self, id, **kwargs): # noqa: E501 - """get_changelog_entry # noqa: E501 + def delete_creator_with_http_info(self, id, **kwargs): # noqa: E501 + """delete_creator # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_changelog_entry_with_http_info(id, async=True) + >>> thread = api.delete_creator_with_http_info(id, async=True) >>> result = thread.get() :param async bool - :param int id: (required) - :return: ChangelogEntry + :param str id: (required) + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['id'] # noqa: E501 + all_params = ['id', 'editgroup'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -1385,14 +1395,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_changelog_entry" % key + " to method delete_creator" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_changelog_entry`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `delete_creator`") # noqa: E501 collection_formats = {} @@ -1401,6 +1411,8 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] + if 'editgroup' in params: + query_params.append(('editgroup', params['editgroup'])) # noqa: E501 header_params = {} @@ -1420,14 +1432,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/changelog/{id}', 'GET', + '/creator/{id}', 'DELETE', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='ChangelogEntry', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -1435,45 +1447,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_container(self, id, **kwargs): # noqa: E501 - """get_container # noqa: E501 + def delete_file(self, id, **kwargs): # noqa: E501 + """delete_file # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_container(id, async=True) + >>> thread = api.delete_file(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: ContainerEntity + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_container_with_http_info(id, **kwargs) # noqa: E501 + return self.delete_file_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_container_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.delete_file_with_http_info(id, **kwargs) # noqa: E501 return data - def get_container_with_http_info(self, id, **kwargs): # noqa: E501 - """get_container # noqa: E501 + def delete_file_with_http_info(self, id, **kwargs): # noqa: E501 + """delete_file # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_container_with_http_info(id, async=True) + >>> thread = api.delete_file_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: ContainerEntity + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'expand'] # noqa: E501 + all_params = ['id', 'editgroup'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -1484,14 +1496,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_container" % key + " to method delete_file" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_container`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `delete_file`") # noqa: E501 collection_formats = {} @@ -1500,8 +1512,8 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'expand' in params: - query_params.append(('expand', params['expand'])) # noqa: E501 + if 'editgroup' in params: + query_params.append(('editgroup', params['editgroup'])) # noqa: E501 header_params = {} @@ -1521,14 +1533,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/container/{id}', 'GET', + '/file/{id}', 'DELETE', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='ContainerEntity', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -1536,45 +1548,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_container_history(self, id, **kwargs): # noqa: E501 - """get_container_history # noqa: E501 + def delete_release(self, id, **kwargs): # noqa: E501 + """delete_release # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_container_history(id, async=True) + >>> thread = api.delete_release(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param int limit: - :return: list[EntityHistoryEntry] + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_container_history_with_http_info(id, **kwargs) # noqa: E501 + return self.delete_release_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_container_history_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.delete_release_with_http_info(id, **kwargs) # noqa: E501 return data - def get_container_history_with_http_info(self, id, **kwargs): # noqa: E501 - """get_container_history # noqa: E501 + def delete_release_with_http_info(self, id, **kwargs): # noqa: E501 + """delete_release # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_container_history_with_http_info(id, async=True) + >>> thread = api.delete_release_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param int limit: - :return: list[EntityHistoryEntry] + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'limit'] # noqa: E501 + all_params = ['id', 'editgroup'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -1585,14 +1597,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_container_history" % key + " to method delete_release" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_container_history`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `delete_release`") # noqa: E501 collection_formats = {} @@ -1601,8 +1613,8 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'limit' in params: - query_params.append(('limit', params['limit'])) # noqa: E501 + if 'editgroup' in params: + query_params.append(('editgroup', params['editgroup'])) # noqa: E501 header_params = {} @@ -1622,14 +1634,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/container/{id}/history', 'GET', + '/release/{id}', 'DELETE', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[EntityHistoryEntry]', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -1637,45 +1649,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_creator(self, id, **kwargs): # noqa: E501 - """get_creator # noqa: E501 + def delete_work(self, id, **kwargs): # noqa: E501 + """delete_work # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_creator(id, async=True) + >>> thread = api.delete_work(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: CreatorEntity + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_creator_with_http_info(id, **kwargs) # noqa: E501 + return self.delete_work_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_creator_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.delete_work_with_http_info(id, **kwargs) # noqa: E501 return data - def get_creator_with_http_info(self, id, **kwargs): # noqa: E501 - """get_creator # noqa: E501 + def delete_work_with_http_info(self, id, **kwargs): # noqa: E501 + """delete_work # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_creator_with_http_info(id, async=True) + >>> thread = api.delete_work_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: CreatorEntity + :param str editgroup: + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'expand'] # noqa: E501 + all_params = ['id', 'editgroup'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -1686,14 +1698,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_creator" % key + " to method delete_work" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_creator`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `delete_work`") # noqa: E501 collection_formats = {} @@ -1702,8 +1714,8 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'expand' in params: - query_params.append(('expand', params['expand'])) # noqa: E501 + if 'editgroup' in params: + query_params.append(('editgroup', params['editgroup'])) # noqa: E501 header_params = {} @@ -1723,14 +1735,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/creator/{id}', 'GET', + '/work/{id}', 'DELETE', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='CreatorEntity', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -1738,45 +1750,43 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_creator_history(self, id, **kwargs): # noqa: E501 - """get_creator_history # noqa: E501 + def get_changelog(self, **kwargs): # noqa: E501 + """get_changelog # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_creator_history(id, async=True) + >>> thread = api.get_changelog(async=True) >>> result = thread.get() :param async bool - :param str id: (required) :param int limit: - :return: list[EntityHistoryEntry] + :return: list[ChangelogEntry] If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_creator_history_with_http_info(id, **kwargs) # noqa: E501 + return self.get_changelog_with_http_info(**kwargs) # noqa: E501 else: - (data) = self.get_creator_history_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_changelog_with_http_info(**kwargs) # noqa: E501 return data - def get_creator_history_with_http_info(self, id, **kwargs): # noqa: E501 - """get_creator_history # noqa: E501 + def get_changelog_with_http_info(self, **kwargs): # noqa: E501 + """get_changelog # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_creator_history_with_http_info(id, async=True) + >>> thread = api.get_changelog_with_http_info(async=True) >>> result = thread.get() :param async bool - :param str id: (required) :param int limit: - :return: list[EntityHistoryEntry] + :return: list[ChangelogEntry] If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'limit'] # noqa: E501 + all_params = ['limit'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -1787,20 +1797,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_creator_history" % key + " to method get_changelog" % key ) params[key] = val del params['kwargs'] - # verify the required parameter 'id' is set - if ('id' not in params or - params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_creator_history`") # noqa: E501 collection_formats = {} path_params = {} - if 'id' in params: - path_params['id'] = params['id'] # noqa: E501 query_params = [] if 'limit' in params: @@ -1824,14 +1828,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/creator/{id}/history', 'GET', + '/changelog', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[EntityHistoryEntry]', # noqa: E501 + response_type='list[ChangelogEntry]', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -1839,38 +1843,38 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_creator_releases(self, id, **kwargs): # noqa: E501 - """get_creator_releases # noqa: E501 + def get_changelog_entry(self, id, **kwargs): # noqa: E501 + """get_changelog_entry # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_creator_releases(id, async=True) + >>> thread = api.get_changelog_entry(id, async=True) >>> result = thread.get() :param async bool - :param str id: (required) - :return: list[ReleaseEntity] + :param int id: (required) + :return: ChangelogEntry If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_creator_releases_with_http_info(id, **kwargs) # noqa: E501 + return self.get_changelog_entry_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_creator_releases_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_changelog_entry_with_http_info(id, **kwargs) # noqa: E501 return data - def get_creator_releases_with_http_info(self, id, **kwargs): # noqa: E501 - """get_creator_releases # noqa: E501 + def get_changelog_entry_with_http_info(self, id, **kwargs): # noqa: E501 + """get_changelog_entry # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_creator_releases_with_http_info(id, async=True) + >>> thread = api.get_changelog_entry_with_http_info(id, async=True) >>> result = thread.get() :param async bool - :param str id: (required) - :return: list[ReleaseEntity] + :param int id: (required) + :return: ChangelogEntry If the method is called asynchronously, returns the request thread. """ @@ -1886,14 +1890,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_creator_releases" % key + " to method get_changelog_entry" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_creator_releases`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_changelog_entry`") # noqa: E501 collection_formats = {} @@ -1921,14 +1925,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/creator/{id}/releases', 'GET', + '/changelog/{id}', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[ReleaseEntity]', # noqa: E501 + response_type='ChangelogEntry', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -1936,43 +1940,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_editgroup(self, id, **kwargs): # noqa: E501 - """get_editgroup # noqa: E501 + def get_container(self, id, **kwargs): # noqa: E501 + """get_container # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_editgroup(id, async=True) + >>> thread = api.get_container(id, async=True) >>> result = thread.get() :param async bool - :param str id: base32-encoded unique identifier (required) - :return: Editgroup + :param str id: (required) + :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. + :return: ContainerEntity If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_editgroup_with_http_info(id, **kwargs) # noqa: E501 + return self.get_container_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_editgroup_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_container_with_http_info(id, **kwargs) # noqa: E501 return data - def get_editgroup_with_http_info(self, id, **kwargs): # noqa: E501 - """get_editgroup # noqa: E501 + def get_container_with_http_info(self, id, **kwargs): # noqa: E501 + """get_container # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_editgroup_with_http_info(id, async=True) + >>> thread = api.get_container_with_http_info(id, async=True) >>> result = thread.get() :param async bool - :param str id: base32-encoded unique identifier (required) - :return: Editgroup + :param str id: (required) + :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. + :return: ContainerEntity If the method is called asynchronously, returns the request thread. """ - all_params = ['id'] # noqa: E501 + all_params = ['id', 'expand'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -1983,23 +1989,15 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_editgroup" % key + " to method get_container" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_editgroup`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_container`") # noqa: E501 - if ('id' in params and - len(params['id']) > 26): - raise ValueError("Invalid value for parameter `id` when calling `get_editgroup`, length must be less than or equal to `26`") # noqa: E501 - if ('id' in params and - len(params['id']) < 26): - raise ValueError("Invalid value for parameter `id` when calling `get_editgroup`, length must be greater than or equal to `26`") # noqa: E501 - if 'id' in params and not re.search('[a-zA-Z2-7]{26}', params['id']): # noqa: E501 - raise ValueError("Invalid value for parameter `id` when calling `get_editgroup`, must conform to the pattern `/[a-zA-Z2-7]{26}/`") # noqa: E501 collection_formats = {} path_params = {} @@ -2007,6 +2005,8 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] + if 'expand' in params: + query_params.append(('expand', params['expand'])) # noqa: E501 header_params = {} @@ -2026,14 +2026,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/editgroup/{id}', 'GET', + '/container/{id}', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='Editgroup', # noqa: E501 + response_type='ContainerEntity', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2041,43 +2041,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_editor(self, id, **kwargs): # noqa: E501 - """get_editor # noqa: E501 + def get_container_history(self, id, **kwargs): # noqa: E501 + """get_container_history # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_editor(id, async=True) + >>> thread = api.get_container_history(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :return: Editor + :param int limit: + :return: list[EntityHistoryEntry] If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_editor_with_http_info(id, **kwargs) # noqa: E501 + return self.get_container_history_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_editor_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_container_history_with_http_info(id, **kwargs) # noqa: E501 return data - def get_editor_with_http_info(self, id, **kwargs): # noqa: E501 - """get_editor # noqa: E501 - + def get_container_history_with_http_info(self, id, **kwargs): # noqa: E501 + """get_container_history # noqa: E501 + This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_editor_with_http_info(id, async=True) + >>> thread = api.get_container_history_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :return: Editor + :param int limit: + :return: list[EntityHistoryEntry] If the method is called asynchronously, returns the request thread. """ - all_params = ['id'] # noqa: E501 + all_params = ['id', 'limit'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -2088,14 +2090,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_editor" % key + " to method get_container_history" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_editor`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_container_history`") # noqa: E501 collection_formats = {} @@ -2104,6 +2106,8 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] + if 'limit' in params: + query_params.append(('limit', params['limit'])) # noqa: E501 header_params = {} @@ -2123,14 +2127,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/editor/{id}', 'GET', + '/container/{id}/history', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='Editor', # noqa: E501 + response_type='list[EntityHistoryEntry]', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2138,43 +2142,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_editor_changelog(self, id, **kwargs): # noqa: E501 - """get_editor_changelog # noqa: E501 + def get_creator(self, id, **kwargs): # noqa: E501 + """get_creator # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_editor_changelog(id, async=True) + >>> thread = api.get_creator(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :return: list[ChangelogEntry] + :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. + :return: CreatorEntity If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_editor_changelog_with_http_info(id, **kwargs) # noqa: E501 + return self.get_creator_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_editor_changelog_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_creator_with_http_info(id, **kwargs) # noqa: E501 return data - def get_editor_changelog_with_http_info(self, id, **kwargs): # noqa: E501 - """get_editor_changelog # noqa: E501 + def get_creator_with_http_info(self, id, **kwargs): # noqa: E501 + """get_creator # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_editor_changelog_with_http_info(id, async=True) + >>> thread = api.get_creator_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :return: list[ChangelogEntry] + :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. + :return: CreatorEntity If the method is called asynchronously, returns the request thread. """ - all_params = ['id'] # noqa: E501 + all_params = ['id', 'expand'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -2185,14 +2191,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_editor_changelog" % key + " to method get_creator" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_editor_changelog`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_creator`") # noqa: E501 collection_formats = {} @@ -2201,6 +2207,8 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] + if 'expand' in params: + query_params.append(('expand', params['expand'])) # noqa: E501 header_params = {} @@ -2220,14 +2228,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/editor/{id}/changelog', 'GET', + '/creator/{id}', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[ChangelogEntry]', # noqa: E501 + response_type='CreatorEntity', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2235,45 +2243,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_file(self, id, **kwargs): # noqa: E501 - """get_file # noqa: E501 + def get_creator_history(self, id, **kwargs): # noqa: E501 + """get_creator_history # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_file(id, async=True) + >>> thread = api.get_creator_history(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: FileEntity + :param int limit: + :return: list[EntityHistoryEntry] If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_file_with_http_info(id, **kwargs) # noqa: E501 + return self.get_creator_history_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_file_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_creator_history_with_http_info(id, **kwargs) # noqa: E501 return data - def get_file_with_http_info(self, id, **kwargs): # noqa: E501 - """get_file # noqa: E501 + def get_creator_history_with_http_info(self, id, **kwargs): # noqa: E501 + """get_creator_history # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_file_with_http_info(id, async=True) + >>> thread = api.get_creator_history_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: FileEntity + :param int limit: + :return: list[EntityHistoryEntry] If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'expand'] # noqa: E501 + all_params = ['id', 'limit'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -2284,14 +2292,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_file" % key + " to method get_creator_history" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_file`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_creator_history`") # noqa: E501 collection_formats = {} @@ -2300,8 +2308,8 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'expand' in params: - query_params.append(('expand', params['expand'])) # noqa: E501 + if 'limit' in params: + query_params.append(('limit', params['limit'])) # noqa: E501 header_params = {} @@ -2321,14 +2329,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/file/{id}', 'GET', + '/creator/{id}/history', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='FileEntity', # noqa: E501 + response_type='list[EntityHistoryEntry]', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2336,45 +2344,43 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_file_history(self, id, **kwargs): # noqa: E501 - """get_file_history # noqa: E501 + def get_creator_releases(self, id, **kwargs): # noqa: E501 + """get_creator_releases # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_file_history(id, async=True) + >>> thread = api.get_creator_releases(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param int limit: - :return: list[EntityHistoryEntry] + :return: list[ReleaseEntity] If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_file_history_with_http_info(id, **kwargs) # noqa: E501 + return self.get_creator_releases_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_file_history_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_creator_releases_with_http_info(id, **kwargs) # noqa: E501 return data - def get_file_history_with_http_info(self, id, **kwargs): # noqa: E501 - """get_file_history # noqa: E501 + def get_creator_releases_with_http_info(self, id, **kwargs): # noqa: E501 + """get_creator_releases # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_file_history_with_http_info(id, async=True) + >>> thread = api.get_creator_releases_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param int limit: - :return: list[EntityHistoryEntry] + :return: list[ReleaseEntity] If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'limit'] # noqa: E501 + all_params = ['id'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -2385,14 +2391,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_file_history" % key + " to method get_creator_releases" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_file_history`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_creator_releases`") # noqa: E501 collection_formats = {} @@ -2401,8 +2407,6 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'limit' in params: - query_params.append(('limit', params['limit'])) # noqa: E501 header_params = {} @@ -2422,14 +2426,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/file/{id}/history', 'GET', + '/creator/{id}/releases', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[EntityHistoryEntry]', # noqa: E501 + response_type='list[ReleaseEntity]', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2437,45 +2441,43 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_release(self, id, **kwargs): # noqa: E501 - """get_release # noqa: E501 + def get_editgroup(self, id, **kwargs): # noqa: E501 + """get_editgroup # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_release(id, async=True) + >>> thread = api.get_editgroup(id, async=True) >>> result = thread.get() :param async bool - :param str id: (required) - :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: ReleaseEntity + :param str id: base32-encoded unique identifier (required) + :return: Editgroup If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_release_with_http_info(id, **kwargs) # noqa: E501 + return self.get_editgroup_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_release_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_editgroup_with_http_info(id, **kwargs) # noqa: E501 return data - def get_release_with_http_info(self, id, **kwargs): # noqa: E501 - """get_release # noqa: E501 + def get_editgroup_with_http_info(self, id, **kwargs): # noqa: E501 + """get_editgroup # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_release_with_http_info(id, async=True) + >>> thread = api.get_editgroup_with_http_info(id, async=True) >>> result = thread.get() :param async bool - :param str id: (required) - :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: ReleaseEntity + :param str id: base32-encoded unique identifier (required) + :return: Editgroup If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'expand'] # noqa: E501 + all_params = ['id'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -2486,15 +2488,23 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_release" % key + " to method get_editgroup" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_release`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_editgroup`") # noqa: E501 + if ('id' in params and + len(params['id']) > 26): + raise ValueError("Invalid value for parameter `id` when calling `get_editgroup`, length must be less than or equal to `26`") # noqa: E501 + if ('id' in params and + len(params['id']) < 26): + raise ValueError("Invalid value for parameter `id` when calling `get_editgroup`, length must be greater than or equal to `26`") # noqa: E501 + if 'id' in params and not re.search('[a-zA-Z2-7]{26}', params['id']): # noqa: E501 + raise ValueError("Invalid value for parameter `id` when calling `get_editgroup`, must conform to the pattern `/[a-zA-Z2-7]{26}/`") # noqa: E501 collection_formats = {} path_params = {} @@ -2502,8 +2512,6 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'expand' in params: - query_params.append(('expand', params['expand'])) # noqa: E501 header_params = {} @@ -2523,14 +2531,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/release/{id}', 'GET', + '/editgroup/{id}', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='ReleaseEntity', # noqa: E501 + response_type='Editgroup', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2538,38 +2546,38 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_release_files(self, id, **kwargs): # noqa: E501 - """get_release_files # noqa: E501 + def get_editor(self, id, **kwargs): # noqa: E501 + """get_editor # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_release_files(id, async=True) + >>> thread = api.get_editor(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :return: list[FileEntity] + :return: Editor If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_release_files_with_http_info(id, **kwargs) # noqa: E501 + return self.get_editor_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_release_files_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_editor_with_http_info(id, **kwargs) # noqa: E501 return data - def get_release_files_with_http_info(self, id, **kwargs): # noqa: E501 - """get_release_files # noqa: E501 + def get_editor_with_http_info(self, id, **kwargs): # noqa: E501 + """get_editor # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_release_files_with_http_info(id, async=True) + >>> thread = api.get_editor_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :return: list[FileEntity] + :return: Editor If the method is called asynchronously, returns the request thread. """ @@ -2585,14 +2593,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_release_files" % key + " to method get_editor" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_release_files`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_editor`") # noqa: E501 collection_formats = {} @@ -2620,14 +2628,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/release/{id}/files', 'GET', + '/editor/{id}', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[FileEntity]', # noqa: E501 + response_type='Editor', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2635,45 +2643,43 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_release_history(self, id, **kwargs): # noqa: E501 - """get_release_history # noqa: E501 + def get_editor_changelog(self, id, **kwargs): # noqa: E501 + """get_editor_changelog # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_release_history(id, async=True) + >>> thread = api.get_editor_changelog(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param int limit: - :return: list[EntityHistoryEntry] + :return: list[ChangelogEntry] If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_release_history_with_http_info(id, **kwargs) # noqa: E501 + return self.get_editor_changelog_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_release_history_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_editor_changelog_with_http_info(id, **kwargs) # noqa: E501 return data - def get_release_history_with_http_info(self, id, **kwargs): # noqa: E501 - """get_release_history # noqa: E501 + def get_editor_changelog_with_http_info(self, id, **kwargs): # noqa: E501 + """get_editor_changelog # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_release_history_with_http_info(id, async=True) + >>> thread = api.get_editor_changelog_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :param int limit: - :return: list[EntityHistoryEntry] + :return: list[ChangelogEntry] If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'limit'] # noqa: E501 + all_params = ['id'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -2684,14 +2690,14 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_release_history" % key + " to method get_editor_changelog" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_release_history`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_editor_changelog`") # noqa: E501 collection_formats = {} @@ -2700,8 +2706,6 @@ class DefaultApi(object): path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'limit' in params: - query_params.append(('limit', params['limit'])) # noqa: E501 header_params = {} @@ -2721,14 +2725,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/release/{id}/history', 'GET', + '/editor/{id}/changelog', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[EntityHistoryEntry]', # noqa: E501 + response_type='list[ChangelogEntry]', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2736,43 +2740,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_stats(self, **kwargs): # noqa: E501 - """get_stats # noqa: E501 + def get_file(self, id, **kwargs): # noqa: E501 + """get_file # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_stats(async=True) + >>> thread = api.get_file(id, async=True) >>> result = thread.get() :param async bool - :param str more: - :return: StatsResponse + :param str id: (required) + :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. + :return: FileEntity If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_stats_with_http_info(**kwargs) # noqa: E501 + return self.get_file_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_stats_with_http_info(**kwargs) # noqa: E501 + (data) = self.get_file_with_http_info(id, **kwargs) # noqa: E501 return data - def get_stats_with_http_info(self, **kwargs): # noqa: E501 - """get_stats # noqa: E501 + def get_file_with_http_info(self, id, **kwargs): # noqa: E501 + """get_file # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_stats_with_http_info(async=True) + >>> thread = api.get_file_with_http_info(id, async=True) >>> result = thread.get() :param async bool - :param str more: - :return: StatsResponse + :param str id: (required) + :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. + :return: FileEntity If the method is called asynchronously, returns the request thread. """ - all_params = ['more'] # noqa: E501 + all_params = ['id', 'expand'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -2783,18 +2789,24 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_stats" % key + " to method get_file" % key ) params[key] = val del params['kwargs'] + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `get_file`") # noqa: E501 collection_formats = {} path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'more' in params: - query_params.append(('more', params['more'])) # noqa: E501 + if 'expand' in params: + query_params.append(('expand', params['expand'])) # noqa: E501 header_params = {} @@ -2814,14 +2826,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/stats', 'GET', + '/file/{id}', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='StatsResponse', # noqa: E501 + response_type='FileEntity', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2829,40 +2841,141 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_work(self, id, **kwargs): # noqa: E501 - """get_work # noqa: E501 + def get_file_history(self, id, **kwargs): # noqa: E501 + """get_file_history # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_work(id, async=True) + >>> thread = api.get_file_history(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :param int limit: + :return: list[EntityHistoryEntry] + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.get_file_history_with_http_info(id, **kwargs) # noqa: E501 + else: + (data) = self.get_file_history_with_http_info(id, **kwargs) # noqa: E501 + return data + + def get_file_history_with_http_info(self, id, **kwargs): # noqa: E501 + """get_file_history # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_file_history_with_http_info(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :param int limit: + :return: list[EntityHistoryEntry] + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['id', 'limit'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method get_file_history" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `get_file_history`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 + + query_params = [] + if 'limit' in params: + query_params.append(('limit', params['limit'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/file/{id}/history', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='list[EntityHistoryEntry]', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def get_release(self, id, **kwargs): # noqa: E501 + """get_release # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_release(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: WorkEntity + :return: ReleaseEntity If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_work_with_http_info(id, **kwargs) # noqa: E501 + return self.get_release_with_http_info(id, **kwargs) # noqa: E501 else: - (data) = self.get_work_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.get_release_with_http_info(id, **kwargs) # noqa: E501 return data - def get_work_with_http_info(self, id, **kwargs): # noqa: E501 - """get_work # noqa: E501 + def get_release_with_http_info(self, id, **kwargs): # noqa: E501 + """get_release # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_work_with_http_info(id, async=True) + >>> thread = api.get_release_with_http_info(id, async=True) >>> result = thread.get() :param async bool :param str id: (required) :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. - :return: WorkEntity + :return: ReleaseEntity If the method is called asynchronously, returns the request thread. """ @@ -2878,24 +2991,921 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_work" % key + " to method get_release" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_work`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `get_release`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 + + query_params = [] + if 'expand' in params: + query_params.append(('expand', params['expand'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/release/{id}', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='ReleaseEntity', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def get_release_files(self, id, **kwargs): # noqa: E501 + """get_release_files # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_release_files(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :return: list[FileEntity] + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.get_release_files_with_http_info(id, **kwargs) # noqa: E501 + else: + (data) = self.get_release_files_with_http_info(id, **kwargs) # noqa: E501 + return data + + def get_release_files_with_http_info(self, id, **kwargs): # noqa: E501 + """get_release_files # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_release_files_with_http_info(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :return: list[FileEntity] + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['id'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method get_release_files" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `get_release_files`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 + + query_params = [] + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/release/{id}/files', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='list[FileEntity]', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def get_release_history(self, id, **kwargs): # noqa: E501 + """get_release_history # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_release_history(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :param int limit: + :return: list[EntityHistoryEntry] + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.get_release_history_with_http_info(id, **kwargs) # noqa: E501 + else: + (data) = self.get_release_history_with_http_info(id, **kwargs) # noqa: E501 + return data + + def get_release_history_with_http_info(self, id, **kwargs): # noqa: E501 + """get_release_history # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_release_history_with_http_info(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :param int limit: + :return: list[EntityHistoryEntry] + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['id', 'limit'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method get_release_history" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `get_release_history`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 + + query_params = [] + if 'limit' in params: + query_params.append(('limit', params['limit'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/release/{id}/history', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='list[EntityHistoryEntry]', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def get_stats(self, **kwargs): # noqa: E501 + """get_stats # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_stats(async=True) + >>> result = thread.get() + + :param async bool + :param str more: + :return: StatsResponse + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.get_stats_with_http_info(**kwargs) # noqa: E501 + else: + (data) = self.get_stats_with_http_info(**kwargs) # noqa: E501 + return data + + def get_stats_with_http_info(self, **kwargs): # noqa: E501 + """get_stats # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_stats_with_http_info(async=True) + >>> result = thread.get() + + :param async bool + :param str more: + :return: StatsResponse + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['more'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method get_stats" % key + ) + params[key] = val + del params['kwargs'] + + collection_formats = {} + + path_params = {} + + query_params = [] + if 'more' in params: + query_params.append(('more', params['more'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/stats', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='StatsResponse', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def get_work(self, id, **kwargs): # noqa: E501 + """get_work # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_work(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. + :return: WorkEntity + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.get_work_with_http_info(id, **kwargs) # noqa: E501 + else: + (data) = self.get_work_with_http_info(id, **kwargs) # noqa: E501 + return data + + def get_work_with_http_info(self, id, **kwargs): # noqa: E501 + """get_work # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_work_with_http_info(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :param str expand: List of sub-entities to expand in response. For now, only 'all' accepted. + :return: WorkEntity + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['id', 'expand'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method get_work" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `get_work`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 + + query_params = [] + if 'expand' in params: + query_params.append(('expand', params['expand'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/work/{id}', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='WorkEntity', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def get_work_history(self, id, **kwargs): # noqa: E501 + """get_work_history # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_work_history(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :param int limit: + :return: list[EntityHistoryEntry] + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.get_work_history_with_http_info(id, **kwargs) # noqa: E501 + else: + (data) = self.get_work_history_with_http_info(id, **kwargs) # noqa: E501 + return data + + def get_work_history_with_http_info(self, id, **kwargs): # noqa: E501 + """get_work_history # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_work_history_with_http_info(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :param int limit: + :return: list[EntityHistoryEntry] + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['id', 'limit'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method get_work_history" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `get_work_history`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 + + query_params = [] + if 'limit' in params: + query_params.append(('limit', params['limit'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/work/{id}/history', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='list[EntityHistoryEntry]', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def get_work_releases(self, id, **kwargs): # noqa: E501 + """get_work_releases # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_work_releases(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :return: list[ReleaseEntity] + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.get_work_releases_with_http_info(id, **kwargs) # noqa: E501 + else: + (data) = self.get_work_releases_with_http_info(id, **kwargs) # noqa: E501 + return data + + def get_work_releases_with_http_info(self, id, **kwargs): # noqa: E501 + """get_work_releases # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.get_work_releases_with_http_info(id, async=True) + >>> result = thread.get() + + :param async bool + :param str id: (required) + :return: list[ReleaseEntity] + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['id'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method get_work_releases" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `get_work_releases`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 + + query_params = [] + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/work/{id}/releases', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='list[ReleaseEntity]', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def lookup_container(self, issnl, **kwargs): # noqa: E501 + """lookup_container # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.lookup_container(issnl, async=True) + >>> result = thread.get() + + :param async bool + :param str issnl: (required) + :return: ContainerEntity + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.lookup_container_with_http_info(issnl, **kwargs) # noqa: E501 + else: + (data) = self.lookup_container_with_http_info(issnl, **kwargs) # noqa: E501 + return data + + def lookup_container_with_http_info(self, issnl, **kwargs): # noqa: E501 + """lookup_container # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.lookup_container_with_http_info(issnl, async=True) + >>> result = thread.get() + + :param async bool + :param str issnl: (required) + :return: ContainerEntity + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['issnl'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method lookup_container" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'issnl' is set + if ('issnl' not in params or + params['issnl'] is None): + raise ValueError("Missing the required parameter `issnl` when calling `lookup_container`") # noqa: E501 + + if ('issnl' in params and + len(params['issnl']) > 9): + raise ValueError("Invalid value for parameter `issnl` when calling `lookup_container`, length must be less than or equal to `9`") # noqa: E501 + if ('issnl' in params and + len(params['issnl']) < 9): + raise ValueError("Invalid value for parameter `issnl` when calling `lookup_container`, length must be greater than or equal to `9`") # noqa: E501 + if 'issnl' in params and not re.search('\\d{4}-\\d{3}[0-9X]', params['issnl']): # noqa: E501 + raise ValueError("Invalid value for parameter `issnl` when calling `lookup_container`, must conform to the pattern `/\\d{4}-\\d{3}[0-9X]/`") # noqa: E501 + collection_formats = {} + + path_params = {} + + query_params = [] + if 'issnl' in params: + query_params.append(('issnl', params['issnl'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/container/lookup', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='ContainerEntity', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def lookup_creator(self, orcid, **kwargs): # noqa: E501 + """lookup_creator # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.lookup_creator(orcid, async=True) + >>> result = thread.get() + + :param async bool + :param str orcid: (required) + :return: CreatorEntity + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.lookup_creator_with_http_info(orcid, **kwargs) # noqa: E501 + else: + (data) = self.lookup_creator_with_http_info(orcid, **kwargs) # noqa: E501 + return data + + def lookup_creator_with_http_info(self, orcid, **kwargs): # noqa: E501 + """lookup_creator # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.lookup_creator_with_http_info(orcid, async=True) + >>> result = thread.get() + + :param async bool + :param str orcid: (required) + :return: CreatorEntity + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['orcid'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method lookup_creator" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'orcid' is set + if ('orcid' not in params or + params['orcid'] is None): + raise ValueError("Missing the required parameter `orcid` when calling `lookup_creator`") # noqa: E501 + + if ('orcid' in params and + len(params['orcid']) > 19): + raise ValueError("Invalid value for parameter `orcid` when calling `lookup_creator`, length must be less than or equal to `19`") # noqa: E501 + if ('orcid' in params and + len(params['orcid']) < 19): + raise ValueError("Invalid value for parameter `orcid` when calling `lookup_creator`, length must be greater than or equal to `19`") # noqa: E501 + if 'orcid' in params and not re.search('\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]', params['orcid']): # noqa: E501 + raise ValueError("Invalid value for parameter `orcid` when calling `lookup_creator`, must conform to the pattern `/\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]/`") # noqa: E501 + collection_formats = {} + + path_params = {} + + query_params = [] + if 'orcid' in params: + query_params.append(('orcid', params['orcid'])) # noqa: E501 + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = [] # noqa: E501 + + return self.api_client.call_api( + '/creator/lookup', 'GET', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type='CreatorEntity', # noqa: E501 + auth_settings=auth_settings, + async=params.get('async'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) + + def lookup_file(self, sha1, **kwargs): # noqa: E501 + """lookup_file # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.lookup_file(sha1, async=True) + >>> result = thread.get() + + :param async bool + :param str sha1: (required) + :return: FileEntity + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async'): + return self.lookup_file_with_http_info(sha1, **kwargs) # noqa: E501 + else: + (data) = self.lookup_file_with_http_info(sha1, **kwargs) # noqa: E501 + return data + + def lookup_file_with_http_info(self, sha1, **kwargs): # noqa: E501 + """lookup_file # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async=True + >>> thread = api.lookup_file_with_http_info(sha1, async=True) + >>> result = thread.get() + + :param async bool + :param str sha1: (required) + :return: FileEntity + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['sha1'] # noqa: E501 + all_params.append('async') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method lookup_file" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'sha1' is set + if ('sha1' not in params or + params['sha1'] is None): + raise ValueError("Missing the required parameter `sha1` when calling `lookup_file`") # noqa: E501 collection_formats = {} path_params = {} - if 'id' in params: - path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'expand' in params: - query_params.append(('expand', params['expand'])) # noqa: E501 + if 'sha1' in params: + query_params.append(('sha1', params['sha1'])) # noqa: E501 header_params = {} @@ -2915,14 +3925,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/work/{id}', 'GET', + '/file/lookup', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='WorkEntity', # noqa: E501 + response_type='FileEntity', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -2930,45 +3940,43 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_work_history(self, id, **kwargs): # noqa: E501 - """get_work_history # noqa: E501 + def lookup_release(self, doi, **kwargs): # noqa: E501 + """lookup_release # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_work_history(id, async=True) + >>> thread = api.lookup_release(doi, async=True) >>> result = thread.get() :param async bool - :param str id: (required) - :param int limit: - :return: list[EntityHistoryEntry] + :param str doi: (required) + :return: ReleaseEntity If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_work_history_with_http_info(id, **kwargs) # noqa: E501 + return self.lookup_release_with_http_info(doi, **kwargs) # noqa: E501 else: - (data) = self.get_work_history_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.lookup_release_with_http_info(doi, **kwargs) # noqa: E501 return data - def get_work_history_with_http_info(self, id, **kwargs): # noqa: E501 - """get_work_history # noqa: E501 + def lookup_release_with_http_info(self, doi, **kwargs): # noqa: E501 + """lookup_release # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_work_history_with_http_info(id, async=True) + >>> thread = api.lookup_release_with_http_info(doi, async=True) >>> result = thread.get() :param async bool - :param str id: (required) - :param int limit: - :return: list[EntityHistoryEntry] + :param str doi: (required) + :return: ReleaseEntity If the method is called asynchronously, returns the request thread. """ - all_params = ['id', 'limit'] # noqa: E501 + all_params = ['doi'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -2979,24 +3987,22 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_work_history" % key + " to method lookup_release" % key ) params[key] = val del params['kwargs'] - # verify the required parameter 'id' is set - if ('id' not in params or - params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_work_history`") # noqa: E501 + # verify the required parameter 'doi' is set + if ('doi' not in params or + params['doi'] is None): + raise ValueError("Missing the required parameter `doi` when calling `lookup_release`") # noqa: E501 collection_formats = {} path_params = {} - if 'id' in params: - path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'limit' in params: - query_params.append(('limit', params['limit'])) # noqa: E501 + if 'doi' in params: + query_params.append(('doi', params['doi'])) # noqa: E501 header_params = {} @@ -3016,14 +4022,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/work/{id}/history', 'GET', + '/release/lookup', 'GET', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[EntityHistoryEntry]', # noqa: E501 + response_type='ReleaseEntity', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -3031,43 +4037,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def get_work_releases(self, id, **kwargs): # noqa: E501 - """get_work_releases # noqa: E501 + def update_container(self, id, entity, **kwargs): # noqa: E501 + """update_container # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_work_releases(id, async=True) + >>> thread = api.update_container(id, entity, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :return: list[ReleaseEntity] + :param ContainerEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.get_work_releases_with_http_info(id, **kwargs) # noqa: E501 + return self.update_container_with_http_info(id, entity, **kwargs) # noqa: E501 else: - (data) = self.get_work_releases_with_http_info(id, **kwargs) # noqa: E501 + (data) = self.update_container_with_http_info(id, entity, **kwargs) # noqa: E501 return data - def get_work_releases_with_http_info(self, id, **kwargs): # noqa: E501 - """get_work_releases # noqa: E501 + def update_container_with_http_info(self, id, entity, **kwargs): # noqa: E501 + """update_container # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.get_work_releases_with_http_info(id, async=True) + >>> thread = api.update_container_with_http_info(id, entity, async=True) >>> result = thread.get() :param async bool :param str id: (required) - :return: list[ReleaseEntity] + :param ContainerEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['id'] # noqa: E501 + all_params = ['id', 'entity'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -3078,14 +4086,18 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method get_work_releases" % key + " to method update_container" % key ) params[key] = val del params['kwargs'] # verify the required parameter 'id' is set if ('id' not in params or params['id'] is None): - raise ValueError("Missing the required parameter `id` when calling `get_work_releases`") # noqa: E501 + raise ValueError("Missing the required parameter `id` when calling `update_container`") # noqa: E501 + # verify the required parameter 'entity' is set + if ('entity' not in params or + params['entity'] is None): + raise ValueError("Missing the required parameter `entity` when calling `update_container`") # noqa: E501 collection_formats = {} @@ -3101,6 +4113,8 @@ class DefaultApi(object): local_var_files = {} body_params = None + if 'entity' in params: + body_params = params['entity'] # HTTP header `Accept` header_params['Accept'] = self.api_client.select_header_accept( ['application/json']) # noqa: E501 @@ -3113,14 +4127,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/work/{id}/releases', 'GET', + '/container/{id}', 'PUT', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='list[ReleaseEntity]', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -3128,43 +4142,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def lookup_container(self, issnl, **kwargs): # noqa: E501 - """lookup_container # noqa: E501 + def update_creator(self, id, entity, **kwargs): # noqa: E501 + """update_creator # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.lookup_container(issnl, async=True) + >>> thread = api.update_creator(id, entity, async=True) >>> result = thread.get() :param async bool - :param str issnl: (required) - :return: ContainerEntity + :param str id: (required) + :param CreatorEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.lookup_container_with_http_info(issnl, **kwargs) # noqa: E501 + return self.update_creator_with_http_info(id, entity, **kwargs) # noqa: E501 else: - (data) = self.lookup_container_with_http_info(issnl, **kwargs) # noqa: E501 + (data) = self.update_creator_with_http_info(id, entity, **kwargs) # noqa: E501 return data - def lookup_container_with_http_info(self, issnl, **kwargs): # noqa: E501 - """lookup_container # noqa: E501 + def update_creator_with_http_info(self, id, entity, **kwargs): # noqa: E501 + """update_creator # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.lookup_container_with_http_info(issnl, async=True) + >>> thread = api.update_creator_with_http_info(id, entity, async=True) >>> result = thread.get() :param async bool - :param str issnl: (required) - :return: ContainerEntity + :param str id: (required) + :param CreatorEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['issnl'] # noqa: E501 + all_params = ['id', 'entity'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -3175,30 +4191,26 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method lookup_container" % key + " to method update_creator" % key ) params[key] = val del params['kwargs'] - # verify the required parameter 'issnl' is set - if ('issnl' not in params or - params['issnl'] is None): - raise ValueError("Missing the required parameter `issnl` when calling `lookup_container`") # noqa: E501 + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `update_creator`") # noqa: E501 + # verify the required parameter 'entity' is set + if ('entity' not in params or + params['entity'] is None): + raise ValueError("Missing the required parameter `entity` when calling `update_creator`") # noqa: E501 - if ('issnl' in params and - len(params['issnl']) > 9): - raise ValueError("Invalid value for parameter `issnl` when calling `lookup_container`, length must be less than or equal to `9`") # noqa: E501 - if ('issnl' in params and - len(params['issnl']) < 9): - raise ValueError("Invalid value for parameter `issnl` when calling `lookup_container`, length must be greater than or equal to `9`") # noqa: E501 - if 'issnl' in params and not re.search('\\d{4}-\\d{3}[0-9X]', params['issnl']): # noqa: E501 - raise ValueError("Invalid value for parameter `issnl` when calling `lookup_container`, must conform to the pattern `/\\d{4}-\\d{3}[0-9X]/`") # noqa: E501 collection_formats = {} path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'issnl' in params: - query_params.append(('issnl', params['issnl'])) # noqa: E501 header_params = {} @@ -3206,6 +4218,8 @@ class DefaultApi(object): local_var_files = {} body_params = None + if 'entity' in params: + body_params = params['entity'] # HTTP header `Accept` header_params['Accept'] = self.api_client.select_header_accept( ['application/json']) # noqa: E501 @@ -3218,14 +4232,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/container/lookup', 'GET', + '/creator/{id}', 'PUT', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='ContainerEntity', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -3233,43 +4247,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def lookup_creator(self, orcid, **kwargs): # noqa: E501 - """lookup_creator # noqa: E501 + def update_file(self, id, entity, **kwargs): # noqa: E501 + """update_file # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.lookup_creator(orcid, async=True) + >>> thread = api.update_file(id, entity, async=True) >>> result = thread.get() :param async bool - :param str orcid: (required) - :return: CreatorEntity + :param str id: (required) + :param FileEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.lookup_creator_with_http_info(orcid, **kwargs) # noqa: E501 + return self.update_file_with_http_info(id, entity, **kwargs) # noqa: E501 else: - (data) = self.lookup_creator_with_http_info(orcid, **kwargs) # noqa: E501 + (data) = self.update_file_with_http_info(id, entity, **kwargs) # noqa: E501 return data - def lookup_creator_with_http_info(self, orcid, **kwargs): # noqa: E501 - """lookup_creator # noqa: E501 + def update_file_with_http_info(self, id, entity, **kwargs): # noqa: E501 + """update_file # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.lookup_creator_with_http_info(orcid, async=True) + >>> thread = api.update_file_with_http_info(id, entity, async=True) >>> result = thread.get() :param async bool - :param str orcid: (required) - :return: CreatorEntity + :param str id: (required) + :param FileEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['orcid'] # noqa: E501 + all_params = ['id', 'entity'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -3280,30 +4296,26 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method lookup_creator" % key + " to method update_file" % key ) params[key] = val del params['kwargs'] - # verify the required parameter 'orcid' is set - if ('orcid' not in params or - params['orcid'] is None): - raise ValueError("Missing the required parameter `orcid` when calling `lookup_creator`") # noqa: E501 + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `update_file`") # noqa: E501 + # verify the required parameter 'entity' is set + if ('entity' not in params or + params['entity'] is None): + raise ValueError("Missing the required parameter `entity` when calling `update_file`") # noqa: E501 - if ('orcid' in params and - len(params['orcid']) > 19): - raise ValueError("Invalid value for parameter `orcid` when calling `lookup_creator`, length must be less than or equal to `19`") # noqa: E501 - if ('orcid' in params and - len(params['orcid']) < 19): - raise ValueError("Invalid value for parameter `orcid` when calling `lookup_creator`, length must be greater than or equal to `19`") # noqa: E501 - if 'orcid' in params and not re.search('\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]', params['orcid']): # noqa: E501 - raise ValueError("Invalid value for parameter `orcid` when calling `lookup_creator`, must conform to the pattern `/\\d{4}-\\d{4}-\\d{4}-\\d{3}[\\dX]/`") # noqa: E501 collection_formats = {} path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'orcid' in params: - query_params.append(('orcid', params['orcid'])) # noqa: E501 header_params = {} @@ -3311,6 +4323,8 @@ class DefaultApi(object): local_var_files = {} body_params = None + if 'entity' in params: + body_params = params['entity'] # HTTP header `Accept` header_params['Accept'] = self.api_client.select_header_accept( ['application/json']) # noqa: E501 @@ -3323,14 +4337,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/creator/lookup', 'GET', + '/file/{id}', 'PUT', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='CreatorEntity', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -3338,43 +4352,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def lookup_file(self, sha1, **kwargs): # noqa: E501 - """lookup_file # noqa: E501 + def update_release(self, id, entity, **kwargs): # noqa: E501 + """update_release # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.lookup_file(sha1, async=True) + >>> thread = api.update_release(id, entity, async=True) >>> result = thread.get() :param async bool - :param str sha1: (required) - :return: FileEntity + :param str id: (required) + :param ReleaseEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.lookup_file_with_http_info(sha1, **kwargs) # noqa: E501 + return self.update_release_with_http_info(id, entity, **kwargs) # noqa: E501 else: - (data) = self.lookup_file_with_http_info(sha1, **kwargs) # noqa: E501 + (data) = self.update_release_with_http_info(id, entity, **kwargs) # noqa: E501 return data - def lookup_file_with_http_info(self, sha1, **kwargs): # noqa: E501 - """lookup_file # noqa: E501 + def update_release_with_http_info(self, id, entity, **kwargs): # noqa: E501 + """update_release # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.lookup_file_with_http_info(sha1, async=True) + >>> thread = api.update_release_with_http_info(id, entity, async=True) >>> result = thread.get() :param async bool - :param str sha1: (required) - :return: FileEntity + :param str id: (required) + :param ReleaseEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['sha1'] # noqa: E501 + all_params = ['id', 'entity'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -3385,22 +4401,26 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method lookup_file" % key + " to method update_release" % key ) params[key] = val del params['kwargs'] - # verify the required parameter 'sha1' is set - if ('sha1' not in params or - params['sha1'] is None): - raise ValueError("Missing the required parameter `sha1` when calling `lookup_file`") # noqa: E501 + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `update_release`") # noqa: E501 + # verify the required parameter 'entity' is set + if ('entity' not in params or + params['entity'] is None): + raise ValueError("Missing the required parameter `entity` when calling `update_release`") # noqa: E501 collection_formats = {} path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'sha1' in params: - query_params.append(('sha1', params['sha1'])) # noqa: E501 header_params = {} @@ -3408,6 +4428,8 @@ class DefaultApi(object): local_var_files = {} body_params = None + if 'entity' in params: + body_params = params['entity'] # HTTP header `Accept` header_params['Accept'] = self.api_client.select_header_accept( ['application/json']) # noqa: E501 @@ -3420,14 +4442,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/file/lookup', 'GET', + '/release/{id}', 'PUT', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='FileEntity', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), @@ -3435,43 +4457,45 @@ class DefaultApi(object): _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) - def lookup_release(self, doi, **kwargs): # noqa: E501 - """lookup_release # noqa: E501 + def update_work(self, id, entity, **kwargs): # noqa: E501 + """update_work # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.lookup_release(doi, async=True) + >>> thread = api.update_work(id, entity, async=True) >>> result = thread.get() :param async bool - :param str doi: (required) - :return: ReleaseEntity + :param str id: (required) + :param WorkEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ kwargs['_return_http_data_only'] = True if kwargs.get('async'): - return self.lookup_release_with_http_info(doi, **kwargs) # noqa: E501 + return self.update_work_with_http_info(id, entity, **kwargs) # noqa: E501 else: - (data) = self.lookup_release_with_http_info(doi, **kwargs) # noqa: E501 + (data) = self.update_work_with_http_info(id, entity, **kwargs) # noqa: E501 return data - def lookup_release_with_http_info(self, doi, **kwargs): # noqa: E501 - """lookup_release # noqa: E501 + def update_work_with_http_info(self, id, entity, **kwargs): # noqa: E501 + """update_work # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async=True - >>> thread = api.lookup_release_with_http_info(doi, async=True) + >>> thread = api.update_work_with_http_info(id, entity, async=True) >>> result = thread.get() :param async bool - :param str doi: (required) - :return: ReleaseEntity + :param str id: (required) + :param WorkEntity entity: (required) + :return: EntityEdit If the method is called asynchronously, returns the request thread. """ - all_params = ['doi'] # noqa: E501 + all_params = ['id', 'entity'] # noqa: E501 all_params.append('async') all_params.append('_return_http_data_only') all_params.append('_preload_content') @@ -3482,22 +4506,26 @@ class DefaultApi(object): if key not in all_params: raise TypeError( "Got an unexpected keyword argument '%s'" - " to method lookup_release" % key + " to method update_work" % key ) params[key] = val del params['kwargs'] - # verify the required parameter 'doi' is set - if ('doi' not in params or - params['doi'] is None): - raise ValueError("Missing the required parameter `doi` when calling `lookup_release`") # noqa: E501 + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `update_work`") # noqa: E501 + # verify the required parameter 'entity' is set + if ('entity' not in params or + params['entity'] is None): + raise ValueError("Missing the required parameter `entity` when calling `update_work`") # noqa: E501 collection_formats = {} path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 query_params = [] - if 'doi' in params: - query_params.append(('doi', params['doi'])) # noqa: E501 header_params = {} @@ -3505,6 +4533,8 @@ class DefaultApi(object): local_var_files = {} body_params = None + if 'entity' in params: + body_params = params['entity'] # HTTP header `Accept` header_params['Accept'] = self.api_client.select_header_accept( ['application/json']) # noqa: E501 @@ -3517,14 +4547,14 @@ class DefaultApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/release/lookup', 'GET', + '/work/{id}', 'PUT', path_params, query_params, header_params, body=body_params, post_params=form_params, files=local_var_files, - response_type='ReleaseEntity', # noqa: E501 + response_type='EntityEdit', # noqa: E501 auth_settings=auth_settings, async=params.get('async'), _return_http_data_only=params.get('_return_http_data_only'), diff --git a/python/tests/codegen_tests/test_default_api.py b/python/tests/codegen_tests/test_default_api.py index e3008898..ec36887b 100644 --- a/python/tests/codegen_tests/test_default_api.py +++ b/python/tests/codegen_tests/test_default_api.py @@ -101,6 +101,36 @@ class TestDefaultApi(unittest.TestCase): """ pass + def test_delete_container(self): + """Test case for delete_container + + """ + pass + + def test_delete_creator(self): + """Test case for delete_creator + + """ + pass + + def test_delete_file(self): + """Test case for delete_file + + """ + pass + + def test_delete_release(self): + """Test case for delete_release + + """ + pass + + def test_delete_work(self): + """Test case for delete_work + + """ + pass + def test_get_changelog(self): """Test case for get_changelog @@ -239,6 +269,36 @@ class TestDefaultApi(unittest.TestCase): """ pass + def test_update_container(self): + """Test case for update_container + + """ + pass + + def test_update_creator(self): + """Test case for update_creator + + """ + pass + + def test_update_file(self): + """Test case for update_file + + """ + pass + + def test_update_release(self): + """Test case for update_release + + """ + pass + + def test_update_work(self): + """Test case for update_work + + """ + pass + if __name__ == '__main__': unittest.main() diff --git a/rust/TODO b/rust/TODO index ed38b915..05ad76d8 100644 --- a/rust/TODO +++ b/rust/TODO @@ -1,4 +1,6 @@ +- database_entity_crud -> api_entity_crud +- merge autoaccept branch in with http-verbs branch - fatcat_api -> fatcat_api_schema (or spec? models? types?) - fatcat -> fatcat-api-server - refactor rev creation (from an entity) into it's own function, across the board diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 56fbca19..31b71395 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -39,7 +39,6 @@ macro_rules! entity_batch_handler { if autoaccept { let _clr: ChangelogRow = diesel::insert_into(changelog::table) - // if autoaccept, eg_id is always Some .values((changelog::editgroup_id.eq(edit_context.editgroup_id.to_uuid()),)) .get_result(conn)?; } -- cgit v1.2.3 From 109f82169ef2a141b5d859e23d3ba052cec99fcb Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sun, 9 Sep 2018 10:05:20 -0700 Subject: parallelize abstracts insertion --- rust/src/database_entity_crud.rs | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'rust') diff --git a/rust/src/database_entity_crud.rs b/rust/src/database_entity_crud.rs index 9a47c2de..88c89e84 100644 --- a/rust/src/database_entity_crud.rs +++ b/rust/src/database_entity_crud.rs @@ -40,7 +40,8 @@ pub trait EntityCrud where Self: Sized, { - // TODO: could these be generic structs? Or do they need to be bound to a specific table? + // TODO: could EditRow and IdentRow be generic structs? Or do they need to be bound to a + // specific table? type EditRow; // EntityEditRow type EditNewRow; type IdentRow; // EntityIdentRow @@ -85,7 +86,7 @@ where fn db_insert_revs(conn: &DbConn, models: &[&Self]) -> Result>; } -// TODO: this could be a separate trait on all entities? +// TODO: this could be a separate trait on all entities macro_rules! generic_parse_editgroup_id{ () => { fn parse_editgroup_id(&self) -> Result> { @@ -832,6 +833,8 @@ impl EntityCrud for ReleaseEntity { let mut release_ref_rows: Vec = vec![]; let mut release_contrib_rows: Vec = vec![]; + let mut abstract_rows: Vec = vec![]; + let mut release_abstract_rows: Vec = vec![]; for (model, rev_id) in models.iter().zip(rev_ids.iter()) { match &model.refs { @@ -883,7 +886,6 @@ impl EntityCrud for ReleaseEntity { } }; - // TODO: this part still isn't parallelized if let Some(abstract_list) = &model.abstracts { // For rows that specify content, we need to insert the abstract if it doesn't exist // already @@ -895,15 +897,8 @@ impl EntityCrud for ReleaseEntity { content: c.content.clone().unwrap(), }) .collect(); - if !new_abstracts.is_empty() { - // Sort of an "upsert"; only inserts new abstract rows if they don't already exist - insert_into(abstracts::table) - .values(&new_abstracts) - .on_conflict(abstracts::sha1) - .do_nothing() - .execute(conn)?; - } - let release_abstract_rows: Vec = abstract_list + abstract_rows.extend(new_abstracts); + let new_release_abstract_rows: Vec = abstract_list .into_iter() .map(|c| { Ok(ReleaseRevAbstractNewRow { @@ -920,9 +915,7 @@ impl EntityCrud for ReleaseEntity { }) }) .collect::>>()?; - insert_into(release_rev_abstract::table) - .values(release_abstract_rows) - .execute(conn)?; + release_abstract_rows.extend(new_release_abstract_rows); } } @@ -938,6 +931,18 @@ impl EntityCrud for ReleaseEntity { .execute(conn)?; } + if !abstract_rows.is_empty() { + // Sort of an "upsert"; only inserts new abstract rows if they don't already exist + insert_into(abstracts::table) + .values(&abstract_rows) + .on_conflict(abstracts::sha1) + .do_nothing() + .execute(conn)?; + insert_into(release_rev_abstract::table) + .values(release_abstract_rows) + .execute(conn)?; + } + Ok(rev_ids) } } -- cgit v1.2.3 From a29beab0683d77086cc1b431779d0540dc5a9b49 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sun, 9 Sep 2018 10:06:49 -0700 Subject: update TODO --- rust/TODO | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'rust') diff --git a/rust/TODO b/rust/TODO index 05ad76d8..ad4b1241 100644 --- a/rust/TODO +++ b/rust/TODO @@ -1,23 +1,26 @@ +finish refactor: - database_entity_crud -> api_entity_crud -- merge autoaccept branch in with http-verbs branch +x merge autoaccept branch in with http-verbs branch +- direct CRUD calls from api_wrappers (except, maybe, batch?) + => generally, standardize "edit" actions +- FatCatId and edit context between wrappers and handlers +- review editgroup accept code + +verbs: +- enforce "previous_rev" required in updates + - fatcat_api -> fatcat_api_schema (or spec? models? types?) - fatcat -> fatcat-api-server -- refactor rev creation (from an entity) into it's own function, across the board - => attach to database module structs? - => should make cockroachdb compatible (single use of CTE) - => usable from both "update" and "create" - editgroup param to update => also for creation? for consistency - - editor_id vs. editor username; return editor_id (in addition to name?) later: +- have editgroup_id be a request-level param everywhere (not entity-level; for batch) - editgroup: state to track review status? - re-implement old python tests - enforce "no editing if editgroup accepted" behavior -- refactor entity creation/editing (DRY) -- refactor to allow Result<> in all handlers - real auth - metrics, jwt, config, sentry - ansible/deployment/DNS story @@ -29,5 +32,4 @@ schema/api questions: - "types" - define release field stuff - what should entity POST return? include both the entity and the edit? -- PUTs (updates) to entities -- cgit v1.2.3