from __future__ import annotations from django.contrib.auth import get_user_model from django.contrib.auth.models import Group from django.utils.translation import gettext_lazy as _ # Product-level and company-level roles intentionally coexist here. # Workdock uses capability checks as the long-term contract so app-registry # visibility can stay a presentation concern instead of an authorization layer. ROLE_PLATFORM_OWNER = 'platform_owner' ROLE_SUPER_ADMIN = 'super_admin' ROLE_ADMIN = 'admin' ROLE_IT_STAFF = 'it_staff' ROLE_STAFF = 'staff' ROLE_GROUP_NAMES = { ROLE_PLATFORM_OWNER: 'Platform Owner', ROLE_SUPER_ADMIN: 'Super Admin', ROLE_ADMIN: 'Admin', ROLE_IT_STAFF: 'IT Staff', ROLE_STAFF: 'Staff', } ROLE_LABELS = { ROLE_PLATFORM_OWNER: _('Platform Owner'), ROLE_SUPER_ADMIN: _('Super Admin'), ROLE_ADMIN: _('Admin'), ROLE_IT_STAFF: _('IT Staff'), ROLE_STAFF: _('Mitarbeiter'), } CAPABILITIES = { # Platform-only capabilities stay above any customer-company admin role. 'manage_users': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN}, 'manage_product_branding': {ROLE_PLATFORM_OWNER}, 'manage_company_config': {ROLE_PLATFORM_OWNER}, 'manage_trial_lifecycle': {ROLE_PLATFORM_OWNER}, 'manage_app_registry': {ROLE_PLATFORM_OWNER}, 'access_requests_dashboard': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN, ROLE_IT_STAFF, ROLE_STAFF}, 'view_request_timeline': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN, ROLE_IT_STAFF}, 'run_intro_session': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN, ROLE_IT_STAFF}, 'generate_intro_pdfs': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN, ROLE_IT_STAFF}, 'retry_requests': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN, ROLE_IT_STAFF}, 'delete_requests': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN}, 'manage_integrations': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN}, 'manage_welcome_emails': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN}, 'manage_builders': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN}, 'view_job_monitor': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN}, 'view_audit_log': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN}, 'manage_backups': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN}, 'view_docs': {ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN}, 'access_django_admin_link': {ROLE_PLATFORM_OWNER}, } def ensure_role_groups() -> None: for name in ROLE_GROUP_NAMES.values(): Group.objects.get_or_create(name=name) def assign_user_role(user, role_key: str) -> None: ensure_role_groups() if role_key not in ROLE_GROUP_NAMES: raise ValueError(f'Unknown role: {role_key}') role_groups = Group.objects.filter(name__in=ROLE_GROUP_NAMES.values()) user.groups.remove(*role_groups) user.groups.add(Group.objects.get(name=ROLE_GROUP_NAMES[role_key])) is_product_owner = role_key == ROLE_PLATFORM_OWNER is_super_admin = role_key == ROLE_SUPER_ADMIN user.is_staff = is_product_owner or is_super_admin user.is_superuser = is_product_owner user.save(update_fields=['is_staff', 'is_superuser']) def ensure_bootstrap_role_assignments() -> None: user_model = get_user_model() bootstrap_roles = { 'admin_test': ROLE_PLATFORM_OWNER, 'user_test': ROLE_STAFF, } role_group_names = set(ROLE_GROUP_NAMES.values()) for username, role_key in bootstrap_roles.items(): try: user = user_model.objects.get(username=username) except user_model.DoesNotExist: continue if role_key == ROLE_PLATFORM_OWNER and not any( get_user_role_key(existing_user) == ROLE_PLATFORM_OWNER for existing_user in user_model.objects.all() ): assign_user_role(user, ROLE_PLATFORM_OWNER) continue if user.groups.filter(name__in=role_group_names).exists(): continue assign_user_role(user, role_key) def get_user_role_key(user) -> str: # Keep a conservative fallback for legacy staff users until a later # dedicated cleanup phase removes the remaining historical assumptions. if not getattr(user, 'is_authenticated', False): return ROLE_STAFF if getattr(user, 'is_superuser', False): return ROLE_PLATFORM_OWNER group_names = set(user.groups.values_list('name', flat=True)) for role_key in (ROLE_PLATFORM_OWNER, ROLE_SUPER_ADMIN, ROLE_ADMIN, ROLE_IT_STAFF, ROLE_STAFF): if ROLE_GROUP_NAMES[role_key] in group_names: return role_key if getattr(user, 'is_staff', False): return ROLE_SUPER_ADMIN return ROLE_STAFF def get_user_role_label(user) -> str: return str(ROLE_LABELS[get_user_role_key(user)]) def user_has_capability(user, capability: str) -> bool: if not getattr(user, 'is_authenticated', False): return False if getattr(user, 'is_superuser', False): return True allowed_roles = CAPABILITIES.get(capability, set()) return get_user_role_key(user) in allowed_roles def template_role_context(user) -> dict[str, object]: role_key = get_user_role_key(user) avatar_url = '' if getattr(user, 'is_authenticated', False): profile = getattr(user, 'profile', None) avatar = getattr(profile, 'avatar_image', None) if avatar: avatar_url = getattr(avatar, 'url', '') or '' return { 'role_key': role_key, 'role_label': str(ROLE_LABELS[role_key]), 'user_avatar_url': avatar_url, 'can_manage_product_branding': user_has_capability(user, 'manage_product_branding'), 'can_manage_company_config': user_has_capability(user, 'manage_company_config'), 'can_manage_trial_lifecycle': user_has_capability(user, 'manage_trial_lifecycle'), 'can_manage_app_registry': user_has_capability(user, 'manage_app_registry'), 'can_manage_users': user_has_capability(user, 'manage_users'), 'can_access_requests_dashboard': user_has_capability(user, 'access_requests_dashboard'), 'can_view_request_timeline': user_has_capability(user, 'view_request_timeline'), 'can_run_intro_session': user_has_capability(user, 'run_intro_session'), 'can_generate_intro_pdfs': user_has_capability(user, 'generate_intro_pdfs'), 'can_retry_requests': user_has_capability(user, 'retry_requests'), 'can_delete_requests': user_has_capability(user, 'delete_requests'), 'can_manage_integrations': user_has_capability(user, 'manage_integrations'), 'can_manage_welcome_emails': user_has_capability(user, 'manage_welcome_emails'), 'can_manage_builders': user_has_capability(user, 'manage_builders'), 'can_view_job_monitor': user_has_capability(user, 'view_job_monitor'), 'can_view_audit_log': user_has_capability(user, 'view_audit_log'), 'can_manage_backups': user_has_capability(user, 'manage_backups'), 'can_view_docs': user_has_capability(user, 'view_docs'), 'can_access_django_admin_link': user_has_capability(user, 'access_django_admin_link'), }