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            intent: None,
57            delivery: None,
58            supervisor: None,
59            now,
60        });
61        let events = self.decide(&command, definition)?;
62        self.apply_all(&events);
63        Ok(())
64    }
65
66    pub fn respond_to_intervention_as(
67        &mut self,
68        definition: &CeremonyDefinition,
69        intervention_id: &CeremonyInterventionId,
70        role_id: RoleId,
71        content: CeremonyInterventionContent,
72        now: OffsetDateTime,
73    ) -> Result<(), DomainError> {
74        let command = CeremonyCommand::RespondToIntervention(RespondToIntervention {
75            intervention_id: intervention_id.clone(),
76            role_id,
77            content,
78            executor: None,
79            delivery_id: None,
80            now,
81        });
82        let events = self.decide(&command, definition)?;
83        self.apply_all(&events);
84        Ok(())
85    }
86
87    /// A query, not a command: what a source should be asked to
88    /// answer an item, checked against the same rules a response is.
89    /// It changes nothing, so it decides no event.
90    pub fn prepare_evidence_request_as(
91        &self,
92        definition: &CeremonyDefinition,
93        intervention_id: CeremonyInterventionId,
94        role_id: RoleId,
95        source_id: CeremonyEvidenceSourceId,
96        query: CeremonyInterventionContent,
97    ) -> Result<CeremonyEvidenceRequest, DomainError> {
98        self.require_active(
99            definition,
100            "terminal ceremony instances cannot collect intervention evidence",
101        )?;
102        self.require_role(definition, &role_id, &RoleAction::respond_to_intervention())?;
103        self.intervention(&intervention_id)
104            .ok_or(DomainError::NotFound {
105                what: "ceremony_intervention",
106            })?
107            .ensure_can_respond(&role_id)?;
108        Ok(CeremonyEvidenceRequest::new(
109            self.id.clone(),
110            intervention_id,
111            role_id,
112            source_id,
113            query,
114            self.context.clone(),
115        ))
116    }
117
118    pub fn respond_to_intervention_with_evidence_as(
119        &mut self,
120        definition: &CeremonyDefinition,
121        intervention_id: &CeremonyInterventionId,
122        role_id: RoleId,
123        evidence_pack: CeremonyEvidencePack,
124        now: OffsetDateTime,
125    ) -> Result<(), DomainError> {
126        let command =
127            CeremonyCommand::RespondToInterventionWithEvidence(RespondToInterventionWithEvidence {
128                intervention_id: intervention_id.clone(),
129                role_id,
130                evidence_pack,
131                now,
132            });
133        let events = self.decide(&command, definition)?;
134        self.apply_all(&events);
135        Ok(())
136    }
137
138    /// State why one thing here led to another.
139    ///
140    /// Its own act rather than a field on contributing, because a
141    /// reason is often known later — "in fact I did that because…" is
142    /// how people reason — and because a field gets filled in by
143    /// inertia while an act is chosen. What it refuses is decided in
144    /// [`Self::decide`]; the reason itself is built first, so a why
145    /// that is empty or an edge from a thing to itself is refused by
146    /// the reason before the session is consulted.
147    pub fn assert_reason_as(
148        &mut self,
149        definition: &CeremonyDefinition,
150        role_id: RoleId,
151        from: CeremonyRecordRef,
152        to: CeremonyRecordRef,
153        kind: CeremonyReasonKind,
154        why: impl Into<String>,
155        confidence: MemoryConfidence,
156        now: OffsetDateTime,
157    ) -> Result<(), DomainError> {
158        let reason = CeremonyReason::new(from, to, kind, why, confidence, Some(role_id), now)?;
159        let command = CeremonyCommand::AssertReason(AssertReason { reason });
160        let events = self.decide(&command, definition)?;
161        self.apply_all(&events);
162        Ok(())
163    }
164
165    pub fn close_intervention_as(
166        &mut self,
167        definition: &CeremonyDefinition,
168        intervention_id: &CeremonyInterventionId,
169        role_id: &RoleId,
170        now: OffsetDateTime,
171    ) -> Result<(), DomainError> {
172        let command = CeremonyCommand::CloseIntervention(CloseIntervention {
173            intervention_id: intervention_id.clone(),
174            role_id: role_id.clone(),
175            now,
176        });
177        let events = self.decide(&command, definition)?;
178        self.apply_all(&events);
179        Ok(())
180    }
181}