versa/protocol/
webhook.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::str::FromStr;
4
5// Feature flagged imports
6
7#[cfg(feature = "diesel")]
8use std::io::Write;
9
10#[cfg(feature = "diesel")]
11use diesel::deserialize::{self, FromSql, FromSqlRow};
12#[cfg(feature = "diesel")]
13use diesel::prelude::*;
14#[cfg(feature = "diesel")]
15use diesel::serialize::{self, IsNull, Output, ToSql};
16#[cfg(feature = "diesel")]
17use diesel::{expression::AsExpression, sql_types::Text};
18
19#[cfg(feature = "diesel")]
20use diesel::mysql::{Mysql, MysqlValue};
21
22////////////////////////////////////////////////////////////////////
23///
24/// TransactionEvent
25/// A subset of webhook event types indicating the protocol events
26/// that are orchestrated directly between senders and receivers.
27///
28////////////////////////////////////////////////////////////////////
29
30#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
31#[cfg_attr(
32  feature = "diesel",
33  derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)
34)]
35#[cfg_attr(feature = "diesel", diesel(sql_type = Text))]
36pub enum TransactionEvent {
37  #[serde(rename = "itinerary")]
38  Itinerary,
39  #[serde(rename = "receipt")]
40  Receipt,
41}
42
43impl fmt::Display for TransactionEvent {
44  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45    let serialized = serde_json::to_string(self).unwrap().replace("\"", "");
46    write!(f, "{}", serialized)
47  }
48}
49
50impl FromStr for TransactionEvent {
51  type Err = String;
52
53  fn from_str(s: &str) -> Result<Self, Self::Err> {
54    match s {
55      "itinerary" => Ok(TransactionEvent::Itinerary),
56      "receipt" => Ok(TransactionEvent::Receipt),
57      _ => Err("Unrecognized TransactionEvent enum variant".to_string()),
58    }
59  }
60}
61
62impl Into<WebhookEventType> for TransactionEvent {
63  fn into(self) -> WebhookEventType {
64    match self {
65      TransactionEvent::Itinerary => WebhookEventType::Itinerary,
66      TransactionEvent::Receipt => WebhookEventType::Receipt,
67    }
68  }
69}
70
71impl TryFrom<WebhookEventType> for TransactionEvent {
72  type Error = String;
73
74  fn try_from(value: WebhookEventType) -> Result<Self, Self::Error> {
75    match value {
76      WebhookEventType::Itinerary => Ok(TransactionEvent::Itinerary),
77      WebhookEventType::Receipt => Ok(TransactionEvent::Receipt),
78      _ => Err(format!(
79        "TransactionEvent cannot be created from WebhookEventType::{}",
80        value
81      )),
82    }
83  }
84}
85
86#[cfg(feature = "diesel")]
87impl ToSql<Text, Mysql> for TransactionEvent {
88  fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
89    out.write_all(&*self.to_string().as_bytes())?;
90    Ok(IsNull::No)
91  }
92}
93
94#[cfg(feature = "diesel")]
95impl FromSql<Text, Mysql> for TransactionEvent {
96  fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
97    match bytes.as_bytes() {
98      b"itinerary" => Ok(TransactionEvent::Itinerary),
99      b"receipt" => Ok(TransactionEvent::Receipt),
100      _ => Err("Unrecognized misuse_code enum variant".into()),
101    }
102  }
103}
104
105////////////////////////////////////////////////////////////////////
106///
107/// WebhookEventType
108/// The superset of webhook event types supported by Versa services.
109///
110////////////////////////////////////////////////////////////////////
111
112#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Hash)]
113#[cfg_attr(
114  feature = "diesel",
115  derive(diesel::expression::AsExpression, diesel::deserialize::FromSqlRow)
116)]
117#[cfg_attr(feature = "diesel", diesel(sql_type = Text))]
118pub enum WebhookEventType {
119  #[serde(rename = "customer.deregistered_by_sender")]
120  CustomerDeregisteredBySender,
121  #[serde(rename = "customer.registered_by_sender")]
122  CustomerRegisteredBySender,
123  #[serde(rename = "itinerary")]
124  Itinerary,
125  #[serde(rename = "itinerary.decrypted")]
126  ItineraryDecrypted,
127  #[serde(rename = "receipt")]
128  Receipt,
129  #[serde(rename = "receipt.decrypted")]
130  ReceiptDecrypted,
131}
132
133impl fmt::Display for WebhookEventType {
134  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135    let serialized = serde_json::to_string(self).unwrap().replace("\"", "");
136    write!(f, "{}", serialized)
137  }
138}
139
140impl FromStr for WebhookEventType {
141  type Err = String;
142
143  fn from_str(s: &str) -> Result<Self, Self::Err> {
144    match s {
145      "customer.deregistered_by_sender" => Ok(WebhookEventType::CustomerDeregisteredBySender),
146      "customer.registered_by_sender" => Ok(WebhookEventType::CustomerRegisteredBySender),
147      "itinerary" => Ok(WebhookEventType::Itinerary),
148      "itinerary.decrypted" => Ok(WebhookEventType::ItineraryDecrypted),
149      "receipt" => Ok(WebhookEventType::Receipt),
150      "receipt.decrypted" => Ok(WebhookEventType::ReceiptDecrypted),
151      _ => Err("Unrecognized WebhookEventType enum variant".to_string()),
152    }
153  }
154}
155
156#[cfg(feature = "diesel")]
157impl ToSql<Text, Mysql> for WebhookEventType {
158  fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
159    out.write_all(&*self.to_string().as_bytes())?;
160    Ok(IsNull::No)
161  }
162}
163
164#[cfg(feature = "diesel")]
165impl FromSql<Text, Mysql> for WebhookEventType {
166  fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
167    match bytes.as_bytes() {
168      b"customer.deregistered_by_sender" => Ok(WebhookEventType::CustomerDeregisteredBySender),
169      b"customer.registered_by_sender" => Ok(WebhookEventType::CustomerRegisteredBySender),
170      b"itinerary" => Ok(WebhookEventType::Itinerary),
171      b"itinerary.decrypted" => Ok(WebhookEventType::ItineraryDecrypted),
172      b"receipt" => Ok(WebhookEventType::Receipt),
173      b"receipt.decrypted" => Ok(WebhookEventType::ReceiptDecrypted),
174      _ => Err("Unrecognized misuse_code enum variant".into()),
175    }
176  }
177}
178
179////////////////////////////////////////////////////////////////////
180///
181/// WebhookEvent
182/// The standard object structure for all webhook events sent
183/// over the Versa network.
184///
185////////////////////////////////////////////////////////////////////
186
187#[derive(Deserialize, Serialize)]
188pub struct WebhookEvent<T> {
189  pub event: WebhookEventType,
190  pub event_id: Option<String>,
191  pub event_at: Option<i64>,
192  pub delivery_id: Option<String>,
193  pub delivery_at: Option<i64>,
194  pub data: T,
195}