Browse Source

Merge branch 'devel' into messanger

devel
Dmitry Novikov 7 years ago
parent
commit
044b154c18
  1. 45
      abonapp/models.py
  2. 47
      abonapp/tasks.py
  3. 2
      abonapp/templates/abonapp/payHistory.html
  4. 29
      abonapp/views.py
  5. 5
      accounts_app/views.py
  6. 3
      clientsideapp/views.py
  7. 7
      devapp/views.py
  8. 2
      djing/lib/decorators.py
  9. 5
      gw_app/nas_managers/core.py
  10. 9
      gw_app/nas_managers/mod_mikrotik.py
  11. 4
      gw_app/nas_managers/structs.py
  12. 7
      periodic.py
  13. 5
      requirements.txt

45
abonapp/models.py

@ -7,7 +7,7 @@ from django.conf import settings
from django.core import validators from django.core import validators
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.db import models, connection, transaction from django.db import models, connection, transaction
from django.db.models.signals import post_delete, pre_delete, post_init, \
from django.db.models.signals import pre_delete, post_init, \
pre_save pre_save
from django.dispatch import receiver from django.dispatch import receiver
from django.shortcuts import resolve_url from django.shortcuts import resolve_url
@ -348,24 +348,6 @@ class Abon(BaseAccount):
except LogicError: except LogicError:
pass pass
def nas_remove_self(self):
"""
Will remove this user to network access server
:return:
"""
if self.nas is None:
raise LogicError(_('gateway required'))
try:
agent_abon = self.build_agent_struct()
if agent_abon is not None:
mngr = self.nas.get_nas_manager()
mngr.remove_user(agent_abon)
except (NasFailedResult, NasNetworkError, ConnectionResetError) as e:
print('ERROR:', e)
return e
except LogicError:
pass
def get_absolute_url(self): def get_absolute_url(self):
return resolve_url('abonapp:abon_home', self.group.id, self.username) return resolve_url('abonapp:abon_home', self.group.id, self.username)
@ -608,17 +590,6 @@ class PeriodicPayForId(models.Model):
ordering = ('last_pay',) ordering = ('last_pay',)
@receiver(post_delete, sender=Abon)
def abon_del_signal(sender, **kwargs):
abon = kwargs.get("instance")
if abon is None:
raise ValueError('Instance does not passed to a signal')
try:
abon.nas_remove_self()
except (NasFailedResult, NasNetworkError, LogicError):
return True
@receiver(post_init, sender=AbonTariff) @receiver(post_init, sender=AbonTariff)
def abon_tariff_post_init(sender, **kwargs): def abon_tariff_post_init(sender, **kwargs):
abon_tariff = kwargs["instance"] abon_tariff = kwargs["instance"]
@ -635,17 +606,3 @@ def abon_tariff_pre_save(sender, **kwargs):
if getattr(abon_tariff, 'deadline') is None: if getattr(abon_tariff, 'deadline') is None:
calc_obj = abon_tariff.tariff.get_calc_type()(abon_tariff) calc_obj = abon_tariff.tariff.get_calc_type()(abon_tariff)
abon_tariff.deadline = calc_obj.calc_deadline() abon_tariff.deadline = calc_obj.calc_deadline()
@receiver(pre_delete, sender=AbonTariff)
def abontariff_pre_delete(sender, **kwargs):
abon_tariff = kwargs.get("instance")
if abon_tariff is None:
raise ValueError('Instance does not passed to a signal')
try:
abon = Abon.objects.get(current_tariff=abon_tariff)
abon.nas_remove_self()
except (NasFailedResult, NasNetworkError, LogicError):
return True
except Abon.DoesNotExist:
print('Error: abontariff_pre_delete - user not found')

47
abonapp/tasks.py

@ -0,0 +1,47 @@
from celery import shared_task
from abonapp.models import Abon
from djing.lib import LogicError
from gw_app.models import NASModel
from gw_app.nas_managers import NasFailedResult, NasNetworkError, SubnetQueue
@shared_task
def customer_nas_command(customer_uid: int, command: str):
if command not in ('add', 'sync'):
return 'Command required'
try:
cust = Abon.objects.get(pk=customer_uid)
print(cust, command)
if command == 'sync':
r = cust.nas_sync_self()
if isinstance(r, Exception):
return 'ABONAPP SYNC ERROR: %s' % r
elif command == 'add':
cust.nas_add_self()
else:
return 'ABONAPP SYNC ERROR: Unknown command "%s"' % command
except Abon.DoesNotExist:
pass
except (LogicError, NasFailedResult, NasNetworkError, ConnectionResetError) as e:
return 'ABONAPP ERROR: %s' % e
@shared_task
def customer_nas_remove(customer_uid: int, ip_addr: str, speed: tuple, is_access: bool, nas_pk: int):
try:
if not isinstance(ip_addr, (str, int)):
ip_addr = str(ip_addr)
sq = SubnetQueue(
name="uid%d" % customer_uid,
network=ip_addr,
max_limit=speed,
is_access=is_access
)
nas = NASModel.objects.get(pk=nas_pk)
mngr = nas.get_nas_manager()
mngr.remove_user(sq)
except (ValueError, NasFailedResult, NasNetworkError, LogicError) as e:
return 'ABONAPP ERROR: %s' % e
except NASModel.DoesNotExist:
return 'NASModel.DoesNotExist id=%d' % nas_pk

2
abonapp/templates/abonapp/payHistory.html

@ -14,7 +14,7 @@
<tbody> <tbody>
{% for ph in pay_history %} {% for ph in pay_history %}
<tr> <tr>
<td>{{ ph.amount }}</td>
<td>{{ ph.amount|floatformat:2 }}</td>
<td>{{ ph.date|date:'d F Y, H:i:s' }}</td> <td>{{ ph.date|date:'d F Y, H:i:s' }}</td>
<td> <td>
{% if ph.author %} {% if ph.author %}

29
abonapp/views.py

@ -1,6 +1,7 @@
from datetime import datetime from datetime import datetime
from typing import Dict, Optional from typing import Dict, Optional
from abonapp.tasks import customer_nas_command, customer_nas_remove
from agent.commands.dhcp import dhcp_commit, dhcp_expiry, dhcp_release from agent.commands.dhcp import dhcp_commit, dhcp_expiry, dhcp_release
from devapp.models import Device, Port as DevPort from devapp.models import Device, Port as DevPort
from dialing_app.models import AsteriskCDR from dialing_app.models import AsteriskCDR
@ -172,6 +173,13 @@ class DelAbonDeleteView(LoginAdminMixin, PermissionRequiredMixin, DeleteView):
try: try:
abon = self.get_object() abon = self.get_object()
gid = abon.group.id gid = abon.group.id
if abon.current_tariff:
abon_tariff = abon.current_tariff.tariff
customer_nas_remove.delay(
customer_uid=abon.pk, ip_addr=abon.ip_address,
speed=(abon_tariff.speedIn, abon_tariff.speedOut),
is_access=abon.is_access(), nas_pk=abon.nas_id
)
abon.delete() abon.delete()
request.user.log(request.META, 'dusr', ( request.user.log(request.META, 'dusr', (
'%(uname)s, "%(fio)s", %(group)s %(street)s %(house)s' % { '%(uname)s, "%(fio)s", %(group)s %(street)s %(house)s' % {
@ -336,9 +344,7 @@ class AbonHomeUpdateView(LoginAdminMixin, PermissionRequiredMixin, UpdateView):
def form_valid(self, form): def form_valid(self, form):
r = super(AbonHomeUpdateView, self).form_valid(form) r = super(AbonHomeUpdateView, self).form_valid(form)
abon = self.object abon = self.object
res = abon.nas_sync_self()
if isinstance(res, Exception):
messages.warning(self.request, res)
customer_nas_command.delay(abon.pk, 'sync')
messages.success(self.request, _('edit abon success msg')) messages.success(self.request, _('edit abon success msg'))
return r return r
@ -450,11 +456,8 @@ def pick_tariff(request, gid: int, uname):
comment=log_comment) comment=log_comment)
else: else:
abon.pick_tariff(trf, request.user, comment=log_comment) abon.pick_tariff(trf, request.user, comment=log_comment)
r = abon.nas_sync_self()
if r is None:
customer_nas_command.delay(abon.pk, 'sync')
messages.success(request, _('Tariff has been picked')) messages.success(request, _('Tariff has been picked'))
else:
messages.error(request, r)
return redirect('abonapp:abon_services', gid=gid, return redirect('abonapp:abon_services', gid=gid,
uname=abon.username) uname=abon.username)
except (lib.LogicError, NasFailedResult) as e: except (lib.LogicError, NasFailedResult) as e:
@ -489,6 +492,13 @@ def unsubscribe_service(request, gid: int, uname, abon_tariff_id: int):
try: try:
abon_tariff = get_object_or_404(models.AbonTariff, abon_tariff = get_object_or_404(models.AbonTariff,
pk=int(abon_tariff_id)) pk=int(abon_tariff_id))
abon = abon_tariff.abon
trf = abon_tariff.tariff
customer_nas_remove.delay(
customer_uid=abon.pk, ip_addr=abon.ip_address,
speed=(trf.speedIn, trf.speedOut),
is_access=abon.is_access(), nas_pk=abon.nas_id
)
abon_tariff.delete() abon_tariff.delete()
messages.success(request, _('User has been detached from service')) messages.success(request, _('User has been detached from service'))
except NasFailedResult as e: except NasFailedResult as e:
@ -610,9 +620,7 @@ class IpUpdateView(LoginAdminPermissionMixin, UpdateView):
def form_valid(self, form): def form_valid(self, form):
r = super(IpUpdateView, self).form_valid(form) r = super(IpUpdateView, self).form_valid(form)
abon = self.object abon = self.object
res = abon.nas_sync_self()
if isinstance(res, Exception):
messages.warning(self.request, res)
customer_nas_command.delay(abon.pk, 'sync')
messages.success(self.request, _('Ip successfully updated')) messages.success(self.request, _('Ip successfully updated'))
return r return r
@ -1219,6 +1227,7 @@ def user_session_free(request, gid: int, uname):
return redirect('abonapp:abon_home', gid, uname) return redirect('abonapp:abon_home', gid, uname)
if abon.ip_address: if abon.ip_address:
abon.free_ip_addr() abon.free_ip_addr()
customer_nas_command.delay(abon.pk, 'remove')
messages.success(request, _('Ip lease has been freed')) messages.success(request, _('Ip lease has been freed'))
else: else:
messages.error(request, _('User not have ip')) messages.error(request, _('User not have ip'))

5
accounts_app/views.py

@ -28,9 +28,8 @@ class CustomLoginView(LoginView):
template_name = 'accounts/login.html' template_name = 'accounts/login.html'
def form_invalid(self, form): def form_invalid(self, form):
login_localed = gettext('profile username')
for msg in form.error_messages.values():
messages.error(self.request, msg % {'username': login_localed})
for msg in form.non_field_errors():
messages.error(self.request, msg)
return super().form_invalid(form) return super().form_invalid(form)
def get_success_url(self): def get_success_url(self):

3
clientsideapp/views.py

@ -5,6 +5,7 @@ from django.db import transaction
from django.utils.translation import gettext_lazy as _, gettext from django.utils.translation import gettext_lazy as _, gettext
from abonapp.models import AbonLog, InvoiceForPayment, Abon from abonapp.models import AbonLog, InvoiceForPayment, Abon
from abonapp.tasks import customer_nas_command
from djing.lib.decorators import json_view from djing.lib.decorators import json_view
from tariff_app.models import Tariff from tariff_app.models import Tariff
from taskapp.models import Task from taskapp.models import Task
@ -52,7 +53,7 @@ def buy_service(request, srv_id):
if request.method == 'POST': if request.method == 'POST':
abon.pick_tariff(service, None, _("Buy the service via user side, service '%s'") abon.pick_tariff(service, None, _("Buy the service via user side, service '%s'")
% service) % service)
abon.nas_sync_self()
customer_nas_command.delay(abon.pk, 'sync')
messages.success(request, _("The service '%s' wan successfully activated") % service.title) messages.success(request, _("The service '%s' wan successfully activated") % service.title)
else: else:
return render(request, 'clientsideapp/modal_service_buy.html', { return render(request, 'clientsideapp/modal_service_buy.html', {

7
devapp/views.py

@ -469,8 +469,7 @@ def devview(request, group_id: int, device_id: int):
template_name = 'generic_switch.html' template_name = 'generic_switch.html'
try: try:
if device.ip_address:
if not ping(str(device.ip_address)):
if device.ip_address and not ping(str(device.ip_address)):
messages.error(request, _('Dot was not pinged')) messages.error(request, _('Dot was not pinged'))
if device.man_passw: if device.man_passw:
manager = device.get_manager_object() manager = device.get_manager_object()
@ -482,13 +481,15 @@ def devview(request, group_id: int, device_id: int):
template_name = manager.get_template_name() template_name = manager.get_template_name()
else: else:
messages.warning(request, _('Not Set snmp device password')) messages.warning(request, _('Not Set snmp device password'))
return render(request, 'devapp/custom_dev_page/' + template_name, { return render(request, 'devapp/custom_dev_page/' + template_name, {
'dev': device, 'dev': device,
'ports': ports, 'ports': ports,
'dev_accs': Abon.objects.filter(device=device), 'dev_accs': Abon.objects.filter(device=device),
'dev_manager': manager, 'dev_manager': manager,
'ports_db': Port.objects.filter(device=device).annotate( 'ports_db': Port.objects.filter(device=device).annotate(
num_abons=Count('abon')),
num_abons=Count('abon')
),
}) })
except EasySNMPError as e: except EasySNMPError as e:
messages.error(request, messages.error(request,

2
djing/lib/decorators.py

@ -81,6 +81,8 @@ def json_view(fn):
@wraps(fn) @wraps(fn)
def wrapped(request, *args, **kwargs): def wrapped(request, *args, **kwargs):
r = fn(request, *args, **kwargs) r = fn(request, *args, **kwargs)
if isinstance(r, dict) and not isinstance(r.get('text'), str):
r['text'] = str(r.get('text'))
return JsonResponse(r, safe=False, json_dumps_params={ return JsonResponse(r, safe=False, json_dumps_params={
'ensure_ascii': False 'ensure_ascii': False
}) })

5
gw_app/nas_managers/core.py

@ -1,4 +1,4 @@
from abc import ABC, abstractmethod, abstractproperty
from abc import ABC, abstractmethod
from typing import Iterator, Tuple, Optional from typing import Iterator, Tuple, Optional
from djing import ping from djing import ping
from gw_app.nas_managers.structs import SubnetQueue, VectorQueue from gw_app.nas_managers.structs import SubnetQueue, VectorQueue
@ -16,7 +16,8 @@ class NasNetworkError(Exception):
# Communicate with gw # Communicate with gw
class BaseTransmitter(ABC): class BaseTransmitter(ABC):
@abstractproperty
@property
@abstractmethod
def description(self): def description(self):
""" """
:return: Returnd a description of nas implementation :return: Returnd a description of nas implementation

9
gw_app/nas_managers/mod_mikrotik.py

@ -301,7 +301,7 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos,
if queue_gw is None: if queue_gw is None:
return self.add_queue(queue) return self.add_queue(queue)
else: else:
cmd = [
cmd = (
'/queue/simple/set', '/queue/simple/set',
'=name=%s' % queue.name, '=name=%s' % queue.name,
'=max-limit=%.3fM/%.3fM' % queue.max_limit, '=max-limit=%.3fM/%.3fM' % queue.max_limit,
@ -311,10 +311,9 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos,
'=queue=Djing_pcq_up/Djing_pcq_down', '=queue=Djing_pcq_up/Djing_pcq_down',
'=burst-time=5/5', '=burst-time=5/5',
'=burst-limit=%.3fM/%.3fM' % tuple(i * 2 for i in queue.max_limit), '=burst-limit=%.3fM/%.3fM' % tuple(i * 2 for i in queue.max_limit),
'=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit)
]
if queue.queue_id:
cmd.insert(1, '=.id=%s' % queue.queue_id)
'=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit),
'=numbers=%s' % queue_gw.queue_id
)
r = self._exec_cmd(cmd) r = self._exec_cmd(cmd)
return r return r

4
gw_app/nas_managers/structs.py

@ -23,7 +23,7 @@ class SubnetQueue(BaseStruct):
return self._max_limit return self._max_limit
def set_max_limit(self, v): def set_max_limit(self, v):
if isinstance(v, tuple):
if isinstance(v, (tuple, list)):
self._max_limit = v self._max_limit = v
elif isinstance(v, str): elif isinstance(v, str):
s_in, s_out = v.split('/') s_in, s_out = v.split('/')
@ -32,7 +32,7 @@ class SubnetQueue(BaseStruct):
sp = float(v) sp = float(v)
self._max_limit = sp, sp self._max_limit = sp, sp
else: else:
raise ValueError('Unexpected format for max_limit')
raise ValueError('Unexpected format for max_limit %s' % v)
max_limit = property(get_max_limit, set_max_limit) max_limit = property(get_max_limit, set_max_limit)

7
periodic.py

@ -7,8 +7,8 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings")
django.setup() django.setup()
from django.utils import timezone from django.utils import timezone
from django.db import transaction from django.db import transaction
from django.db.models import signals, Count
from abonapp.models import Abon, AbonTariff, abontariff_pre_delete, PeriodicPayForId, AbonLog
from django.db.models import Count
from abonapp.models import Abon, AbonTariff, PeriodicPayForId, AbonLog
from gw_app.nas_managers import NasNetworkError, NasFailedResult from gw_app.nas_managers import NasNetworkError, NasFailedResult
from gw_app.models import NASModel from gw_app.models import NASModel
from djing.lib import LogicError from djing.lib import LogicError
@ -34,7 +34,6 @@ class NasSyncThread(Thread):
def main(): def main():
signals.pre_delete.disconnect(abontariff_pre_delete, sender=AbonTariff)
AbonTariff.objects.filter(abon=None).delete() AbonTariff.objects.filter(abon=None).delete()
now = timezone.now() now = timezone.now()
fields = ('id', 'tariff__title', 'abon__id', 'abon__username') fields = ('id', 'tariff__title', 'abon__id', 'abon__username')
@ -78,7 +77,7 @@ def main():
# make log about it # make log about it
l = AbonLog.objects.create( l = AbonLog.objects.create(
abon=abon, amount=-amount, abon=abon, amount=-amount,
comment="Автоматическое продление услуги '%s'" % trf.title
comment="Автоматическое продление услуги '%s' для %s" % (trf.title, abon)
) )
print(l.comment) print(l.comment)
else: else:

5
requirements.txt

@ -17,7 +17,10 @@ pid
django-guardian django-guardian
pinax-theme-bootstrap pinax-theme-bootstrap
django-bootstrap3 django-bootstrap3
django-jsonfield
# django-jsonfield
-e git://github.com/dmkoch/django-jsonfield.git#egg=django-jsonfield
requests requests
webdavclient webdavclient
pyst2 pyst2

Loading…
Cancel
Save