Phase 2 fix remaining RBAC safe responses and work route aliases
This commit is contained in:
@@ -904,8 +904,19 @@ def partner_branch_storage_dashboard(request: Request):
|
||||
|
||||
It intentionally reuses the same storage node data model and keeps the full
|
||||
Storage Nodes screen intact. Partner/Branch Manager users are automatically
|
||||
scoped to their own branch.
|
||||
scoped to their own branch. Staff users receive a clear 403 instead of a
|
||||
generic dashboard page.
|
||||
"""
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user, response = _require_user(request, db, "documents.view")
|
||||
if response:
|
||||
return response
|
||||
scope = build_document_scope(request, db, user)
|
||||
if not _can_manage_branch_storage(scope):
|
||||
return _redirect_denied()
|
||||
finally:
|
||||
db.close()
|
||||
return storage_nodes(request)
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from datetime import datetime, timedelta, timezone
|
||||
|
||||
from fastapi import APIRouter, Form, Request
|
||||
from fastapi.responses import RedirectResponse
|
||||
from app.core.http_responses import forbidden_response
|
||||
from sqlalchemy import desc, func, or_, select
|
||||
|
||||
from app.core.db.common import CommonSessionLocal
|
||||
@@ -72,7 +73,7 @@ def email_audit_dashboard_page(request: Request):
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
now = datetime.now(timezone.utc)
|
||||
since_24h = now - timedelta(hours=24)
|
||||
@@ -197,7 +198,7 @@ def email_settings_page(request: Request, flash: str | None = None):
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
if not tenant_id:
|
||||
return RedirectResponse(url="/system-settings", status_code=303)
|
||||
@@ -258,7 +259,7 @@ def save_email_settings(
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
setting = get_or_create_email_setting(db, int(tenant_id), branch_id, actor_user_id=int(user.id))
|
||||
setting.smtp_host = smtp_host.strip() or None
|
||||
@@ -305,7 +306,7 @@ def test_email_settings(request: Request, csrf_token: str = Form(...), test_emai
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
recipient = (test_email or getattr(user, "email", "")).strip()
|
||||
send_template_email(
|
||||
@@ -333,7 +334,7 @@ def email_logs_page(request: Request):
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
q = select(EmailLog).where(EmailLog.tenant_id == tenant_id)
|
||||
if branch_id:
|
||||
@@ -356,7 +357,7 @@ def email_queue_page(request: Request, flash: str | None = None):
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
q = select(EmailLog).where(EmailLog.tenant_id == tenant_id, EmailLog.status.in_(["PENDING", "FAILED"]))
|
||||
if branch_id:
|
||||
@@ -379,7 +380,7 @@ def process_email_queue_page(request: Request, csrf_token: str = Form(...), limi
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
result = process_pending_email_queue(db, tenant_id=tenant_id, branch_id=branch_id, limit=limit)
|
||||
db.commit()
|
||||
@@ -397,7 +398,7 @@ def email_inbox_page(request: Request, flash: str | None = None):
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
q = select(EmailIncomingMessage).where(EmailIncomingMessage.tenant_id == tenant_id)
|
||||
if branch_id:
|
||||
@@ -427,7 +428,7 @@ def fetch_email_inbox_page(
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
setting = get_or_create_email_setting(db, int(tenant_id), branch_id, actor_user_id=int(user.id))
|
||||
result = fetch_incoming_emails(
|
||||
@@ -458,7 +459,7 @@ def email_inbox_detail_page(request: Request, message_id: int):
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
filters = [EmailIncomingMessage.id == message_id, EmailIncomingMessage.tenant_id == tenant_id]
|
||||
if branch_id:
|
||||
@@ -503,7 +504,7 @@ def email_inbox_map_all(request: Request, csrf_token: str = Form(...), limit: in
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
result = auto_map_unmapped_emails(db, tenant_id=tenant_id, branch_id=branch_id, limit=limit)
|
||||
db.commit()
|
||||
@@ -529,7 +530,7 @@ def email_inbox_manual_map_page(
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
filters = [EmailIncomingMessage.id == message_id, EmailIncomingMessage.tenant_id == tenant_id]
|
||||
if branch_id:
|
||||
@@ -557,7 +558,7 @@ def email_templates_page(request: Request):
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
seed_default_email_templates(db, tenant_id=tenant_id, branch_id=branch_id)
|
||||
db.commit()
|
||||
@@ -590,7 +591,7 @@ def update_email_template(
|
||||
if not user:
|
||||
return _redirect_login()
|
||||
if not _user_can_manage_email(db, user):
|
||||
return RedirectResponse(url="/employee/dashboard", status_code=303)
|
||||
return forbidden_response(request, "Access denied: email settings require administrator permission")
|
||||
tenant_id, branch_id = _scope_from_request(request, user)
|
||||
row = db.execute(
|
||||
select(EmailTemplate).where(
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Form, Request
|
||||
from fastapi.responses import RedirectResponse
|
||||
from app.core.http_responses import not_found_response
|
||||
|
||||
from app.core.db.common import CommonSessionLocal
|
||||
from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
|
||||
@@ -289,7 +290,7 @@ def lead_detail(request: Request, lead_id: int):
|
||||
return response
|
||||
lead = get_marketplace_lead(db, lead_id)
|
||||
if not lead:
|
||||
return RedirectResponse(url="/marketplace/leads", status_code=303)
|
||||
return not_found_response(request, "Marketplace lead not found")
|
||||
return _render(request, "modules/marketplace/templates/marketplace/lead_detail.html", db, user, title=f"Lead {lead.lead_no}", lead=lead, audit_firms=list_reference_audit_firms(db), branches=list_reference_branches(db, lead.assigned_tenant_id), partners=list_reference_partners(db, lead.assigned_tenant_id), can_assign=_has_perm(db, user, "marketplace_leads.assign"), can_update=_has_perm(db, user, "marketplace_leads.update"), can_convert=_has_perm(db, user, "marketplace_leads.convert"))
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Form, Request
|
||||
from fastapi.responses import RedirectResponse
|
||||
from app.core.http_responses import forbidden_response, not_found_response
|
||||
|
||||
from app.core.db.common import CommonSessionLocal
|
||||
from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
|
||||
@@ -38,6 +39,39 @@ def _fallback_for_user(db, user) -> str:
|
||||
return "/employee/work"
|
||||
|
||||
|
||||
@router.get("")
|
||||
def unified_work_board(request: Request):
|
||||
"""Compatibility alias for the common /work route.
|
||||
|
||||
Existing functionality remains in the Services Work Tracker module.
|
||||
This route only prevents stale bookmarks/tests from receiving a 404.
|
||||
"""
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user = get_current_user(request, db=db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=303)
|
||||
return RedirectResponse(url="/services/work-tracker", status_code=303)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.get("/engagements")
|
||||
def unified_engagements_index(request: Request):
|
||||
"""Compatibility alias for /work/engagements.
|
||||
|
||||
Engagement listing is maintained under /services/engagements.
|
||||
"""
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
user = get_current_user(request, db=db)
|
||||
if not user:
|
||||
return RedirectResponse(url="/login", status_code=303)
|
||||
return RedirectResponse(url="/services/engagements", status_code=303)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@router.get("/engagements/{engagement_id}")
|
||||
def unified_engagement_detail(request: Request, engagement_id: int):
|
||||
db = CommonSessionLocal()
|
||||
@@ -47,7 +81,7 @@ def unified_engagement_detail(request: Request, engagement_id: int):
|
||||
return RedirectResponse(url="/login", status_code=303)
|
||||
detail = load_unified_engagement_detail(db, request=request, user=user, engagement_id=engagement_id)
|
||||
if not detail:
|
||||
return RedirectResponse(url=_fallback_for_user(db, user), status_code=303)
|
||||
return not_found_response(request, "Work engagement not found or access denied")
|
||||
return templates.TemplateResponse(
|
||||
"modules/work_detail/templates/work_detail/engagement_detail.html",
|
||||
_base_ctx(request, db, user, title="Work Details", **detail),
|
||||
|
||||
Reference in New Issue
Block a user