Browse Source

Create monitoring for ZTE devices

devel
bashmak 8 years ago
parent
commit
f7008d2d0c
  1. 68
      devapp/dev_types.py
  2. 60
      devapp/migrations/0003_auto_20180529_1311.py
  3. 8
      devapp/models.py
  4. 2
      devapp/templates/devapp/add_dev.html
  5. 2
      devapp/templates/devapp/custom_dev_page/olt_ztec320_ports.html
  6. 19
      devapp/templates/devapp/custom_dev_page/onu.html
  7. 91
      devapp/templates/devapp/custom_dev_page/onu_for_zte.html
  8. 2
      devapp/templates/devapp/dev.html
  9. 16
      devapp/views.py
  10. 0
      djing/lib/auth_backends.py
  11. 359
      migrate_to_0.2.py
  12. 187
      mydefs.py
  13. 18
      static/css/custom.css

68
devapp/dev_types.py

@ -1,9 +1,9 @@
from typing import AnyStr, Iterable
from typing import AnyStr, Iterable, Optional, Dict
from datetime import timedelta
from easysnmp import EasySNMPTimeoutError
from django.utils.translation import gettext_lazy as _, gettext
from mydefs import RuTimedelta, safe_int
from djing.lib import RuTimedelta, safe_int
from .base_intr import DevBase, SNMPBaseWorker, BasePort, DeviceImplementationError, ListOrError
@ -197,7 +197,7 @@ class OnuDevice(DevBase, SNMPBaseWorker):
def get_details(self):
if self.db_instance is None:
return
num = self.db_instance.snmp_item_num
num = safe_int(self.db_instance.snmp_extra)
if num == 0:
return
try:
@ -272,8 +272,17 @@ class EltexSwitch(DLinkDevice):
return False
class Olt_ZTE_C320(OLTDevice):
def conv_signal(lvl: int) -> float:
if lvl == 65535: return 0.0
r = 0
if 0 < lvl < 30000:
r = lvl * 0.002 - 30
elif 60000 < lvl < 65534:
r = (lvl - 65534) * 0.002 - 30
return round(r, 2)
class Olt_ZTE_C320(OLTDevice):
@staticmethod
def description():
return gettext('OLT ZTE C320')
@ -287,16 +296,8 @@ class Olt_ZTE_C320(OLTDevice):
return fibers
def get_ports_on_fiber(self, fiber_num: int) -> Iterable:
def conv_signal(lvl: int) -> float:
if lvl == 65535: return 0.0
r = 0
if 0 < lvl < 30000:
r = lvl * 0.002 - 30
elif 60000 < lvl < 65534:
r = (lvl - 65534) * 0.002 - 30
return round(r, 2)
onu_types = self.get_list('.1.3.6.1.4.1.3902.1012.3.28.1.1.1.%d' % fiber_num)
onu_types = self.get_list_keyval('.1.3.6.1.4.1.3902.1012.3.28.1.1.1.%d' % fiber_num)
onu_ports = self.get_list('.1.3.6.1.4.1.3902.1012.3.28.1.1.2.%d' % fiber_num)
onu_signals = self.get_list('.1.3.6.1.4.1.3902.1012.3.50.12.1.1.10.%d' % fiber_num)
@ -304,13 +305,15 @@ class Olt_ZTE_C320(OLTDevice):
onu_sns = self.get_list('.1.3.6.1.4.1.3902.1012.3.28.1.1.5.%d' % fiber_num)
onu_prefixs = self.get_list('.1.3.6.1.4.1.3902.1012.3.50.11.2.1.1.%d' % fiber_num)
onu_list = ({
'onu_type': onu_type,
'onu_type': onu_type_num[0],
'onu_port': onu_port,
'onu_signal': conv_signal(safe_int(onu_signal)),
'onu_sn': onu_prefix + ''.join('%.2X' % ord(i) for i in onu_sn[-4:]), # Real sn in last 4 octets
} for onu_type, onu_port, onu_signal, onu_sn, onu_prefix in zip(
'onu_sn': onu_prefix + ''.join('%.2X' % ord(i) for i in onu_sn[-4:]), # Real sn in last 4 octets,
'snmp_extra': "%d.%d" % (fiber_num, safe_int(onu_type_num[1])),
} for onu_type_num, onu_port, onu_signal, onu_sn, onu_prefix in zip(
onu_types, onu_ports, onu_signals, onu_sns, onu_prefixs
))
return onu_list
def uptime(self):
@ -326,3 +329,34 @@ class Olt_ZTE_C320(OLTDevice):
def get_template_name(self):
return 'olt_ztec320.html'
class ZteOnuDevice(OnuDevice):
@staticmethod
def description():
return _('ZTE PON ONU')
def get_details(self) -> Optional[Dict]:
if self.db_instance is None:
return
snmp_extra = self.db_instance.snmp_extra
if not snmp_extra:
return
try:
fiber_num, onu_num = snmp_extra.split('.')
fiber_num, onu_num = int(fiber_num), int(onu_num)
status = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.12.1.1.1.%d.%d.1' % (fiber_num, onu_num))
signal = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.12.1.1.10.%d.%d.1' % (fiber_num, onu_num))
distance = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.12.1.1.18.%d.%d.1' % (fiber_num, onu_num))
name = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.11.2.1.1.%d.%d' % (fiber_num, onu_num))
return {
'status': status,
'signal': conv_signal(safe_int(signal)),
'name': name,
'distance': int(distance) / 10 if distance != 'NOSUCHINSTANCE' else 0
}
except ValueError:
pass
def get_template_name(self):
return 'onu_for_zte.html'

60
devapp/migrations/0003_auto_20180529_1311.py

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-05-29 13:11
from __future__ import unicode_literals
import os
from json import load
from django.db import migrations, models
from django.core import serializers
TMP_FILE = '/tmp/djing_snmp_info_backup.json'
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)
def snmp_restore_info_to_new_scheme(apps, _):
Device = apps.get_model('devapp', 'Device')
with open(TMP_FILE, 'r') as f:
for device in load(f):
Device.objects.filter(pk=device['pk']).update(snmp_extra=device['fields']['snmp_item_num'])
if os.path.isfile(TMP_FILE):
os.remove(TMP_FILE)
class Migration(migrations.Migration):
dependencies = [
('devapp', '0002_auto_20180409_1318'),
]
operations = [
migrations.RunPython(snmp_backup_info),
migrations.AlterModelOptions(
name='device',
options={'ordering': ('id',), 'permissions': (('can_view_device', 'Can view device'),), 'verbose_name': 'Device', 'verbose_name_plural': 'Devices'},
),
migrations.AlterModelOptions(
name='port',
options={'ordering': ('num',), 'permissions': (('can_toggle_ports', 'Can toggle ports'),), 'verbose_name': 'Port', 'verbose_name_plural': 'Ports'},
),
migrations.RemoveField(
model_name='device',
name='snmp_item_num',
),
migrations.AddField(
model_name='device',
name='snmp_extra',
field=models.CharField(blank=True, max_length=256, null=True, verbose_name='SNMP extra info'),
),
migrations.AlterField(
model_name='device',
name='devtype',
field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU'), ('Ex', 'Eltex switch'), ('Zt', 'OLT ZTE C320'), ('Zo', 'ZTE PON ONU')], default='Dl', max_length=2, verbose_name='Device type'),
),
migrations.RunPython(snmp_restore_info_to_new_scheme)
]

8
devapp/models.py

@ -1,8 +1,9 @@
import os
from django.db import models
from djing.fields import MACAddressField
from .base_intr import DevBase
from mydefs import MyGenericIPAddressField, MyChoicesAdapter
from djing.lib import MyGenericIPAddressField, MyChoicesAdapter
from . import dev_types
from subprocess import run
from django.conf import settings
@ -27,7 +28,8 @@ class Device(models.Model):
('Pn', dev_types.OLTDevice),
('On', dev_types.OnuDevice),
('Ex', dev_types.EltexSwitch),
('Zt', dev_types.Olt_ZTE_C320)
('Zt', dev_types.Olt_ZTE_C320),
('Zo', dev_types.ZteOnuDevice)
)
devtype = models.CharField(_('Device type'), max_length=2, default=DEVICE_TYPES[0][0],
choices=MyChoicesAdapter(DEVICE_TYPES))
@ -36,7 +38,7 @@ class Device(models.Model):
parent_dev = models.ForeignKey('self', verbose_name=_('Parent device'), blank=True, null=True,
on_delete=models.SET_NULL)
snmp_item_num = models.PositiveSmallIntegerField(_('SNMP Number'), default=0, blank=True)
snmp_extra = models.CharField(_('SNMP extra info'), max_length=256, null=True, blank=True)
NETWORK_STATES = (
('und', _('Undefined')),

2
devapp/templates/devapp/add_dev.html

@ -63,7 +63,7 @@
</div>
{% bootstrap_icon 'list-alt' as ic %}
{% bootstrap_field form.snmp_item_num addon_before=ic %}
{% bootstrap_field form.snmp_extra addon_before=ic %}
{% bootstrap_field form.is_noticeable %}

2
devapp/templates/devapp/custom_dev_page/olt_ztec320_ports.html

@ -42,7 +42,7 @@
<td>{{ onu.onu_signal }}</td>
<td>{{ onu.onu_sn }}</td>
<td>
<a href="{% url 'devapp:add' grp %}?t=On&pdev={{ dev.pk }}&c={{ onu.onu_sn }}" title="{% trans 'Create device' %}">
<a href="{% url 'devapp:add' grp %}?t=Zo&pdev={{ dev.pk }}&c={{ onu.onu_sn }}&n={{ onu.snmp_extra }}" title="{% trans 'Create device' %}">
<span class="glyphicon glyphicon-plus"></span>
</a>
</td>

19
devapp/templates/devapp/custom_dev_page/onu.html

@ -31,9 +31,10 @@
{% if dev.parent_dev %}
<li class="list-group-item">
{% with pdev=dev.parent_dev pdgrp=dev.parent_dev.group %}
{% trans 'Parent device' %}:<a href="{% url 'devapp:view' pdgrp.pk pdev.pk %}"
title="{{ pdev.mac_addr|default:'' }}"
target="_blank">{{ pdev.ip_address|default:'-' }} {{ pdev.comment }}</a>
{% trans 'Parent device' %}:
<a href="{% url 'devapp:view' pdgrp.pk pdev.pk %}" title="{{ pdev.mac_addr|default:'' }}" target="_blank">
{{ pdev.ip_address|default:'-' }} {{ pdev.comment }}
</a>
{% endwith %}
</li>
{% endif %}
@ -51,20 +52,20 @@
{% if onu_details %}
{% if onu_details.err %}
<div class="media">
<div class="media-left"><span class="media-object glyphicon glyphicon-remove-sign text-danger" style="font-size: 75px;"></span></div>
<div class="media-left"><span class="media-object glyphicon glyphicon-remove-sign text-danger font-extra-large"></span></div>
</div>
<div class="media-body">
<b>{% trans 'ONU error' %}</b>: {{ onu_details.err }}<br>
</div>
{% else %}
<div class="media">
<div class="media-left">
<div class="media-left font-extra-large">
{% if onu_details.status == '3' %}
<span class="media-object glyphicon glyphicon-ok-sign text-success" style="font-size: 75px;"></span>
<span class="media-object glyphicon glyphicon-ok-sign text-success"></span>
{% elif onu_details.status == '2' %}
<span class="media-object glyphicon glyphicon-remove-sign text-danger" style="font-size: 75px;"></span>
<span class="media-object glyphicon glyphicon-remove-sign text-danger"></span>
{% else %}
<span class="media-object glyphicon glyphicon-question-sign" style="font-size: 75px;"></span>
<span class="media-object glyphicon glyphicon-question-sign"></span>
{% endif %}
</div>
<div class="media-body">
@ -76,7 +77,7 @@
<span class="text-danger">
<b>{% trans 'Mac on OLT' %}</b>: {{ onu_details.mac }}
<h4 class="glyphicon glyphicon-exclamation-sign" title="{% trans 'Mac-addresses does not match' %}" data-toggle="tooltip"></h4>
<a href="{% url 'devapp:fix_onu' %}" data-param="{{ dev.mac_addr }}" class="btn btn-default btn-xs btn-cmd" title="{% trans 'Fix it' %}" data-toggle="tooltip">
<a href="{% url 'devapp:fix_onu' %}" data-param="{{ dev.mac_addr }}" class="btn btn-default btn-xs btn-cmd" title="{% trans 'Fix it' %}" data-toggle="tooltip">
<span class="glyphicon glyphicon-fire"></span>
<span class="hidden-xs">{% trans 'Fix it' %}</span>
</a>

91
devapp/templates/devapp/custom_dev_page/onu_for_zte.html

@ -0,0 +1,91 @@
{% extends request.is_ajax|yesno:'nullcont.htm,devapp/ext.htm' %}
{% load i18n %}
{% block content %}
{% with uptime=dev_manager.uptime onu_details=dev_manager.get_details %}
<div class="row">
<div class="col-xs-12 col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">{{ dev.get_devtype_display|default:_('Title of the type of switch') }}.
{% if uptime %}
{% trans 'Uptime' %} {{ uptime }}
{% endif %}
</div>
</div>
<div class="panel-body">
<ul class="list-group">
<li class="list-group-item">{% trans 'Ip address' %}: {{ dev.ip_address|default:'-' }}</li>
<li class="list-group-item">{% trans 'Mac' %}: {{ dev.mac_addr }}</li>
<li class="list-group-item">{% trans 'Description' %}: {{ dev.comment }}</li>
{% for da in dev_accs %}
<li class="list-group-item">{% trans 'Attached user' %}:
{% if da.group %}
<a href="{% url 'abonapp:abon_home' da.group.pk da.username %}"
target="_blank">{{ da.get_full_name }}</a>
{% else %}
{{ da.get_full_name }}
{% endif %}
</li>
{% endfor %}
{% if dev.parent_dev %}
<li class="list-group-item">
{% with pdev=dev.parent_dev pdgrp=dev.parent_dev.group %}
{% trans 'Parent device' %}:
<a href="{% url 'devapp:view' pdgrp.pk pdev.pk %}"
title="{{ pdev.mac_addr|default:'' }}"
target="_blank">
{{ pdev.ip_address|default:'-' }} {{ pdev.comment }}
</a>
{% endwith %}
</li>
{% endif %}
</ul>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'ONU Status' %}</h3>
</div>
<div class="panel-body">
{% if onu_details %}
{% if onu_details.err %}
<div class="media">
<div class="media-left"><span class="media-object glyphicon glyphicon-remove-sign text-danger font-extra-large"></span></div>
</div>
<div class="media-body">
<b>{% trans 'ONU error' %}</b>: {{ onu_details.err }}<br>
</div>
{% else %}
<div class="media">
<div class="media-left font-extra-large">
{% if onu_details.status == '1' %}
<span class="media-object glyphicon glyphicon-ok-sign text-success"></span>
{% elif onu_details.status == '2' %}
<span class="media-object glyphicon glyphicon-remove-sign text-danger"></span>
{% else %}
<span class="media-object glyphicon glyphicon-question-sign"></span>
{% endif %}
</div>
<div class="media-body">
<b>{% trans 'Name on OLT' %}</b>: {{ onu_details.name }}<br>
<b>{% trans 'Distance(m)' %}</b>: {{ onu_details.distance }}<br>
<b>{% trans 'Signal' %}</b>: {{ onu_details.signal }}<br>
</div>
</div>
{% endif %}
{% else %}
<h3>{% trans 'Info does not fetch' %}</h3>
{% endif %}
</div>
</div>
</div>
</div>
{% endwith %}
{% endblock %}

2
devapp/templates/devapp/dev.html

@ -52,7 +52,7 @@
</div>
{% bootstrap_icon 'list-alt' as ic %}
{% bootstrap_field form.snmp_item_num addon_before=ic %}
{% bootstrap_field form.snmp_extra addon_before=ic %}
{% bootstrap_field form.is_noticeable %}

16
devapp/views.py

@ -14,7 +14,7 @@ from easysnmp import EasySNMPTimeoutError, EasySNMPError
from django.views.generic import DetailView
from devapp.base_intr import DeviceImplementationError
from mydefs import res_success, res_error, only_admins, safe_int
from djing.lib import res_success, res_error, only_admins, safe_int
from abonapp.models import Abon
from group_app.models import Group
from accounts_app.models import UserProfile
@ -137,7 +137,7 @@ def dev(request, group_id, device_id=0):
'comment': request.GET.get('c'),
'ip_address': request.GET.get('ip'),
'man_passw': getattr(settings, 'DEFAULT_SNMP_PASSWORD', ''),
'snmp_item_num': request.GET.get('n') or 0
'snmp_extra': request.GET.get('n') or ''
})
else:
frm = DeviceForm(instance=devinst)
@ -505,8 +505,8 @@ def fix_onu(request):
# convert bytes mac address to str presentation mac address
real_mac = ':'.join('%x' % ord(i) for i in srcmac)
if mac == real_mac:
onu.snmp_item_num = snmpnum
onu.save(update_fields=('snmp_item_num',))
onu.snmp_extra = str(snmpnum)
onu.save(update_fields=('snmp_extra',))
status = 0
text = '<span class="glyphicon glyphicon-ok"></span> <span class="hidden-xs">%s</span>' % _('Fixed')
break
@ -619,11 +619,11 @@ class NagiosObjectsConfView(global_base_views.AuthenticatedOrHashAuthView):
if device.devtype == 'On':
if device.parent_dev:
host_addr = device.parent_dev.ip_address
conf = self.templ_onu(host_name, host_addr, mac=mac_addr, snmp_item=device.snmp_item_num or None)
conf = self.templ_onu(host_name, host_addr, mac=mac_addr, snmp_item=device.snmp_extra or None)
else:
if device.ip_address:
host_addr = device.ip_address
conf = self.templ_onu(host_name, host_addr, mac=mac_addr, snmp_item=device.snmp_item_num or None)
conf = self.templ_onu(host_name, host_addr, mac=mac_addr, snmp_item=device.snmp_extra or None)
else:
parent_host_name = norm_name("%d%s" % (
device.parent_dev.pk, translit(device.parent_dev.comment, language_code='ru', reversed=True)
@ -651,7 +651,7 @@ class NagiosObjectsConfView(global_base_views.AuthenticatedOrHashAuthView):
return '\n'.join(i for i in r if i)
@staticmethod
def templ_onu(host_name: str, host_addr: str, mac: Optional[str], snmp_item: int):
def templ_onu(host_name: str, host_addr: str, mac: Optional[str], snmp_item: str):
if not host_addr:
return
r = (
@ -659,7 +659,7 @@ class NagiosObjectsConfView(global_base_views.AuthenticatedOrHashAuthView):
"\tuse device-onu",
"\thost_name %s" % host_name,
"\taddress %s" % host_addr,
"\t_snmp_item %d" % snmp_item if snmp_item is not None else '',
"\t_snmp_item %s" % snmp_item if snmp_item is not None else '',
"\t_mac_addr %s" % mac if mac is not None else '',
"}\n"
)

0
djing/auth_backends.py → djing/lib/auth_backends.py

359
migrate_to_0.2.py

@ -1,359 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import shutil
from json import dump
import django
'''
Some permissions is not migrates, all admins is superuser
after migrate.
'''
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings")
from django.db.models import fields as django_fields
def get_fixture_from_unchanget_model(model_name: str, model_class):
"""
Создаёт фикстуру если модели между версиями не изменились
:param model_name: str 'app_label.model_name'
:param model_class: Model модель для которой надо сделать фикстуру
:return: список словарей
"""
print(model_name)
def get_fields(obj):
fields = dict()
for field in obj._meta.get_fields():
if isinstance(field,
(django_fields.reverse_related.ManyToOneRel, django_fields.reverse_related.ManyToManyRel)):
continue
field_val = getattr(obj, field.name)
if field_val is None:
continue
if isinstance(field, django_fields.related.ManyToManyField):
fields[field.name] = [f.pk for f in field_val.all()]
elif isinstance(field,
(django_fields.related.ForeignKey, django.contrib.contenttypes.fields.GenericForeignKey)):
fields[field.name] = field_val.pk
elif isinstance(field, django_fields.FloatField):
fields[field.name] = float(field_val)
elif isinstance(field, django_fields.DateTimeField):
fields[field.name] = str(field_val)
elif isinstance(field, django_fields.AutoField):
continue
else:
fields[field.name] = field_val
return fields
res = [{
'model': model_name,
'pk': obj.pk,
'fields': get_fields(obj)
} for obj in model_class.objects.all()]
return res
def dump_groups():
from abonapp import models
print('group_app.group')
res = [{
'model': 'group_app.group',
'pk': abon_group.pk,
'fields': {
'title': abon_group.title
}
} for abon_group in models.AbonGroup.objects.all()]
return res
def dump_abonapp():
from abonapp import models
res = get_fixture_from_unchanget_model('abonapp.abontariff', models.AbonTariff)
res += get_fixture_from_unchanget_model('abonapp.abonstreet', models.AbonStreet)
res += get_fixture_from_unchanget_model('abonapp.extrafieldsmodel', models.ExtraFieldsModel)
# res += get_fixture_from_unchanget_model('abonapp.abonlog', models.AbonLog)
print('abonapp.abon')
res += [{
'model': 'abonapp.abon',
'pk': abon.pk,
'fields': {
'current_tariff': abon.current_tariff.pk if abon.current_tariff else None,
'group': abon.group.pk if abon.group else None,
'ballance': abon.ballance,
'ip_address': abon.ip_address,
'description': abon.description,
'street': abon.street.pk if abon.street else None,
'house': abon.house,
'extra_fields': [a.pk for a in abon.extra_fields.all()],
'device': abon.device.pk if abon.device else None,
'dev_port': abon.dev_port if abon.dev_port else None,
'is_dynamic_ip': abon.is_dynamic_ip,
'markers': abon.markers
}
} for abon in models.Abon.objects.filter(is_admin=False)]
res += get_fixture_from_unchanget_model('abonapp.passportinfo', models.PassportInfo)
res += get_fixture_from_unchanget_model('abonapp.invoiceforpayment', models.InvoiceForPayment)
res += get_fixture_from_unchanget_model('abonapp.alltimepaylog', models.AllTimePayLog)
res += get_fixture_from_unchanget_model('abonapp.abonrawpassword', models.AbonRawPassword)
res += get_fixture_from_unchanget_model('abonapp.additionaltelephone', models.AdditionalTelephone)
res += get_fixture_from_unchanget_model('abonapp.periodicpayforid', models.PeriodicPayForId)
return res
def dump_tariffs():
from tariff_app import models
from abonapp.models import AbonGroup
print('tariff_app.tariff')
res = [{
'model': 'tariff_app.tariff',
'pk': trf.pk,
'fields': {
'title': trf.title,
'descr': trf.descr,
'speedIn': trf.speedIn,
'speedOut': trf.speedOut,
'amount': trf.amount,
'calc_type': trf.calc_type,
'is_admin': trf.is_admin,
'groups': [ag.pk for ag in AbonGroup.objects.filter(tariffs__in=[trf])]
}
} for trf in models.Tariff.objects.all()]
res += get_fixture_from_unchanget_model('tariff_app.periodicpay', models.PeriodicPay)
return res
def dump_devs():
from devapp import models
print('devapp.device')
res = [{
'model': 'devapp.device',
'pk': dv.pk,
'fields': {
'ip_address': dv.ip_address,
'mac_addr': str(dv.mac_addr) if dv.mac_addr else None,
'comment': dv.comment,
'devtype': dv.devtype,
'man_passw': dv.man_passw,
'group': dv.user_group.pk if dv.user_group else None,
'parent_dev': dv.parent_dev.pk if dv.parent_dev else None,
'snmp_item_num': dv.snmp_item_num,
'status': dv.status,
'is_noticeable': dv.is_noticeable
}
} for dv in models.Device.objects.all()]
res += get_fixture_from_unchanget_model('devapp.port', models.Port)
return res
def dump_accounts():
from accounts_app import models
from abonapp.models import AbonGroup
def get_responsibility_groups(account):
responsibility_groups = AbonGroup.objects.filter(profiles__in=[account])
ids = [ag.pk for ag in responsibility_groups]
return ids
print('accounts_app.baseaccount')
res = [{
'model': 'accounts_app.baseaccount',
'pk': up.pk,
'fields': {
'username': up.username,
'fio': up.fio,
'birth_day': up.birth_day,
'is_active': up.is_active,
'is_admin': up.is_admin,
'telephone': up.telephone,
'password': up.password,
'last_login': up.last_login,
'is_superuser': up.is_admin
}
} for up in models.UserProfile.objects.all()]
print('accounts_app.userprofile')
res += [{
'model': 'accounts_app.userprofile',
'pk': up.pk,
'fields': {
'avatar': up.avatar.pk if up.avatar else None,
'email': up.email,
'responsibility_groups': get_responsibility_groups(up)
}
} for up in models.UserProfile.objects.filter(is_admin=True)]
return res
def dump_photos():
from photo_app.models import Photo
print('photo_app.photo')
res = [{
'model': 'photo_app.photo',
'pk': p.pk,
'fields': {
'image': "%s" % p.image,
'wdth': p.wdth,
'heigt': p.heigt
}
} for p in Photo.objects.all()]
return res
def dump_chatbot():
from chatbot import models
res = get_fixture_from_unchanget_model('chatbot.telegrambot', models.TelegramBot)
res += get_fixture_from_unchanget_model('chatbot.messagehistory', models.MessageHistory)
res += get_fixture_from_unchanget_model('chatbot.messagequeue', models.MessageQueue)
return res
def dump_map():
from mapapp import models
res = get_fixture_from_unchanget_model('mapapp.dot', models.Dot)
return res
def dump_task_app():
from taskapp import models
res = get_fixture_from_unchanget_model('taskapp.changelog', models.ChangeLog)
res += get_fixture_from_unchanget_model('taskapp.task', models.Task)
res += get_fixture_from_unchanget_model('taskapp.ExtraComment', models.ExtraComment)
return res
def dump_auth():
from django.contrib.auth import models
from django.contrib.contenttypes.models import ContentType
res = get_fixture_from_unchanget_model('contenttypes.contenttype', ContentType)
res += get_fixture_from_unchanget_model('auth.group', models.Group)
res += get_fixture_from_unchanget_model('auth.permission', models.Permission)
return res
def dump_guardian():
from guardian import models
print('guardian.groupobjectpermission')
res = [{
'model': 'guardian.groupobjectpermission',
'pk': gp.pk,
'fields': {
'group': gp.group.pk,
'permission': gp.permission.pk,
'content_type': gp.content_type.pk,
'object_pk': str(gp.object_pk),
'content_object': gp.content_object.pk
}
} for gp in models.GroupObjectPermission.objects.all()]
print('guardian.userobjectpermission')
res += [{
'model': 'guardian.userobjectpermission',
'pk': up.pk,
'fields': {
'permission': up.permission.pk,
'content_type': up.content_type.pk,
'object_pk': str(up.object_pk),
'user': up.user.pk
}
} for up in models.UserObjectPermission.objects.all()]
return res
def make_migration():
from datetime import datetime, date
def my_date_converter(o):
if isinstance(o, datetime) or isinstance(o, date):
return "%s" % o
def appdump(path, func):
fname = os.path.join(*path)
path_dir = os.path.join(*path[:-1])
if not os.path.isdir(path_dir):
os.mkdir(path_dir)
with open(fname, 'w') as f:
dump(func(), f, default=my_date_converter, ensure_ascii=False)
if not os.path.isdir('fixtures'):
os.mkdir('fixtures')
appdump(['fixtures', 'group_app', 'groups_fixture.json'], dump_groups)
appdump(['fixtures', 'tariff_app', 'tariffs_fixture.json'], dump_tariffs)
appdump(['fixtures', 'photo_app', 'photos_fixture.json'], dump_photos)
appdump(['fixtures', 'devapp', 'devs_fixture.json'], dump_devs)
appdump(['fixtures', 'accounts_app', 'accounts_fixture.json'], dump_accounts)
appdump(['fixtures', 'abonapp', 'abon_fixture.json'], dump_abonapp)
appdump(['fixtures', 'chatbot', 'chatbot_fixture.json'], dump_chatbot)
appdump(['fixtures', 'mapapp', 'map_fixture.json'], dump_map)
appdump(['fixtures', 'taskapp', 'task_fixture.json'], dump_task_app)
# appdump(['fixtures', 'accounts_app', 'auth_fixture.json'], dump_auth)
# appdump(['fixtures', 'accounts_app', 'guardian_fixture.json'], dump_guardian)
def move_to_fixtures_dirs():
fixdir = 'fixtures'
for dr in os.listdir(fixdir):
fixture_dir = os.path.join(fixdir, dr)
for fixture_file in os.listdir(fixture_dir):
from_file = os.path.join(fixture_dir, fixture_file)
dst_dir = os.path.join(dr, fixdir)
to_file = os.path.join(dst_dir, fixture_file)
if not os.path.isdir(dst_dir):
os.mkdir(dst_dir)
shutil.copyfile(from_file, to_file)
print('cp %s -> %s' % (from_file, to_file))
def apply_fixtures():
from django.core.management import execute_from_command_line
from accounts_app.models import UserProfile
# from django.contrib.auth import models
UserProfile.objects.filter(username='AnonymousUser').delete()
# print('clearing auth.group')
# models.Group.objects.all().delete()
# print('clearing auth.permission')
# models.Permission.objects.all().delete()
fixtures_names = [
'groups_fixture.json', 'tariffs_fixture.json', 'photos_fixture.json',
'devs_fixture.json', 'accounts_fixture.json', 'abon_fixture.json',
'chatbot_fixture.json', 'map_fixture.json', 'task_fixture.json'
]
# 'auth_fixture.json', 'guardian_fixture.json'
print('./manage.py loaddata ' + ', '.join(fixtures_names))
execute_from_command_line([sys.argv[0], 'loaddata'] + fixtures_names)
if __name__ == '__main__':
if len(sys.argv) < 2:
print('Usage: ./migrate_to_0.2.py [makedump OR applydump]')
exit(1)
choice = sys.argv[1]
if choice == 'applydump':
django.setup()
move_to_fixtures_dirs()
apply_fixtures()
shutil.rmtree('fixtures')
elif choice == 'makedump':
django.setup()
make_migration()
else:
print('Unexpected choice')

187
mydefs.py

@ -1,187 +0,0 @@
# -*- coding: utf-8 -*-
from datetime import timedelta
from json import dumps
import socket
import struct
from collections import Iterator
from functools import wraps
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.shortcuts import redirect
from django.db import models
from django.conf import settings
DEBUG = getattr(settings, 'DEBUG', False)
def ip2int(addr):
try:
return struct.unpack("!I", socket.inet_aton(addr))[0]
except:
return 0
def int2ip(addr):
try:
return socket.inet_ntoa(struct.pack("!I", addr))
except:
return ''
def safe_float(fl):
try:
return 0.0 if fl is None or fl == '' else float(fl)
except ValueError:
return 0.0
def safe_int(i):
try:
return 0 if i is None or i == '' else int(i)
except ValueError:
return 0
def res_success(request, redirect_to='/'):
if request.is_ajax():
return HttpResponse(dumps({'errnum': 0}))
else:
return redirect(redirect_to)
def res_error(request, text):
if request.is_ajax():
return HttpResponse(dumps({'errnum': 1, 'errtext': text}))
else:
raise Http404(text)
class MyGenericIPAddressField(models.GenericIPAddressField):
description = "Int32 notation ip address"
def __init__(self, protocol='ipv4', *args, **kwargs):
super(MyGenericIPAddressField, self).__init__(protocol=protocol, *args, **kwargs)
self.max_length = 8
def get_prep_value(self, value):
# strIp to Int
value = super(MyGenericIPAddressField, self).get_prep_value(value)
return ip2int(value)
def to_python(self, value):
return value
def get_internal_type(self):
return 'PositiveIntegerField'
@staticmethod
def from_db_value(value, expression, connection, context):
return int2ip(value) if value != 0 else None
def int_ip(self):
return ip2int(self)
# Предназначен для Django CHOICES чтоб можно было передавать классы вместо просто описания поля,
# классы передавать для того чтоб по значению кода из базы понять какой класс нужно взять для нужной функциональности.
# Например по коду в базе вам нужно определять как считать тариф абонента, что реализовано в возвращаемом классе.
class MyChoicesAdapter(Iterator):
chs = tuple()
current_index = 0
_max_index = 0
# На вход принимает кортеж кортежей, вложенный из 2х элементов: кода и класса, как: TARIFF_CHOICES
def __init__(self, choices):
self._max_index = len(choices)
self.chs = choices
def __next__(self):
if self.current_index >= self._max_index:
raise StopIteration
else:
e = self.chs
ci = self.current_index
res = e[ci][0], e[ci][1].description()
self.current_index += 1
return res
# Декоратор проверяет аккаунт, чтоб не пускать клиентов в страницы администрации
def only_admins(fn):
@wraps(fn)
def wrapped(request, *args, **kwargs):
if request.user.is_admin:
return fn(request, *args, **kwargs)
else:
return redirect('client_side:home')
return wrapped
# Русифицированный вывод timedelta
class RuTimedelta(timedelta):
def __new__(cls, tm):
if isinstance(tm, timedelta):
return timedelta.__new__(
cls,
days=tm.days,
seconds=tm.seconds,
microseconds=tm.microseconds
)
def __str__(self):
# hours, remainder = divmod(self.seconds, 3600)
# minutes, seconds = divmod(remainder, 60)
# text_date = "%d:%d" % (
# hours,
# minutes
# )
if self.days > 1:
ru_days = 'дней'
if 5 > self.days > 1:
ru_days = 'дня'
elif self.days == 1:
ru_days = 'день'
# text_date = '%d %s %s' % (self.days, ru_days, text_date)
text_date = '%d %s' % (self.days, ru_days)
else:
text_date = ''
return text_date
def require_ssl(view):
"""
Decorator that requires an SSL connection. If the current connection is not SSL, we redirect to the SSL version of
the page.
from: https://gist.github.com/ckinsey/9709984
"""
@wraps(view)
def wrapper(request, *args, **kwargs):
if not DEBUG and not request.is_secure():
target_url = "https://" + request.META['HTTP_HOST'] + request.path_info
return HttpResponseRedirect(target_url)
return view(request, *args, **kwargs)
return wrapper
class MultipleException(Exception):
def __init__(self, err_list):
if not isinstance(err_list, (list, tuple)):
raise TypeError
self.err_list = err_list
class LogicError(Exception):
pass
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance

18
static/css/custom.css

@ -110,7 +110,7 @@ td.btn-group {
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
border-bottom: 1px solid #ddd;
border-radius: 0px 0px 5px 5px;
border-radius: 0 0 5px 5px;
padding: 10px;
}
@ -209,8 +209,7 @@ a.port-img{
left: 0;
}
.row-offcanvas-left
.sidebar-offcanvas {
.row-offcanvas-left .sidebar-offcanvas {
left: -50%; /* 6 columns */
}
@ -299,3 +298,16 @@ pre {
.m-icon_dollar{background-position: 0 -52px;}
.m-icon_service{background-position: -26px -52px;}
.m-icon_mrk{background-position: -52px -52px;}
@media (max-width: 991px) and (min-width: 768px){
.container {
width: 874px;
}
}
/* Icon near to device info */
.font-extra-large{
font-size: 75px;
}
Loading…
Cancel
Save