use serde::{Deserialize, Serialize};
use serde_json::Value;
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct InteractionId(pub Uuid);
impl std::fmt::Display for InteractionId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ResponseStatus {
Accepted,
Completed,
Failed,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum InteractionContent {
Message { body: String },
Request { intent: String, params: Value },
Response {
in_reply_to: InteractionId,
status: ResponseStatus,
result: Value,
},
}
#[derive(Debug, Clone)]
pub struct InboxInteraction {
pub id: InteractionId,
pub from: String,
pub content: InteractionContent,
pub rendered_text: String,
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
#[test]
fn interaction_id_json_roundtrip() {
let id = InteractionId(Uuid::new_v4());
let json = serde_json::to_string(&id).unwrap();
let parsed: InteractionId = serde_json::from_str(&json).unwrap();
assert_eq!(id, parsed);
}
#[test]
fn interaction_content_message_json_roundtrip() {
let content = InteractionContent::Message {
body: "hello".to_string(),
};
let json = serde_json::to_value(&content).unwrap();
assert_eq!(json["type"], "message");
let parsed: InteractionContent = serde_json::from_value(json).unwrap();
assert_eq!(content, parsed);
}
#[test]
fn interaction_content_request_json_roundtrip() {
let content = InteractionContent::Request {
intent: "review".to_string(),
params: serde_json::json!({"pr": 42}),
};
let json = serde_json::to_value(&content).unwrap();
assert_eq!(json["type"], "request");
let parsed: InteractionContent = serde_json::from_value(json).unwrap();
assert_eq!(content, parsed);
}
#[test]
fn interaction_content_response_json_roundtrip() {
let id = InteractionId(Uuid::new_v4());
let content = InteractionContent::Response {
in_reply_to: id,
status: ResponseStatus::Completed,
result: serde_json::json!({"ok": true}),
};
let json = serde_json::to_value(&content).unwrap();
assert_eq!(json["type"], "response");
assert_eq!(json["status"], "completed");
let parsed: InteractionContent = serde_json::from_value(json).unwrap();
assert_eq!(content, parsed);
}
#[test]
fn response_status_json_roundtrip_all_variants() {
for (variant, expected_str) in [
(ResponseStatus::Accepted, "accepted"),
(ResponseStatus::Completed, "completed"),
(ResponseStatus::Failed, "failed"),
] {
let json = serde_json::to_value(variant).unwrap();
assert_eq!(json, expected_str);
let parsed: ResponseStatus = serde_json::from_value(json).unwrap();
assert_eq!(variant, parsed);
}
}
}