Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
httpd: Add cob state to listing endpoints
Sebastian Martinez committed 3 years ago
commit 866755374058f1bbfcdf209c7788fc5755b14ad1
parent 6f17a4db67206748b5fe8f812920efaf9b7427ac
3 files changed +83 -14
modified radicle-httpd/src/api.rs
@@ -14,8 +14,8 @@ use serde_json::json;
use tokio::sync::RwLock;
use tower_http::cors::{self, CorsLayer};

-
use radicle::cob::issue::Issues;
-
use radicle::cob::patch::Patches;
+
use radicle::cob::issue;
+
use radicle::cob::patch;
use radicle::identity::Id;
use radicle::storage::{ReadRepository, ReadStorage};
use radicle::Profile;
@@ -50,8 +50,8 @@ impl Context {
        let doc = repo.identity_doc()?.1.verified()?;
        let payload = doc.project()?;
        let delegates = doc.delegates;
-
        let issues = Issues::open(&repo)?.counts()?;
-
        let patches = Patches::open(&repo)?.counts()?;
+
        let issues = issue::Issues::open(&repo)?.counts()?;
+
        let patches = patch::Patches::open(&repo)?.counts()?;

        Ok(project::Info {
            payload,
@@ -115,6 +115,52 @@ pub struct PaginationQuery {
    pub per_page: Option<usize>,
}

+
#[derive(Serialize, Deserialize, Clone)]
+
#[serde(rename_all = "camelCase")]
+
pub struct CobsQuery<T> {
+
    pub page: Option<usize>,
+
    pub per_page: Option<usize>,
+
    pub state: Option<T>,
+
}
+

+
#[derive(Default, Serialize, Deserialize, Clone)]
+
#[serde(rename_all = "camelCase")]
+
pub enum IssueState {
+
    Closed,
+
    #[default]
+
    Open,
+
}
+

+
impl IssueState {
+
    pub fn matches(&self, issue: &issue::State) -> bool {
+
        match self {
+
            Self::Open => matches!(issue, issue::State::Open),
+
            Self::Closed => matches!(issue, issue::State::Closed { .. }),
+
        }
+
    }
+
}
+

+
#[derive(Default, Serialize, Deserialize, Clone)]
+
#[serde(rename_all = "camelCase")]
+
pub enum PatchState {
+
    #[default]
+
    Open,
+
    Draft,
+
    Archived,
+
    Merged,
+
}
+

+
impl PatchState {
+
    pub fn matches(&self, patch: &patch::State) -> bool {
+
        match self {
+
            Self::Open => matches!(patch, patch::State::Open),
+
            Self::Draft => matches!(patch, patch::State::Draft),
+
            Self::Archived => matches!(patch, patch::State::Archived),
+
            Self::Merged => matches!(patch, patch::State::Merged),
+
        }
+
    }
+
}
+

mod project {
    use nonempty::NonEmpty;
    use serde::Serialize;
modified radicle-httpd/src/api/v1/projects.rs
@@ -21,7 +21,7 @@ use radicle_surf::{Glob, Oid, Repository};

use crate::api::error::Error;
use crate::api::project::Info;
-
use crate::api::{self, Context, PaginationQuery};
+
use crate::api::{self, CobsQuery, Context, PaginationQuery};
use crate::axum_extra::{Path, Query};

const CACHE_1_HOUR: &str = "public, max-age=3600, must-revalidate";
@@ -416,15 +416,27 @@ async fn readme_handler(
async fn issues_handler(
    State(ctx): State<Context>,
    Path(project): Path<Id>,
-
    Query(qs): Query<PaginationQuery>,
+
    Query(qs): Query<CobsQuery<api::IssueState>>,
) -> impl IntoResponse {
-
    let PaginationQuery { page, per_page } = qs;
+
    let CobsQuery {
+
        page,
+
        per_page,
+
        state,
+
    } = qs;
    let page = page.unwrap_or(0);
    let per_page = per_page.unwrap_or(10);
+
    let state = state.unwrap_or_default();
    let storage = &ctx.profile.storage;
    let repo = storage.repository(project)?;
    let issues = issue::Issues::open(&repo)?;
-
    let mut issues: Vec<_> = issues.all()?.filter_map(|r| r.ok()).collect::<Vec<_>>();
+
    let mut issues: Vec<_> = issues
+
        .all()?
+
        .filter_map(|r| {
+
            let (id, issue, clock) = r.ok()?;
+
            (state.matches(issue.state())).then_some((id, issue, clock))
+
        })
+
        .collect::<Vec<_>>();
+

    issues.sort_by(|(_, a, _), (_, b, _)| b.timestamp().cmp(&a.timestamp()));
    let issues = issues
        .into_iter()
@@ -687,15 +699,26 @@ async fn patch_update_handler(
async fn patches_handler(
    State(ctx): State<Context>,
    Path(project): Path<Id>,
-
    Query(qs): Query<PaginationQuery>,
+
    Query(qs): Query<CobsQuery<api::PatchState>>,
) -> impl IntoResponse {
-
    let PaginationQuery { page, per_page } = qs;
+
    let CobsQuery {
+
        page,
+
        per_page,
+
        state,
+
    } = qs;
    let page = page.unwrap_or(0);
    let per_page = per_page.unwrap_or(10);
+
    let state = state.unwrap_or_default();
    let storage = &ctx.profile.storage;
    let repo = storage.repository(project)?;
    let patches = patch::Patches::open(&repo)?;
-
    let mut patches = patches.all()?.filter_map(|r| r.ok()).collect::<Vec<_>>();
+
    let mut patches = patches
+
        .all()?
+
        .filter_map(|r| {
+
            let (id, patch, clock) = r.ok()?;
+
            (state.matches(&patch.state())).then_some((id, patch, clock))
+
        })
+
        .collect::<Vec<_>>();
    patches.sort_by(|(_, a, _), (_, b, _)| b.timestamp().cmp(&a.timestamp()));
    let patches = patches
        .into_iter()
modified radicle/src/cob/issue.rs
@@ -63,7 +63,7 @@ impl std::fmt::Display for State {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Closed { .. } => write!(f, "closed"),
-
            Self::Open { .. } => write!(f, "open"),
+
            Self::Open => write!(f, "open"),
        }
    }
}
@@ -71,8 +71,8 @@ impl std::fmt::Display for State {
impl State {
    pub fn lifecycle_message(self) -> String {
        match self {
-
            State::Open => "Open issue".to_owned(),
-
            State::Closed { .. } => "Close issue".to_owned(),
+
            Self::Open => "Open issue".to_owned(),
+
            Self::Closed { .. } => "Close issue".to_owned(),
        }
    }
}