from django.contrib import admin from django.utils.translation import gettext_lazy as _ from unfold.admin import ModelAdmin, TabularInline, StackedInline from unfold.decorators import display, action from apps.profiles.models import ( Region, Institution, InstitutionMember, InstitutionTimeline, InstitutionMedia, InstitutionFollower, ) from utils.admin import project_admin_site @admin.register(Region, site=project_admin_site) class RegionAdmin(ModelAdmin): list_display = ( 'name', 'code', 'slug', 'is_active', 'institutions_count', 'created_at', ) list_display_links = ('name', 'code', 'slug') list_filter = ('is_active', 'created_at') search_fields = ('name', 'code', 'description') prepopulated_fields = {'slug': ('name',)} readonly_fields = ('created_at', 'updated_at', 'institutions_count') fieldsets = ( (_('Region Details'), { 'fields': ('name', 'slug', 'code', 'is_active', 'description') }), (_('Timestamps & Statistics'), { 'fields': ('institutions_count', 'created_at', 'updated_at') }), ) @display(description=_('Institutions Count')) def institutions_count(self, obj): return obj.institutions.count() def get_queryset(self, request): qs = super().get_queryset(request) if request.user.is_superuser or getattr(request.user, 'is_super_admin', False): return qs if getattr(request.user, 'is_regional_admin', False) and hasattr(request.user, 'managed_regions'): return qs.filter(id__in=request.user.managed_regions.all()) return qs class InstitutionMemberInline(TabularInline): model = InstitutionMember extra = 0 fields = ('user', 'role', 'title', 'joined_at') readonly_fields = ('joined_at',) class InstitutionTimelineInline(StackedInline): model = InstitutionTimeline extra = 0 fields = ('year', 'title', 'description', 'order') class InstitutionMediaInline(TabularInline): model = InstitutionMedia extra = 0 fields = ('file', 'media_type', 'title', 'uploaded_at') readonly_fields = ('uploaded_at',) @admin.register(Institution, site=project_admin_site) class InstitutionAdmin(ModelAdmin): list_display = ( 'name', 'type_badge', 'region_display', 'city', 'country', 'verification_badge', 'follower_count', 'is_featured', 'is_active', 'created_at', ) list_display_links = ('name', 'type_badge', 'city', 'country') list_filter = ('region', 'type', 'verification_status', 'is_featured', 'is_active', 'country') search_fields = ('name', 'region__name', 'city', 'country', 'description', 'email', 'phone') prepopulated_fields = {'slug': ('name',)} readonly_fields = ('follower_count', 'created_at', 'updated_at') inlines = [InstitutionMemberInline, InstitutionTimelineInline, InstitutionMediaInline] actions = ['approve_institutions', 'reject_institutions', 'toggle_featured'] def get_queryset(self, request): qs = super().get_queryset(request) if request.user.is_superuser or getattr(request.user, 'is_super_admin', False): return qs if getattr(request.user, 'is_regional_admin', False) and hasattr(request.user, 'managed_regions'): return qs.filter(region__in=request.user.managed_regions.all()) return qs def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "region": if not (request.user.is_superuser or getattr(request.user, 'is_super_admin', False)) and getattr(request.user, 'is_regional_admin', False) and hasattr(request.user, 'managed_regions'): kwargs["queryset"] = request.user.managed_regions.all() return super().formfield_for_foreignkey(db_field, request, **kwargs) def has_change_permission(self, request, obj=None): if not super().has_change_permission(request, obj): return False if obj is not None and not (request.user.is_superuser or getattr(request.user, 'is_super_admin', False)) and getattr(request.user, 'is_regional_admin', False): if hasattr(request.user, 'can_manage_region'): return request.user.can_manage_region(obj.region) return True def has_delete_permission(self, request, obj=None): if not super().has_delete_permission(request, obj): return False if obj is not None and not (request.user.is_superuser or getattr(request.user, 'is_super_admin', False)) and getattr(request.user, 'is_regional_admin', False): if hasattr(request.user, 'can_manage_region'): return request.user.can_manage_region(obj.region) return True fieldsets = ( (_('Identity & Classification'), { 'fields': ('name', 'slug', 'type', 'is_featured', 'is_active', 'created_by') }), (_('Location & Geo-Coordinates'), { 'fields': ('region', 'country', 'city', 'address', 'latitude', 'longitude') }), (_('Contact & Official Channels'), { 'fields': ('email', 'phone', 'website', 'established_year') }), (_('Media & Branding'), { 'fields': ('avatar', 'cover_image') }), (_('Structured JSON Metadata'), { 'fields': ('description', 'social_media', 'working_hours', 'tags') }), (_('Verification & Statistics'), { 'fields': ('verification_status', 'follower_count', 'created_at', 'updated_at') }), ) @display(description=_('Region')) def region_display(self, obj): return obj.region.name if obj.region else "-" @display(description=_('Type')) def type_badge(self, obj): return obj.get_type_display() @display(description=_('Verification'), label={ Institution.VerificationStatus.APPROVED: "success", Institution.VerificationStatus.PENDING: "warning", Institution.VerificationStatus.REJECTED: "danger", }) def verification_badge(self, obj): return obj.get_verification_status_display() @action(description=_('Approve and verify selected institutions')) def approve_institutions(self, request, queryset): count = queryset.update(verification_status=Institution.VerificationStatus.APPROVED) self.message_user(request, _(f"{count} institution(s) approved and verified.")) @action(description=_('Reject selected institutions')) def reject_institutions(self, request, queryset): count = queryset.update(verification_status=Institution.VerificationStatus.REJECTED) self.message_user(request, _(f"{count} institution(s) marked as rejected.")) @action(description=_('Toggle featured status for selected institutions')) def toggle_featured(self, request, queryset): for item in queryset: item.is_featured = not item.is_featured item.save(update_fields=['is_featured']) self.message_user(request, _("Featured status updated for selected institutions.")) @admin.register(InstitutionMember, site=project_admin_site) class InstitutionMemberAdmin(ModelAdmin): list_display = ('user', 'institution', 'role_badge', 'title', 'joined_at') list_display_links = ('user', 'institution', 'title') list_filter = ('role', 'joined_at') search_fields = ('user__email', 'user__fullname', 'institution__name', 'title') readonly_fields = ('joined_at',) @display(description=_('Role'), label={ InstitutionMember.MemberRole.ADMIN: "danger", InstitutionMember.MemberRole.EDITOR: "warning", InstitutionMember.MemberRole.VIEWER: "info", }) def role_badge(self, obj): return obj.get_role_display() @admin.register(InstitutionTimeline, site=project_admin_site) class InstitutionTimelineAdmin(ModelAdmin): list_display = ('institution', 'year', 'title', 'order', 'created_at') list_display_links = ('institution', 'title', 'year') search_fields = ('institution__name', 'title', 'description', 'year') list_filter = ('created_at',) @admin.register(InstitutionMedia, site=project_admin_site) class InstitutionMediaAdmin(ModelAdmin): list_display = ('institution', 'title', 'media_type', 'uploaded_at') list_display_links = ('institution', 'title') list_filter = ('media_type', 'uploaded_at') search_fields = ('institution__name', 'title', 'caption') @admin.register(InstitutionFollower, site=project_admin_site) class InstitutionFollowerAdmin(ModelAdmin): list_display = ('user', 'institution', 'created_at') list_display_links = ('user', 'institution') search_fields = ('user__email', 'user__fullname', 'institution__name') readonly_fields = ('created_at',)