cleanup-mastodon-users.sh/cleanup-mastodon-users.sh
ij daf3cdff94 Minor changes and corrections
Rewording of "deactivated" instead of "disabled", replacement of $profileurl and some changes to the stats output. Additionally some hints in the mail texts about notifiying by mail.

Signed-off-by: ij <ij@noreply.codeberg.org>
2023-12-13 20:05:13 +00:00

294 lines
12 KiB
Bash

#!/bin/sh
set -f
# create a default config when started with --init
initConfig() {
(
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
) > "${HOME}"/.cleanup-mastodon-users.conf
echo "✅ - Configuration file created. You can now edit "${HOME}"/.cleanup-mastodon-users.conf"
}
case $1 in
"--init")
initConfig
exit 0
;;
"--dry-run")
mode="dryrun"
;;
"--cron")
mode="cron"
;;
"--dowhatimean")
mode="hotrun"
;;
*)
echo "Usage: "
echo " --init \t: create $0/.cleanup-mastodon-users.conf config file."
echo " --dry-run \t: make a dry-run, no deletion will be done, no mails are sent."
echo " --cron \t: delete deactivated users in a regularly cron run step by step to avoid mass flooding."
echo " --dowhatimean \t: add this option if you really want to delete users."
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
exit 0
;;
esac
. "${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")
# make a list to be used for grep -E
PROTECTED=$(echo "$PROTECTEDUSERS" | sed 's/\"//g' | sed 's/\ /\\\|/g')
#echo $PROTECTED
# notify the user that s/he needs to re-login after 6 months to prevent account deletion
notifyUser() {
(
cat <<EOF
Dear ${dispname},
you have registered your account on ${LOCAL_DOMAIN} at ${registered} and last time you logged in was at ${lastlogin}.
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).
You can access your profile at https://${LOCAL_DOMAIN}/@${username} or you can cancel your account on your own when logged in at https://${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.
Sincerely,
your ${SITE} admins
EOF
) | sed 's/_/\ /g' | /usr/bin/mail -s "The Fediverse misses you, ${username}!" -r "${SMTP_FROM_ADDRESS}" -- "${usermail}"
# add '-b "$SITEADMIN"' before the "--" above to receive BCC mails
}
# notify user that the account has been deleted because of inactivity
notifyUserDisable() {
(
cat <<EOF
Dear ${dispname},
you have registered your account on ${LOCAL_DOMAIN} at ${registered} and last time you logged in was at ${lastlogin}.
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 (after ${DELDELIMIT}). Until then you can still request reactivattion from the admins. See ${LOCAL_DOMAIN}/about for contact information.
You will just receive the final confirmation mail of account deletion and no further mails!
Sincerely,
your ${SITE} admins
EOF
) | sed 's/_/\ /g' | /usr/bin/mail -s "Your account ${username} on ${SITE} has been deactivated!" -r "${SMTP_FROM_ADDRESS}" -- "${usermail}"
# add '-b "$SITEADMIN"' before the "--" above to receive BCC mails
}
# notify user that the account has been deleted because of inactivity
notifyUserDeletion() {
(
cat <<EOF
Dear ${dispname},
you have registered your account on ${LOCAL_DOMAIN} at ${registered} and last time you logged in was at ${lastlogin}.
Since you haven't reacted to the previous mails and didn't login again, your account including all your data has now been deleted.
This is the last and final mail about your account on ${LOCAL_DOMAIN}
Sincerely,
your ${SITE} admins
EOF
) | 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
}
# main loop
case ${mode} in
"init")
initConfig
;;
"cron")
# get the total number of deactivated accounts
# the intention is that you can better judge how often you need to invoke the cron option
# or by increasing the LIMIT_DELETE variable
# the backlog queue shouldn't pile up but also not run empty to fast to reduce the load
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 " " )
# when there is less then 1 user to delete (=0) then exit
if [ "${num_deactivated_overgrace}" -lt 1 ]; then
exit 0
fi
echo "==================================="
echo "Account summary:"
echo "Total deactivated (>${UPPERLIMIT}): ${num_deactivated_total}"
echo "Over grace (${DELDELIMIT}): ${num_deactivated_overgrace}"
echo "Deleting at once: ${LIMIT_DELETE}"
echo "==================================="
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
#echo ${u}
username=$(echo "${u}" | awk -F ";" '{print $1}')
dispname=$(echo "${u}" | awk -F ";" '{print $2}')
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
# and later change the text to a notification that the account has been deleted.
# if username is a PROTECTED user do nothing, else delete user
echo -n "${username} : "
run_tootctl accounts delete "${username}"
notifyUserDeletion
num_deleted=$((num_deleted+1))
RND=$(date +%s)
sec=$(( $RND %60 ))
ms=$(( $RND %23 ))
sleep ${sec}.${ms}
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'" )
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
#echo ${line}
username=$(echo "${line}" | cut -f1 -d"," )
mail=$(echo "${line}" | cut -f2 -d"," )
# if username is a PROTECTED user do nothing, else delete user
if [ -n "${PROTECTEDUSERS}" ]; then
pcheck=0
for s in ${PROTECTEDUSERS} ; do
if [ "${s}" = "${username}" ]; then
pcheck=1
fi
done
if [ ${pcheck} -eq 0 ]; then
echo "Delete unconfirmed user ${username}"
if [ "${mode}" = "hotrun" ]; then
run_tootctl accounts delete "${username}"
elif [ "${mode}" = "dryrun" ]; then
echo "${username}: skipped because of dryrun."
fi
fi
fi
done
#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
for mode2 in $(echo "warn disable"); do
#echo "mode2: $mode2"
case ${mode2} in
"warn")
#echo "in warn"
SQLSTATE="current_sign_in_at between now()-'${UPPERLIMIT}'::interval and now()-'${LOWERLIMIT}'::interval"
;;
"disable")
#echo "in disable"
#SQLSTATE="current_sign_in_at < now()-'${UPPERLIMIT}'::interval"
SQLSTATE="current_sign_in_at between now()-'${UPPERLIMIT}'::interval and now()-'${UPPERLIMIT}'::interval-'1 week'::interval"
;;
#"delete")
# #echo "in delete"
# SQLSTATE="current_sign_in_at < now()-'${UPPERLIMIT}'::interval"
# ;;
esac
#echo "SQL: $SQLSTATE"
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
#echo ${u}
username=$(echo "${u}" | awk -F ";" '{print $1}')
dispname=$(echo "${u}" | awk -F ";" '{print $2}')
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
# and later change the text to a notification that the account has been deleted.
# if username is a PROTECTED user do nothing, else delete user
echo -n "${username} : "
if [ "${mode}" = "hotrun" ]; then
#echo -n "hotrun "
#run_tootctl accounts delete "${username}"
run_tootctl accounts modify "${username}" --disable
#notifyUserDeletion
notifyUserDisable
#echo "deleted."
elif [ "${mode}" = "dryrun" ]; then
echo "will be deactivated, but is skipped because of dryrun."
fi
num_disabled=$((num_disabled+1))
exit
;;
esac
RND=$(date +%s)
sec=$(( $RND %5 ))
ms=$(( $RND %23 ))
sleep ${sec}.${ms}
done
done
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 " " )
;;
esac
ENDDATE=$(date +"%d.%m.%Y %H:%M:%S")
echo "==================================="
echo "Starting time : ${STARTDATE}"
echo "Ending time : ${ENDDATE}"
echo "Notified Users: $num_notified"
echo "Deactivated : $num_disabled"
echo "To be deleted : $num_deactivated_total"
echo "==================================="