diff --git a/delete_inactive_gitea_users.py b/delete_inactive_gitea_users.py new file mode 100644 index 0000000..eea8b33 --- /dev/null +++ b/delete_inactive_gitea_users.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +""" +CRON (przykład codziennie o 3:00): +0 3 * * * /usr/bin/python3 /root/gitea_clean/delete_inactive_gitea_users.py --delete-spammers >> /var/log/gitea_cleanup.log 2>&1 +""" + +import requests +import configparser +from datetime import datetime, timedelta, timezone +import os +import argparse +import dns.resolver + +CONFIG_FILE = 'config.ini' +GITEA_URL = 'https://gitea.linuxiarz.pl' +DNI_BEZ_AKTYWNOŚCI = 180 + +def save_token_to_config(token): + config = configparser.ConfigParser() + config['auth'] = {'token': token} + with open(CONFIG_FILE, 'w') as configfile: + config.write(configfile) + +def verify_token(token): + headers = {'Authorization': f'token {token}'} + r = requests.get(f'{GITEA_URL}/api/v1/admin/users?page=1', headers=headers) + return r.status_code == 200 + +def load_token(): + config = configparser.ConfigParser() + if os.path.exists(CONFIG_FILE): + config.read(CONFIG_FILE) + token = config.get('auth', 'token', fallback=None) + if token and verify_token(token): + return token + else: + print("Token nie działa lub jest nieprawidłowy.") + token = input("Wklej ważny token API admina Gitea: ").strip() + save_token_to_config(token) + return token + +def get_users(token): + headers = {'Authorization': f'token {token}'} + users = [] + page = 1 + while True: + r = requests.get(f'{GITEA_URL}/api/v1/admin/users?page={page}', headers=headers) + r.raise_for_status() + data = r.json() + if not data: + break + users.extend(data) + page += 1 + return users + +def delete_user(username, token, debug=False): + headers = {'Authorization': f'token {token}'} + r = requests.delete(f'{GITEA_URL}/api/v1/admin/users/{username}', headers=headers) + if r.status_code == 204: + if debug: + print(f"✅ Użytkownik {username} usunięty.") + else: + print(f"❌ Błąd przy usuwaniu {username}: {r.status_code} - {r.text}") + +def is_email_domain_valid(email): + try: + domain = email.split('@')[1].lower() + answers = dns.resolver.resolve(domain, 'MX') + return len(answers) > 0 + except Exception: + return False + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--delete-spammers', action='store_true', help='Usuń konta nieaktywne, zablokowane lub z błędnym e-mailem') + parser.add_argument('--delete-id-range', nargs=2, type=int, metavar=('MIN_ID', 'MAX_ID'), help='Usuń konta o ID z danego zakresu (włącznie)') + parser.add_argument('--debug', action='store_true', help='Tryb debugowania (wypisz operacje i użytkowników)') + args = parser.parse_args() + + token = load_token() + cutoff = datetime.now(timezone.utc) - timedelta(days=DNI_BEZ_AKTYWNOŚCI) + users = get_users(token) + + if args.debug: + print(f"📋 Pobrano {len(users)} użytkowników.") + print(f"⏱ Granica nieaktywności: {cutoff.isoformat()}") + + for user in users: + user_id = user.get('id') + login = user['login'] + email = user.get('email', '') + is_active = user.get('is_active', True) + prohibit_login = user.get('prohibit_login', False) + last_login = user.get('last_login', '') + + if args.debug: + print(f"🔍 ID: {user_id} | {login} | aktywny: {is_active} | zablokowany: {prohibit_login} | e-mail: {email} | logowanie: {last_login or 'brak'}") + + # ID zakres + if args.delete_id_range: + min_id, max_id = args.delete_id_range + if min_id <= user_id <= max_id: + if args.debug: + print(f"➡️ Usuwam ID {user_id}: {login}") + delete_user(login, token, args.debug) + continue + + # Spammerzy + if args.delete_spammers: + if not is_email_domain_valid(email) or not is_active or prohibit_login: + if args.debug: + print(f"➡️ Usuwam spammera: {login}") + delete_user(login, token, args.debug) + continue + + # Nieaktywni + if last_login: + last_login_dt = datetime.strptime(last_login, "%Y-%m-%dT%H:%M:%S%z") + if last_login_dt < cutoff: + if args.debug: + print(f"➡️ Usuwam nieaktywnego: {login}") + delete_user(login, token, args.debug) + else: + if args.debug: + print(f"➡️ Usuwam: {login} (nigdy się nie logował)") + delete_user(login, token, args.debug) + +if __name__ == '__main__': + main()