HEAD
from django.contrib import admin
from django.contrib.auth.forms import UserChangeForm, UsernameField
from django.contrib.auth.admin import UserAdmin
from django.utils.translation import gettext_lazy as _
from rest_framework.authtoken.models import TokenProxy
from ajaxdatatable.admin import AjaxDatatable
from apps.account.models import User, Notification
from django import forms
from django.contrib import admin
from django.urls import path, reverse
from django.shortcuts import render, redirect
from django.contrib import messages
from apps.account.models import ClientUser, AdminUser
@admin.register(Notification)
class NotificationAdmin(AjaxDatatable):
list_display = ('title', 'user', 'is_read', 'created_at')
list_filter = ('is_read', 'created_at')
search_fields = ('title', 'message', 'user__fullname')
list_editable = ('is_read',)
ordering = ('-created_at',)
autocomplete_fields = ['user',]
@admin.register(User)
class UserAdmin(UserAdmin, AjaxDatatable):
list_display = (
'device_id', 'email', 'fullname', 'user_type','last_login', 'device_os', 'date_joined',
)
ordering = '-id',
readonly_fields = ('date_joined',)
exclude = ('password', 'user_permissions')
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),
}),
)
search_fields = (
'email', 'fullname', 'username',
)
fieldsets = (
(_('Personal info'), {'fields': ('fullname', 'email', 'phone_number', 'avatar',)}),
(_('Permissions'), {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'password'),
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined', 'fcm')}),
)
def save_model(self, request, obj, form, change):
if not change:
obj.set_password(form.cleaned_data['password1'])
# obj.user_type = User.UserType.CLIENT
super().save_model(request, obj, form, change)
@admin.display(description='Phone Number')
def _phone_number(self, obj):
return obj.phone_number
@admin.register(AdminUser)
class AdminUserAdmin(UserAdmin, AjaxDatatable):
list_display = (
'email', 'fullname', 'user_type','last_login', 'date_joined',
)
ordering = 'last_login',
readonly_fields = ('date_joined',)
exclude = ('password', 'user_permissions')
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2'),
}),
)
search_fields = (
'email', 'fullname', 'username',
)
fieldsets = (
(_('Personal info'), {'fields': ('fullname', 'email', 'phone_number', 'avatar',)}),
(_('Permissions'), {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'password'),
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined', 'fcm')}),
)
def save_model(self, request, obj, form, change):
if not change:
obj.set_password(form.cleaned_data['password1'])
# obj.user_type = User.UserType.CLIENT
super().save_model(request, obj, form, change)
@admin.display(description='Phone Number')
def _phone_number(self, obj):
return obj.phone_number
admin.site.unregister(TokenProxy)
=======
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.contrib.auth.models import Group
from django.db import models
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
from django.templatetags.static import static
from rest_framework.authtoken.models import TokenProxy
from unfold.admin import ModelAdmin, StackedInline
from unfold.contrib.forms.widgets import WysiwygWidget
from unfold.decorators import display
from unfold.forms import AdminPasswordChangeForm
from unfold.sections import TableSection
from unfold.contrib.filters.admin import RangeDateTimeFilter
# Import Models
from apps.account.models import User, ClientUser, StudentUser, ProfessorUser, LocationHistory
from apps.course.models import Participant
# Import Admin Sites from utils
from utils.admin import project_admin_site, dovoodi_admin_site
from apps.account.admin.location import LocationHistoryInline
# =========================================================
# 1. Base User Admin (Logic Shared by all User types)
# =========================================================
class UserAdmin(BaseUserAdmin, ModelAdmin):
form = UserChangeForm
add_form = UserCreationForm
change_password_form = AdminPasswordChangeForm
compressed_fields = False
list_before_template = "account/user_list_section.html"
list_display = ('fullname', 'email', 'is_active', 'display_date_joined',)
ordering = ("-id",)
search_fields = ('email', 'fullname', 'username',)
list_filter = [
"is_active",
"is_staff",
("last_login", RangeDateTimeFilter),
("date_joined", RangeDateTimeFilter),
]
inlines = [LocationHistoryInline]
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': (('fullname', 'email'), 'phone_number', 'birthdate', 'gender', 'avatar', 'skill', 'info'),
}),
(_('Location'), {
'fields': ('city', 'country'),
'classes': ('collapse',),
}),
(_('Password'), {
'fields': ('password1', 'password2'),
'classes': ('collapse',),
}),
(_('Permissions'), {
'fields': ('is_active', 'is_staff', 'is_superuser', 'groups'),
'classes': ('collapse',),
}),
)
fieldsets = (
(None, {"fields": ("email", "fullname")}),
(_("Basic Information"), {
"fields": ("gender", "avatar", "phone_number", "birthdate", 'info', 'skill', "password"),
"classes": ["tab"],
}),
(_('Country & City'), {
'fields': ('city', 'country'),
"classes": ["tab"],
}),
(_('Device Information'), {
'fields': ('device_id', 'device_os', 'fcm', 'language',),
"classes": ["tab"],
}),
(_('Authentication'), {
'fields': ('display_auth_token',),
"classes": ["tab"],
}),
(_('Permissions'), {
'fields': ('user_type', 'is_active', 'is_staff', 'groups'),
"classes": ["tab"],
}),
(_('Important dates'), {
'fields': ('last_login', 'date_joined', 'deleted_at'),
"classes": ["tab"],
}),
)
formfield_overrides = {
models.TextField: {"widget": WysiwygWidget}
}
radio_fields = {"gender": admin.HORIZONTAL}
readonly_fields = ["last_login", "date_joined", "display_auth_token"]
@display(description=_("Date Joined"))
def display_date_joined(self, instance: User):
return instance.date_joined.strftime("%Y-%m-%d %H:%M") if instance.date_joined else "-"
@display(description=_("Last Login"))
def display_last_login(self, instance: User):
return instance.last_login.strftime("%Y-%m-%d %H:%M") if instance.last_login else "-"
@display(description=_("Authentication Token"))
def display_auth_token(self, instance: User):
from rest_framework.authtoken.models import Token
try:
token, created = Token.objects.get_or_create(user=instance)
return format_html('{}', token.key)
except Exception as e:
return format_html('{}', str(e))
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.filter(email__isnull=False)
# =========================================================
# 2. Specific User Type Admins
# =========================================================
class GuestUserAdmin(UserAdmin):
list_display = ('device_id', 'device_os', 'is_active', 'display_date_joined',)
def has_add_permission(self, request):
if '_popup' in request.GET and request.GET['_popup'] == '1':
return True
return False
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.filter(email__isnull=True)
@display(description=_("Date Joined"))
def display_date_joined(self, instance: User):
return instance.date_joined.strftime("%Y-%m-%d %H:%M") if instance.date_joined else "-"
class StudentParticipantInline(StackedInline):
"""Inline to show courses a student has joined"""
model = Participant
extra = 0
readonly_fields = ('course', 'joined_date', 'course_status', 'course_professor')
fields = ('course', 'course_status', 'course_professor', 'joined_date', 'is_active')
verbose_name = _('Course Participation')
verbose_name_plural = _('Course Participations')
autocomplete_fields = ['course']
tab = True
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('course', 'course__professor')
@admin.display(description=_('Course Status'))
def course_status(self, obj):
if obj.course:
return obj.course.get_status_display()
return '-'
@admin.display(description=_('Professor'))
def course_professor(self, obj):
if obj.course and obj.course.professor:
return obj.course.professor.fullname or obj.course.professor.email
return '-'
def has_add_permission(self, request, obj=None):
return True
def has_change_permission(self, request, obj=None):
return True
def has_delete_permission(self, request, obj=None):
return True
class StudentUserAdmin(UserAdmin):
list_display = ('display_header', 'email', 'gender', 'display_age', 'courses_count')
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': (('fullname', 'email'), 'phone_number', 'avatar', 'birthdate', 'gender'),
}),
(_('Location'), {
'fields': (('city', 'country'),),
'classes': ('collapse',),
}),
(_('password'), {
'fields': ('password1', 'password2',),
'classes': ('collapse',),
}),
)
inlines = [StudentParticipantInline, LocationHistoryInline]
@display(description=_("Student"), header=True)
def display_header(self, instance: StudentUser):
avatar_path = instance.avatar.url if instance.avatar else static("images/reading(1).png")
return [
instance.fullname,
None,
None,
{
"path": avatar_path,
"height": 30,
"width": 36,
"borderless": True,
},
]
@display(description=_("Age"))
def display_age(self, instance: StudentUser):
from datetime import date
if not instance.birthdate:
return "-"
today = date.today()
birthdate = instance.birthdate
age = today.year - birthdate.year - ((today.month, today.day) < (birthdate.month, birthdate.day))
formatted_date = birthdate.strftime("%Y-%m-%d")
return format_html('{}', f"Born on {formatted_date}", age)
@display(description=_("Courses"), dropdown=True)
def courses_count(self, instance: StudentUser):
total = instance.participated_courses.count()
items = []
for participant in instance.participated_courses.all():
course = participant.course
title = format_html(
"""