Coverage for product_risk_suite/api/admin.py: 61%
46 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-16 14:44 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-16 14:44 +0000
1from django.contrib import admin, messages
2from django.contrib.auth.admin import UserAdmin
3from django.contrib.auth.models import User
5from .models import APIToken
8class APITokenInline(admin.TabularInline):
9 model = APIToken
10 fk_name = "owner"
11 extra = 0
12 fields = ("name", "display_prefix", "created_at", "last_used_at", "expires_at", "is_active")
13 readonly_fields = ("display_prefix", "created_at", "last_used_at")
14 show_change_link = True
17class UserAdminWithAPITokens(UserAdmin):
18 inlines = UserAdmin.inlines + (APITokenInline,)
19 list_display = UserAdmin.list_display + ("api_token_count",)
21 @admin.display(description="API tokens")
22 def api_token_count(self, obj):
23 return obj.api_tokens.count()
26admin.site.unregister(User)
27admin.site.register(User, UserAdminWithAPITokens)
30@admin.register(APIToken)
31class APITokenAdmin(admin.ModelAdmin):
32 list_display = ("name", "owner", "display_prefix", "is_active", "created_at", "last_used_at", "expires_at")
33 list_filter = ("is_active",)
34 search_fields = ("name", "owner__username", "display_prefix")
35 autocomplete_fields = ("owner",)
37 def get_fields(self, request, obj=None):
38 if obj is None:
39 return ("name", "owner", "expires_at", "is_active")
40 return ("name", "owner", "display_prefix", "created_by", "created_at", "last_used_at", "expires_at", "is_active")
42 def get_readonly_fields(self, request, obj=None):
43 if obj is None:
44 return ()
45 return ("display_prefix", "created_by", "created_at", "last_used_at")
47 def save_model(self, request, obj, form, change):
48 if not change:
49 raw_token = APIToken.generate_raw_token()
50 obj.display_prefix = raw_token[:12]
51 obj.hashed_key = APIToken.hash_token(raw_token)
52 obj.created_by = request.user
53 self._raw_token_to_display = raw_token
54 super().save_model(request, obj, form, change)
56 def response_add(self, request, obj, post_url_continue=None):
57 raw_token = getattr(self, "_raw_token_to_display", None)
58 if raw_token:
59 messages.warning(
60 request,
61 f"API token created for '{obj.name}'. Copy it now — it will not be shown again: {raw_token}",
62 )
63 return super().response_add(request, obj, post_url_continue)