"""Admin models for the users app."""
from __future__ import annotations
from typing import TYPE_CHECKING, List, Tuple, Type
from django.contrib import admin
from django.contrib.auth import models
from django.db.models.expressions import Value as V
from django.db.models.functions import Concat as C
from django.db.models.query import QuerySet
from django.forms.fields import BooleanField
from django.forms.models import ModelForm
from django.forms.widgets import CheckboxSelectMultiple
from django.utils.functional import cached_property
from django.utils.html import format_html
from allauth.account.models import EmailAddress
from allauth.socialaccount.admin import SocialAppAdmin
from allauth.socialaccount.models import SocialAccount, SocialApp, SocialToken
from MangAdventure.filters import boolean_filter
if TYPE_CHECKING: # pragma: no cover
from django.http import HttpRequest
[docs]class UserTypeFilter(admin.SimpleListFilter):
"""Admin interface filter for user types."""
#: The title of the filter.
title = 'type'
#: The filter's query parameter.
parameter_name = 'type'
[docs] def lookups(self, request: HttpRequest, model_admin:
Type[admin.ModelAdmin]) -> List[Tuple[str, str]]:
"""
Return a list of lookups for this filter.
The first element in each tuple is the value of the
query parameter. The second element is the human-readable
name for the option that will appear in the admin sidebar.
:param request: The original request.
:param model_admin: An admin model object.
:return: The following list of tuples:
.. code-block:: python
[
('superuser', 'Superuser'),
('staff', 'Staff'),
('scanlator', 'Scanlator'),
('regular', 'Regular')
]
"""
return [
('superuser', 'Superuser'),
('staff', 'Staff'),
('scanlator', 'Scanlator'),
('regular', 'Regular')
]
[docs] def queryset(self, request: HttpRequest, queryset: QuerySet) -> QuerySet:
"""
Return the filtered queryset based on
the value provided in the query string.
:param request: The original request.
:param queryset: The original queryset.
:return: A filtered queryset according to :meth:`lookups`.
"""
return {
'superuser': queryset.filter(is_superuser=True),
'staff': queryset.filter(is_staff=True),
'scanlator': queryset.filter(groups__name='Scanlator'),
'regular': queryset.exclude(is_staff=True)
}.get(self.value() or '', queryset)
[docs]class User(models.User):
""":class:`django.contrib.auth.models.User` proxy model."""
@cached_property
def is_scanlator(self) -> bool:
"""Get the scanlator status of the user."""
return self.groups.filter(name='Scanlator').exists()
class Meta:
proxy = True
auto_created = True
app_label = 'users'
verbose_name = 'user'
[docs]class UserAdmin(admin.ModelAdmin):
"""Admin model for :class:`User`."""
form = UserForm
exclude = ('password', 'groups')
list_display = (
'username', '_email', 'full_name',
'date_joined', 'last_login', 'is_active'
)
list_editable = ('is_active',)
search_fields = ('username', 'email', 'first_name', 'last_name')
list_filter = (
boolean_filter('status', 'is_active', ('Active', 'Inactive')),
UserTypeFilter,
)
ordering = ('username',)
sortable_by = ('username', 'full_name', 'date_joined', 'last_login')
@admin.display(description='e-mail address')
def _email(self, obj: User) -> str:
return format_html(
'<a href="mailto:{0}" rel="noopener noreferrer"'
' target="_blank">{0}</a>', obj.email
) if obj.email else ''
[docs] @admin.display(ordering=C('first_name', V(' '), 'last_name'))
def full_name(self, obj: User) -> str:
"""
Get the full name of the user.
:param obj: A ``User`` model instance.
:return: The user's full name.
"""
return obj.get_full_name()
[docs] def has_add_permission(self, request: HttpRequest) -> bool:
"""
Return whether adding an ``User`` object is permitted.
:param request: The original request.
:return: Always returns ``False``.
"""
return False
[docs]class OAuthApp(SocialApp):
""":class:`allauth.socialaccount.models.SocialApp` proxy model."""
class Meta:
proxy = True
auto_created = True
app_label = 'users'
verbose_name = 'OAuth app'
[docs] def __str__(self) -> str:
"""
Return a string representing the object.
:return: The name and provider of the app.
"""
return f'{self.name} ({self.provider})'
[docs]class OAuthAppAdmin(SocialAppAdmin):
"""Admin model for :class:`OAuthApp`."""
list_display = ('name', '_provider', 'client_id')
exclude = ('provider_id', 'settings')
sortable_by = ('name', '_provider')
radio_fields = {'provider': admin.HORIZONTAL}
@admin.display(ordering='provider', description='provider')
def _provider(self, obj: OAuthApp) -> str:
return format_html(
'<a rel="noopener noreferrer" target="_blank" href='
'"https://django-allauth.readthedocs.io/en/stable/providers.html'
'#{0}">{0}</a>', obj.provider
) if obj.provider else ''
admin.site.unregister((
EmailAddress, SocialAccount, SocialToken,
SocialApp, models.User, models.Group
))
admin.site.register(User, UserAdmin)
admin.site.register(OAuthApp, OAuthAppAdmin)
__all__ = [
'UserTypeFilter', 'User', 'UserForm',
'UserAdmin', 'OAuthApp', 'OAuthAppAdmin'
]