diff --git a/src/bot/command_execution.rs b/src/bot/command_execution.rs
index 528d664..1c72d1c 100644
--- a/src/bot/command_execution.rs
+++ b/src/bot/command_execution.rs
@@ -18,7 +18,45 @@ pub(super) async fn handle_single_result(
event_id: EventId,
) {
let html = cmd_result.message_html(respond_to);
- matrix::send_message(client, room.room_id(), &html, Some(event_id)).await;
+ let plain = cmd_result.message_plain(respond_to);
+ matrix::send_message(client, room.room_id(), (&html, &plain), Some(event_id)).await;
+}
+
+/// Format failure messages nicely in either HTML or plain text. If
+/// plain is true, plain-text will be returned. Otherwise, formatted
+/// HTML.
+fn format_failures(
+ errors: &[(&str, &BotError)],
+ commands_executed: usize,
+ respond_to: &str,
+ plain: bool,
+) -> String {
+ let respond_to = match plain {
+ true => respond_to.to_owned(),
+ false => format!(
+ "{}",
+ respond_to, respond_to
+ ),
+ };
+
+ let failures: Vec = errors
+ .iter()
+ .map(|&(cmd, err)| format!("{}: {}", cmd, err))
+ .collect();
+
+ let message = format!(
+ "{}: Executed {} commands ({} failed)\n\nFailures:\n{}",
+ respond_to,
+ commands_executed,
+ errors.len(),
+ failures.join("\n")
+ )
+ .replace("\n", "
");
+
+ match plain {
+ true => html2text::from_read(message.as_bytes(), message.len()),
+ false => message,
+ }
}
/// Handle responding to multiple commands being executed. Will print
@@ -29,7 +67,7 @@ pub(super) async fn handle_multiple_results(
respond_to: &str,
room: &Joined,
) {
- let respond_to = format!(
+ let user_pill = format!(
"{}",
respond_to, respond_to
);
@@ -42,25 +80,19 @@ pub(super) async fn handle_multiple_results(
})
.collect();
- let message = if errors.len() == 0 {
- format!("{}: Executed {} commands", respond_to, results.len())
- } else {
- let failures: Vec = errors
- .iter()
- .map(|&(cmd, err)| format!("{}: {}", cmd, err))
- .collect();
-
- format!(
- "{}: Executed {} commands ({} failed)\n\nFailures:\n{}",
- respond_to,
- results.len(),
- errors.len(),
- failures.join("\n")
+ let (message, plain) = if errors.len() == 0 {
+ (
+ format!("{}: Executed {} commands", user_pill, results.len()),
+ format!("{}: Executed {} commands", respond_to, results.len()),
+ )
+ } else {
+ (
+ format_failures(&errors, results.len(), respond_to, false),
+ format_failures(&errors, results.len(), respond_to, true),
)
- .replace("\n", "
")
};
- matrix::send_message(client, room.room_id(), &message, None).await;
+ matrix::send_message(client, room.room_id(), (&message, &plain), None).await;
}
/// Create a context for command execution. Can fai if the room
diff --git a/src/commands/mod.rs b/src/commands/mod.rs
index 2f81af2..35ebce8 100644
--- a/src/commands/mod.rs
+++ b/src/commands/mod.rs
@@ -55,6 +55,8 @@ pub trait ResponseExtractor {
/// HTML representation of the message, directly mentioning the
/// username.
fn message_html(&self, username: &str) -> String;
+
+ fn message_plain(&self, username: &str) -> String;
}
impl ResponseExtractor for ExecutionResult {
@@ -68,12 +70,23 @@ impl ResponseExtractor for ExecutionResult {
);
match self {
- Ok(resp) => format!("{}
{}
", username, resp.html).replace("\n", "
"),
- Err(e) => {
- format!("{}
{}
", username, e).replace("\n", "
")
- }
+ Ok(resp) => format!("{}
", resp.html).replace("\n", "
"),
+ Err(e) => format!("{}: {}
", username, e).replace("\n", "
"),
}
}
+
+ fn message_plain(&self, username: &str) -> String {
+ let message = match self {
+ Ok(resp) => format!("{}", resp.html),
+ Err(e) => format!("{}", e),
+ };
+
+ format!(
+ "{}:\n{}",
+ username,
+ html2text::from_read(message.as_bytes(), message.len())
+ )
+ }
}
/// The trait that any command that can be executed must implement.
@@ -256,15 +269,6 @@ mod tests {
assert_eq!(execution_allowed(&cmd, &ctx).is_err(), true);
}
- #[test]
- fn command_result_extractor_creates_bubble() {
- let result = Execution::success("test".to_string());
- let message = result.message_html("@myuser:example.com");
- assert!(message.contains(
- "@myuser:example.com"
- ));
- }
-
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn unrecognized_command() {
let db_path = tempfile::NamedTempFile::new_in(".").unwrap();
diff --git a/src/matrix.rs b/src/matrix.rs
index 5c9f6a8..7bec296 100644
--- a/src/matrix.rs
+++ b/src/matrix.rs
@@ -61,20 +61,22 @@ pub async fn get_rooms_for_user(
Ok(rooms_for_user)
}
+/// Send a message. The message is a tuple of HTML and plain text
+/// responses.
pub async fn send_message(
client: &Client,
room_id: &RoomId,
- message: &str,
+ message: (&str, &str),
reply_to: Option,
) {
+ let (html, plain) = message;
let room = match client.get_joined_room(room_id) {
Some(room) => room,
_ => return,
};
- let plain = html2text::from_read(message.as_bytes(), message.len());
let mut content = MessageEventContent::new(MessageType::Notice(
- NoticeMessageEventContent::html(plain.trim(), message),
+ NoticeMessageEventContent::html(plain.trim(), html),
));
content.relates_to = reply_to.map(|event_id| Relation::Reply {
@@ -86,7 +88,7 @@ pub async fn send_message(
let result = room.send(content, None).await;
if let Err(e) = result {
- let message = extract_error_message(e);
- error!("Error sending message: {}", message);
+ let html = extract_error_message(e);
+ error!("Error sending html: {}", html);
};
}