Jun 26 MT-1 phase
This commit is contained in:
+33
-54
@@ -11,7 +11,9 @@ import os
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
db = SQLAlchemy()
|
||||
from app.tenancy.routing import RoutingSession
|
||||
|
||||
db = SQLAlchemy(session_options={'class_': RoutingSession})
|
||||
login_manager = LoginManager()
|
||||
migrate = Migrate()
|
||||
mail = Mail()
|
||||
@@ -37,6 +39,13 @@ def create_app(config_name='default'):
|
||||
csrf.init_app(app) # enables CSRF protection for all web routes
|
||||
limiter.init_app(app) # rate limiting — applied per-route via @limiter.limit()
|
||||
|
||||
# ── Multi-tenant resolution (MT-1) ───────────────────────────────────────
|
||||
# Registers the before_request Host→tenant resolver. Inert (no-op) unless
|
||||
# config MULTI_TENANT_ENABLED is True, so the single-tenant deployment is
|
||||
# unaffected until tenants are provisioned and the flag is flipped.
|
||||
from app.tenancy.middleware import init_tenancy
|
||||
init_tenancy(app)
|
||||
|
||||
login_manager.login_view = 'auth.login'
|
||||
login_manager.login_message = 'Please log in to access this page.'
|
||||
login_manager.login_message_category = 'info'
|
||||
@@ -103,56 +112,32 @@ def create_app(config_name='default'):
|
||||
|
||||
@app.context_processor
|
||||
def inject_notification_count():
|
||||
if not current_user.is_authenticated:
|
||||
return {
|
||||
'unread_notification_count': 0,
|
||||
'pending_verification_count': 0,
|
||||
'open_support_tickets_count': 0,
|
||||
}
|
||||
|
||||
# ── Unread notification count (all roles) ──────────────────────────
|
||||
# Computed first, in its own try/except, so a failure in the
|
||||
# director-specific queries below never zeroes out the bell badge.
|
||||
try:
|
||||
from app.models.notification import Notification
|
||||
unread = Notification.query.filter_by(
|
||||
user_id=current_user.id, is_read=False
|
||||
).count()
|
||||
except Exception as exc:
|
||||
import logging as _logging
|
||||
_logging.getLogger(__name__).warning(
|
||||
'inject_notification_count: unread query failed: %s', exc
|
||||
)
|
||||
unread = 0
|
||||
|
||||
# ── Director/admin-only counts ─────────────────────────────────────
|
||||
pv_count = 0
|
||||
open_support = 0
|
||||
if current_user.role in ('admin', 'director'):
|
||||
try:
|
||||
if current_user.is_authenticated:
|
||||
from app.models.notification import Notification
|
||||
from app.models.issue import Issue
|
||||
pv_count = Issue.query.filter_by(
|
||||
status='pending_verification'
|
||||
unread = Notification.query.filter_by(
|
||||
user_id=current_user.id, is_read=False
|
||||
).count()
|
||||
except Exception as exc:
|
||||
import logging as _logging
|
||||
_logging.getLogger(__name__).warning(
|
||||
'inject_notification_count: pv_count query failed: %s', exc
|
||||
)
|
||||
try:
|
||||
from app.models.support import SupportTicket
|
||||
open_support = SupportTicket.query.filter_by(status='open').count()
|
||||
except Exception as exc:
|
||||
import logging as _logging
|
||||
_logging.getLogger(__name__).warning(
|
||||
'inject_notification_count: support_tickets query failed: %s', exc
|
||||
)
|
||||
|
||||
return {
|
||||
'unread_notification_count': unread,
|
||||
'pending_verification_count': pv_count,
|
||||
'open_support_tickets_count': open_support,
|
||||
}
|
||||
# Pending verification count — only computed for director+ roles
|
||||
pv_count = 0
|
||||
if current_user.role in ('admin', 'director'):
|
||||
pv_count = Issue.query.filter_by(
|
||||
status='pending_verification'
|
||||
).count()
|
||||
# Open support tickets — admin/director only
|
||||
open_support = 0
|
||||
if current_user.role in ('admin', 'director'):
|
||||
from app.models.support import SupportTicket
|
||||
open_support = SupportTicket.query.filter_by(status='open').count()
|
||||
return {
|
||||
'unread_notification_count': unread,
|
||||
'pending_verification_count': pv_count,
|
||||
'open_support_tickets_count': open_support,
|
||||
}
|
||||
except Exception:
|
||||
pass
|
||||
return {'unread_notification_count': 0, 'pending_verification_count': 0, 'open_support_tickets_count': 0}
|
||||
|
||||
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
||||
|
||||
@@ -164,8 +149,6 @@ def create_app(config_name='default'):
|
||||
from app.routes import customers # Phase 5 — Customer management
|
||||
from app.routes import scheduled_reports # Phase 6 — Scheduled reports
|
||||
from app.routes import support # Support chat + admin tickets
|
||||
from app.routes import broadcast # Admin broadcast notifications
|
||||
from app.routes import devices # Admin device registry
|
||||
|
||||
app.register_blueprint(auth.bp)
|
||||
app.register_blueprint(dashboard.bp)
|
||||
@@ -180,8 +163,6 @@ def create_app(config_name='default'):
|
||||
app.register_blueprint(customers.bp)
|
||||
app.register_blueprint(scheduled_reports.bp)
|
||||
app.register_blueprint(support.bp)
|
||||
app.register_blueprint(broadcast.bp)
|
||||
app.register_blueprint(devices.bp)
|
||||
|
||||
# ── Mobile API (Phase 7 / Phase A / Phase B / Phase C) ───────────────────
|
||||
# The /api/v1 blueprint group uses JWT Bearer tokens — no CSRF cookies needed.
|
||||
@@ -199,7 +180,6 @@ def create_app(config_name='default'):
|
||||
from app.api.notifications import bp as _api_notifications_bp
|
||||
from app.api.stats import bp as _api_stats_bp
|
||||
from app.api.comments import bp as _api_comments_bp
|
||||
from app.api.devices import bp as _api_devices_bp
|
||||
csrf.exempt(_api_auth_bp)
|
||||
csrf.exempt(_api_facilities_bp)
|
||||
csrf.exempt(_api_templates_bp)
|
||||
@@ -209,7 +189,6 @@ def create_app(config_name='default'):
|
||||
csrf.exempt(_api_notifications_bp)
|
||||
csrf.exempt(_api_stats_bp)
|
||||
csrf.exempt(_api_comments_bp)
|
||||
csrf.exempt(_api_devices_bp)
|
||||
register_api(app)
|
||||
|
||||
# ── Security response headers ─────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user