Mar 02 2026: fix notification update, and sent email
This commit is contained in:
@@ -239,7 +239,7 @@
|
||||
}
|
||||
function escapeAttr(str) { return escapeHtml(str); }
|
||||
|
||||
function fetchNotifications() {
|
||||
window.fetchNotifications = function fetchNotifications() {
|
||||
fetch(FEED_URL, { credentials: 'same-origin' })
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
{% if comments %}
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0"><i class="bi bi-clock-history"></i> Update History</h6>
|
||||
<h6 class="mb-0" id="update-history"><i class="bi bi-clock-history"></i> Update History</h6>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush">
|
||||
{% for c in comments %}
|
||||
@@ -181,4 +181,32 @@
|
||||
<a href="{{ url_for('issues.index') }}" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-arrow-left"></i> Back to Issues
|
||||
</a>
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// ── Immediate bell refresh after a successful update ──────────────────
|
||||
// After form submit + redirect, Flask flashes 'Issue updated.' and the
|
||||
// URL stays at /issues/<id>. We detect the flash message presence and
|
||||
// call the global fetchNotifications() defined in base.html so the bell
|
||||
// badge updates instantly without waiting for the 60-second poll cycle.
|
||||
if (document.querySelector('.alert-success')) {
|
||||
if (typeof fetchNotifications === 'function') {
|
||||
fetchNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
// ── Auto-scroll to Update History after save ──────────────────────────
|
||||
// If there's a success flash AND comments exist, scroll the history
|
||||
// section into view so the newly added comment is immediately visible.
|
||||
if (document.querySelector('.alert-success')) {
|
||||
var historyEl = document.getElementById('update-history');
|
||||
if (historyEl) {
|
||||
historyEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -24,7 +24,7 @@ Digest emails are sent by calling send_pending_digests(frequency) from the
|
||||
/notifications/send-digest route, which is triggered by a server cron job.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import logging, threading
|
||||
from flask import current_app, render_template_string
|
||||
from flask_mail import Message
|
||||
from app import db, mail
|
||||
@@ -218,7 +218,13 @@ def notify(
|
||||
|
||||
|
||||
def _send_single_email(recipient, title, body, link):
|
||||
"""Dispatch a single immediate notification email. Fire-and-forget."""
|
||||
"""Dispatch a single immediate notification email in a background thread.
|
||||
|
||||
Sending is offloaded to a daemon thread so SMTP latency never blocks the
|
||||
HTTP response. The Flask application context is pushed explicitly so that
|
||||
Flask-Mail and config lookups work outside the request context.
|
||||
"""
|
||||
# Render templates while still inside the request context
|
||||
try:
|
||||
base_url = current_app.config.get('APP_BASE_URL', '').rstrip('/')
|
||||
sender = current_app.config.get(
|
||||
@@ -238,17 +244,32 @@ def _send_single_email(recipient, title, body, link):
|
||||
body = text_body,
|
||||
html = html_body,
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.error('NOTIFICATION EMAIL BUILD FAILED | to=%s | error=%s', recipient.email, exc)
|
||||
return
|
||||
|
||||
# Capture app instance before leaving the request context
|
||||
app = current_app._get_current_object()
|
||||
recipient_email = recipient.email
|
||||
subject = msg.subject
|
||||
|
||||
def _send():
|
||||
with app.app_context():
|
||||
try:
|
||||
mail.send(msg)
|
||||
logger.info(
|
||||
'NOTIFICATION EMAIL SENT | to=%s | subject=%s',
|
||||
recipient.email, msg.subject,
|
||||
recipient_email, subject,
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.error(
|
||||
'NOTIFICATION EMAIL FAILED | to=%s | error=%s',
|
||||
recipient.email, exc,
|
||||
recipient_email, exc,
|
||||
)
|
||||
|
||||
t = threading.Thread(target=_send, daemon=True)
|
||||
t.start()
|
||||
|
||||
|
||||
# ── Digest delivery ────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user