nordabiz/scripts/classified_expiry_notifier.py
Maciej Pienczyn 3f1e66d3ca
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
feat(email): per-typ preferencje powiadomień e-mail (D.1 dopełnienie)
Symetria z push — panel /konto/prywatnosc rozszerzony o 3 dodatkowe
toggle w karcie "Powiadomienia e-mail":
- Pytanie pod moim ogłoszeniem B2B (notify_email_classified_question)
- Odpowiedź pod moim pytaniem B2B (notify_email_classified_answer)
- Ogłoszenie wygasa za 3 dni (notify_email_classified_expiry)

Migracja 102 dodaje kolumny (default TRUE — nie zmienia zachowania
istniejących userów). Endpointy ask_question / answer_question teraz
czytają dedykowaną flagę zamiast notify_email_messages (która zostaje
tylko dla wiadomości prywatnych). Skrypt classified_expiry_notifier.py
pomija userów z wyłączonym notify_email_classified_expiry.

W kolejnych sub-fazach D.2/D.3 symetrycznie dojdą triggery e-mail +
toggle dla forum/broadcast/wydarzeń — z defaults dobranymi tak, by
nie zalać inbox użytkowników (broadcast OFF, personalne ON).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 17:50:41 +02:00

115 lines
4.2 KiB
Python

#!/usr/bin/env python3
"""
Classified Expiry Notifier
==========================
Sends email notifications to classified authors 3 days before expiry.
Run daily via cron: 0 8 * * * cd /var/www/nordabiznes && venv/bin/python3 scripts/classified_expiry_notifier.py
Author: Maciej Pienczyn, InPi sp. z o.o.
"""
import os
import sys
# Add project root to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from datetime import datetime, timedelta
from database import SessionLocal, Classified, User
def main():
# Initialize email service
from dotenv import load_dotenv
load_dotenv()
from email_service import init_email_service, send_email
init_email_service()
db = SessionLocal()
try:
# Find classifieds expiring in exactly 3 days
target_date = datetime.now().date() + timedelta(days=3)
next_day = target_date + timedelta(days=1)
expiring = db.query(Classified).filter(
Classified.is_active == True,
Classified.expires_at >= datetime.combine(target_date, datetime.min.time()),
Classified.expires_at < datetime.combine(next_day, datetime.min.time())
).all()
if not expiring:
print(f"[{datetime.now()}] Brak ogłoszeń wygasających {target_date}")
return
print(f"[{datetime.now()}] Znaleziono {len(expiring)} ogłoszeń wygasających {target_date}")
for classified in expiring:
author = db.query(User).filter(User.id == classified.author_id).first()
if not author or not author.email:
continue
# Respect user preference
if getattr(author, 'notify_email_classified_expiry', True) is False:
print(f" [pomijam] {classified.title} -> {author.email} (wyłączył powiadomienia e-mail o wygasaniu)")
continue
author_name = author.name or author.email.split('@')[0]
expire_date = classified.expires_at.strftime('%d.%m.%Y')
extend_url = f"https://nordabiznes.pl/tablica/{classified.id}"
subject = f"Twoje ogłoszenie wygasa za 3 dni: {classified.title}"
body_text = f"""Cześć {author_name},
Twoje ogłoszenie na portalu NordaBiznes.pl wygasa {expire_date}:
{classified.title}"
Jeśli chcesz je przedłużyć o kolejne 30 dni, wejdź na stronę ogłoszenia i kliknij przycisk „Przedłuż o 30 dni":
{extend_url}
Jeśli ogłoszenie jest już nieaktualne, nie musisz nic robić — wygaśnie automatycznie.
Pozdrawiam,
Portal NordaBiznes.pl"""
body_html = f"""
<div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; max-width: 600px; margin: 0 auto;">
<p>Cześć {author_name},</p>
<p>Twoje ogłoszenie na portalu NordaBiznes.pl wygasa <strong>{expire_date}</strong>:</p>
<div style="background: #f8fafc; border-left: 4px solid #2E4872; padding: 16px; margin: 16px 0; border-radius: 4px;">
<strong>{classified.title}</strong>
</div>
<p>Jeśli chcesz je przedłużyć o kolejne 30 dni, kliknij poniższy przycisk:</p>
<p style="text-align: center; margin: 24px 0;">
<a href="{extend_url}" style="background: #2E4872; color: white; padding: 12px 24px; border-radius: 6px; text-decoration: none; font-weight: 600;">
Przedłuż ogłoszenie
</a>
</p>
<p style="color: #64748b; font-size: 14px;">Jeśli ogłoszenie jest już nieaktualne, nie musisz nic robić — wygaśnie automatycznie.</p>
<hr style="border: none; border-top: 1px solid #e2e8f0; margin: 24px 0;">
<p style="color: #94a3b8; font-size: 12px;">Portal NordaBiznes.pl — Izba Gospodarcza Norda Biznes</p>
</div>"""
success = send_email(
to=[author.email],
subject=subject,
body_text=body_text,
body_html=body_html,
email_type='classified_expiry',
user_id=author.id,
recipient_name=author_name
)
status = "wysłano" if success else "BŁĄD"
print(f" [{status}] {classified.title} -> {author.email} (wygasa {expire_date})")
finally:
db.close()
if __name__ == '__main__':
main()