Browse Source

Merge branch 'devel' into separate_network

devel
bashmak 8 years ago
parent
commit
ac78a64c8b
  1. 8
      abonapp/forms.py
  2. 4
      abonapp/templates/abonapp/editAbon.html
  3. 10
      abonapp/templates/abonapp/modal_abonamount.html
  4. 21
      abonapp/views.py
  5. 6
      devapp/dev_types.py
  6. 44
      devapp/models.py
  7. 24
      devapp/onu_register.py
  8. 55
      devapp/onu_register.sh
  9. 2
      devapp/views.py
  10. 2
      dialing_app/views.py

8
abonapp/forms.py

@ -165,3 +165,11 @@ class MarkersForm(forms.ModelForm):
def save(self, commit=True): def save(self, commit=True):
instance = super(MarkersForm, self).save(commit=False) instance = super(MarkersForm, self).save(commit=False)
return instance.save(update_fields=('markers',)) return instance.save(update_fields=('markers',))
class AmountMoneyForm(forms.Form):
amount = forms.FloatField(max_value=50000, label=_('Amount of money'))
comment = forms.CharField(max_length=128, label=_('Comment'), required=False)
def save(self):
pass

4
abonapp/templates/abonapp/editAbon.html

@ -40,7 +40,9 @@
{# Ip address field #} {# Ip address field #}
{# {% trans 'Reset ip' as tx %}#} {# {% trans 'Reset ip' as tx %}#}
{# {% url 'abonapp:reset_ip' group.pk abon.username as url %}#} {# {% 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 %}#}
{# {% if abon.is_dynamic_ip %}#}
{# {% bootstrap_button '' button_type='link' icon='refresh' button_class='btn-default btn-cmd' id='iprefreshbtn' href=url size='sm' title=tx as bt %}#}
{# {% endif %} #}
{# {% bootstrap_field form.ip_address form_group_class='form-group-sm' addon_after_class='input-group-btn' addon_after=bt %}#} {# {% bootstrap_field form.ip_address form_group_class='form-group-sm' addon_after_class='input-group-btn' addon_after=bt %}#}

10
abonapp/templates/abonapp/modal_abonamount.html

@ -1,4 +1,5 @@
{% load i18n %} {% load i18n %}
{% load bootstrap3 %}
<form role="form" action="{% url 'abonapp:abon_amount' group_id abon.username %}" method="post"> {% csrf_token %} <form role="form" action="{% url 'abonapp:abon_amount' group_id abon.username %}" method="post"> {% csrf_token %}
<div class="modal-header primary"> <div class="modal-header primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
@ -6,15 +7,8 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-group-sm">
<label for="amount">{% trans 'Amount of money' %}</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-ruble"></span></span>
<input id="amount" type="text" name="amount" placeholder="0.0" class="form-control" required>
</div>
</div>
<input type="hidden" name="abonuname" value="{{ abon.username }}"><br>
{% bootstrap_form form %}
<div class="btn-group"> <div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary"> <button type="submit" class="btn btn-sm btn-primary">

21
abonapp/views.py

@ -4,6 +4,7 @@ from django.contrib.gis.shortcuts import render_to_text
from django.core.exceptions import PermissionDenied, ValidationError from django.core.exceptions import PermissionDenied, ValidationError
from django.db import IntegrityError, ProgrammingError, transaction from django.db import IntegrityError, ProgrammingError, transaction
from django.db.models import Count, Q from django.db.models import Count, Q
from django.http.request import QueryDict
from django.shortcuts import render, redirect, get_object_or_404, resolve_url from django.shortcuts import render, redirect, get_object_or_404, resolve_url
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseRedirect from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseRedirect
@ -188,17 +189,23 @@ class DelAbonDeleteView(DeleteView):
@transaction.atomic @transaction.atomic
def abonamount(request, gid, uname): def abonamount(request, gid, uname):
abon = get_object_or_404(models.Abon, username=uname) abon = get_object_or_404(models.Abon, username=uname)
frm = None
try: try:
if request.method == 'POST': if request.method == 'POST':
abonuname = request.POST.get('abonuname')
if abonuname == uname:
amnt = lib.safe_float(request.POST.get('amount'))
abon.add_ballance(request.user, amnt, comment=_('fill account through admin side'))
frm = forms.AmountMoneyForm(request.POST)
if frm.is_valid():
amnt = frm.cleaned_data.get('amount')
comment = frm.cleaned_data.get('comment')
if not comment:
comment = _('fill account through admin side')
abon.add_ballance(request.user, amnt, comment=comment)
abon.save(update_fields=('ballance',)) abon.save(update_fields=('ballance',))
messages.success(request, _('Account filled successfully on %.2f') % amnt) messages.success(request, _('Account filled successfully on %.2f') % amnt)
return redirect('abonapp:abon_phistory', gid=gid, uname=uname) return redirect('abonapp:abon_phistory', gid=gid, uname=uname)
else: else:
messages.error(request, _('I not know the account id')) messages.error(request, _('I not know the account id'))
else:
frm = forms.AmountMoneyForm()
except (NasNetworkError, NasFailedResult) as e: except (NasNetworkError, NasFailedResult) as e:
messages.error(request, e) messages.error(request, e)
except lib.MultipleException as errs: except lib.MultipleException as errs:
@ -206,7 +213,8 @@ def abonamount(request, gid, uname):
messages.error(request, err) messages.error(request, err)
return render_to_text('abonapp/modal_abonamount.html', { return render_to_text('abonapp/modal_abonamount.html', {
'abon': abon, 'abon': abon,
'group_id': gid
'group_id': gid,
'form': frm
}, request=request) }, request=request)
@ -1154,8 +1162,7 @@ def search_abon(request):
if not word: if not word:
return None return None
results = models.Abon.objects.filter(fio__icontains=word)[:8] results = models.Abon.objects.filter(fio__icontains=word)[:8]
results = ({'id': usr.pk, 'text': "%s: %s" % (usr.username, usr.fio)} for usr in results)
return results
return list({'id': usr.pk, 'text': "%s: %s" % (usr.username, usr.fio)} for usr in results)
class DhcpLever(SecureApiView): class DhcpLever(SecureApiView):

6
devapp/dev_types.py

@ -61,6 +61,7 @@ class DLinkPort(BasePort):
class DLinkDevice(DevBase, SNMPBaseWorker): class DLinkDevice(DevBase, SNMPBaseWorker):
has_attachable_to_subscriber = True has_attachable_to_subscriber = True
tech_code = 'dlink_sw'
description = _('DLink switch') description = _('DLink switch')
is_use_device_port = True is_use_device_port = True
@ -196,6 +197,7 @@ class OLTDevice(DevBase, SNMPBaseWorker):
class OnuDevice(DevBase, SNMPBaseWorker): class OnuDevice(DevBase, SNMPBaseWorker):
has_attachable_to_subscriber = True has_attachable_to_subscriber = True
description = _('PON ONU') description = _('PON ONU')
tech_code = 'bdcom_onu'
is_use_device_port = False is_use_device_port = False
def __init__(self, dev_instance): def __init__(self, dev_instance):
@ -312,6 +314,7 @@ class EltexSwitch(DLinkDevice):
description = _('Eltex switch') description = _('Eltex switch')
is_use_device_port = False is_use_device_port = False
has_attachable_to_subscriber = True has_attachable_to_subscriber = True
tech_code = 'eltex_sw'
def get_ports(self) -> ListOrError: def get_ports(self) -> ListOrError:
res = [] res = []
@ -322,7 +325,7 @@ class EltexSwitch(DLinkDevice):
self.get_item('.1.3.6.1.2.1.31.1.1.1.18.%d' % n), self.get_item('.1.3.6.1.2.1.31.1.1.1.18.%d' % n),
self.get_item('.1.3.6.1.2.1.2.2.1.8.%d' % n), self.get_item('.1.3.6.1.2.1.2.2.1.8.%d' % n),
self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n),
int(speed),
int(speed) if speed != 'NOSUCHINSTANCE' else 0,
)) ))
return res return res
@ -414,6 +417,7 @@ class Olt_ZTE_C320(OLTDevice):
class ZteOnuDevice(OnuDevice): class ZteOnuDevice(OnuDevice):
description = _('ZTE PON ONU') description = _('ZTE PON ONU')
tech_code = 'zte_onu'
def get_details(self) -> Optional[Dict]: def get_details(self) -> Optional[Dict]:
if self.db_instance is None: if self.db_instance is None:

44
devapp/models.py

@ -1,11 +1,9 @@
import os
from typing import Optional, AnyStr from typing import Optional, AnyStr
from subprocess import run
from jsonfield import JSONField
from django.db import models from django.db import models
from django.conf import settings
from django.shortcuts import resolve_url from django.shortcuts import resolve_url
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from jsonfield import JSONField
from djing.fields import MACAddressField from djing.fields import MACAddressField
from djing.lib import MyChoicesAdapter from djing.lib import MyChoicesAdapter
@ -67,20 +65,12 @@ class Device(models.Model):
verbose_name_plural = _('Devices') verbose_name_plural = _('Devices')
ordering = ('id',) ordering = ('id',)
def get_abons(self):
pass
def get_status(self):
return self.status
def get_manager_klass(self): def get_manager_klass(self):
klasses = next(kl for kl in self.DEVICE_TYPES if kl[0] == self.devtype)
if klasses:
code, dev_class = klasses
if issubclass(dev_class, DevBase):
return dev_class
raise TypeError('one of types is not subclass of DevBase. '
'Or implementation of that device type is not found')
try:
return next(klass for code, klass in self.DEVICE_TYPES if code == self.devtype)
except StopIteration:
raise TypeError('one of types is not subclass of DevBase. '
'Or implementation of that device type is not found')
def get_manager_object(self) -> DevBase: def get_manager_object(self) -> DevBase:
man_klass = self.get_manager_klass() man_klass = self.get_manager_klass()
@ -96,20 +86,12 @@ class Device(models.Model):
def __str__(self): def __str__(self):
return "%s: (%s) %s %s" % (self.comment, self.get_devtype_display(), self.ip_address or '', self.mac_addr or '') return "%s: (%s) %s %s" % (self.comment, self.get_devtype_display(), self.ip_address or '', self.mac_addr or '')
def update_dhcp(self, remove=False):
# FIXME: Remove static list of registrable device types
if self.devtype not in ('On', 'Dl', 'Zo'):
return
if self.group is None:
raise DeviceDBException(_('Device does not have a group, please fix that'))
code = self.group.code
newmac = str(self.mac_addr)
filepath = os.path.join(settings.BASE_DIR, 'devapp', 'onu_register.sh')
if remove:
param = 'del'
else:
param = 'update'
run((filepath, param, newmac, code))
@staticmethod
def update_dhcp():
from .onu_register import onu_register
onu_register(
Device.objects.exclude(group=None).select_related('group').only('mac_addr', 'group__code').iterator()
)
def generate_config_template(self) -> Optional[AnyStr]: def generate_config_template(self) -> Optional[AnyStr]:
mng = self.get_manager_object() mng = self.get_manager_object()

24
devapp/onu_register.py

@ -0,0 +1,24 @@
#!/usr/bin/env python3
from typing import Iterable
from subprocess import run
def onu_register(devices: Iterable):
with open('/etc/dhcp/macs.conf', 'w') as f:
for dev in devices:
if not dev.has_attachable_to_subscriber() or dev.mac_addr is None:
continue
group_code = dev.group.code
if not group_code:
continue
try:
mn = dev.get_manager_klass()
dev_code = mn.tech_code
f.write('subclass "%(group_code)s.%(dev_code)s" "%(mac)s";\n' % {
'group_code': group_code,
'mac': dev.mac_addr,
'dev_code': dev_code
})
except TypeError:
continue
run(('/usr/bin/sudo', 'systemctl', 'restart', 'isc-dhcp-server.service'))

55
devapp/onu_register.sh

@ -1,55 +0,0 @@
#!/bin/bash
# Action
ACT=$1
if [[ ${ACT} == '' ]]; then
echo 'Need the action type parameter'
exit
fi
# old mac address
if [[ $2 =~ ^([0-9A-Fa-f]{1,2}[:-]){5}([0-9A-Fa-f]{1,2})$ ]]; then
MAC=$2
else
echo "Bad mac $MAC addr"
exit
fi
# part code
if [[ $3 =~ ^[a-zA-Z]+$ ]]; then
PART_CODE=$3
else
echo 'code must contains only letters'
exit
fi
DHCP_MACS='/etc/dhcp/macs.conf'
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/bin
# if just remove device
if [[ ${ACT} == 'del' ]]; then
sed -i "/${MAC}/d" ${DHCP_MACS}
exit
fi
# If exist mac with code
if grep "^subclass\ \"${PART_CODE}\" \"${MAC}\";$" "${DHCP_MACS}" > /dev/null; then
# mac is already exists, quit
exit
else
# If mac existing in another group
if grep "${MAC}" ${DHCP_MACS} > /dev/null; then
# remove it
sed -i "/${MAC}/d" ${DHCP_MACS}
fi
# add new mac
echo "subclass \"${PART_CODE}\" \"${MAC}\";" >> ${DHCP_MACS}
sudo systemctl restart isc-dhcp-server.service
fi

2
devapp/views.py

@ -76,7 +76,7 @@ class DeviceDeleteView(DeleteView):
def delete(self, request, *args, **kwargs): def delete(self, request, *args, **kwargs):
res = super().delete(request, *args, **kwargs) res = super().delete(request, *args, **kwargs)
try: try:
self.object.update_dhcp(remove=True)
self.object.update_dhcp()
except DeviceDBException as e: except DeviceDBException as e:
messages.error(request, e) messages.error(request, e)
messages.success(request, _('Device successfully deleted')) messages.success(request, _('Device successfully deleted'))

2
dialing_app/views.py

@ -49,7 +49,7 @@ class LastCallsListView(BaseListView):
@login_required @login_required
@only_admins @only_admins
def to_abon(request, tel): def to_abon(request, tel):
abon = Abon.objects.filter(telephone=tel)
abon = Abon.objects.filter(Q(telephone__icontains=tel) | Q(additional_telephones__telephone__icontains=tel))
abon_count = abon.count() abon_count = abon.count()
if abon_count > 1: if abon_count > 1:
messages.warning(request, _('Multiple users with the telephone number')) messages.warning(request, _('Multiple users with the telephone number'))

Loading…
Cancel
Save