gatewayd: the texts that say who asked for a redirected approval
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
@@ -173,3 +173,52 @@ pub fn ended_line(ended: &Ended) -> String {
|
||||
pub fn with_ending(last: &str, ended: &Ended) -> String {
|
||||
format!("{last}\n\n{}", ended_line(ended))
|
||||
}
|
||||
|
||||
/// The most characters of an asker's message shown to the approver: it is context, not what is
|
||||
/// approved, so it may be cut.
|
||||
pub const PROMPT_SHOWN: usize = 2_000;
|
||||
|
||||
/// Who asked for an approval that is shown elsewhere (M4b spec, section 6).
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Asked {
|
||||
/// `@username`, or the user id when the name could not be found.
|
||||
pub by: String,
|
||||
/// The channel's type: `D` a direct message, `G` a group message.
|
||||
pub channel_type: String,
|
||||
/// The text of the turn that asked.
|
||||
pub prompt: String,
|
||||
}
|
||||
|
||||
/// The first post of a redirected approval: who asked, where, and their message.
|
||||
pub fn asked_post(id: u64, asked: &Asked) -> String {
|
||||
let place = if asked.channel_type == "G" {
|
||||
"a group message"
|
||||
} else {
|
||||
"a direct message"
|
||||
};
|
||||
let escaped = proto::escape::escape_model_text(&asked.prompt);
|
||||
let total = escaped.chars().count();
|
||||
let shown: String = escaped.chars().take(PROMPT_SHOWN).collect();
|
||||
let mut post = format!(
|
||||
"**Approval {id}** was asked by {} in {place} with the bot. Their message:\n{}",
|
||||
asked.by,
|
||||
fence(&shown)
|
||||
);
|
||||
if total > PROMPT_SHOWN {
|
||||
post.push_str(&format!("\n(… {} more characters)", total - PROMPT_SHOWN));
|
||||
}
|
||||
post
|
||||
}
|
||||
|
||||
/// The first post of an approval whose session `gatewayd` does not follow.
|
||||
pub fn unfollowed_post(id: u64, session: &str) -> String {
|
||||
format!(
|
||||
"**Approval {id}** was asked in session {}, which gatewayd does not follow now (a restart, or a session from outside Mattermost).",
|
||||
code(session)
|
||||
)
|
||||
}
|
||||
|
||||
/// The line left in the asking thread when its approval goes to an approver.
|
||||
pub fn sent_to_approver(id: u64) -> String {
|
||||
format!("waiting for approval {id}: it was sent to an approver")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
//! The posts that tell an approver who asked for a redirected approval and what, and the line left
|
||||
//! in the asking thread (M4b spec, section 6, after the review). Do not edit.
|
||||
|
||||
use gatewayd::approvals::text::{
|
||||
Asked, PROMPT_SHOWN, asked_post, sent_to_approver, unfollowed_post,
|
||||
};
|
||||
|
||||
/// The escape for one code point, built here so this file holds no such character itself.
|
||||
fn esc(code: u32) -> String {
|
||||
format!("{}u{code:04x}", char::from(92))
|
||||
}
|
||||
|
||||
fn asked(prompt: &str, channel_type: &str) -> Asked {
|
||||
Asked {
|
||||
by: "@alex".to_string(),
|
||||
channel_type: channel_type.to_string(),
|
||||
prompt: prompt.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn who_where_and_what_they_asked() {
|
||||
assert_eq!(
|
||||
asked_post(
|
||||
3,
|
||||
&asked("Read the file /srv/notes/q3.txt and summarise it.", "D")
|
||||
),
|
||||
"**Approval 3** was asked by @alex in a direct message with the bot. Their message:\n```\nRead the file /srv/notes/q3.txt and summarise it.\n```"
|
||||
);
|
||||
let group = asked_post(4, &asked("first\n\nsecond", "G"));
|
||||
assert_eq!(
|
||||
group,
|
||||
"**Approval 4** was asked by @alex in a group message with the bot. Their message:\n```\nfirst\n\nsecond\n```",
|
||||
"a burst keeps its lines"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_message_is_escaped_and_fenced() {
|
||||
let hostile = format!(
|
||||
"see ``` and @channel{}{}",
|
||||
char::from_u32(0x202e).unwrap(),
|
||||
char::from(7)
|
||||
);
|
||||
let post = asked_post(5, &asked(&hostile, "D"));
|
||||
assert!(
|
||||
post.contains(&format!(
|
||||
"\n````\nsee ``` and @channel{}{}\n````",
|
||||
esc(0x202e),
|
||||
esc(7)
|
||||
)),
|
||||
"{post}"
|
||||
);
|
||||
assert!(!post.contains(char::from_u32(0x202e).unwrap()) && !post.contains(char::from(7)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_long_message_is_cut_and_says_how_much() {
|
||||
let long = "é".repeat(PROMPT_SHOWN + 25);
|
||||
let post = asked_post(6, &asked(&long, "D"));
|
||||
assert!(
|
||||
post.ends_with(&format!(
|
||||
"\n```\n{}\n```\n(… 25 more characters)",
|
||||
"é".repeat(PROMPT_SHOWN)
|
||||
)),
|
||||
"{}",
|
||||
&post[post.len() - 80..]
|
||||
);
|
||||
let exact = asked_post(6, &asked(&"x".repeat(PROMPT_SHOWN), "D"));
|
||||
assert!(
|
||||
!exact.contains("more characters"),
|
||||
"nothing cut, nothing said"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_unfollowed_session_and_the_note() {
|
||||
assert_eq!(
|
||||
unfollowed_post(9, "chat-1789700000-1"),
|
||||
"**Approval 9** was asked in session `chat-1789700000-1`, which gatewayd does not follow now (a restart, or a session from outside Mattermost)."
|
||||
);
|
||||
assert_eq!(
|
||||
sent_to_approver(3),
|
||||
"waiting for approval 3: it was sent to an approver"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user