diff options
| author | Bryan Newbold <bnewbold@robocracy.org> | 2018-05-26 18:12:53 -0700 | 
|---|---|---|
| committer | Bryan Newbold <bnewbold@robocracy.org> | 2018-05-26 18:12:53 -0700 | 
| commit | 04f09af13ceb1c5d02e4b22fd35a9aa915053a1b (patch) | |
| tree | 0a967563d7462b8432cbd5d9bb129624fd3c90bd /rust | |
| parent | 331064f105e1f6b548bb2fc5141a42d0659342f0 (diff) | |
| download | fatcat-04f09af13ceb1c5d02e4b22fd35a9aa915053a1b.tar.gz fatcat-04f09af13ceb1c5d02e4b22fd35a9aa915053a1b.zip | |
more refactoring
Diffstat (limited to 'rust')
| -rw-r--r-- | rust/src/api_server.rs | 498 | 
1 files changed, 253 insertions, 245 deletions
| diff --git a/rust/src/api_server.rs b/rust/src/api_server.rs index 488dfc9b..cb4424c4 100644 --- a/rust/src/api_server.rs +++ b/rust/src/api_server.rs @@ -25,21 +25,37 @@ use uuid;  // Helper for calling through to handlers  macro_rules! wrap_entity_handlers { -    ($get_fn:ident, $get_handler:ident, $get_resp:ident) => { +    ($get_fn:ident, $get_handler:ident, $get_resp:ident, $post_fn:ident, $post_handler:ident, +            $post_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) { +            let ret = match self.$get_handler(id.clone()) {                  Ok(Some(entity)) =>                      $get_resp::FoundEntity(entity),                  Ok(None) => -                    $get_resp::NotFound(ErrorResponse { message: "No such entity".to_string() }), +                    $get_resp::NotFound(ErrorResponse { message: format!("No such entity {}: {}", stringify!($model), id) }),                  Err(e) => $get_resp::BadRequest(ErrorResponse { message: e.to_string() }),              };              Box::new(futures::done(Ok(ret)))          } + +        fn $post_fn( +            &self, +            body: models::$model, +            _context: &Context, +        ) -> Box<Future<Item = $post_resp, Error = ApiError> + Send> { +            // TODO: look for diesel foreign key and other type errors, return as BadRequest; other +            // errors are a 500. +            let ret = match self.$post_handler(body) { +                Ok(edit) => +                    $post_resp::CreatedEntity(edit), +                Err(e) => $post_resp::BadRequest(ErrorResponse { message: e.to_string() }), +            }; +            Box::new(futures::done(Ok(ret))) +        }      }  }  macro_rules! wrap_lookup_handler { @@ -429,190 +445,7 @@ impl Server {          Ok(Some(entity))      } -    fn editgroup_id_get_handler(&self, id: i64) -> Result<Option<Editgroup>> { -        let conn = self.db_pool.get().expect("db_pool error"); - -        let row: EditgroupRow = editgroup::table.find(id as i64).first(&conn)?; - -        let edits = EditgroupEdits { -            containers: Some( -                container_edit::table -                    .filter(container_edit::editgroup_id.eq(id)) -                    .get_results(&conn) -                    .unwrap() -                    .iter() -                    .map(|e: &ContainerEditRow| EntityEdit { -                        edit_id: e.id, -                        editgroup_id: e.editgroup_id, -                        revision: e.rev_id, -                        redirect_ident: e.redirect_id.map(|v| v.to_string()), -                        ident: e.ident_id.to_string(), -                        extra: e.extra_json.clone(), -                    }) -                    .collect(), -            ), -            creators: Some( -                creator_edit::table -                    .filter(creator_edit::editgroup_id.eq(id)) -                    .get_results(&conn) -                    .unwrap() -                    .iter() -                    .map(|e: &CreatorEditRow| EntityEdit { -                        edit_id: e.id, -                        editgroup_id: e.editgroup_id, -                        revision: e.rev_id, -                        redirect_ident: e.redirect_id.map(|v| v.to_string()), -                        ident: e.ident_id.to_string(), -                        extra: e.extra_json.clone(), -                    }) -                    .collect(), -            ), -            files: Some( -                file_edit::table -                    .filter(file_edit::editgroup_id.eq(id)) -                    .get_results(&conn) -                    .unwrap() -                    .iter() -                    .map(|e: &FileEditRow| EntityEdit { -                        edit_id: e.id, -                        editgroup_id: e.editgroup_id, -                        revision: e.rev_id, -                        redirect_ident: e.redirect_id.map(|v| v.to_string()), -                        ident: e.ident_id.to_string(), -                        extra: e.extra_json.clone(), -                    }) -                    .collect(), -            ), -            releases: Some( -                release_edit::table -                    .filter(release_edit::editgroup_id.eq(id)) -                    .get_results(&conn) -                    .unwrap() -                    .iter() -                    .map(|e: &ReleaseEditRow| EntityEdit { -                        edit_id: e.id, -                        editgroup_id: e.editgroup_id, -                        revision: e.rev_id, -                        redirect_ident: e.redirect_id.map(|v| v.to_string()), -                        ident: e.ident_id.to_string(), -                        extra: e.extra_json.clone(), -                    }) -                    .collect(), -            ), -            works: Some( -                work_edit::table -                    .filter(work_edit::editgroup_id.eq(id)) -                    .get_results(&conn) -                    .unwrap() -                    .iter() -                    .map(|e: &WorkEditRow| EntityEdit { -                        edit_id: e.id, -                        editgroup_id: e.editgroup_id, -                        revision: e.rev_id, -                        redirect_ident: e.redirect_id.map(|v| v.to_string()), -                        ident: e.ident_id.to_string(), -                        extra: e.extra_json.clone(), -                    }) -                    .collect(), -            ), -        }; - -        let eg = Editgroup { -            id: Some(row.id), -            editor_id: row.editor_id, -            description: row.description, -            edits: Some(edits), -            extra: row.extra_json, -        }; -        Ok(Some(eg)) -    } - -    fn editor_get_handler(&self, username: String) -> Result<Option<Editor>> { -        let conn = self.db_pool.get().expect("db_pool error"); - -        let row: EditorRow = editor::table -            .filter(editor::username.eq(&username)) -            .first(&conn)?; - -        let ed = Editor { -            username: row.username, -        }; -        Ok(Some(ed)) -    } - -    fn editor_changelog_get_handler(&self, username: String) -> Result<Option<Changelogentries>> { -        let conn = self.db_pool.get().expect("db_pool error"); - -        // TODO: single query -        let editor: EditorRow = editor::table -            .filter(editor::username.eq(username)) -            .first(&conn)?; -        let changes: Vec<(ChangelogRow, EditgroupRow)> = changelog::table -            .inner_join(editgroup::table) -            .filter(editgroup::editor_id.eq(editor.id)) -            .load(&conn)?; - -        let entries = changes -            .iter() -            .map(|(row, _)| ChangelogentriesInner { -                index: row.id, -                editgroup_id: row.editgroup_id, -                timestamp: chrono::DateTime::from_utc(row.timestamp, chrono::Utc), -            }) -            .collect(); -        Ok(Some(entries)) -    } -} - -impl Api for Server { -    wrap_entity_handlers!( -        container_id_get, -        container_id_get_handler, -        ContainerIdGetResponse -    ); -    wrap_entity_handlers!( -        creator_id_get, -        creator_id_get_handler, -        CreatorIdGetResponse -    ); -    wrap_entity_handlers!(file_id_get, file_id_get_handler, FileIdGetResponse); -    wrap_entity_handlers!(work_id_get, work_id_get_handler, WorkIdGetResponse); -    wrap_entity_handlers!(release_id_get, release_id_get_handler, ReleaseIdGetResponse); - -    wrap_lookup_handler!( -        container_lookup_get, -        container_lookup_get_handler, -        ContainerLookupGetResponse, -        issnl, -        String -    ); -    wrap_lookup_handler!( -        creator_lookup_get, -        creator_lookup_get_handler, -        CreatorLookupGetResponse, -        orcid, -        String -    ); -    wrap_lookup_handler!( -        file_lookup_get, -        file_lookup_get_handler, -        FileLookupGetResponse, -        sha1, -        String -    ); -    wrap_lookup_handler!( -        release_lookup_get, -        release_lookup_get_handler, -        ReleaseLookupGetResponse, -        doi, -        String -    ); - -    fn container_post( -        &self, -        body: models::ContainerEntity, -        _context: &Context, -    ) -> Box<Future<Item = ContainerPostResponse, Error = ApiError> + Send> { +    fn container_post_handler(&self, body: models::ContainerEntity) -> Result<EntityEdit> {          let conn = self.db_pool.get().expect("db_pool error");          let editor_id = 1; // TODO: auth          let editgroup_id = match body.editgroup_id { @@ -637,28 +470,20 @@ impl Api for Server {              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.coden)              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Json>, _>(body.extra)              .bind::<diesel::sql_types::BigInt, _>(editgroup_id) -            .get_result(&conn) -            .unwrap(); +            .get_result(&conn)?;          let edit = &edit; -        let entity_edit = EntityEdit { +        Ok(EntityEdit {              editgroup_id: edit.editgroup_id,              revision: Some(edit.rev_id.unwrap()),              redirect_ident: None,              ident: edit.ident_id.to_string(),              edit_id: edit.id,              extra: edit.extra_json.clone(), -        }; -        Box::new(futures::done(Ok(ContainerPostResponse::CreatedEntity( -            entity_edit, -        )))) +        })      } -    fn creator_post( -        &self, -        body: models::CreatorEntity, -        _context: &Context, -    ) -> Box<Future<Item = CreatorPostResponse, Error = ApiError> + Send> { +    fn creator_post_handler(&self, body: models::CreatorEntity) -> Result<EntityEdit> {          let conn = self.db_pool.get().expect("db_pool error");          let editor_id = 1; // TODO: auth          let editgroup_id = match body.editgroup_id { @@ -680,28 +505,20 @@ impl Api for Server {              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.orcid)              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Json>, _>(body.extra)              .bind::<diesel::sql_types::BigInt, _>(editgroup_id) -            .get_result(&conn) -            .unwrap(); +            .get_result(&conn)?;          let edit = &edit; -        let entity_edit = EntityEdit { +        Ok(EntityEdit {              editgroup_id: edit.editgroup_id,              revision: Some(edit.rev_id.unwrap()),              redirect_ident: None,              ident: edit.ident_id.to_string(),              edit_id: edit.id,              extra: edit.extra_json.clone(), -        }; -        Box::new(futures::done(Ok(CreatorPostResponse::CreatedEntity( -            entity_edit, -        )))) +        })      } -    fn file_post( -        &self, -        body: models::FileEntity, -        _context: &Context, -    ) -> Box<Future<Item = FilePostResponse, Error = ApiError> + Send> { +    fn file_post_handler(&self, body: models::FileEntity) -> Result<EntityEdit> {          let conn = self.db_pool.get().expect("db_pool error");          let editor_id = 1; // TODO: auth          let editgroup_id = match body.editgroup_id { @@ -726,8 +543,7 @@ impl Api for Server {                  .bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.url)                  .bind::<diesel::sql_types::Nullable<diesel::sql_types::Json>, _>(body.extra)                  .bind::<diesel::sql_types::BigInt, _>(editgroup_id) -                .get_result(&conn) -                .unwrap(); +                .get_result(&conn)?;          let edit = &edit;          let _releases: Option<Vec<FileReleaseRow>> = match body.releases { @@ -752,24 +568,17 @@ impl Api for Server {              }          }; -        let entity_edit = EntityEdit { +        Ok(EntityEdit {              editgroup_id: edit.editgroup_id,              revision: Some(edit.rev_id.unwrap()),              redirect_ident: None,              ident: edit.ident_id.to_string(),              edit_id: edit.id,              extra: edit.extra_json.clone(), -        }; -        Box::new(futures::done(Ok(FilePostResponse::CreatedEntity( -            entity_edit, -        )))) +        })      } -    fn work_post( -        &self, -        body: models::WorkEntity, -        _context: &Context, -    ) -> Box<Future<Item = WorkPostResponse, Error = ApiError> + Send> { +    fn work_post_handler(&self, body: models::WorkEntity) -> Result<EntityEdit> {          let conn = self.db_pool.get().expect("db_pool error");          let editor_id = 1; // TODO: auth          let editgroup_id = match body.editgroup_id { @@ -791,28 +600,20 @@ impl Api for Server {              ).bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.work_type)                  .bind::<diesel::sql_types::Nullable<diesel::sql_types::Json>, _>(body.extra)                  .bind::<diesel::sql_types::BigInt, _>(editgroup_id) -                .get_result(&conn) -                .unwrap(); +                .get_result(&conn)?;          let edit = &edit; -        let entity_edit = EntityEdit { +        Ok(EntityEdit {              editgroup_id: edit.editgroup_id,              revision: Some(edit.rev_id.unwrap()),              redirect_ident: None,              ident: edit.ident_id.to_string(),              edit_id: edit.id,              extra: edit.extra_json.clone(), -        }; -        Box::new(futures::done(Ok(WorkPostResponse::CreatedEntity( -            entity_edit, -        )))) +        })      } -    fn release_post( -        &self, -        body: models::ReleaseEntity, -        _context: &Context, -    ) -> Box<Future<Item = ReleasePostResponse, Error = ApiError> + Send> { +    fn release_post_handler(&self, body: models::ReleaseEntity) -> Result<EntityEdit> {          let conn = self.db_pool.get().expect("db_pool error");          let editor_id = 1; // TODO: auth          let editgroup_id = match body.editgroup_id { @@ -838,7 +639,8 @@ impl Api for Server {              RETURNING *",          ).bind::<diesel::sql_types::Text, _>(body.title)              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.release_type) -            .bind::<diesel::sql_types::Nullable<diesel::sql_types::Date>, _>(body.date.map(|v| v.naive_utc().date())) +            .bind::<diesel::sql_types::Nullable<diesel::sql_types::Date>, _>( +                body.date.map(|v| v.naive_utc().date()))              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.doi)              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.isbn13)              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.volume) @@ -849,8 +651,7 @@ impl Api for Server {              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Text>, _>(body.publisher)              .bind::<diesel::sql_types::Nullable<diesel::sql_types::Json>, _>(body.extra)              .bind::<diesel::sql_types::BigInt, _>(editgroup_id) -            .get_result(&conn) -            .unwrap(); +            .get_result(&conn)?;          let edit = &edit;          let _refs: Option<Vec<ReleaseRefRow>> = match body.refs { @@ -906,19 +707,222 @@ impl Api for Server {              }          }; -        let entity_edit = EntityEdit { +        Ok(EntityEdit {              editgroup_id: edit.editgroup_id,              revision: Some(edit.rev_id.unwrap()),              redirect_ident: None,              ident: edit.ident_id.to_string(),              edit_id: edit.id,              extra: edit.extra_json.clone(), +        }) +    } + +    fn editgroup_id_get_handler(&self, id: i64) -> Result<Option<Editgroup>> { +        let conn = self.db_pool.get().expect("db_pool error"); + +        let row: EditgroupRow = editgroup::table.find(id as i64).first(&conn)?; + +        let edits = EditgroupEdits { +            containers: Some( +                container_edit::table +                    .filter(container_edit::editgroup_id.eq(id)) +                    .get_results(&conn)? +                    .iter() +                    .map(|e: &ContainerEditRow| EntityEdit { +                        edit_id: e.id, +                        editgroup_id: e.editgroup_id, +                        revision: e.rev_id, +                        redirect_ident: e.redirect_id.map(|v| v.to_string()), +                        ident: e.ident_id.to_string(), +                        extra: e.extra_json.clone(), +                    }) +                    .collect(), +            ), +            creators: Some( +                creator_edit::table +                    .filter(creator_edit::editgroup_id.eq(id)) +                    .get_results(&conn)? +                    .iter() +                    .map(|e: &CreatorEditRow| EntityEdit { +                        edit_id: e.id, +                        editgroup_id: e.editgroup_id, +                        revision: e.rev_id, +                        redirect_ident: e.redirect_id.map(|v| v.to_string()), +                        ident: e.ident_id.to_string(), +                        extra: e.extra_json.clone(), +                    }) +                    .collect(), +            ), +            files: Some( +                file_edit::table +                    .filter(file_edit::editgroup_id.eq(id)) +                    .get_results(&conn)? +                    .iter() +                    .map(|e: &FileEditRow| EntityEdit { +                        edit_id: e.id, +                        editgroup_id: e.editgroup_id, +                        revision: e.rev_id, +                        redirect_ident: e.redirect_id.map(|v| v.to_string()), +                        ident: e.ident_id.to_string(), +                        extra: e.extra_json.clone(), +                    }) +                    .collect(), +            ), +            releases: Some( +                release_edit::table +                    .filter(release_edit::editgroup_id.eq(id)) +                    .get_results(&conn)? +                    .iter() +                    .map(|e: &ReleaseEditRow| EntityEdit { +                        edit_id: e.id, +                        editgroup_id: e.editgroup_id, +                        revision: e.rev_id, +                        redirect_ident: e.redirect_id.map(|v| v.to_string()), +                        ident: e.ident_id.to_string(), +                        extra: e.extra_json.clone(), +                    }) +                    .collect(), +            ), +            works: Some( +                work_edit::table +                    .filter(work_edit::editgroup_id.eq(id)) +                    .get_results(&conn)? +                    .iter() +                    .map(|e: &WorkEditRow| EntityEdit { +                        edit_id: e.id, +                        editgroup_id: e.editgroup_id, +                        revision: e.rev_id, +                        redirect_ident: e.redirect_id.map(|v| v.to_string()), +                        ident: e.ident_id.to_string(), +                        extra: e.extra_json.clone(), +                    }) +                    .collect(), +            ),          }; -        Box::new(futures::done(Ok(ReleasePostResponse::CreatedEntity( -            entity_edit, -        )))) + +        let eg = Editgroup { +            id: Some(row.id), +            editor_id: row.editor_id, +            description: row.description, +            edits: Some(edits), +            extra: row.extra_json, +        }; +        Ok(Some(eg))      } +    fn editor_get_handler(&self, username: String) -> Result<Option<Editor>> { +        let conn = self.db_pool.get().expect("db_pool error"); + +        let row: EditorRow = editor::table +            .filter(editor::username.eq(&username)) +            .first(&conn)?; + +        let ed = Editor { +            username: row.username, +        }; +        Ok(Some(ed)) +    } + +    fn editor_changelog_get_handler(&self, username: String) -> Result<Option<Changelogentries>> { +        let conn = self.db_pool.get().expect("db_pool error"); + +        // TODO: single query +        let editor: EditorRow = editor::table +            .filter(editor::username.eq(username)) +            .first(&conn)?; +        let changes: Vec<(ChangelogRow, EditgroupRow)> = changelog::table +            .inner_join(editgroup::table) +            .filter(editgroup::editor_id.eq(editor.id)) +            .load(&conn)?; + +        let entries = changes +            .iter() +            .map(|(row, _)| ChangelogentriesInner { +                index: row.id, +                editgroup_id: row.editgroup_id, +                timestamp: chrono::DateTime::from_utc(row.timestamp, chrono::Utc), +            }) +            .collect(); +        Ok(Some(entries)) +    } +} + +impl Api for Server { +    wrap_entity_handlers!( +        container_id_get, +        container_id_get_handler, +        ContainerIdGetResponse, +        container_post, +        container_post_handler, +        ContainerPostResponse, +        ContainerEntity +    ); +    wrap_entity_handlers!( +        creator_id_get, +        creator_id_get_handler, +        CreatorIdGetResponse, +        creator_post, +        creator_post_handler, +        CreatorPostResponse, +        CreatorEntity +    ); +    wrap_entity_handlers!( +        file_id_get, +        file_id_get_handler, +        FileIdGetResponse, +        file_post, +        file_post_handler, +        FilePostResponse, +        FileEntity +    ); +    wrap_entity_handlers!( +        release_id_get, +        release_id_get_handler, +        ReleaseIdGetResponse, +        release_post, +        release_post_handler, +        ReleasePostResponse, +        ReleaseEntity +    ); +    wrap_entity_handlers!( +        work_id_get, +        work_id_get_handler, +        WorkIdGetResponse, +        work_post, +        work_post_handler, +        WorkPostResponse, +        WorkEntity +    ); + +    wrap_lookup_handler!( +        container_lookup_get, +        container_lookup_get_handler, +        ContainerLookupGetResponse, +        issnl, +        String +    ); +    wrap_lookup_handler!( +        creator_lookup_get, +        creator_lookup_get_handler, +        CreatorLookupGetResponse, +        orcid, +        String +    ); +    wrap_lookup_handler!( +        file_lookup_get, +        file_lookup_get_handler, +        FileLookupGetResponse, +        sha1, +        String +    ); +    wrap_lookup_handler!( +        release_lookup_get, +        release_lookup_get_handler, +        ReleaseLookupGetResponse, +        doi, +        String +    ); +      fn editgroup_id_accept_post(          &self,          id: i64, @@ -928,7 +932,9 @@ impl Api for Server {          accept_editgroup(id as i64, &conn).expect("failed to accept editgroup"); -        let ret = EditgroupIdAcceptPostResponse::MergedSuccessfully(Success { message: "horray!".to_string()}); +        let ret = EditgroupIdAcceptPostResponse::MergedSuccessfully(Success { +            message: "horray!".to_string(), +        });          Box::new(futures::done(Ok(ret)))      } @@ -988,10 +994,12 @@ impl Api for Server {              Ok(Some(entries)) =>                  EditorUsernameChangelogGetResponse::FoundMergedChanges(entries),              Ok(None) => -                EditorUsernameChangelogGetResponse::NotFound(ErrorResponse { message: "No such entity".to_string() }), +                EditorUsernameChangelogGetResponse::NotFound( +                    ErrorResponse { message: "No such entity".to_string() }),              Err(e) =>                  // TODO: dig in to error type here -                EditorUsernameChangelogGetResponse::GenericError(ErrorResponse { message: e.to_string() }), +                EditorUsernameChangelogGetResponse::GenericError( +                    ErrorResponse { message: e.to_string() }),          };          Box::new(futures::done(Ok(ret)))      } | 
