loko/streetup/maps/permissions.py
2026-07-22 14:48:40 +02:00

115 lines
3.4 KiB
Python

from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import PermissionDenied
from django.shortcuts import redirect
from django.conf import settings
from urllib.parse import urlencode
from functools import wraps
def _user_has_restricted_access(user, map_config):
"""
Return True if an authenticated *user* satisfies at least one of the
restricted-access conditions configured on *map_config*.
Admins always bypass the restriction.
"""
from common.models import UserConfig, UserThematics
try:
user_config = UserConfig.objects.get(user=user)
except UserConfig.DoesNotExist:
return False
# Admin role: unconditional bypass
if user_config.roles.filter(name='admin').exists():
return True
# Thematic-based access
if map_config.thematics.exists():
user_thematic_ids = UserThematics.objects.filter(
user_config=user_config
).values_list('thematic_id', flat=True)
if map_config.thematics.filter(pk__in=user_thematic_ids).exists():
return True
# Team-based access
if map_config.teams.exists():
from contracts.models import UserCompanyTeamAccess
user_team_ids = UserCompanyTeamAccess.objects.filter(
user_config=user_config
).values_list('team_id', flat=True)
if map_config.teams.filter(pk__in=user_team_ids).exists():
return True
# Direct user access
if map_config.users.filter(pk=user.pk).exists():
return True
return False
def check_map_access(request, map_code):
"""
Verify that *request* is authorised to access the map identified by
*map_code*.
Returns ``True`` on success.
Returns a redirect ``HttpResponse`` when the user needs to authenticate.
Raises ``PermissionDenied`` when the user is authenticated but not
authorised.
When no ``MapConfig`` record exists for *map_code* the default policy is
``authenticated`` (any logged-in user may access).
"""
from .models import MapConfig
try:
map_config = MapConfig.objects.get(code=map_code)
except MapConfig.DoesNotExist:
# Fallback: require authentication
if not request.user.is_authenticated:
return _login_redirect(request)
return True
if map_config.access_level == MapConfig.ACCESS_PUBLIC:
return True
if not request.user.is_authenticated:
return _login_redirect(request)
if map_config.access_level == MapConfig.ACCESS_AUTHENTICATED:
return True
# ACCESS_RESTRICTED
if _user_has_restricted_access(request.user, map_config):
return True
raise PermissionDenied
def _login_redirect(request):
login_url = settings.LOGIN_URL
path = request.get_full_path()
return redirect(f"{login_url}?{urlencode({REDIRECT_FIELD_NAME: path})}")
def map_access_required(map_code):
"""
View decorator that enforces map-level access control.
Usage::
@map_access_required('concrete_blocks')
def my_view(request):
...
"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
result = check_map_access(request, map_code)
if result is not True:
return result # redirect response
return view_func(request, *args, **kwargs)
return _wrapped_view
return decorator