fix: optimize and debug has_role and can_manage_some_groups (#7949)

* fix: optimize can_manage_some_groups

* fix: improve cache key

* refactor: extra_role_qs to kwargs and bugfix to cache key

* fix: restrict groupman_role matches to active states

* chore: styling, decommenting, black
This commit is contained in:
Robert Sparks 2024-09-17 13:05:56 -05:00 committed by GitHub
parent 86148a2a3c
commit 8362b45c8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 130 additions and 51 deletions

View file

@ -2,6 +2,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import datetime import datetime
from itertools import chain
from pathlib import Path from pathlib import Path
from django.db.models import Q from django.db.models import Q
@ -153,17 +154,23 @@ def can_manage_materials(user, group):
def can_manage_session_materials(user, group, session): def can_manage_session_materials(user, group, session):
return has_role(user, 'Secretariat') or (group.has_role(user, group.features.matman_roles) and not session.is_material_submission_cutoff()) return has_role(user, 'Secretariat') or (group.has_role(user, group.features.matman_roles) and not session.is_material_submission_cutoff())
# Maybe this should be cached...
def can_manage_some_groups(user): def can_manage_some_groups(user):
if not user.is_authenticated: if not user.is_authenticated:
return False return False
authroles = set(
chain.from_iterable(
GroupFeatures.objects.values_list("groupman_authroles", flat=True)
)
)
extra_role_qs = dict()
for gf in GroupFeatures.objects.all(): for gf in GroupFeatures.objects.all():
for authrole in gf.groupman_authroles: extra_role_qs[f"{gf.type_id} groupman roles"] = Q(
if has_role(user, authrole): name__in=gf.groupman_roles,
return True group__type_id=gf.type_id,
if Role.objects.filter(name__in=gf.groupman_roles, group__type_id=gf.type_id, person__user=user).exists(): group__state__in=["active", "bof", "proposed"],
return True )
return False return has_role(user, authroles, extra_role_qs=extra_role_qs)
def can_provide_status_update(user, group): def can_provide_status_update(user, group):
if not group.features.acts_like_wg: if not group.features.acts_like_wg:

View file

@ -38,9 +38,10 @@ def has_role(user, role_names, *args, **kwargs):
"""Determines whether user has any of the given standard roles """Determines whether user has any of the given standard roles
given. Role names must be a list or, in case of a single value, a given. Role names must be a list or, in case of a single value, a
string.""" string."""
if not isinstance(role_names, (list, tuple)): extra_role_qs = kwargs.get("extra_role_qs", None)
role_names = [ role_names ] if not isinstance(role_names, (list, tuple, set)):
role_names = [role_names]
if not user or not user.is_authenticated: if not user or not user.is_authenticated:
return False return False
@ -48,7 +49,13 @@ def has_role(user, role_names, *args, **kwargs):
if not hasattr(user, "roles_check_cache"): if not hasattr(user, "roles_check_cache"):
user.roles_check_cache = {} user.roles_check_cache = {}
key = frozenset(role_names) keynames = set(role_names)
if extra_role_qs:
keynames.update(set(extra_role_qs.keys()))
year = kwargs.get("year", None)
if year is not None:
keynames.add(f"nomcomyear{year}")
key = frozenset(keynames)
if key not in user.roles_check_cache: if key not in user.roles_check_cache:
try: try:
person = user.person person = user.person
@ -56,54 +63,119 @@ def has_role(user, role_names, *args, **kwargs):
return False return False
role_qs = { role_qs = {
"Area Director": Q(person=person, name__in=("pre-ad", "ad"), group__type="area", group__state="active"), "Area Director": Q(
"Secretariat": Q(person=person, name="secr", group__acronym="secretariat"), name__in=("pre-ad", "ad"), group__type="area", group__state="active"
"IAB" : Q(person=person, name="member", group__acronym="iab"), ),
"IANA": Q(person=person, name="auth", group__acronym="iana"), "Secretariat": Q(name="secr", group__acronym="secretariat"),
"RFC Editor": Q(person=person, name="auth", group__acronym="rpc"), "IAB": Q(name="member", group__acronym="iab"),
"ISE" : Q(person=person, name="chair", group__acronym="ise"), "IANA": Q(name="auth", group__acronym="iana"),
"IAD": Q(person=person, name="admdir", group__acronym="ietf"), "RFC Editor": Q(name="auth", group__acronym="rpc"),
"IETF Chair": Q(person=person, name="chair", group__acronym="ietf"), "ISE": Q(name="chair", group__acronym="ise"),
"IETF Trust Chair": Q(person=person, name="chair", group__acronym="ietf-trust"), "IAD": Q(name="admdir", group__acronym="ietf"),
"IRTF Chair": Q(person=person, name="chair", group__acronym="irtf"), "IETF Chair": Q(name="chair", group__acronym="ietf"),
"RSAB Chair": Q(person=person, name="chair", group__acronym="rsab"), "IETF Trust Chair": Q(name="chair", group__acronym="ietf-trust"),
"IAB Chair": Q(person=person, name="chair", group__acronym="iab"), "IRTF Chair": Q(name="chair", group__acronym="irtf"),
"IAB Executive Director": Q(person=person, name="execdir", group__acronym="iab"), "RSAB Chair": Q(name="chair", group__acronym="rsab"),
"IAB Group Chair": Q(person=person, name="chair", group__type="iab", group__state="active"), "IAB Chair": Q(name="chair", group__acronym="iab"),
"IAOC Chair": Q(person=person, name="chair", group__acronym="iaoc"), "IAB Executive Director": Q(name="execdir", group__acronym="iab"),
"WG Chair": Q(person=person,name="chair", group__type="wg", group__state__in=["active","bof", "proposed"]), "IAB Group Chair": Q(
"WG Secretary": Q(person=person,name="secr", group__type="wg", group__state__in=["active","bof", "proposed"]), name="chair", group__type="iab", group__state="active"
"RG Chair": Q(person=person,name="chair", group__type="rg", group__state__in=["active","proposed"]), ),
"RG Secretary": Q(person=person,name="secr", group__type="rg", group__state__in=["active","proposed"]), "IAOC Chair": Q(name="chair", group__acronym="iaoc"),
"AG Secretary": Q(person=person,name="secr", group__type="ag", group__state__in=["active"]), "WG Chair": Q(
"RAG Secretary": Q(person=person,name="secr", group__type="rag", group__state__in=["active"]), name="chair",
"Team Chair": Q(person=person,name="chair", group__type="team", group__state="active"), group__type="wg",
"Program Lead": Q(person=person,name="lead", group__type="program", group__state="active"), group__state__in=["active", "bof", "proposed"],
"Program Secretary": Q(person=person,name="secr", group__type="program", group__state="active"), ),
"Program Chair": Q(person=person,name="chair", group__type="program", group__state="active"), "WG Secretary": Q(
"EDWG Chair": Q(person=person, name="chair", group__type="edwg", group__state="active"), name="secr",
"Nomcom Chair": Q(person=person, name="chair", group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')), group__type="wg",
"Nomcom Advisor": Q(person=person, name="advisor", group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')), group__state__in=["active", "bof", "proposed"],
"Nomcom": Q(person=person, group__type="nomcom", group__acronym__icontains=kwargs.get('year', '0000')), ),
"Liaison Manager": Q(person=person,name="liaiman",group__type="sdo",group__state="active", ), "RG Chair": Q(
"Authorized Individual": Q(person=person,name="auth",group__type="sdo",group__state="active", ), name="chair", group__type="rg", group__state__in=["active", "proposed"]
"Recording Manager": Q(person=person,name="recman",group__type="ietf",group__state="active", ), ),
"Reviewer": Q(person=person, name="reviewer", group__state="active"), "RG Secretary": Q(
"Review Team Secretary": Q(person=person, name="secr", group__reviewteamsettings__isnull=False,group__state="active", ), name="secr", group__type="rg", group__state__in=["active", "proposed"]
"IRSG Member": (Q(person=person, name="member", group__acronym="irsg") | Q(person=person, name="chair", group__acronym="irtf") | Q(person=person, name="atlarge", group__acronym="irsg")), ),
"RSAB Member": Q(person=person, name="member", group__acronym="rsab"), "AG Secretary": Q(
"Robot": Q(person=person, name="robot", group__acronym="secretariat"), name="secr", group__type="ag", group__state__in=["active"]
} ),
"RAG Secretary": Q(
name="secr", group__type="rag", group__state__in=["active"]
),
"Team Chair": Q(name="chair", group__type="team", group__state="active"),
"Program Lead": Q(
name="lead", group__type="program", group__state="active"
),
"Program Secretary": Q(
name="secr", group__type="program", group__state="active"
),
"Program Chair": Q(
name="chair", group__type="program", group__state="active"
),
"EDWG Chair": Q(name="chair", group__type="edwg", group__state="active"),
"Nomcom Chair": Q(
name="chair",
group__type="nomcom",
group__acronym__icontains=kwargs.get("year", "0000"),
),
"Nomcom Advisor": Q(
name="advisor",
group__type="nomcom",
group__acronym__icontains=kwargs.get("year", "0000"),
),
"Nomcom": Q(
group__type="nomcom",
group__acronym__icontains=kwargs.get("year", "0000"),
),
"Liaison Manager": Q(
name="liaiman",
group__type="sdo",
group__state="active",
),
"Authorized Individual": Q(
name="auth",
group__type="sdo",
group__state="active",
),
"Recording Manager": Q(
name="recman",
group__type="ietf",
group__state="active",
),
"Reviewer": Q(name="reviewer", group__state="active"),
"Review Team Secretary": Q(
name="secr",
group__reviewteamsettings__isnull=False,
group__state="active",
),
"IRSG Member": (
Q(name="member", group__acronym="irsg")
| Q(name="chair", group__acronym="irtf")
| Q(name="atlarge", group__acronym="irsg")
),
"RSAB Member": Q(name="member", group__acronym="rsab"),
"Robot": Q(name="robot", group__acronym="secretariat"),
}
filter_expr = Q(pk__in=[]) # ensure empty set is returned if no other terms are added filter_expr = Q(
pk__in=[]
) # ensure empty set is returned if no other terms are added
for r in role_names: for r in role_names:
filter_expr |= role_qs[r] filter_expr |= role_qs[r]
if extra_role_qs:
for r in extra_role_qs:
filter_expr |= extra_role_qs[r]
user.roles_check_cache[key] = bool(Role.objects.filter(filter_expr).exists()) user.roles_check_cache[key] = bool(
Role.objects.filter(person=person).filter(filter_expr).exists()
)
return user.roles_check_cache[key] return user.roles_check_cache[key]
# convenient decorator # convenient decorator
def passes_test_decorator(test_func, message): def passes_test_decorator(test_func, message):