From 6b7abe9f0ab959ebefe65c099dea4c30e293d5a0 Mon Sep 17 00:00:00 2001 From: bashmak Date: Tue, 26 Jun 2018 18:55:59 +0300 Subject: [PATCH] Fix bugs in nas in subscribers management --- abonapp/forms.py | 18 ++- abonapp/models.py | 44 +++--- abonapp/templates/abonapp/editAbon.html | 20 +-- abonapp/templates/abonapp/peoples.html | 11 +- abonapp/urls.py | 2 + abonapp/views.py | 55 +++++--- agent/commands/dhcp.py | 33 +++-- agent/core.py | 2 +- agent/mod_mikrotik.py | 129 +++++++++--------- agent/structs.py | 17 ++- djing/settings.py | 5 + ip_pool/admin.py | 2 +- ip_pool/fields.py | 84 ++++++++++++ ip_pool/forms.py | 30 +--- ip_pool/models.py | 96 ++++++++----- ...loyed_ip_list.html => ip_leases_list.html} | 11 +- ip_pool/templates/ip_pool/net_add.html | 6 +- ip_pool/templates/ip_pool/net_edit.html | 8 +- ip_pool/templates/ip_pool/network_list.html | 4 +- ip_pool/urls.py | 2 +- periodic.py | 5 + static/js/cidr.js | 16 ++- 22 files changed, 370 insertions(+), 230 deletions(-) create mode 100644 ip_pool/fields.py rename ip_pool/templates/ip_pool/{employed_ip_list.html => ip_leases_list.html} (67%) diff --git a/abonapp/forms.py b/abonapp/forms.py index f02cb6b..4d1d561 100644 --- a/abonapp/forms.py +++ b/abonapp/forms.py @@ -5,7 +5,6 @@ from random import choice from string import digits, ascii_lowercase from . import models from django.conf import settings -from djing import IP_ADDR_REGEX def generate_random_chars(length=6, chars=digits, split=2, delimiter=''): @@ -42,8 +41,8 @@ class AbonForm(forms.ModelForm): abon_group_queryset = None if abon_group_queryset is not None: self.fields['street'].queryset = abon_group_queryset - if instance is not None and instance.is_dynamic_ip: - self.fields['ip_address'].widget.attrs['readonly'] = True + #if instance is not None and instance.is_dynamic_ip: + # self.fields['ip_address'].widget.attrs['readonly'] = True username = forms.CharField(max_length=127, required=False, initial=generate_random_username, widget=forms.TextInput(attrs={ @@ -56,13 +55,13 @@ class AbonForm(forms.ModelForm): 'type': 'password', 'autocomplete': 'new-password' }), label=_('Password')) - ip_address = forms.CharField(widget=forms.TextInput(attrs={ - 'pattern': IP_ADDR_REGEX - }), label=_('Ip Address'), required=False) + # ip_address = forms.CharField(widget=forms.TextInput(attrs={ + # 'pattern': IP_ADDR_REGEX + # }), label=_('Ip Address'), required=False) class Meta: model = models.Abon - fields = ('username', 'telephone', 'fio', 'group', 'description', 'street', 'house', 'is_active', 'ip_address') + fields = ('username', 'telephone', 'fio', 'group', 'description', 'street', 'house', 'is_active') widgets = { 'fio': forms.TextInput(attrs={ 'placeholder': _('fio'), @@ -72,8 +71,7 @@ class AbonForm(forms.ModelForm): 'placeholder': _('telephone placeholder'), 'pattern': getattr(settings, 'TELEPHONE_REGEXP', r'^(\+[7,8,9,3]\d{10,11})?$') }), - 'description': forms.Textarea(attrs={'rows': '4'}), - 'is_active': forms.NullBooleanSelect(attrs={'class': 'form-control'}) + 'description': forms.Textarea(attrs={'rows': '4'}) } def save(self, commit=True): @@ -141,7 +139,7 @@ class ExportUsersForm(forms.Form): FIELDS_CHOICES = ( ('username', _('profile username')), ('fio', _('fio')), - ('ip_address', _('Ip Address')), + #('ip_address', _('Ip Address')), ('description', _('Comment')), ('street__name', _('Street')), ('house', _('House')), diff --git a/abonapp/models.py b/abonapp/models.py index a203c7a..a80018f 100644 --- a/abonapp/models.py +++ b/abonapp/models.py @@ -1,9 +1,9 @@ from datetime import datetime +from ipaddress import ip_address from typing import Optional from django.conf import settings from django.core import validators -from django.core.exceptions import ValidationError from django.core.validators import RegexValidator from django.db import models, connection, transaction from django.db.models.signals import post_delete, pre_delete, post_init @@ -15,7 +15,8 @@ from django.utils.translation import ugettext_lazy as _, gettext from accounts_app.models import UserProfile, MyUserManager, BaseAccount from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNetworkError from group_app.models import Group -from djing.lib import ip2int, LogicError +from djing.lib import LogicError +from ip_pool.models import IpLeaseModel from tariff_app.models import Tariff, PeriodicPay from bitfield import BitField @@ -92,7 +93,8 @@ class Abon(BaseAccount): current_tariff = models.ForeignKey(AbonTariff, null=True, blank=True, on_delete=models.SET_NULL) group = models.ForeignKey(Group, models.SET_NULL, blank=True, null=True, verbose_name=_('User group')) ballance = models.FloatField(default=0.0) - ip_address = models.GenericIPAddressField(blank=True, null=True, verbose_name=_('Ip Address')) + ip_addresses = models.ManyToManyField(IpLeaseModel, verbose_name=_('Ip addresses')) + # ip_address = models.GenericIPAddressField(blank=True, null=True, verbose_name=_('Ip Address')) description = models.TextField(_('Comment'), null=True, blank=True) street = models.ForeignKey(AbonStreet, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Street')) house = models.CharField(_('House'), max_length=12, null=True, blank=True) @@ -213,23 +215,24 @@ class Abon(BaseAccount): # make subscriber from agent structure def build_agent_struct(self): - if self.ip_address: - user_ip = ip2int(self.ip_address) - else: + abon_addresses = tuple(ip_address(i.ip) for i in self.ip_addresses.filter(is_active=True)) + if not abon_addresses: return abon_tariff = self.active_tariff() if abon_tariff is None: - return - trf = abon_tariff.tariff - agent_trf = TariffStruct(trf.id, trf.speedIn, trf.speedOut) - return AbonStruct(self.pk, user_ip, agent_trf, bool(self.is_active)) - - def clean(self): - # check if ip address already busy - if self.ip_address is not None and Abon.objects.filter(ip_address=self.ip_address).exclude( - pk=self.pk).count() > 0: - raise ValidationError({'ip_address': (gettext('Ip address already exist'),)}) - return super(Abon, self).clean() + agent_trf = None + else: + trf = abon_tariff.tariff + agent_trf = TariffStruct(trf.id, trf.speedIn, trf.speedOut) + return AbonStruct(self.pk, abon_addresses, agent_trf, self.is_access()) + + # def clean(self): + # # check if ip address already busy + # abon_addresses = tuple(p.ip for p in self.ip_addresses.all().iterator()) + # if self.ip_address is not None and Abon.objects.filter(ip_address=self.ip_address).exclude( + # pk=self.pk).count() > 0: + # raise ValidationError({'ip_address': (gettext('Ip address already exist'),)}) + # return super(Abon, self).clean() def sync_with_nas(self, created: bool) -> Optional[Exception]: agent_abon = self.build_agent_struct() @@ -245,6 +248,13 @@ class Abon(BaseAccount): print('ERROR:', e) return e + # def disable_on_nas(self): + # agent_abon = self.build_agent_struct() + # if agent_abon is None: + # return + # tm = Transmitter() + # tm.remove_user(agent_abon) + def get_absolute_url(self): return resolve_url('abonapp:abon_home', self.group.id, self.username) diff --git a/abonapp/templates/abonapp/editAbon.html b/abonapp/templates/abonapp/editAbon.html index a28d907..ad003ec 100644 --- a/abonapp/templates/abonapp/editAbon.html +++ b/abonapp/templates/abonapp/editAbon.html @@ -37,17 +37,17 @@ {% bootstrap_field form.telephone form_group_class='form-group-sm' addon_after_class='input-group-btn' addon_after=bt %} {% endwith %} + {% bootstrap_field form.is_active form_group_class='form-group-sm' %} {# Ip address field #} - {% trans 'Reset ip' as tx %} - {% url 'abonapp:reset_ip' group.pk abon.username as url %} - {% bootstrap_button '' button_type='link' icon='refresh' button_class='btn-default btn-cmd' id='iprefreshbtn' href=url size='sm' title=tx as bt %} - {% bootstrap_field form.ip_address form_group_class='form-group-sm' addon_after_class='input-group-btn' addon_after=bt %} +{# {% trans 'Reset ip' as tx %}#} +{# {% url 'abonapp:reset_ip' group.pk abon.username as url %}#} +{# {% bootstrap_button '' button_type='link' icon='refresh' button_class='btn-default btn-cmd' id='iprefreshbtn' href=url size='sm' title=tx as bt %}#} +{# {% bootstrap_field form.ip_address form_group_class='form-group-sm' addon_after_class='input-group-btn' addon_after=bt %}#} {% bootstrap_field form.street form_group_class='form-group-sm' %} {% bootstrap_field form.house form_group_class='form-group-sm' %} - {% bootstrap_field form.is_active form_group_class='form-group-sm' %} {% bootstrap_field form.group form_group_class='form-group-sm' %} @@ -203,9 +203,13 @@ {% for lease in abon.ip_addresses.all %}
  • {% if lease.is_active %} - × + + + {% else %} - × + + + {% endif %} {{ lease }} @@ -217,7 +221,7 @@ {% endfor %}