From 0fb0c3759a04c025800e3175fb4cbd8d595f8c4b Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 17 Nov 2020 15:48:33 -0800 Subject: rust: fatcatd changes for DOAJ+dblp identifiers --- rust/src/entity_crud.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'rust/src/entity_crud.rs') diff --git a/rust/src/entity_crud.rs b/rust/src/entity_crud.rs index 83dd26c9..89ee83bf 100644 --- a/rust/src/entity_crud.rs +++ b/rust/src/entity_crud.rs @@ -1742,6 +1742,8 @@ impl EntityCrud for ReleaseEntity { jstor: None, ark: None, mag: None, + doaj: None, + dblp: None, }, refs: None, contribs: None, @@ -2018,6 +2020,8 @@ impl EntityCrud for ReleaseEntity { jstor: None, ark: None, mag: None, + doaj: None, + dblp: None, }; let extid_rows: Vec = release_rev_extid::table @@ -2030,6 +2034,8 @@ impl EntityCrud for ReleaseEntity { "jstor" => ext_ids.jstor = Some(extid_row.value), "ark" => ext_ids.ark = Some(extid_row.value), "mag" => ext_ids.mag = Some(extid_row.value), + "doaj" => ext_ids.doaj = Some(extid_row.value), + "dblp" => ext_ids.dblp = Some(extid_row.value), _ => (), } } @@ -2290,6 +2296,20 @@ impl EntityCrud for ReleaseEntity { value: extid.clone(), }); }; + if let Some(extid) = &model.ext_ids.doaj { + release_extid_rows.push(ReleaseExtidRow { + release_rev: *rev_id, + extid_type: "doaj".to_string(), + value: extid.clone(), + }); + }; + if let Some(extid) = &model.ext_ids.dblp { + release_extid_rows.push(ReleaseExtidRow { + release_rev: *rev_id, + extid_type: "dblp".to_string(), + value: extid.clone(), + }); + }; } for (model, rev_id) in models.iter().zip(rev_ids.iter()) { -- cgit v1.2.3 From 68bb2a00e56fda04228c13cc2bea90b71002c527 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Tue, 17 Nov 2020 15:48:49 -0800 Subject: rustfmt --- rust/src/bin/fatcatd.rs | 3 +- rust/src/endpoint_handlers.rs | 3 +- rust/src/endpoints.rs | 206 +++++++++++++++++++++++-------------- rust/src/entity_crud.rs | 8 +- rust/tests/test_api_server_http.rs | 5 +- 5 files changed, 138 insertions(+), 87 deletions(-) (limited to 'rust/src/entity_crud.rs') diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs index 6f5610f0..b27ff911 100644 --- a/rust/src/bin/fatcatd.rs +++ b/rust/src/bin/fatcatd.rs @@ -35,8 +35,7 @@ impl AfterMiddleware for XClacksOverheadMiddleware { /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. fn main() -> Result<()> { - let _matches = App::new("server") - .get_matches(); + let _matches = App::new("server").get_matches(); dotenv::dotenv().ok(); diff --git a/rust/src/endpoint_handlers.rs b/rust/src/endpoint_handlers.rs index cc717344..1b7bd0b6 100644 --- a/rust/src/endpoint_handlers.rs +++ b/rust/src/endpoint_handlers.rs @@ -26,7 +26,6 @@ macro_rules! entity_auto_batch_handler { entity_list: &[models::$model], editor_id: FatcatId, ) -> Result { - let editgroup_row = editgroup.db_create(conn, true)?; let editgroup_id = FatcatId::from_uuid(&editgroup_row.id); let edit_context = make_edit_context(editor_id, editgroup_id, true)?; @@ -39,7 +38,7 @@ macro_rules! entity_auto_batch_handler { .get_result(conn)?; self.get_editgroup_handler(conn, editgroup_id) } - } + }; } pub fn get_release_files( diff --git a/rust/src/endpoints.rs b/rust/src/endpoints.rs index fda4688c..7ac0a068 100644 --- a/rust/src/endpoints.rs +++ b/rust/src/endpoints.rs @@ -76,7 +76,6 @@ macro_rules! wrap_entity_handlers { $delete_edit_fn:ident, $delete_edit_resp:ident, $get_rev_fn:ident, $get_rev_resp:ident, $get_redirects_fn:ident, $get_redirects_resp:ident, $model:ident) => { - fn $get_fn( &self, ident: String, @@ -99,11 +98,12 @@ macro_rules! wrap_entity_handlers { let mut entity = $model::db_get(&conn, entity_id, hide_flags)?; entity.db_expand(&conn, expand_flags)?; Ok(entity) - }, + } } - })().map_err(|e| FatcatError::from(e)) { - Ok(entity) => - $get_resp::FoundEntity(entity), + })() + .map_err(|e| FatcatError::from(e)) + { + Ok(entity) => $get_resp::FoundEntity(entity), Err(fe) => generic_err_responses!(fe, $get_resp), }; Box::new(futures::done(Ok(ret))) @@ -116,19 +116,27 @@ macro_rules! wrap_entity_handlers { context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); - let ret = match conn.transaction(|| { - let editgroup_id = FatcatId::from_str(&editgroup_id)?; - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($post_fn)))?; - auth_context.require_role(FatcatRole::Editor)?; - auth_context.require_editgroup(&conn, editgroup_id)?; - let edit_context = make_edit_context(auth_context.editor_id, editgroup_id, false)?; - edit_context.check(&conn)?; - entity.db_create(&conn, &edit_context)?.into_model() - }).map_err(|e| FatcatError::from(e)) { + let ret = match conn + .transaction(|| { + let editgroup_id = FatcatId::from_str(&editgroup_id)?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some(stringify!($post_fn)), + )?; + auth_context.require_role(FatcatRole::Editor)?; + auth_context.require_editgroup(&conn, editgroup_id)?; + let edit_context = + make_edit_context(auth_context.editor_id, editgroup_id, false)?; + edit_context.check(&conn)?; + entity.db_create(&conn, &edit_context)?.into_model() + }) + .map_err(|e| FatcatError::from(e)) + { Ok(edit) => { self.metrics.incr("entities.created").ok(); $post_resp::CreatedEntity(edit) - }, + } Err(fe) => generic_auth_err_responses!(fe, $post_resp), }; Box::new(futures::done(Ok(ret))) @@ -141,7 +149,11 @@ macro_rules! wrap_entity_handlers { ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); let ret = match conn.transaction(|| { - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($post_auto_batch_fn)))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some(stringify!($post_auto_batch_fn)), + )?; auth_context.require_role(FatcatRole::Admin)?; let mut editgroup = auto_batch.editgroup.clone(); // TODO: this is duplicated code with create_editgroup() @@ -151,16 +163,21 @@ macro_rules! wrap_entity_handlers { && !auth_context.has_role(FatcatRole::Admin) { return Err(FatcatError::InsufficientPrivileges( - "not authorized to create editgroups in others' names".to_string() - )) + "not authorized to create editgroups in others' names".to_string(), + )); } } None => { editgroup.editor_id = Some(auth_context.editor_id.to_string()); } }; - self.$post_auto_batch_handler(&conn, editgroup, &auto_batch.entity_list, auth_context.editor_id) - .map_err(|e| FatcatError::from(e)) + self.$post_auto_batch_handler( + &conn, + editgroup, + &auto_batch.entity_list, + auth_context.editor_id, + ) + .map_err(|e| FatcatError::from(e)) }) { Ok(editgroup) => { // TODO: need a count helper on editgroup @@ -168,7 +185,7 @@ macro_rules! wrap_entity_handlers { self.metrics.incr("editgroup.created").ok(); self.metrics.incr("editgroup.accepted").ok(); $post_auto_batch_resp::CreatedEditgroup(editgroup) - }, + } Err(fe) => generic_auth_err_responses!(fe, $post_auto_batch_resp), }; Box::new(futures::done(Ok(ret))) @@ -182,20 +199,30 @@ macro_rules! wrap_entity_handlers { context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); - let ret = match conn.transaction(|| { - let editgroup_id = FatcatId::from_str(&editgroup_id)?; - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($update_fn)))?; - auth_context.require_role(FatcatRole::Editor)?; - let entity_id = FatcatId::from_str(&ident)?; - auth_context.require_editgroup(&conn, editgroup_id)?; - let edit_context = make_edit_context(auth_context.editor_id, editgroup_id, false)?; - edit_context.check(&conn)?; - entity.db_update(&conn, &edit_context, entity_id)?.into_model() - }).map_err(|e| FatcatError::from(e)) { + let ret = match conn + .transaction(|| { + let editgroup_id = FatcatId::from_str(&editgroup_id)?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some(stringify!($update_fn)), + )?; + auth_context.require_role(FatcatRole::Editor)?; + let entity_id = FatcatId::from_str(&ident)?; + auth_context.require_editgroup(&conn, editgroup_id)?; + let edit_context = + make_edit_context(auth_context.editor_id, editgroup_id, false)?; + edit_context.check(&conn)?; + entity + .db_update(&conn, &edit_context, entity_id)? + .into_model() + }) + .map_err(|e| FatcatError::from(e)) + { Ok(edit) => { self.metrics.incr("entities.updated").ok(); $update_resp::UpdatedEntity(edit) - }, + } Err(fe) => generic_auth_err_responses!(fe, $update_resp), }; Box::new(futures::done(Ok(ret))) @@ -208,20 +235,28 @@ macro_rules! wrap_entity_handlers { context: &Context, ) -> Box + Send> { let conn = self.db_pool.get().expect("db_pool error"); - let ret = match conn.transaction(|| { - let editgroup_id = FatcatId::from_str(&editgroup_id)?; - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($delete_fn)))?; - auth_context.require_role(FatcatRole::Editor)?; - let entity_id = FatcatId::from_str(&ident)?; - auth_context.require_editgroup(&conn, editgroup_id)?; - let edit_context = make_edit_context(auth_context.editor_id, editgroup_id, false)?; - edit_context.check(&conn)?; - $model::db_delete(&conn, &edit_context, entity_id)?.into_model() - }).map_err(|e| FatcatError::from(e)) { + let ret = match conn + .transaction(|| { + let editgroup_id = FatcatId::from_str(&editgroup_id)?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some(stringify!($delete_fn)), + )?; + auth_context.require_role(FatcatRole::Editor)?; + let entity_id = FatcatId::from_str(&ident)?; + auth_context.require_editgroup(&conn, editgroup_id)?; + let edit_context = + make_edit_context(auth_context.editor_id, editgroup_id, false)?; + edit_context.check(&conn)?; + $model::db_delete(&conn, &edit_context, entity_id)?.into_model() + }) + .map_err(|e| FatcatError::from(e)) + { Ok(edit) => { self.metrics.incr("entities.deleted").ok(); $delete_resp::DeletedEntity(edit) - }, + } Err(fe) => generic_auth_err_responses!(fe, $delete_resp), }; Box::new(futures::done(Ok(ret))) @@ -238,9 +273,10 @@ macro_rules! wrap_entity_handlers { let ret = match (|| { let entity_id = FatcatId::from_str(&ident)?; $model::db_get_history(&conn, entity_id, limit) - })().map_err(|e| FatcatError::from(e)) { - Ok(history) => - $get_history_resp::FoundEntityHistory(history), + })() + .map_err(|e| FatcatError::from(e)) + { + Ok(history) => $get_history_resp::FoundEntityHistory(history), Err(fe) => generic_err_responses!(fe, $get_history_resp), }; Box::new(futures::done(Ok(ret))) @@ -268,11 +304,12 @@ macro_rules! wrap_entity_handlers { let mut entity = $model::db_get_rev(&conn, rev_id, hide_flags)?; entity.db_expand(&conn, expand_flags)?; Ok(entity) - }, + } } - })().map_err(|e| FatcatError::from(e)) { - Ok(entity) => - $get_rev_resp::FoundEntityRevision(entity), + })() + .map_err(|e| FatcatError::from(e)) + { + Ok(entity) => $get_rev_resp::FoundEntityRevision(entity), Err(fe) => generic_err_responses!(fe, $get_rev_resp), }; Box::new(futures::done(Ok(ret))) @@ -288,9 +325,10 @@ macro_rules! wrap_entity_handlers { let ret = match (|| { let edit_id = Uuid::from_str(&edit_id)?; $model::db_get_edit(&conn, edit_id)?.into_model() - })().map_err(|e| FatcatError::from(e)) { - Ok(edit) => - $get_edit_resp::FoundEdit(edit), + })() + .map_err(|e| FatcatError::from(e)) + { + Ok(edit) => $get_edit_resp::FoundEdit(edit), Err(fe) => generic_err_responses!(fe, $get_edit_resp), }; Box::new(futures::done(Ok(ret))) @@ -306,23 +344,29 @@ macro_rules! wrap_entity_handlers { let ret = match conn.transaction(|| { let editgroup_id = FatcatId::from_str(&editgroup_id)?; let edit_id = Uuid::from_str(&edit_id)?; - let auth_context = self.auth_confectionary.require_auth(&conn, &context.auth_data, Some(stringify!($delete_edit_fn)))?; + let auth_context = self.auth_confectionary.require_auth( + &conn, + &context.auth_data, + Some(stringify!($delete_edit_fn)), + )?; auth_context.require_role(FatcatRole::Editor)?; let edit = $model::db_get_edit(&conn, edit_id)?; if !(edit.editgroup_id == editgroup_id.to_uuid()) { return Err(FatcatError::BadRequest( - "editgroup_id parameter didn't match that of the edit".to_string() - )) + "editgroup_id parameter didn't match that of the edit".to_string(), + )); } auth_context.require_editgroup(&conn, editgroup_id)?; // check for editgroup being deleted happens in db_delete_edit() - $model::db_delete_edit(&conn, edit_id) - .map_err(|e| FatcatError::from(e)) + $model::db_delete_edit(&conn, edit_id).map_err(|e| FatcatError::from(e)) }) { - Ok(()) => - $delete_edit_resp::DeletedEdit(Success { - success: true, - message: format!("Successfully deleted work-in-progress {} edit: {}", stringify!($model), edit_id) + Ok(()) => $delete_edit_resp::DeletedEdit(Success { + success: true, + message: format!( + "Successfully deleted work-in-progress {} edit: {}", + stringify!($model), + edit_id + ), }), Err(fe) => generic_auth_err_responses!(fe, $delete_edit_resp), }; @@ -340,15 +384,15 @@ macro_rules! wrap_entity_handlers { let entity_id = FatcatId::from_str(&ident)?; let redirects: Vec = $model::db_get_redirects(&conn, entity_id)?; Ok(redirects.into_iter().map(|fcid| fcid.to_string()).collect()) - })().map_err(|e: Error| FatcatError::from(e)) { - Ok(redirects) => - $get_redirects_resp::FoundEntityRedirects(redirects), + })() + .map_err(|e: Error| FatcatError::from(e)) + { + Ok(redirects) => $get_redirects_resp::FoundEntityRedirects(redirects), Err(fe) => generic_err_responses!(fe, $get_redirects_resp), }; Box::new(futures::done(Ok(ret))) } - - } + }; } macro_rules! wrap_lookup_handler { @@ -371,14 +415,16 @@ macro_rules! wrap_lookup_handler { Some(param) => HideFlags::from_str(¶m).unwrap(), }; // No transaction for GET - let ret = match self.$get_handler(&conn, &$idname, &wikidata_qid, expand_flags, hide_flags).map_err(|e| FatcatError::from(e)) { - Ok(entity) => - $get_resp::FoundEntity(entity), + let ret = match self + .$get_handler(&conn, &$idname, &wikidata_qid, expand_flags, hide_flags) + .map_err(|e| FatcatError::from(e)) + { + Ok(entity) => $get_resp::FoundEntity(entity), Err(fe) => generic_err_responses!(fe, $get_resp), }; Box::new(futures::done(Ok(ret))) } - } + }; } macro_rules! wrap_fcid_handler { @@ -393,14 +439,15 @@ macro_rules! wrap_fcid_handler { let ret = match (|| { let fcid = FatcatId::from_str(&id)?; self.$get_handler(&conn, fcid) - })().map_err(|e| FatcatError::from(e)) { - Ok(entity) => - $get_resp::Found(entity), + })() + .map_err(|e| FatcatError::from(e)) + { + Ok(entity) => $get_resp::Found(entity), Err(fe) => generic_err_responses!(fe, $get_resp), }; Box::new(futures::done(Ok(ret))) } - } + }; } macro_rules! wrap_fcid_hide_handler { @@ -420,14 +467,15 @@ macro_rules! wrap_fcid_hide_handler { Some(param) => HideFlags::from_str(¶m)?, }; self.$get_handler(&conn, fcid, hide_flags) - })().map_err(|e| FatcatError::from(e)) { - Ok(entity) => - $get_resp::Found(entity), + })() + .map_err(|e| FatcatError::from(e)) + { + Ok(entity) => $get_resp::Found(entity), Err(fe) => generic_err_responses!(fe, $get_resp), }; Box::new(futures::done(Ok(ret))) } - } + }; } impl Api for Server { diff --git a/rust/src/entity_crud.rs b/rust/src/entity_crud.rs index 89ee83bf..bac8c0fc 100644 --- a/rust/src/entity_crud.rs +++ b/rust/src/entity_crud.rs @@ -334,7 +334,9 @@ macro_rules! generic_db_create { fn db_create(&self, conn: &DbConn, edit_context: &EditContext) -> Result { if self.redirect.is_some() { return Err(FatcatError::BadRequest( - "can't create an entity that redirects from the start".to_string()).into()); + "can't create an entity that redirects from the start".to_string(), + ) + .into()); } let rev_id = self.db_insert_rev(conn)?; let ident: Uuid = insert_into($ident_table::table) @@ -351,7 +353,7 @@ macro_rules! generic_db_create { .get_result(conn)?; Ok(edit) } - } + }; } macro_rules! generic_db_create_batch { @@ -764,7 +766,7 @@ macro_rules! generic_db_insert_rev { fn db_insert_rev(&self, conn: &DbConn) -> Result { Self::db_insert_revs(conn, &[self]).map(|id_list| id_list[0]) } - } + }; } impl EntityCrud for ContainerEntity { diff --git a/rust/tests/test_api_server_http.rs b/rust/tests/test_api_server_http.rs index ae875a05..adab5745 100644 --- a/rust/tests/test_api_server_http.rs +++ b/rust/tests/test_api_server_http.rs @@ -664,7 +664,10 @@ fn test_post_fileset() { helpers::check_http_response( request::post( - &format!("http://localhost:9411/v0/editgroup/{}/fileset", editgroup_id), + &format!( + "http://localhost:9411/v0/editgroup/{}/fileset", + editgroup_id + ), headers.clone(), r#"{"manifest": [ {"path": "new_file.txt", "size": 12345, "sha1": "e9dd75237c94b209dc3ccd52722de6931a310ba3" }, -- cgit v1.2.3 From 7fa96bab1bb4d1a99048cf9398fd3e1c8a4bf78a Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Thu, 19 Nov 2020 13:15:24 -0800 Subject: update fatcatd rust code for 'oai' external identifier --- rust/src/endpoint_handlers.rs | 150 ++++++++++++++++++++++++++++++++++++++---- rust/src/endpoints.rs | 2 + rust/src/entity_crud.rs | 10 +++ rust/src/identifiers.rs | 38 +++++++++++ 4 files changed, 189 insertions(+), 11 deletions(-) (limited to 'rust/src/entity_crud.rs') diff --git a/rust/src/endpoint_handlers.rs b/rust/src/endpoint_handlers.rs index 1b7bd0b6..91ea2393 100644 --- a/rust/src/endpoint_handlers.rs +++ b/rust/src/endpoint_handlers.rs @@ -263,6 +263,7 @@ impl Server { mag: &Option, doaj: &Option, dblp: &Option, + oai: &Option, expand_flags: ExpandFlags, hide_flags: HideFlags, ) -> Result { @@ -279,8 +280,9 @@ impl Server { mag, doaj, dblp, + oai, ) { - (Some(doi), None, None, None, None, None, None, None, None, None, None, None) => { + (Some(doi), None, None, None, None, None, None, None, None, None, None, None, None) => { // DOIs always stored lower-case; lookups are case-insensitive let doi = doi.to_lowercase(); check_doi(&doi)?; @@ -304,6 +306,7 @@ impl Server { None, None, None, + None, ) => { check_wikidata_qid(wikidata_qid)?; release_ident::table @@ -313,7 +316,21 @@ impl Server { .filter(release_ident::redirect_id.is_null()) .first(conn)? } - (None, None, Some(isbn13), None, None, None, None, None, None, None, None, None) => { + ( + None, + None, + Some(isbn13), + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + ) => { check_isbn13(isbn13)?; let (rev, ident, _extid): (ReleaseRevRow, ReleaseIdentRow, ReleaseExtidRow) = release_rev::table @@ -326,7 +343,21 @@ impl Server { .first(conn)?; (ident, rev) } - (None, None, None, Some(pmid), None, None, None, None, None, None, None, None) => { + ( + None, + None, + None, + Some(pmid), + None, + None, + None, + None, + None, + None, + None, + None, + None, + ) => { check_pmid(pmid)?; release_ident::table .inner_join(release_rev::table) @@ -335,7 +366,21 @@ impl Server { .filter(release_ident::redirect_id.is_null()) .first(conn)? } - (None, None, None, None, Some(pmcid), None, None, None, None, None, None, None) => { + ( + None, + None, + None, + None, + Some(pmcid), + None, + None, + None, + None, + None, + None, + None, + None, + ) => { check_pmcid(pmcid)?; release_ident::table .inner_join(release_rev::table) @@ -344,7 +389,21 @@ impl Server { .filter(release_ident::redirect_id.is_null()) .first(conn)? } - (None, None, None, None, None, Some(core), None, None, None, None, None, None) => { + ( + None, + None, + None, + None, + None, + Some(core), + None, + None, + None, + None, + None, + None, + None, + ) => { check_core_id(core)?; release_ident::table .inner_join(release_rev::table) @@ -353,7 +412,21 @@ impl Server { .filter(release_ident::redirect_id.is_null()) .first(conn)? } - (None, None, None, None, None, None, Some(arxiv), None, None, None, None, None) => { + ( + None, + None, + None, + None, + None, + None, + Some(arxiv), + None, + None, + None, + None, + None, + None, + ) => { // TODO: this allows only lookup by full, versioned arxiv identifier. Probably also // want to allow lookup by "work" style identifier? check_arxiv_id(arxiv)?; @@ -368,7 +441,21 @@ impl Server { .first(conn)?; (ident, rev) } - (None, None, None, None, None, None, None, Some(jstor), None, None, None, None) => { + ( + None, + None, + None, + None, + None, + None, + None, + Some(jstor), + None, + None, + None, + None, + None, + ) => { check_jstor_id(jstor)?; let (rev, ident, _extid): (ReleaseRevRow, ReleaseIdentRow, ReleaseExtidRow) = release_rev::table @@ -381,7 +468,7 @@ impl Server { .first(conn)?; (ident, rev) } - (None, None, None, None, None, None, None, None, Some(ark), None, None, None) => { + (None, None, None, None, None, None, None, None, Some(ark), None, None, None, None) => { check_ark_id(ark)?; let (rev, ident, _extid): (ReleaseRevRow, ReleaseIdentRow, ReleaseExtidRow) = release_rev::table @@ -394,7 +481,7 @@ impl Server { .first(conn)?; (ident, rev) } - (None, None, None, None, None, None, None, None, None, Some(mag), None, None) => { + (None, None, None, None, None, None, None, None, None, Some(mag), None, None, None) => { check_mag_id(mag)?; let (rev, ident, _extid): (ReleaseRevRow, ReleaseIdentRow, ReleaseExtidRow) = release_rev::table @@ -407,7 +494,21 @@ impl Server { .first(conn)?; (ident, rev) } - (None, None, None, None, None, None, None, None, None, None, Some(doaj), None) => { + ( + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + Some(doaj), + None, + None, + ) => { check_doaj_id(doaj)?; let (rev, ident, _extid): (ReleaseRevRow, ReleaseIdentRow, ReleaseExtidRow) = release_rev::table @@ -420,7 +521,21 @@ impl Server { .first(conn)?; (ident, rev) } - (None, None, None, None, None, None, None, None, None, None, None, Some(dblp)) => { + ( + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + Some(dblp), + None, + ) => { check_dblp_id(dblp)?; let (rev, ident, _extid): (ReleaseRevRow, ReleaseIdentRow, ReleaseExtidRow) = release_rev::table @@ -433,6 +548,19 @@ impl Server { .first(conn)?; (ident, rev) } + (None, None, None, None, None, None, None, None, None, None, None, None, Some(oai)) => { + check_oai_id(oai)?; + let (rev, ident, _extid): (ReleaseRevRow, ReleaseIdentRow, ReleaseExtidRow) = + release_rev::table + .inner_join(release_ident::table) + .inner_join(release_rev_extid::table) + .filter(release_rev_extid::extid_type.eq("oai".to_string())) + .filter(release_rev_extid::value.eq(oai)) + .filter(release_ident::is_live.eq(true)) + .filter(release_ident::redirect_id.is_null()) + .first(conn)?; + (ident, rev) + } _ => { return Err( FatcatError::MissingOrMultipleExternalId("in lookup".to_string()).into(), diff --git a/rust/src/endpoints.rs b/rust/src/endpoints.rs index 7ac0a068..0dd232c6 100644 --- a/rust/src/endpoints.rs +++ b/rust/src/endpoints.rs @@ -739,6 +739,7 @@ impl Api for Server { mag: Option, doaj: Option, dblp: Option, + oai: Option, expand: Option, hide: Option, _context: &Context, @@ -768,6 +769,7 @@ impl Api for Server { &mag, &doaj, &dblp, + &oai, expand_flags, hide_flags, ) diff --git a/rust/src/entity_crud.rs b/rust/src/entity_crud.rs index bac8c0fc..0d72788d 100644 --- a/rust/src/entity_crud.rs +++ b/rust/src/entity_crud.rs @@ -1746,6 +1746,7 @@ impl EntityCrud for ReleaseEntity { mag: None, doaj: None, dblp: None, + oai: None, }, refs: None, contribs: None, @@ -2024,6 +2025,7 @@ impl EntityCrud for ReleaseEntity { mag: None, doaj: None, dblp: None, + oai: None, }; let extid_rows: Vec = release_rev_extid::table @@ -2038,6 +2040,7 @@ impl EntityCrud for ReleaseEntity { "mag" => ext_ids.mag = Some(extid_row.value), "doaj" => ext_ids.doaj = Some(extid_row.value), "dblp" => ext_ids.dblp = Some(extid_row.value), + "oai" => ext_ids.oai = Some(extid_row.value), _ => (), } } @@ -2312,6 +2315,13 @@ impl EntityCrud for ReleaseEntity { value: extid.clone(), }); }; + if let Some(extid) = &model.ext_ids.oai { + release_extid_rows.push(ReleaseExtidRow { + release_rev: *rev_id, + extid_type: "oai".to_string(), + value: extid.clone(), + }); + }; } for (model, rev_id) in models.iter().zip(rev_ids.iter()) { diff --git a/rust/src/identifiers.rs b/rust/src/identifiers.rs index 22ffcc79..76f978f9 100644 --- a/rust/src/identifiers.rs +++ b/rust/src/identifiers.rs @@ -411,6 +411,44 @@ fn test_check_dblp_id() { assert!(check_dblp_id("").is_err()); } +pub fn check_oai_id(raw: &str) -> Result<()> { + lazy_static! { + // http://www.openarchives.org/OAI/2.0/guidelines-oai-identifier.htm + static ref RE: Regex = Regex::new(r"^oai:[a-zA-Z][a-zA-Z0-9\-]*(\.[a-zA-Z][a-zA-Z0-9\-]*)+:[a-zA-Z0-9\-_\.!~\*'\(\);/\?:@&=\+$,%]+$").unwrap(); + } + if raw.is_ascii() && RE.is_match(raw) { + Ok(()) + } else { + Err(FatcatError::MalformedChecksum( + "OAI-PMH identifier (expected, eg, 'oai:foo.org:some-local-id-54')".to_string(), + raw.to_string(), + ))? + } +} + +#[test] +fn test_check_oai_id() { + assert!(check_oai_id("journals/entcs/GoubaultM12").is_err()); + assert!(check_oai_id("10.123*").is_err()); + assert!(check_oai_id("").is_err()); + assert!(check_oai_id("something:arXiv.org:hep-th/9901001").is_err()); // bad schema + assert!(check_oai_id("oai:999:abc123").is_err()); // namespace-identifier must not start with digit + assert!(check_oai_id("oai:wibble:abc123").is_err()); // namespace-identifier must be domain name + assert!(check_oai_id("oai:wibble.org:ab cd").is_err()); // space not permitted (must be escaped as %20) + assert!(check_oai_id("oai:wibble.org:ab#cd").is_err()); // # not permitted + assert!(check_oai_id("oai:wibble.org:ab Result<()> { lazy_static! { static ref RE: Regex = Regex::new(r"^\d{4}-\d{3}[0-9X]$").unwrap(); -- cgit v1.2.3