Coverage for sm/utils_permissions.py: 80%

25 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-24 19:06 +0000

1from django.contrib.auth.models import Group, Permission 

2from django.contrib.contenttypes.models import ContentType 

3from typing import List, Tuple 

4import logging 

5 

6logger = logging.getLogger(__name__) 

7 

8 

9# All core tenant models that can be permission-managed per group. 

10APP_MODELS: List[Tuple[str, str]] = [ 

11 ("server", "model"), 

12 ("cluster", "model"), 

13 ("domain", "model"), 

14 ("vendor", "model"), 

15 ("operatingsystem", "model"), 

16 ("status", "model"), 

17 ("location", "model"), 

18 ("patchtime", "model"), 

19 ("servermodel", "model"), 

20 ("clusterpackage", "model"), 

21 ("clustersoftware", "model"), 

22 ("clusterpackagetype", "model"), 

23] 

24 

25# Human-readable labels for the permission management UI, keyed by app_label. 

26MODEL_LABELS: dict = { 

27 "server": "Servers", 

28 "cluster": "Clusters", 

29 "domain": "Domains", 

30 "vendor": "Vendors", 

31 "operatingsystem": "Operating Systems", 

32 "status": "Statuses", 

33 "location": "Locations", 

34 "patchtime": "Patch Times", 

35 "servermodel": "Server Models", 

36 "clusterpackage": "Cluster Packages", 

37 "clustersoftware": "Cluster Software", 

38 "clusterpackagetype": "Package Types", 

39} 

40 

41 

42def get_group_permissions_for_model( 

43 app_label: str, model_name: str = "model" 

44) -> List[Permission]: 

45 """ 

46 Returns the standard permissions (view, add, change, delete) for a model. 

47 """ 

48 try: 

49 ct = ContentType.objects.get(app_label=app_label, model=model_name) 

50 return list(Permission.objects.filter(content_type=ct)) 

51 except ContentType.DoesNotExist: 

52 logger.warning(f"ContentType for {app_label}.{model_name} not found.") 

53 return [] 

54 

55 

56def assign_group_permissions(group: Group, permissions: List[Permission]) -> None: 

57 """ 

58 Assigns a list of permissions to a group. 

59 """ 

60 group.permissions.add(*permissions) 

61 

62 

63def sync_group_permissions(group: Group, grant_all: bool = False) -> None: 

64 """ 

65 Ensures a group has at least basic view permissions for the core models 

66 so multi-tenancy works as expected. 

67 If grant_all is True, also grants add, change, and delete permissions. 

68 """ 

69 for app, model in APP_MODELS: 

70 perms = get_group_permissions_for_model(app, model) 

71 if grant_all: 

72 # Grant all permissions for this model 

73 group.permissions.add(*perms) 

74 else: 

75 # By default, give view permission to every group 

76 view_perm = next((p for p in perms if p.codename.startswith("view_")), None) 

77 if view_perm: 

78 group.permissions.add(view_perm) 

79 else: 

80 logger.debug(f"View permission for {app}.{model} not found.")