2021-08-05 10:14:46 +02:00
#!/bin/sh
2023-11-16 23:15:45 +01:00
set -f
2023-11-18 21:18:16 +01:00
# create a default config when started with --init
initConfig( ) {
2023-11-16 23:15:45 +01:00
(
cat <<EOF
LOWERLIMIT = "6 months" # all accounts below 6 months inactivity are safe, start notifiying them when >6 months
UPPERLIMIT = "7 months" # inactive accounts older than 7 months will be deactivated
DELDELIMIT = "1 year" # all accounts not used within a year will get deleted
LIVE_PATH = " ${ HOME } /live/ " # Path to live data from mastodon
TOOTCTL = " ${ HOME } /live/bin/tootctl "
SITE = "Mastodon"
SITEADMIN = "root@localhost"
PROTECTEDUSERS = "user foo bar baz"
SQLPROTECTEDUSERS = "'user', 'foo', 'bar', 'baz'"
LIMIT_DELETE = "2"
EOF
2023-11-18 21:18:16 +01:00
) > " ${ HOME } " /.cleanup-mastodon-users.conf
echo "✅ - Configuration file created. You can now edit " ${ HOME } "/.cleanup-mastodon-users.conf"
2023-10-25 15:46:46 +02:00
}
2023-08-17 19:25:27 +00:00
2021-08-05 10:14:46 +02:00
case $1 in
2023-11-18 21:18:16 +01:00
"--init" )
initConfig
exit 0
; ;
2021-08-05 10:14:46 +02:00
"--dry-run" )
mode = "dryrun"
; ;
2023-08-17 19:25:27 +00:00
"--cron" )
mode = "cron"
; ;
2021-08-05 10:14:46 +02:00
"--dowhatimean" )
mode = "hotrun"
; ;
*)
echo "Usage: "
2023-11-18 21:18:16 +01:00
echo " --init \t \t: create $0 /.cleanup-mastodon-users.conf config file. "
2021-08-05 10:14:46 +02:00
echo " --dry-run \t: make a dry-run, no deletion will be done, no mails are sent."
2023-08-17 19:25:27 +00:00
echo " --cron \t: delete deactivated users in a regularly cron run step by step to avoid mass flooding."
2021-08-05 10:14:46 +02:00
echo " --dowhatimean \t: add this option if you really want to delete users."
2023-11-18 21:18:16 +01:00
echo ""
if [ ! -f " ${ HOME } " /.cleanup-mastodon-users.conf ] ; then
echo "❌ - No configuration file found!"
echo " Please start with \" $0 --init\" to create config files "
echo " and edit the file \" ${ HOME } /.cleanup-mastodon-users.conf\" to your needs. "
exit 0
fi
2021-08-05 10:14:46 +02:00
exit 0
; ;
esac
2023-11-18 21:18:16 +01:00
. " ${ HOME } " /.cleanup-mastodon-users.conf
LOWERLIMIT = " ${ LOWERLIMIT :- '6 months' } " # all accounts below 6 months inactivity are safe, start notifiying them when >6 months
UPPERLIMIT = " ${ UPPERLIMIT :- '7 months' } " # inactive accounts older than 7 months will be deactivated
DELDELIMIT = " ${ DELDELIMIT :- '1 year' } " # all accounts not used within a year will get deleted
LIVE_PATH = " ${ LIVE_PATH :- ${ HOME } /live/ } " # Path to live data from mastodon
TOOTCTL = " ${ TOOTCTL :- ${ HOME } /bin/tootctl } "
SITE = " ${ SITE :- $LOCAL_DOMAIN } "
SITEADMIN = " ${ SITEADMIN :- root @localhost } "
LIMIT_DELETE = " ${ LIMIT_DELETE :- 2 } "
cd " ${ LIVE_PATH } " || exit
# shellcheck source=/dev/null
. " ${ LIVE_PATH } /.env.production " 2>/dev/null
run_tootctl( ) {
" ${ TOOTCTL } " " $@ "
}
num_notified = 0
num_disabled = 0
num_deleted = 0
STARTDATE = $( date +"%d.%m.%Y %H:%M:%S" )
2023-10-25 15:46:46 +02:00
# make a list to be used for grep -E
2023-11-16 23:15:45 +01:00
PROTECTED = $( echo " $PROTECTEDUSERS " | sed 's/\"//g' | sed 's/\ /\\\|/g' )
#echo $PROTECTED
2021-08-05 10:14:46 +02:00
2023-11-18 21:18:16 +01:00
2021-08-05 10:14:46 +02:00
# notify the user that s/he needs to re-login after 6 months to prevent account deletion
2023-10-25 15:46:46 +02:00
notifyUser( ) {
(
cat <<EOF
Dear ${ dispname } ,
2021-08-05 10:14:46 +02:00
2023-10-25 15:46:46 +02:00
you have registered your account on ${ LOCAL_DOMAIN } at ${ registered } and last time you logged in was at ${ lastlogin } .
2021-08-05 10:14:46 +02:00
2023-10-25 15:46:46 +02:00
If you want to continue to keep your Mastodon account on Nerdculture then please log in at least every 6 months via web browser to keep your account alive. Otherwise we assume that you don' t want to use it anymore and will deactivate your account 7 months after your last login ( and delete it later) .
2021-08-05 10:14:46 +02:00
2023-10-25 15:46:46 +02:00
You can access your profile at ${ profileurl } or you can cancel your account on your own when logged in at ${ LOCAL_DOMAIN } removeme - however we would like to see you become an active user again and contribute to the Fediverse, but of course it' s up to you.
2021-08-05 10:14:46 +02:00
Sincerely,
2023-11-16 23:15:45 +01:00
your ${ SITE } admins
2023-10-25 15:46:46 +02:00
2021-08-05 10:14:46 +02:00
EOF
2023-10-25 15:46:46 +02:00
) | sed 's/_/\ /g' | /usr/bin/mail -s " The Fediverse misses you, ${ username } ! " -r " ${ SMTP_FROM_ADDRESS } " -- " ${ usermail } "
2023-11-16 23:15:45 +01:00
# add '-b "$SITEADMIN"' before the "--" above to receive BCC mails
2023-08-17 19:25:27 +00:00
#((num_notified++))
}
# notify user that the account has been deleted because of inactivity
2023-10-25 15:46:46 +02:00
notifyUserDisable( ) {
(
cat <<EOF
Dear ${ dispname } ,
2023-08-17 19:25:27 +00:00
2023-10-25 15:46:46 +02:00
you have registered your account on ${ LOCAL_DOMAIN } at ${ registered } and last time you logged in was at ${ lastlogin } .
2023-08-17 19:25:27 +00:00
2023-10-25 15:46:46 +02:00
Since you haven't reacted to the previous mails and didn' t login again, your account including all your data has now been deactivated and will be deleted at a ( random) later time.
2023-08-17 19:25:27 +00:00
Sincerely,
2023-11-16 23:15:45 +01:00
your ${ SITE } admins
2023-10-25 15:46:46 +02:00
2023-08-17 19:25:27 +00:00
EOF
2023-11-16 23:15:45 +01:00
) | sed 's/_/\ /g' | /usr/bin/mail -s " Your account ${ username } on ${ SITE } has been deleted! " -r " ${ SMTP_FROM_ADDRESS } " -- " ${ usermail } "
# add '-b "$SITEADMIN"' before the "--" above to receive BCC mails
2021-08-05 10:14:46 +02:00
}
# notify user that the account has been deleted because of inactivity
2023-10-25 15:46:46 +02:00
notifyUserDeletion( ) {
(
cat <<EOF
Dear ${ dispname } ,
2021-08-05 10:14:46 +02:00
2023-10-25 15:46:46 +02:00
you have registered your account on ${ LOCAL_DOMAIN } at ${ registered } and last time you logged in was at ${ lastlogin } .
2021-08-05 10:14:46 +02:00
2023-10-25 15:46:46 +02:00
Since you haven't reacted to the previous mails and didn' t login again, your account including all your data has now been deleted.
2021-08-05 10:14:46 +02:00
Sincerely,
2023-11-16 23:15:45 +01:00
your ${ SITE } admins
2023-10-25 15:46:46 +02:00
2021-08-05 10:14:46 +02:00
EOF
2023-11-16 23:15:45 +01:00
) | sed 's/_/\ /g' | /usr/bin/mail -s " Your account ${ username } on ${ SITE } has been deleted! " -r " ${ SMTP_FROM_ADDRESS } " -- " ${ usermail } "
# add '-b "$SITEADMIN"' before the "--" above to receive BCC mails
2021-08-05 10:14:46 +02:00
}
2023-08-17 19:25:27 +00:00
# delete users that never logged in and never posted content
2023-10-25 15:46:46 +02:00
# filtering for "weeks" will result in accounts with 2 weeks old accounts,
2023-08-17 19:25:27 +00:00
# filter for just "week" will do the same after 1 week.
# same should apply to "month" and "months", but untested.
2023-10-25 15:46:46 +02:00
#for username in $( "${TOOTCTL}" user list active -c 10000 | grep 'never.*never' | grep weeks | awk '{print $2}') ; do
2023-08-17 19:25:27 +00:00
# select a.id, username, email, current_sign_in_at from accounts a, users u where domain is null and a.id=u.account_id and current_sign_in_at <'2019-01-01'
case ${ mode } in
2023-11-18 21:18:16 +01:00
"init" )
initConfig
; ;
2023-08-17 19:25:27 +00:00
"cron" )
2023-10-25 15:46:46 +02:00
# get the total number of deactivated accounts
2023-08-17 19:25:27 +00:00
# the intention is that you can better judge how often you need to invoke the cron option
2023-11-18 21:18:16 +01:00
# or by increasing the LIMIT_DELETE variable
2023-08-17 19:25:27 +00:00
# the backlog queue shouldn't pile up but also not run empty to fast to reduce the load
2023-11-16 23:15:45 +01:00
num_deactivated_overgrace = $( psql -U " ${ DB_USER } " -w -h " ${ DB_HOST } " -p " ${ DB_PORT } " -t " ${ DB_NAME } " -c " select count(username) from accounts a, users u where disabled is true and a.id=u.account_id and current_sign_in_at < now()-' ${ DELDELIMIT } '::interval and username not in ( $SQLPROTECTEDUSERS ) " | tr -d " " )
num_deactivated_total = $( psql -U " ${ DB_USER } " -w -h " ${ DB_HOST } " -p " ${ DB_PORT } " -t " ${ DB_NAME } " -c " select count(username) from accounts a, users u where disabled is true and a.id=u.account_id and username not in ( $SQLPROTECTEDUSERS ) " | tr -d " " )
2023-08-17 19:25:27 +00:00
# when there is less then 1 user to delete (=0) then exit
2023-10-25 15:46:46 +02:00
if [ " ${ num_deactivated_overgrace } " -lt 1 ] ; then
2023-08-17 19:25:27 +00:00
exit 0
2021-08-05 10:14:46 +02:00
fi
2023-08-17 19:25:27 +00:00
echo "==================================="
2023-08-20 17:11:49 +00:00
echo " Total deactivated accounts: ${ num_deactivated_total } "
echo " Number deactivated accounts over grace: ${ num_deactivated_overgrace } "
2023-11-18 21:18:16 +01:00
echo " Deleting this many accounts: ${ LIMIT_DELETE } "
2023-08-17 19:25:27 +00:00
echo "==================================="
2023-11-18 21:18:16 +01:00
for u in $( psql -U " ${ DB_USER } " -w -h " ${ DB_HOST } " -p " ${ DB_PORT } " -t " ${ DB_NAME } " -c " select concat(username||';'||display_name||';'||email||';'||to_char(a.created_at, 'YYYY-MM-DD')||';'||to_char(current_sign_in_at,'YYYY-MM-DD')) from accounts a, users u where disabled is true and a.id=u.account_id and current_sign_in_at < now()-' ${ DELDELIMIT } '::interval and username not in ( $SQLPROTECTEDUSERS ) order by current_sign_in_at limit ${ LIMIT_DELETE } " | tr -d " " ) ; do
2023-08-17 19:25:27 +00:00
#echo ${u}
username = $( echo " ${ u } " | awk -F ";" '{print $1}' )
dispname = $( echo " ${ u } " | awk -F ";" '{print $2}' )
profileurl = " https://nerdculture.de/@ ${ username } "
usermail = $( echo " ${ u } " | awk -F ";" '{print $3}' )
registered = $( echo " ${ u } " | awk -F ";" '{print $4}' )
lastlogin = $( echo " ${ u } " | awk -F ";" '{print $5}' )
# delete account when last login is older than 7 months and send mail about deletion
# you should copy & paste the text from 6 months for the first runs of this script
2023-10-25 15:46:46 +02:00
# and later change the text to a notification that the account has been deleted.
2023-11-16 23:15:45 +01:00
# if username is a PROTECTED user do nothing, else delete user
2023-08-17 19:25:27 +00:00
echo -n " ${ username } : "
2023-10-25 15:46:46 +02:00
run_tootctl accounts delete " ${ username } "
2023-08-17 19:25:27 +00:00
notifyUserDeletion
num_deleted = $(( num_deleted+1))
RND = $( date +%s)
sec = $(( $RND % 60 ))
ms = $(( $RND % 23 ))
2023-10-25 15:46:46 +02:00
sleep ${ sec } .${ ms }
2023-08-17 19:25:27 +00:00
done
; ;
*)
# find & notify users that didn't logged in >6 months and send mail to log in again#psql -U ${DB_USER} -w -h ${DB_HOST} -p ${DB_PORT} -t ${DB_NAME} -c "select concat(username||';'||email) from accounts a, users u where domain is null and a.id=u.account_id and current_sign_in_at is null and u.created_at < now()-'2 weeks'::interval" | tr -d " "
#for username in $(psql -U ${DB_USER} -w -h ${DB_HOST} -p ${DB_PORT} -t ${DB_NAME} -c "select a.id, username, email, current_sign_in_at from accounts a, users u where domain is null and a.id=u.account_id and current_sign_in_at <'2019-01-01'" )
2023-11-18 21:18:16 +01:00
for line in $( psql -U " ${ DB_USER } " -w -h " ${ DB_HOST } " -p " ${ DB_PORT } " -t " ${ DB_NAME } " -c " select concat(username||','||email) from accounts a, users u where domain is null and disabled is false and a.id=u.account_id and current_sign_in_at is null and u.created_at < now()-'2 weeks'::interval and username not in ( ${ SQLPROTECTEDUSERS } ) " | tr -d " " ) ; do
2023-08-17 19:25:27 +00:00
#echo ${line}
2023-10-25 15:46:46 +02:00
username = $( echo " ${ line } " | cut -f1 -d"," )
mail = $( echo " ${ line } " | cut -f2 -d"," )
2023-11-16 23:15:45 +01:00
# if username is a PROTECTED user do nothing, else delete user
if [ -n " ${ PROTECTEDUSERS } " ] ; then
2023-08-17 19:25:27 +00:00
pcheck = 0
2023-11-16 23:15:45 +01:00
for s in ${ PROTECTEDUSERS } ; do
2023-08-17 19:25:27 +00:00
if [ " ${ s } " = " ${ username } " ] ; then
pcheck = 1
fi
done
if [ ${ pcheck } -eq 0 ] ; then
echo " Delete unconfirmed user ${ username } "
if [ " ${ mode } " = "hotrun" ] ; then
2023-10-25 15:46:46 +02:00
run_tootctl accounts delete " ${ username } "
2023-08-17 19:25:27 +00:00
elif [ " ${ mode } " = "dryrun" ] ; then
echo " ${ username } : skipped because of dryrun. "
fi
2021-08-05 10:14:46 +02:00
fi
2023-08-17 19:25:27 +00:00
fi
done
2023-11-16 23:15:45 +01:00
#for u in $( ${LIVE_PATH}/bin/console user list active -c 10000 | grep -v '.*---.*' | sed 's/|/;/g' | tr -s "\ " | sed 's/^;\ //g' | sed 's/\ ;\ /;/g' | sed 's/\ /_/g' | tail -n +2 | grep -i -v -E ${PROTECTED} ); do
2023-08-17 19:25:27 +00:00
for mode2 in $( echo "warn disable" ) ; do
#echo "mode2: $mode2"
case ${ mode2 } in
"warn" )
#echo "in warn"
2023-10-25 15:46:46 +02:00
SQLSTATE = " current_sign_in_at between now()-' ${ UPPERLIMIT } '::interval and now()-' ${ LOWERLIMIT } '::interval "
2023-08-17 19:25:27 +00:00
; ;
"disable" )
#echo "in disable"
2023-11-18 21:18:16 +01:00
#SQLSTATE="current_sign_in_at < now()-'${UPPERLIMIT}'::interval"
SQLSTATE = " current_sign_in_at between now()-' ${ UPPERLIMIT } '::interval and now()-' ${ UPPERLIMIT } '::interval-'1 week'::interval "
2023-08-17 19:25:27 +00:00
; ;
#"delete")
# #echo "in delete"
# SQLSTATE="current_sign_in_at < now()-'${UPPERLIMIT}'::interval"
# ;;
esac
#echo "SQL: $SQLSTATE"
2023-11-18 21:18:16 +01:00
for u in $( psql -U " ${ DB_USER } " -w -h " ${ DB_HOST } " -p " ${ DB_PORT } " -t " ${ DB_NAME } " -c " select concat(username||';'||display_name||';'||email||';'||to_char(a.created_at, 'YYYY-MM-DD')||';'||to_char(current_sign_in_at,'YYYY-MM-DD')) from accounts a, users u where domain is null and a.id=u.account_id and ${ SQLSTATE } and disabled is false and username not in ( $SQLPROTECTEDUSERS ) order by current_sign_in_at " | tr -d " " ) ; do
2023-08-17 19:25:27 +00:00
#echo ${u}
username = $( echo " ${ u } " | awk -F ";" '{print $1}' )
dispname = $( echo " ${ u } " | awk -F ";" '{print $2}' )
profileurl = " https://nerdculture.de/@ ${ username } "
usermail = $( echo " ${ u } " | awk -F ";" '{print $3}' )
registered = $( echo " ${ u } " | awk -F ";" '{print $4}' )
lastlogin = $( echo " ${ u } " | awk -F ";" '{print $5}' )
case ${ mode2 } in
"warn" )
if [ " ${ mode } " = "hotrun" ] ; then
#echo -n "hotrun "
notifyUser
elif [ " ${ mode } " = "dryrun" ] ; then
echo " Check ${ username } : notify skipped because of dryrun. "
fi
num_notified = $(( num_notified+1))
; ;
"disable" )
# delete account when last login is older than 7 months and send mail about deletion
# you should copy & paste the text from 6 months for the first runs of this script
2023-10-25 15:46:46 +02:00
# and later change the text to a notification that the account has been deleted.
2023-11-16 23:15:45 +01:00
# if username is a PROTECTED user do nothing, else delete user
2023-08-17 19:25:27 +00:00
echo -n " ${ username } : "
if [ " ${ mode } " = "hotrun" ] ; then
#echo -n "hotrun "
2023-10-25 15:46:46 +02:00
#run_tootctl accounts delete "${username}"
run_tootctl accounts modify " ${ username } " --disable
2023-08-17 19:25:27 +00:00
#notifyUserDeletion
notifyUserDisable
#echo "deleted."
elif [ " ${ mode } " = "dryrun" ] ; then
echo "will be disabled, but is skipped because of dryrun."
fi
num_disabled = $(( num_disabled+1))
2023-11-18 21:18:16 +01:00
exit
2023-08-17 19:25:27 +00:00
; ;
esac
RND = $( date +%s)
sec = $(( $RND % 5 ))
ms = $(( $RND % 23 ))
sleep ${ sec } .${ ms }
done
done
2023-11-18 21:18:16 +01:00
num_deactivated_total = $( psql -U " ${ DB_USER } " -w -h " ${ DB_HOST } " -p " ${ DB_PORT } " -t " ${ DB_NAME } " -c " select count(username) from accounts a, users u where disabled is true and a.id=u.account_id and username not in ( $SQLPROTECTEDUSERS ) " | tr -d " " )
2023-08-17 19:25:27 +00:00
; ;
esac
ENDDATE = $( date +"%d.%m.%Y %H:%M:%S" )
echo "==================================="
echo " Starting time : ${ STARTDATE } "
echo " Ending time : ${ ENDDATE } "
echo " Notified Users: $num_notified "
echo " Disabled Users: $num_disabled "
2023-11-18 21:18:16 +01:00
echo " Deleted Users : $num_deactivated_total "
2023-08-17 19:25:27 +00:00
echo "==================================="