tap_msg/message/
reject.rs

1//! Reject message type for the Transaction Authorization Protocol.
2//!
3//! This module defines the Reject message type, which is used
4//! for rejecting transactions in the TAP protocol.
5
6use chrono::Utc;
7use serde::{Deserialize, Serialize};
8
9use crate::didcomm::PlainMessage;
10use crate::error::{Error, Result};
11use crate::impl_tap_message;
12use crate::message::tap_message_trait::TapMessageBody;
13
14/// Reject message body (TAIP-4).
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Reject {
17    /// ID of the transaction being rejected.
18    pub transaction_id: String,
19
20    /// Reason for rejection.
21    pub reason: String,
22}
23
24impl Reject {
25    /// Create a new Reject message
26    pub fn new(transaction_id: &str, reason: &str) -> Self {
27        Self {
28            transaction_id: transaction_id.to_string(),
29            reason: reason.to_string(),
30        }
31    }
32}
33
34impl TapMessageBody for Reject {
35    fn message_type() -> &'static str {
36        "https://tap.rsvp/schema/1.0#reject"
37    }
38
39    fn validate(&self) -> Result<()> {
40        if self.transaction_id.is_empty() {
41            return Err(Error::Validation(
42                "Transaction ID is required in Reject".to_string(),
43            ));
44        }
45
46        if self.reason.is_empty() {
47            return Err(Error::Validation(
48                "Reason is required in Reject".to_string(),
49            ));
50        }
51
52        Ok(())
53    }
54
55    fn to_didcomm(&self, from_did: &str) -> Result<PlainMessage> {
56        // Create a JSON representation of self with explicit type field
57        let mut body_json =
58            serde_json::to_value(self).map_err(|e| Error::SerializationError(e.to_string()))?;
59
60        // Ensure the @type field is correctly set in the body
61        if let Some(body_obj) = body_json.as_object_mut() {
62            // Add or update the @type field with the message type
63            body_obj.insert(
64                "@type".to_string(),
65                serde_json::Value::String(Self::message_type().to_string()),
66            );
67        }
68
69        // Create a new message with a random ID
70        let id = uuid::Uuid::new_v4().to_string();
71        let created_time = Utc::now().timestamp() as u64;
72
73        // The from field is required in our PlainMessage
74        let from = from_did.to_string();
75
76        // Create the message
77        let message = PlainMessage {
78            id,
79            typ: "application/didcomm-plain+json".to_string(),
80            type_: Self::message_type().to_string(),
81            from,
82            to: Vec::new(), // Empty recipients, will be determined by the framework later
83            thid: Some(self.transaction_id.clone()),
84            pthid: None,
85            created_time: Some(created_time),
86            expires_time: None,
87            extra_headers: std::collections::HashMap::new(),
88            from_prior: None,
89            body: body_json,
90            attachments: None,
91        };
92
93        Ok(message)
94    }
95}
96
97impl_tap_message!(Reject);