Files
dashboard-cpsp-executive/backend/apps/accounts/scoping.py
T

180 lines
4.7 KiB
Python

"""Visibility scoping for HQ executives.
- director / director_admin: all sites / active sites / GMs
- buh / bu_admin: only GMs (and gm_admins) they manage, plus those GMs' sites
- gm / gm_admin: only their own sites / active sites they manage
Farm Site rows are only visible to non-directors when linked to an enabled
ActiveSite in the viewer's Pengaturan registry.
"""
from __future__ import annotations
from django.db.models import QuerySet
from apps.accounts.models import User
DIRECTOR_STATUSES = frozenset(
{
User.STATUS_DIRECTOR,
User.STATUS_DIRECTOR_ADMIN,
User.STATUS_SUPERUSER,
}
)
BUH_STATUSES = frozenset(
{
User.STATUS_BUH,
User.STATUS_BU_ADMIN,
}
)
GM_STATUSES = frozenset(
{
User.STATUS_GM,
User.STATUS_GM_ADMIN,
}
)
def is_director_scope(user: User) -> bool:
return bool(user and user.status in DIRECTOR_STATUSES)
def is_buh_scope(user: User) -> bool:
return bool(user and user.status in BUH_STATUSES)
def is_gm_scope(user: User) -> bool:
return bool(user and user.status in GM_STATUSES)
def managed_gm_ids(buh: User) -> list[int]:
"""User pks for GMs / GM Admins reporting to this BUH."""
return list(
User.objects.filter(
managed_by=buh,
status__in=GM_STATUSES,
).values_list("pk", flat=True)
)
def visible_owner_ids(user: User) -> list[int] | None:
"""
Site.user / ActiveSite.managed_by ids this viewer may see.
Returns None when there is no restriction (director / superuser).
"""
if is_director_scope(user):
return None
if is_buh_scope(user):
return managed_gm_ids(user)
if is_gm_scope(user):
return [user.pk]
return []
def visible_active_site_ids(user: User) -> list[int] | None:
"""
Enabled ActiveSite pks in this viewer's Pengaturan registry.
Returns None for directors (no restriction). Empty list means no farm sites.
"""
from apps.sync.models import ActiveSite
owners = visible_owner_ids(user)
if owners is None:
return None
if not owners:
return []
return list(
ActiveSite.objects.filter(
managed_by_id__in=owners,
is_active=True,
).values_list("pk", flat=True)
)
def is_account_admin_scope(user: User) -> bool:
return bool(user and user.status == User.STATUS_ACCOUNT_ADMIN)
def filter_users_queryset(qs: QuerySet, viewer: User) -> QuerySet:
"""BUH sees managed GMs; director / account_admin see product users.
Break-glass status=superuser is never listed in the user directory.
"""
qs = qs.exclude(status=User.STATUS_SUPERUSER)
if is_director_scope(viewer) or is_account_admin_scope(viewer):
return qs
if is_buh_scope(viewer):
return qs.filter(pk__in=managed_gm_ids(viewer))
if is_gm_scope(viewer):
return qs.filter(pk=viewer.pk)
return qs.none()
def filter_sites_queryset(qs: QuerySet, viewer: User) -> QuerySet:
owners = visible_owner_ids(viewer)
if owners is None:
return qs
if not owners:
return qs.none()
active_ids = visible_active_site_ids(viewer)
if not active_ids:
return qs.none()
return qs.filter(user_id__in=owners, active_site_id__in=active_ids)
def filter_active_sites_queryset(qs: QuerySet, viewer: User) -> QuerySet:
owners = visible_owner_ids(viewer)
if owners is None:
return qs
if not owners:
return qs.none()
return qs.filter(managed_by_id__in=owners)
def filter_kandangs_queryset(qs: QuerySet, viewer: User) -> QuerySet:
owners = visible_owner_ids(viewer)
if owners is None:
return qs
if not owners:
return qs.none()
active_ids = visible_active_site_ids(viewer)
if not active_ids:
return qs.none()
return qs.filter(
site__user_id__in=owners, site__active_site_id__in=active_ids
)
def filter_flocks_queryset(qs: QuerySet, viewer: User) -> QuerySet:
owners = visible_owner_ids(viewer)
if owners is None:
return qs
if not owners:
return qs.none()
active_ids = visible_active_site_ids(viewer)
if not active_ids:
return qs.none()
return qs.filter(
kandang__site__user_id__in=owners,
kandang__site__active_site_id__in=active_ids,
)
def filter_cycles_queryset(qs: QuerySet, viewer: User) -> QuerySet:
owners = visible_owner_ids(viewer)
if owners is None:
return qs
if not owners:
return qs.none()
active_ids = visible_active_site_ids(viewer)
if not active_ids:
return qs.none()
return qs.filter(
kandang__site__user_id__in=owners,
kandang__site__active_site_id__in=active_ids,
)