nowy mail i funkcja
This commit is contained in:
63
app.py
63
app.py
@ -21,6 +21,7 @@ import smtplib
|
|||||||
from email.mime.multipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
import time
|
import time
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
|
||||||
# Redis - baza 5
|
# Redis - baza 5
|
||||||
@ -79,7 +80,6 @@ def is_temp_email(email):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def export_to_csv(users):
|
def export_to_csv(users):
|
||||||
now = datetime.datetime.now().strftime("%Y-%m-%d_%H%M")
|
now = datetime.datetime.now().strftime("%Y-%m-%d_%H%M")
|
||||||
filename = f"user_cleanup_results_{now}.csv"
|
filename = f"user_cleanup_results_{now}.csv"
|
||||||
@ -167,7 +167,7 @@ def get_smtp_config():
|
|||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def send_email_batch(users, smtp_config, mails_per_pack=100, time_per_pack=60, dry_run=False):
|
def send_email_batch(users, smtp_config, mails_per_pack=100, time_per_pack=60, dry_run=False, inactive_range=None):
|
||||||
import os
|
import os
|
||||||
|
|
||||||
template_path = "mail_template.html"
|
template_path = "mail_template.html"
|
||||||
@ -182,6 +182,19 @@ def send_email_batch(users, smtp_config, mails_per_pack=100, time_per_pack=60, d
|
|||||||
print(f"❌ Błąd podczas odczytu szablonu HTML: {e}")
|
print(f"❌ Błąd podczas odczytu szablonu HTML: {e}")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Filtrowanie użytkowników według zakresu nieaktywności
|
||||||
|
if inactive_range:
|
||||||
|
min_days, max_days = inactive_range
|
||||||
|
now_ts = int(datetime.datetime.now().timestamp())
|
||||||
|
filtered_users = []
|
||||||
|
for user in users:
|
||||||
|
last_access = user['access'] or 0
|
||||||
|
days_inactive = (now_ts - last_access) / 86400
|
||||||
|
if min_days <= days_inactive <= max_days:
|
||||||
|
filtered_users.append(user)
|
||||||
|
users = filtered_users
|
||||||
|
print(f"📨 Wysyłka maili tylko dla użytkowników nieaktywnych od {min_days} do {max_days} dni ({len(users)} osób)")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
smtp = smtplib.SMTP(smtp_config["host"], int(smtp_config["port"]))
|
smtp = smtplib.SMTP(smtp_config["host"], int(smtp_config["port"]))
|
||||||
smtp.ehlo()
|
smtp.ehlo()
|
||||||
@ -213,8 +226,11 @@ def send_email_batch(users, smtp_config, mails_per_pack=100, time_per_pack=60, d
|
|||||||
msg['To'] = user['mail']
|
msg['To'] = user['mail']
|
||||||
msg['Subject'] = "Twoje konto w unitraklub.pl"
|
msg['Subject'] = "Twoje konto w unitraklub.pl"
|
||||||
|
|
||||||
body = template.replace("@user", user['name']).replace(
|
# Generowanie treści maila z uwzględnieniem ostatniego logowania
|
||||||
"@rejestracja", datetime.datetime.fromtimestamp(user['created']).strftime('%Y-%m-%d'))
|
body = template.replace("@user", user['name']) \
|
||||||
|
.replace("@rejestracja", datetime.datetime.fromtimestamp(user['created']).strftime('%Y-%m-%d')) \
|
||||||
|
.replace("@ostatnie_logowanie", datetime.datetime.fromtimestamp(user['access']).strftime('%Y-%m-%d') if user['access'] else 'nigdy')
|
||||||
|
|
||||||
msg.attach(MIMEText(body, 'html'))
|
msg.attach(MIMEText(body, 'html'))
|
||||||
|
|
||||||
smtp.send_message(msg)
|
smtp.send_message(msg)
|
||||||
@ -263,6 +279,9 @@ def main():
|
|||||||
|
|
||||||
# Czyszczenie cache DNS w Redisie
|
# Czyszczenie cache DNS w Redisie
|
||||||
/root/user_manager/venv/bin/python3 app.py --flush-cache
|
/root/user_manager/venv/bin/python3 app.py --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
|
||||||
""",
|
""",
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter
|
formatter_class=argparse.RawDescriptionHelpFormatter
|
||||||
)
|
)
|
||||||
@ -318,11 +337,27 @@ def main():
|
|||||||
help='Ile sekund czekać między paczkami maili (domyślnie: 60 sek.)')
|
help='Ile sekund czekać między paczkami maili (domyślnie: 60 sek.)')
|
||||||
|
|
||||||
parser.add_argument('--only-invalid-emails', action='store_true',
|
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ń tylko użytkowników z nieprawidłowymi lub tymczasowymi adresami e-mail (bez sprawdzania aktywności)')
|
||||||
|
|
||||||
|
# NEW: dodano argument --inactive-since
|
||||||
|
parser.add_argument(
|
||||||
|
"--inactive-since",
|
||||||
|
type=str,
|
||||||
|
help="Zakres dni nieaktywności w formacie min-max, np. 360-1825 (tylko dla wysyłki maili)"
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# NEW: przetwarzanie parametru --inactive-since
|
||||||
|
inactive_range = None
|
||||||
|
if args.inactive_since:
|
||||||
|
try:
|
||||||
|
min_days, max_days = map(int, args.inactive_since.split('-'))
|
||||||
|
inactive_range = (min_days, max_days)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Błąd parsowania zakresu dni w --inactive-since: {e}")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
if args.send_test:
|
if args.send_test:
|
||||||
test_user = {
|
test_user = {
|
||||||
'name': 'Testowy Użytkownik',
|
'name': 'Testowy Użytkownik',
|
||||||
@ -334,7 +369,6 @@ def main():
|
|||||||
send_email_batch([test_user], smtp_config, mails_per_pack=1, time_per_pack=0, dry_run=False)
|
send_email_batch([test_user], smtp_config, mails_per_pack=1, time_per_pack=0, dry_run=False)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
if not args.drupal_path:
|
if not args.drupal_path:
|
||||||
args.drupal_path = os.getenv("DRUPAL_PATH")
|
args.drupal_path = os.getenv("DRUPAL_PATH")
|
||||||
|
|
||||||
@ -406,7 +440,6 @@ def main():
|
|||||||
# Redundant safety filter to exclude any with points
|
# Redundant safety filter to exclude any with points
|
||||||
final_candidates = [u for u in final_candidates if (u.get('points') or 0) == 0]
|
final_candidates = [u for u in final_candidates if (u.get('points') or 0) == 0]
|
||||||
|
|
||||||
|
|
||||||
if args.report_domains:
|
if args.report_domains:
|
||||||
domain_report(final_candidates)
|
domain_report(final_candidates)
|
||||||
|
|
||||||
@ -424,19 +457,26 @@ def main():
|
|||||||
|
|
||||||
export_to_csv(final_candidates)
|
export_to_csv(final_candidates)
|
||||||
|
|
||||||
|
|
||||||
if args.export_excel:
|
if args.export_excel:
|
||||||
export_to_excel(final_candidates)
|
export_to_excel(final_candidates)
|
||||||
|
|
||||||
if args.send_mails:
|
if args.send_mails:
|
||||||
send_email_batch(final_candidates, smtp_config, args.mails_per_pack, args.time_per_pack)
|
send_email_batch(
|
||||||
|
final_candidates,
|
||||||
|
smtp_config,
|
||||||
|
args.mails_per_pack,
|
||||||
|
args.time_per_pack,
|
||||||
|
inactive_range=inactive_range # NEW: przekazanie zakresu nieaktywności
|
||||||
|
)
|
||||||
|
|
||||||
print("\n📋 Parametry filtrowania:")
|
print("\n📋 Parametry filtrowania:")
|
||||||
if args.days_inactive:
|
if args.days_inactive:
|
||||||
print(f"- Nieaktywni: brak logowania przez ≥ {args.days_inactive} dni (~{days_to_years(args.days_inactive)} lat)")
|
print(f"- Nieaktywni: brak logowania przez ≥ {args.days_inactive} dni (~{days_to_years(args.days_inactive)} lat)")
|
||||||
print(f"- Weterani: konta zarejestrowane w roku ≤ {args.veteran_year}")
|
print(f"- Weterani: konta zarejestrowane w roku ≤ {args.veteran_year}")
|
||||||
print(f"- Pominięci weterani: logowanie w ciągu ostatnich ≤ {args.recent_login_days} dni (~{days_to_years(args.recent_login_days)} lat)")
|
print(f"- Pominięci weterani: logowanie w ciągu ostatnich ≤ {args.recent_login_days} dni (~{days_to_years(args.recent_login_days)} lat)")
|
||||||
|
if args.inactive_since: # NEW: wyświetlanie zakresu nieaktywności
|
||||||
|
min_days, max_days = map(int, args.inactive_since.split('-'))
|
||||||
|
print(f"- Wysyłka maili tylko dla nieaktywnych od {min_days} do {max_days} dni (~{days_to_years(min_days)}-{days_to_years(max_days)} lat)")
|
||||||
|
|
||||||
print("\n📊 Podsumowanie:")
|
print("\n📊 Podsumowanie:")
|
||||||
print(f"- Całkowita liczba użytkowników w bazie: {len(users)}")
|
print(f"- Całkowita liczba użytkowników w bazie: {len(users)}")
|
||||||
@ -459,6 +499,5 @@ def main():
|
|||||||
delete_user_via_php(u['uid'], args.drupal_path)
|
delete_user_via_php(u['uid'], args.drupal_path)
|
||||||
print(f"✅ Usunięto {len(final_candidates)} użytkowników przez delete_user.php")
|
print(f"✅ Usunięto {len(final_candidates)} użytkowników przez delete_user.php")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
@ -25,6 +25,11 @@
|
|||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
color: #222222;
|
color: #222222;
|
||||||
}
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #222222;
|
||||||
|
margin-top: 25px;
|
||||||
|
}
|
||||||
p {
|
p {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
@ -42,6 +47,28 @@
|
|||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
.details {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 12px;
|
||||||
|
border-left: 4px solid #3498db;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.details-item {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.benefits {
|
||||||
|
background-color: #e8f4fd;
|
||||||
|
padding: 12px;
|
||||||
|
border-left: 4px solid #2980b9;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.benefits ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.benefits li {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -52,14 +79,26 @@
|
|||||||
Kontaktujemy się z Tobą w sprawie Twojego konta w serwisie <strong>unitraklub.pl</strong>.
|
Kontaktujemy się z Tobą w sprawie Twojego konta w serwisie <strong>unitraklub.pl</strong>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<div class="details">
|
||||||
Zarejestrowałeś/aś konto dnia <strong>@rejestracja</strong>. Niestety, od momentu rejestracji nie wykazało ono żadnej aktywności.
|
<div class="details-item"><strong>Data rejestracji:</strong> @rejestracja</div>
|
||||||
</p>
|
<div class="details-item"><strong>Ostatnie logowanie:</strong> @ostatnie_logowanie</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="highlight">
|
<div class="highlight">
|
||||||
Jeśli nie zalogujesz się w najbliższym czasie, konto zostanie zablokowane i następnie usunięte.
|
Jeśli nie zalogujesz się w najbliższym czasie, konto zostanie zablokowane i następnie usunięte.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2>Dlaczego warto zachować obecne konto?</h2>
|
||||||
|
|
||||||
|
<div class="benefits">
|
||||||
|
<p>Od pewnego czasu wprowadziliśmy nowe zasady dostępu do cennych zasobów:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Aby korzystać z działu <strong>download</strong>, gdzie znajdziesz schematy, instrukcje serwisowe i inne cenne materiały, wymagany jest minimalny staż w serwisie</li>
|
||||||
|
<li>Twoje obecne konto ma już historię, którą stracisz jeśli zostanie usunięte</li>
|
||||||
|
<li>Długoletnie konta mają pierwszeństwo dostępu do specjalnych zasobów</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Jeśli nadal chcesz korzystać z serwisu, wystarczy się zalogować – to wszystko!
|
Jeśli nadal chcesz korzystać z serwisu, wystarczy się zalogować – to wszystko!
|
||||||
</p>
|
</p>
|
||||||
@ -71,4 +110,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Reference in New Issue
Block a user