|
|
|
use once_cell::sync::Lazy;
|
|
|
|
use regex::Regex;
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub enum StatusCommand {
|
|
|
|
/// Ignore this post
|
|
|
|
Ignore,
|
|
|
|
/// Boost the previous post in the thread
|
|
|
|
Boost,
|
|
|
|
/// Un-reblog parent post, or delete an announcement
|
|
|
|
Undo,
|
|
|
|
/// Admin: Ban a user
|
|
|
|
BanUser(String),
|
|
|
|
/// Admin: Un-ban a server
|
|
|
|
UnbanUser(String),
|
|
|
|
/// Admin: Ban a server
|
|
|
|
BanServer(String),
|
|
|
|
/// Admin: Un-ban a server
|
|
|
|
UnbanServer(String),
|
|
|
|
/// Admin: Add a member to a closed group (or force join)
|
|
|
|
AddMember(String),
|
|
|
|
/// Admin: Remove a user from the group, also unfollow
|
|
|
|
RemoveMember(String),
|
|
|
|
/// Admin: Add a hashtag to the group
|
|
|
|
AddTag(String),
|
|
|
|
/// Admin: Remove a hashtag from the group
|
|
|
|
RemoveTag(String),
|
|
|
|
/// Admin: Give admin to a user
|
|
|
|
GrantAdmin(String),
|
|
|
|
/// Admin: Revoke admin to a user
|
|
|
|
RemoveAdmin(String),
|
|
|
|
/// Admin: Send a public announcement
|
|
|
|
Announce(String),
|
|
|
|
/// Admin: Make the group open-access
|
|
|
|
OpenGroup,
|
|
|
|
/// Admin: Make the group member-only, this effectively disables posting from non-members
|
|
|
|
/// and disables /join and follow-back
|
|
|
|
CloseGroup,
|
|
|
|
/// Show help. The content varies by group params (open/closed access), the user's privileges
|
|
|
|
/// and membership status.
|
|
|
|
Help,
|
|
|
|
/// Show members. Non-admins will only see a list of admins.
|
|
|
|
ListMembers,
|
|
|
|
/// Show tags.
|
|
|
|
ListTags,
|
|
|
|
/// Leave the group, this asks the group to unfollow the user and also revokes their membership.
|
|
|
|
Leave,
|
|
|
|
/// Join a public group. This is normally not needed, as the group follows back and adds followers as members.
|
|
|
|
/// Manual join is useful when the follow somehow fails, or when the user wants to be able to
|
|
|
|
/// post without receiving the group's posts (naughty!)
|
|
|
|
///
|
|
|
|
/// In member-only groups, this will just DM the user some info on how to get added.
|
|
|
|
Join,
|
|
|
|
/// The group will DM "Pong" back, this is to test that the daemon is running and also that the
|
|
|
|
/// user is not banned and federates.
|
|
|
|
Ping,
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! p_user {
|
|
|
|
() => {
|
|
|
|
r"(@?[a-zA-Z0-9_.-]+@[a-zA-Z0-9_.-]+\.[a-z0-9_-]+|@[a-zA-Z0-9_.-]+)"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! p_server {
|
|
|
|
() => {
|
|
|
|
r"([a-zA-Z0-9_.-]+\.[a-zA-Z0-9_-]+)"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! p_hashtag {
|
|
|
|
() => {
|
|
|
|
r"#(\w+)"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! command {
|
|
|
|
($($val:expr),+) => {
|
|
|
|
Regex::new(concat!(r"(?:^|\s|>|\n)[\\/]", $($val,)+ r"(?:$|[!,]|\W)")).unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static RE_BOOST: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"b(?:oost)?"));
|
|
|
|
|
|
|
|
static RE_UNDO: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:delete|undo)"));
|
|
|
|
|
|
|
|
static RE_IGNORE: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"i(?:g(?:n(?:ore)?)?)?"));
|
|
|
|
|
|
|
|
static RE_BAN_USER: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"ban\s+", p_user!()));
|
|
|
|
|
|
|
|
static RE_UNBAN_USER: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"unban\s+", p_user!()));
|
|
|
|
|
|
|
|
static RE_BAN_SERVER: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"ban\s+", p_server!()));
|
|
|
|
|
|
|
|
static RE_UNBAN_SERVER: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"unban\s+", p_server!()));
|
|
|
|
|
|
|
|
static RE_ADD_MEMBER: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:add|follow)\s+", p_user!()));
|
|
|
|
|
|
|
|
static RE_REMOVE_MEMBER: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:kick|unfollow|remove)\s+", p_user!()));
|
|
|
|
|
|
|
|
static RE_ADD_TAG: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:add|follow)\s+", p_hashtag!()));
|
|
|
|
|
|
|
|
static RE_REMOVE_TAG: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:remove|unfollow)\s+", p_hashtag!()));
|
|
|
|
|
|
|
|
static RE_GRANT_ADMIN: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:op|admin)\s+", p_user!()));
|
|
|
|
|
|
|
|
static RE_REVOKE_ADMIN: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:deop|deadmin)\s+", p_user!()));
|
|
|
|
|
|
|
|
static RE_OPEN_GROUP: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"opengroup"));
|
|
|
|
|
|
|
|
static RE_CLOSE_GROUP: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"closegroup"));
|
|
|
|
|
|
|
|
static RE_HELP: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"help"));
|
|
|
|
|
|
|
|
static RE_MEMBERS: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:members|who|admins)"));
|
|
|
|
|
|
|
|
static RE_TAGS: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"(?:hashtags|tags)"));
|
|
|
|
|
|
|
|
static RE_LEAVE: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"leave"));
|
|
|
|
|
|
|
|
static RE_JOIN: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"join"));
|
|
|
|
|
|
|
|
static RE_PING: once_cell::sync::Lazy<Regex> = Lazy::new(|| command!(r"ping"));
|
|
|
|
|
|
|
|
static RE_ANNOUNCE: once_cell::sync::Lazy<Regex> =
|
|
|
|
Lazy::new(|| Regex::new(r"(?:^|\s|>|\n)[\\/]announce\s+(.*)$").unwrap());
|
|
|
|
|
|
|
|
static RE_A_HASHTAG: once_cell::sync::Lazy<Regex> =
|
|
|
|
Lazy::new(|| Regex::new(r"(?:^|\b|\s|>|\n)#(\w+)").unwrap());
|
|
|
|
|
|
|
|
pub static RE_HASHTAG_TRIGGERING_PLEROMA_BUG: once_cell::sync::Lazy<Regex> =
|
|
|
|
Lazy::new(|| Regex::new(r"(?:^|\b|\s|>|\n)#\w+[^\s]*$").unwrap());
|
|
|
|
|
|
|
|
pub fn parse_status_tags(content: &str) -> Vec<String> {
|
|
|
|
debug!("Raw content: {}", content);
|
|
|
|
let content = content.replace("<br/>", "<br/> ");
|
|
|
|
let content = content.replace("</p>", "</p> ");
|
|
|
|
let content = voca_rs::strip::strip_tags(&content);
|
|
|
|
debug!("Stripped tags: {}", content);
|
|
|
|
|
|
|
|
let mut tags = vec![];
|
|
|
|
for c in RE_A_HASHTAG.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
tags.push(s.as_str().to_lowercase())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
tags
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn parse_slash_commands(content: &str) -> Vec<StatusCommand> {
|
|
|
|
debug!("Raw content: {}", content);
|
|
|
|
|
|
|
|
let content = content.replace("<br/>", "<br/> ");
|
|
|
|
let content = content.replace("</p>", "</p> ");
|
|
|
|
|
|
|
|
let content = voca_rs::strip::strip_tags(&content);
|
|
|
|
debug!("Stripped tags: {}", content);
|
|
|
|
|
|
|
|
if !content.contains('/') && !content.contains('\\') {
|
|
|
|
// No slash = no command
|
|
|
|
return vec![];
|
|
|
|
}
|
|
|
|
|
|
|
|
// short-circuiting commands
|
|
|
|
|
|
|
|
if RE_IGNORE.is_match(&content) {
|
|
|
|
debug!("IGNORE");
|
|
|
|
return vec![StatusCommand::Ignore];
|
|
|
|
}
|
|
|
|
|
|
|
|
if RE_HELP.is_match(&content) {
|
|
|
|
debug!("HELP");
|
|
|
|
return vec![StatusCommand::Help];
|
|
|
|
}
|
|
|
|
|
|
|
|
if RE_UNDO.is_match(&content) {
|
|
|
|
debug!("UNDO");
|
|
|
|
return vec![StatusCommand::Undo];
|
|
|
|
}
|
|
|
|
|
|
|
|
// additive commands
|
|
|
|
|
|
|
|
let mut commands = vec![];
|
|
|
|
|
|
|
|
// one-use commands
|
|
|
|
|
|
|
|
if RE_BOOST.is_match(&content) {
|
|
|
|
debug!("BOOST");
|
|
|
|
commands.push(StatusCommand::Boost);
|
|
|
|
}
|
|
|
|
|
|
|
|
if RE_LEAVE.is_match(&content) {
|
|
|
|
debug!("LEAVE");
|
|
|
|
commands.push(StatusCommand::Leave);
|
|
|
|
} else if RE_JOIN.is_match(&content) {
|
|
|
|
debug!("JOIN");
|
|
|
|
commands.push(StatusCommand::Join);
|
|
|
|
}
|
|
|
|
|
|
|
|
if RE_PING.is_match(&content) {
|
|
|
|
debug!("PING");
|
|
|
|
commands.push(StatusCommand::Ping);
|
|
|
|
}
|
|
|
|
|
|
|
|
if RE_MEMBERS.is_match(&content) {
|
|
|
|
debug!("MEMBERS");
|
|
|
|
commands.push(StatusCommand::ListMembers);
|
|
|
|
}
|
|
|
|
|
|
|
|
if RE_TAGS.is_match(&content) {
|
|
|
|
debug!("TAGS");
|
|
|
|
commands.push(StatusCommand::ListTags);
|
|
|
|
}
|
|
|
|
|
|
|
|
if RE_OPEN_GROUP.is_match(&content) {
|
|
|
|
debug!("OPEN GROUP");
|
|
|
|
commands.push(StatusCommand::OpenGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
if RE_CLOSE_GROUP.is_match(&content) {
|
|
|
|
debug!("CLOSE GROUP");
|
|
|
|
commands.push(StatusCommand::CloseGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(c) = RE_ANNOUNCE.captures(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str().trim();
|
|
|
|
debug!("ANNOUNCE: «{}»", s);
|
|
|
|
commands.push(StatusCommand::Announce(s.to_owned()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// multi-occurence commands
|
|
|
|
|
|
|
|
for c in RE_BAN_USER.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str();
|
|
|
|
let s = s.trim_start_matches('@');
|
|
|
|
debug!("BAN USER: {}", s);
|
|
|
|
commands.push(StatusCommand::BanUser(s.to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_UNBAN_USER.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str();
|
|
|
|
let s = s.trim_start_matches('@');
|
|
|
|
debug!("UNBAN USER: {}", s);
|
|
|
|
commands.push(StatusCommand::UnbanUser(s.to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_BAN_SERVER.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
debug!("BAN SERVER: {}", s.as_str());
|
|
|
|
commands.push(StatusCommand::BanServer(s.as_str().to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_UNBAN_SERVER.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
debug!("UNBAN SERVER: {}", s.as_str());
|
|
|
|
commands.push(StatusCommand::UnbanServer(s.as_str().to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_ADD_MEMBER.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str();
|
|
|
|
let s = s.trim_start_matches('@');
|
|
|
|
debug!("ADD MEMBER: {}", s);
|
|
|
|
commands.push(StatusCommand::AddMember(s.to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_REMOVE_MEMBER.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str();
|
|
|
|
let s = s.trim_start_matches('@');
|
|
|
|
debug!("REMOVE USER: {}", s);
|
|
|
|
commands.push(StatusCommand::RemoveMember(s.to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_ADD_TAG.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str();
|
|
|
|
debug!("ADD TAG: {}", s);
|
|
|
|
commands.push(StatusCommand::AddTag(s.to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_REMOVE_TAG.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str();
|
|
|
|
debug!("REMOVE TAG: {}", s);
|
|
|
|
commands.push(StatusCommand::RemoveTag(s.to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_GRANT_ADMIN.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str();
|
|
|
|
let s = s.trim_start_matches('@');
|
|
|
|
debug!("ADD ADMIN: {}", s);
|
|
|
|
commands.push(StatusCommand::GrantAdmin(s.to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for c in RE_REVOKE_ADMIN.captures_iter(&content) {
|
|
|
|
if let Some(s) = c.get(1) {
|
|
|
|
let s = s.as_str();
|
|
|
|
let s = s.trim_start_matches('@');
|
|
|
|
debug!("REMOVE ADMIN: {}", s);
|
|
|
|
commands.push(StatusCommand::RemoveAdmin(s.to_lowercase()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commands
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use crate::command::{parse_slash_commands, RE_A_HASHTAG, RE_HASHTAG_TRIGGERING_PLEROMA_BUG, RE_ADD_TAG, RE_JOIN, StatusCommand};
|
|
|
|
|
|
|
|
use super::{
|
|
|
|
RE_ADD_MEMBER, RE_ANNOUNCE, RE_BAN_SERVER, RE_BAN_USER, RE_BOOST, RE_CLOSE_GROUP, RE_GRANT_ADMIN, RE_HELP,
|
|
|
|
RE_IGNORE, RE_LEAVE, RE_MEMBERS, RE_OPEN_GROUP, RE_REMOVE_MEMBER, RE_REVOKE_ADMIN, RE_TAGS, RE_UNDO,
|
|
|
|
};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_boost() {
|
|
|
|
assert!(RE_BOOST.is_match("/b"));
|
|
|
|
assert!(RE_BOOST.is_match(">/b"));
|
|
|
|
assert!(RE_BOOST.is_match("/b mm"));
|
|
|
|
assert!(RE_BOOST.is_match("/b."));
|
|
|
|
assert!(RE_BOOST.is_match("\\b"));
|
|
|
|
assert!(!RE_BOOST.is_match("boo/b"));
|
|
|
|
assert!(RE_BOOST.is_match("bla\n/b"));
|
|
|
|
assert!(RE_BOOST.is_match("/boost"));
|
|
|
|
assert!(RE_BOOST.is_match("/boost\n"));
|
|
|
|
assert!(RE_BOOST.is_match("/boost dfdfg"));
|
|
|
|
assert!(!RE_BOOST.is_match("/boosty"));
|
|
|
|
assert!(RE_BOOST.is_match("/b\nxxx"));
|
|
|
|
assert!(!RE_BOOST.is_match("/bleble\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ignore() {
|
|
|
|
assert!(RE_IGNORE.is_match("/i"));
|
|
|
|
assert!(RE_IGNORE.is_match("/ig"));
|
|
|
|
assert!(RE_IGNORE.is_match("/ign"));
|
|
|
|
assert!(RE_IGNORE.is_match("/i mm"));
|
|
|
|
assert!(RE_IGNORE.is_match("/i."));
|
|
|
|
assert!(RE_IGNORE.is_match("\\i"));
|
|
|
|
assert!(!RE_IGNORE.is_match("boo/i"));
|
|
|
|
assert!(RE_IGNORE.is_match("bla\n/i"));
|
|
|
|
assert!(RE_IGNORE.is_match("/ignore"));
|
|
|
|
assert!(RE_IGNORE.is_match("/ignore x"));
|
|
|
|
assert!(RE_IGNORE.is_match("/ignore\n"));
|
|
|
|
assert!(RE_IGNORE.is_match("/ignore dfdfg"));
|
|
|
|
assert!(!RE_IGNORE.is_match("/ignorey"));
|
|
|
|
assert!(RE_IGNORE.is_match("/i\nxxx"));
|
|
|
|
assert!(!RE_IGNORE.is_match("/ileble\n"));
|
|
|
|
assert!(!RE_IGNORE.is_match("/ignx"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ban_user() {
|
|
|
|
assert!(RE_BAN_USER.is_match("/ban lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_BAN_USER.is_match("/ban lain@stupidname.uk"));
|
|
|
|
assert!(RE_BAN_USER.is_match("bababababa /ban lain@stupidname.uk lala"));
|
|
|
|
assert!(!RE_BAN_USER.is_match("/ban stupidname.uk"));
|
|
|
|
|
|
|
|
assert!(RE_BAN_USER.is_match("/ban @lain"));
|
|
|
|
assert!(RE_BAN_USER.is_match("/ban @lain aaa"));
|
|
|
|
|
|
|
|
assert!(RE_BAN_USER.is_match("/ban \t lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_BAN_USER.is_match("/ban @lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_BAN_USER.is_match("/ban @l-a_i.n9@xn--999pleroma-weirdname.com"));
|
|
|
|
assert!(RE_BAN_USER.is_match("/ban @LAIN@PleromA.soykaf.com"));
|
|
|
|
|
|
|
|
let c = RE_BAN_USER.captures("/ban lain@pleroma.soykaf.com");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "lain@pleroma.soykaf.com");
|
|
|
|
|
|
|
|
let c = RE_BAN_USER.captures("/ban lain@pleroma.soykaf.com xx");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "lain@pleroma.soykaf.com");
|
|
|
|
|
|
|
|
let c = RE_BAN_USER.captures("/ban @lain@pleroma.soykaf.com");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain@pleroma.soykaf.com");
|
|
|
|
|
|
|
|
let c = RE_BAN_USER.captures("/ban @lain");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain");
|
|
|
|
|
|
|
|
let c = RE_BAN_USER.captures("/ban @lain xx");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ban_server() {
|
|
|
|
assert!(!RE_BAN_SERVER.is_match("/ban lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_BAN_SERVER.is_match("/ban pleroma.soykaf.com"));
|
|
|
|
assert!(RE_BAN_SERVER.is_match("/ban xn--999pleroma-weirdname.com"));
|
|
|
|
assert!(RE_BAN_SERVER.is_match("/ban \t xn--999pleroma-weirdname.com"));
|
|
|
|
assert!(RE_BAN_SERVER.is_match("mamama /ban pleroma.soykaf.com momomo"));
|
|
|
|
assert!(!RE_BAN_SERVER.is_match("/ban @pleroma.soykaf.com"));
|
|
|
|
|
|
|
|
let c = RE_BAN_SERVER.captures("/ban pleroma.soykaf.com");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "pleroma.soykaf.com");
|
|
|
|
|
|
|
|
let c = RE_BAN_SERVER.captures("/ban pleroma.soykaf.com xx");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "pleroma.soykaf.com");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_member() {
|
|
|
|
assert!(RE_ADD_MEMBER.is_match("/add lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_ADD_MEMBER.is_match("/add @lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_ADD_MEMBER.is_match("/follow @lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_ADD_MEMBER.is_match("\\add @lain"));
|
|
|
|
|
|
|
|
let c = RE_ADD_MEMBER.captures("/add @lain");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_remove_member() {
|
|
|
|
assert!(!RE_REMOVE_MEMBER.is_match("/admin lain@pleroma.soykaf.com"));
|
|
|
|
|
|
|
|
assert!(RE_REMOVE_MEMBER.is_match("/remove lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_REMOVE_MEMBER.is_match("/remove @lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_REMOVE_MEMBER.is_match("\\remove @lain"));
|
|
|
|
|
|
|
|
assert!(RE_REMOVE_MEMBER.is_match("/kick @lain"));
|
|
|
|
assert!(RE_REMOVE_MEMBER.is_match("/remove @lain"));
|
|
|
|
|
|
|
|
let c = RE_REMOVE_MEMBER.captures("/kick lain@pleroma.soykaf.com");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "lain@pleroma.soykaf.com");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_tag() {
|
|
|
|
assert!(RE_ADD_TAG.is_match("/add #breadposting"));
|
|
|
|
assert!(RE_ADD_TAG.is_match("/add #čučkaři"));
|
|
|
|
assert!(RE_ADD_TAG.is_match("/add #χαλβάς"));
|
|
|
|
assert!(RE_ADD_TAG.is_match("\\add #ласточка"));
|
|
|
|
assert!(RE_ADD_TAG.is_match("/add #nya."));
|
|
|
|
assert!(RE_ADD_TAG.is_match("/add #nya)"));
|
|
|
|
assert!(RE_ADD_TAG.is_match("/follow #nya)"));
|
|
|
|
assert!(RE_ADD_TAG.is_match("/add #nya and more)"));
|
|
|
|
|
|
|
|
let c = RE_ADD_TAG.captures("/add #breadposting");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "breadposting");
|
|
|
|
|
|
|
|
let c = RE_ADD_TAG.captures("/add #χαλβάς");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "χαλβάς");
|
|
|
|
|
|
|
|
let c = RE_ADD_TAG.captures("/add #ласточка");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "ласточка");
|
|
|
|
|
|
|
|
let c = RE_ADD_TAG.captures("/add #nya.");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "nya");
|
|
|
|
|
|
|
|
let c = RE_ADD_TAG.captures("/add #nya)");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "nya");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_add_admin() {
|
|
|
|
assert!(!RE_GRANT_ADMIN.is_match("/expel lain@pleroma.soykaf.com"));
|
|
|
|
|
|
|
|
assert!(RE_GRANT_ADMIN.is_match("/admin lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_GRANT_ADMIN.is_match("/op @lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_GRANT_ADMIN.is_match("\\op @lain"));
|
|
|
|
|
|
|
|
let c = RE_GRANT_ADMIN.captures("/op @lain@pleroma.soykaf.com");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain@pleroma.soykaf.com");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_remove_admin() {
|
|
|
|
assert!(!RE_REVOKE_ADMIN.is_match("/admin lain@pleroma.soykaf.com"));
|
|
|
|
|
|
|
|
assert!(RE_REVOKE_ADMIN.is_match("/deop @lain"));
|
|
|
|
assert!(RE_REVOKE_ADMIN.is_match("/deadmin @lain"));
|
|
|
|
|
|
|
|
let c = RE_REVOKE_ADMIN.captures("/deadmin @lain");
|
|
|
|
assert_eq!(c.unwrap().get(1).unwrap().as_str(), "@lain");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_opengroup() {
|
|
|
|
assert!(!RE_OPEN_GROUP.is_match("/admin lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_OPEN_GROUP.is_match("/opengroup"));
|
|
|
|
assert!(RE_OPEN_GROUP.is_match("x /opengroup"));
|
|
|
|
assert!(RE_OPEN_GROUP.is_match("/opengroup dfgdfg"));
|
|
|
|
assert!(RE_OPEN_GROUP.is_match("\n\n/opengroup\n dfgdfg\n\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_closegroup() {
|
|
|
|
assert!(!RE_CLOSE_GROUP.is_match("/admin lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_CLOSE_GROUP.is_match("/closegroup"));
|
|
|
|
assert!(RE_CLOSE_GROUP.is_match("x /closegroup"));
|
|
|
|
assert!(RE_CLOSE_GROUP.is_match("/closegroup dfgdfg"));
|
|
|
|
assert!(RE_CLOSE_GROUP.is_match("\n\n/closegroup\n dfgdfg\n\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_help() {
|
|
|
|
assert!(!RE_HELP.is_match("/admin lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_HELP.is_match("/help"));
|
|
|
|
|
|
|
|
assert!(!RE_HELP.is_match("/helpx"));
|
|
|
|
assert!(!RE_HELP.is_match("a/help"));
|
|
|
|
assert!(!RE_HELP.is_match("help"));
|
|
|
|
|
|
|
|
assert!(RE_HELP.is_match("x /help"));
|
|
|
|
assert!(RE_HELP.is_match("/help dfgdfg"));
|
|
|
|
assert!(RE_HELP.is_match("\n\n/help\n dfgdfg\n\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_members() {
|
|
|
|
assert!(!RE_MEMBERS.is_match("/admin lain@pleroma.soykaf.com"));
|
|
|
|
assert!(RE_MEMBERS.is_match("/members"));
|
|
|
|
assert!(RE_MEMBERS.is_match("/who"));
|
|
|
|
assert!(RE_MEMBERS.is_match("/admins"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_tags() {
|
|
|
|
assert!(!RE_TAGS.is_match("/members"));
|
|
|
|
assert!(RE_TAGS.is_match("/hashtags"));
|
|
|
|
assert!(RE_TAGS.is_match("dsfsd /tags dfgd d"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_match_tag() {
|
|
|
|
assert!(!RE_A_HASHTAG.is_match("banana sdfsdf sdfsd fdsf sd"));
|
|
|
|
assert!(RE_A_HASHTAG.is_match("#banana"));
|
|
|
|
assert!(RE_A_HASHTAG.is_match("#ласточка"));
|
|
|
|
assert!(RE_A_HASHTAG.is_match("#χαλβάς"));
|
|
|
|
assert!(RE_A_HASHTAG.is_match("foo #banana gfdfgd"));
|
|
|
|
|
|
|
|
for (i, c) in RE_A_HASHTAG.captures_iter("foo #banana #χαλβάς #ласточка").enumerate() {
|
|
|
|
if i == 0 {
|
|
|
|
assert_eq!(c.get(1).unwrap().as_str(), "banana");
|
|
|
|
} else if i == 1 {
|
|
|
|
assert_eq!(c.get(1).unwrap().as_str(), "χαλβάς");
|
|
|
|
} else if i == 2 {
|
|
|
|
assert_eq!(c.get(1).unwrap().as_str(), "ласточка");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
fn test_match_tag_at_end() {
|
|
|
|
assert!(!RE_HASHTAG_TRIGGERING_PLEROMA_BUG.is_match("banana #tag sdfsd"));
|
|
|
|
assert!(!RE_HASHTAG_TRIGGERING_PLEROMA_BUG.is_match("banana #tag ."));
|
|
|
|
assert!(RE_HASHTAG_TRIGGERING_PLEROMA_BUG.is_match("banana #tag"));
|
|
|
|
assert!(RE_HASHTAG_TRIGGERING_PLEROMA_BUG.is_match("banana #tag."));
|
|
|
|
assert!(RE_HASHTAG_TRIGGERING_PLEROMA_BUG.is_match("banana #tag..."));
|
|
|
|
assert!(RE_HASHTAG_TRIGGERING_PLEROMA_BUG.is_match("#tag..."));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_leave() {
|
|
|
|
assert!(!RE_LEAVE.is_match("/list"));
|
|
|
|
assert!(RE_LEAVE.is_match("/leave"));
|
|
|
|
assert!(RE_LEAVE.is_match("/leave"));
|
|
|
|
assert!(RE_LEAVE.is_match("x /leave"));
|
|
|
|
assert!(RE_LEAVE.is_match("/leave z"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_undo() {
|
|
|
|
assert!(!RE_UNDO.is_match("/list"));
|
|
|
|
assert!(RE_UNDO.is_match("/undo"));
|
|
|
|
assert!(RE_UNDO.is_match("/delete"));
|
|
|
|
assert!(RE_UNDO.is_match("/undo"));
|
|
|
|
assert!(RE_UNDO.is_match("x /undo"));
|
|
|
|
assert!(RE_UNDO.is_match("/undo z"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_join() {
|
|
|
|
assert!(!RE_JOIN.is_match("/list"));
|
|
|
|
assert!(RE_JOIN.is_match("/join"));
|
|
|
|
assert!(RE_JOIN.is_match("/join"));
|
|
|
|
assert!(RE_JOIN.is_match("x /join"));
|
|
|
|
assert!(RE_JOIN.is_match("/join z"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_announce() {
|
|
|
|
assert!(!RE_ANNOUNCE.is_match("/list"));
|
|
|
|
assert!(RE_ANNOUNCE.is_match("sdfsdffsd /announce b"));
|
|
|
|
assert!(RE_ANNOUNCE.is_match("/announce bla bla bla"));
|
|
|
|
assert!(RE_ANNOUNCE.is_match("sdfsdffsd /announce bla bla bla"));
|
|
|
|
assert_eq!(
|
|
|
|
"bla bla bla",
|
|
|
|
RE_ANNOUNCE
|
|
|
|
.captures("sdfsdffsd /announce bla bla bla")
|
|
|
|
.unwrap()
|
|
|
|
.get(1)
|
|
|
|
.unwrap()
|
|
|
|
.as_str()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_real_post() {
|
|
|
|
assert_eq!(
|
|
|
|
Vec::<StatusCommand>::new(),
|
|
|
|
parse_slash_commands("Hello there is nothing here /fake command")
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
vec![StatusCommand::Help],
|
|
|
|
parse_slash_commands("lets see some \\help and /ban @lain")
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
vec![StatusCommand::Ignore],
|
|
|
|
parse_slash_commands("lets see some /ignore and /ban @lain")
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
vec![
|
|
|
|
StatusCommand::BanUser("lain".to_string()),
|
|
|
|
StatusCommand::BanUser("piggo@piggo.space".to_string()),
|
|
|
|
StatusCommand::BanServer("soykaf.com".to_string()),
|
|
|
|
],
|
|
|
|
parse_slash_commands("let's /ban @lain! /ban @piggo@piggo.space and also /ban soykaf.com")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_strip() {
|
|
|
|
assert_eq!(
|
|
|
|
vec![StatusCommand::BanUser("betty".to_string())],
|
|
|
|
parse_slash_commands(
|
|
|
|
r#"Let's bad the naughty bot: /ban <span class="h-card"><a class="u-url mention" data-user="9nXpaGZL88fPAiP8xU" href="https://piggo.space/users/betty" rel="ugc">@<span>betty</span></a></span>"#
|
|
|
|
)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
vec![StatusCommand::BanUser("betty@abstarbauze.com".to_string())],
|
|
|
|
parse_slash_commands(
|
|
|
|
r#"Let's bad the naughty bot: /ban <span class="h-card"><a class="u-url mention" data-user="9nXpaGZL88fPAiP8xU" href="https://piggo.space/users/betty" rel="ugc">@<span>betty@abstarbauze.com</span></a></span>"#
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|