Skip to content

Commit 0a19157

Browse files
committed
feat(auth): added admin utilities for UserGroup
1 parent 0917b31 commit 0a19157

File tree

4 files changed

+112
-19
lines changed

4 files changed

+112
-19
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 UserGroupAdmin(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)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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+
class Meta:
19+
abstract = True
Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,10 @@
11
from django.apps import apps
22
from django.conf import settings
3-
from django.db import models
43
from keycloak import KeycloakAdmin
54
from keycloak import KeycloakOpenIDConnection
65
from keycloak.exceptions import KeycloakGetError
76

87

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-
278
class KeycloakService:
289
def __init__(self):
2910
self._user_group_model = self._get_user_group_model()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 %}

0 commit comments

Comments
 (0)