from django.conf import settings from django.db import OperationalError, ProgrammingError from django.utils.safestring import mark_safe from django.templatetags.static import static from .models import PageTitle, SiteBranding def site_branding(request): """Expose editable branding and the title configured for the current route.""" try: branding = SiteBranding.load() route_name = getattr(getattr(request, "resolver_match", None), "view_name", "") or "" configured = PageTitle.objects.filter(route_name=route_name, is_active=True).values_list("title", flat=True).first() except (OperationalError, ProgrammingError, RuntimeError): branding = SiteBranding() configured = None developer_credit = ( mark_safe(branding.developer_credit_html) if branding.use_developer_credit_html and branding.developer_credit_html.strip() else branding.developer_credit_text ) staff_sidebar_credit = ( mark_safe(branding.staff_sidebar_credit_html) if branding.use_staff_sidebar_credit_html and branding.staff_sidebar_credit_html.strip() else branding.staff_sidebar_credit_text ) def asset_url(field, fallback): try: return field.url if field else static(fallback) except (ValueError, OSError): return static(fallback) branding_version = str(int(branding.updated_at.timestamp())) if branding.pk and branding.updated_at else "default" return { "site_branding": branding, "page_title": configured or branding.site_title, "developer_credit": developer_credit, "staff_sidebar_credit": staff_sidebar_credit, "branding_version": branding_version, "company_logo_url": asset_url(branding.company_logo, "images/company-logo.png"), "favicon_url": asset_url(branding.favicon, "images/favicon.ico"), "pwa_icon_url": asset_url(branding.pwa_icon, "images/pwa-icon.png"), } def static_asset_version(request): """Change frontend and worker versions whenever static files or templates change.""" roots = (settings.BASE_DIR / "static", settings.BASE_DIR / "templates") mtimes = (path.stat().st_mtime_ns for root in roots if root.exists() for path in root.rglob("*") if path.is_file()) return {"static_asset_version": str(max(mtimes, default=0))} def staff_operations_access(request): """Expose unit-scoped navigation capabilities without hardcoded roles.""" user = request.user if not getattr(user, "is_authenticated", False) or getattr(user, "account_type", "") != "STAFF": return {} from apps.tickets.policies import TicketPolicy from apps.tickets.staff_conversation import unread_shares memberships = list(user.unit_memberships.filter(is_active=True, unit__is_active=True).select_related("unit")) def allowed(permission): return user.is_superuser or user.has_perm(permission) or any(TicketPolicy.has_unit_permission(user, item.unit, permission) for item in memberships) return {"staff_unread_shares": unread_shares(user), "staff_operations_access": { "create_ticket": user.has_perm("tickets.add_ticket") or allowed("tickets.add_ticket"), "contacts": True, "contact_groups": allowed("customers.view_contactgroup") or allowed("customers.add_contactgroup"), "dispatches": any(allowed(permission) for permission in ("tickets.create_bulk_dispatch", "tickets.create_inquiry", "tickets.dispatch_group_tickets", "tickets.view_all_bulk_dispatches", "tickets.view_all_inquiries")), "templates": allowed("notifications.view_smstemplate") or allowed("notifications.add_smstemplate"), "audit": user.has_perm("accounts.view_all_magic_links") or allowed("accounts.view_ticketmagiclink"), }}