origin_platform/
confirmation.rs1use async_trait::async_trait;
11use origin_domain::Result;
12use std::fmt::Debug;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct ConfirmationRequest {
17 pub title: String,
19 pub body: String,
21}
22
23impl ConfirmationRequest {
24 pub fn new(title: impl Into<String>, body: impl Into<String>) -> Self {
25 Self {
26 title: title.into(),
27 body: body.into(),
28 }
29 }
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum ConfirmationDecision {
35 Approved,
36 Denied,
37}
38
39#[async_trait]
45pub trait ConfirmationService: Debug + Send + Sync + 'static {
46 async fn confirm(&self, request: ConfirmationRequest) -> Result<ConfirmationDecision>;
47}
48
49#[derive(Debug, Clone, Copy, Default)]
55pub struct DenyingConfirmationService;
56
57#[async_trait]
58impl ConfirmationService for DenyingConfirmationService {
59 async fn confirm(&self, request: ConfirmationRequest) -> Result<ConfirmationDecision> {
60 tracing::info!(
61 title = %request.title,
62 "confirmation denied — no confirmation service configured"
63 );
64 Ok(ConfirmationDecision::Denied)
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[tokio::test]
73 async fn the_denying_confirmation_service_always_returns_denied() {
74 let service = DenyingConfirmationService;
75
76 let decision = service
77 .confirm(ConfirmationRequest::new("Allow?", "Run?"))
78 .await
79 .unwrap();
80
81 assert_eq!(decision, ConfirmationDecision::Denied);
82 }
83}