zmiany, temp maile, csv browser
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,3 +6,5 @@ __pycache__/
|
||||
*.pyc
|
||||
user_cleanup_results_*
|
||||
venv
|
||||
exports
|
||||
logs
|
96
app.py
96
app.py
@ -21,20 +21,25 @@ import smtplib
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
import time
|
||||
import requests
|
||||
|
||||
os.makedirs("logs", exist_ok=True)
|
||||
os.makedirs("exports", exist_ok=True)
|
||||
|
||||
# Redis - baza 5
|
||||
redis_client = redis.Redis(host='localhost', port=6379, db=5, decode_responses=True)
|
||||
|
||||
script_path = os.path.abspath(__file__)
|
||||
|
||||
# Tymczasowe domeny
|
||||
TEMP_DOMAINS = {
|
||||
"10minutemail.com", "tempmail.com", "tempmail.net", "tempmail.org",
|
||||
"guerrillamail.com", "mailinator.com", "discard.email", "fakeinbox.com",
|
||||
"trashmail.com", "getnada.com", "yopmail.com", "maildrop.cc", "sharklasers.com"
|
||||
}
|
||||
DISPOSABLE_DOMAINS_URL = "https://raw.githubusercontent.com/disposable-email-domains/disposable-email-domains/refs/heads/main/disposable_email_blocklist.conf"
|
||||
DISPOSABLE_DOMAINS_CACHE_KEY = "disposable_domains:list"
|
||||
DISPOSABLE_DOMAINS_TTL = 86400 # 24h
|
||||
|
||||
|
||||
# Logi
|
||||
logging.basicConfig(
|
||||
filename='user_cleanup.log',
|
||||
filename='logs/user_cleanup.log',
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s [%(levelname)s] %(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S'
|
||||
@ -71,16 +76,37 @@ def is_fake_email(email):
|
||||
redis_client.set(cache_key, result, ex=259200)
|
||||
return result == "true"
|
||||
|
||||
def is_temp_email(email):
|
||||
def load_temp_domains():
|
||||
cached = redis_client.get(DISPOSABLE_DOMAINS_CACHE_KEY)
|
||||
if cached:
|
||||
return set(cached.split(","))
|
||||
|
||||
try:
|
||||
resp = requests.get(DISPOSABLE_DOMAINS_URL, timeout=10)
|
||||
if resp.status_code == 200:
|
||||
domains = {line.strip().lower() for line in resp.text.splitlines() if line.strip() and not line.startswith("#")}
|
||||
redis_client.set(DISPOSABLE_DOMAINS_CACHE_KEY, ",".join(domains), ex=DISPOSABLE_DOMAINS_TTL)
|
||||
return domains
|
||||
else:
|
||||
print(f"⚠️ Nie udało się pobrać listy disposable domains (kod {resp.status_code})")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Błąd pobierania listy disposable domains: {e}")
|
||||
|
||||
return set()
|
||||
|
||||
def is_temp_email(email, temp_domains_cache=None):
|
||||
try:
|
||||
domain = email.split('@')[1].lower()
|
||||
return domain in TEMP_DOMAINS
|
||||
if temp_domains_cache is None:
|
||||
temp_domains_cache = load_temp_domains()
|
||||
return domain in temp_domains_cache
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def export_to_csv(users):
|
||||
now = datetime.now().strftime("%Y-%m-%d_%H%M")
|
||||
filename = f"user_cleanup_results_{now}.csv"
|
||||
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"])
|
||||
@ -98,7 +124,7 @@ def export_to_csv(users):
|
||||
|
||||
def export_to_excel(users):
|
||||
now = datetime.now().strftime("%Y-%m-%d_%H%M")
|
||||
filename = f"user_cleanup_results_{now}.xlsx"
|
||||
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"]
|
||||
@ -250,27 +276,49 @@ def main():
|
||||
epilog="""
|
||||
Przykłady użycia:
|
||||
|
||||
# Podgląd nieaktywnych użytkowników bez punktów
|
||||
/root/user_manager/venv/bin/python3 app.py --days-inactive 730 --dry-run
|
||||
# 1. Podgląd nieaktywnych użytkowników bez punktów
|
||||
{script_path} --days-inactive 730 --dry-run
|
||||
|
||||
# Usuń użytkowników z błędnymi e-mailami i nieaktywnych 2+ lata
|
||||
/root/user_manager/venv/bin/python3 app.py --days-inactive 730 --delete
|
||||
# 2. Usuń użytkowników z błędnymi e-mailami i nieaktywnych ponad 2 lata
|
||||
{script_path} --days-inactive 730 --delete
|
||||
|
||||
# Uwzględnij starych użytkowników, którzy logowali się ostatnio
|
||||
/root/user_manager/venv/bin/python3 app.py --days-inactive 730 --veteran-year 2012 --recent-login-days 1095
|
||||
# 3. Uwzględnij starych użytkowników (sprzed 2012), którzy logowali się w ciągu ostatnich 3 lat
|
||||
{script_path} --days-inactive 730 --veteran-year 2012 --recent-login-days 1095
|
||||
|
||||
# Tylko walidacja adresów e-mail
|
||||
/root/user_manager/venv/bin/python3 app.py --validate
|
||||
# 4. Walidacja poprawności adresów e-mail (bez usuwania)
|
||||
{script_path} --validate
|
||||
|
||||
# Czyszczenie cache DNS w Redisie
|
||||
/root/user_manager/venv/bin/python3 app.py --flush-cache
|
||||
# 5. Czyszczenie cache rekordów MX w Redisie
|
||||
{script_path} --flush-cache
|
||||
|
||||
# Wyślij maile tylko do użytkowników nieaktywnych od 1 do 5 lat
|
||||
/root/user_manager/venv/bin/python3 app.py --send-mails --inactive-since 365-1825
|
||||
# 6. Eksportuj dane użytkowników do pliku Excel
|
||||
{script_path} --days-inactive 730 --dry-run --export-excel
|
||||
|
||||
# 7. Wygeneruj raport liczby użytkowników wg domen e-mail
|
||||
{script_path} --days-inactive 730 --report-domains
|
||||
|
||||
# 8. Wyświetl tabelę z użytkownikami kwalifikującymi się do usunięcia
|
||||
{script_path} --days-inactive 730 --show-table
|
||||
|
||||
# 9. Wyślij e-maile do użytkowników nieaktywnych od 1 do 5 lat
|
||||
{script_path} --send-mails --inactive-since 365-1825
|
||||
|
||||
# 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
|
||||
{script_path} --only-invalid-emails --delete
|
||||
|
||||
# 12. Usuń 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)
|
||||
{script_path} --send-mails --inactive-since 730-2000 --mails-per-pack 50 --time-per-pack 30
|
||||
""",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument('--host', help='Adres hosta bazy danych (można ustawić w .env jako DB_HOST)')
|
||||
parser.add_argument('--user', help='Użytkownik bazy danych (lub DB_USER z .env)')
|
||||
parser.add_argument('--password', help='Hasło do bazy danych (lub DB_PASSWORD z .env)')
|
||||
@ -377,6 +425,8 @@ def main():
|
||||
skipped_with_points = 0
|
||||
skipped_veterans = 0
|
||||
|
||||
temp_domains_cache = load_temp_domains()
|
||||
|
||||
for user in tqdm(users, desc="Analiza"):
|
||||
if (user.get('points') or 0) > 0:
|
||||
skipped_with_points += 1
|
||||
@ -393,7 +443,7 @@ def main():
|
||||
is_inactive_by_range = inactive_range and (inactive_range[0] <= days_inactive <= inactive_range[1])
|
||||
|
||||
user['inactive'] = is_inactive_by_days or is_inactive_by_range
|
||||
user['temp_email'] = is_temp_email(user['mail'])
|
||||
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']
|
||||
|
||||
if args.only_invalid_emails:
|
||||
|
72
csv_browser.py
Normal file
72
csv_browser.py
Normal file
@ -0,0 +1,72 @@
|
||||
import os
|
||||
from flask import Flask, render_template_string, send_from_directory, request
|
||||
import pandas as pd
|
||||
|
||||
EXPORTS_DIR = "exports"
|
||||
PORT = 8899
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
TEMPLATE = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>CSV Viewer</title>
|
||||
<link rel="stylesheet"
|
||||
href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css">
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script
|
||||
src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>📂 CSV Viewer</h2>
|
||||
{% if files %}
|
||||
<ul>
|
||||
{% for file in files %}
|
||||
<li><a href="/view?file={{ file }}">{{ file }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>Brak plików w katalogu <code>{{ dir }}</code>.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if table %}
|
||||
<hr>
|
||||
<h3>Plik: {{ filename }}</h3>
|
||||
{{ table | safe }}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#csv-table').DataTable();
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
files = [f for f in os.listdir(EXPORTS_DIR) if f.endswith(".csv")]
|
||||
return render_template_string(TEMPLATE, files=files, table=None, dir=EXPORTS_DIR)
|
||||
|
||||
@app.route("/view")
|
||||
def view_file():
|
||||
filename = request.args.get("file")
|
||||
if not filename or not filename.endswith(".csv"):
|
||||
return "Niepoprawny plik.", 400
|
||||
path = os.path.join(EXPORTS_DIR, filename)
|
||||
if not os.path.exists(path):
|
||||
return "Plik nie istnieje.", 404
|
||||
|
||||
try:
|
||||
df = pd.read_csv(path)
|
||||
html_table = df.to_html(classes="display", index=False, table_id="csv-table")
|
||||
files = [f for f in os.listdir(EXPORTS_DIR) if f.endswith(".csv")]
|
||||
return render_template_string(TEMPLATE, files=files, table=html_table, filename=filename, dir=EXPORTS_DIR)
|
||||
except Exception as e:
|
||||
return f"Błąd odczytu CSV: {e}", 500
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.makedirs(EXPORTS_DIR, exist_ok=True)
|
||||
app.run(host="0.0.0.0", port=PORT)
|
@ -5,3 +5,6 @@ python-dotenv
|
||||
tqdm
|
||||
redis
|
||||
xlsxwriter
|
||||
requests
|
||||
flask
|
||||
pandas
|
Reference in New Issue
Block a user