diff --git a/blueprints/community/classifieds/routes.py b/blueprints/community/classifieds/routes.py index dd7d29c..76434c2 100644 --- a/blueprints/community/classifieds/routes.py +++ b/blueprints/community/classifieds/routes.py @@ -12,7 +12,7 @@ from flask_login import login_required, current_user from . import bp from database import SessionLocal, Classified, ClassifiedRead, ClassifiedInterest, ClassifiedQuestion, ClassifiedAttachment, User from sqlalchemy import desc -from utils.helpers import sanitize_input +from utils.helpers import sanitize_input, sanitize_html from utils.decorators import member_required from utils.notifications import ( create_classified_question_notification, @@ -87,7 +87,7 @@ def new(): listing_type = request.form.get('listing_type', '') category = request.form.get('category', '') title = sanitize_input(request.form.get('title', ''), 255) - description = request.form.get('description', '').strip() + description = sanitize_html(request.form.get('description', '').strip()) budget_info = sanitize_input(request.form.get('budget_info', ''), 255) location_info = sanitize_input(request.form.get('location_info', ''), 255) @@ -259,7 +259,7 @@ def edit(classified_id): classified.listing_type = request.form.get('listing_type', classified.listing_type) classified.category = request.form.get('category', classified.category) classified.title = sanitize_input(request.form.get('title', ''), 255) - classified.description = request.form.get('description', '').strip() + classified.description = sanitize_html(request.form.get('description', '').strip()) classified.budget_info = sanitize_input(request.form.get('budget_info', ''), 255) classified.location_info = sanitize_input(request.form.get('location_info', ''), 255) classified.updated_at = datetime.now() diff --git a/scripts/classified_expiry_notifier.py b/scripts/classified_expiry_notifier.py new file mode 100644 index 0000000..f680d4c --- /dev/null +++ b/scripts/classified_expiry_notifier.py @@ -0,0 +1,109 @@ +#!/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 + + 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""" +
+

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, kliknij poniższy przycisk:

+

+ + Przedłuż ogłoszenie + +

+

Jeśli ogłoszenie jest już nieaktualne, nie musisz nic robić — wygaśnie automatycznie.

+
+

Portal NordaBiznes.pl — Izba Gospodarcza Norda Biznes

+
""" + + 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() diff --git a/templates/classifieds/edit.html b/templates/classifieds/edit.html index 2fe7351..99ebe86 100644 --- a/templates/classifieds/edit.html +++ b/templates/classifieds/edit.html @@ -2,6 +2,11 @@ {% block title %}Edycja ogloszenia - Norda Biznes Partner{% endblock %} +{% block head_extra %} + + +{% endblock %} + {% block extra_css %}