- Show markdown when signing a document

- Introduce consent history
- Centralise consent and content services and config
This commit is contained in:
Josako
2025-10-17 14:06:51 +02:00
parent eeb76d57b7
commit 5501061dd1
12 changed files with 162 additions and 49 deletions

View File

@@ -1,6 +1,6 @@
from common.services.user.user_services import UserServices
from common.services.user.partner_services import PartnerServices
from common.services.user.tenant_services import TenantServices
from common.services.user.consent_service import ConsentService
from common.services.user.consent_services import ConsentServices
__all__ = ['UserServices', 'PartnerServices', 'TenantServices', 'ConsentService']
__all__ = ['UserServices', 'PartnerServices', 'TenantServices', 'ConsentServices']

View File

@@ -20,7 +20,7 @@ class TypeStatus:
last_version: Optional[str]
class ConsentService:
class ConsentServices:
@staticmethod
def get_required_consent_types() -> List[str]:
return list(current_app.config.get("CONSENT_TYPES", []))
@@ -50,12 +50,12 @@ class ConsentService:
@staticmethod
def evaluate_type_status(tenant_id: int, consent_type: str) -> TypeStatus:
active = ConsentService.get_active_consent_version(consent_type)
active = ConsentServices.get_active_consent_version(consent_type)
if not active:
current_app.logger.error(f"No active ConsentVersion found for type {consent_type}")
return TypeStatus(consent_type, ConsentStatus.UNKNOWN_CONSENT_VERSION, None, None)
last = ConsentService.get_tenant_last_consent(tenant_id, consent_type)
last = ConsentServices.get_tenant_last_consent(tenant_id, consent_type)
if not last:
return TypeStatus(consent_type, ConsentStatus.NOT_CONSENTED, active.consent_version, None)
@@ -98,8 +98,8 @@ class ConsentService:
@staticmethod
def get_consent_status(tenant_id: int) -> ConsentStatus:
statuses = [ConsentService.evaluate_type_status(tenant_id, ct) for ct in ConsentService.get_required_consent_types()]
return ConsentService.aggregate_status(statuses)
statuses = [ConsentServices.evaluate_type_status(tenant_id, ct) for ct in ConsentServices.get_required_consent_types()]
return ConsentServices.aggregate_status(statuses)
@staticmethod
def _is_tenant_admin_for(tenant_id: int) -> bool:
@@ -131,9 +131,9 @@ class ConsentService:
@staticmethod
def can_consent_on_behalf(tenant_id: int) -> Tuple[bool, str, Optional[int], Optional[int]]:
# Returns: allowed, mode('tenant_admin'|'management_partner'), partner_id, partner_service_id
if ConsentService._is_tenant_admin_for(tenant_id):
if ConsentServices._is_tenant_admin_for(tenant_id):
return True, 'tenant_admin', None, None
allowed, partner_id, partner_service_id = ConsentService._is_management_partner_for(tenant_id)
allowed, partner_id, partner_service_id = ConsentServices._is_management_partner_for(tenant_id)
if allowed:
return True, 'management_partner', partner_id, partner_service_id
return False, 'none', None, None
@@ -195,13 +195,13 @@ class ConsentService:
@staticmethod
def record_consent(tenant_id: int, consent_type: str) -> TenantConsent:
# Validate type
if consent_type not in ConsentService.get_required_consent_types():
if consent_type not in ConsentServices.get_required_consent_types():
raise ValueError(f"Unknown consent type: {consent_type}")
active = ConsentService.get_active_consent_version(consent_type)
active = ConsentServices.get_active_consent_version(consent_type)
if not active:
raise RuntimeError(f"No active ConsentVersion for type {consent_type}")
allowed, mode, partner_id, partner_service_id = ConsentService.can_consent_on_behalf(tenant_id)
allowed, mode, partner_id, partner_service_id = ConsentServices.can_consent_on_behalf(tenant_id)
if not allowed:
raise PermissionError("Not authorized to record consent for this tenant")
@@ -216,7 +216,7 @@ class ConsentService:
ip = request.headers.get('X-Forwarded-For', '').split(',')[0].strip() or request.remote_addr or ''
ua = request.headers.get('User-Agent', '')
locale = session.get('locale') or request.accept_languages.best or ''
content_meta = ConsentService._resolve_consent_content(consent_type, active.consent_version)
content_meta = ConsentServices._resolve_consent_content(consent_type, active.consent_version)
consent_data = {
'source_ip': ip,
'user_agent': ua,

View File

@@ -178,5 +178,5 @@ class TenantServices:
@staticmethod
def get_consent_status(tenant_id: int) -> ConsentStatus:
# Delegate to centralized ConsentService to ensure consistent logic
from common.services.user.consent_service import ConsentService
return ConsentService.get_consent_status(tenant_id)
from common.services.user.consent_services import ConsentServices
return ConsentServices.get_consent_status(tenant_id)