@ -12,6 +12,7 @@ use crate::error::GroupError;
use crate ::group_handler ::GroupHandle ;
use crate ::group_handler ::GroupHandle ;
use crate ::store ::group_config ::GroupConfig ;
use crate ::store ::group_config ::GroupConfig ;
use crate ::store ::CommonConfig ;
use crate ::store ::CommonConfig ;
use crate ::tr ::TranslationTable ;
use crate ::utils ;
use crate ::utils ;
use crate ::utils ::{ normalize_acct , LogError } ;
use crate ::utils ::{ normalize_acct , LogError } ;
@ -26,13 +27,17 @@ pub struct ProcessMention<'a> {
status_user_id : String ,
status_user_id : String ,
can_write : bool ,
can_write : bool ,
is_admin : bool ,
is_admin : bool ,
replies : Vec < String > ,
replies : String ,
announcements : Vec < String > ,
announcements : String ,
do_boost_prev_post : bool ,
do_boost_prev_post : bool ,
want_markdown : bool ,
want_markdown : bool ,
}
}
impl < ' a > ProcessMention < ' a > {
impl < ' a > ProcessMention < ' a > {
fn tr ( & self ) -> & TranslationTable {
self . cc . tr ( self . config . get_locale ( ) )
}
async fn lookup_acct_id ( & self , acct : & str , followed : bool ) -> Result < Option < String > , GroupError > {
async fn lookup_acct_id ( & self , acct : & str , followed : bool ) -> Result < Option < String > , GroupError > {
debug ! ( "Looking up user ID by acct: {}" , acct ) ;
debug ! ( "Looking up user ID by acct: {}" , acct ) ;
@ -41,7 +46,7 @@ impl<'a> ProcessMention<'a> {
self . client
self . client
. search_v2 ( acct , ! followed , Some ( SearchType ::Accounts ) , Some ( 1 ) , followed ) ,
. search_v2 ( acct , ! followed , Some ( SearchType ::Accounts ) , Some ( 1 ) , followed ) ,
)
)
. await
. await
{
{
Err ( _ ) = > {
Err ( _ ) = > {
warn ! ( "Account lookup timeout!" ) ;
warn ! ( "Account lookup timeout!" ) ;
@ -72,9 +77,11 @@ impl<'a> ProcessMention<'a> {
fn append_admin_list_to_reply ( & mut self ) {
fn append_admin_list_to_reply ( & mut self ) {
let mut admins = self . config . get_admins ( ) . collect ::< Vec < _ > > ( ) ;
let mut admins = self . config . get_admins ( ) . collect ::< Vec < _ > > ( ) ;
admins . sort ( ) ;
admins . sort ( ) ;
let mut to_add = String ::new ( ) ;
for a in admins {
for a in admins {
self . replies . push ( format! ( "- {}" , a ) ) ;
to_add . push_str ( & crate ::tr ! ( self , "user_list_entry" , user = a ) ) ;
}
}
self . add_reply ( & to_add ) ;
}
}
fn append_member_list_to_reply ( & mut self ) {
fn append_member_list_to_reply ( & mut self ) {
@ -83,13 +90,15 @@ impl<'a> ProcessMention<'a> {
members . extend ( admins . iter ( ) ) ;
members . extend ( admins . iter ( ) ) ;
members . sort ( ) ;
members . sort ( ) ;
members . dedup ( ) ;
members . dedup ( ) ;
let mut to_add = String ::new ( ) ;
for m in members {
for m in members {
self . replies . push ( if admins . contains ( & m ) {
to_add . push_str ( & if admins . contains ( & m ) {
format! ( "- {} [admin] ", m )
crate ::tr ! ( self , "user_list_entry_admin ", user = m )
} else {
} else {
format! ( "- {} ", m )
crate ::tr ! ( self , "user_list_entry ", user = m )
} ) ;
} ) ;
}
}
self . add_reply ( & to_add ) ;
}
}
async fn follow_user_by_id ( & self , id : & str ) -> Result < ( ) , GroupError > {
async fn follow_user_by_id ( & self , id : & str ) -> Result < ( ) , GroupError > {
@ -122,8 +131,8 @@ impl<'a> ProcessMention<'a> {
cc : & gh . cc ,
cc : & gh . cc ,
can_write : gh . config . can_write ( & status_acct ) ,
can_write : gh . config . can_write ( & status_acct ) ,
is_admin : gh . config . is_admin ( & status_acct ) ,
is_admin : gh . config . is_admin ( & status_acct ) ,
replies : vec ! [ ] ,
replies : String ::new ( ) ,
announcements : vec ! [ ] ,
announcements : String ::new ( ) ,
do_boost_prev_post : false ,
do_boost_prev_post : false ,
want_markdown : false ,
want_markdown : false ,
group_acct ,
group_acct ,
@ -136,16 +145,17 @@ impl<'a> ProcessMention<'a> {
}
}
async fn reblog_status ( & self ) {
async fn reblog_status ( & self ) {
self . client . reblog ( & self . status . id ) . await . log_error ( "Failed to reblog status" ) ;
self . client . reblog ( & self . status . id )
. await . log_error ( "Failed to reblog status" ) ;
self . delay_after_post ( ) . await ;
self . delay_after_post ( ) . await ;
}
}
fn add_reply ( & mut self , line : impl AsRef < str > ) {
fn add_reply ( & mut self , line : impl AsRef < str > ) {
self . replies . push ( line . as_ref ( ) . trim_matches ( ' ' ) . to_string ( ) )
self . replies . push_str ( line . as_ref ( ) )
}
}
fn add_announcement ( & mut self , line : impl AsRef < str > ) {
fn add_announcement ( & mut self , line : impl AsRef < str > ) {
self . announcements . push ( line . as_ref ( ) . trim_matches ( ' ' ) . to_string ( ) )
self . announcements . push_str ( line . as_ref ( ) )
}
}
async fn handle ( mut self ) -> Result < ( ) , GroupError > {
async fn handle ( mut self ) -> Result < ( ) , GroupError > {
@ -160,6 +170,9 @@ impl<'a> ProcessMention<'a> {
}
}
for cmd in commands {
for cmd in commands {
if ! self . replies . is_empty ( ) {
self . replies . push ( '\n' ) ; // make sure there's a newline between batched commands.
}
match cmd {
match cmd {
StatusCommand ::Undo = > {
StatusCommand ::Undo = > {
self . cmd_undo ( ) . await . log_error ( "Error handling undo cmd" ) ;
self . cmd_undo ( ) . await . log_error ( "Error handling undo cmd" ) ;
@ -207,7 +220,7 @@ impl<'a> ProcessMention<'a> {
self . cmd_grant_admin ( & u ) . await . log_error ( "Error handling grant-admin cmd" ) ;
self . cmd_grant_admin ( & u ) . await . log_error ( "Error handling grant-admin cmd" ) ;
}
}
StatusCommand ::RemoveAdmin ( u ) = > {
StatusCommand ::RemoveAdmin ( u ) = > {
self . cmd_revoke_member ( & u ) . await . log_error ( "Error handling grant-admin cmd" ) ;
self . cmd_revoke_admin ( & u ) . await . log_error ( "Error handling grant-admin cmd" ) ;
}
}
StatusCommand ::OpenGroup = > {
StatusCommand ::OpenGroup = > {
self . cmd_open_group ( ) . await ;
self . cmd_open_group ( ) . await ;
@ -255,26 +268,26 @@ impl<'a> ProcessMention<'a> {
}
}
if ! self . replies . is_empty ( ) {
if ! self . replies . is_empty ( ) {
let mut msg = self . replies . join ( "\n" ) ;
let mut msg = std ::mem ::take ( & mut self . replies ) ;
debug ! ( "r={}" , msg ) ;
debug ! ( "r={}" , msg ) ;
if self . want_markdown {
if self . want_markdown {
apply_trailing_hashtag_pleroma_bug_workaround ( & mut msg ) ;
apply_trailing_hashtag_pleroma_bug_workaround ( & mut msg ) ;
}
}
let mention = format! ( "@{user} ", user = self . status_acct ) ;
let mention = crate ::tr ! ( self , "mention_prefix ", user = & self . status_acct ) ;
self . send_reply_multipart ( mention , msg ) . await ? ;
self . send_reply_multipart ( mention , msg ) . await ? ;
}
}
if ! self . announcements . is_empty ( ) {
if ! self . announcements . is_empty ( ) {
let mut msg = self . announcements . join ( "\n" ) ;
let mut msg = std ::mem ::take ( & mut self . announcements ) ;
debug ! ( "a={}" , msg ) ;
debug ! ( "a={}" , msg ) ;
if self . want_markdown {
if self . want_markdown {
apply_trailing_hashtag_pleroma_bug_workaround ( & mut msg ) ;
apply_trailing_hashtag_pleroma_bug_workaround ( & mut msg ) ;
}
}
let msg = format! ( "**📢 Group announcement**\n{msg} ", msg = msg ) ;
let msg = crate ::tr ! ( self , "group_announcement ", mes sa ge = & msg ) ;
self . send_announcement_multipart ( & msg ) . await ? ;
self . send_announcement_multipart ( & msg ) . await ? ;
}
}
@ -367,29 +380,29 @@ impl<'a> ProcessMention<'a> {
async fn cmd_optout ( & mut self ) {
async fn cmd_optout ( & mut self ) {
if self . is_admin {
if self . is_admin {
self . add_reply ( "Group admins can't opt-out." ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_optout_fail_admin_cant" ) ) ;
} else if self . config . is_member ( & self . status_acct ) {
} else if self . config . is_member ( & self . status_acct ) {
self . add_reply ( "Group members can't opt-out. You have to leave first." ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_optout_fail_member_cant" ) ) ;
} else {
} else {
self . config . set_optout ( & self . status_acct , true ) ;
self . config . set_optout ( & self . status_acct , true ) ;
self . add_reply ( "Your posts will no longer be shared to the group." ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_optout_ok" ) ) ;
}
}
}
}
async fn cmd_optin ( & mut self ) {
async fn cmd_optin ( & mut self ) {
if self . is_admin {
if self . is_admin {
self . add_reply ( "Opt-in has no effect for admins." ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_optin_fail_admin_cant" ) ) ;
} else if self . config . is_member ( & self . status_acct ) {
} else if self . config . is_member ( & self . status_acct ) {
self . add_reply ( "Opt-in has no effect for members." ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_optin_fail_member_cant" ) ) ;
} else {
} else {
self . config . set_optout ( & self . status_acct , false ) ;
self . config . set_optout ( & self . status_acct , false ) ;
self . add_reply ( "Your posts can now be shared to the group." ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_optin_ok" ) ) ;
}
}
}
}
async fn cmd_undo ( & mut self ) -> Result < ( ) , GroupError > {
async fn cmd_undo ( & mut self ) -> Result < ( ) , GroupError > {
if let ( Some ( ref parent_account_id ) , Some ( ref parent_status_id ) ) =
if let ( Some ( ref parent_account_id ) , Some ( ref parent_status_id ) ) =
( & self . status . in_reply_to_account_id , & self . status . in_reply_to_id )
( & self . status . in_reply_to_account_id , & self . status . in_reply_to_id )
{
{
if parent_account_id = = & self . group_account . id {
if parent_account_id = = & self . group_account . id {
// This is a post sent by the group user, likely an announcement.
// This is a post sent by the group user, likely an announcement.
@ -422,15 +435,15 @@ impl<'a> ProcessMention<'a> {
if ! self . config . is_banned ( & u ) {
if ! self . config . is_banned ( & u ) {
match self . config . ban_user ( & u , true ) {
match self . config . ban_user ( & u , true ) {
Ok ( _ ) = > {
Ok ( _ ) = > {
self . add_reply ( format! ( "User {} banned from group! ", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_ban_user_ok ", user = & u ) ) ;
self . unfollow_by_acct ( & u ) . await . log_error ( "Failed to unfollow banned user" ) ;
self . unfollow_by_acct ( & u ) . await . log_error ( "Failed to unfollow banned user" ) ;
}
}
Err ( e ) = > {
Err ( e ) = > {
self . add_reply ( format! ( "Failed to ban user {}: {}" , u , e ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_error" , cause = & e . to_string ( ) ) ) ;
}
}
}
}
} else {
} else {
self . add_reply ( format! ( "No action, user {} is already banned ", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_ban_user_fail_already ", user = & u ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -444,15 +457,15 @@ impl<'a> ProcessMention<'a> {
if self . config . is_banned ( & u ) {
if self . config . is_banned ( & u ) {
match self . config . ban_user ( & u , false ) {
match self . config . ban_user ( & u , false ) {
Ok ( _ ) = > {
Ok ( _ ) = > {
self . add_reply ( format! ( "User {} un-banned! ", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_unban_user_ok ", user = & u ) ) ;
// no announcement here
// no announcement here
}
}
Err ( _ ) = > {
Err ( e ) = > {
unreachable! ( )
self . add_reply ( crate ::tr ! ( self , "cmd_error" , cause = & e . to_string ( ) ) ) ;
}
}
}
}
} else {
} else {
self . add_reply ( format! ( "No action, user {} is not banned ", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_unban_user_fail_already ", user = & u ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -465,14 +478,14 @@ impl<'a> ProcessMention<'a> {
if ! self . config . is_server_banned ( s ) {
if ! self . config . is_server_banned ( s ) {
match self . config . ban_server ( s , true ) {
match self . config . ban_server ( s , true ) {
Ok ( _ ) = > {
Ok ( _ ) = > {
self . add_reply ( format! ( "Server {} banned from group!" , s ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_ban_server_ok" , server = s ) ) ;
}
}
Err ( e ) = > {
Err ( e ) = > {
self . add_reply ( format! ( "Failed to ban server {}: {}" , s , e ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_error" , cause = & e . to_string ( ) ) ) ;
}
}
}
}
} else {
} else {
self . add_reply ( format! ( "No action, server {} already banned" , s ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_ban_server_fail_already" , server = s ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -484,14 +497,14 @@ impl<'a> ProcessMention<'a> {
if self . config . is_server_banned ( s ) {
if self . config . is_server_banned ( s ) {
match self . config . ban_server ( s , false ) {
match self . config . ban_server ( s , false ) {
Ok ( _ ) = > {
Ok ( _ ) = > {
self . add_reply ( format! ( "Server {} un-banned!" , s ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_unban_server_ok" , server = s ) ) ;
}
}
Err ( e ) = > {
Err ( e ) = > {
self . add_reply ( format! ( "Unexpected error occured: {} ", e ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_error ", caus e = & e . to_string ( ) ) ) ;
}
}
}
}
} else {
} else {
self . add_reply ( format! ( "No action, server {} is not banned" , s ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_unban_server_fail_already" , server = s ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -504,11 +517,12 @@ impl<'a> ProcessMention<'a> {
// Allow even if the user is already a member - that will trigger re-follow
// Allow even if the user is already a member - that will trigger re-follow
match self . config . set_member ( & u , true ) {
match self . config . set_member ( & u , true ) {
Ok ( _ ) = > {
Ok ( _ ) = > {
self . add_reply ( format! ( "User {} added to the group!" , u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_add_user_ok" , user = & u ) ) ;
// marked as member, now also follow the user
self . follow_by_acct ( & u ) . await . log_error ( "Failed to follow" ) ;
self . follow_by_acct ( & u ) . await . log_error ( "Failed to follow" ) ;
}
}
Err ( e ) = > {
Err ( e ) = > {
self . add_reply ( format! ( "Failed to add user {} to group: {}" , u , e ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_error" , cause = & e . to_string ( ) ) ) ;
}
}
}
}
} else {
} else {
@ -522,11 +536,11 @@ impl<'a> ProcessMention<'a> {
if self . is_admin {
if self . is_admin {
match self . config . set_member ( & u , false ) {
match self . config . set_member ( & u , false ) {
Ok ( _ ) = > {
Ok ( _ ) = > {
self . add_reply ( format! ( "User {} removed from the group. ", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_remove_user_ok ", user = & u ) ) ;
self . unfollow_by_acct ( & u ) . await . log_error ( "Failed to unfollow removed user" ) ;
self . unfollow_by_acct ( & u ) . await . log_error ( "Failed to unfollow removed user" ) ;
}
}
Err ( e ) = > {
Err ( e ) = > {
self . add_reply ( format! ( "Unexpected error occured: {} ", e ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_error ", caus e = & e . to_string ( ) ) ) ;
}
}
}
}
} else {
} else {
@ -539,9 +553,9 @@ impl<'a> ProcessMention<'a> {
if self . is_admin {
if self . is_admin {
if ! self . config . is_tag_followed ( & tag ) {
if ! self . config . is_tag_followed ( & tag ) {
self . config . add_tag ( & tag ) ;
self . config . add_tag ( & tag ) ;
self . add_reply ( format! ( "Tag \"{}\" added to the group! ", tag ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_add_tag_ok ", tag = & tag ) ) ;
} else {
} else {
self . add_reply ( format! ( "No action, \"{}\" is already a group tag" , tag ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_add_tag_fail_already" , tag = & tag ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -552,9 +566,9 @@ impl<'a> ProcessMention<'a> {
if self . is_admin {
if self . is_admin {
if self . config . is_tag_followed ( & tag ) {
if self . config . is_tag_followed ( & tag ) {
self . config . remove_tag ( & tag ) ;
self . config . remove_tag ( & tag ) ;
self . add_reply ( format! ( "Tag \"{}\" removed from the group! ", tag ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_remove_tag_ok ", tag = & tag ) ) ;
} else {
} else {
self . add_reply ( format! ( "No action, \"{}\" is not a group tag" , tag ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_remove_tag_fail_already" , tag = & tag ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -570,14 +584,14 @@ impl<'a> ProcessMention<'a> {
// try to make the config a little more sane, admins should be members
// try to make the config a little more sane, admins should be members
let _ = self . config . set_member ( & u , true ) ;
let _ = self . config . set_member ( & u , true ) ;
self . add_reply ( format! ( "User {} is now a group admin! ", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_admin_ok ", user = & u ) ) ;
}
}
Err ( e ) = > {
Err ( e ) = > {
self . add_reply ( format! ( "Failed to make user {} a group admin: {}" , u , e ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_error" , cause = & e . to_string ( ) ) ) ;
}
}
}
}
} else {
} else {
self . add_reply ( format! ( "No action, \"{}\" is admin already", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_admin_fail_ already", user = & u ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -585,20 +599,20 @@ impl<'a> ProcessMention<'a> {
Ok ( ( ) )
Ok ( ( ) )
}
}
async fn cmd_revoke_member ( & mut self , user : & str ) -> Result < ( ) , GroupError > {
async fn cmd_revoke_admin ( & mut self , user : & str ) -> Result < ( ) , GroupError > {
let u = normalize_acct ( user , & self . group_acct ) ? ;
let u = normalize_acct ( user , & self . group_acct ) ? ;
if self . is_admin {
if self . is_admin {
if self . config . is_admin ( & u ) {
if self . config . is_admin ( & u ) {
match self . config . set_admin ( & u , false ) {
match self . config . set_admin ( & u , false ) {
Ok ( _ ) = > {
Ok ( _ ) = > {
self . add_reply ( format! ( "User {} is no longer a group admin! ", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_unadmin_ok ", user = & u ) ) ;
}
}
Err ( e ) = > {
Err ( e ) = > {
self . add_reply ( format! ( "Failed to revoke {}'s group admin: {}" , u , e ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_error" , cause = & e . to_string ( ) ) ) ;
}
}
}
}
} else {
} else {
self . add_reply ( format! ( "No action, user {} is not admin ", u ) ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_unadmin_fail_already ", user = & u ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -610,9 +624,9 @@ impl<'a> ProcessMention<'a> {
if self . is_admin {
if self . is_admin {
if self . config . is_member_only ( ) {
if self . config . is_member_only ( ) {
self . config . set_member_only ( false ) ;
self . config . set_member_only ( false ) ;
self . add_reply ( "Group changed to open-access" ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_open_resp" ) ) ;
} else {
} else {
self . add_reply ( "No action, group is open-access already" ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_open_resp_already" ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -623,9 +637,9 @@ impl<'a> ProcessMention<'a> {
if self . is_admin {
if self . is_admin {
if ! self . config . is_member_only ( ) {
if ! self . config . is_member_only ( ) {
self . config . set_member_only ( true ) ;
self . config . set_member_only ( true ) ;
self . add_reply ( "Group changed to member-only" ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_close_resp" ) ) ;
} else {
} else {
self . add_reply ( "No action, group is member-only already" ) ;
self . add_reply ( crate ::tr ! ( self , "cmd_close_resp_already" ) ) ;
}
}
} else {
} else {
warn ! ( "Ignore cmd, user not admin" ) ;
warn ! ( "Ignore cmd, user not admin" ) ;
@ -636,93 +650,62 @@ impl<'a> ProcessMention<'a> {
self . want_markdown = true ;
self . want_markdown = true ;
let membership_line = if self . is_admin {
let membership_line = if self . is_admin {
"*You are an admin.*"
crate ::tr ! ( self , "help_membership_admin" )
} else if self . config . is_member ( & self . status_acct ) {
} else if self . config . is_member ( & self . status_acct ) {
"*You are a member.*"
crate ::tr ! ( self , "help_membership_member" )
} else if self . config . is_member_only ( ) {
} else if self . config . is_member_only ( ) {
"*You are not a member, ask one of the admins to add you.*"
crate ::tr ! ( self , "help_membership_guest_closed" )
} else {
} else {
"*You are not a member, follow or use /join to join the group.*"
crate ::tr ! ( self , "help_membership_guest_open" )
} ;
} ;
if self . config . is_member_only ( ) {
if self . config . is_member_only ( ) {
self . add_reply ( format! ( "This is a member-only group. {}" , membership_line ) ) ;
self . add_reply ( crate ::tr ! ( self , "help_group_info_closed" , membership = & membership_line ) ) ;
} else {
self . add_reply ( format! ( "This is a public-access group. {}" , membership_line ) ) ;
}
self . add_reply (
" \
To share a post , @ the group user or use a group hashtag . \ n \
\ n \
* * Supported commands :* * \ n \
` / boost ` , ` / b ` - boost the replied - to post into the group \ n \
` / ignore ` , ` / i ` - make the group ignore the post \ n \
` / tags ` - show group hashtags \ n \
` / join ` - ( re - ) join the group \ n \
` / leave ` - leave the group \ n \
` / optout ` - forbid sharing of your posts " ,
) ;
if self . is_admin {
self . add_reply ( "`/members`, `/who` - show group members / admins" ) ;
// undo is listed as an admin command
} else {
} else {
self . add_reply ( "`/admins` - show group admins" ) ;
self . add_reply ( crate ::tr ! ( self , "help_group_info_open" , membership = & membership_line ) ) ;
self . add_reply ( "`/undo` - un-boost your post (use in a reply)" ) ;
}
}
// XXX when used on instance with small character limit, this won't fit!
self . add_reply ( crate ::tr ! ( self , "help_basic_commands" ) ) ;
if ! self . is_admin {
self . add_reply ( crate ::tr ! ( self , "help_member_commands" ) ) ;
}
if self . is_admin {
if self . is_admin {
self . add_reply (
self . add_reply ( crate ::tr ! ( self , "help_admin_commands" ) ) ;
" \ n \
* * Admin commands :* * \ n \
` / ping ` - check the group works \ n \
` / add user ` - add a member ( user @ domain ) \ n \
` / remove user ` - remove a member \ n \
` / add #hashtag ` - add a group hashtag \ n \
` / remove #hashtag ` - remove a group hashtag \ n \
` / undo ` - un - boost a replied - to post , delete an announcement \ n \
` / ban x ` - ban a user or server \ n \
` / unban x ` - lift a ban \ n \
` / admin user ` - grant admin rights \ n \
` / deadmin user ` - revoke admin rights \ n \
` / closegroup ` - make member - only \ n \
` / opengroup ` - make public - access \ n \
` / announce x ` - make a public announcement " ,
) ;
}
}
}
}
async fn cmd_list_members ( & mut self ) {
async fn cmd_list_members ( & mut self ) {
self . want_markdown = true ;
self . want_markdown = true ;
if self . is_admin {
if self . is_admin {
self . add_reply ( "Group members:" ) ;
self . add_reply ( crate ::tr ! ( self , "member_list_heading" ) ) ;
self . append_member_list_to_reply ( ) ;
self . append_member_list_to_reply ( ) ;
} else {
} else {
self . add_reply ( "Group admins:" ) ;
self . add_reply ( crate ::tr ! ( self , "admin_list_heading" ) ) ;
self . append_admin_list_to_reply ( ) ;
self . append_admin_list_to_reply ( ) ;
}
}
}
}
async fn cmd_list_tags ( & mut self ) {
async fn cmd_list_tags ( & mut self ) {
self . add_reply ( "Group tags:" ) ;
self . add_reply ( crate ::tr ! ( self , "tag_list_heading" ) ) ;
self . want_markdown = true ;
self . want_markdown = true ;
let mut tags = self . config . get_tags ( ) . collect ::< Vec < _ > > ( ) ;
let mut tags = self . config . get_tags ( ) . collect ::< Vec < _ > > ( ) ;
tags . sort ( ) ;
tags . sort ( ) ;
let mut to_add = String ::new ( ) ;
for t in tags {
for t in tags {
self . replies . push ( format! ( "- {}" , t ) . to_string ( ) ) ;
to_add . push_str ( & crate ::tr ! ( self , "tag_list_entry" , tag = t ) ) ;
}
}
self . add_reply ( to_add ) ;
}
}
async fn cmd_leave ( & mut self ) {
async fn cmd_leave ( & mut self ) {
if self . config . is_member_or_admin ( & self . status_acct ) {
if self . config . is_member_or_admin ( & self . status_acct ) {
// admin can leave but that's a bad idea
// admin can leave but that's a bad idea
let _ = self . config . set_member ( & self . status_acct , false ) ;
let _ = self . config . set_member ( & self . status_acct , false ) ;
self . add_reply (
self . add_reply ( crate ::tr ! ( self , "cmd_leave_resp" ) ) ;
"You're no longer a group member. Unfollow the group user to stop receiving group messages." ,
) ;
}
}
self . unfollow_user_by_id ( & self . status_user_id )
self . unfollow_user_by_id ( & self . status_user_id )
@ -740,12 +723,7 @@ impl<'a> ProcessMention<'a> {
// Not a member yet
// Not a member yet
if self . config . is_member_only ( ) {
if self . config . is_member_only ( ) {
// No you can't
// No you can't
self . add_reply (
self . add_reply ( crate ::tr ! ( self , "welcome_closed" ) ) ;
" \
Sorry , this group is closed to new sign - ups . \ n \
Please ask one of the group admins to add you :" ,
) ;
self . append_admin_list_to_reply ( ) ;
self . append_admin_list_to_reply ( ) ;
} else {
} else {
// Open access, try to follow back
// Open access, try to follow back
@ -753,21 +731,13 @@ impl<'a> ProcessMention<'a> {
// This only fails if the user is banned, but that is filtered above
// This only fails if the user is banned, but that is filtered above
let _ = self . config . set_member ( & self . status_acct , true ) ;
let _ = self . config . set_member ( & self . status_acct , true ) ;
self . add_reply (
self . add_reply ( crate ::tr ! ( self , "welcome_join_cmd" ) ) ;
" \
Welcome to the group ! The group user will now follow you to complete the sign - up . \
Make sure you follow back to receive shared posts ! \ n \ n \
Use / help for more info . " ,
) ;
}
}
}
}
}
}
async fn cmd_ping ( & mut self ) {
async fn cmd_ping ( & mut self ) {
self . add_reply ( format! (
self . add_reply ( crate ::tr ! ( self , "ping_response" , version = env! ( "CARGO_PKG_VERSION" ) ) ) ;
"pong, this is fedigroups service v{}" ,
env! ( "CARGO_PKG_VERSION" )
) ) ;
}
}
async fn unfollow_by_acct ( & self , acct : & str ) -> Result < ( ) , GroupError > {
async fn unfollow_by_acct ( & self , acct : & str ) -> Result < ( ) , GroupError > {
@ -917,21 +887,21 @@ mod test {
let to_split = "foo\nbar\nbaz" ;
let to_split = "foo\nbar\nbaz" ;
let parts = super ::smart_split ( to_split , None , 1000 ) ;
let parts = super ::smart_split ( to_split , None , 1000 ) ;
assert_eq! ( vec! [ "foo\nbar\nbaz" . to_string ( ) , ] , parts ) ;
assert_eq! ( vec! [ "foo\nbar\nbaz" . to_string ( ) ] , parts ) ;
}
}
#[ test ]
#[ test ]
fn test_smart_split_nosplit_prefix ( ) {
fn test_smart_split_nosplit_prefix ( ) {
let to_split = "foo\nbar\nbaz" ;
let to_split = "foo\nbar\nbaz" ;
let parts = super ::smart_split ( to_split , Some ( "PREFIX" . to_string ( ) ) , 1000 ) ;
let parts = super ::smart_split ( to_split , Some ( "PREFIX" . to_string ( ) ) , 1000 ) ;
assert_eq! ( vec! [ "PREFIXfoo\nbar\nbaz" . to_string ( ) , ] , parts ) ;
assert_eq! ( vec! [ "PREFIXfoo\nbar\nbaz" . to_string ( ) ] , parts ) ;
}
}
#[ test ]
#[ test ]
fn test_smart_split_prefix_each ( ) {
fn test_smart_split_prefix_each ( ) {
let to_split = "1234\n56\n7" ;
let to_split = "1234\n56\n7" ;
let parts = super ::smart_split ( to_split , Some ( "PREFIX" . to_string ( ) ) , 10 ) ;
let parts = super ::smart_split ( to_split , Some ( "PREFIX" . to_string ( ) ) , 10 ) ;
assert_eq! ( vec! [ "PREFIX1234" . to_string ( ) , "PREFIX56\n7" . to_string ( ) , ] , parts ) ;
assert_eq! ( vec! [ "PREFIX1234" . to_string ( ) , "PREFIX56\n7" . to_string ( ) ] , parts ) ;
}
}
#[ test ]
#[ test ]
@ -973,7 +943,7 @@ mod test {
let to_split = "one two threefourfive six" ;
let to_split = "one two threefourfive six" ;
let parts = super ::smart_split ( to_split , None , 10 ) ;
let parts = super ::smart_split ( to_split , None , 10 ) ;
assert_eq! (
assert_eq! (
vec! [ "one two" . to_string ( ) , "threefourf" . to_string ( ) , "ive six" . to_string ( ) , ] ,
vec! [ "one two" . to_string ( ) , "threefourf" . to_string ( ) , "ive six" . to_string ( ) ] ,
parts
parts
) ;
) ;
}
}