from typing import Any from django.contrib import admin from django.contrib.admin import register from django.contrib.auth.admin import ( GroupAdmin as BaseGroupAdmin, ) from django.contrib.auth.admin import ( UserAdmin as BaseUserAdmin, ) from django.contrib.auth.models import Group as BaseGroup from django.contrib.auth.models import Permission from django.core.exceptions import PermissionDenied from django.db.models import Prefetch, QuerySet from django.http import HttpRequest from django.utils.translation import gettext_lazy as _ from rest_framework_simplejwt.token_blacklist.admin import ( BlacklistedTokenAdmin as BaseBlacklistedTokenAdmin, ) from rest_framework_simplejwt.token_blacklist.admin import ( OutstandingTokenAdmin as BaseOutstandingTokenAdmin, ) from rest_framework_simplejwt.token_blacklist.models import ( BlacklistedToken as BaseBlacklistedToken, ) from rest_framework_simplejwt.token_blacklist.models import ( OutstandingToken as BaseOutstandingToken, ) from unfold.admin import ModelAdmin, TabularInline from unfold.forms import AdminPasswordChangeForm, UserCreationForm from engine.core.admin import ActivationActionsMixin from engine.core.models import Order from engine.payments.models import Balance from engine.vibes_auth.forms import UserForm from engine.vibes_auth.models import ( BlacklistedToken, ChatMessage, ChatThread, Group, OutstandingToken, ThreadStatus, User, ) class BalanceInline(TabularInline): model = Balance can_delete = False extra = 0 verbose_name = _("balance") verbose_name_plural = _("balance") is_navtab = True icon = "fa-solid fa-wallet" class OrderInline(TabularInline): model = Order extra = 0 verbose_name = _("order") verbose_name_plural = _("orders") is_navtab = True icon = "fa-solid fa-cart-shopping" class UserAdmin(ActivationActionsMixin, BaseUserAdmin, ModelAdmin): inlines = (BalanceInline, OrderInline) fieldsets = ( (None, {"fields": ("email", "password")}), ( _("personal info"), {"fields": ("first_name", "last_name", "phone_number", "avatar")}, ), ( _("permissions"), { "fields": ( "is_active", "is_verified", "is_subscribed", "is_staff", "is_superuser", "groups", "user_permissions", ) }, ), (_("important dates"), {"fields": ("last_login", "date_joined")}), (_("additional info"), {"fields": ("language", "attributes")}), ) add_fieldsets = ( ( None, { "classes": ("wide",), "fields": ("email", "password1", "password2"), }, ), ) list_display = ("email", "phone_number", "is_verified", "is_active", "is_staff") search_fields = ("email", "phone_number") list_filter = ( "is_verified", "is_active", "is_staff", "is_superuser", "is_subscribed", ) ordering = ("email",) readonly_fields = ("password",) form = UserForm add_form = UserCreationForm change_password_form = AdminPasswordChangeForm def get_queryset(self, request: HttpRequest) -> QuerySet[User]: qs = super().get_queryset(request) return qs.prefetch_related( "groups", "payments_balance", "orders" ).prefetch_related( Prefetch( "user_permissions", queryset=Permission.objects.select_related("content_type"), ) ) def save_model( # ty: ignore[invalid-method-override] self, request: HttpRequest, obj: Any, form: UserForm, change: Any ) -> None: if form.cleaned_data.get("attributes") is None: obj.attributes = None if ( form.cleaned_data.get("is_superuser", False) and not request.user.is_superuser # ty: ignore[possibly-missing-attribute] ): raise PermissionDenied(_("You cannot jump over your head!")) super().save_model(request, obj, form, change) # ty: ignore[invalid-argument-type] # noinspection PyUnusedLocal @register(ChatThread) class ChatThreadAdmin(ModelAdmin): list_display = ( "uuid", "user", "email", "assigned_to", "status", "last_message_at", "is_active", "created", "modified", ) list_filter = ( "status", "is_active", ("assigned_to", admin.EmptyFieldListFilter), ) search_fields = ("uuid", "email", "user__email", "user__username") autocomplete_fields = ("user", "assigned_to") actions = ( "close_threads", "open_threads", "delete_selected", ) readonly_fields = ("created", "modified") @admin.action(description=_("Close selected threads")) def close_threads(self, request, queryset): queryset.update(status=ThreadStatus.CLOSED) @admin.action(description=_("Open selected threads")) def open_threads(self, request, queryset): queryset.update(status=ThreadStatus.OPEN) @register(ChatMessage) class ChatMessageAdmin(admin.ModelAdmin): list_display = ("uuid", "thread", "sender_type", "sender_user", "sent_at") list_filter = ("sender_type",) search_fields = ("uuid", "thread__uuid", "sender_user__email") autocomplete_fields = ("thread", "sender_user") readonly_fields = ("created", "modified") class GroupAdmin(BaseGroupAdmin, ModelAdmin): pass class BlacklistedTokenAdmin(BaseBlacklistedTokenAdmin, ModelAdmin): pass class OutstandingTokenAdmin(BaseOutstandingTokenAdmin, ModelAdmin): pass admin.site.register(User, UserAdmin) admin.site.unregister(BaseGroup) admin.site.register(Group, GroupAdmin) admin.site.unregister(BaseBlacklistedToken) admin.site.register(BlacklistedToken, BlacklistedTokenAdmin) admin.site.unregister(BaseOutstandingToken) admin.site.register(OutstandingToken, OutstandingTokenAdmin)