made-api 0.3.0

Published contract of the embedded MADE: versioned views, capabilities and errors
Documentation
use serde::{Deserialize, Serialize};

use crate::InterventionResponseView;

/// One intervention — a question, investigation or proposed action put to the
/// table — as a consumer sees it.
///
/// The table's conversational unit. A projection, never the entity: responses
/// come with who answered and when, the request with who asked, and `open`
/// with whether the table still owes an answer.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct InterventionView {
    pub intervention_id: String,
    /// `opinion`, `investigation` or `action`.
    pub kind: String,
    pub requested_by: String,
    /// The seats asked. Empty means the whole table.
    pub target_role_ids: Vec<String>,
    pub request: String,
    pub open: bool,
    pub responses: Vec<InterventionResponseView>,
    pub created_at_millis: i64,
    pub closed_at_millis: Option<i64>,
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::RaiseInterventionRequest;

    #[test]
    fn an_intervention_survives_the_wire() {
        let view = InterventionView {
            intervention_id: "iv-1".to_owned(),
            kind: "opinion".to_owned(),
            requested_by: "FACILITATOR".to_owned(),
            target_role_ids: vec!["REVIEWER".to_owned()],
            request: "Recommend the safest cleanup.".to_owned(),
            open: true,
            responses: vec![InterventionResponseView {
                role_id: "REVIEWER".to_owned(),
                content: "Rotate the certificate first.".to_owned(),
                responded_at_millis: 1_700_000_000_000,
            }],
            created_at_millis: 1_700_000_000_000,
            closed_at_millis: None,
        };
        let bytes = serde_json::to_vec(&view).expect("serializes");
        assert_eq!(
            serde_json::from_slice::<InterventionView>(&bytes).expect("deserializes"),
            view
        );
    }

    #[test]
    fn an_empty_target_means_the_whole_table() {
        let request = RaiseInterventionRequest {
            ceremony_id: "c-1".to_owned(),
            intervention_id: "iv-1".to_owned(),
            role_id: "FACILITATOR".to_owned(),
            role_kind: "human".to_owned(),
            kind: "opinion".to_owned(),
            target_role_ids: Vec::new(),
            request: "Thoughts?".to_owned(),
        };
        assert!(
            request.target_role_ids.is_empty(),
            "no listed seat narrows the question; everyone at the table is asked"
        );
    }
}