Browse Source

Change ip_field in abon model

devel
Dmitry Novikov 8 years ago
parent
commit
7cf7138a6e
  1. 20
      abonapp/locale/ru/LC_MESSAGES/django.po
  2. 51
      abonapp/migrations/0006_change_ip.py
  3. 46
      abonapp/models.py
  4. 55
      abonapp/templates/abonapp/editAbon.html
  5. 24
      abonapp/templates/abonapp/modal_add_lease.html
  6. 4
      abonapp/urls.py
  7. 155
      abonapp/views.py
  8. 6
      accounts_app/templatetags/acc_tags.py
  9. 27
      agent/commands/dhcp.py
  10. 8
      djing/lib/auth_backends.py
  11. 9
      djing/lib/mixins.py
  12. 1
      ip_pool/admin.py
  13. 33
      ip_pool/forms.py
  14. 37
      ip_pool/migrations/0003_add_leases_history_model.py
  15. 31
      ip_pool/models.py
  16. 44
      ip_pool/templates/ip_pool/ip_leases_list.html
  17. 4
      ip_pool/templates/ip_pool/net_edit.html
  18. 6
      ip_pool/templates/ip_pool/network_list.html
  19. 1
      ip_pool/urls.py
  20. 17
      ip_pool/views.py
  21. 36
      nas_app/nas_managers/core.py
  22. 66
      nas_app/nas_managers/mod_mikrotik.py
  23. 30
      nas_app/nas_managers/structs.py
  24. 10
      periodic.py
  25. 2
      searchapp/views.py

20
abonapp/locale/ru/LC_MESSAGES/django.po

@ -116,8 +116,8 @@ msgid "User group"
msgstr "Группа"
#: models.py:96 templates/abonapp/editAbon.html:180
msgid "Ip addresses"
msgstr "IP Адреса"
msgid "Ip address"
msgstr "IP Адрес"
#: models.py:103
msgid "Network access server"
@ -202,11 +202,6 @@ msgstr "Не хватает денег на счету"
msgid "Buy service default log"
msgstr "Покупка тарифного плана через админку"
#: models.py:228
#, python-format
msgid "Account \"%(username)s\" not have any active leases"
msgstr "Учётная запись \"%(username)s\" не имеет ни одной активной сессии"
#: models.py:238 models.py:255 models.py:272 views.py:684 views.py:1132
#: views.py:1175
msgid "NAS required"
@ -515,10 +510,6 @@ msgstr "Выделен из:"
msgid "From"
msgstr "От"
#: templates/abonapp/editAbon.html:218
msgid "Leases does not found"
msgstr "Аренды ip не найдены"
#: templates/abonapp/editAbon.html:230
#: templates/abonapp/modal_add_lease.html:16
#: templates/abonapp/modal_add_phone.html:27
@ -529,8 +520,8 @@ msgid "Add"
msgstr "Добавить"
#: templates/abonapp/editAbon.html:234
msgid "Active networks"
msgstr "Активные подсети"
msgid "Networks"
msgstr "Подсети"
#: templates/abonapp/editAbon.html:242
msgid "User flags"
@ -1159,3 +1150,6 @@ msgstr "Автопродление услуги."
msgid "No author attached"
msgstr "Автор не назначен"
msgid "User not have ip"
msgstr "У пользователя нет ip"

51
abonapp/migrations/0006_change_ip.py

@ -0,0 +1,51 @@
# Generated by Django 2.1 on 2018-10-10 16:11
# from json import dump
from django.db import migrations, models
TMP_FILE = '/tmp/migrate_ip.json'
DUMP = []
def backup_info(apps, _):
Abon = apps.get_model('abonapp', 'Abon')
abons = Abon.objects.annotate(
addr_count=models.Count('ip_addresses')
).filter(addr_count__gt=0).only('ip_addresses').iterator()
global DUMP
for abon in abons:
ip_addr = abon.ip_addresses.first()
DUMP.append({
'pk': abon.pk,
'addr': ip_addr.ip
})
# with open(TMP_FILE, 'w') as f:
# dump(r, f, indent=2)
def restore_ips(apps, _):
Abon = apps.get_model('abonapp', 'Abon')
for abon in DUMP:
Abon.objects.filter(pk=abon.get('pk')).update(ip_address=abon.get('addr'))
class Migration(migrations.Migration):
dependencies = [
('abonapp', '0005_current_tariff'),
]
operations = [
migrations.RunPython(backup_info),
migrations.RemoveField(
model_name='abon',
name='ip_addresses',
),
migrations.AddField(
model_name='abon',
name='ip_address',
field=models.GenericIPAddressField(blank=True, null=True, unique=True, verbose_name='Ip address'),
),
migrations.RunPython(restore_ips)
]

46
abonapp/models.py

@ -16,7 +16,7 @@ from accounts_app.models import UserProfile, MyUserManager, BaseAccount
from nas_app.nas_managers import AbonStruct, TariffStruct, NasFailedResult, NasNetworkError
from group_app.models import Group
from djing.lib import LogicError
from ip_pool.models import IpLeaseModel, NetworkModel
from ip_pool.models import NetworkModel
from tariff_app.models import Tariff, PeriodicPay
from bitfield import BitField
@ -90,7 +90,7 @@ class Abon(BaseAccount):
current_tariff = models.OneToOneField(AbonTariff, null=True, blank=True, on_delete=models.SET_NULL, default=None)
group = models.ForeignKey(Group, on_delete=models.SET_NULL, blank=True, null=True, verbose_name=_('User group'))
ballance = models.FloatField(default=0.0)
ip_addresses = models.ManyToManyField(IpLeaseModel, verbose_name=_('Ip addresses'))
ip_address = models.GenericIPAddressField(verbose_name=_('Ip address'), unique=True, null=True, blank=True)
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)
@ -198,6 +198,25 @@ class Abon(BaseAccount):
comment=comment or _('Buy service default log')
)
def attach_ip_addr(self, ip, strict=False):
"""
Attach ip address to account
:param ip: Instance of str or ip_address
:param strict: If strict is True then ip not replaced quietly
:return: None
"""
if strict and self.ip_address:
raise LogicError('Ip address already exists')
self.ip_address = ip
self.save(update_fields=('ip_address',))
def free_ip_addr(self) -> bool:
if self.ip_address:
self.ip_address = None
self.save(update_fields=('ip_address',))
return True
return False
# is subscriber have access to service, view in tariff_app.custom_tariffs.<TariffBase>.manage_access()
def is_access(self) -> bool:
if not self.is_active:
@ -210,22 +229,17 @@ class Abon(BaseAccount):
return ct.manage_access(self)
# make subscriber from agent structure
def build_agent_struct(self, raise_errs=True):
abon_addresses = tuple(ip_address(i.ip) for i in self.ip_addresses.filter(is_active=True))
# if not abon_addresses:
# return
def build_agent_struct(self):
if not self.ip_address:
return
abon_address = ip_address(self.ip_address)
abon_tariff = self.active_tariff()
if abon_tariff is None:
agent_trf = None
else:
trf = abon_tariff.tariff
agent_trf = TariffStruct(trf.id, trf.speedIn, trf.speedOut)
if len(abon_addresses) > 0:
return AbonStruct(self.pk, abon_addresses, agent_trf, self.is_access())
if raise_errs:
raise LogicError(_('Account "%(username)s" not have any active leases') % {
'username': self.username
})
return AbonStruct(self.pk, abon_address, agent_trf, self.is_access())
def nas_sync_self(self) -> Optional[Exception]:
"""
@ -281,14 +295,6 @@ 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, 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=network, mac=mac_addr)
if lease is None:
return 'Error while creating a ip lease'
self.ip_addresses.add(lease)
def enable_service(self, tariff: Tariff, deadline=None, time_start=None):
"""
Makes a services for current user

55
abonapp/templates/abonapp/editAbon.html

@ -46,9 +46,6 @@
<script type="text/javascript">
$(function () {
$("#iprefreshbtn").on('click', function(){
$("#{{ form.ip_address.id_for_label }}").val('');
});
$('#passwdtoggler').on('mousedown', function(){
document.getElementById("{{ form.password.id_for_label }}").type='text';
}).on('mouseup', function(){
@ -182,25 +179,17 @@
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'Ip addresses' %}</h3>
<h3 class="panel-title">{% trans 'Ip address' %}</h3>
</div>
<ul class="list-group">
{% with can_ping=perms.abonapp.can_ping %}
{% for lease in abon.ip_addresses.all %}
<li class="list-group-item">
<div class="panel-body">
{% if abon.ip_address %}
<div class="btn-group btn-group-xs">
{% if lease.is_active %}
<a href="{% url 'abonapp:user_session_free' group.pk abon.username lease.pk %}" class="btn btn-danger" title="{% trans 'Free session' %}" data-toggle="tooltip">
<a href="{% url 'abonapp:user_session_free' group.pk abon.username %}" class="btn btn-danger" title="{% trans 'Free session' %}" data-toggle="tooltip">
<span class="glyphicon glyphicon-remove"></span>
</a>
{% else %}
<a href="{% url 'abonapp:user_session_start' group.pk abon.username lease.pk %}" class="btn btn-success" title="{% trans 'Start session' %}" data-toggle="tooltip">
<span class="glyphicon glyphicon-flash"></span>
</a>
{% endif %}
{% if can_ping %}
<a href="{% url 'abonapp:ping' group.pk abon.username %}" class="btn btn-default btn-cmd" title="Ping" data-param="{{ lease.ip }}">
<b>{{ abon.ip_address }}</b>
{% if perms.abonapp.can_ping %}
<a href="{% url 'abonapp:ping' group.pk abon.username %}" class="btn btn-default btn-cmd" title="Ping" data-param="{{ abon.ip_address }}">
<span class="glyphicon glyphicon-flash"></span> Ping
</a>
{% else %}
@ -209,34 +198,26 @@
</a>
{% endif %}
</div>
<span{{ lease.is_active|yesno:', class="text-muted"'|safe }}>
<b>{{ lease }}</b>
<small>{% trans 'Leased by:' %} {{ lease.lease_time|date:'d-m H:i:s' }}.
{% if lease.mac_addr %}
{% trans 'From' %}: {{ lease.mac_addr }}.
{% else %}
<span class="text-info">{% trans 'No ip address' %}</span>
{% endif %}
</small>
</span>
</li>
{% empty %}
<li class="list-group-item">{% trans 'Leases does not found' %}</li>
{% endfor %}
{% endwith %}
</ul>
</div>
<div class="panel-footer">
<div class="btn-group btn-group-sm">
{% if abon.is_dynamic_ip %}
<a href="#" class="btn btn-success" disabled>
{% if abon.ip_address %}
<a href="#" class="btn btn-primary">
<span class="glyphicon glyphicon-edit"></span>
<span class="hidden-xs">{% trans 'Change' %}</span>
</a>
{% else %}
<a href="{% url 'abonapp:lease_add' group.pk abon.username %}" class="btn btn-success btn-modal">
{% endif %}
<a href="#" class="btn btn-success btn-modal">
<span class="glyphicon glyphicon-plus"></span>
<span class="hidden-xs">{% trans 'Add' %}</span>
</a>
{% endif %}
<a href="{% url 'abonapp:active_nets' group.pk %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-globe"></span>
<span class="hidden-sm hidden-xs">{% trans 'Active networks' %}</span>
<span class="hidden-sm hidden-xs">{% trans 'Networks' %}</span>
</a>
</div>
</div>

24
abonapp/templates/abonapp/modal_add_lease.html

@ -1,24 +0,0 @@
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %}
{% load i18n bootstrap3 %}
{% block content %}
<form role="form" action="{% url 'abonapp:lease_add' group.id uname %}" method="post"> {% csrf_token %}
<div class="modal-header primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title"><span class="glyphicon glyphicon-compressed"></span>{% trans 'Add ip lease' %}</h4>
</div>
<div class="modal-body">
{% bootstrap_form form %}
<div class="btn-group">
<button type="submit" class="btn btn-success">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %}
</button>
<button type="reset" class="btn btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Reset' %}
</button>
</div>
</div>
</form>
{% endblock %}

4
abonapp/urls.py

@ -26,12 +26,10 @@ subscriber_patterns = [
path('tel/add/', views.tel_add, name='telephone_new'),
path('tel/del/', views.tel_del, name='telephone_del'),
path('markers/', views.EditSibscriberMarkers.as_view(), name='markers_edit'),
path('session/<int:lease_id>/free/', views.user_session_toggle, {'action': 'free'}, name='user_session_free'),
path('session/<int:lease_id>/start/', views.user_session_toggle, {'action': 'start'}, name='user_session_start'),
path('session/free/', views.user_session_free, name='user_session_free'),
path('periodic_pay/', views.add_edit_periodic_pay, name='add_periodic_pay'),
path('periodic_pay/<int:periodic_pay_id>/', views.add_edit_periodic_pay, name='add_periodic_pay'),
path('periodic_pay/<int:periodic_pay_id>/del/', views.del_periodic_pay, name='del_periodic_pay'),
path('lease/add/', views.lease_add, name='lease_add'),
path('ping/', views.abon_ping, name='ping'),
path('set_auto_continue_service/', views.set_auto_continue_service, name='set_auto_continue_service')
]

155
abonapp/views.py

@ -1,4 +1,3 @@
from ipaddress import ip_address
from typing import Dict, Optional
from datetime import datetime, date
from django.core.exceptions import PermissionDenied, ValidationError
@ -6,6 +5,7 @@ from django.db import IntegrityError, ProgrammingError, transaction, Operational
from django.db.models import Count, Q
from django.shortcuts import render, redirect, get_object_or_404, resolve_url
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
from django.contrib import messages
from django.urls import reverse_lazy
@ -25,21 +25,22 @@ from taskapp.models import Task
from dialing_app.models import AsteriskCDR
from statistics.models import getModel
from group_app.models import Group
from ip_pool.models import IpLeaseModel, NetworkModel
from ip_pool.forms import LeaseForm
from ip_pool.models import NetworkModel
from guardian.shortcuts import get_objects_for_user, assign_perm
from guardian.decorators import permission_required_or_403 as permission_required
from guardian.mixins import PermissionRequiredMixin
from djing import ping
from djing import lib
from djing.lib.decorators import json_view, only_admins
from djing.lib.mixins import OnlyAdminsMixin
from djing.global_base_views import OrderedFilteredList, SecureApiView
login_decs = login_required, only_admins
class AbonappPermissionMixin(LoginRequiredMixin, OnlyAdminsMixin, PermissionRequiredMixin):
return_403 = True
@method_decorator(login_decs, name='dispatch')
class PeoplesListView(OrderedFilteredList):
class PeoplesListView(LoginRequiredMixin, OnlyAdminsMixin, OrderedFilteredList):
template_name = 'abonapp/peoples.html'
def get_queryset(self):
@ -77,8 +78,7 @@ class PeoplesListView(OrderedFilteredList):
return context
@method_decorator(login_decs, name='dispatch')
class GroupListView(OrderedFilteredList):
class GroupListView(LoginRequiredMixin, OnlyAdminsMixin, OrderedFilteredList):
context_object_name = 'groups'
template_name = 'abonapp/group_list.html'
queryset = Group.objects.annotate(usercount=Count('abon'))
@ -90,9 +90,8 @@ class GroupListView(OrderedFilteredList):
return queryset
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('abonapp.add_abon'), name='dispatch')
class AbonCreateView(CreateView):
class AbonCreateView(AbonappPermissionMixin, CreateView):
permission_required = 'abonapp.add_abon'
group = None
abon = None
form_class = forms.AbonForm
@ -146,9 +145,8 @@ class AbonCreateView(CreateView):
return super(AbonCreateView, self).form_invalid(form)
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('abonapp.delete_abon'), name='dispatch')
class DelAbonDeleteView(DeleteView):
class DelAbonDeleteView(AbonappPermissionMixin, DeleteView):
permission_required = 'abonapp.delete_abon'
model = models.Abon
slug_url_kwarg = 'uname'
slug_field = 'username'
@ -220,12 +218,14 @@ def abonamount(request, gid: int, uname):
})
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('group_app.view_group', (Group, 'pk', 'gid')), name='dispatch')
class DebtsListView(OrderedFilteredList):
class DebtsListView(AbonappPermissionMixin, OrderedFilteredList):
permission_required = 'group_app.view_group'
context_object_name = 'invoices'
template_name = 'abonapp/invoiceForPayment.html'
def get_permission_object(self):
return self.abon.group
def get_queryset(self):
abon = get_object_or_404(models.Abon, username=self.kwargs.get('uname'))
self.abon = abon
@ -238,12 +238,14 @@ class DebtsListView(OrderedFilteredList):
return context
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('group_app.view_group', (Group, 'pk', 'gid')), name='dispatch')
class PayHistoryListView(OrderedFilteredList):
class PayHistoryListView(AbonappPermissionMixin, OrderedFilteredList):
permission_required = 'group_app.view_group'
context_object_name = 'pay_history'
template_name = 'abonapp/payHistory.html'
def get_permission_object(self):
return self.abon.group
def get_queryset(self):
abon = get_object_or_404(models.Abon, username=self.kwargs.get('uname'))
self.abon = abon
@ -283,9 +285,8 @@ def abon_services(request, gid: int, uname):
})
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('abonapp.view_abon'), name='post')
class AbonHomeUpdateView(UpdateView):
class AbonHomeUpdateView(AbonappPermissionMixin, UpdateView):
permission_required = 'abonapp.view_abon'
model = models.Abon
form_class = forms.AbonForm
slug_field = 'username'
@ -469,9 +470,8 @@ def unsubscribe_service(request, gid: int, uname, abon_tariff_id: int):
return redirect('abonapp:abon_services', gid=gid, uname=uname)
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('abonapp.view_abonlog'), name='dispatch')
class LogListView(ListView):
class LogListView(AbonappPermissionMixin, ListView):
permission_required = 'abonapp.view_abonlog'
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
http_method_names = ('get',)
context_object_name = 'logs'
@ -479,9 +479,8 @@ class LogListView(ListView):
model = models.AbonLog
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('abonapp.view_invoiceforpayment'), name='dispatch')
class DebtorsListView(ListView):
class DebtorsListView(AbonappPermissionMixin, ListView):
permission_required = 'abonapp.view_invoiceforpayment'
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
http_method_names = ('get',)
context_object_name = 'invoices'
@ -489,14 +488,16 @@ class DebtorsListView(ListView):
queryset = models.InvoiceForPayment.objects.filter(status=True)
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('group_app.view_group', (Group, 'pk', 'gid')), name='dispatch')
class TaskLogListView(ListView):
class TaskLogListView(AbonappPermissionMixin, ListView):
permission_required = 'group_app.view_group'
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
http_method_names = ('get',)
context_object_name = 'tasks'
template_name = 'abonapp/task_log.html'
def get_permission_object(self):
return self.abon.group
def get_queryset(self):
abon = get_object_or_404(models.Abon, username=self.kwargs.get('uname'))
self.abon = abon
@ -509,9 +510,8 @@ class TaskLogListView(ListView):
return context
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('abonapp.view_passportinfo'), name='dispatch')
class PassportUpdateView(UpdateView):
class PassportUpdateView(AbonappPermissionMixin, UpdateView):
permission_required = 'abonapp.view_passportinfo'
form_class = forms.PassportForm
model = models.PassportInfo
template_name = 'abonapp/modal_passport_view.html'
@ -775,8 +775,7 @@ def vcards(r):
return response
@method_decorator(login_decs, name='dispatch')
class DialsListView(OrderedFilteredList):
class DialsListView(LoginRequiredMixin, OnlyAdminsMixin, OrderedFilteredList):
context_object_name = 'logs'
template_name = 'abonapp/dial_log.html'
@ -1106,9 +1105,8 @@ def del_periodic_pay(request, gid: int, uname, periodic_pay_id):
return redirect('abonapp:abon_services', gid, uname)
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('abonapp.change_abon'), name='dispatch')
class EditSibscriberMarkers(UpdateView):
class EditSibscriberMarkers(AbonappPermissionMixin, UpdateView):
permission_required = 'abonapp.change_abon'
http_method_names = ('get', 'post')
template_name = 'abonapp/modal_user_markers.html'
form_class = forms.MarkersForm
@ -1142,80 +1140,19 @@ class EditSibscriberMarkers(UpdateView):
@login_required
@only_admins
@permission_required('abonapp.change_abon')
def user_session_toggle(request, gid: int, uname, lease_id: int, action=None):
def user_session_free(request, gid: int, uname):
abon = get_object_or_404(models.Abon, username=uname)
if abon.nas is None:
messages.error(request, _('NAS required'))
return redirect('abonapp:abon_home', gid, uname)
lease = abon.ip_addresses.get(pk=lease_id)
tm = abon.nas.get_nas_manager()
try:
if action == 'free':
try:
abon_nas_obj = abon.build_agent_struct()
tm.lease_free(abon_nas_obj, ip_address(lease.ip))
if abon.ip_address:
abon.free_ip_addr()
messages.success(request, _('Ip lease has been freed'))
lease.free()
except lib.LogicError:
messages.error(request, _('You cannot disable last session'))
elif action == 'start':
lease.start()
abon_nas_obj = abon.build_agent_struct()
tm.lease_start(abon_nas_obj, ip_address(lease.ip))
messages.success(request, _('Ip lease has been started'))
else:
messages.error(request, _('Unexpected action'))
except (NasFailedResult, lib.LogicError) as e:
messages.error(request, e)
messages.error(request, _('User not have ip'))
return redirect('abonapp:abon_home', gid, uname)
@login_required
@only_admins
@permission_required('abonapp.change_abon')
def lease_add(request, gid: int, uname):
group = get_object_or_404(Group, pk=gid)
if request.method == 'POST':
frm = LeaseForm(request.POST)
if frm.is_valid():
try:
abon = get_object_or_404(models.Abon, username=uname)
cleaned = frm.clean()
ip = cleaned.get('ip_addr')
is_dynamic = cleaned.get('is_dynamic')
network_id = cleaned.get('possible_networks') # str(int)
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)
if abon.nas is None:
messages.error(request, _('NAS required'))
else:
tm = abon.nas.get_nas_manager()
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:
messages.error(request, e)
else:
messages.error(request, _('Check form errors'))
else:
first_network = NetworkModel.objects.filter(groups=group).first()
if first_network is not None:
free_ip = IpLeaseModel.objects.get_free_ip(first_network)
initial = {'ip_addr': free_ip}
else:
initial = None
frm = LeaseForm(initial=initial)
return render(request, 'abonapp/modal_add_lease.html', {
'form': frm,
'group': group,
'uname': uname
})
@login_required
@only_admins
@permission_required('abonapp.change_abon')
@ -1247,9 +1184,8 @@ def abons(request):
ablist = ({
'id': abn.pk,
'tarif_id': abn.active_tariff().tariff.pk if abn.active_tariff() is not None else 0,
'ips': ','.join(str(i.ip) for i in abn.ip_addresses.filter(is_active=True)),
'is_active': abn.is_active
} for abn in models.Abon.objects.all())
'ip': abn.ip_address
} for abn in models.Abon.objects.iterator())
tarlist = ({
'id': trf.pk,
@ -1285,10 +1221,13 @@ class DhcpLever(SecureApiView):
@method_decorator(json_view)
def get(self, request, *args, **kwargs):
data = request.GET.copy()
try:
r = self.on_dhcp_event(data)
if r is not None:
return {'text': r}
return {'status': 'ok'}
except IntegrityError as e:
return {'status': str(e).replace('\n', ' ')}
@staticmethod
def on_dhcp_event(data: Dict) -> Optional[str]:

6
accounts_app/templatetags/acc_tags.py

@ -3,7 +3,7 @@ from ipaddress import ip_address, AddressValueError
from django import template
from django.db.models import Model
from django.apps import apps
from ip_pool.models import IpLeaseModel
from abonapp.models import Abon
from six import string_types, class_types
register = template.Library()
@ -26,8 +26,8 @@ def can_login_by_location(request):
try:
remote_ip = ip_address(request.META.get('REMOTE_ADDR'))
if remote_ip.version == 4:
has_leases = IpLeaseModel.objects.filter(ip=str(remote_ip), abon__is_active=True).exists()
return has_leases
has_exist = Abon.objects.filter(ip_address=str(remote_ip), is_active=True).exists()
return has_exist
except AddressValueError:
pass
return False

27
agent/commands/dhcp.py

@ -2,7 +2,6 @@ from typing import Optional
from django.core.exceptions import MultipleObjectsReturned
from abonapp.models import Abon
from devapp.models import Device, Port
from ip_pool.models import IpLeaseModel
def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: int) -> Optional[str]:
@ -13,22 +12,17 @@ def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: i
if mngr_class.get_is_use_device_port():
abon = Abon.objects.get(dev_port__device=dev,
dev_port__num=switch_port,
device=dev)
device=dev, is_active=True)
else:
abon = Abon.objects.get(device=dev)
abon = Abon.objects.get(device=dev, is_active=True)
if not abon.is_dynamic_ip:
return 'User settings is not dynamic'
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:
abon.attach_ip_addr(client_ip, strict=False)
if abon.is_access():
abon.nas_sync_self()
r = abon.nas_sync_self()
return r if r else None
else:
return 'User %s is not access to service' % abon.username
else:
return add_lease_result
except Abon.DoesNotExist:
return "User with device with mac '%s' does not exist" % switch_mac
except Device.DoesNotExist:
@ -43,16 +37,13 @@ def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: i
def dhcp_expiry(client_ip: str) -> Optional[str]:
try:
lease = IpLeaseModel.objects.get(ip=client_ip)
lease.is_active = False
lease.save(update_fields=('is_active',))
abon = Abon.objects.filter(ip_addresses=lease).first()
abon = Abon.objects.filter(ip_address=client_ip, is_active=True).exclude(current_tariff=None).first()
if abon is None:
return "Subscriber with ip %s does not exist" % client_ip
else:
is_freed = abon.free_ip_addr()
if is_freed:
abon.nas_sync_self()
except IpLeaseModel.DoesNotExist:
pass
def dhcp_release(client_ip: str) -> Optional[str]:

8
djing/lib/auth_backends.py

@ -3,7 +3,6 @@ from ipaddress import ip_address, AddressValueError
from django.contrib.auth.backends import ModelBackend
from accounts_app.models import BaseAccount, UserProfile
from abonapp.models import Abon
from ip_pool.models import IpLeaseModel
class CustomAuthBackend(ModelBackend):
@ -40,13 +39,12 @@ class LocationAuthBackend(ModelBackend):
def authenticate(self, request, byip, **kwargs):
try:
remote_ip = ip_address(request.META.get('REMOTE_ADDR'))
lease = IpLeaseModel.objects.filter(ip=str(remote_ip), abon__is_active=True).first()
if lease is None:
user = Abon.objects.filter(ip_address=str(remote_ip), is_active=True).first()
if user is None:
return
user = Abon.objects.get(ip_addresses=lease)
if self.user_can_authenticate(user):
return user
except (AddressValueError, Abon.DoesNotExist):
except AddressValueError:
return
def get_user(self, user_id):

9
djing/lib/mixins.py

@ -0,0 +1,9 @@
from django.contrib.auth.mixins import AccessMixin
class OnlyAdminsMixin(AccessMixin):
"""Verify that the current user is admin."""
def dispatch(self, request, *args, **kwargs):
if not request.user.is_admin:
return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs)

1
ip_pool/admin.py

@ -2,4 +2,3 @@ from django.contrib import admin
from ip_pool import models
admin.site.register(models.NetworkModel)
admin.site.register(models.IpLeaseModel)

33
ip_pool/forms.py

@ -1,14 +1,12 @@
from ipaddress import ip_network, ip_address
from ipaddress import ip_network
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from ip_pool import models
class NetworkForm(forms.ModelForm):
def clean_network(self):
netw = self.data.get('network')
if netw is None:
@ -22,32 +20,3 @@ class NetworkForm(forms.ModelForm):
class Meta:
model = models.NetworkModel
fields = '__all__'
class LeaseForm(forms.Form):
def __init__(self, data=None, *args, **kwargs):
super(LeaseForm, self).__init__(data=data, *args, **kwargs)
nets = models.NetworkModel.objects.defer('groups')
if nets.exists():
self.fields['possible_networks'].choices = ((net.pk, str(net.get_network())) for net in nets.iterator())
def clean_ip_addr(self):
ip_addr = self.data.get('ip_addr')
if ip_addr is None:
return
ip_addr = ip_address(ip_addr)
net_id = self.data.get('possible_networks')
if net_id is None:
return ip_addr.compressed
net = models.NetworkModel.objects.get(pk=net_id)
if ip_addr not in net.get_network():
raise ValidationError(_('Ip that you typed is not in subnet that you have selected'))
if ip_addr < ip_address(net.ip_start):
raise ValidationError(_('Ip that you have passed is less than allowed network range'))
if ip_addr > ip_address(net.ip_end):
raise ValidationError(_('Ip that you have passed is greater than allowed network range'))
return ip_addr.compressed
ip_addr = forms.GenericIPAddressField(label=_('Ip address'))
is_dynamic = forms.BooleanField(label=_('Is dynamic'), required=False)
possible_networks = forms.ChoiceField(label=_('Possible networks'))

37
ip_pool/migrations/0003_add_leases_history_model.py

@ -0,0 +1,37 @@
# Generated by Django 2.1 on 2018-10-11 11:55
from django.db import migrations, models
import djing.fields
class Migration(migrations.Migration):
dependencies = [
('ip_pool', '0002_change_unique'),
]
operations = [
migrations.CreateModel(
name='LeasesHistory',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip', models.GenericIPAddressField(verbose_name='Ip address')),
('lease_time', models.DateTimeField(auto_now_add=True, verbose_name='Lease time')),
('mac_addr', djing.fields.MACAddressField(blank=True, integer=True, null=True, verbose_name='Mac address')),
],
options={
'verbose_name': 'History lease',
'verbose_name_plural': 'Leases history',
'db_table': 'ip_pool_leases_history',
'ordering': ('-lease_time',),
},
),
migrations.RemoveField(
model_name='ipleasemodel',
name='is_active',
),
migrations.RemoveField(
model_name='ipleasemodel',
name='is_dynamic',
),
]

31
ip_pool/models.py

@ -145,7 +145,6 @@ class IpLeaseManager(models.Manager):
ip=ip,
network=net,
is_dynamic=is_dynamic,
is_active=True,
mac_addr=mac
)
except IntegrityError as e:
@ -159,14 +158,13 @@ class IpLeaseManager(models.Manager):
return self.filter(lease_time__lt=senility)
# Deprecated. Remove after migrations squashed
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'), null=True, blank=True)
mac_addr = MACAddressField(verbose_name=_('Mac address'), null=True, blank=True)
lease_time = models.DateTimeField(_('Lease time'), auto_now_add=True)
is_dynamic = models.BooleanField(_('Is dynamic'), default=False)
is_active = models.BooleanField(_('Is active'), default=True)
device_info = models.CharField(null=True, blank=True, default=None, max_length=128)
objects = IpLeaseManager()
@ -174,16 +172,6 @@ class IpLeaseModel(models.Model):
def __str__(self):
return self.ip
def free(self):
if self.is_active:
self.is_active = False
self.save(update_fields=('is_active',))
def start(self):
if not self.is_active:
self.is_active = True
self.save(update_fields=('is_active',))
def clean(self):
ip = ip_address(self.ip)
network = self.network.get_network()
@ -201,7 +189,16 @@ class IpLeaseModel(models.Model):
unique_together = ('ip', 'network', 'mac_addr')
# class LeasesHistory(models.Model):
# ip = models.GenericIPAddressField(verbose_name=_('Ip address'))
# lease_time = models.DateTimeField(_('Lease time'), auto_now_add=True)
# mac_addr = MACAddressField(_('Mac address'), null=True, blank=True)
class LeasesHistory(models.Model):
ip = models.GenericIPAddressField(verbose_name=_('Ip address'))
lease_time = models.DateTimeField(_('Lease time'), auto_now_add=True)
mac_addr = MACAddressField(_('Mac address'), null=True, blank=True)
def __str__(self):
return self.ip
class Meta:
db_table = 'ip_pool_leases_history'
verbose_name = _('History lease')
verbose_name_plural = _('Leases history')
ordering = '-lease_time',

44
ip_pool/templates/ip_pool/ip_leases_list.html

@ -1,44 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block breadcrumb %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'ip_pool:networks' %}">{% trans 'Ip pool' %}</a></li>
<li><a href="{% url 'ip_pool:net_edit' net.id %}">{{ net }}</a></li>
<li class="active">{% trans 'Ip leases list' %}</li>
</ol>
{% endblock %}
{% block page-header %}
{% trans 'Ip leases list' %}
{% endblock %}
{% block main %}
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th class="col-sm-5">{% trans 'Ip' %}</th>
<th class="col-sm-3">{% trans 'Lease time' %}</th>
<th class="col-sm-3">{% trans 'Network' %}</th>
<th class="col-sm-1">{% trans 'Is dynamic' %}</th>
</tr>
</thead>
<tbody>
{% for ip in object_list %}
<tr>
<td>{{ ip.ip }}</td>
<td>{{ ip.lease_time|date:'j:n H:i:s' }}</td>
<td>{{ ip.get_network }}</td>
<td><input type="checkbox" {{ ip.is_dynamic|yesno:'checked,' }}></td>
</tr>
{% empty %}
<tr>
<td colspan="4">{% trans 'You have not any available dedicated ips in this network' %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}

4
ip_pool/templates/ip_pool/net_edit.html

@ -38,10 +38,6 @@
<a href="{% back_url request %}" class="btn btn-default">
<span class="glyphicon glyphicon-backward"></span> {% trans 'Back' %}
</a>
<a href="{% url 'ip_pool:ip_leases_list' object.pk %}" class="btn btn-default">
<span class="glyphicon glyphicon-eye-open"></span>
<span class="hidden-xs hidden-sm">{% trans 'View employed' %}</span>
</a>
<a href="{% url 'ip_pool:net_groups' object.pk %}" class="btn btn-default">
<span class="glyphicon glyphicon-user"></span>
<span class="hidden-xs hidden-sm">{% trans 'Groups available' %}</span>

6
ip_pool/templates/ip_pool/network_list.html

@ -28,7 +28,7 @@
{% with can_ch_net=perms.ip_pool.change_networkmodel can_del_net=perms.ip_poo.delete_networkmodel %}
{% for netw in networks_list %}
<tr>
<td><a href="{% url 'ip_pool:ip_leases_list' netw.id %}">{{ netw.get_network }}</a></td>
<td>{{ netw.get_network }}</td>
<td>{{ netw.get_kind_display }}</td>
<td>{{ netw.description }}</td>
<td>{{ netw.get_scope }}</td>
@ -55,10 +55,6 @@
<span class="hidden-xs hidden-sm">{% trans 'Permission denied' %}</span>
</a>
{% endif %}
<a href="{% url 'ip_pool:ip_leases_list' netw.pk %}" class="btn btn-default">
<span class="glyphicon glyphicon-eye-open"></span>
<span class="hidden-xs hidden-sm">{% trans 'View employed' %}</span>
</a>
</td>
</tr>
{% empty %}

1
ip_pool/urls.py

@ -7,7 +7,6 @@ app_name = 'ip_pool'
urlpatterns = [
path('', views.NetworksListView.as_view(), name='networks'),
path('network_add/', views.NetworkCreateView.as_view(), name='net_add'),
path('<int:net_id>/', views.IpLeasesListView.as_view(), name='ip_leases_list'),
path('<int:net_id>/edit/', views.NetworkUpdateView.as_view(), name='net_edit'),
path('<int:net_id>/del/', views.NetworkDeleteView.as_view(), name='net_delete'),
path('<int:net_id>/group_attach/', views.network_in_groups, name='net_groups')

17
ip_pool/views.py

@ -57,23 +57,6 @@ class NetworkDeleteView(DeleteView):
return super(NetworkDeleteView, self).delete(request, *args, **kwargs)
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('ip_pool.view_ipleasemodel'), name='dispatch')
class IpLeasesListView(OrderedFilteredList):
template_name = 'ip_pool/ip_leases_list.html'
model = models.IpLeaseModel
def get_context_data(self, **kwargs):
net_id = self.kwargs.get('net_id')
context = super().get_context_data(**kwargs)
context['net'] = get_object_or_404(models.NetworkModel, pk=net_id)
return context
def get_queryset(self):
net_id = self.kwargs.get('net_id')
return self.model.objects.filter(network__id=net_id)
@method_decorator(login_decs, name='dispatch')
@method_decorator(permission_required('ip_pool.add_networkmodel'), name='dispatch')
class NetworkCreateView(CreateView):

36
nas_app/nas_managers/core.py

@ -108,30 +108,30 @@ class BaseTransmitter(ABC):
def read_users(self) -> VectorAbon:
pass
@abstractmethod
def lease_free(self, user: AbonStruct, lease):
"""
Remove ip lease from allowed to network
:param lease: ip_address for lease
:param user: Subscriber instance
:return:
"""
@abstractmethod
def lease_start(self, user: AbonStruct, lease):
"""
Starts ip lease to allowed to network
:param lease: ip_address for lease
:param user: Subscriber instance
:return:
"""
# @abstractmethod
# def lease_free(self, user: AbonStruct, lease):
# """
# Remove ip lease from allowed to network
# :param lease: ip_address for lease
# :param user: Subscriber instance
# :return:
# """
#
# @abstractmethod
# def lease_start(self, user: AbonStruct, lease):
# """
# Starts ip lease to allowed to network
# :param lease: ip_address for lease
# :param user: Subscriber instance
# :return:
# """
def _diff_users(self, users_from_db: Iterator[Any]) -> Tuple[set, set]:
"""
:param users_from_db: QuerySet of all subscribers that can have service
:return: Tuple of 2 lists that contain list to add users and list to remove users
"""
users_struct_gen = (ab.build_agent_struct(raise_errs=False) for ab in users_from_db if
users_struct_gen = (ab.build_agent_struct() for ab in users_from_db if
ab is not None and ab.is_access())
users_struct_set = set(ab for ab in users_struct_gen if ab is not None and ab.tariff is not None)
users_from_nas = set(self.read_users())

66
nas_app/nas_managers/mod_mikrotik.py

@ -228,17 +228,20 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
disabled = info.get('=disabled', False)
if disabled is not None:
disabled = True if disabled == 'true' else False
if target is not None and name is not None:
if target and name:
# target may be '192.168.0.3/32,192.168.0.2/32'
ips = (ip.split('/')[0] for ip in target.split(','))
ip = target.split(',')[0]
if not ip:
return
ip, mask_bits = ip.split('/')
if not ip:
return
a = AbonStruct(
uid=int(name[3:]),
ips=ips,
ip=ip,
tariff=t,
is_access=not disabled
)
if len(a.ips) < 1:
return
a.queue_id = info.get('=.id')
return a
except ValueError as e:
@ -259,12 +262,11 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
raise TypeError
if user.tariff is None or not isinstance(user.tariff, TariffStruct):
return
ips = ','.join(str(i) for i in user.ips)
self._exec_cmd((
'/queue/simple/add',
'=name=uid%d' % user.uid,
# FIXME: тут в разных микротиках или =target-addresses или =target
'=target=%s' % ips,
'=target=%s' % user.ip,
'=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
'=queue=Djing_SFQ/Djing_SFQ',
'=burst-time=1/1'
@ -302,7 +304,7 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
'=name=uid%d' % user.uid,
'=max-limit=%.3fM/%.3fM' % (user.tariff.speedOut, user.tariff.speedIn),
# FIXME: тут в разных версиях прошивки микротика или =target-addresses или =target
'=target=%s' % ','.join(str(i) for i in user.ips),
'=target=%s' % user.ip,
'=queue=Djing_SFQ/Djing_SFQ',
'=burst-time=1/1'
]
@ -377,8 +379,7 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
self.remove_queue_range(queue_ids)
for user in users:
if isinstance(user, AbonStruct):
for ip in user.ips:
ip_list_entity = self.find_ip(ip, LIST_USERS_ALLOWED)
ip_list_entity = self.find_ip(user.ip, LIST_USERS_ALLOWED)
if ip_list_entity:
self.remove_ip(ip_list_entity.get('=.id'))
@ -391,7 +392,7 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
self.add_queue(user)
except NasFailedResult as e:
print('Error:', e)
for ip in user.ips:
ip = user.ip
if not issubclass(ip.__class__, _BaseAddress):
raise TypeError
try:
@ -401,19 +402,15 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
def remove_user(self, user: AbonStruct):
self.remove_queue(user)
def _finder(ips):
for ip in ips:
r = self.find_ip(ip, LIST_USERS_ALLOWED)
if r: yield r.get('=.id')
firewall_ip_list_ids = _finder(user.ips)
self.remove_ip_range(firewall_ip_list_ids)
r = self.find_ip(user.ip, LIST_USERS_ALLOWED)
ip_id = r.get('=.id')
self.remove_ip(ip_id)
def update_user(self, user: AbonStruct, *args):
# queue is instance of AbonStruct
queue = self.find_queue('uid%d' % user.uid)
for ip in user.ips:
ip = user.ip
if not issubclass(ip.__class__, _BaseAddress):
raise TypeError
nas_ip = self.find_ip(ip, LIST_USERS_ALLOWED)
@ -481,32 +478,3 @@ class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs
all_ips = set(ip for ip, mkid in self.read_ips_iter(LIST_USERS_ALLOWED))
queues = (q for q in self.read_queue_iter() if all_ips.issuperset(q.ips))
return queues
def lease_free(self, user: AbonStruct, lease):
queue = self.find_queue('uid%d' % user.uid)
if queue is None:
return
if len(queue.ips) > 1:
if queue is not None:
user.ips = tuple(i for i in user.ips if i != lease)
self.update_queue(user, queue)
ip = self.find_ip(lease, LIST_USERS_ALLOWED)
if ip is not None:
self.remove_ip(ip.get('=.id'))
else:
raise NasFailedResult(_('You cannot disable last session'))
def lease_start(self, user: AbonStruct, lease):
if not issubclass(lease.__class__, _BaseAddress):
lease = ip_address(lease)
if not isinstance(user, AbonStruct):
raise TypeError
ip = self.find_ip(lease, LIST_USERS_ALLOWED)
if ip is None:
self.add_ip(LIST_USERS_ALLOWED, lease)
queue = self.find_queue('uid%d' % user.uid)
user.ips += lease,
if queue is None:
self.add_queue(user)
else:
self.update_queue(user, queue)

30
nas_app/nas_managers/structs.py

@ -1,5 +1,5 @@
from abc import ABCMeta
from ipaddress import ip_address
from ipaddress import ip_address, _BaseAddress
from typing import Iterable
@ -36,38 +36,38 @@ class TariffStruct(BaseStruct):
# Abon from database
class AbonStruct(BaseStruct):
__slots__ = ('uid', '_ips', 'tariff', 'is_access', 'queue_id')
__slots__ = ('uid', '_ip', 'tariff', 'is_access', 'queue_id')
def __init__(self, uid=0, ips=None, tariff=None, is_access=True):
def __init__(self, uid=0, ip=None, tariff=None, is_access=True):
self.uid = int(uid or 0)
if ips is None:
self._ips = ()
else:
self._ips = tuple(ip_address(ip) for ip in ips)
self._ip = ip
self.tariff = tariff
self.is_access = is_access
self.queue_id = 0
def get_ips(self):
return self._ips
def get_ip(self):
return self._ip
def set_ips(self, v):
self._ips = set(v)
def set_ip(self, v):
if issubclass(v.__class__, _BaseAddress):
self._ip = v
else:
self._ip = ip_address(v)
ips = property(get_ips, set_ips, doc='Ip addresses')
ip = property(get_ip, set_ip, doc='Ip address')
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._ip == other._ip
r = r and self.tariff == other.tariff
return r
def __str__(self):
return "uid=%d, ips=[%s], tariff=%s" % (self.uid, ';'.join(str(i) for i in self._ips), self.tariff or '<No Service>')
return "uid=%d, ip=[%s], tariff=%s" % (self.uid, self._ip, self.tariff or '<No Service>')
def __hash__(self):
return hash(hash(self._ips) + hash(self.tariff) if self.tariff is not None else 0)
return hash(hash(self._ip) + hash(self.tariff) if self.tariff is not None else 0)
VectorAbon = Iterable[AbonStruct]

10
periodic.py

@ -9,7 +9,6 @@ from django.utils import timezone
from django.db import transaction
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 nas_app.nas_managers import NasNetworkError, NasFailedResult
from nas_app.models import NASModel
from djing.lib import LogicError
@ -24,10 +23,8 @@ class NasSyncThread(Thread):
try:
tm = self.nas.get_nas_manager()
users = Abon.objects \
.annotate(ips_count=Count('ip_addresses')) \
.filter(is_active=True, ips_count__gt=0, nas=self.nas) \
.exclude(current_tariff=None) \
.prefetch_related('ip_addresses') \
.filter(is_active=True, nas=self.nas) \
.exclude(current_tariff=None, ip_address=None) \
.iterator()
tm.sync_nas(users)
except NasNetworkError as er:
@ -102,9 +99,6 @@ def main():
for pay in ppays:
pay.payment_for_service(now=now)
# Remove old inactive ip leases
IpLeaseModel.objects.expired().filter(is_active=False).delete()
# sync subscribers on NAS
threads = tuple(NasSyncThread(nas) for nas in NASModel.objects.
annotate(usercount=Count('abon')).

2
searchapp/views.py

@ -21,7 +21,7 @@ def home(request):
if s:
if re.match(IP_ADDR_REGEX, s):
abons = Abon.objects.filter(ip_addresses__ip=s)
abons = Abon.objects.filter(ip_address=s)
devices = Device.objects.filter(ip_address=s)
else:
abons = Abon.objects.filter(

Loading…
Cancel
Save