kanidm_proto/messages.rs
1// User-facing output things
2
3use std::fmt;
4use std::str::FromStr;
5
6use serde::{Deserialize, Serialize};
7
8/// This is used in user-facing CLIs to set the formatting for output,
9/// and defaults to text.
10#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default)]
11#[serde(rename_all = "lowercase")]
12pub enum ConsoleOutputMode {
13 #[default]
14 Text,
15 JSON,
16}
17
18impl FromStr for ConsoleOutputMode {
19 type Err = &'static str;
20
21 /// This can be safely unwrap'd because it'll always return a default of text
22 /// ```
23 /// use kanidm_proto::messages::ConsoleOutputMode;
24 ///
25 /// let mode: ConsoleOutputMode = "🦀".into();
26 /// assert_eq!(ConsoleOutputMode::Text, mode);
27 /// let mode: ConsoleOutputMode = "".into();
28 /// assert_eq!(ConsoleOutputMode::Text, mode);
29 ///
30 /// let mode: ConsoleOutputMode = "json".into();
31 /// assert_eq!(ConsoleOutputMode::JSON, mode);
32 /// ```
33 fn from_str(s: &str) -> Result<Self, Self::Err> {
34 match s {
35 "json" => Ok(ConsoleOutputMode::JSON),
36 "text" => Ok(ConsoleOutputMode::Text),
37 _ => {
38 eprintln!("Supplied output mode ({s:?}) was invalid, defaulting to text");
39 Ok(ConsoleOutputMode::Text)
40 }
41 }
42 }
43}
44
45/// This will take any string, if it's 'text' or 'json' then you'll get
46/// what you asked for, else you'll get a text version.
47///
48/// ```
49/// use kanidm_proto::messages::ConsoleOutputMode;
50/// let bork = "text";
51/// let com: ConsoleOutputMode = bork.into();
52/// matches!(ConsoleOutputMode::Text, com);
53/// ```
54impl From<&str> for ConsoleOutputMode {
55 fn from(input: &str) -> Self {
56 match ConsoleOutputMode::from_str(input) {
57 Ok(val) => val,
58 Err(_) => Self::Text,
59 }
60 }
61}
62
63/// This will take any string, if it's 'text' or 'json' then you'll get
64/// what you asked for, else you'll get a text version.
65///
66/// ```
67/// use kanidm_proto::messages::ConsoleOutputMode;
68/// let bork = String::from("cr4bz");
69/// let com: ConsoleOutputMode = bork.into();
70/// matches!(ConsoleOutputMode::Text, com);
71/// ```
72impl From<String> for ConsoleOutputMode {
73 fn from(input: String) -> Self {
74 match ConsoleOutputMode::from_str(input.as_str()) {
75 Ok(val) => val,
76 Err(_) => Self::Text,
77 }
78 }
79}
80
81#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
82#[serde(rename_all = "lowercase")]
83pub enum MessageStatus {
84 Failure,
85 Success,
86}
87
88impl fmt::Display for MessageStatus {
89 fn fmt(&self, f: &mut fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
90 match *self {
91 MessageStatus::Failure => f.write_str("failure"),
92 MessageStatus::Success => f.write_str("success"),
93 }
94 }
95}
96
97#[derive(Debug, Serialize, Deserialize)]
98pub struct AccountChangeMessage {
99 #[serde(skip_serializing)]
100 pub output_mode: ConsoleOutputMode,
101 pub action: String,
102 pub result: String,
103 pub status: MessageStatus,
104 pub src_user: String,
105 pub dest_user: String,
106}
107
108impl Default for AccountChangeMessage {
109 fn default() -> Self {
110 AccountChangeMessage {
111 output_mode: ConsoleOutputMode::Text,
112 action: String::from(""),
113 result: String::from(""),
114 status: MessageStatus::Success,
115 src_user: String::from(""),
116 dest_user: String::from(""),
117 }
118 }
119}
120
121/// This outputs in either JSON or Text depending on the output_mode setting
122/// ```
123/// use std::fmt::format;
124/// use kanidm_proto::messages::*;
125/// let mut msg = AccountChangeMessage::default();
126/// msg.action=String::from("cake_eating");
127/// msg.src_user=String::from("Kani");
128/// msg.dest_user=String::from("Krabby");
129/// msg.result=String::from("It was amazing");
130/// assert_eq!(msg.status, MessageStatus::Success);
131///
132/// let expected_result = "success - cake_eating for Krabby: It was amazing";
133/// assert_eq!(format!("{}", msg), expected_result);
134///
135/// msg.output_mode = ConsoleOutputMode::JSON;
136/// let expected_result = "{\"action\":\"cake_eating\",\"result\":\"It was amazing\",\"status\":\"success\",\"src_user\":\"Kani\",\"dest_user\":\"Krabby\"}";
137/// assert_eq!(format!("{}", msg), expected_result);
138/// ```
139impl fmt::Display for AccountChangeMessage {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self.output_mode {
142 ConsoleOutputMode::JSON => write!(
143 f,
144 "{}",
145 serde_json::to_string(self).unwrap_or(format!("{self:?}")) /* if it fails to JSON serialize, just debug-dump it */
146 ),
147 ConsoleOutputMode::Text => write!(
148 f,
149 "{} - {} for {}: {}",
150 self.status, self.action, self.dest_user, self.result,
151 ),
152 }
153 }
154}
155
156#[derive(Debug, Serialize, Deserialize)]
157pub struct BasicMessage {
158 #[serde(skip_serializing)]
159 pub output_mode: ConsoleOutputMode,
160 pub action: String,
161 pub result: String,
162 pub status: MessageStatus,
163}
164
165impl Default for BasicMessage {
166 fn default() -> Self {
167 BasicMessage {
168 output_mode: ConsoleOutputMode::Text,
169 action: String::from(""),
170 result: String::from(""),
171 status: MessageStatus::Success,
172 }
173 }
174}
175
176/// This outputs in either JSON or Text depending on the output_mode setting
177/// ```
178/// use kanidm_proto::messages::*;
179/// use std::fmt::format;
180/// let mut msg = BasicMessage::default();
181/// msg.action = String::from("cake_eating");
182/// msg.result = String::from("It was amazing");
183/// assert_eq!(msg.status, MessageStatus::Success);
184///
185/// let expected_result = "success - cake_eating: It was amazing";
186/// assert_eq!(format!("{}", msg), expected_result);
187///
188/// msg.output_mode = ConsoleOutputMode::JSON;
189/// let expected_result =
190/// "{\"action\":\"cake_eating\",\"result\":\"It was amazing\",\"status\":\"success\"}";
191/// assert_eq!(format!("{}", msg), expected_result);
192/// ```
193impl fmt::Display for BasicMessage {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 match self.output_mode {
196 ConsoleOutputMode::JSON => write!(
197 f,
198 "{}",
199 serde_json::to_string(self).unwrap_or(format!("{self:?}")) /* if it fails to JSON serialize, just debug-dump it */
200 ),
201 ConsoleOutputMode::Text => {
202 write!(f, "{} - {}: {}", self.status, self.action, self.result,)
203 }
204 }
205 }
206}