from django import forms from django.contrib import admin, messages from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME from django.template.response import TemplateResponse from import_export.admin import ImportExportModelAdmin from simplemde.widgets import SimpleMDEEditor from apps.users.models import User, University, Major from apps.users.resources import UserResource from apps.notifications.tasks import send_manual_notification from core.admin import SoftDeleteListFilter, BaseModelAdmin class UserAdminForm(forms.ModelForm): mobile = forms.CharField(required=True) bio = forms.CharField(widget=SimpleMDEEditor(), required=False) student_id = forms.CharField(required=False) class Meta: model = User fields = '__all__' class ManualNotificationForm(forms.Form): title = forms.CharField(max_length=200, label="عنوان") digest = forms.CharField(max_length=500, label="توضیح کوتاه", widget=forms.Textarea(attrs={"rows": 3})) body_markdown = forms.CharField(required=False, label="متن کامل (Markdown)", widget=SimpleMDEEditor()) @admin.register(User) class UserAdmin(BaseUserAdmin, BaseModelAdmin, ImportExportModelAdmin): form = UserAdminForm resource_class = UserResource list_display = ('email', 'mobile', 'username', 'university', 'is_email_verified', 'is_mobile_verified', 'date_joined') list_filter = ('is_email_verified', 'is_mobile_verified', 'is_staff', 'year_of_study', SoftDeleteListFilter) search_fields = ('email', 'mobile', 'username', 'student_id', 'first_name', 'last_name') ordering = ('-date_joined',) fieldsets = ( ('Auth Credentials', {'fields': ('username', 'email', 'mobile', 'password')}), ('Personal info', { 'fields': ('first_name', 'last_name', 'student_id', 'university', 'year_of_study', 'major', 'bio', 'profile_picture') }), ('Permissions', { 'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions',), }), ('Important dates', {'fields': ('last_login', 'date_joined')}), ('Email identity', {'fields': ('is_email_verified',)}), ('Mobile Verification', { 'fields': ('is_mobile_verified',) }), ('Soft Delete', { 'fields': ('is_deleted', 'deleted_at'), 'classes': ('collapse',) }), ) add_fieldsets = ( ( 'Step 1', { 'classes': ('wide',), 'fields': ('email', 'mobile', 'student_id', 'password1', 'password2', 'usable_password'), }, ), ) readonly_fields = ('deleted_at',) actions = BaseModelAdmin.actions + ['send_notification'] def get_actions(self, request): actions = super().get_actions(request) if not request.user.has_perm('users.send_notification'): actions.pop('send_notification', None) return actions @admin.action(description="Send in-app notification to selected users") def send_notification(self, request, queryset): if not request.user.has_perm('users.send_notification'): self.message_user(request, "اجازه ارسال اعلان ندارید.", level=messages.ERROR) return None form = ManualNotificationForm(request.POST if 'confirm_send' in request.POST else None) user_ids = list(queryset.filter(is_active=True, is_deleted=False).values_list('pk', flat=True)) if not user_ids: self.message_user(request, "کاربر فعال برای ارسال انتخاب نشده است.", level=messages.WARNING) return None if 'confirm_send' in request.POST and form.is_valid() and user_ids: send_manual_notification.delay( user_ids, form.cleaned_data['title'], form.cleaned_data['digest'], form.cleaned_data['body_markdown'] or None, ) self.message_user(request, f"ارسال اعلان برای {len(user_ids)} کاربر در صف قرار گرفت.") return None return TemplateResponse(request, 'admin/users/send_notification.html', { **self.admin_site.each_context(request), 'title': 'ارسال اعلان', 'opts': self.model._meta, 'form': form, 'selected_ids': user_ids, 'selected_count': len(user_ids), 'action_checkbox_name': ACTION_CHECKBOX_NAME, }) @admin.register(University) class UniversityAdmin(BaseModelAdmin): list_display = ('name', 'code', 'is_active', 'created_at') list_filter = ('is_active', SoftDeleteListFilter) search_fields = ('name', 'code') @admin.register(Major) class MajorAdmin(BaseModelAdmin): list_display = ('name', 'code', 'is_active', 'created_at') list_filter = ('is_active', SoftDeleteListFilter) search_fields = ('name', 'code')