diff --git a/devapp/dev_types.py b/devapp/dev_types.py index 7dda24e..c6c46c7 100644 --- a/devapp/dev_types.py +++ b/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' diff --git a/devapp/migrations/0003_auto_20180529_1311.py b/devapp/migrations/0003_auto_20180529_1311.py new file mode 100644 index 0000000..747c845 --- /dev/null +++ b/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) + ] diff --git a/devapp/models.py b/devapp/models.py index abf87c5..24e5066 100644 --- a/devapp/models.py +++ b/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')), diff --git a/devapp/templates/devapp/add_dev.html b/devapp/templates/devapp/add_dev.html index 793f829..30fbb9c 100644 --- a/devapp/templates/devapp/add_dev.html +++ b/devapp/templates/devapp/add_dev.html @@ -63,7 +63,7 @@ {% 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 %} diff --git a/devapp/templates/devapp/custom_dev_page/olt_ztec320_ports.html b/devapp/templates/devapp/custom_dev_page/olt_ztec320_ports.html index 19c6db0..adfaf39 100644 --- a/devapp/templates/devapp/custom_dev_page/olt_ztec320_ports.html +++ b/devapp/templates/devapp/custom_dev_page/olt_ztec320_ports.html @@ -42,7 +42,7 @@ {{ onu.onu_signal }} {{ onu.onu_sn }} - + diff --git a/devapp/templates/devapp/custom_dev_page/onu.html b/devapp/templates/devapp/custom_dev_page/onu.html index 6e93877..ae164fe 100644 --- a/devapp/templates/devapp/custom_dev_page/onu.html +++ b/devapp/templates/devapp/custom_dev_page/onu.html @@ -31,9 +31,10 @@ {% if dev.parent_dev %}
  • {% with pdev=dev.parent_dev pdgrp=dev.parent_dev.group %} - {% trans 'Parent device' %}:{{ pdev.ip_address|default:'-' }} {{ pdev.comment }} + {% trans 'Parent device' %}: + + {{ pdev.ip_address|default:'-' }} {{ pdev.comment }} + {% endwith %}
  • {% endif %} @@ -51,20 +52,20 @@ {% if onu_details %} {% if onu_details.err %}
    -
    +
    {% trans 'ONU error' %}: {{ onu_details.err }}
    {% else %}
    -
    +
    {% if onu_details.status == '3' %} - + {% elif onu_details.status == '2' %} - + {% else %} - + {% endif %}
    @@ -76,7 +77,7 @@ {% trans 'Mac on OLT' %}: {{ onu_details.mac }}

    - + diff --git a/devapp/templates/devapp/custom_dev_page/onu_for_zte.html b/devapp/templates/devapp/custom_dev_page/onu_for_zte.html new file mode 100644 index 0000000..49317c6 --- /dev/null +++ b/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 %} +
    +
    +
    +
    +
    {{ dev.get_devtype_display|default:_('Title of the type of switch') }}. + {% if uptime %} + {% trans 'Uptime' %} {{ uptime }} + {% endif %} +
    +
    +
    +
      +
    • {% trans 'Ip address' %}: {{ dev.ip_address|default:'-' }}
    • +
    • {% trans 'Mac' %}: {{ dev.mac_addr }}
    • +
    • {% trans 'Description' %}: {{ dev.comment }}
    • + {% for da in dev_accs %} +
    • {% trans 'Attached user' %}: + {% if da.group %} + {{ da.get_full_name }} + {% else %} + {{ da.get_full_name }} + {% endif %} +
    • + {% endfor %} + {% if dev.parent_dev %} +
    • + {% with pdev=dev.parent_dev pdgrp=dev.parent_dev.group %} + {% trans 'Parent device' %}: + + {{ pdev.ip_address|default:'-' }} {{ pdev.comment }} + + {% endwith %} +
    • + {% endif %} +
    +
    +
    +
    +
    +
    +
    +

    {% trans 'ONU Status' %}

    +
    + +
    + {% if onu_details %} + {% if onu_details.err %} +
    +
    +
    +
    + {% trans 'ONU error' %}: {{ onu_details.err }}
    +
    + {% else %} +
    +
    + {% if onu_details.status == '1' %} + + {% elif onu_details.status == '2' %} + + {% else %} + + {% endif %} +
    +
    + + {% trans 'Name on OLT' %}: {{ onu_details.name }}
    + {% trans 'Distance(m)' %}: {{ onu_details.distance }}
    + {% trans 'Signal' %}: {{ onu_details.signal }}
    + +
    +
    + {% endif %} + {% else %} +

    {% trans 'Info does not fetch' %}

    + {% endif %} +
    +
    +
    +
    + +{% endwith %} +{% endblock %} diff --git a/devapp/templates/devapp/dev.html b/devapp/templates/devapp/dev.html index 3910334..31f2f9d 100644 --- a/devapp/templates/devapp/dev.html +++ b/devapp/templates/devapp/dev.html @@ -52,7 +52,7 @@
    {% 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 %} diff --git a/devapp/views.py b/devapp/views.py index 44afebb..5417e75 100644 --- a/devapp/views.py +++ b/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 = ' ' % _('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" ) diff --git a/djing/auth_backends.py b/djing/lib/auth_backends.py similarity index 100% rename from djing/auth_backends.py rename to djing/lib/auth_backends.py diff --git a/migrate_to_0.2.py b/migrate_to_0.2.py deleted file mode 100755 index a2edee8..0000000 --- a/migrate_to_0.2.py +++ /dev/null @@ -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') diff --git a/mydefs.py b/mydefs.py deleted file mode 100644 index d885fa0..0000000 --- a/mydefs.py +++ /dev/null @@ -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 diff --git a/static/css/custom.css b/static/css/custom.css index 4e12389..3903f00 100644 --- a/static/css/custom.css +++ b/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; +}