Commit 13141284 authored by Élie Bouttier's avatar Élie Bouttier

restriction allocations

parent cd80a830
......@@ -3,7 +3,7 @@ from django.db import models
from django.db.models import Q
from django.forms import ModelForm, BaseInlineFormSet
from django.utils import timezone
from django.urls import reverse
from django.urls import reverse, path
from django.utils.html import format_html
from django.conf.urls import url
from django.template.response import TemplateResponse
......@@ -30,7 +30,7 @@ from .models import Service, ServiceType, IPPrefix, IPResource, IPResourceState,
ServiceAllocation, Antenna, AntennaAllocation, Allocation, \
Route, Tunnel, Switch, Port
from .utils.notifications import notify_allocation
from .forms import AntennaForm
from .forms import AntennaForm, StopAllocationForm
### Filters
......@@ -206,14 +206,17 @@ class AllocationInline(admin.TabularInline):
return False
class NewAllocationMixin:
verbose_name_plural = 'Nouvelle allocation'
max_num = 1
def get_queryset(self, request):
return super().get_queryset(request).model.objects.none()
class ActiveAllocationMixin:
verbose_name_plural = 'Allocations actives'
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
max_num = 0
def get_queryset(self, request):
return super().get_queryset(request).filter(get_active_filter())
......@@ -239,46 +242,54 @@ class ServiceAllocationMixin:
return qs
class AntennaAllocationMixin:
model = AntennaAllocation
fields = ('id', 'antenna', 'resource', 'start', 'end')
raw_id_fields = ('resource',)
autocomplete_fields = ('antenna',)
#class AntennaAllocationMixin:
# model = AntennaAllocation
# fields = ('id', 'antenna', 'resource', 'start', 'end')
# raw_id_fields = ('resource',)
# autocomplete_fields = ('antenna',)
#
# def get_queryset(self, request):
# qs = super().get_queryset(request)
# qs = qs.select_related('antenna')
# return qs
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.select_related('antenna')
return qs
class NewServiceAllocationInline(ServiceAllocationMixin, NewAllocationMixin, AllocationInline):
fields = ('id', 'service', 'resource', 'route',)
class ActiveServiceAllocationInline(ServiceAllocationMixin, ActiveAllocationMixin, AllocationInline):
pass
fields = ('id', 'service', 'resource', 'route', 'start', 'stop',)
readonly_fields = ('service', 'start', 'resource', 'stop',)
def stop(self, obj):
return format_html('<a href="{}" class="deletelink">Terminer</a>', reverse('admin:stop-allocation', kwargs={'resource': obj.resource.ip}))
stop.short_description = 'Terminer l’allocation'
class InactiveServiceAllocationInline(ServiceAllocationMixin, InactiveAllocationMixin, AllocationInline):
pass
fields = ('id', 'service', 'resource', 'route', 'start', 'end')
readonly_fields = ('service', 'resource', 'route', 'start', 'end')
class ActiveAntennaAllocationInline(AntennaAllocationMixin, ActiveAllocationMixin, AllocationInline):
pass
#class ActiveAntennaAllocationInline(AntennaAllocationMixin, ActiveAllocationMixin, AllocationInline):
# pass
class InactiveAntennaAllocationInline(AntennaAllocationMixin, InactiveAllocationMixin, AllocationInline):
pass
#class InactiveAntennaAllocationInline(AntennaAllocationMixin, InactiveAllocationMixin, AllocationInline):
# pass
class IPResourceStateInline(admin.TabularInline):
model = IPResourceState
verbose_name_plural = 'Historique des changements d’état'
verbose_name_plural = 'Historique des derniers changements d’état'
fields = ['date']
readonly_fields = ['date']
ordering = ['-date']
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj):
return False
def has_delete_permission(self, request, obj=None):
return False
......@@ -310,15 +321,6 @@ class ServicePortInline(PortInline):
readonly_fields = ('switch', 'port', 'up',)
### 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):
......@@ -353,7 +355,11 @@ class ServiceAdmin(admin.ModelAdmin):
inlines = []
if obj and obj.ports.exists():
inlines += [ServicePortInline]
inlines += [ActiveServiceAllocationInline, InactiveServiceAllocationInline]
inlines += [NewServiceAllocationInline]
if obj and obj.active_allocations.exists():
inlines += [ActiveServiceAllocationInline]
if obj and obj.inactive_allocations.exists():
inlines += [InactiveServiceAllocationInline]
return [inline(self.model, self.admin_site) for inline in inlines]
def get_actions(self, request):
......@@ -429,13 +435,14 @@ class IPResourceAdmin(admin.ModelAdmin):
def get_inline_instances(self, request, obj=None):
super_inlines = super().get_inline_instances(request, obj)
if obj:
if obj.category == 0:
inlines = (ActiveServiceAllocationInline, InactiveServiceAllocationInline,)
elif obj.category == 1:
inlines = (ActiveAntennaAllocationInline, InactiveAntennaAllocationInline,)
else:
inlines = ()
inlines = []
if obj and obj.category == IPResource.CATEGORY_PUBLIC:
if obj.allocations.filter(get_active_filter()).exists():
inlines += [ActiveServiceAllocationInline]
else:
inlines += [NewServiceAllocationInline]
if obj.allocations.exclude(get_active_filter()).exists():
inlines += [InactiveServiceAllocationInline]
return [inline(self.model, self.admin_site) for inline in inlines] + super_inlines
def get_queryset(self, request):
......@@ -495,6 +502,7 @@ class IPResourceAdmin(admin.ModelAdmin):
else:
return label
ping.short_description = 'ping'
#ping.admin_order_field = 'last_state__date'
ping.admin_order_field = 'downtime'
def route(self, obj):
......@@ -518,6 +526,51 @@ class IPResourceAdmin(admin.ModelAdmin):
return HttpResponseRedirect(reverse('admin:contact-adherents') + "?pk=%s" % pk)
contact_ip_owners.short_description = 'Contacter les adhérents'
def stop_allocation(self, request, resource):
resource = self.get_object(request, resource)
allocation = resource.allocations.filter(get_active_filter()).first()
if not allocation: # L’IP n’est pas allouée
return HttpResponseRedirect(reverse('admin:services_ipresource_change', args=[resource.pk]))
form = StopAllocationForm(request.POST or None)
if request.method == 'POST' and form.is_valid():
self.message_user(request, 'Allocation stoppée.')
allocation.end = timezone.now()
allocation.save()
notify_allocation(request, allocation)
# Il faudrait rajouter un redirect dans l’URL pour rediriger vers l’IP ou le Service
return HttpResponseRedirect(reverse('admin:services_ipresource_change', args=[resource.pk]))
context = self.admin_site.each_context(request)
context.update({
'opts': self.model._meta,
'title': 'Stopper une allocation',
'object': resource,
'media': self.media,
'form': form,
})
return TemplateResponse(request, "admin/services/ipresource/stop_allocation.html", context)
def get_urls(self):
my_urls = [
path('<resource>/stop/', self.admin_site.admin_view(self.stop_allocation), name='stop-allocation'),
]
return my_urls + super().get_urls()
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 IPResourceStateAdmin(admin.ModelAdmin):
list_display = ('ip', 'date', 'state',)
def get_actions(self, request):
actions = super().get_actions(request)
if 'delete_selected' in actions:
......@@ -527,6 +580,9 @@ class IPResourceAdmin(admin.ModelAdmin):
def has_add_permission(self, request, obj=None):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
......@@ -613,7 +669,7 @@ class ActiveAntennaLayer(GeoJSONLayerView):
class AntennaAdmin(admin.ModelAdmin):
inlines = (ActiveAntennaAllocationInline, InactiveAntennaAllocationInline,)
#inlines = (ActiveAntennaAllocationInline, InactiveAntennaAllocationInline,)
list_filter = (
AntennaPrefixFilter,
AntennaPositionFilter,
......
......@@ -4,6 +4,10 @@ from django.contrib.gis.geos import Point
from .models import Antenna
class StopAllocationForm(forms.Form):
pass
class AntennaForm(forms.ModelForm):
longitude = forms.FloatField(
min_value=-180,
......
......@@ -109,9 +109,9 @@ class IPResource(models.Model):
@property
def allocations(self):
if self.category == 0:
if self.category == self.CATEGORY_PUBLIC:
return self.service_allocations
if self.category == 1:
if self.category == self.CATEGORY_ANTENNA:
return self.antenna_allocations
@property
......@@ -198,6 +198,10 @@ class Service(models.Model):
def active_allocations(self):
return self.allocations.filter(get_active_filter())
@property
def inactive_allocations(self):
return self.allocations.exclude(get_active_filter())
def get_absolute_url(self):
return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name), args=(self.pk,))
......
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static %}
{% block extrahead %}
{{ block.super }}
{{ media }}
<script type="text/javascript" src="{% static 'admin/js/cancel.js' %}"></script>
{% endblock %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
&rsaquo; Stopper l’allocation
</div>
{% endblock %}
{% block content %}
<p>Voulez-vous vraiment stopper l’allocation de l’IP « {{ object }} » ?</p>
<form method="post">{% csrf_token %}
<div>
<input type="hidden" name="post" value="yes">
<input type="submit" value="{% trans "Yes, I'm sure" %}">
<a href="#" class="button cancel-link">{% trans "No, take me back" %}</a>
</div>
</form>
{% endblock %}
......@@ -4,6 +4,7 @@ from django.conf import settings
from djadhere.utils import send_notification
# À simplifier : seul la route peut changer maintenant
def notify_allocation(request, new_alloc, old_alloc=None):
fields = ['resource', 'service', 'route', 'start', 'end', 'notes']
......@@ -32,12 +33,15 @@ def notify_allocation(request, new_alloc, old_alloc=None):
message += '\n\nVoir : ' + url
if old_alloc and diff:
sujet = 'Modification d’une allocation'
sujet = 'Modification d’allocation'
elif not old_alloc:
sujet = 'Nouvelle allocation'
if new_alloc.end:
sujet = 'Fin d’allocation'
else:
sujet = 'Nouvelle allocation'
else:
sujet = None
if sujet:
sujet += ' ADT%d' % new_alloc.service.adhesion.pk
sujet += ' {} sur {}'.format(new_alloc.resource, new_alloc.route)
send_notification(sujet, message, settings.ALLOCATIONS_EMAILS, cc=[benevole])
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment