aboutsummaryrefslogtreecommitdiffstats
path: root/rust/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/api_server.rs492
-rw-r--r--rust/src/api_wrappers.rs414
-rw-r--r--rust/src/lib.rs1
3 files changed, 468 insertions, 439 deletions
diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs
index fa767699..bd211d1f 100644
--- a/rust/src/api_server.rs
+++ b/rust/src/api_server.rs
@@ -1,7 +1,7 @@
//! API endpoint handlers
use ConnectionPool;
-use api_helpers::*;
+use api_helpers::{get_or_create_editgroup, accept_editgroup};
use chrono;
use database_models::*;
use database_schema::{changelog, container_edit, container_ident, container_rev, creator_edit,
@@ -13,133 +13,13 @@ use diesel::{self, insert_into};
use errors::*;
use fatcat_api::models;
use fatcat_api::models::*;
-use fatcat_api::*;
-use futures::{self, Future};
use uuid;
type DbConn = diesel::r2d2::PooledConnection<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
-/// Helper for generating wrappers (which return "Box::new(futures::done(Ok(BLAH)))" like the
-/// codegen fatcat-api code wants) that call through to actual helpers (which have simple Result<>
-/// return types)
-macro_rules! wrap_entity_handlers {
- // Would much rather just have entity ident, then generate the other fields from that, but Rust
- // 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_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) => {
-
- fn $get_fn(
- &self,
- id: String,
- _context: &Context,
- ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
- let ret = match self.$get_handler(id.clone()) {
- Ok(entity) =>
- $get_resp::FoundEntity(entity),
- Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
- $get_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),
- Err(Error(ErrorKind::Uuid(e), _)) =>
- $get_resp::BadRequest(ErrorResponse { message: e.to_string() }),
- Err(e) => {
- error!("{}", e);
- $get_resp::GenericError(ErrorResponse { message: e.to_string() })
- },
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn $post_fn(
- &self,
- entity: models::$model,
- _context: &Context,
- ) -> Box<Future<Item = $post_resp, Error = ApiError> + Send> {
- let ret = match self.$post_handler(entity, None) {
- Ok(edit) =>
- $post_resp::CreatedEntity(edit),
- Err(Error(ErrorKind::Diesel(e), _)) =>
- $post_resp::BadRequest(ErrorResponse { message: e.to_string() }),
- Err(Error(ErrorKind::Uuid(e), _)) =>
- $post_resp::BadRequest(ErrorResponse { message: e.to_string() }),
- Err(e) => {
- error!("{}", e);
- $post_resp::GenericError(ErrorResponse { message: e.to_string() })
- },
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn $post_batch_fn(
- &self,
- entity_list: &Vec<models::$model>,
- _context: &Context,
- ) -> Box<Future<Item = $post_batch_resp, Error = ApiError> + Send> {
- let ret = match self.$post_batch_handler(entity_list) {
- Ok(edit) =>
- $post_batch_resp::CreatedEntities(edit),
- Err(Error(ErrorKind::Diesel(e), _)) =>
- $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }),
- Err(Error(ErrorKind::Uuid(e), _)) =>
- $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }),
- Err(e) => {
- error!("{}", e);
- $post_batch_resp::GenericError(ErrorResponse { message: e.to_string() })
- },
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn $get_history_fn(
- &self,
- id: String,
- limit: Option<i64>,
- _context: &Context,
- ) -> Box<Future<Item = $get_history_resp, Error = ApiError> + Send> {
- let ret = match self.$get_history_handler(id.clone(), limit) {
- Ok(history) =>
- $get_history_resp::FoundEntityHistory(history),
- Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
- $get_history_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),
- Err(Error(ErrorKind::Uuid(e), _)) =>
- $get_history_resp::BadRequest(ErrorResponse { message: e.to_string() }),
- Err(e) => {
- error!("{}", e);
- $get_history_resp::GenericError(ErrorResponse { message: e.to_string() })
- },
- };
- Box::new(futures::done(Ok(ret)))
- }
- }
-}
-
-macro_rules! wrap_lookup_handler {
- ($get_fn:ident, $get_handler:ident, $get_resp:ident, $idname:ident, $idtype:ident) => {
- fn $get_fn(
- &self,
- $idname: $idtype,
- _context: &Context,
- ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
- let ret = match self.$get_handler($idname.clone()) {
- Ok(entity) =>
- $get_resp::FoundEntity(entity),
- Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
- $get_resp::NotFound(ErrorResponse { message: format!("Not found: {}", $idname) }),
- Err(e) => {
- error!("{}", e);
- $get_resp::BadRequest(ErrorResponse { message: e.to_string() })
- },
- };
- Box::new(futures::done(Ok(ret)))
- }
- }
-}
-
macro_rules! entity_batch_handler {
($post_handler:ident, $post_batch_handler:ident, $model:ident) => {
- fn $post_batch_handler(&self, entity_list: &Vec<models::$model>) ->
+ pub fn $post_batch_handler(&self, entity_list: &Vec<models::$model>) ->
Result<Vec<EntityEdit>> {
let conn = self.db_pool.get().expect("db_pool error");
// TODO: start a transaction
@@ -154,7 +34,7 @@ macro_rules! entity_batch_handler {
macro_rules! entity_history_handler {
($history_handler:ident, $edit_row_type:ident, $edit_table:ident) => {
- fn $history_handler(
+ pub fn $history_handler(
&self,
id: String,
limit: Option<i64>,
@@ -380,7 +260,7 @@ fn work_row2entity(ident: Option<WorkIdentRow>, rev: WorkRevRow) -> Result<WorkE
}
impl Server {
- fn get_container_handler(&self, id: String) -> Result<ContainerEntity> {
+ pub fn get_container_handler(&self, id: String) -> Result<ContainerEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let id = uuid::Uuid::parse_str(&id)?;
@@ -393,7 +273,7 @@ impl Server {
container_row2entity(Some(ident), rev)
}
- fn lookup_container_handler(&self, issnl: String) -> Result<ContainerEntity> {
+ pub fn lookup_container_handler(&self, issnl: String) -> Result<ContainerEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let (ident, rev): (ContainerIdentRow, ContainerRevRow) = container_ident::table
@@ -406,7 +286,7 @@ impl Server {
container_row2entity(Some(ident), rev)
}
- fn get_creator_handler(&self, id: String) -> Result<CreatorEntity> {
+ pub fn get_creator_handler(&self, id: String) -> Result<CreatorEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let id = uuid::Uuid::parse_str(&id)?;
@@ -418,7 +298,7 @@ impl Server {
creator_row2entity(Some(ident), rev)
}
- fn lookup_creator_handler(&self, orcid: String) -> Result<CreatorEntity> {
+ pub fn lookup_creator_handler(&self, orcid: String) -> Result<CreatorEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let (ident, rev): (CreatorIdentRow, CreatorRevRow) = creator_ident::table
@@ -431,7 +311,7 @@ impl Server {
creator_row2entity(Some(ident), rev)
}
- fn get_creator_releases_handler(&self, id: String) -> Result<Vec<ReleaseEntity>> {
+ pub fn get_creator_releases_handler(&self, id: String) -> Result<Vec<ReleaseEntity>> {
let conn = self.db_pool.get().expect("db_pool error");
let id = uuid::Uuid::parse_str(&id)?;
@@ -449,7 +329,7 @@ impl Server {
.collect()
}
- fn get_file_handler(&self, id: String) -> Result<FileEntity> {
+ pub fn get_file_handler(&self, id: String) -> Result<FileEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let id = uuid::Uuid::parse_str(&id)?;
@@ -461,7 +341,7 @@ impl Server {
file_row2entity(Some(ident), rev, &conn)
}
- fn lookup_file_handler(&self, sha1: String) -> Result<FileEntity> {
+ pub fn lookup_file_handler(&self, sha1: String) -> Result<FileEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let (ident, rev): (FileIdentRow, FileRevRow) = file_ident::table
@@ -474,7 +354,7 @@ impl Server {
file_row2entity(Some(ident), rev, &conn)
}
- fn get_release_handler(&self, id: String) -> Result<ReleaseEntity> {
+ pub fn get_release_handler(&self, id: String) -> Result<ReleaseEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let id = uuid::Uuid::parse_str(&id)?;
@@ -486,7 +366,7 @@ impl Server {
release_row2entity(Some(ident), rev, &conn)
}
- fn lookup_release_handler(&self, doi: String) -> Result<ReleaseEntity> {
+ pub fn lookup_release_handler(&self, doi: String) -> Result<ReleaseEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let (ident, rev): (ReleaseIdentRow, ReleaseRevRow) = release_ident::table
@@ -499,7 +379,7 @@ impl Server {
release_row2entity(Some(ident), rev, &conn)
}
- fn get_release_files_handler(&self, id: String) -> Result<Vec<FileEntity>> {
+ pub fn get_release_files_handler(&self, id: String) -> Result<Vec<FileEntity>> {
let conn = self.db_pool.get().expect("db_pool error");
let id = uuid::Uuid::parse_str(&id)?;
@@ -516,7 +396,7 @@ impl Server {
.collect()
}
- fn get_work_handler(&self, id: String) -> Result<WorkEntity> {
+ pub fn get_work_handler(&self, id: String) -> Result<WorkEntity> {
let conn = self.db_pool.get().expect("db_pool error");
let id = uuid::Uuid::parse_str(&id)?;
@@ -528,7 +408,7 @@ impl Server {
work_row2entity(Some(ident), rev)
}
- fn get_work_releases_handler(&self, id: String) -> Result<Vec<ReleaseEntity>> {
+ pub fn get_work_releases_handler(&self, id: String) -> Result<Vec<ReleaseEntity>> {
let conn = self.db_pool.get().expect("db_pool error");
let id = uuid::Uuid::parse_str(&id)?;
@@ -544,7 +424,7 @@ impl Server {
.collect()
}
- fn create_container_handler(
+ pub fn create_container_handler(
&self,
entity: models::ContainerEntity,
conn: Option<&DbConn>,
@@ -587,7 +467,7 @@ impl Server {
edit.to_model()
}
- fn create_creator_handler(
+ pub fn create_creator_handler(
&self,
entity: models::CreatorEntity,
conn: Option<&DbConn>,
@@ -628,7 +508,7 @@ impl Server {
edit.to_model()
}
- fn create_file_handler(
+ pub fn create_file_handler(
&self,
entity: models::FileEntity,
conn: Option<&DbConn>,
@@ -694,7 +574,7 @@ impl Server {
edit.to_model()
}
- fn create_release_handler(
+ pub fn create_release_handler(
&self,
entity: models::ReleaseEntity,
conn: Option<&DbConn>,
@@ -826,7 +706,7 @@ impl Server {
edit.to_model()
}
- fn create_work_handler(
+ pub fn create_work_handler(
&self,
entity: models::WorkEntity,
conn: Option<&DbConn>,
@@ -866,7 +746,34 @@ impl Server {
edit.to_model()
}
- fn get_editgroup_handler(&self, id: i64) -> Result<Editgroup> {
+ pub fn accept_editgroup_handler(&self, id: i64) -> Result<()> {
+ let conn = self.db_pool.get().expect("db_pool error");
+ accept_editgroup(id as i64, &conn)?;
+ Ok(())
+ }
+
+ pub fn create_editgroup_handler(&self, entity: models::Editgroup) -> Result<Editgroup> {
+ let conn = self.db_pool.get().expect("db_pool error");
+
+ let row: EditgroupRow = insert_into(editgroup::table)
+ .values((
+ editgroup::editor_id.eq(entity.editor_id as i64),
+ editgroup::description.eq(entity.description),
+ editgroup::extra_json.eq(entity.extra),
+ ))
+ .get_result(&conn)
+ .expect("error creating edit group");
+
+ Ok(Editgroup {
+ id: Some(row.id),
+ editor_id: row.editor_id,
+ description: row.description,
+ edits: None,
+ extra: row.extra_json,
+ })
+ }
+
+ pub fn get_editgroup_handler(&self, id: i64) -> Result<Editgroup> {
let conn = self.db_pool.get().expect("db_pool error");
let row: EditgroupRow = editgroup::table.find(id as i64).first(&conn)?;
@@ -924,7 +831,7 @@ impl Server {
Ok(eg)
}
- fn get_editor_handler(&self, username: String) -> Result<Editor> {
+ pub fn get_editor_handler(&self, username: String) -> Result<Editor> {
let conn = self.db_pool.get().expect("db_pool error");
let row: EditorRow = editor::table
@@ -937,7 +844,7 @@ impl Server {
Ok(ed)
}
- fn editor_changelog_get_handler(&self, username: String) -> Result<Vec<ChangelogEntry>> {
+ pub fn editor_changelog_get_handler(&self, username: String) -> Result<Vec<ChangelogEntry>> {
let conn = self.db_pool.get().expect("db_pool error");
// TODO: single query
@@ -961,7 +868,7 @@ impl Server {
Ok(entries)
}
- fn get_changelog_handler(&self, limit: Option<i64>) -> Result<Vec<ChangelogEntry>> {
+ pub fn get_changelog_handler(&self, limit: Option<i64>) -> Result<Vec<ChangelogEntry>> {
let conn = self.db_pool.get().expect("db_pool error");
let limit = limit.unwrap_or(50);
@@ -983,7 +890,7 @@ impl Server {
Ok(entries)
}
- fn get_changelog_entry_handler(&self, id: i64) -> Result<ChangelogEntry> {
+ pub fn get_changelog_entry_handler(&self, id: i64) -> Result<ChangelogEntry> {
let conn = self.db_pool.get().expect("db_pool error");
let cl_row: ChangelogRow = changelog::table.find(id).first(&conn)?;
@@ -994,7 +901,7 @@ impl Server {
Ok(entry)
}
- fn get_stats_handler(&self, more: Option<String>) -> Result<StatsResponse> {
+ pub fn get_stats_handler(&self, more: Option<String>) -> Result<StatsResponse> {
let conn = self.db_pool.get().expect("db_pool error");
let merged_editgroups: i64 = changelog::table
@@ -1099,296 +1006,3 @@ impl Server {
entity_history_handler!(get_work_history_handler, WorkEditRow, work_edit);
}
-impl Api for Server {
- wrap_entity_handlers!(
- get_container,
- get_container_handler,
- GetContainerResponse,
- create_container,
- create_container_handler,
- CreateContainerResponse,
- create_container_batch,
- create_container_batch_handler,
- CreateContainerBatchResponse,
- get_container_history,
- get_container_history_handler,
- GetContainerHistoryResponse,
- ContainerEntity
- );
-
- wrap_entity_handlers!(
- get_creator,
- get_creator_handler,
- GetCreatorResponse,
- create_creator,
- create_creator_handler,
- CreateCreatorResponse,
- create_creator_batch,
- create_creator_batch_handler,
- CreateCreatorBatchResponse,
- get_creator_history,
- get_creator_history_handler,
- GetCreatorHistoryResponse,
- CreatorEntity
- );
- wrap_entity_handlers!(
- get_file,
- get_file_handler,
- GetFileResponse,
- create_file,
- create_file_handler,
- CreateFileResponse,
- create_file_batch,
- create_file_batch_handler,
- CreateFileBatchResponse,
- get_file_history,
- get_file_history_handler,
- GetFileHistoryResponse,
- FileEntity
- );
- wrap_entity_handlers!(
- get_release,
- get_release_handler,
- GetReleaseResponse,
- create_release,
- create_release_handler,
- CreateReleaseResponse,
- create_release_batch,
- create_release_batch_handler,
- CreateReleaseBatchResponse,
- get_release_history,
- get_release_history_handler,
- GetReleaseHistoryResponse,
- ReleaseEntity
- );
- wrap_entity_handlers!(
- get_work,
- get_work_handler,
- GetWorkResponse,
- create_work,
- create_work_handler,
- CreateWorkResponse,
- create_work_batch,
- create_work_batch_handler,
- CreateWorkBatchResponse,
- get_work_history,
- get_work_history_handler,
- GetWorkHistoryResponse,
- WorkEntity
- );
-
- wrap_lookup_handler!(
- lookup_container,
- lookup_container_handler,
- LookupContainerResponse,
- issnl,
- String
- );
- 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
- );
-
- wrap_lookup_handler!(
- get_release_files,
- get_release_files_handler,
- GetReleaseFilesResponse,
- id,
- String
- );
- wrap_lookup_handler!(
- get_work_releases,
- get_work_releases_handler,
- GetWorkReleasesResponse,
- id,
- String
- );
- wrap_lookup_handler!(
- get_creator_releases,
- get_creator_releases_handler,
- GetCreatorReleasesResponse,
- id,
- String
- );
-
- fn accept_editgroup(
- &self,
- id: i64,
- _context: &Context,
- ) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> {
- let conn = self.db_pool.get().expect("db_pool error");
-
- accept_editgroup(id as i64, &conn).expect("failed to accept editgroup");
-
- let ret = AcceptEditgroupResponse::MergedSuccessfully(Success {
- message: "horray!".to_string(),
- });
- Box::new(futures::done(Ok(ret)))
- }
-
- fn get_editgroup(
- &self,
- id: i64,
- _context: &Context,
- ) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> {
- let ret = match self.get_editgroup_handler(id) {
- Ok(entity) =>
- GetEditgroupResponse::FoundEntity(entity),
- Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
- GetEditgroupResponse::NotFound(
- ErrorResponse { message: format!("No such editgroup: {}", id) }),
- Err(e) =>
- // TODO: dig in to error type here
- GetEditgroupResponse::GenericError(
- ErrorResponse { message: e.to_string() }),
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn create_editgroup(
- &self,
- entity: models::Editgroup,
- _context: &Context,
- ) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> {
- let conn = self.db_pool.get().expect("db_pool error");
-
- let row: EditgroupRow = insert_into(editgroup::table)
- .values((
- editgroup::editor_id.eq(entity.editor_id as i64),
- editgroup::description.eq(entity.description),
- editgroup::extra_json.eq(entity.extra),
- ))
- .get_result(&conn)
- .expect("error creating edit group");
-
- let new_eg = Editgroup {
- id: Some(row.id),
- editor_id: row.editor_id,
- description: row.description,
- edits: None,
- extra: row.extra_json,
- };
- Box::new(futures::done(Ok(
- CreateEditgroupResponse::SuccessfullyCreated(new_eg),
- )))
- }
-
- fn get_editor_changelog(
- &self,
- username: String,
- _context: &Context,
- ) -> Box<Future<Item = GetEditorChangelogResponse, Error = ApiError> + Send> {
- let ret = match self.editor_changelog_get_handler(username.clone()) {
- Ok(entries) => GetEditorChangelogResponse::FoundMergedChanges(entries),
- Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
- GetEditorChangelogResponse::NotFound(ErrorResponse {
- message: format!("No such editor: {}", username.clone()),
- })
- }
- Err(e) => {
- // TODO: dig in to error type here
- error!("{}", e);
- GetEditorChangelogResponse::GenericError(ErrorResponse {
- message: e.to_string(),
- })
- }
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn get_editor(
- &self,
- username: String,
- _context: &Context,
- ) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> {
- let ret = match self.get_editor_handler(username.clone()) {
- Ok(entity) => GetEditorResponse::FoundEditor(entity),
- Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
- GetEditorResponse::NotFound(ErrorResponse {
- message: format!("No such editor: {}", username.clone()),
- })
- }
- Err(e) => {
- // TODO: dig in to error type here
- error!("{}", e);
- GetEditorResponse::GenericError(ErrorResponse {
- message: e.to_string(),
- })
- }
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn get_changelog(
- &self,
- limit: Option<i64>,
- _context: &Context,
- ) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> {
- let ret = match self.get_changelog_handler(limit) {
- Ok(changelog) => GetChangelogResponse::Success(changelog),
- Err(e) => {
- error!("{}", e);
- GetChangelogResponse::GenericError(ErrorResponse {
- message: e.to_string(),
- })
- }
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn get_changelog_entry(
- &self,
- id: i64,
- _context: &Context,
- ) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> {
- let ret = match self.get_changelog_entry_handler(id) {
- Ok(entry) => GetChangelogEntryResponse::FoundChangelogEntry(entry),
- Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
- GetChangelogEntryResponse::NotFound(ErrorResponse {
- message: format!("No such changelog entry: {}", id),
- })
- }
- Err(e) => {
- error!("{}", e);
- GetChangelogEntryResponse::GenericError(ErrorResponse {
- message: e.to_string(),
- })
- }
- };
- Box::new(futures::done(Ok(ret)))
- }
-
- fn get_stats(
- &self,
- more: Option<String>,
- _context: &Context,
- ) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> {
- let ret = match self.get_stats_handler(more.clone()) {
- Ok(stats) => GetStatsResponse::Success(stats),
- Err(e) => {
- error!("{}", e);
- GetStatsResponse::GenericError(ErrorResponse {
- message: e.to_string(),
- })
- }
- };
- Box::new(futures::done(Ok(ret)))
- }
-}
diff --git a/rust/src/api_wrappers.rs b/rust/src/api_wrappers.rs
new file mode 100644
index 00000000..8651252c
--- /dev/null
+++ b/rust/src/api_wrappers.rs
@@ -0,0 +1,414 @@
+//! API endpoint handlers
+
+use errors::*;
+use api_server::Server;
+use fatcat_api::models;
+use fatcat_api::models::*;
+use fatcat_api::*;
+use futures::{self, Future};
+
+/// Helper for generating wrappers (which return "Box::new(futures::done(Ok(BLAH)))" like the
+/// codegen fatcat-api code wants) that call through to actual helpers (which have simple Result<>
+/// return types)
+macro_rules! wrap_entity_handlers {
+ // Would much rather just have entity ident, then generate the other fields from that, but Rust
+ // 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_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) => {
+
+ fn $get_fn(
+ &self,
+ id: String,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
+ let ret = match self.$get_handler(id.clone()) {
+ Ok(entity) =>
+ $get_resp::FoundEntity(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $get_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $get_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $post_fn(
+ &self,
+ entity: models::$model,
+ _context: &Context,
+ ) -> Box<Future<Item = $post_resp, Error = ApiError> + Send> {
+ let ret = match self.$post_handler(entity, None) {
+ Ok(edit) =>
+ $post_resp::CreatedEntity(edit),
+ Err(Error(ErrorKind::Diesel(e), _)) =>
+ $post_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $post_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $post_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $post_batch_fn(
+ &self,
+ entity_list: &Vec<models::$model>,
+ _context: &Context,
+ ) -> Box<Future<Item = $post_batch_resp, Error = ApiError> + Send> {
+ let ret = match self.$post_batch_handler(entity_list) {
+ Ok(edit) =>
+ $post_batch_resp::CreatedEntities(edit),
+ Err(Error(ErrorKind::Diesel(e), _)) =>
+ $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $post_batch_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $post_batch_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn $get_history_fn(
+ &self,
+ id: String,
+ limit: Option<i64>,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_history_resp, Error = ApiError> + Send> {
+ let ret = match self.$get_history_handler(id.clone(), limit) {
+ Ok(history) =>
+ $get_history_resp::FoundEntityHistory(history),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_history_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),
+ Err(Error(ErrorKind::Uuid(e), _)) =>
+ $get_history_resp::BadRequest(ErrorResponse { message: e.to_string() }),
+ Err(e) => {
+ error!("{}", e);
+ $get_history_resp::GenericError(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+ }
+}
+
+macro_rules! wrap_lookup_handler {
+ ($get_fn:ident, $get_handler:ident, $get_resp:ident, $idname:ident, $idtype:ident) => {
+ fn $get_fn(
+ &self,
+ $idname: $idtype,
+ _context: &Context,
+ ) -> Box<Future<Item = $get_resp, Error = ApiError> + Send> {
+ let ret = match self.$get_handler($idname.clone()) {
+ Ok(entity) =>
+ $get_resp::FoundEntity(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ $get_resp::NotFound(ErrorResponse { message: format!("Not found: {}", $idname) }),
+ Err(e) => {
+ error!("{}", e);
+ $get_resp::BadRequest(ErrorResponse { message: e.to_string() })
+ },
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+ }
+}
+
+impl Api for Server {
+ wrap_entity_handlers!(
+ get_container,
+ get_container_handler,
+ GetContainerResponse,
+ create_container,
+ create_container_handler,
+ CreateContainerResponse,
+ create_container_batch,
+ create_container_batch_handler,
+ CreateContainerBatchResponse,
+ get_container_history,
+ get_container_history_handler,
+ GetContainerHistoryResponse,
+ ContainerEntity
+ );
+
+ wrap_entity_handlers!(
+ get_creator,
+ get_creator_handler,
+ GetCreatorResponse,
+ create_creator,
+ create_creator_handler,
+ CreateCreatorResponse,
+ create_creator_batch,
+ create_creator_batch_handler,
+ CreateCreatorBatchResponse,
+ get_creator_history,
+ get_creator_history_handler,
+ GetCreatorHistoryResponse,
+ CreatorEntity
+ );
+ wrap_entity_handlers!(
+ get_file,
+ get_file_handler,
+ GetFileResponse,
+ create_file,
+ create_file_handler,
+ CreateFileResponse,
+ create_file_batch,
+ create_file_batch_handler,
+ CreateFileBatchResponse,
+ get_file_history,
+ get_file_history_handler,
+ GetFileHistoryResponse,
+ FileEntity
+ );
+ wrap_entity_handlers!(
+ get_release,
+ get_release_handler,
+ GetReleaseResponse,
+ create_release,
+ create_release_handler,
+ CreateReleaseResponse,
+ create_release_batch,
+ create_release_batch_handler,
+ CreateReleaseBatchResponse,
+ get_release_history,
+ get_release_history_handler,
+ GetReleaseHistoryResponse,
+ ReleaseEntity
+ );
+ wrap_entity_handlers!(
+ get_work,
+ get_work_handler,
+ GetWorkResponse,
+ create_work,
+ create_work_handler,
+ CreateWorkResponse,
+ create_work_batch,
+ create_work_batch_handler,
+ CreateWorkBatchResponse,
+ get_work_history,
+ get_work_history_handler,
+ GetWorkHistoryResponse,
+ WorkEntity
+ );
+
+ wrap_lookup_handler!(
+ lookup_container,
+ lookup_container_handler,
+ LookupContainerResponse,
+ issnl,
+ String
+ );
+ 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
+ );
+
+ wrap_lookup_handler!(
+ get_release_files,
+ get_release_files_handler,
+ GetReleaseFilesResponse,
+ id,
+ String
+ );
+ wrap_lookup_handler!(
+ get_work_releases,
+ get_work_releases_handler,
+ GetWorkReleasesResponse,
+ id,
+ String
+ );
+ wrap_lookup_handler!(
+ get_creator_releases,
+ get_creator_releases_handler,
+ GetCreatorReleasesResponse,
+ id,
+ String
+ );
+
+ fn accept_editgroup(
+ &self,
+ id: i64,
+ _context: &Context,
+ ) -> Box<Future<Item = AcceptEditgroupResponse, Error = ApiError> + Send> {
+
+ let ret = match self.accept_editgroup_handler(id) {
+ Ok(()) => AcceptEditgroupResponse::MergedSuccessfully(Success {
+ message: "horray!".to_string(),
+ }),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ AcceptEditgroupResponse::NotFound(
+ ErrorResponse { message: format!("No such editgroup: {}", id) }),
+ Err(e) =>
+ AcceptEditgroupResponse::GenericError(
+ ErrorResponse { message: e.to_string() }),
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_editgroup(
+ &self,
+ id: i64,
+ _context: &Context,
+ ) -> Box<Future<Item = GetEditgroupResponse, Error = ApiError> + Send> {
+ let ret = match self.get_editgroup_handler(id) {
+ Ok(entity) =>
+ GetEditgroupResponse::FoundEntity(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) =>
+ GetEditgroupResponse::NotFound(
+ ErrorResponse { message: format!("No such editgroup: {}", id) }),
+ Err(e) =>
+ // TODO: dig in to error type here
+ GetEditgroupResponse::GenericError(
+ ErrorResponse { message: e.to_string() }),
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn create_editgroup(
+ &self,
+ entity: models::Editgroup,
+ _context: &Context,
+ ) -> Box<Future<Item = CreateEditgroupResponse, Error = ApiError> + Send> {
+
+ let ret = match self.create_editgroup_handler(entity) {
+ Ok(eg) =>
+ CreateEditgroupResponse::SuccessfullyCreated(eg),
+ Err(e) =>
+ // TODO: dig in to error type here
+ CreateEditgroupResponse::GenericError(
+ ErrorResponse { message: e.to_string() }),
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_editor_changelog(
+ &self,
+ username: String,
+ _context: &Context,
+ ) -> Box<Future<Item = GetEditorChangelogResponse, Error = ApiError> + Send> {
+ let ret = match self.editor_changelog_get_handler(username.clone()) {
+ Ok(entries) => GetEditorChangelogResponse::FoundMergedChanges(entries),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
+ GetEditorChangelogResponse::NotFound(ErrorResponse {
+ message: format!("No such editor: {}", username.clone()),
+ })
+ }
+ Err(e) => {
+ // TODO: dig in to error type here
+ error!("{}", e);
+ GetEditorChangelogResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_editor(
+ &self,
+ username: String,
+ _context: &Context,
+ ) -> Box<Future<Item = GetEditorResponse, Error = ApiError> + Send> {
+ let ret = match self.get_editor_handler(username.clone()) {
+ Ok(entity) => GetEditorResponse::FoundEditor(entity),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
+ GetEditorResponse::NotFound(ErrorResponse {
+ message: format!("No such editor: {}", username.clone()),
+ })
+ }
+ Err(e) => {
+ // TODO: dig in to error type here
+ error!("{}", e);
+ GetEditorResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_changelog(
+ &self,
+ limit: Option<i64>,
+ _context: &Context,
+ ) -> Box<Future<Item = GetChangelogResponse, Error = ApiError> + Send> {
+ let ret = match self.get_changelog_handler(limit) {
+ Ok(changelog) => GetChangelogResponse::Success(changelog),
+ Err(e) => {
+ error!("{}", e);
+ GetChangelogResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_changelog_entry(
+ &self,
+ id: i64,
+ _context: &Context,
+ ) -> Box<Future<Item = GetChangelogEntryResponse, Error = ApiError> + Send> {
+ let ret = match self.get_changelog_entry_handler(id) {
+ Ok(entry) => GetChangelogEntryResponse::FoundChangelogEntry(entry),
+ Err(Error(ErrorKind::Diesel(::diesel::result::Error::NotFound), _)) => {
+ GetChangelogEntryResponse::NotFound(ErrorResponse {
+ message: format!("No such changelog entry: {}", id),
+ })
+ }
+ Err(e) => {
+ error!("{}", e);
+ GetChangelogEntryResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+
+ fn get_stats(
+ &self,
+ more: Option<String>,
+ _context: &Context,
+ ) -> Box<Future<Item = GetStatsResponse, Error = ApiError> + Send> {
+ let ret = match self.get_stats_handler(more.clone()) {
+ Ok(stats) => GetStatsResponse::Success(stats),
+ Err(e) => {
+ error!("{}", e);
+ GetStatsResponse::GenericError(ErrorResponse {
+ message: e.to_string(),
+ })
+ }
+ };
+ Box::new(futures::done(Ok(ret)))
+ }
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index d81035cc..d9193f2f 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -19,6 +19,7 @@ extern crate log;
pub mod api_helpers;
pub mod api_server;
+pub mod api_wrappers;
pub mod database_models;
pub mod database_schema;