agent_office/services/mail/
domain.rs1use crate::domain::{string_to_node_id, Node, NodeId, Properties, PropertyValue, Timestamp};
2use chrono::Utc;
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6pub type MailboxId = NodeId;
8pub type MailId = NodeId;
9pub type AgentId = String;
10
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12pub struct Mailbox {
13 pub id: MailboxId,
14 pub owner_id: AgentId,
15 pub name: String,
16 pub created_at: Timestamp,
17}
18
19impl Mailbox {}
20
21#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
22pub struct Mail {
23 pub id: MailId,
24 pub from_mailbox_id: MailboxId,
25 pub to_mailbox_id: MailboxId,
26 pub subject: String,
27 pub body: String,
28 pub read: bool,
29 pub created_at: Timestamp,
30}
31
32impl Mail {
33 pub fn new(
34 from_mailbox_id: MailboxId,
35 to_mailbox_id: MailboxId,
36 subject: impl Into<String>,
37 body: impl Into<String>,
38 ) -> Self {
39 Self {
40 id: MailId::new_v4(),
41 from_mailbox_id,
42 to_mailbox_id,
43 subject: subject.into(),
44 body: body.into(),
45 read: false,
46 created_at: Utc::now(),
47 }
48 }
49
50 pub fn to_node(&self) -> Node {
51 let mut props = Properties::new();
52 props.insert(
53 "from_mailbox_id".to_string(),
54 PropertyValue::String(self.from_mailbox_id.to_string()),
55 );
56 props.insert(
57 "to_mailbox_id".to_string(),
58 PropertyValue::String(self.to_mailbox_id.to_string()),
59 );
60 props.insert(
61 "subject".to_string(),
62 PropertyValue::String(self.subject.clone()),
63 );
64 props.insert("body".to_string(), PropertyValue::String(self.body.clone()));
65 props.insert("read".to_string(), PropertyValue::Boolean(self.read));
66
67 let mut node = Node::new("mail", props);
68 node.id = self.id;
69 node
70 }
71
72 pub fn from_node(node: &Node) -> Option<Self> {
73 if node.node_type != "mail" {
74 return None;
75 }
76
77 let from_mailbox_id = node.get_property("from_mailbox_id").and_then(|v| match v {
78 PropertyValue::String(s) => Uuid::parse_str(s).ok(),
79 _ => None,
80 })?;
81
82 let to_mailbox_id = node.get_property("to_mailbox_id").and_then(|v| match v {
83 PropertyValue::String(s) => Uuid::parse_str(s).ok(),
84 _ => None,
85 })?;
86
87 let subject = node.get_property("subject").and_then(|v| match v {
88 PropertyValue::String(s) => Some(s.clone()),
89 _ => None,
90 })?;
91
92 let body = node.get_property("body").and_then(|v| match v {
93 PropertyValue::String(s) => Some(s.clone()),
94 _ => None,
95 })?;
96
97 let read = node
98 .get_property("read")
99 .and_then(|v| match v {
100 PropertyValue::Boolean(b) => Some(*b),
101 _ => None,
102 })
103 .unwrap_or(false);
104
105 Some(Self {
106 id: node.id,
107 from_mailbox_id,
108 to_mailbox_id,
109 subject,
110 body,
111 read,
112 created_at: node.created_at,
113 })
114 }
115
116 pub fn mark_as_read(&mut self) {
117 self.read = true;
118 }
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct Agent {
123 pub id: AgentId,
124 pub name: String,
125 pub status: String,
126 pub created_at: Timestamp,
127}
128
129impl Default for Agent {
130 fn default() -> Self {
131 let name = String::from("Unnamed");
132 Self {
133 id: name.clone(),
134 name,
135 status: String::from("offline"),
136 created_at: Utc::now(),
137 }
138 }
139}
140
141impl Agent {
142 pub fn new(name: impl Into<String>) -> Self {
143 let name = name.into();
144 let id = if name.contains(char::is_whitespace) || name.is_empty() {
147 format!(
148 "agent_{}",
149 uuid::Uuid::new_v4().to_string().split('-').next().unwrap()
150 )
151 } else {
152 name.clone()
153 };
154
155 Self {
156 id,
157 name,
158 status: String::from("offline"),
159 created_at: Utc::now(),
160 }
161 }
162
163 pub fn to_node(&self) -> Node {
164 let mut props = Properties::new();
165 props.insert("name".to_string(), PropertyValue::String(self.name.clone()));
166 props.insert(
167 "agent_id".to_string(),
168 PropertyValue::String(self.id.clone()),
169 );
170 props.insert(
171 "status".to_string(),
172 PropertyValue::String(self.status.clone()),
173 );
174
175 let mut node = Node::new("agent", props);
176 node.id = string_to_node_id(&self.id);
178 node
179 }
180
181 pub fn from_node(node: &Node) -> Option<Self> {
182 if node.node_type != "agent" {
183 return None;
184 }
185
186 let name = node.get_property("name").and_then(|v| match v {
187 PropertyValue::String(s) => Some(s.clone()),
188 _ => None,
189 })?;
190
191 let id = node
193 .get_property("agent_id")
194 .and_then(|v| match v {
195 PropertyValue::String(s) => Some(s.clone()),
196 _ => None,
197 })
198 .unwrap_or_else(|| node.id.to_string());
199
200 let status = node
202 .get_property("status")
203 .and_then(|v| match v {
204 PropertyValue::String(s) => Some(s.clone()),
205 _ => None,
206 })
207 .unwrap_or_else(|| String::from("offline"));
208
209 Some(Self {
210 id,
211 name,
212 status,
213 created_at: node.created_at,
214 })
215 }
216}