Mar 02 2026: fix email notification

This commit is contained in:
2026-03-02 15:24:49 -05:00
parent f73a641aef
commit 7e12d519c1
2 changed files with 51 additions and 2 deletions
+42
View File
@@ -5,6 +5,8 @@ from flask_migrate import Migrate
from flask_mail import Mail from flask_mail import Mail
from config import config from config import config
import os import os
import logging
from logging.handlers import RotatingFileHandler
db = SQLAlchemy() db = SQLAlchemy()
login_manager = LoginManager() login_manager = LoginManager()
@@ -25,6 +27,46 @@ def create_app(config_name='default'):
login_manager.login_message = 'Please log in to access this page.' login_manager.login_message = 'Please log in to access this page.'
login_manager.login_message_category = 'info' login_manager.login_message_category = 'info'
# ── Logging setup ────────────────────────────────────────────────────────
# Configure root logger so that logger.info/error calls in all modules
# (notifications.py, issues.py, etc.) actually write output.
# Writes to stdout (captured by journalctl/gunicorn) AND a rotating file.
if not app.debug or os.environ.get('LOG_TO_FILE'):
log_level = logging.INFO
formatter = logging.Formatter(
'[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
)
# Stream handler — always on; journalctl captures stdout
stream_handler = logging.StreamHandler()
stream_handler.setLevel(log_level)
stream_handler.setFormatter(formatter)
# Rotating file handler — keeps 5 × 5 MB log files
log_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'logs')
os.makedirs(log_dir, exist_ok=True)
file_handler = RotatingFileHandler(
os.path.join(log_dir, 'jqc.log'),
maxBytes=5 * 1024 * 1024,
backupCount=5,
)
file_handler.setLevel(log_level)
file_handler.setFormatter(formatter)
# Apply to both the Flask app logger and the root logger so all
# getLogger(__name__) calls in sub-modules are captured.
app.logger.setLevel(log_level)
app.logger.addHandler(stream_handler)
app.logger.addHandler(file_handler)
root_logger = logging.getLogger()
root_logger.setLevel(log_level)
if not root_logger.handlers:
root_logger.addHandler(stream_handler)
root_logger.addHandler(file_handler)
# Register csrf_token() as an app-wide Jinja2 global so templates that # Register csrf_token() as an app-wide Jinja2 global so templates that
# render manual forms (no WTForms object) can still inject the CSRF token. # render manual forms (no WTForms object) can still inject the CSRF token.
from flask_wtf.csrf import generate_csrf from flask_wtf.csrf import generate_csrf
+9 -2
View File
@@ -52,11 +52,18 @@ class Config:
DIGEST_SECRET = os.environ.get('DIGEST_SECRET') DIGEST_SECRET = os.environ.get('DIGEST_SECRET')
MAIL_SERVER = os.environ.get('MAIL_SERVER') MAIL_SERVER = os.environ.get('MAIL_SERVER')
MAIL_PORT = int(os.environ.get('MAIL_PORT') or 587)
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true').lower() in ('true', 'on', '1')
MAIL_USERNAME = os.environ.get('MAIL_USERNAME') MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
# ── SSL vs STARTTLS selection ────────────────────────────────────────────
# Port 465 = implicit SSL → MAIL_USE_SSL=True, MAIL_USE_TLS=False
# Port 587 = STARTTLS → MAIL_USE_SSL=False, MAIL_USE_TLS=True
# The two flags are mutually exclusive; setting both True breaks Flask-Mail.
_mail_port = int(os.environ.get('MAIL_PORT') or 587)
MAIL_PORT = _mail_port
MAIL_USE_SSL = _mail_port == 465
MAIL_USE_TLS = not MAIL_USE_SSL # STARTTLS only when NOT using implicit SSL
class DevelopmentConfig(Config): class DevelopmentConfig(Config):
DEBUG = True DEBUG = True