You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
8.7 KiB
220 lines
8.7 KiB
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',)
|