"""Newsletter subscription routes.""" from __future__ import annotations import logging from flask import Blueprint, jsonify, request, render_template from ..services import newsletter bp = Blueprint("newsletter", __name__) @bp.route("/api/newsletter", methods=["POST"]) def subscribe(): payload = request.form or request.get_json(silent=True) or {} email = (payload.get("email") or "").strip() if not newsletter.validate_email(email): return jsonify({"status": "error", "message": "Valid email is required."}), 400 try: created = newsletter.subscribe(email) except Exception as exc: # pragma: no cover - errors are logged logging.exception("Failed to persist subscriber: %s", exc) return jsonify({"status": "error", "message": "Could not store subscription."}), 500 if not created: logging.info("Newsletter subscription ignored (duplicate): %s", email) return jsonify({"status": "error", "message": "Email is already subscribed."}), 409 logging.info("New newsletter subscription: %s", email) # Send confirmation email email_sent = newsletter.send_subscription_confirmation(email) if not email_sent: logging.warning("Confirmation email not sent for %s", email) return jsonify({"status": "ok", "message": "Subscribed successfully."}), 201 @bp.route("/api/newsletter", methods=["DELETE"]) def unsubscribe(): payload = request.form or request.get_json(silent=True) or {} email = (payload.get("email") or "").strip() if not newsletter.validate_email(email): return jsonify({"status": "error", "message": "Valid email is required."}), 400 try: deleted = newsletter.unsubscribe(email) except Exception as exc: # pragma: no cover - errors are logged logging.exception("Failed to remove subscriber: %s", exc) return jsonify({"status": "error", "message": "Could not remove subscription."}), 500 if not deleted: logging.info( "Newsletter unsubscription ignored (not subscribed): %s", email) return jsonify({"status": "error", "message": "Email is not subscribed."}), 404 logging.info("Newsletter unsubscription: %s", email) return jsonify({"status": "ok", "message": "Unsubscribed successfully."}), 200 @bp.route("/api/newsletter", methods=["PUT"]) def update_subscription(): payload = request.form or request.get_json(silent=True) or {} old_email = (payload.get("old_email") or "").strip() new_email = (payload.get("new_email") or "").strip() if not newsletter.validate_email(old_email) or not newsletter.validate_email(new_email): return jsonify({"status": "error", "message": "Valid old and new emails are required."}), 400 try: updated = newsletter.update_email(old_email, new_email) except Exception as exc: # pragma: no cover - errors are logged logging.exception("Failed to update subscriber: %s", exc) return jsonify({"status": "error", "message": "Could not update subscription."}), 500 if not updated: return jsonify({"status": "error", "message": "Old email not found or new email already exists."}), 404 logging.info("Newsletter subscription updated: %s -> %s", old_email, new_email) return jsonify({"status": "ok", "message": "Subscription updated successfully."}), 200 @bp.route("/newsletter/manage", methods=["GET", "POST"]) def manage_subscription(): """Display newsletter subscription management page.""" message = None message_type = None if request.method == "POST": action = request.form.get("action") email = (request.form.get("email") or "").strip() if not newsletter.validate_email(email): message = "Please enter a valid email address." message_type = "error" else: try: if action == "subscribe": created = newsletter.subscribe(email) if created: message = "Successfully subscribed to newsletter!" message_type = "success" else: message = "This email is already subscribed." message_type = "info" elif action == "unsubscribe": deleted = newsletter.unsubscribe(email) if deleted: return render_template("unsubscribe_confirmation.html") else: message = "This email is not currently subscribed." message_type = "info" elif action == "update": old_email = (request.form.get("old_email") or "").strip() if not newsletter.validate_email(old_email): message = "Please enter a valid current email address." message_type = "error" elif old_email == email: message = "New email must be different from current email." message_type = "error" else: updated = newsletter.update_email(old_email, email) if updated: message = "Email address updated successfully!" message_type = "success" else: message = "Current email not found or new email already exists." message_type = "error" except Exception as exc: logging.exception("Failed to manage subscription: %s", exc) message = "An error occurred. Please try again." message_type = "error" return render_template("newsletter_manage.html", message=message, message_type=message_type) @bp.route("/newsletter/unsubscribe/confirmation", methods=["GET"]) def unsubscribe_confirmation(): """Display newsletter unsubscription confirmation page.""" return render_template("unsubscribe_confirmation.html")