from django.contrib import admin from django.contrib.gis import admin as geo_admin from django.db import models from django.db.models import Q from django.forms import ModelForm, BaseInlineFormSet from django.utils import timezone from django.core.urlresolvers import reverse from django.utils.html import format_html from django.core.mail import mail_managers from adhesions.models import Adhesion from .models import Service, ServiceType, IPResource, Route, ServiceAllocation, Antenna, AntennaAllocation, Allocation from .utils import notify_allocation ### Filters class ResourceInUseFilter(admin.SimpleListFilter): title = 'disponibilité' parameter_name = 'available' def lookups(self, request, model_admin): return ( (1, 'Disponible'), (0, 'Non disponible'), ) def queryset(self, request, queryset): available_filter = Q(reserved=False, in_use=False) if self.value() == '0': # non disponible return queryset.exclude(available_filter) if self.value() == '1': # disponible return queryset.filter(available_filter) ### Inlines class AllocationInlineFormSet(BaseInlineFormSet): def save_new(self, form, commit=True): obj = super().save_new(form, commit) if type(obj) == ServiceAllocation: notify_allocation(self.request, obj) return obj def save_existing(self, form, instance, commit=True): old = type(instance).objects.get(pk=instance.pk) if type(instance) == ServiceAllocation: notify_allocation(self.request, instance, old) return super().save_existing(form, instance, commit) class AllocationInline(admin.TabularInline): formset = AllocationInlineFormSet extra = 0 verbose_name_plural = 'Allocations' show_change_link = True def get_formset(self, request, obj=None, **kwargs): formset = super().get_formset(request, obj, **kwargs) formset.request = request return formset def get_max_num(self, request, obj=None, **kwargs): existing = obj.allocations.count() if obj else 0 # pour simplifier la validation, on ajoute qu’une allocation à la fois # il faudrait surcharger la méthode clean du formset pour supprimer cette limite return existing + 1 def has_delete_permission(self, request, obj=None): return False class ServiceAllocationInline(AllocationInline): model = ServiceAllocation fields = ('id', 'service', 'resource', 'route', 'start', 'end') raw_id_fields = ('service', 'resource',) class AntennaAllocationInline(AllocationInline): model = AntennaAllocation fields = ('id', 'antenna', 'resource', 'start', 'end') raw_id_fields = ('antenna', 'resource',) ### Actions def ends_resource(resource, request, queryset): now = timezone.now() queryset.exclude(start__lte=now, end__isnull=False).update(end=now) # TODO: send mail ends_resource.short_description = 'Terminer les allocations sélectionnées' ### ModelAdmin class ServiceAdmin(admin.ModelAdmin): list_display = ('id', 'get_adhesion_link', 'get_adherent_link', 'service_type', 'label', 'active') list_select_related = ('adhesion',) # to reduce database requests list_filter = ( 'active', ('service_type', admin.RelatedOnlyFieldListFilter), ) inlines = (ServiceAllocationInline,) search_fields = ('id', 'service_type__name', 'label', 'adhesion__id',) raw_id_fields = ('adhesion',) get_adhesion_link = lambda self, service: service.adhesion.get_adhesion_link() get_adhesion_link.short_description = Adhesion.get_adhesion_link.short_description get_adherent_link = lambda self, service: service.adhesion.get_adherent_link() get_adherent_link.short_description = Adhesion.get_adherent_link.short_description def get_actions(self, request): actions = super().get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions def has_delete_permission(self, request, obj=None): return False class IPResourceAdmin(admin.ModelAdmin): list_display = ('__str__', 'available_display', 'last_use',) list_filter = ( 'category', ResourceInUseFilter, ('prefixes', admin.RelatedOnlyFieldListFilter), ) fields = ('ip', 'reserved', 'notes') readonly_fields = ('ip', 'reserved',) search_fields = ('ip',) def get_inline_instances(self, request, obj=None): if obj: if obj.category == 0: inlines = (ServiceAllocationInline,) elif obj.category == 1: inlines = (AntennaAllocationInline,) else: inlines = () return [inline(self.model, self.admin_site) for inline in inlines] def get_queryset(self, request): qs = super().get_queryset(request) qs = qs.annotate(last_use=models.Case( models.When(category=0, then=models.Max('service_allocation__end')), models.When(category=1, then=models.Max('antenna_allocation__end')), )) return qs def available_display(self, obj): return not obj.reserved and not obj.in_use available_display.short_description = 'Disponible' available_display.boolean = True def last_use(self, obj): if obj.allocations.exists(): return obj.allocations.last().end else: return None last_use.short_description = 'Dernière utilisation' last_use.admin_order_field = 'last_use' def get_actions(self, request): actions = super().get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions def has_add_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False class RouteAdmin(admin.ModelAdmin): fields = ('name',) readonly_fields = ('name',) def has_add_permission(self, request, obj=None): return False def get_actions(self, request): actions = super().get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions def has_delete_permission(self, request, obj=None): return False class ServiceTypeAdmin(admin.ModelAdmin): fields = ('name',) readonly_fields = ('name',) def get_actions(self, request): actions = super().get_actions(request) if 'delete_selected' in actions: del actions['delete_selected'] return actions def has_add_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False class AntennaAdmin(geo_admin.OSMGeoAdmin): inlines = (AntennaAllocationInline,) admin.site.register(ServiceType, ServiceTypeAdmin) admin.site.register(Service, ServiceAdmin) admin.site.register(IPResource, IPResourceAdmin) admin.site.register(Route, RouteAdmin) geo_admin.site.register(Antenna, AntennaAdmin)