diff --git a/abonapp/models.py b/abonapp/models.py
index 806ada4..ee22b0a 100644
--- a/abonapp/models.py
+++ b/abonapp/models.py
@@ -16,7 +16,7 @@ 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 LogicError
-from ip_pool.models import IpLeaseModel
+from ip_pool.models import IpLeaseModel, NetworkModel
from tariff_app.models import Tariff, PeriodicPay
from bitfield import BitField
@@ -225,18 +225,12 @@ class Abon(BaseAccount):
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()
if agent_abon is None:
return
+ if len(agent_abon.ips) < 1:
+ return _('Account has no one ips')
try:
tm = Transmitter()
if created:
@@ -250,14 +244,13 @@ class Abon(BaseAccount):
def get_absolute_url(self):
return resolve_url('abonapp:abon_home', self.group.id, self.username)
- def add_lease(self, ip: str, mac_addr=None):
+ def add_lease(self, ip: str, network: Optional[NetworkModel], mac_addr=None):
existed_client_ips = tuple(l.ip for l in self.ip_addresses.all())
if ip not in existed_client_ips:
- lease = IpLeaseModel.objects.create_from_ip(ip=ip, net=None, mac=mac_addr)
+ lease = IpLeaseModel.objects.create_from_ip(ip=ip, net=network, mac=mac_addr)
if lease is None:
- return 'Subnet not found'
+ return 'Error while creating a ip lease'
self.ip_addresses.add(lease)
- #self.save()
class PassportInfo(models.Model):
diff --git a/abonapp/templates/abonapp/editAbon.html b/abonapp/templates/abonapp/editAbon.html
index f64c739..04ff226 100644
--- a/abonapp/templates/abonapp/editAbon.html
+++ b/abonapp/templates/abonapp/editAbon.html
@@ -215,7 +215,11 @@
{% endif %}
{{ lease }}
- {% trans 'Leased by:' %} {{ lease.lease_time|date:'d-m H:i:s' }}
+ {% trans 'Leased by:' %} {{ lease.lease_time|date:'d-m H:i:s' }}.
+ {% if lease.mac_addr %}
+ {% trans 'From' %}: {{ lease.mac_addr }}.
+ {% endif %}
+
{% empty %}
diff --git a/abonapp/views.py b/abonapp/views.py
index 5d692e9..a6874aa 100644
--- a/abonapp/views.py
+++ b/abonapp/views.py
@@ -421,8 +421,11 @@ def pick_tariff(request, gid, uname):
else:
deadline = datetime.strptime(deadline, '%Y-%m-%d %H:%M:%S')
abon.pick_tariff(trf, request.user, deadline=deadline, comment=log_comment)
- abon.sync_with_nas(created=False)
- messages.success(request, _('Tariff has been picked'))
+ r = abon.sync_with_nas(created=False)
+ if r is None:
+ messages.success(request, _('Tariff has been picked'))
+ else:
+ messages.error(request, r)
return redirect('abonapp:abon_services', gid=gid, uname=abon.username)
except (lib.LogicError, NasFailedResult) as e:
messages.error(request, e)
@@ -554,7 +557,6 @@ def chgroup_tariff(request, gid):
tr = request.POST.getlist('tr')
grp.tariff_set.clear()
grp.tariff_set.add(*tr)
- grp.save()
messages.success(request, _('Successfully saved'))
return redirect('abonapp:ch_group_tariff', gid)
tariffs = Tariff.objects.all()
@@ -1001,20 +1003,6 @@ def abon_export(request, gid):
}, request=request)
-# @login_required
-# @permission_required('abonapp.change_abon')
-# @permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
-# @json_view
-# def reset_ip(request, gid, uname):
-# abon = get_object_or_404(models.Abon, username=uname)
-# abon.ip_address = None
-# abon.save(update_fields=('ip_address',))
-# return {
-# 'status': 0,
-# 'dat': ""
-# }
-
-
@login_required
@lib.decorators.only_admins
def fin_report(request):
@@ -1151,6 +1139,11 @@ def lease_add(request, gid, uname):
network = get_object_or_404(NetworkModel, pk=network_id)
lease = IpLeaseModel.objects.create_from_ip(ip, net=network, is_dynamic=is_dynamic)
abon.ip_addresses.add(lease)
+ tm = Transmitter()
+ tm.lease_start(
+ user=abon.build_agent_struct(),
+ lease=lease.ip
+ )
messages.success(request, _('Ip lease has been created'))
return redirect('abonapp:abon_home', gid, uname)
except lib.DuplicateEntry as e:
@@ -1233,19 +1226,24 @@ class DhcpLever(SecureApiView):
'switch_port': 3,
'cmd': 'commit'
}"""
- r = None
try:
- action = data['cmd']
+ action = data.get('cmd')
+ if action is None:
+ return '"cmd" parameter is missing'
+ client_ip = data.get('client_ip')
+ if client_ip is None:
+ return '"client_ip" parameter is missing'
if action == 'commit':
- r = dhcp_commit(
- data['client_ip'], data['client_mac'],
- data['switch_mac'], data['switch_port']
+ return dhcp_commit(
+ client_ip, data.get('client_mac'),
+ data.get('switch_mac'), data.get('switch_port')
)
elif action == 'expiry':
- r = dhcp_expiry(data['client_ip'])
+ return dhcp_expiry(client_ip)
elif action == 'release':
- r = dhcp_release(data['client_ip'])
+ return dhcp_release(client_ip)
+ else:
+ return '"cmd" parameter is invalid: %s' % action
except lib.LogicError as e:
print('LogicError', e)
- r = str(e)
- return r
+ return str(e)
diff --git a/agent/commands/dhcp.py b/agent/commands/dhcp.py
index 73fd293..1bef7e3 100644
--- a/agent/commands/dhcp.py
+++ b/agent/commands/dhcp.py
@@ -18,7 +18,10 @@ def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: i
abon = Abon.objects.get(device=dev)
if not abon.is_dynamic_ip:
return 'User settings is not dynamic'
- add_lease_result = abon.add_lease(client_ip)
+ client_ips = tuple(str(ip) for ip in abon.ip_addresses.all())
+ if client_ip in client_ips:
+ return 'Ip address already existed'
+ add_lease_result = abon.add_lease(client_ip, mac_addr=client_mac, network=None)
if add_lease_result is None:
if abon.is_access():
abon.sync_with_nas(created=False)
diff --git a/agent/core.py b/agent/core.py
index b9194e6..130420c 100644
--- a/agent/core.py
+++ b/agent/core.py
@@ -108,12 +108,12 @@ class BaseTransmitter(ABC):
def sync_nas(self, users_from_db: Iterator):
list_for_add, list_for_del = self._diff_users(users_from_db)
if len(list_for_del) > 0:
- print('List for del:')
+ print('List for del:', len(list_for_del))
for ld in list_for_del:
- print('\t', ld.ips)
+ print('\t', ld)
self.remove_user_range(list_for_del)
if len(list_for_add) > 0:
- print('List for add:')
+ print('List for add:', len(list_for_add))
for la in list_for_add:
- print('\t', la.ips)
+ print('\t', la)
self.add_user_range(list_for_add)
diff --git a/agent/mod_mikrotik.py b/agent/mod_mikrotik.py
index 9a44a27..2cdba3f 100644
--- a/agent/mod_mikrotik.py
+++ b/agent/mod_mikrotik.py
@@ -490,6 +490,8 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
raise NasFailedResult(_('You cannot disable last session'))
def lease_start(self, user: AbonStruct, lease):
+ if not issubclass(lease.__class__, _BaseAddress):
+ lease = ip_address(lease)
ip = self.find_ip(lease, LIST_USERS_ALLOWED)
if ip is None:
self.add_ip(LIST_USERS_ALLOWED, lease)
diff --git a/agent/structs.py b/agent/structs.py
index 2bc187e..3a603b9 100644
--- a/agent/structs.py
+++ b/agent/structs.py
@@ -36,30 +36,38 @@ class TariffStruct(BaseStruct):
# Abon from database
class AbonStruct(BaseStruct):
- __slots__ = ('uid', 'ips', 'tariff', 'is_access', 'queue_id')
+ __slots__ = ('uid', '_ips', 'tariff', 'is_access', 'queue_id')
def __init__(self, uid=0, ips=None, tariff=None, is_access=True):
self.uid = int(uid or 0)
if ips is None:
- self.ips = ()
+ self._ips = ()
else:
- self.ips = tuple(ip_address(ip) for ip in ips)
+ self._ips = tuple(ip_address(ip) for ip in ips)
self.tariff = tariff
self.is_access = is_access
self.queue_id = 0
+ def get_ips(self):
+ return self._ips
+
+ def set_ips(self, v):
+ self._ips = set(v)
+
+ ips = property(get_ips, set_ips, doc='Ip addresses')
+
def __eq__(self, other):
if not isinstance(other, AbonStruct):
raise TypeError
- r = self.uid == other.uid and self.ips == other.ips
+ r = self.uid == other.uid and self._ips == other._ips
r = r and self.tariff == other.tariff
return r
def __str__(self):
- return "uid=%d, ips=[%s], tariff=%s" % (self.uid, ';'.join(self.ips), self.tariff or '')
+ return "uid=%d, ips=[%s], tariff=%s" % (self.uid, ';'.join(str(i) for i in self._ips), self.tariff or '')
def __hash__(self):
- return hash(hash(self.ips) + hash(self.tariff)) if self.tariff is not None else 0
+ return hash(hash(self._ips) + hash(self.tariff)) if self.tariff is not None else 0
# Shape rule from NAS(Network Access Server)
diff --git a/devapp/migrations/0003_auto_20180529_1311.py b/devapp/migrations/0003_auto_20180529_1311.py
index 747c845..16baee2 100644
--- a/devapp/migrations/0003_auto_20180529_1311.py
+++ b/devapp/migrations/0003_auto_20180529_1311.py
@@ -14,7 +14,7 @@ def snmp_backup_info(apps, _):
Device = apps.get_model('devapp', 'Device')
obs = Device.objects.only('snmp_item_num')
with open(TMP_FILE, 'w') as f:
- serializers.serialize('json', obs, stream=f)
+ serializers.serialize('json', obs, stream=f, fields=('snmp_item_num',))
def snmp_restore_info_to_new_scheme(apps, _):
diff --git a/devapp/views.py b/devapp/views.py
index deb8289..353b4fc 100644
--- a/devapp/views.py
+++ b/devapp/views.py
@@ -123,8 +123,11 @@ class DeviceUpdate(UpdateView):
pass
r = super().form_valid(form)
# change device info in dhcpd.conf
- self.object.update_dhcp()
- messages.success(self.request, _('Device info has been saved'))
+ try:
+ self.object.update_dhcp()
+ messages.success(self.request, _('Device info has been saved'))
+ except PermissionError as e:
+ messages.error(self.request, e)
return r
def dispatch(self, request, *args, **kwargs):
@@ -177,8 +180,11 @@ class DeviceCreateView(CreateView):
pass
r = super().form_valid(form)
# change device info in dhcpd.conf
- self.object.update_dhcp()
- messages.success(self.request, _('Device info has been saved'))
+ try:
+ self.object.update_dhcp()
+ messages.success(self.request, _('Device info has been saved'))
+ except PermissionError as e:
+ messages.error(self.request, e)
return r
def dispatch(self, request, *args, **kwargs):
diff --git a/ip_pool/migrations/0001_initial.py b/ip_pool/migrations/0001_initial.py
index b8db851..9ce0cdb 100644
--- a/ip_pool/migrations/0001_initial.py
+++ b/ip_pool/migrations/0001_initial.py
@@ -56,7 +56,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='ipleasemodel',
name='network',
- field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ip_pool.NetworkModel', verbose_name='Parent network'),
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ip_pool.NetworkModel', verbose_name='Parent network', blank=True, null=True),
),
migrations.AlterUniqueTogether(
name='ipleasemodel',
diff --git a/ip_pool/models.py b/ip_pool/models.py
index 5d389ab..642e780 100644
--- a/ip_pool/models.py
+++ b/ip_pool/models.py
@@ -163,7 +163,7 @@ class IpLeaseManager(models.Manager):
class IpLeaseModel(models.Model):
ip = models.GenericIPAddressField(verbose_name=_('Ip address'), unique=True)
- network = models.ForeignKey(NetworkModel, on_delete=models.CASCADE, verbose_name=_('Parent network'))
+ network = models.ForeignKey(NetworkModel, on_delete=models.CASCADE, verbose_name=_('Parent network'), null=True, blank=True)
mac_addr = MACAddressField(verbose_name=_('Mac address'), null=True, blank=True, unique=True)
lease_time = models.DateTimeField(_('Lease time'), auto_now_add=True)
is_dynamic = models.BooleanField(_('Is dynamic'), default=False)
diff --git a/periodic.py b/periodic.py
index 79f94f1..abab7e3 100755
--- a/periodic.py
+++ b/periodic.py
@@ -6,7 +6,7 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings")
django.setup()
from django.utils import timezone
from django.db import transaction
-from django.db.models import signals
+from django.db.models import signals, Count
from abonapp.models import Abon, AbonTariff, abontariff_pre_delete, PeriodicPayForId, AbonLog
from ip_pool.models import IpLeaseModel
from agent import Transmitter, NasNetworkError, NasFailedResult
@@ -42,6 +42,8 @@ def main():
users = Abon.objects\
.filter(is_active=True)\
.exclude(current_tariff=None)\
+ .annotate(ips_count=Count('ip_addresses'))\
+ .filter(ips_count__gt=0)\
.prefetch_related('ip_addresses')\
.iterator()
tm.sync_nas(users)