#!/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()