cardo-python-utils 0.5.dev2__tar.gz → 0.5.dev5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. cardo_python_utils-0.5.dev5/MANIFEST.in +4 -0
  2. {cardo_python_utils-0.5.dev2/cardo_python_utils.egg-info → cardo_python_utils-0.5.dev5}/PKG-INFO +1 -1
  3. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5/cardo_python_utils.egg-info}/PKG-INFO +1 -1
  4. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/cardo_python_utils.egg-info/SOURCES.txt +5 -2
  5. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/pyproject.toml +1 -1
  6. cardo_python_utils-0.5.dev5/python_utils/django/keycloak/admin.py +86 -0
  7. cardo_python_utils-0.5.dev5/python_utils/django/keycloak/models.py +22 -0
  8. cardo_python_utils-0.5.dev2/python_utils/django/auth/keycloak.py → cardo_python_utils-0.5.dev5/python_utils/django/keycloak/service.py +1 -20
  9. cardo_python_utils-0.5.dev5/python_utils/django/keycloak/user_groups_changelist.html +7 -0
  10. cardo_python_utils-0.5.dev2/MANIFEST.in +0 -3
  11. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/LICENSE +0 -0
  12. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/README.rst +0 -0
  13. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/cardo_python_utils.egg-info/dependency_links.txt +0 -0
  14. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/cardo_python_utils.egg-info/requires.txt +0 -0
  15. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/cardo_python_utils.egg-info/top_level.txt +0 -0
  16. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/__init__.py +0 -0
  17. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/choices.py +0 -0
  18. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/data_structures.py +0 -0
  19. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/db.py +0 -0
  20. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/django/auth/__init__.py +0 -0
  21. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/django/auth/admin.py +0 -0
  22. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/django/auth/drf.py +0 -0
  23. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/django/auth/ninja.py +0 -0
  24. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/django/utils.py +0 -0
  25. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/esma_choices.py +0 -0
  26. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/exceptions.py +0 -0
  27. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/imports.py +0 -0
  28. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/math.py +0 -0
  29. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/text.py +0 -0
  30. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/time.py +0 -0
  31. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/python_utils/types_hinting.py +0 -0
  32. {cardo_python_utils-0.5.dev2 → cardo_python_utils-0.5.dev5}/setup.cfg +0 -0
@@ -0,0 +1,4 @@
1
+ include LICENSE
2
+ include README.rst
3
+ include python_utils/django/keycloak/user_groups_changelist.html
4
+ recursive-exclude tests *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cardo-python-utils
3
- Version: 0.5.dev2
3
+ Version: 0.5.dev5
4
4
  Summary: Python library enhanced with a wide range of functions for different scenarios.
5
5
  Author-email: CardoAI <hello@cardoai.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cardo-python-utils
3
- Version: 0.5.dev2
3
+ Version: 0.5.dev5
4
4
  Summary: Python library enhanced with a wide range of functions for different scenarios.
5
5
  Author-email: CardoAI <hello@cardoai.com>
6
6
  License: MIT
@@ -22,5 +22,8 @@ python_utils/django/utils.py
22
22
  python_utils/django/auth/__init__.py
23
23
  python_utils/django/auth/admin.py
24
24
  python_utils/django/auth/drf.py
25
- python_utils/django/auth/keycloak.py
26
- python_utils/django/auth/ninja.py
25
+ python_utils/django/auth/ninja.py
26
+ python_utils/django/keycloak/admin.py
27
+ python_utils/django/keycloak/models.py
28
+ python_utils/django/keycloak/service.py
29
+ python_utils/django/keycloak/user_groups_changelist.html
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cardo-python-utils"
7
- version = "0.5.dev2"
7
+ version = "0.5.dev5"
8
8
  description = "Python library enhanced with a wide range of functions for different scenarios."
9
9
  readme = "README.rst"
10
10
  requires-python = ">=3.8"
@@ -0,0 +1,86 @@
1
+ from django.contrib import admin, messages
2
+ from django.core.cache import cache
3
+ from django.urls import path
4
+ from django.shortcuts import redirect
5
+
6
+ from .service import KeycloakService
7
+
8
+
9
+ class UserGroupAdminBase(admin.ModelAdmin):
10
+ list_display = ("path",)
11
+ search_fields = ("id", "path")
12
+ readonly_fields = ("id", "path")
13
+
14
+ # To show ManyToMany fields with a horizontal filter widget
15
+ # filter_horizontal = ("allowed_entities",)
16
+
17
+ change_list_template = "user_groups_changelist.html"
18
+
19
+ # To show fields in this order in the detail view
20
+ # fieldsets = (
21
+ # (
22
+ # None,
23
+ # {
24
+ # "fields": (
25
+ # "id",
26
+ # "path",
27
+ # "allow_all_entities",
28
+ # "allowed_entities",
29
+ # )
30
+ # },
31
+ # ),
32
+ # )
33
+
34
+ def has_add_permission(self, request):
35
+ # Manual addition of user groups is not allowed
36
+ return False
37
+
38
+ def has_delete_permission(self, request, obj=None):
39
+ # Manual deletion of user groups is not allowed
40
+ return False
41
+
42
+ # To show annotated fields in the list view
43
+ # def get_queryset(self, request):
44
+ # return (
45
+ # super()
46
+ # .get_queryset(request)
47
+ # .annotate(allowed_job_configs_count=Count("allowed_job_configs"))
48
+ # )
49
+
50
+ def get_urls(self):
51
+ return [
52
+ path("sync-with-keycloak/", self.sync_groups_with_keycloak),
53
+ *super().get_urls(),
54
+ ]
55
+
56
+ @staticmethod
57
+ def sync_groups_with_keycloak(request): # noqa
58
+ """Syncs user groups with Keycloak"""
59
+
60
+ try:
61
+ KeycloakService().sync_user_groups(raise_exceptions=True)
62
+ messages.success(request, "User groups synced successfully.")
63
+ except Exception as e:
64
+ messages.error(request, f"Error syncing user groups: {e}")
65
+
66
+ return redirect("..")
67
+
68
+ # To allow sorting by annotated fields
69
+ # @admin.display(
70
+ # description="Allowed Job Configs", ordering="allowed_job_configs_count"
71
+ # )
72
+ # def allowed_job_configs_count(self, obj):
73
+ # return obj.allowed_job_configs_count
74
+
75
+ def changelist_view(self, request, extra_context=None):
76
+ """
77
+ When the list view is accessed, sync the user groups from Keycloak.
78
+ Cache the sync for 10 minutes to avoid excessive requests.
79
+ """
80
+ cache_key = "keycloak_group_sync_lock"
81
+
82
+ if cache.get(cache_key) is None:
83
+ KeycloakService().sync_user_groups()
84
+ cache.set(cache_key, "true", 60 * 10)
85
+
86
+ return super().changelist_view(request, extra_context)
@@ -0,0 +1,22 @@
1
+ from django.db import models
2
+
3
+
4
+ class UserGroupBase(models.Model):
5
+ """
6
+ Abstract base model for Keycloak user groups.
7
+ """
8
+ id = models.UUIDField(
9
+ primary_key=True,
10
+ help_text="The ID of the group, as coming from Keycloak.",
11
+ )
12
+ path = models.CharField(
13
+ max_length=255,
14
+ help_text="The full path of the group, as coming from Keycloak.",
15
+ db_index=True,
16
+ )
17
+
18
+ def __str__(self):
19
+ return self.path
20
+
21
+ class Meta:
22
+ abstract = True
@@ -1,29 +1,10 @@
1
1
  from django.apps import apps
2
2
  from django.conf import settings
3
- from django.db import models
4
3
  from keycloak import KeycloakAdmin
5
4
  from keycloak import KeycloakOpenIDConnection
6
5
  from keycloak.exceptions import KeycloakGetError
7
6
 
8
7
 
9
- class UserGroupBase(models.Model):
10
- """
11
- Abstract base model for Keycloak user groups.
12
- """
13
- id = models.UUIDField(
14
- primary_key=True,
15
- help_text="The ID of the group, as coming from Keycloak.",
16
- )
17
- path = models.CharField(
18
- max_length=255,
19
- help_text="The full path of the group, as coming from Keycloak.",
20
- db_index=True,
21
- )
22
-
23
- class Meta:
24
- abstract = True
25
-
26
-
27
8
  class KeycloakService:
28
9
  def __init__(self):
29
10
  self._user_group_model = self._get_user_group_model()
@@ -89,7 +70,7 @@ class KeycloakService:
89
70
  except AttributeError:
90
71
  raise LookupError(
91
72
  "Please set KEYCLOAK_USER_GROUP_MODEL in your Django settings "
92
- "(e.g., 'myapp.models.UserGroup')."
73
+ "(e.g., 'myapp.UserGroup')."
93
74
  )
94
75
 
95
76
  return apps.get_model(model_string)
@@ -0,0 +1,7 @@
1
+ {% extends 'admin/change_list.html' %}
2
+
3
+ {% block object-tools-items %}
4
+ {{ block.super }}
5
+ <li><a href="sync-with-keycloak/">Sync groups with Keycloak 🔄</a></li>
6
+
7
+ {% endblock %}
@@ -1,3 +0,0 @@
1
- include LICENSE
2
- include README.rst
3
- recursive-exclude tests *