diff --git a/ipv6ula/forms.py b/ipv6ula/forms.py index 0800a9f..2569abc 100644 --- a/ipv6ula/forms.py +++ b/ipv6ula/forms.py @@ -1,6 +1,7 @@ from django import forms - -from .models import validate_ula_prefix, ULA +import ipaddress +from .models import validate_ula_prefix, ULA, validate_owner_ula_prefix +from django.core.exceptions import ValidationError class ULAForm(forms.ModelForm): class Meta: @@ -17,3 +18,48 @@ class ULAGenerateForm(forms.ModelForm): class Meta: model = ULA fields = [ 'name', 'organization', 'website' ] + +class ULAUpdateForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + self.owner = kwargs.pop('owner', None) + super().__init__(*args, **kwargs) + + class Meta: + model = ULA + fields = [ 'prefix', 'name', 'organization', 'website' ] + + def clean_prefix(self): + prefix = self.cleaned_data.get("prefix") + if not prefix or not self.owner: + return prefix + + net_str = f"{prefix}/48" + net = ipaddress.IPv6Network(net_str, strict=False) + normalized_prefix = str(net[0]) + self.cleaned_data['prefix'] = normalized_prefix + + qs = ULA.objects.filter(prefix=normalized_prefix) + if self.instance.pk: + qs = qs.exclude(pk=self.instance.pk) + + if qs.exists(): + existing = qs.first() + if existing.owner != self.owner: + raise ValidationError("This prefix is already registered by another user.") + else: + self.instance = existing + return normalized_prefix + + +class ULADeleteForm(forms.ModelForm): + class Meta: + model = ULA + fields = [ 'prefix' ] + + def clean_prefix(self): + prefix = self.cleaned_data['prefix'] + validate_ula_prefix(prefix) + validate_owner_ula_prefix(prefix) + + return prefix + diff --git a/ipv6ula/models.py b/ipv6ula/models.py index d7232ed..9b791f5 100644 --- a/ipv6ula/models.py +++ b/ipv6ula/models.py @@ -31,6 +31,30 @@ def validate_ula_prefix(prefix): params = {'prefix': net } ) +def validate_owner_ula_prefix(prefix): + ula_net = ipaddress.IPv6Network("fd00::/8") + net_str = f"{prefix}/48" + net = ipaddress.IPv6Network(net_str, strict=False) + + if not net.subnet_of(ula_net): + raise ValidationError( + _(f"Prefix {net} is not within ULA range ({ula_net})"), + code='invalid', + params = {'prefix': net } + ) + + + try: + ULA.objects.get(prefix=str(net[0])) + except ULA.DoesNotExist: + raise ValidationError( + _(f"Prefix {net} is not your prefix"), + code='invalid', + params = {'prefix': net } + ) + else: + pass + class User(AbstractUser): pass @@ -41,7 +65,7 @@ class ULA(models.Model): on_delete=models.CASCADE ) - prefix = models.GenericIPAddressField(protocol='IPv6', unique=True, validators=[validate_ula_prefix]) + prefix = models.GenericIPAddressField(protocol='IPv6', unique=True) name = models.CharField(max_length=256) organization = models.CharField(max_length=256) website = models.URLField() @@ -54,7 +78,6 @@ class ULA(models.Model): net_str = f"{self.prefix}/48" net = ipaddress.IPv6Network(net_str, strict=False) self.prefix = str(net[0]) - super().save(*args, **kwargs) def __str__(self): diff --git a/ipv6ula/templates/ipv6ula/base.html b/ipv6ula/templates/ipv6ula/base.html index a005058..d9d6fb2 100644 --- a/ipv6ula/templates/ipv6ula/base.html +++ b/ipv6ula/templates/ipv6ula/base.html @@ -33,6 +33,14 @@ Submit existing prefix +
A new random prefix will be generated for you.
+ {% elif method == 'update' %} ++ You update your existing prefix. +
+ {% elif method == 'delete' %} ++ You delete your existing prefix. +
{% endif %}diff --git a/ipv6ula/urls.py b/ipv6ula/urls.py index eebc776..1c0af23 100644 --- a/ipv6ula/urls.py +++ b/ipv6ula/urls.py @@ -28,4 +28,6 @@ urlpatterns = [ path('login/', views.LoginView.as_view(), name='login'), path('logout/', views.logout_view, name='logout'), path('admin/', admin.site.urls), + path('update/', views.UpdateView.as_view(), name='update'), + path('delete/', views.DeleteView.as_view(), name='delete'), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/ipv6ula/views.py b/ipv6ula/views.py index 14cbdee..0a7cbe5 100644 --- a/ipv6ula/views.py +++ b/ipv6ula/views.py @@ -73,6 +73,27 @@ class SubmitView(GenerateSubmitView): class LoginView(auth_views.LoginView): template_name = 'ipv6ula/login.html' +class UpdateView(GenerateSubmitView): + form_class = ULAUpdateForm + gen_method = "update" + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs['owner'] = self.request.user + return kwargs + + def form_valid(self, form): + form.instance.owner = self.request.user + return super().form_valid(form) + +class DeleteView(GenerateSubmitView): + form_class = ULADeleteForm + gen_method = "delete" + + def form_valid(self, form): + form.instance.owner = self.request.user + return super().form_valid(form) + def logout_view(request): logout(request) return redirect("/")