123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- 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)
|