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