aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2018-12-13 19:36:57 +0800
committerBryan Newbold <bnewbold@robocracy.org>2018-12-13 19:36:57 +0800
commit54abbfcd57fa82624504a1f2f359aa668e75f3d8 (patch)
treeef84f9de9f734386678c27c98685c4da27311d51
parent061e66c4c41063e6b7321f1f421b5152e9e5a84d (diff)
downloadfatcat-54abbfcd57fa82624504a1f2f359aa668e75f3d8.tar.gz
fatcat-54abbfcd57fa82624504a1f2f359aa668e75f3d8.zip
skeleton out new schema features
-rw-r--r--rust/src/api_entity_crud.rs80
-rw-r--r--rust/src/api_server.rs190
-rw-r--r--rust/src/api_wrappers.rs282
-rw-r--r--rust/src/lib.rs4
-rw-r--r--rust/tests/test_old_python_tests.rs12
5 files changed, 493 insertions, 75 deletions
diff --git a/rust/src/api_entity_crud.rs b/rust/src/api_entity_crud.rs
index 3a2760c2..814b42da 100644
--- a/rust/src/api_entity_crud.rs
+++ b/rust/src/api_entity_crud.rs
@@ -23,6 +23,9 @@ use uuid::Uuid;
* db_update
* db_delete
* db_get_history
+ * db_get_edit
+ * db_delete_edit
+ * db_get_redirects
*
* For now, these will probably be macros, until we can level up our trait/generics foo.
*/
@@ -66,6 +69,9 @@ where
ident: FatCatId,
limit: Option<i64>,
) -> Result<Vec<EntityHistoryEntry>>;
+ fn db_get_edit(conn: &DbConn, edit_id: i64) -> Result<Self::EditRow>;
+ fn db_delete_edit(conn: &DbConn, edit_id: i64) -> Result<()>;
+ fn db_get_redirects(conn: &DbConn, ident: FatCatId) -> Result<Vec<FatCatId>>;
fn db_accept_edits(conn: &DbConn, editgroup_id: FatCatId) -> Result<u64>;
// Entity-specific Methods
@@ -260,6 +266,47 @@ macro_rules! generic_db_get_history {
};
}
+macro_rules! generic_db_get_edit {
+ ($edit_table:ident) => {
+ fn db_get_edit(conn: &DbConn, edit_id: i64) -> Result<Self::EditRow> {
+ Ok($edit_table::table.find(edit_id).first(conn)?)
+ }
+ };
+}
+
+macro_rules! generic_db_delete_edit {
+ ($edit_table:ident) => {
+ /// This method assumes the connection is already in a transaction
+ fn db_delete_edit(conn: &DbConn, edit_id: i64) -> Result<()> {
+ // ensure that edit hasn't been accepted
+ let accepted_rows: Vec<(EditgroupRow, ChangelogRow, Self::EditRow)> = editgroup::table
+ .inner_join(changelog::table)
+ .inner_join($edit_table::table)
+ .filter($edit_table::id.eq(edit_id))
+ .limit(1)
+ .get_results(conn)?;
+ if accepted_rows.len() != 0 {
+ // TODO: should be a 4xx, not a 5xx
+ bail!("attempted to delete an already accepted edit")
+ }
+ diesel::delete($edit_table::table.filter($edit_table::id.eq(edit_id))).execute(conn)?;
+ Ok(())
+ }
+ };
+}
+
+macro_rules! generic_db_get_redirects {
+ ($ident_table:ident) => {
+ fn db_get_redirects(conn: &DbConn, ident: FatCatId) -> Result<Vec<FatCatId>> {
+ let res: Vec<Uuid> = $ident_table::table
+ .select($ident_table::id)
+ .filter($ident_table::redirect_id.eq(ident.to_uuid()))
+ .get_results(conn)?;
+ Ok(res.iter().map(|u| FatCatId::from_uuid(u)).collect())
+ }
+ };
+}
+
/*
// This would be the clean and efficient way, but see:
// https://github.com/diesel-rs/diesel/issues/1478
@@ -382,6 +429,9 @@ impl EntityCrud for ContainerEntity {
generic_db_update!(container_ident, container_edit);
generic_db_delete!(container_ident, container_edit);
generic_db_get_history!(container_edit);
+ generic_db_get_edit!(container_edit);
+ generic_db_delete_edit!(container_edit);
+ generic_db_get_redirects!(container_ident);
generic_db_accept_edits_batch!("container");
generic_db_insert_rev!();
@@ -404,7 +454,7 @@ impl EntityCrud for ContainerEntity {
issnl: rev_row.issnl,
wikidata_qid: rev_row.wikidata_qid,
publisher: rev_row.publisher,
- name: rev_row.name,
+ name: Some(rev_row.name),
abbrev: rev_row.abbrev,
coden: rev_row.coden,
state: state,
@@ -432,7 +482,7 @@ impl EntityCrud for ContainerEntity {
models
.iter()
.map(|model| ContainerRevNewRow {
- name: model.name.clone(),
+ name: model.name.clone().unwrap(), // XXX: unwrap
publisher: model.publisher.clone(),
issnl: model.issnl.clone(),
wikidata_qid: model.wikidata_qid.clone(),
@@ -461,6 +511,9 @@ impl EntityCrud for CreatorEntity {
generic_db_update!(creator_ident, creator_edit);
generic_db_delete!(creator_ident, creator_edit);
generic_db_get_history!(creator_edit);
+ generic_db_get_edit!(creator_edit);
+ generic_db_delete_edit!(creator_edit);
+ generic_db_get_redirects!(creator_ident);
generic_db_accept_edits_batch!("creator");
generic_db_insert_rev!();
@@ -479,7 +532,7 @@ impl EntityCrud for CreatorEntity {
None => (None, None, None),
};
Ok(CreatorEntity {
- display_name: rev_row.display_name,
+ display_name: Some(rev_row.display_name),
given_name: rev_row.given_name,
surname: rev_row.surname,
orcid: rev_row.orcid,
@@ -509,7 +562,7 @@ impl EntityCrud for CreatorEntity {
models
.iter()
.map(|model| CreatorRevNewRow {
- display_name: model.display_name.clone(),
+ display_name: model.display_name.clone().unwrap(), // XXX: unwrap
given_name: model.given_name.clone(),
surname: model.surname.clone(),
orcid: model.orcid.clone(),
@@ -537,6 +590,9 @@ impl EntityCrud for FileEntity {
generic_db_update!(file_ident, file_edit);
generic_db_delete!(file_ident, file_edit);
generic_db_get_history!(file_edit);
+ generic_db_get_edit!(file_edit);
+ generic_db_delete_edit!(file_edit);
+ generic_db_get_redirects!(file_ident);
generic_db_accept_edits_batch!("file");
generic_db_insert_rev!();
@@ -667,6 +723,9 @@ impl EntityCrud for ReleaseEntity {
generic_db_update!(release_ident, release_edit);
generic_db_delete!(release_ident, release_edit);
generic_db_get_history!(release_edit);
+ generic_db_get_edit!(release_edit);
+ generic_db_delete_edit!(release_edit);
+ generic_db_get_redirects!(release_ident);
generic_db_accept_edits_batch!("release");
generic_db_insert_rev!();
@@ -680,7 +739,11 @@ impl EntityCrud for ReleaseEntity {
}
if expand.container {
if let Some(ref cid) = self.container_id {
- self.container = Some(ContainerEntity::db_get(conn, FatCatId::from_str(&cid)?, HideFlags::none())?);
+ self.container = Some(ContainerEntity::db_get(
+ conn,
+ FatCatId::from_str(&cid)?,
+ HideFlags::none(),
+ )?);
}
}
Ok(())
@@ -847,7 +910,7 @@ impl EntityCrud for ReleaseEntity {
};
Ok(ReleaseEntity {
- title: rev_row.title,
+ title: Some(rev_row.title),
release_type: rev_row.release_type,
release_status: rev_row.release_status,
release_date: rev_row.release_date,
@@ -913,7 +976,7 @@ impl EntityCrud for ReleaseEntity {
.iter()
.map(|model| {
Ok(ReleaseRevNewRow {
- title: model.title.clone(),
+ title: model.title.clone().unwrap(), // XXX: unwrap()
release_type: model.release_type.clone(),
release_status: model.release_status.clone(),
release_date: model.release_date,
@@ -1071,6 +1134,9 @@ impl EntityCrud for WorkEntity {
generic_db_update!(work_ident, work_edit);
generic_db_delete!(work_ident, work_edit);
generic_db_get_history!(work_edit);
+ generic_db_get_edit!(work_edit);
+ generic_db_delete_edit!(work_edit);
+ generic_db_get_redirects!(work_ident);
generic_db_accept_edits_batch!("work");
generic_db_insert_rev!();
diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs
index 2bcd4a7f..0a415e91 100644
--- a/rust/src/api_server.rs
+++ b/rust/src/api_server.rs
@@ -63,32 +63,75 @@ pub fn get_release_files(id: FatCatId, hide: HideFlags, conn: &DbConn) -> Result
.load(conn)?;
rows.into_iter()
- .map(
- |(rev, ident, _)| FileEntity::db_from_row(conn, rev, Some(ident), hide),
- ).collect()
+ .map(|(rev, ident, _)| FileEntity::db_from_row(conn, rev, Some(ident), hide))
+ .collect()
}
impl Server {
- pub fn lookup_container_handler(&self, issnl: &str, hide: HideFlags, conn: &DbConn) -> Result<ContainerEntity> {
- check_issn(issnl)?;
- let (ident, rev): (ContainerIdentRow, ContainerRevRow) = container_ident::table
- .inner_join(container_rev::table)
- .filter(container_rev::issnl.eq(issnl))
- .filter(container_ident::is_live.eq(true))
- .filter(container_ident::redirect_id.is_null())
- .first(conn)?;
+ pub fn lookup_container_handler(
+ &self,
+ issnl: &Option<String>,
+ wikidata_qid: &Option<String>,
+ hide: HideFlags,
+ conn: &DbConn,
+ ) -> Result<ContainerEntity> {
+ let (ident, rev): (ContainerIdentRow, ContainerRevRow) = match (issnl, wikidata_qid) {
+ (Some(issnl), None) => {
+ check_issn(issnl)?;
+ container_ident::table
+ .inner_join(container_rev::table)
+ .filter(container_rev::issnl.eq(&issnl))
+ .filter(container_ident::is_live.eq(true))
+ .filter(container_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ (None, Some(wikidata_qid)) => {
+ check_issn(wikidata_qid)?;
+ container_ident::table
+ .inner_join(container_rev::table)
+ .filter(container_rev::wikidata_qid.eq(&wikidata_qid))
+ .filter(container_ident::is_live.eq(true))
+ .filter(container_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ _ => {
+ return Err(ErrorKind::MissingOrMultipleExternalId("in lookup".to_string()).into());
+ }
+ };
ContainerEntity::db_from_row(conn, rev, Some(ident), hide)
}
- pub fn lookup_creator_handler(&self, orcid: &str, hide: HideFlags, conn: &DbConn) -> Result<CreatorEntity> {
- check_orcid(orcid)?;
- let (ident, rev): (CreatorIdentRow, CreatorRevRow) = creator_ident::table
- .inner_join(creator_rev::table)
- .filter(creator_rev::orcid.eq(orcid))
- .filter(creator_ident::is_live.eq(true))
- .filter(creator_ident::redirect_id.is_null())
- .first(conn)?;
+ pub fn lookup_creator_handler(
+ &self,
+ orcid: &Option<String>,
+ wikidata_qid: &Option<String>,
+ hide: HideFlags,
+ conn: &DbConn,
+ ) -> Result<CreatorEntity> {
+ let (ident, rev): (CreatorIdentRow, CreatorRevRow) = match (orcid, wikidata_qid) {
+ (Some(orcid), None) => {
+ check_orcid(orcid)?;
+ creator_ident::table
+ .inner_join(creator_rev::table)
+ .filter(creator_rev::orcid.eq(orcid))
+ .filter(creator_ident::is_live.eq(true))
+ .filter(creator_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ (None, Some(wikidata_qid)) => {
+ check_wikidata_qid(wikidata_qid)?;
+ creator_ident::table
+ .inner_join(creator_rev::table)
+ .filter(creator_rev::wikidata_qid.eq(wikidata_qid))
+ .filter(creator_ident::is_live.eq(true))
+ .filter(creator_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ _ => {
+ return Err(ErrorKind::MissingOrMultipleExternalId("in lookup".to_string()).into());
+ }
+ };
CreatorEntity::db_from_row(conn, rev, Some(ident), hide)
}
@@ -114,30 +157,104 @@ impl Server {
.collect()
}
- pub fn lookup_file_handler(&self, sha1: &str, hide: HideFlags, conn: &DbConn) -> Result<FileEntity> {
- let (ident, rev): (FileIdentRow, FileRevRow) = file_ident::table
- .inner_join(file_rev::table)
- .filter(file_rev::sha1.eq(sha1))
- .filter(file_ident::is_live.eq(true))
- .filter(file_ident::redirect_id.is_null())
- .first(conn)?;
+ pub fn lookup_file_handler(
+ &self,
+ md5: &Option<String>,
+ sha1: &Option<String>,
+ sha256: &Option<String>,
+ hide: HideFlags,
+ conn: &DbConn,
+ ) -> Result<FileEntity> {
+ let (ident, rev): (FileIdentRow, FileRevRow) = match (md5, sha1, sha256) {
+ (Some(md5), None, None) => file_ident::table
+ .inner_join(file_rev::table)
+ .filter(file_rev::md5.eq(md5))
+ .filter(file_ident::is_live.eq(true))
+ .filter(file_ident::redirect_id.is_null())
+ .first(conn)?,
+ (None, Some(sha1), None) => file_ident::table
+ .inner_join(file_rev::table)
+ .filter(file_rev::sha1.eq(sha1))
+ .filter(file_ident::is_live.eq(true))
+ .filter(file_ident::redirect_id.is_null())
+ .first(conn)?,
+ (None, None, Some(sha256)) => file_ident::table
+ .inner_join(file_rev::table)
+ .filter(file_rev::sha256.eq(sha256))
+ .filter(file_ident::is_live.eq(true))
+ .filter(file_ident::redirect_id.is_null())
+ .first(conn)?,
+ _ => {
+ return Err(ErrorKind::MissingOrMultipleExternalId("in lookup".to_string()).into());
+ }
+ };
FileEntity::db_from_row(conn, rev, Some(ident), hide)
}
pub fn lookup_release_handler(
&self,
- doi: &str,
+ doi: &Option<String>,
+ wikidata_qid: &Option<String>,
+ isbn13: &Option<String>,
+ pmid: &Option<String>,
+ pmcid: &Option<String>,
hide: HideFlags,
conn: &DbConn,
) -> Result<ReleaseEntity> {
- check_doi(doi)?;
- let (ident, rev): (ReleaseIdentRow, ReleaseRevRow) = release_ident::table
- .inner_join(release_rev::table)
- .filter(release_rev::doi.eq(doi))
- .filter(release_ident::is_live.eq(true))
- .filter(release_ident::redirect_id.is_null())
- .first(conn)?;
+ let (ident, rev): (ReleaseIdentRow, ReleaseRevRow) =
+ match (doi, wikidata_qid, isbn13, pmid, pmcid) {
+ (Some(doi), None, None, None, None) => {
+ check_doi(doi)?;
+ release_ident::table
+ .inner_join(release_rev::table)
+ .filter(release_rev::doi.eq(doi))
+ .filter(release_ident::is_live.eq(true))
+ .filter(release_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ (None, Some(wikidata_qid), None, None, None) => {
+ check_wikidata_qid(wikidata_qid)?;
+ release_ident::table
+ .inner_join(release_rev::table)
+ .filter(release_rev::wikidata_qid.eq(wikidata_qid))
+ .filter(release_ident::is_live.eq(true))
+ .filter(release_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ (None, None, Some(isbn13), None, None) => {
+ // TODO: check_isbn13(isbn13)?;
+ release_ident::table
+ .inner_join(release_rev::table)
+ .filter(release_rev::isbn13.eq(isbn13))
+ .filter(release_ident::is_live.eq(true))
+ .filter(release_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ (None, None, None, Some(pmid), None) => {
+ check_pmid(pmid)?;
+ release_ident::table
+ .inner_join(release_rev::table)
+ .filter(release_rev::pmid.eq(pmid))
+ .filter(release_ident::is_live.eq(true))
+ .filter(release_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ (None, None, None, None, Some(pmcid)) => {
+ check_pmcid(pmcid)?;
+ release_ident::table
+ .inner_join(release_rev::table)
+ .filter(release_rev::pmcid.eq(pmcid))
+ .filter(release_ident::is_live.eq(true))
+ .filter(release_ident::redirect_id.is_null())
+ .first(conn)?
+ }
+ _ => {
+ return Err(
+ ErrorKind::MissingOrMultipleExternalId("in lookup".to_string()).into(),
+ );
+ }
+ };
ReleaseEntity::db_from_row(conn, rev, Some(ident), hide)
}
@@ -165,9 +282,8 @@ impl Server {
.load(conn)?;
rows.into_iter()
- .map(|(rev, ident)| {
- ReleaseEntity::db_from_row(conn, rev, Some(ident), hide)
- }).collect()
+ .map(|(rev, ident)| ReleaseEntity::db_from_row(conn, rev, Some(ident), hide))
+ .collect()
}
pub fn accept_editgroup_handler(&self, id: FatCatId, conn: &DbConn) -> Result<()> {
diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs
index e5176ac6..8c274fb5 100644
--- a/rust/src/api_wrappers.rs
+++ b/rust/src/api_wrappers.rs
@@ -11,6 +11,7 @@ use fatcat_api_spec::models::*;
use fatcat_api_spec::*;
use futures::{self, Future};
use std::str::FromStr;
+use uuid::Uuid;
/// Helper for generating wrappers (which return "Box::new(futures::done(Ok(BLAH)))" like the
/// codegen fatcat-api-spec code wants) that call through to actual helpers (which have simple
@@ -20,11 +21,12 @@ macro_rules! wrap_entity_handlers {
// stable doesn't have a mechanism to "concat" or generate new identifiers in macros, at least
// in the context of defining new functions.
// The only stable approach I know of would be: https://github.com/dtolnay/mashup
- ($get_fn:ident, $get_resp:ident, $post_fn:ident,
- $post_resp:ident, $post_batch_fn:ident, $post_batch_handler:ident,
- $post_batch_resp:ident, $update_fn:ident, $update_resp:ident,
- $delete_fn:ident, $delete_resp:ident, $get_history_fn:ident,
- $get_history_resp:ident, $model:ident) => {
+ ($get_fn:ident, $get_resp:ident, $post_fn:ident, $post_resp:ident, $post_batch_fn:ident,
+ $post_batch_handler:ident, $post_batch_resp:ident, $update_fn:ident, $update_resp:ident,
+ $delete_fn:ident, $delete_resp:ident, $get_history_fn:ident, $get_history_resp:ident,
+ $get_edit_fn:ident, $get_edit_resp:ident, $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,
@@ -244,14 +246,131 @@ macro_rules! wrap_entity_handlers {
};
Box::new(futures::done(Ok(ret)))
}
+
+ fn $get_rev_fn(
+ &self,
+ id: String,
+ expand: Option<String>,
+ hide: Option<String>,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_rev_resp, Error = ApiError> + Send> {
+ let conn = self.db_pool.get().expect("db_pool error");
+ // No transaction for GET
+ let ret = match conn.transaction(|| {
+ let rev_id = Uuid::from_str(&id)?;
+ let hide_flags = match hide {
+ None => HideFlags::none(),
+ Some(param) => HideFlags::from_str(&param)?,
+ };
+ match expand {
+ None => $model::db_get_rev(&conn, rev_id, hide_flags),
+ Some(param) => {
+ let expand_flags = ExpandFlags::from_str(&param)?;
+ let mut entity = $model::db_get_rev(&conn, rev_id, hide_flags)?;
+ entity.db_expand(&conn, expand_flags)?;
+ Ok(entity)
+ },
+ }
+ }) {
+ Ok(entity) =>
+ $get_rev_resp::FoundEntityRevision(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_rev_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $get_rev_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(Error(ErrorKind::MalformedExternalId(e), _)) =>
+ $get_rev_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $get_rev_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $get_edit_fn(
+ &self,
+ edit_id: i64,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_edit_resp, Error = ApiError> + Send> {
+ let conn = self.db_pool.get().expect("db_pool error");
+ // No transaction for GET
+ let ret = match conn.transaction(|| {
+ $model::db_get_edit(&conn, edit_id)?.into_model()
+ }) {
+ Ok(edit) =>
+ $get_edit_resp::FoundEdit(edit),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_edit_resp::NotFound(ErrorResponse { message: format!("No such {} entity edit: {}", stringify!($model), edit_id) }),
+ Err(e) => {
+ error!("{}", e);
+ $get_edit_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $delete_edit_fn(
+ &self,
+ edit_id: i64,
+ _context: &Context,
+ ) -> Box<Future<Item = $delete_edit_resp, Error = ApiError> + Send> {
+ let conn = self.db_pool.get().expect("db_pool error");
+ let ret = match conn.transaction(|| {
+ $model::db_delete_edit(&conn, edit_id)
+ }) {
+ Ok(()) =>
+ $delete_edit_resp::DeletedEdit(Success { message: format!("Successfully deleted work-in-progress {} edit: {}", stringify!($model), edit_id) } ),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $delete_edit_resp::NotFound(ErrorResponse { message: format!("No such {} edit: {}", stringify!($model), edit_id) }),
+ Err(Error(ErrorKind::Diesel(e), _)) =>
+ $delete_edit_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $delete_edit_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $get_redirects_fn(
+ &self,
+ id: String,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_redirects_resp, Error = ApiError> + Send> {
+ let conn = self.db_pool.get().expect("db_pool error");
+ // No transaction for GET
+ let ret = match conn.transaction(|| {
+ let entity_id = FatCatId::from_str(&id)?;
+ let redirects: Vec<FatCatId> = $model::db_get_redirects(&conn, entity_id)?;
+ Ok(redirects.into_iter().map(|fcid| fcid.to_string()).collect())
+ }) {
+ Ok(redirects) =>
+ $get_redirects_resp::FoundEntityRedirects(redirects),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_redirects_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $get_redirects_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(Error(ErrorKind::InvalidFatcatId(e), _)) =>
+ $get_redirects_resp::BadRequest(ErrorResponse {
+ message: ErrorKind::InvalidFatcatId(e).to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $get_redirects_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
}
}
macro_rules! wrap_lookup_handler {
- ($get_fn:ident, $get_handler:ident, $get_resp:ident, $idname:ident, $idtype:ident) => {
+ ($get_fn:ident, $get_handler:ident, $get_resp:ident, $idname:ident) => {
fn $get_fn(
&self,
- $idname: $idtype,
+ $idname: Option<String>,
+ wikidata_qid: Option<String>,
hide: Option<String>,
_context: &Context,
) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
@@ -261,11 +380,11 @@ macro_rules! wrap_lookup_handler {
Some(param) => HideFlags::from_str(&param).unwrap(),
};
// No transaction for GET
- let ret = match self.$get_handler(&$idname, hide_flags, &conn) {
+ let ret = match self.$get_handler(&$idname, &wikidata_qid, hide_flags, &conn) {
Ok(entity) =>
$get_resp::FoundEntity(entity),
Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
- $get_resp::NotFound(ErrorResponse { message: format!("Not found: {}", $idname) }),
+ $get_resp::NotFound(ErrorResponse { message: format!("Not found: {:?} / {:?}", $idname, wikidata_qid) }),
Err(Error(ErrorKind::MalformedExternalId(e), _)) =>
$get_resp::BadRequest(ErrorResponse { message: e.to_string() }),
Err(e) => {
@@ -360,6 +479,14 @@ impl Api for Server {
DeleteContainerResponse,
get_container_history,
GetContainerHistoryResponse,
+ get_container_edit,
+ GetContainerEditResponse,
+ delete_container_edit,
+ DeleteContainerEditResponse,
+ get_container_revision,
+ GetContainerRevisionResponse,
+ get_container_redirects,
+ GetContainerRedirectsResponse,
ContainerEntity
);
@@ -377,6 +504,14 @@ impl Api for Server {
DeleteCreatorResponse,
get_creator_history,
GetCreatorHistoryResponse,
+ get_creator_edit,
+ GetCreatorEditResponse,
+ delete_creator_edit,
+ DeleteCreatorEditResponse,
+ get_creator_revision,
+ GetCreatorRevisionResponse,
+ get_creator_redirects,
+ GetCreatorRedirectsResponse,
CreatorEntity
);
wrap_entity_handlers!(
@@ -393,6 +528,14 @@ impl Api for Server {
DeleteFileResponse,
get_file_history,
GetFileHistoryResponse,
+ get_file_edit,
+ GetFileEditResponse,
+ delete_file_edit,
+ DeleteFileEditResponse,
+ get_file_revision,
+ GetFileRevisionResponse,
+ get_file_redirects,
+ GetFileRedirectsResponse,
FileEntity
);
wrap_entity_handlers!(
@@ -409,6 +552,14 @@ impl Api for Server {
DeleteReleaseResponse,
get_release_history,
GetReleaseHistoryResponse,
+ get_release_edit,
+ GetReleaseEditResponse,
+ delete_release_edit,
+ DeleteReleaseEditResponse,
+ get_release_revision,
+ GetReleaseRevisionResponse,
+ get_release_redirects,
+ GetReleaseRedirectsResponse,
ReleaseEntity
);
wrap_entity_handlers!(
@@ -425,6 +576,14 @@ impl Api for Server {
DeleteWorkResponse,
get_work_history,
GetWorkHistoryResponse,
+ get_work_edit,
+ GetWorkEditResponse,
+ delete_work_edit,
+ DeleteWorkEditResponse,
+ get_work_revision,
+ GetWorkRevisionResponse,
+ get_work_redirects,
+ GetWorkRedirectsResponse,
WorkEntity
);
@@ -432,29 +591,13 @@ impl Api for Server {
lookup_container,
lookup_container_handler,
LookupContainerResponse,
- issnl,
- String
+ issnl
);
wrap_lookup_handler!(
lookup_creator,
lookup_creator_handler,
LookupCreatorResponse,
- orcid,
- String
- );
- wrap_lookup_handler!(
- lookup_file,
- lookup_file_handler,
- LookupFileResponse,
- sha1,
- String
- );
- wrap_lookup_handler!(
- lookup_release,
- lookup_release_handler,
- LookupReleaseResponse,
- doi,
- String
+ orcid
);
wrap_fcid_hide_handler!(
@@ -479,6 +622,91 @@ impl Api for Server {
GetEditorChangelogResponse
);
+ fn lookup_file(
+ &self,
+ md5: Option<String>,
+ sha1: Option<String>,
+ sha256: Option<String>,
+ hide: Option<String>,
+ _context: &Context,
+ ) -> Box<Future<Item = LookupFileResponse, Error = ApiError> + Send> {
+ let conn = self.db_pool.get().expect("db_pool error");
+ let hide_flags = match hide {
+ None => HideFlags::none(),
+ Some(param) => HideFlags::from_str(&param).unwrap(),
+ };
+ // No transaction for GET
+ let ret = match self.lookup_file_handler(&md5, &sha1, &sha256, hide_flags, &conn) {
+ Ok(entity) => LookupFileResponse::FoundEntity(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
+ LookupFileResponse::NotFound(ErrorResponse {
+ message: format!("Not found: {:?} / {:?} / {:?}", md5, sha1, sha256),
+ })
+ }
+ Err(Error(ErrorKind::MalformedExternalId(e), _)) => {
+ LookupFileResponse::BadRequest(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ Err(e) => {
+ error!("{}", e);
+ LookupFileResponse::BadRequest(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn lookup_release(
+ &self,
+ doi: Option<String>,
+ wikidata_qid: Option<String>,
+ isbn13: Option<String>,
+ pmid: Option<String>,
+ pmcid: Option<String>,
+ hide: Option<String>,
+ _context: &Context,
+ ) -> Box<Future<Item = LookupReleaseResponse, Error = ApiError> + Send> {
+ let conn = self.db_pool.get().expect("db_pool error");
+ let hide_flags = match hide {
+ None => HideFlags::none(),
+ Some(param) => HideFlags::from_str(&param).unwrap(),
+ };
+ // No transaction for GET
+ let ret = match self.lookup_release_handler(
+ &doi,
+ &wikidata_qid,
+ &isbn13,
+ &pmid,
+ &pmcid,
+ hide_flags,
+ &conn,
+ ) {
+ Ok(entity) => LookupReleaseResponse::FoundEntity(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
+ LookupReleaseResponse::NotFound(ErrorResponse {
+ message: format!(
+ "Not found: {:?} / {:?} / {:?} / {:?} / {:?}",
+ doi, wikidata_qid, isbn13, pmid, pmcid
+ ),
+ })
+ }
+ Err(Error(ErrorKind::MalformedExternalId(e), _)) => {
+ LookupReleaseResponse::BadRequest(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ Err(e) => {
+ error!("{}", e);
+ LookupReleaseResponse::BadRequest(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
fn accept_editgroup(
&self,
id: String,
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 99035b85..6dbfc468 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -58,6 +58,10 @@ pub mod errors {
description("editgroup was already accepted")
display("attempted to accept an editgroup which was already accepted: {}", id)
}
+ MissingOrMultipleExternalId(message: String) {
+ description("external identifiers missing or multiple specified")
+ display("external identifiers missing or multiple specified; please supply exactly one")
+ }
}
}
}
diff --git a/rust/tests/test_old_python_tests.rs b/rust/tests/test_old_python_tests.rs
index dde8d66e..eae131a7 100644
--- a/rust/tests/test_old_python_tests.rs
+++ b/rust/tests/test_old_python_tests.rs
@@ -30,7 +30,8 @@ fn test_api_rich_create() {
_ => unreachable!(),
};
- let mut new_container = ContainerEntity::new("schmournal".to_string());
+ let mut new_container = ContainerEntity::new();
+ new_container.name = Some("schmournal".to_string());
new_container.publisher = Some("society of authors".to_string());
new_container.issnl = Some("2222-3333".to_string());
// extra=dict(a=2, i="zing"))),
@@ -43,7 +44,8 @@ fn test_api_rich_create() {
_ => unreachable!(),
};
- let mut new_creator = CreatorEntity::new("anon y. mouse".to_string());
+ let mut new_creator = CreatorEntity::new();
+ new_creator.display_name = Some("anon y. mouse".to_string());
new_creator.orcid = Some("0000-0002-1825-0097".to_string());
// extra=dict(a=2, i="zing"))),
let resp = client
@@ -67,7 +69,8 @@ fn test_api_rich_create() {
};
// this stub work will be referenced
- let mut new_release = ReleaseEntity::new("derivative work".to_string());
+ let mut new_release = ReleaseEntity::new();
+ new_release.title = Some("derivative work".to_string());
new_release.release_type = Some("article-journal".to_string());
new_release.work_id = Some(work_id.clone());
let mut contrib = ReleaseContrib::new();
@@ -87,7 +90,8 @@ fn test_api_rich_create() {
_ => unreachable!(),
};
- let mut new_release = ReleaseEntity::new("dummy work".to_string());
+ let mut new_release = ReleaseEntity::new();
+ new_release.title = Some("dummy work".to_string());
new_release.release_type = Some("book".to_string());
new_release.work_id = Some(work_id.clone());
new_release.container_id = Some(container_id.clone());