Skip to content

Commit aaff284

Browse files
authored
Merge pull request #109 from CodeGov-org/feat/review-summary
feat: `get_my_proposal_review_summary` endpoint
2 parents bb438a4 + 62e6bbe commit aaff284

16 files changed

Lines changed: 897 additions & 151 deletions

src/backend/api/backend.did

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,11 +317,22 @@ type GetMyProposalReviewRequest = record {
317317
proposal_id : text;
318318
};
319319

320+
type GetMyProposalReviewSummaryRequest = record {
321+
proposal_id : text;
322+
};
323+
320324
type GetMyProposalReviewResponse = variant {
321325
ok : ProposalReviewWithId;
322326
err : Err;
323327
};
324328

329+
type GetMyProposalReviewSummaryResponse = variant {
330+
ok : record {
331+
summary_markdown : text;
332+
};
333+
err : Err;
334+
};
335+
325336
type ProposalReviewCommit = record {
326337
proposal_review_id : text;
327338
user_id : text;
@@ -404,6 +415,7 @@ service : {
404415
create_proposal_review_image : (CreateProposalReviewImageRequest) -> (CreateProposalReviewImageResponse);
405416
delete_proposal_review_image : (DeleteProposalReviewImageRequest) -> (DeleteProposalReviewImageResponse);
406417
get_my_proposal_review : (GetMyProposalReviewRequest) -> (GetMyProposalReviewResponse) query;
418+
get_my_proposal_review_summary : (GetMyProposalReviewSummaryRequest) -> (GetMyProposalReviewSummaryResponse) query;
407419
create_proposal_review_commit : (CreateProposalReviewCommitRequest) -> (CreateProposalReviewCommitResponse);
408420
update_proposal_review_commit : (UpdateProposalReviewCommitRequest) -> (UpdateProposalReviewCommitResponse);
409421
delete_proposal_review_commit : (DeleteProposalReviewCommitRequest) -> (DeleteProposalReviewCommitResponse);

src/backend/api/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod log;
44
mod proposal;
55
mod proposal_review;
66
mod proposal_review_commit;
7+
mod proposal_review_summary;
78
mod result;
89
mod user_profile;
910

@@ -13,5 +14,6 @@ pub use log::*;
1314
pub use proposal::*;
1415
pub use proposal_review::*;
1516
pub use proposal_review_commit::*;
17+
pub use proposal_review_summary::*;
1618
pub use result::*;
1719
pub use user_profile::*;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use candid::{CandidType, Deserialize};
2+
3+
#[derive(Debug, Clone, CandidType, Deserialize, PartialEq, Eq)]
4+
pub struct GetMyProposalReviewSummaryRequest {
5+
pub proposal_id: String,
6+
}
7+
8+
#[derive(Debug, Clone, CandidType, Deserialize, PartialEq, Eq)]
9+
pub struct GetMyProposalReviewSummaryResponse {
10+
pub summary_markdown: String,
11+
}

src/backend/impl/src/controllers/proposal_review_controller.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use crate::{
1212
use backend_api::{
1313
ApiError, ApiResult, CreateProposalReviewImageRequest, CreateProposalReviewImageResponse,
1414
CreateProposalReviewRequest, CreateProposalReviewResponse, DeleteProposalReviewImageRequest,
15-
GetMyProposalReviewRequest, GetMyProposalReviewResponse, GetProposalReviewRequest,
16-
GetProposalReviewResponse, ListProposalReviewsRequest, ListProposalReviewsResponse,
17-
UpdateProposalReviewRequest,
15+
GetMyProposalReviewRequest, GetMyProposalReviewResponse, GetMyProposalReviewSummaryRequest,
16+
GetMyProposalReviewSummaryResponse, GetProposalReviewRequest, GetProposalReviewResponse,
17+
ListProposalReviewsRequest, ListProposalReviewsResponse, UpdateProposalReviewRequest,
1818
};
1919
use candid::Principal;
2020
use ic_cdk::*;
@@ -92,6 +92,17 @@ fn get_my_proposal_review(
9292
.into()
9393
}
9494

95+
#[query]
96+
fn get_my_proposal_review_summary(
97+
request: GetMyProposalReviewSummaryRequest,
98+
) -> ApiResult<GetMyProposalReviewSummaryResponse> {
99+
let calling_principal = caller();
100+
101+
ProposalReviewController::default()
102+
.get_my_proposal_review_summary(calling_principal, request)
103+
.into()
104+
}
105+
95106
struct ProposalReviewController<A: AccessControlService, P: ProposalReviewService> {
96107
access_control_service: A,
97108
proposal_review_service: P,
@@ -199,6 +210,20 @@ impl<A: AccessControlService, P: ProposalReviewService> ProposalReviewController
199210
.get_my_proposal_review(calling_principal, request)
200211
}
201212

213+
fn get_my_proposal_review_summary(
214+
&self,
215+
calling_principal: Principal,
216+
request: GetMyProposalReviewSummaryRequest,
217+
) -> Result<GetMyProposalReviewSummaryResponse, ApiError> {
218+
self.access_control_service
219+
.assert_principal_not_anonymous(&calling_principal)?;
220+
self.access_control_service
221+
.assert_principal_is_reviewer(&calling_principal)?;
222+
223+
self.proposal_review_service
224+
.get_my_proposal_review_summary(calling_principal, request)
225+
}
226+
202227
fn delete_proposal_review_image(
203228
&self,
204229
calling_principal: Principal,

src/backend/impl/src/fixtures/commit_sha.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,8 @@ pub fn commit_sha_a() -> CommitSha {
1111
pub fn commit_sha_b() -> CommitSha {
1212
CommitSha::try_from("47d98477c6c59e570e2220aab433b0943b326ef8").unwrap()
1313
}
14+
15+
#[fixture]
16+
pub fn commit_sha_c() -> CommitSha {
17+
CommitSha::try_from("e62e328fa193e73fbb7562458d719f311c25d455").unwrap()
18+
}

src/backend/impl/src/fixtures/proposal_review_commit.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rstest::*;
22

3-
use crate::repositories::{ProposalReviewCommit, ReviewCommitState};
3+
use crate::repositories::{ProposalReviewCommit, ReviewCommitState, ReviewedCommitState};
44

55
use super::{commit_sha_a, commit_sha_b, date_time_a, proposal_review_id, user_id};
66

@@ -12,11 +12,11 @@ pub fn proposal_review_commit_reviewed() -> ProposalReviewCommit {
1212
created_at: date_time_a(),
1313
last_updated_at: None,
1414
commit_sha: commit_sha_a(),
15-
state: ReviewCommitState::Reviewed {
15+
state: ReviewCommitState::Reviewed(ReviewedCommitState {
1616
matches_description: Some(true),
1717
comment: Some("Review commit comment".to_string()),
1818
highlights: vec![],
19-
},
19+
}),
2020
}
2121
}
2222

src/backend/impl/src/mappings/proposal_review_commit.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
use crate::repositories::{ProposalReviewCommit, ProposalReviewCommitId, ReviewCommitState};
1+
use crate::repositories::{
2+
ProposalReviewCommit, ProposalReviewCommitId, ReviewCommitState, ReviewedCommitState,
3+
};
24

35
impl From<ReviewCommitState> for backend_api::ReviewCommitState {
46
fn from(proposal_review_commit_state: ReviewCommitState) -> Self {
57
match proposal_review_commit_state {
6-
ReviewCommitState::Reviewed {
8+
ReviewCommitState::Reviewed(ReviewedCommitState {
79
matches_description,
810
comment,
911
highlights,
10-
} => backend_api::ReviewCommitState::Reviewed {
12+
}) => backend_api::ReviewCommitState::Reviewed {
1113
matches_description,
1214
comment,
1315
highlights,
@@ -24,11 +26,11 @@ impl From<backend_api::ReviewCommitState> for ReviewCommitState {
2426
matches_description,
2527
comment,
2628
highlights,
27-
} => ReviewCommitState::Reviewed {
29+
} => ReviewCommitState::Reviewed(ReviewedCommitState {
2830
matches_description,
2931
comment,
3032
highlights,
31-
},
33+
}),
3234
backend_api::ReviewCommitState::NotReviewed => ReviewCommitState::NotReviewed,
3335
}
3436
}

src/backend/impl/src/repositories/proposal_review_commit_repository.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ mod tests {
233233
use super::*;
234234
use crate::{
235235
fixtures::{self, commit_sha_a, commit_sha_b, uuid_a, uuid_b},
236-
repositories::ReviewCommitState,
236+
repositories::{ReviewCommitState, ReviewedCommitState},
237237
};
238238
use rstest::*;
239239

@@ -507,11 +507,11 @@ mod tests {
507507
#[fixture]
508508
fn updated_proposal_review_commit() -> ProposalReviewCommit {
509509
ProposalReviewCommit {
510-
state: ReviewCommitState::Reviewed {
510+
state: ReviewCommitState::Reviewed(ReviewedCommitState {
511511
matches_description: Some(false),
512512
comment: Some("Updated comment".to_string()),
513513
highlights: vec![],
514-
},
514+
}),
515515
..fixtures::proposal_review_commit_not_reviewed()
516516
}
517517
}

src/backend/impl/src/repositories/types/proposal_review.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{borrow::Cow, ops::RangeBounds};
1+
use std::{borrow::Cow, fmt::Display, ops::RangeBounds};
22

33
use backend_api::ApiError;
44
use candid::{CandidType, Decode, Deserialize, Encode};
@@ -26,6 +26,17 @@ pub enum ProposalVote {
2626
No = 2,
2727
}
2828

29+
impl Display for ProposalVote {
30+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31+
let val = match self {
32+
ProposalVote::Unspecified => "-",
33+
ProposalVote::Yes => "ADOPTED",
34+
ProposalVote::No => "REJECTED",
35+
};
36+
write!(f, "{}", val)
37+
}
38+
}
39+
2940
#[derive(Debug, CandidType, Deserialize, Clone, PartialEq, Eq)]
3041
pub struct ProposalReview {
3142
pub proposal_id: ProposalId,

src/backend/impl/src/repositories/types/proposal_review_commit.rs

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{borrow::Cow, ops::RangeBounds};
1+
use std::{borrow::Cow, fmt::Display, ops::RangeBounds};
22

33
use backend_api::ApiError;
44
use candid::{CandidType, Decode, Deserialize, Encode};
@@ -11,13 +11,40 @@ use super::{CommitSha, DateTime, ProposalReviewId, UserId, Uuid};
1111

1212
pub type ProposalReviewCommitId = Uuid;
1313

14+
#[derive(Debug, CandidType, Deserialize, Clone, PartialEq, Eq)]
15+
pub struct ReviewedCommitState {
16+
pub matches_description: Option<bool>,
17+
pub comment: Option<String>,
18+
pub highlights: Vec<String>,
19+
}
20+
21+
impl Display for ReviewedCommitState {
22+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23+
let mut commit_details = format!(
24+
"Matches description: {}",
25+
self.matches_description
26+
.map(|b| b.to_string())
27+
.unwrap_or_else(|| "Unanswered".to_string()),
28+
);
29+
if let Some(comment) = self.comment.as_ref() {
30+
if !comment.is_empty() {
31+
commit_details = format!("{}\nComment: {}", commit_details, comment);
32+
}
33+
}
34+
if !self.highlights.is_empty() {
35+
commit_details = format!(
36+
"{}\nHighlights: {}",
37+
commit_details,
38+
self.highlights.join(", ")
39+
);
40+
}
41+
write!(f, "{}", commit_details)
42+
}
43+
}
44+
1445
#[derive(Debug, CandidType, Deserialize, Clone, PartialEq, Eq)]
1546
pub enum ReviewCommitState {
16-
Reviewed {
17-
matches_description: Option<bool>,
18-
comment: Option<String>,
19-
highlights: Vec<String>,
20-
},
47+
Reviewed(ReviewedCommitState),
2148
NotReviewed,
2249
}
2350

@@ -39,6 +66,14 @@ impl ProposalReviewCommit {
3966
pub fn is_not_reviewed(&self) -> bool {
4067
matches!(&self.state, ReviewCommitState::NotReviewed)
4168
}
69+
70+
pub fn reviewed_state(&self) -> Option<&ReviewedCommitState> {
71+
if let ReviewCommitState::Reviewed(state) = &self.state {
72+
Some(state)
73+
} else {
74+
None
75+
}
76+
}
4277
}
4378

4479
impl Storable for ProposalReviewCommit {
@@ -174,4 +209,42 @@ mod tests {
174209

175210
assert_eq!(key, deserialized_key);
176211
}
212+
213+
#[rstest]
214+
fn reviewed_commit_state_display_impl() {
215+
let mut state = ReviewedCommitState {
216+
matches_description: None,
217+
comment: None,
218+
highlights: vec![],
219+
};
220+
221+
assert_eq!(state.to_string(), "Matches description: Unanswered");
222+
223+
state.matches_description = Some(false);
224+
assert_eq!(state.to_string(), "Matches description: false");
225+
226+
state.matches_description = Some(true);
227+
assert_eq!(state.to_string(), "Matches description: true");
228+
229+
state.comment = Some("".to_string());
230+
assert_eq!(state.to_string(), "Matches description: true");
231+
232+
state.comment = Some("test".to_string());
233+
assert_eq!(
234+
state.to_string(),
235+
"Matches description: true\nComment: test"
236+
);
237+
238+
state.highlights = vec!["test".to_string()];
239+
assert_eq!(
240+
state.to_string(),
241+
"Matches description: true\nComment: test\nHighlights: test"
242+
);
243+
244+
state.highlights = vec!["test1".to_string(), "test2".to_string()];
245+
assert_eq!(
246+
state.to_string(),
247+
"Matches description: true\nComment: test\nHighlights: test1, test2"
248+
);
249+
}
177250
}

0 commit comments

Comments
 (0)