funkcja wykrywania złego nicka
This commit is contained in:
96
app.py
96
app.py
@ -22,6 +22,7 @@ from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
import time
|
||||
import requests
|
||||
import string
|
||||
|
||||
os.makedirs("logs", exist_ok=True)
|
||||
os.makedirs("exports", exist_ok=True)
|
||||
@ -103,33 +104,74 @@ def is_temp_email(email, temp_domains_cache=None):
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def is_bad_name(name):
|
||||
if not name or len(name.strip()) < 3:
|
||||
return True
|
||||
|
||||
name = name.strip()
|
||||
lowered = name.lower()
|
||||
|
||||
# Cecha 1: tylko litery/cyfry i brak słów
|
||||
entropy_chars = len(set(name)) / len(name)
|
||||
digit_ratio = sum(c.isdigit() for c in name) / len(name)
|
||||
alpha_ratio = sum(c.isalpha() for c in name) / len(name)
|
||||
has_vowel = any(c in 'aeiouy' for c in lowered)
|
||||
has_common_words = any(word in lowered for word in ['admin', 'user', 'test', 'konto', 'login', 'abc', 'name'])
|
||||
|
||||
# Cecha 2: wygląda na hash/random
|
||||
is_alphanum = all(c in string.ascii_letters + string.digits for c in name)
|
||||
long_gibberish = is_alphanum and len(name) >= 8 and entropy_chars > 0.6 and digit_ratio > 0.3 and not has_vowel
|
||||
|
||||
# Punktacja heurystyczna
|
||||
score = 0
|
||||
if digit_ratio > 0.5: score += 1
|
||||
if entropy_chars > 0.7: score += 1
|
||||
if not has_vowel: score += 1
|
||||
if not has_common_words and is_alphanum and len(name) >= 8: score += 1
|
||||
if long_gibberish: score += 1
|
||||
if any(c in "!@#$%^&*()" for c in name): score += 1
|
||||
if name.lower() in {"unknown", "guest", "null"}: score += 2
|
||||
|
||||
return score >= 3 # 3+ z 6 wskazuje na losowość
|
||||
|
||||
def export_to_csv(users):
|
||||
now = datetime.now().strftime("%Y-%m-%d_%H%M")
|
||||
filename = f"exports/user_cleanup_results_{now}.csv"
|
||||
with open(filename, mode='w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(["UID", "Login", "E-mail", "Ostatnie logowanie", "Rejestracja", "Punkty", "Nieaktywny", "E-mail OK", "Tymczasowy"])
|
||||
writer.writerow([
|
||||
"UID", "Login", "E-mail", "Ostatnie logowanie", "Rejestracja",
|
||||
"Punkty", "Nieaktywny", "E-mail OK", "Tymczasowy", "Zły nick"
|
||||
])
|
||||
for u in users:
|
||||
writer.writerow([
|
||||
u['uid'], u['name'], u['mail'],
|
||||
u['uid'],
|
||||
u['name'],
|
||||
u['mail'],
|
||||
datetime.fromtimestamp(u['access']).strftime('%Y-%m-%d') if u['access'] else 'nigdy',
|
||||
datetime.fromtimestamp(u['created']).strftime('%Y-%m-%d') if u.get('created') else 'brak',
|
||||
u.get('points', 0),
|
||||
'TAK' if u['inactive'] else 'NIE',
|
||||
'TAK' if u['email_valid'] else 'NIE',
|
||||
'TAK' if u['temp_email'] else 'NIE'
|
||||
'TAK' if u.get('inactive') else 'NIE',
|
||||
'TAK' if u.get('email_valid') else 'NIE',
|
||||
'TAK' if u.get('temp_email') else 'NIE',
|
||||
'TAK' if u.get('bad_name') else 'NIE',
|
||||
])
|
||||
print(f"📁 CSV zapisany: {filename}")
|
||||
|
||||
|
||||
def export_to_excel(users):
|
||||
now = datetime.now().strftime("%Y-%m-%d_%H%M")
|
||||
filename = f"exports/user_cleanup_results_{now}.xlsx"
|
||||
workbook = xlsxwriter.Workbook(filename)
|
||||
sheet = workbook.add_worksheet("Wyniki")
|
||||
headers = ["UID", "Login", "E-mail", "Ostatnie logowanie", "Rejestracja", "Punkty", "Nieaktywny", "E-mail OK", "Tymczasowy"]
|
||||
|
||||
headers = [
|
||||
"UID", "Login", "E-mail", "Ostatnie logowanie", "Rejestracja",
|
||||
"Punkty", "Nieaktywny", "E-mail OK", "Tymczasowy", "Zły nick"
|
||||
]
|
||||
for col, header in enumerate(headers):
|
||||
sheet.write(0, col, header)
|
||||
|
||||
for row_idx, u in enumerate(users, start=1):
|
||||
sheet.write(row_idx, 0, u['uid'])
|
||||
sheet.write(row_idx, 1, u['name'])
|
||||
@ -137,12 +179,15 @@ def export_to_excel(users):
|
||||
sheet.write(row_idx, 3, datetime.fromtimestamp(u['access']).strftime('%Y-%m-%d') if u['access'] else 'nigdy')
|
||||
sheet.write(row_idx, 4, datetime.fromtimestamp(u['created']).strftime('%Y-%m-%d') if u.get('created') else 'brak')
|
||||
sheet.write(row_idx, 5, u.get('points', 0))
|
||||
sheet.write(row_idx, 6, 'TAK' if u['inactive'] else 'NIE')
|
||||
sheet.write(row_idx, 7, 'TAK' if u['email_valid'] else 'NIE')
|
||||
sheet.write(row_idx, 8, 'TAK' if u['temp_email'] else 'NIE')
|
||||
sheet.write(row_idx, 6, 'TAK' if u.get('inactive') else 'NIE')
|
||||
sheet.write(row_idx, 7, 'TAK' if u.get('email_valid') else 'NIE')
|
||||
sheet.write(row_idx, 8, 'TAK' if u.get('temp_email') else 'NIE')
|
||||
sheet.write(row_idx, 9, 'TAK' if u.get('bad_name') else 'NIE')
|
||||
|
||||
workbook.close()
|
||||
print(f"📁 Excel zapisany: {filename}")
|
||||
|
||||
|
||||
def flush_redis_cache():
|
||||
keys = redis_client.keys("mx:*")
|
||||
for key in keys:
|
||||
@ -170,7 +215,7 @@ def delete_user_via_php(uid, drupal_path):
|
||||
logging.error(f"Błąd PHP delete UID {uid}: {e.stderr}")
|
||||
|
||||
def confirm_delete():
|
||||
answer = input("❗ Czy na pewno chcesz USUNĄĆ użytkowników? [tak/N]: ").strip().lower()
|
||||
answer = input("❗ Czy na pewno chcesz ZDEZAKTYWOWAĆ użytkowników? [tak/N]: ").strip().lower()
|
||||
if answer not in ("tak", "t", "yes", "y"):
|
||||
print("❌ Operacja anulowana.")
|
||||
sys.exit(0)
|
||||
@ -279,7 +324,7 @@ def main():
|
||||
# 1. Podgląd nieaktywnych użytkowników bez punktów
|
||||
{script_path} --days-inactive 730 --dry-run
|
||||
|
||||
# 2. Usuń użytkowników z błędnymi e-mailami i nieaktywnych ponad 2 lata
|
||||
# 2. Usuń (dezaktywuj) użytkowników z błędnymi e-mailami i nieaktywnych ponad 2 lata
|
||||
{script_path} --days-inactive 730 --delete
|
||||
|
||||
# 3. Uwzględnij starych użytkowników (sprzed 2012), którzy logowali się w ciągu ostatnich 3 lat
|
||||
@ -306,10 +351,10 @@ def main():
|
||||
# 10. Wyślij testowego maila na podany adres
|
||||
{script_path} --send-test test@example.com
|
||||
|
||||
# 11. Usuń tylko użytkowników z nieprawidłowym lub tymczasowym adresem e-mail
|
||||
# 11. Usuń (dezaktywuj) tylko użytkowników z nieprawidłowym lub tymczasowym adresem e-mail
|
||||
{script_path} --only-invalid-emails --delete
|
||||
|
||||
# 12. Usuń nieaktywnych użytkowników, z ustawioną ścieżką do Drupala
|
||||
# 12. Usuń (dezaktywuj) nieaktywnych użytkowników, z ustawioną ścieżką do Drupala
|
||||
{script_path} --days-inactive 730 --delete --drupal-path /var/www/drupal
|
||||
|
||||
# 13. Ustaw inną liczbę maili i przerwę między paczkami (np. 50 maili co 30s)
|
||||
@ -331,7 +376,7 @@ def main():
|
||||
help='Tryb podglądu: nie wykonuje żadnych zmian, tylko raportuje')
|
||||
|
||||
parser.add_argument('--delete', action='store_true',
|
||||
help='Usuń użytkowników, którzy spełniają kryteria filtrowania')
|
||||
help='Usuń (dezaktywuj) użytkowników, którzy spełniają kryteria filtrowania')
|
||||
|
||||
parser.add_argument('--validate', action='store_true',
|
||||
help='Tylko sprawdź poprawność adresów e-mail (bez usuwania)')
|
||||
@ -370,14 +415,16 @@ def main():
|
||||
help='Ile sekund czekać między paczkami maili (domyślnie: 60 sek.)')
|
||||
|
||||
parser.add_argument('--only-invalid-emails', action='store_true',
|
||||
help='Usuń tylko użytkowników z nieprawidłowymi lub tymczasowymi adresami e-mail (bez sprawdzania aktywności)')
|
||||
help='Usuń (dezaktywuj) tylko użytkowników z nieprawidłowymi lub tymczasowymi adresami e-mail (bez sprawdzania aktywności)')
|
||||
|
||||
parser.add_argument(
|
||||
"--inactive-since",
|
||||
type=str,
|
||||
parser.add_argument("--inactive-since", type=str,
|
||||
help="Zakres dni nieaktywności w formacie min-max, np. 360-1825 (tylko dla wysyłki maili)"
|
||||
)
|
||||
|
||||
parser.add_argument('--bad-name', action='store_true',
|
||||
help='Oznacz użytkowników z losowymi lub bezużytecznymi nazwami jako kandydatów do usunięcia')
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
inactive_range = None
|
||||
@ -424,6 +471,7 @@ def main():
|
||||
temp_email_count = 0
|
||||
skipped_with_points = 0
|
||||
skipped_veterans = 0
|
||||
bad_name_count = 0
|
||||
|
||||
temp_domains_cache = load_temp_domains()
|
||||
|
||||
@ -435,6 +483,9 @@ def main():
|
||||
if (user.get('post_count') or 0) > 0:
|
||||
continue
|
||||
|
||||
if user.get('bad_name'):
|
||||
bad_name_count += 1
|
||||
|
||||
last_access = user['access'] or 0
|
||||
days_inactive = (now_ts - last_access) / 86400
|
||||
|
||||
@ -445,6 +496,7 @@ def main():
|
||||
user['inactive'] = is_inactive_by_days or is_inactive_by_range
|
||||
user['temp_email'] = is_temp_email(user['mail'], temp_domains_cache)
|
||||
user['email_valid'] = not is_fake_email(user['mail']) and not user['temp_email']
|
||||
user['bad_name'] = args.bad_name and is_bad_name(user['name'])
|
||||
|
||||
if args.only_invalid_emails:
|
||||
if not user['email_valid']:
|
||||
@ -466,7 +518,7 @@ def main():
|
||||
if user['temp_email']:
|
||||
temp_email_count += 1
|
||||
|
||||
if args.validate or user['inactive'] or not user['email_valid']:
|
||||
if args.validate or user['inactive'] or not user['email_valid'] or user.get('bad_name'):
|
||||
final_candidates.append(user)
|
||||
|
||||
final_candidates = [u for u in final_candidates if (u.get('points') or 0) == 0]
|
||||
@ -504,6 +556,8 @@ def main():
|
||||
print(f"- Nieaktywni: > {args.days_inactive} dni (~{days_to_years(args.days_inactive)} lat)")
|
||||
if inactive_range:
|
||||
print(f"- Zakres nieaktywności: {inactive_range[0]}-{inactive_range[1]} dni (~{days_to_years(inactive_range[0])}-{days_to_years(inactive_range[1])} lat)")
|
||||
|
||||
|
||||
print(f"- Weterani: konta przed {args.veteran_year}")
|
||||
print(f"- Pominięci weterani: logowanie w ostatnich {args.recent_login_days} dniach")
|
||||
|
||||
@ -515,6 +569,8 @@ def main():
|
||||
print(f"- Z tymczasowym e-mailem: {temp_email_count}")
|
||||
print(f"- Kandydaci do usunięcia: {len(final_candidates)}")
|
||||
print(f"- Pominięci weterani: {skipped_veterans}")
|
||||
print(f"- Z losowym lub podejrzanym nickiem: {bad_name_count}")
|
||||
|
||||
|
||||
if args.delete:
|
||||
confirm_delete()
|
||||
@ -523,7 +579,7 @@ def main():
|
||||
sys.exit(1)
|
||||
for u in tqdm(final_candidates, desc="Usuwanie"):
|
||||
delete_user_via_php(u['uid'], args.drupal_path)
|
||||
print(f"✅ Usunięto {len(final_candidates)} użytkowników")
|
||||
print(f"✅ Zedaktywowano {len(final_candidates)} użytkowników")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Reference in New Issue
Block a user