diff --git a/rfd-api/src/context.rs b/rfd-api/src/context.rs index d60e0147..9ca3f124 100644 --- a/rfd-api/src/context.rs +++ b/rfd-api/src/context.rs @@ -18,7 +18,8 @@ use rfd_github::{GitHubError, GitHubNewRfdNumber, GitHubRfdRepo}; use rfd_model::{ schema_ext::{ContentFormat, Visibility}, storage::{JobStore, RfdFilter, RfdMetaStore, RfdPdfFilter, RfdPdfStore, RfdStorage, RfdStore}, - CommitSha, FileSha, Job, NewJob, Rfd, RfdId, RfdMeta, RfdPdf, RfdRevision, RfdRevisionId, + CommitSha, FileSha, Job, NewJob, Rfd, RfdComment, RfdId, RfdMeta, RfdPdf, RfdRevision, + RfdRevisionId, }; use rsa::{ pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey}, @@ -512,6 +513,15 @@ impl RfdContext { Ok(pdfs) } + pub async fn view_rfd_comments( + &self, + caller: &Caller, + rfd_number: i32, + revision: Option, + ) -> ResourceResult, StoreError> { + unimplemented!() + } + #[instrument(skip(self, caller, content))] pub async fn update_rfd_content( &self, diff --git a/rfd-api/src/endpoints/rfd.rs b/rfd-api/src/endpoints/rfd.rs index 4b766530..600c73b5 100644 --- a/rfd-api/src/endpoints/rfd.rs +++ b/rfd-api/src/endpoints/rfd.rs @@ -13,7 +13,7 @@ use rfd_data::{ }; use rfd_model::{ schema_ext::{ContentFormat, Visibility}, - Rfd, RfdPdf, RfdRevisionId, + Rfd, RfdComment, RfdPdf, RfdRevisionId, }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -175,8 +175,11 @@ pub async fn view_rfd_attr( pub async fn view_rfd_comments( rqctx: RequestContext, path: Path, -) -> Result, HttpError> { - unimplemented!() +) -> Result>, HttpError> { + let ctx = rqctx.context(); + let caller = ctx.v_ctx().get_caller(&rqctx).await?; + let path = path.into_inner(); + view_rfd_comments_op(ctx, &caller, path.number, None).await } // Specific RFD revision endpoints @@ -266,8 +269,11 @@ pub async fn view_rfd_revision_attr( pub async fn view_rfd_revision_comments( rqctx: RequestContext, path: Path, -) -> Result, HttpError> { - unimplemented!() +) -> Result>, HttpError> { + let ctx = rqctx.context(); + let caller = ctx.v_ctx().get_caller(&rqctx).await?; + let path = path.into_inner(); + view_rfd_comments_op(ctx, &caller, path.number, Some(path.revision.into())).await } #[derive(Debug, Deserialize, JsonSchema)] @@ -406,7 +412,7 @@ async fn view_rfd_attr_op( attr: RfdAttrName, ) -> Result, HttpError> { if let Ok(rfd_number) = number.parse::() { - let rfd = ctx.view_rfd(caller, rfd_number, None).await?; + let rfd = ctx.view_rfd(caller, rfd_number, revision).await?; let content = match rfd.format { ContentFormat::Asciidoc => RfdContent::Asciidoc(RfdAsciidoc::new(rfd.content)), ContentFormat::Markdown => RfdContent::Markdown(RfdMarkdown::new(rfd.content)), @@ -427,8 +433,16 @@ async fn view_rfd_comments_op( caller: &Caller, number: String, revision: Option, -) -> Result, HttpError> { - unimplemented!() +) -> Result>, HttpError> { + if let Ok(rfd_number) = number.parse::() { + let comments = ctx.view_rfd_comments(caller, rfd_number, revision).await?; + Ok(HttpResponseOk(comments)) + } else { + Err(client_error( + ClientErrorStatusCode::BAD_REQUEST, + "Malformed RFD number", + )) + } } #[instrument(skip(ctx, caller), fields(caller = ?caller.id), err(Debug))] diff --git a/rfd-model/src/lib.rs b/rfd-model/src/lib.rs index 5cb9378a..dd264a06 100644 --- a/rfd-model/src/lib.rs +++ b/rfd-model/src/lib.rs @@ -337,7 +337,7 @@ impl TypedUuidKind for RfdCommentId { pub struct RfdComment { pub id: TypedUuid, pub rfd_id: TypedUuid, - pub comment_user_id: TypedUuid, + pub comment_user: RfdCommentUser, pub external_id: Option, pub node_id: String, pub discussion_number: Option, diff --git a/rfd-model/src/storage/mod.rs b/rfd-model/src/storage/mod.rs index a583e06b..58177122 100644 --- a/rfd-model/src/storage/mod.rs +++ b/rfd-model/src/storage/mod.rs @@ -12,8 +12,9 @@ use std::fmt::Debug; use v_model::storage::{ListPagination, StoreError}; use crate::{ - schema_ext::PdfSource, CommitSha, Job, NewJob, NewRfd, NewRfdPdf, NewRfdRevision, Rfd, RfdId, - RfdMeta, RfdPdf, RfdPdfId, RfdRevision, RfdRevisionId, RfdRevisionMeta, + schema_ext::PdfSource, CommitSha, Job, NewJob, NewRfd, NewRfdComment, NewRfdCommentUser, + NewRfdPdf, NewRfdRevision, Rfd, RfdComment, RfdCommentId, RfdCommentUser, RfdCommentUserId, + RfdId, RfdMeta, RfdPdf, RfdPdfId, RfdRevision, RfdRevisionId, RfdRevisionMeta, }; #[cfg(feature = "mock")] @@ -308,3 +309,42 @@ pub trait JobStore { async fn start(&self, id: i32) -> Result, StoreError>; async fn complete(&self, id: i32) -> Result, StoreError>; } + +#[cfg_attr(feature = "mock", automock)] +#[async_trait] +pub trait RfdCommentUserStore { + async fn upsert( + &self, + new_rfd_comment_user: NewRfdCommentUser, + ) -> Result; +} + +#[derive(Debug, Default)] +pub struct RfdCommentFilter { + pub rfd: Option>>, + pub user: Option>>, +} + +impl RfdCommentFilter { + pub fn rfd(mut self, rfd: Option>>) -> Self { + self.rfd = rfd; + self + } + + pub fn user(mut self, user: Option>>) -> Self { + self.user = user; + self + } +} + +#[cfg_attr(feature = "mock", automock)] +#[async_trait] +pub trait RfdCommentStore { + async fn list( + &self, + filters: Vec, + pagination: &ListPagination, + ) -> Result, StoreError>; + async fn upsert(&self, new_rfd_comment: NewRfdComment) -> Result; + async fn delete(&self, id: &TypedUuid) -> Result, StoreError>; +} diff --git a/rfd-model/src/storage/postgres.rs b/rfd-model/src/storage/postgres.rs index bb954cb4..05a6953d 100644 --- a/rfd-model/src/storage/postgres.rs +++ b/rfd-model/src/storage/postgres.rs @@ -23,13 +23,15 @@ use crate::{ schema::{job, rfd, rfd_pdf, rfd_revision}, schema_ext::Visibility, storage::StoreError, - Job, NewJob, NewRfd, NewRfdPdf, NewRfdRevision, Rfd, RfdId, RfdMeta, RfdPdf, RfdPdfId, - RfdRevision, RfdRevisionId, RfdRevisionMeta, + Job, NewJob, NewRfd, NewRfdComment, NewRfdCommentUser, NewRfdPdf, NewRfdRevision, Rfd, + RfdComment, RfdCommentId, RfdCommentUser, RfdId, RfdMeta, RfdPdf, RfdPdfId, RfdRevision, + RfdRevisionId, RfdRevisionMeta, }; use super::{ - JobFilter, JobStore, ListPagination, RfdFilter, RfdMetaStore, RfdPdfFilter, RfdPdfStore, - RfdRevisionFilter, RfdRevisionMetaStore, RfdRevisionStore, RfdStore, + JobFilter, JobStore, ListPagination, RfdCommentFilter, RfdCommentStore, RfdCommentUserStore, + RfdFilter, RfdMetaStore, RfdPdfFilter, RfdPdfStore, RfdRevisionFilter, RfdRevisionMetaStore, + RfdRevisionStore, RfdStore, }; #[async_trait] @@ -748,6 +750,35 @@ impl JobStore for PostgresStore { } } +#[async_trait] +impl RfdCommentUserStore for PostgresStore { + async fn upsert( + &self, + new_rfd_comment_user: NewRfdCommentUser, + ) -> Result { + unimplemented!() + } +} + +#[async_trait] +impl RfdCommentStore for PostgresStore { + async fn list( + &self, + filters: Vec, + pagination: &ListPagination, + ) -> Result, StoreError> { + unimplemented!() + } + + async fn upsert(&self, new_rfd_comment: NewRfdComment) -> Result { + unimplemented!() + } + + async fn delete(&self, id: &TypedUuid) -> Result, StoreError> { + unimplemented!() + } +} + fn flatten_predicates( predicates: Vec>>>, ) -> Option>>