Skip to main content

made_core/entities/ceremony_instance/
interventions.rs

1use crate::entities::ceremony_commands::{
2    AssertReason, CloseIntervention, RequestIntervention, RespondToIntervention,
3    RespondToInterventionWithEvidence,
4};
5use crate::entities::CeremonyCommand;
6
7use super::{
8    CeremonyDefinition, CeremonyEvidencePack, CeremonyEvidenceRequest, CeremonyEvidenceSourceId,
9    CeremonyInstance, CeremonyInterventionContent, CeremonyInterventionId,
10    CeremonyInterventionKind, CeremonyInterventionProvenance, CeremonyInterventionTarget,
11    CeremonyReason, CeremonyReasonKind, CeremonyRecordRef, DomainError, MemoryConfidence,
12    OffsetDateTime, RoleAction, RoleId,
13};
14
15impl CeremonyInstance {
16    pub fn request_intervention_as(
17        &mut self,
18        definition: &CeremonyDefinition,
19        intervention_id: CeremonyInterventionId,
20        role_id: RoleId,
21        kind: CeremonyInterventionKind,
22        target: CeremonyInterventionTarget,
23        content: CeremonyInterventionContent,
24        now: OffsetDateTime,
25    ) -> Result<(), DomainError> {
26        self.request_intervention_with_provenance_as(
27            definition,
28            intervention_id,
29            role_id,
30            kind,
31            target,
32            content,
33            None,
34            now,
35        )
36    }
37
38    pub fn request_intervention_with_provenance_as(
39        &mut self,
40        definition: &CeremonyDefinition,
41        intervention_id: CeremonyInterventionId,
42        role_id: RoleId,
43        kind: CeremonyInterventionKind,
44        target: CeremonyInterventionTarget,
45        content: CeremonyInterventionContent,
46        provenance: Option<CeremonyInterventionProvenance>,
47        now: OffsetDateTime,
48    ) -> Result<(), DomainError> {
49        let command = CeremonyCommand::RequestIntervention(RequestIntervention {
50            intervention_id,
51            role_id,
52            kind,
53            target,
54            content,
55            provenance,
56            now,
57        });
58        let events = self.decide(&command, definition)?;
59        self.apply_all(&events);
60        Ok(())
61    }
62
63    pub fn respond_to_intervention_as(
64        &mut self,
65        definition: &CeremonyDefinition,
66        intervention_id: &CeremonyInterventionId,
67        role_id: RoleId,
68        content: CeremonyInterventionContent,
69        now: OffsetDateTime,
70    ) -> Result<(), DomainError> {
71        let command = CeremonyCommand::RespondToIntervention(RespondToIntervention {
72            intervention_id: intervention_id.clone(),
73            role_id,
74            content,
75            now,
76        });
77        let events = self.decide(&command, definition)?;
78        self.apply_all(&events);
79        Ok(())
80    }
81
82    /// A query, not a command: what a source should be asked to
83    /// answer an item, checked against the same rules a response is.
84    /// It changes nothing, so it decides no event.
85    pub fn prepare_evidence_request_as(
86        &self,
87        definition: &CeremonyDefinition,
88        intervention_id: CeremonyInterventionId,
89        role_id: RoleId,
90        source_id: CeremonyEvidenceSourceId,
91        query: CeremonyInterventionContent,
92    ) -> Result<CeremonyEvidenceRequest, DomainError> {
93        self.require_active(
94            definition,
95            "terminal ceremony instances cannot collect intervention evidence",
96        )?;
97        self.require_role(definition, &role_id, &RoleAction::respond_to_intervention())?;
98        self.intervention(&intervention_id)
99            .ok_or(DomainError::NotFound {
100                what: "ceremony_intervention",
101            })?
102            .ensure_can_respond(&role_id)?;
103        Ok(CeremonyEvidenceRequest::new(
104            self.id.clone(),
105            intervention_id,
106            role_id,
107            source_id,
108            query,
109            self.context.clone(),
110        ))
111    }
112
113    pub fn respond_to_intervention_with_evidence_as(
114        &mut self,
115        definition: &CeremonyDefinition,
116        intervention_id: &CeremonyInterventionId,
117        role_id: RoleId,
118        evidence_pack: CeremonyEvidencePack,
119        now: OffsetDateTime,
120    ) -> Result<(), DomainError> {
121        let command =
122            CeremonyCommand::RespondToInterventionWithEvidence(RespondToInterventionWithEvidence {
123                intervention_id: intervention_id.clone(),
124                role_id,
125                evidence_pack,
126                now,
127            });
128        let events = self.decide(&command, definition)?;
129        self.apply_all(&events);
130        Ok(())
131    }
132
133    /// State why one thing here led to another.
134    ///
135    /// Its own act rather than a field on contributing, because a
136    /// reason is often known later — "in fact I did that because…" is
137    /// how people reason — and because a field gets filled in by
138    /// inertia while an act is chosen. What it refuses is decided in
139    /// [`Self::decide`]; the reason itself is built first, so a why
140    /// that is empty or an edge from a thing to itself is refused by
141    /// the reason before the session is consulted.
142    pub fn assert_reason_as(
143        &mut self,
144        definition: &CeremonyDefinition,
145        role_id: RoleId,
146        from: CeremonyRecordRef,
147        to: CeremonyRecordRef,
148        kind: CeremonyReasonKind,
149        why: impl Into<String>,
150        confidence: MemoryConfidence,
151        now: OffsetDateTime,
152    ) -> Result<(), DomainError> {
153        let reason = CeremonyReason::new(from, to, kind, why, confidence, Some(role_id), now)?;
154        let command = CeremonyCommand::AssertReason(AssertReason { reason });
155        let events = self.decide(&command, definition)?;
156        self.apply_all(&events);
157        Ok(())
158    }
159
160    pub fn close_intervention_as(
161        &mut self,
162        definition: &CeremonyDefinition,
163        intervention_id: &CeremonyInterventionId,
164        role_id: &RoleId,
165        now: OffsetDateTime,
166    ) -> Result<(), DomainError> {
167        let command = CeremonyCommand::CloseIntervention(CloseIntervention {
168            intervention_id: intervention_id.clone(),
169            role_id: role_id.clone(),
170            now,
171        });
172        let events = self.decide(&command, definition)?;
173        self.apply_all(&events);
174        Ok(())
175    }
176}