feat: add SUPERADMIN role (200) with full audit access
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions

Replace hardcoded email check for audit panels with role-based
SUPERADMIN check. ADMIN retains all management capabilities but
SUPERADMIN adds access to technical audits (SEO, IT, GBP, Social,
Access Control).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Maciej Pienczyn 2026-03-13 11:20:25 +01:00
parent 8f37ef4ded
commit f960a4cf0d
2 changed files with 9 additions and 7 deletions

View File

@ -50,7 +50,8 @@ class SystemRole(IntEnum):
- EMPLOYEE (30): Pracownik firmy członkowskiej - może edytować dane firmy
- MANAGER (40): Kadra zarządzająca - pełna kontrola firmy + zarządzanie użytkownikami
- OFFICE_MANAGER (50): Kierownik biura Norda - panel admina (bez użytkowników)
- ADMIN (100): Administrator portalu - pełne prawa
- ADMIN (100): Administrator portalu - zarządzanie treścią i użytkownikami
- SUPERADMIN (200): Superadministrator - pełne prawa + audyty techniczne
"""
UNAFFILIATED = 10 # Niezrzeszony (firma spoza Izby)
MEMBER = 20 # Członek Norda bez firmy
@ -58,6 +59,7 @@ class SystemRole(IntEnum):
MANAGER = 40 # Kadra zarządzająca firmy
OFFICE_MANAGER = 50 # Kierownik biura Norda
ADMIN = 100 # Administrator portalu
SUPERADMIN = 200 # Superadministrator - pełne prawa + audyty
@classmethod
def choices(cls):
@ -69,6 +71,7 @@ class SystemRole(IntEnum):
cls.MANAGER: 'Kadra Zarządzająca',
cls.OFFICE_MANAGER: 'Kierownik Biura',
cls.ADMIN: 'Administrator',
cls.SUPERADMIN: 'Superadministrator',
}
return [(role.value, labels[role]) for role in cls]
@ -82,6 +85,7 @@ class SystemRole(IntEnum):
'MANAGER': cls.MANAGER,
'OFFICE_MANAGER': cls.OFFICE_MANAGER,
'ADMIN': cls.ADMIN,
'SUPERADMIN': cls.SUPERADMIN,
}
return mapping.get(value.upper(), cls.UNAFFILIATED)
@ -560,7 +564,7 @@ class User(Base, UserMixin):
"""
self.role = new_role.name
if sync_is_admin:
self.is_admin = (new_role == SystemRole.ADMIN)
self.is_admin = (new_role >= SystemRole.ADMIN)
def set_company_role(self, new_role: CompanyRole):
"""Set the user's company role."""

View File

@ -18,14 +18,12 @@ from functools import wraps
from flask import abort, flash, redirect, url_for, request
from flask_login import current_user
# Audit access restriction — only this user sees SEO/IT/GBP/Social audits
AUDIT_OWNER_EMAIL = 'maciej.pienczyn@inpi.pl'
def is_audit_owner():
"""True only for the designated audit owner."""
"""True for SUPERADMIN users — full access to audits and technical panels."""
if not current_user.is_authenticated:
return False
return current_user.email == AUDIT_OWNER_EMAIL
from database import SystemRole
return current_user.has_role(SystemRole.SUPERADMIN)
# Import role enums (lazy import to avoid circular dependencies)
def _get_system_role():