pleroma groups!!!!!! try it ->
https://piggo.space/hob
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
626 lines
22 KiB
626 lines
22 KiB
4 years ago
|
use std::collections::HashSet;
|
||
|
use std::time::Duration;
|
||
|
|
||
|
use elefren::{FediClient, SearchType, StatusBuilder};
|
||
|
use elefren::entities::prelude::Status;
|
||
|
use elefren::status_builder::Visibility;
|
||
|
|
||
|
use crate::command::StatusCommand;
|
||
|
use crate::error::GroupError;
|
||
|
use crate::group_handler::GroupHandle;
|
||
|
use crate::store::data::GroupConfig;
|
||
|
use crate::utils::{LogError, normalize_acct};
|
||
|
|
||
|
pub struct ProcessMention<'a> {
|
||
|
status: Status,
|
||
|
config: &'a mut GroupConfig,
|
||
|
client: &'a mut FediClient,
|
||
|
group_acct: String,
|
||
|
status_acct: String,
|
||
|
status_user_id: String,
|
||
|
can_write: bool,
|
||
|
is_admin: bool,
|
||
|
replies: Vec<String>,
|
||
|
announcements: Vec<String>,
|
||
|
do_boost_prev_post: bool,
|
||
|
want_markdown: bool,
|
||
|
}
|
||
|
|
||
|
impl<'a> ProcessMention<'a> {
|
||
|
async fn lookup_acct_id(&self, acct: &str, followed: bool) -> Result<Option<String>, GroupError> {
|
||
|
debug!("Looking up user ID by acct: {}", acct);
|
||
|
|
||
|
match tokio::time::timeout(Duration::from_secs(5), self.client.search_v2(
|
||
|
acct,
|
||
|
!followed,
|
||
|
Some(SearchType::Accounts),
|
||
|
Some(1),
|
||
|
followed,
|
||
|
)).await {
|
||
|
Err(_) => {
|
||
|
warn!("Account lookup timeout!");
|
||
|
Err(GroupError::ApiTimeout)
|
||
|
}
|
||
|
Ok(Err(e)) => {
|
||
|
// Elefren error
|
||
|
Err(e.into())
|
||
|
}
|
||
|
Ok(Ok(res)) => {
|
||
|
if let Some(item) = res.accounts.into_iter().next() {
|
||
|
debug!("Search done, account found");
|
||
|
Ok(Some(item.id))
|
||
|
} else {
|
||
|
debug!("Search done, nothing found");
|
||
|
Ok(None)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn append_admin_list_to_reply(&mut self) {
|
||
|
let mut admins = self.config.get_admins().collect::<Vec<_>>();
|
||
|
admins.sort();
|
||
|
for a in admins {
|
||
|
self.replies.push(a.to_string());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn append_member_list_to_reply(&mut self) {
|
||
|
let admins = self.config.get_admins().collect::<HashSet<_>>();
|
||
|
let mut members = self.config.get_members().collect::<Vec<_>>();
|
||
|
members.extend(admins.iter());
|
||
|
members.sort();
|
||
|
members.dedup();
|
||
|
for m in members {
|
||
|
self.replies.push(if admins.contains(&m) {
|
||
|
format!("{} [admin]", m)
|
||
|
} else {
|
||
|
m.to_string()
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn follow_user(&self, id: &str) -> Result<(), GroupError> {
|
||
|
self.client.follow(id).await?;
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
async fn unfollow_user(&self, id: &str) -> Result<(), GroupError> {
|
||
|
self.client.unfollow(id).await?;
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
pub(crate) async fn run(gh: &'a mut GroupHandle, status: Status) -> Result<(), GroupError> {
|
||
|
let group_acct = gh.config.get_acct().to_string();
|
||
|
let status_acct = normalize_acct(&status.account.acct, &group_acct)?.to_string();
|
||
|
|
||
|
if gh.config.is_banned(&status_acct) {
|
||
|
warn!("Status author {} is banned!", status_acct);
|
||
|
return Ok(());
|
||
|
}
|
||
|
|
||
|
let pm = Self {
|
||
|
status_user_id: status.account.id.to_string(),
|
||
|
client: &mut gh.client,
|
||
|
can_write: gh.config.can_write(&status_acct),
|
||
|
is_admin: gh.config.is_admin(&status_acct),
|
||
|
replies: vec![],
|
||
|
announcements: vec![],
|
||
|
do_boost_prev_post: false,
|
||
|
want_markdown: false,
|
||
|
group_acct,
|
||
|
status_acct,
|
||
|
status,
|
||
|
config: &mut gh.config,
|
||
|
};
|
||
|
|
||
|
pm.handle().await
|
||
|
}
|
||
|
|
||
|
async fn reblog_status(&self) {
|
||
|
self.client.reblog(&self.status.id)
|
||
|
.await
|
||
|
.log_error("Failed to reblog status")
|
||
|
}
|
||
|
|
||
|
fn add_reply(&mut self, line: impl ToString) {
|
||
|
self.replies.push(line.to_string())
|
||
|
}
|
||
|
|
||
|
fn add_announcement(&mut self, line: impl ToString) {
|
||
|
self.announcements.push(line.to_string())
|
||
|
}
|
||
|
|
||
|
async fn handle(mut self) -> Result<(), GroupError> {
|
||
|
let commands = crate::command::parse_slash_commands(&self.status.content);
|
||
|
|
||
|
if commands.is_empty() {
|
||
|
self.handle_post_with_no_commands().await;
|
||
|
} else {
|
||
|
if commands.contains(&StatusCommand::Ignore) {
|
||
|
debug!("Notif ignored because of ignore command");
|
||
|
return Ok(());
|
||
|
}
|
||
|
|
||
|
for cmd in commands {
|
||
|
match cmd {
|
||
|
StatusCommand::Ignore => {
|
||
|
unreachable!(); // Handled above
|
||
|
}
|
||
|
StatusCommand::Announce(a) => {
|
||
|
self.cmd_announce(a).await;
|
||
|
}
|
||
|
StatusCommand::Boost => {
|
||
|
self.cmd_boost().await;
|
||
|
}
|
||
|
StatusCommand::BanUser(u) => {
|
||
|
self.cmd_ban_user(&u).await
|
||
|
.log_error("Error handling ban-user cmd");
|
||
|
}
|
||
|
StatusCommand::UnbanUser(u) => {
|
||
|
self.cmd_unban_user(&u).await
|
||
|
.log_error("Error handling unban-user cmd");
|
||
|
}
|
||
|
StatusCommand::BanServer(s) => {
|
||
|
self.cmd_ban_server(&s).await;
|
||
|
}
|
||
|
StatusCommand::UnbanServer(s) => {
|
||
|
self.cmd_unban_server(&s).await;
|
||
|
}
|
||
|
StatusCommand::AddMember(u) => {
|
||
|
self.cmd_add_member(&u).await
|
||
|
.log_error("Error handling add-member cmd");
|
||
|
}
|
||
|
StatusCommand::RemoveMember(u) => {
|
||
|
self.cmd_remove_member(&u).await
|
||
|
.log_error("Error handling remove-member cmd");
|
||
|
}
|
||
|
StatusCommand::AddTag(tag) => {
|
||
|
self.cmd_add_tag(tag).await;
|
||
|
}
|
||
|
StatusCommand::RemoveTag(tag) => {
|
||
|
self.cmd_remove_tag(tag).await;
|
||
|
}
|
||
|
StatusCommand::GrantAdmin(u) => {
|
||
|
self.cmd_grant_member(&u).await
|
||
|
.log_error("Error handling grant-admin cmd");
|
||
|
}
|
||
|
StatusCommand::RemoveAdmin(u) => {
|
||
|
self.cmd_revoke_member(&u).await
|
||
|
.log_error("Error handling grant-admin cmd");
|
||
|
}
|
||
|
StatusCommand::OpenGroup => {
|
||
|
self.cmd_open_group().await;
|
||
|
}
|
||
|
StatusCommand::CloseGroup => {
|
||
|
self.cmd_close_group().await;
|
||
|
}
|
||
|
StatusCommand::Help => {
|
||
|
self.cmd_help().await;
|
||
|
}
|
||
|
StatusCommand::ListMembers => {
|
||
|
self.cmd_list_members().await;
|
||
|
}
|
||
|
StatusCommand::ListTags => {
|
||
|
self.cmd_list_tags().await;
|
||
|
}
|
||
|
StatusCommand::Leave => {
|
||
|
self.cmd_leave().await;
|
||
|
}
|
||
|
StatusCommand::Join => {
|
||
|
self.cmd_join().await;
|
||
|
}
|
||
|
StatusCommand::Ping => {
|
||
|
self.cmd_ping().await;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if self.do_boost_prev_post {
|
||
|
self.client
|
||
|
.reblog(self.status.in_reply_to_id.as_ref().unwrap())
|
||
|
.await
|
||
|
.log_error("Failed to boost");
|
||
|
}
|
||
|
|
||
|
if !self.replies.is_empty() {
|
||
|
debug!("replies={:?}", self.replies);
|
||
|
let r = self.replies.join("\n");
|
||
|
debug!("r={}", r);
|
||
|
|
||
|
if let Ok(post) = StatusBuilder::new()
|
||
|
.status(format!("@{user}\n{msg}", user = self.status_acct, msg = r))
|
||
|
.content_type(if self.want_markdown {
|
||
|
"text/markdown"
|
||
|
} else {
|
||
|
"text/plain"
|
||
|
})
|
||
|
.visibility(self.status.visibility) // Copy visibility
|
||
|
.build()
|
||
|
{
|
||
|
let _ = self.client.new_status(post)
|
||
|
.await.log_error("Failed to post");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !self.announcements.is_empty() {
|
||
|
let msg = self.announcements.join("\n");
|
||
|
let post = StatusBuilder::new()
|
||
|
.status(format!("**📢 Group announcement**\n{msg}", msg = msg))
|
||
|
.content_type("text/markdown")
|
||
|
.visibility(Visibility::Public)
|
||
|
.build()
|
||
|
.expect("error build status");
|
||
|
|
||
|
let _ = self.client.new_status(post)
|
||
|
.await.log_error("Failed to post");
|
||
|
}
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
async fn handle_post_with_no_commands(&mut self) {
|
||
|
debug!("No commands in post");
|
||
|
if self.status.in_reply_to_id.is_none() {
|
||
|
if self.can_write {
|
||
|
// Someone tagged the group in OP, boost it.
|
||
|
info!("Boosting OP mention");
|
||
|
// tokio::time::sleep(DELAY_BEFORE_ACTION).await;
|
||
|
self.reblog_status().await;
|
||
|
} else {
|
||
|
self.add_reply("You are not allowed to post to this group");
|
||
|
}
|
||
|
} else {
|
||
|
debug!("Not OP, ignore mention");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_announce(&mut self, msg: String) {
|
||
|
info!("Sending PSA");
|
||
|
self.add_announcement(msg);
|
||
|
}
|
||
|
|
||
|
async fn cmd_boost(&mut self) {
|
||
|
if self.can_write {
|
||
|
self.do_boost_prev_post = self.status.in_reply_to_id.is_some();
|
||
|
} else {
|
||
|
self.add_reply("You are not allowed to share to this group");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_ban_user(&mut self, user: &str) -> Result<(), GroupError> {
|
||
|
let u = normalize_acct(user, &self.group_acct)?;
|
||
|
if self.is_admin {
|
||
|
if !self.config.is_banned(&u) {
|
||
|
match self.config.ban_user(&u, true) {
|
||
|
Ok(_) => {
|
||
|
self.add_reply(format!("User {} banned from group!", u));
|
||
|
self.unfollow_by_acct(&u).await
|
||
|
.log_error("Failed to unfollow banned user");
|
||
|
}
|
||
|
Err(e) => {
|
||
|
self.add_reply(format!("Failed to ban user {}: {}", u, e));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage user bans");
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
async fn cmd_unban_user(&mut self, user: &str) -> Result<(), GroupError> {
|
||
|
let u = normalize_acct(user, &self.group_acct)?;
|
||
|
if self.is_admin {
|
||
|
if self.config.is_banned(&u) {
|
||
|
match self.config.ban_user(&u, false) {
|
||
|
Ok(_) => {
|
||
|
self.add_reply(format!("User {} un-banned!", u));
|
||
|
// no announcement here
|
||
|
}
|
||
|
Err(_) => {
|
||
|
unreachable!()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage user bans");
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
async fn cmd_ban_server(&mut self, s: &str) {
|
||
|
if self.is_admin {
|
||
|
if !self.config.is_server_banned(s) {
|
||
|
match self.config.ban_server(s, true) {
|
||
|
Ok(_) => {
|
||
|
self.add_announcement(format!("Server \"{}\" has been banned.", s));
|
||
|
self.add_reply(format!("Server {} banned from group!", s));
|
||
|
}
|
||
|
Err(e) => {
|
||
|
self.add_reply(format!("Failed to ban server {}: {}", s, e));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage server bans");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_unban_server(&mut self, s: &str) {
|
||
|
if self.is_admin {
|
||
|
if self.config.is_server_banned(s) {
|
||
|
match self.config.ban_server(s, false) {
|
||
|
Ok(_) => {
|
||
|
self.add_announcement(format!("Server \"{}\" has been un-banned.", s));
|
||
|
self.add_reply(format!("Server {} un-banned!", s));
|
||
|
}
|
||
|
Err(_) => {
|
||
|
unreachable!()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage server bans");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_add_member(&mut self, user: &str) -> Result<(), GroupError> {
|
||
|
let u = normalize_acct(user, &self.group_acct)?;
|
||
|
if self.is_admin {
|
||
|
if !self.config.is_member(&u) {
|
||
|
match self.config.set_member(&u, true) {
|
||
|
Ok(_) => {
|
||
|
self.add_reply(format!("User {} added to the group!", u));
|
||
|
self.follow_user(&self.status_user_id)
|
||
|
.await.log_error("Failed to follow");
|
||
|
}
|
||
|
Err(e) => {
|
||
|
self.add_reply(format!("Failed to add user {} to group: {}", u, e));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage members");
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
async fn cmd_remove_member(&mut self, user: &str) -> Result<(), GroupError> {
|
||
|
let u = normalize_acct(user, &self.group_acct)?;
|
||
|
if self.is_admin {
|
||
|
if self.config.is_member(&u) {
|
||
|
match self.config.set_member(&u, false) {
|
||
|
Ok(_) => {
|
||
|
self.add_reply(format!("User {} removed from the group.", u));
|
||
|
self.unfollow_by_acct(&u).await
|
||
|
.log_error("Failed to unfollow removed user");
|
||
|
}
|
||
|
Err(_) => {
|
||
|
unreachable!()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage members");
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
async fn cmd_add_tag(&mut self, tag: String) {
|
||
|
if self.is_admin {
|
||
|
self.config.add_tag(&tag);
|
||
|
self.add_reply(format!("Tag #{} added to the group!", tag));
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage group tags");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_remove_tag(&mut self, tag: String) {
|
||
|
if self.is_admin {
|
||
|
self.config.remove_tag(&tag);
|
||
|
self.add_reply(format!("Tag #{} removed from the group!", tag));
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage group tags");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_grant_member(&mut self, user: &str) -> Result<(), GroupError> {
|
||
|
let u = normalize_acct(user, &self.group_acct)?;
|
||
|
if self.is_admin {
|
||
|
if !self.config.is_admin(&u) {
|
||
|
match self.config.set_admin(&u, true) {
|
||
|
Ok(_) => {
|
||
|
// try to make the config a little more sane, admins should be members
|
||
|
let _ = self.config.set_member(&u, true);
|
||
|
|
||
|
self.add_reply(format!("User {} is now a group admin!", u));
|
||
|
self.add_announcement(format!("User @{} can now manage this group!", u));
|
||
|
}
|
||
|
Err(e) => {
|
||
|
self.add_reply(format!(
|
||
|
"Failed to make user {} a group admin: {}",
|
||
|
u, e
|
||
|
));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage admins");
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
async fn cmd_revoke_member(&mut self, user: &str) -> Result<(), GroupError> {
|
||
|
let u = normalize_acct(user, &self.group_acct)?;
|
||
|
if self.is_admin {
|
||
|
if self.config.is_admin(&u) {
|
||
|
match self.config.set_admin(&u, false) {
|
||
|
Ok(_) => {
|
||
|
self.add_reply(format!("User {} is no longer a group admin!", u));
|
||
|
self.add_announcement(format!("User @{} no longer manages this group.", u));
|
||
|
}
|
||
|
Err(e) => {
|
||
|
self.add_reply(format!("Failed to revoke {}'s group admin: {}", u, e));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can manage admins");
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
async fn cmd_open_group(&mut self) {
|
||
|
if self.is_admin {
|
||
|
if self.config.is_member_only() {
|
||
|
self.config.set_member_only(false);
|
||
|
self.add_reply("Group changed to open-access");
|
||
|
self.add_announcement("This group is now open-access!");
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can set group options");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_close_group(&mut self) {
|
||
|
if self.is_admin {
|
||
|
if !self.config.is_member_only() {
|
||
|
self.config.set_member_only(true);
|
||
|
self.add_reply("Group changed to member-only");
|
||
|
self.add_announcement("This group is now member-only!");
|
||
|
}
|
||
|
} else {
|
||
|
self.add_reply("Only admins can set group options");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_help(&mut self) {
|
||
|
self.want_markdown = true;
|
||
|
|
||
|
if self.config.is_member_only() {
|
||
|
self.add_reply("This is a member-only group. ");
|
||
|
} else {
|
||
|
self.add_reply("This is a public-access group. ");
|
||
|
}
|
||
|
|
||
|
if self.config.can_write(&self.status_acct) {
|
||
|
if self.is_admin {
|
||
|
self.add_reply("*You are an admin.*");
|
||
|
} else {
|
||
|
self.add_reply("*You are a member.*");
|
||
|
}
|
||
|
} else {
|
||
|
if self.config.is_member_only() {
|
||
|
self.add_reply("*You are not a member, ask one of the admins to add you.*");
|
||
|
} else {
|
||
|
self.add_reply("*You are not a member, follow or use /join to join the group.*");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
self.add_reply("\n\
|
||
|
To share an original post, mention the group user.\n\
|
||
|
Replies and mentions with commands won't be shared.\n\
|
||
|
\n\
|
||
|
**Supported commands:**\n\
|
||
|
`/boost, /b` - boost the replied-to post into the group\n\
|
||
|
`/ignore, /i` - make the group completely ignore the post\n\
|
||
|
`/ping` - check that the service is alive\n\
|
||
|
`/join` - join the group\n\
|
||
|
`/leave` - leave the group");
|
||
|
|
||
|
if self.config.is_member_only() {
|
||
|
self.add_reply("`/members, /who` - show group members / admins");
|
||
|
} else {
|
||
|
self.add_reply("`/members, /who` - show group admins");
|
||
|
}
|
||
|
|
||
|
if self.is_admin {
|
||
|
self.add_reply("\n\
|
||
|
**Admin commands:**\n\
|
||
|
`/add user` - add a member (use e-mail style address)\n\
|
||
|
`/kick, /remove user` - kick a member\n\
|
||
|
`/ban x` - ban a user or a server\n\
|
||
|
`/unban x` - lift a ban\n\
|
||
|
`/op, /admin user` - grant admin rights\n\
|
||
|
`/deop, /deadmin user` - revoke admin rights\n\
|
||
|
`/opengroup` - make member-only\n\
|
||
|
`/closegroup` - make public-access\n\
|
||
|
`/announce x` - make a public announcement from the rest of the status");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_list_members(&mut self) {
|
||
|
if self.is_admin {
|
||
|
self.add_reply("Group members:");
|
||
|
self.append_member_list_to_reply();
|
||
|
} else {
|
||
|
self.add_reply("Group admins:");
|
||
|
self.append_admin_list_to_reply();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_list_tags(&mut self) {
|
||
|
self.add_reply("Group tags:");
|
||
|
let mut tags = self.config.get_tags().collect::<Vec<_>>();
|
||
|
tags.sort();
|
||
|
for t in tags {
|
||
|
self.replies.push(format!("#{}", t).to_string());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_leave(&mut self) {
|
||
|
if self.config.is_member_or_admin(&self.status_acct) {
|
||
|
// admin can leave but that's a bad idea
|
||
|
let _ = self.config.set_member(&self.status_acct, false);
|
||
|
self.add_reply("You're no longer a group member. Unfollow the group user to stop receiving group messages.");
|
||
|
self.unfollow_user(&self.status_user_id).await
|
||
|
.log_error("Failed to unfollow");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn cmd_join(&mut self) {
|
||
|
if self.config.is_member_or_admin(&self.status_acct) {
|
||
|
debug!("Already member or admin, try to follow-back again");
|
||
|
// Already a member, so let's try to follow the user
|
||
|
// again, maybe first time it failed
|
||
|
self.follow_user(&self.status_user_id).await
|
||
|
.log_error("Failed to follow");
|
||
|
} else {
|
||
|
// Not a member yet
|
||
|
if self.config.is_member_only() {
|
||
|
// No you can't
|
||
|
self.add_reply("\
|
||
|
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();
|
||
|
} else {
|
||
|
// Open access, try to follow back
|
||
|
self.follow_user(&self.status_user_id).await
|
||
|
.log_error("Failed to follow");
|
||
|
|
||
|
// This only fails if the user is banned, but that is filtered above
|
||
|
let _ = self.config.set_member(&self.status_acct, true);
|
||
|
self.add_reply("\
|
||
|
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) {
|
||
|
self.add_reply(format!("pong, this is fedigroups service v{}", env!("CARGO_PKG_VERSION")));
|
||
|
}
|
||
|
|
||
|
async fn unfollow_by_acct(&self, acct: &str) -> Result<(), GroupError> {
|
||
|
// Try to unfollow
|
||
|
if let Ok(Some(id)) = self.lookup_acct_id(acct, true).await {
|
||
|
self.unfollow_user(&id).await?;
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
}
|