Browse Source

Make registration button

devel
bashmak 8 years ago
parent
commit
d033dbf8d8
  1. 4
      abonapp/migrations/0001_initial.py
  2. 3
      abonapp/models.py
  3. 13
      devapp/base_intr.py
  4. 52
      devapp/dev_types.py
  5. 2
      devapp/forms.py
  6. 11
      devapp/locale/ru/LC_MESSAGES/django.po
  7. 2
      devapp/migrations/0001_initial.py
  8. 2
      devapp/migrations/0002_auto_20180409_1318.py
  9. 19
      devapp/models.py
  10. 3
      devapp/templates/devapp/dev.html
  11. 3
      devapp/urls.py
  12. 30
      devapp/views.py
  13. 28
      djing/fields.py
  14. 53
      djing/lib/__init__.py
  15. 2
      djing/lib/tln/__init__.py
  16. 3
      djing/lib/tln/tln.py
  17. 5
      docs/dev.md
  18. 2
      statistics/migrations/0001_initial.py
  19. 2
      statistics/models.py

4
abonapp/migrations/0001_initial.py

@ -7,7 +7,7 @@ from django.conf import settings
import django.core.validators import django.core.validators
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
from djing import lib
from djing.fields import MyGenericIPAddressField
import re import re
@ -30,7 +30,7 @@ class Migration(migrations.Migration):
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='accounts_app.BaseAccount')), primary_key=True, serialize=False, to='accounts_app.BaseAccount')),
('ballance', models.FloatField(default=0.0)), ('ballance', models.FloatField(default=0.0)),
('ip_address', lib.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4')),
('ip_address', MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4')),
('description', models.TextField(blank=True, null=True, verbose_name='Comment')), ('description', models.TextField(blank=True, null=True, verbose_name='Comment')),
('house', models.CharField(blank=True, max_length=12, null=True, verbose_name='House')), ('house', models.CharField(blank=True, max_length=12, null=True, verbose_name='House')),
('is_dynamic_ip', models.BooleanField(default=False)), ('is_dynamic_ip', models.BooleanField(default=False)),

3
abonapp/models.py

@ -14,7 +14,8 @@ from django.utils.translation import ugettext_lazy as _, gettext
from accounts_app.models import UserProfile, MyUserManager, BaseAccount from accounts_app.models import UserProfile, MyUserManager, BaseAccount
from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNetworkError from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNetworkError
from group_app.models import Group from group_app.models import Group
from djing.lib import ip2int, MyGenericIPAddressField, LogicError
from djing.lib import ip2int, LogicError
from djing.fields import MyGenericIPAddressField
from djing import IP_ADDR_REGEX from djing import IP_ADDR_REGEX
from tariff_app.models import Tariff, PeriodicPay from tariff_app.models import Tariff, PeriodicPay
from bitfield import BitField from bitfield import BitField

13
devapp/base_intr.py

@ -45,14 +45,15 @@ class DevBase(object, metaclass=ABCMeta):
def get_template_name(self) -> AnyStr: def get_template_name(self) -> AnyStr:
"""Return path to html template for device""" """Return path to html template for device"""
@abstract_static_method
def has_attachable_to_subscriber() -> bool:
@abstractmethod
def has_attachable_to_subscriber(self) -> bool:
"""Can connect device to subscriber""" """Can connect device to subscriber"""
@abstract_static_method @abstract_static_method
def is_use_device_port() -> bool: def is_use_device_port() -> bool:
"""True if used device port while opt82 authorization""" """True if used device port while opt82 authorization"""
# fixme: only that is abstract static
@abstract_static_method @abstract_static_method
def validate_extra_snmp_info(v: str) -> None: def validate_extra_snmp_info(v: str) -> None:
""" """
@ -62,8 +63,12 @@ class DevBase(object, metaclass=ABCMeta):
:param v: String value for validate :param v: String value for validate
""" """
@abstract_static_method
def monitoring_template(device_instance, *args, **kwargs) -> Optional[str]:
@abstractmethod
def register_device(self):
pass
@abstractmethod
def monitoring_template(self, *args, **kwargs) -> Optional[str]:
""" """
Template for monitoring system config Template for monitoring system config
:return: string for config file :return: string for config file

52
devapp/dev_types.py

@ -6,7 +6,7 @@ from transliterate import translit
from django.utils.translation import gettext_lazy as _, gettext from django.utils.translation import gettext_lazy as _, gettext
from djing.lib import RuTimedelta, safe_int from djing.lib import RuTimedelta, safe_int
from djing.lib.tln.tln import ValidationError as TlnValidationError
from djing.lib.tln.tln import ValidationError as TlnValidationError, register_onu_ZTE_F660
from .base_intr import DevBase, SNMPBaseWorker, BasePort, DeviceImplementationError, ListOrError from .base_intr import DevBase, SNMPBaseWorker, BasePort, DeviceImplementationError, ListOrError
@ -100,8 +100,7 @@ class DLinkDevice(DevBase, SNMPBaseWorker):
def get_template_name(self): def get_template_name(self):
return 'ports.html' return 'ports.html'
@staticmethod
def has_attachable_to_subscriber():
def has_attachable_to_subscriber(self) -> bool:
return True return True
@staticmethod @staticmethod
@ -113,8 +112,8 @@ class DLinkDevice(DevBase, SNMPBaseWorker):
# Dlink has no require snmp info # Dlink has no require snmp info
pass pass
@staticmethod
def monitoring_template(device, *args, **kwargs) -> Optional[str]:
def monitoring_template(self, *args, **kwargs) -> Optional[str]:
device = self.db_instance
return plain_ip_device_mon_template(device, *args, **kwargs) return plain_ip_device_mon_template(device, *args, **kwargs)
@ -182,8 +181,7 @@ class OLTDevice(DevBase, SNMPBaseWorker):
def get_template_name(self): def get_template_name(self):
return 'olt.html' return 'olt.html'
@staticmethod
def has_attachable_to_subscriber():
def has_attachable_to_subscriber(self) -> bool:
return False return False
@staticmethod @staticmethod
@ -195,8 +193,8 @@ class OLTDevice(DevBase, SNMPBaseWorker):
# Olt has no require snmp info # Olt has no require snmp info
pass pass
@staticmethod
def monitoring_template(device, *args, **kwargs) -> Optional[str]:
def monitoring_template(self, *args, **kwargs) -> Optional[str]:
device = self.db_instance
return plain_ip_device_mon_template(device) return plain_ip_device_mon_template(device)
@ -235,8 +233,7 @@ class OnuDevice(DevBase, SNMPBaseWorker):
def get_template_name(self): def get_template_name(self):
return "onu.html" return "onu.html"
@staticmethod
def has_attachable_to_subscriber():
def has_attachable_to_subscriber(self) -> bool:
return True return True
@staticmethod @staticmethod
@ -273,8 +270,8 @@ class OnuDevice(DevBase, SNMPBaseWorker):
except ValueError: except ValueError:
raise TlnValidationError(_('Onu snmp field must be en integer')) raise TlnValidationError(_('Onu snmp field must be en integer'))
@staticmethod
def monitoring_template(device, *args, **kwargs) -> Optional[str]:
def monitoring_template(self, *args, **kwargs) -> Optional[str]:
device = self.db_instance
if not device: if not device:
return return
host_name = _norm_name("%d%s" % (device.pk, translit(device.comment, language_code='ru', reversed=True))) host_name = _norm_name("%d%s" % (device.pk, translit(device.comment, language_code='ru', reversed=True)))
@ -344,16 +341,15 @@ class EltexSwitch(DLinkDevice):
tm = RuTimedelta(timedelta(seconds=uptimestamp / 100)) or RuTimedelta(timedelta()) tm = RuTimedelta(timedelta(seconds=uptimestamp / 100)) or RuTimedelta(timedelta())
return tm return tm
@staticmethod
def has_attachable_to_subscriber():
def has_attachable_to_subscriber(self) -> bool:
return True return True
@staticmethod @staticmethod
def is_use_device_port(): def is_use_device_port():
return False return False
@staticmethod
def monitoring_template(device, *args, **kwargs) -> Optional[str]:
def monitoring_template(self, *args, **kwargs) -> Optional[str]:
device = self.db_instance
return plain_ip_device_mon_template(device) return plain_ip_device_mon_template(device)
@ -432,6 +428,9 @@ class Olt_ZTE_C320(OLTDevice):
def get_template_name(self): def get_template_name(self):
return 'olt_ztec320.html' return 'olt_ztec320.html'
def register_device(self):
pass
class ZteOnuDevice(OnuDevice): class ZteOnuDevice(OnuDevice):
@staticmethod @staticmethod
@ -472,8 +471,8 @@ class ZteOnuDevice(OnuDevice):
except ValueError: except ValueError:
raise TlnValidationError(_('Zte onu snmp field must be two dot separated integers')) raise TlnValidationError(_('Zte onu snmp field must be two dot separated integers'))
@staticmethod
def monitoring_template(device, *args, **kwargs) -> Optional[str]:
def monitoring_template(self, *args, **kwargs) -> Optional[str]:
device = self.db_instance
if not device: if not device:
return return
host_name = _norm_name("%d%s" % (device.pk, translit(device.comment, language_code='ru', reversed=True))) host_name = _norm_name("%d%s" % (device.pk, translit(device.comment, language_code='ru', reversed=True)))
@ -495,3 +494,18 @@ class ZteOnuDevice(OnuDevice):
"}\n" "}\n"
) )
return '\n'.join(i for i in r if i) return '\n'.join(i for i in r if i)
def register_device(self):
device = self.db_instance
ip = None
if device.ip_address:
ip = device.ip_address
elif device.parent_dev:
ip = device.parent_dev.ip_address
if ip:
mac = str(device.mac_addr).encode()
sn = b"ZTEG%s" % b''.join(mac.split(b':')[-4:]).upper()
register_onu_ZTE_F660(
olt_ip=ip, onu_sn=sn, login_passwd=(b'admin', b'2ekc3'),
onu_mac=mac
)

2
devapp/forms.py

@ -22,6 +22,8 @@ class DeviceForm(forms.ModelForm):
if snmp_extra is None: if snmp_extra is None:
return return
device = self.instance device = self.instance
# fixme: if creating device than check disabled
if device.pk is not None:
manager_class = device.get_manager_klass() manager_class = device.get_manager_klass()
try: try:
manager_class.validate_extra_snmp_info(snmp_extra) manager_class.validate_extra_snmp_info(snmp_extra)

11
devapp/locale/ru/LC_MESSAGES/django.po

@ -234,7 +234,7 @@ msgstr "Сохранить"
#: templates/devapp/add_dev.html:75 templates/devapp/dev.html:73 #: templates/devapp/add_dev.html:75 templates/devapp/dev.html:73
#: templates/devapp/fix_dev_group.html:67 #: templates/devapp/fix_dev_group.html:67
msgid "Reset" msgid "Reset"
msgstr "Сбросить"
msgstr "Сбросить форму"
#: templates/devapp/custom_dev_page/olt.html:10 #: templates/devapp/custom_dev_page/olt.html:10
#: templates/devapp/custom_dev_page/olt_ztec320.html:11 #: templates/devapp/custom_dev_page/olt_ztec320.html:11
@ -609,3 +609,12 @@ msgstr "Посмотреть"
msgid "Unregistered units" msgid "Unregistered units"
msgstr "Незарегистрированные юниты" msgstr "Незарегистрированные юниты"
msgid "Register device"
msgstr "Зарегистрировать устройство"
msgid "Unregistered onu not found"
msgstr "Незарегистрированные ONU не найдены"
msgid "Process locked by another process"
msgstr "Процесс занят другой задачей, подождите чуть и попробуйте ещё"

2
devapp/migrations/0001_initial.py

@ -5,7 +5,7 @@ from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import djing.fields import djing.fields
from djing.lib import MyGenericIPAddressField
from djing.fields import MyGenericIPAddressField
class Migration(migrations.Migration): class Migration(migrations.Migration):

2
devapp/migrations/0002_auto_20180409_1318.py

@ -3,7 +3,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations from django.db import migrations
from djing.lib import MyGenericIPAddressField
from djing.fields import MyGenericIPAddressField
class Migration(migrations.Migration): class Migration(migrations.Migration):

19
devapp/models.py

@ -5,8 +5,8 @@ from django.db import models
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from djing.fields import MACAddressField
from djing.lib import MyGenericIPAddressField, MyChoicesAdapter
from djing.fields import MACAddressField, MyGenericIPAddressField
from djing.lib import MyChoicesAdapter
from group_app.models import Group from group_app.models import Group
from . import dev_types from . import dev_types
from .base_intr import DevBase from .base_intr import DevBase
@ -84,9 +84,9 @@ class Device(models.Model):
return self._cached_manager return self._cached_manager
# Can attach device to subscriber in subscriber page # Can attach device to subscriber in subscriber page
def has_attachable_to_subscriber(self):
mngr_class = self.get_manager_klass()
return mngr_class.has_attachable_to_subscriber()
def has_attachable_to_subscriber(self) -> bool:
mngr = self.get_manager_object()
return mngr.has_attachable_to_subscriber()
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 '')
@ -106,8 +106,13 @@ class Device(models.Model):
run((filepath, param, newmac, code)) run((filepath, param, newmac, code))
def generate_config_template(self) -> Optional[AnyStr]: def generate_config_template(self) -> Optional[AnyStr]:
mng_class = self.get_manager_klass()
return mng_class.monitoring_template(self)
mng = self.get_manager_object()
return mng.monitoring_template()
def register_device(self):
mng = self.get_manager_object()
# if hasattr(mng, 'register_device') and callable(mng.register_device):
mng.register_device()
class Port(models.Model): class Port(models.Model):

3
devapp/templates/devapp/dev.html

@ -69,6 +69,9 @@
<span class="glyphicon glyphicon-remove"></span> {% trans 'Delete' %} <span class="glyphicon glyphicon-remove"></span> {% trans 'Delete' %}
</a> </a>
{% endif %} {% endif %}
<a href="{% url 'devapp:dev_register' group.pk|default:0 dev.pk %}" class="btn btn-default btn-cmd">
<span class="glyphicon glyphicon-fire"></span> <span class="hidden-xs">{% trans 'Register device' %}</span>
</a>
<button type="reset" class="btn btn-default"> <button type="reset" class="btn btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Reset' %} <span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Reset' %}
</button> </button>

3
devapp/urls.py

@ -18,7 +18,8 @@ urlpatterns = [
name='fix_port_conflict'), name='fix_port_conflict'),
url(r'^(?P<group_id>\d+)/(?P<device_id>\d+)/ports/(?P<port_id>\d+)/show_subscriber_on_port$', url(r'^(?P<group_id>\d+)/(?P<device_id>\d+)/ports/(?P<port_id>\d+)/show_subscriber_on_port$',
views.ShowSubscriberOnPort.as_view(), name='show_subscriber_on_port'), views.ShowSubscriberOnPort.as_view(), name='show_subscriber_on_port'),
url(r'^(\d+)/(?P<device_id>\d+)/ports_add', views.add_ports, name='add_ports'),
url(r'^(\d+)/(?P<device_id>\d+)/ports_add/$', views.add_ports, name='add_ports'),
url(r'^(\d+)/(?P<device_id>\d+)/regster_device/$', views.regster_device, name='dev_register'),
url(r'^(\d+)/(?P<device_id>\d+)/(?P<portid>\d+)_(?P<status>[0-1]{1})$', views.toggle_port, name='port_toggle'), url(r'^(\d+)/(?P<device_id>\d+)/(?P<portid>\d+)_(?P<status>[0-1]{1})$', views.toggle_port, name='port_toggle'),
url(r'^(?P<group_id>\d+)/(?P<device_id>\d+)/(?P<portid>\d+)/del$', views.delete_single_port, name='del_port'), url(r'^(?P<group_id>\d+)/(?P<device_id>\d+)/(?P<portid>\d+)/del$', views.delete_single_port, name='del_port'),
url(r'^(?P<group_id>\d+)/(?P<device_id>\d+)/(?P<port_id>\d+)/edit$', views.edit_single_port, name='edit_port'), url(r'^(?P<group_id>\d+)/(?P<device_id>\d+)/(?P<port_id>\d+)/edit$', views.edit_single_port, name='edit_port'),

30
devapp/views.py

@ -14,8 +14,9 @@ from django.views.generic import DetailView, DeleteView, UpdateView, CreateView
from devapp.base_intr import DeviceImplementationError from devapp.base_intr import DeviceImplementationError
from djing.lib.decorators import only_admins, hash_auth_view from djing.lib.decorators import only_admins, hash_auth_view
from djing.lib import safe_int
from djing.lib import safe_int, ProcessLocked
from abonapp.models import Abon from abonapp.models import Abon
from djing.lib.tln import ZteOltConsoleError, OnuZteRegisterError
from group_app.models import Group from group_app.models import Group
from accounts_app.models import UserProfile from accounts_app.models import UserProfile
from django.conf import settings from django.conf import settings
@ -693,3 +694,30 @@ class DevicesGetListView(global_base_views.SecureApiView):
if isinstance(r['mac_addr'], EUI): if isinstance(r['mac_addr'], EUI):
r['mac_addr'] = int(r['mac_addr']) r['mac_addr'] = int(r['mac_addr'])
return tuple(res) return tuple(res)
@login_required
@json_view
def regster_device(request, device_id: str):
def format_msg(msg: str, icon: str):
return ' '.join((
'<span class="glyphicon glyphicon-%s"></span>' % icon,
'<span class="hidden-xs">%s</span>' % msg
))
device = get_object_or_404(Device, pk=device_id)
status = 1
try:
device.register_device()
status = 0
except OnuZteRegisterError:
text = format_msg(gettext('Unregistered onu not found'), 'eye-close')
except (ConnectionRefusedError, ZteOltConsoleError) as e:
text = format_msg(e, 'exclamation-sign')
except ProcessLocked:
text = format_msg(gettext('Process locked by another process'), 'time')
else:
text = format_msg(msg='ok', icon='ok')
return {
'status': status,
'dat': text
}

28
djing/fields.py

@ -4,6 +4,8 @@
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from netaddr import EUI, AddrFormatError from netaddr import EUI, AddrFormatError
from djing.lib import ip2int, int2ip
from .formfields import MACAddressField as MACAddressFormField from .formfields import MACAddressField as MACAddressFormField
from . import default_dialect from . import default_dialect
import warnings import warnings
@ -107,3 +109,29 @@ try:
add_introspection_rules([], ["^macaddress\.fields\.MACAddressField"]) add_introspection_rules([], ["^macaddress\.fields\.MACAddressField"])
except ImportError: except ImportError:
pass pass
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)

53
djing/lib/__init__.py

@ -1,9 +1,9 @@
import socket import socket
import struct import struct
from functools import wraps
from hashlib import sha256 from hashlib import sha256
from datetime import timedelta from datetime import timedelta
from collections import Iterator from collections import Iterator
from django.db import models
def ip2int(addr): def ip2int(addr):
@ -34,32 +34,6 @@ def safe_int(i):
return 0 return 0
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 чтоб можно было передавать классы вместо просто описания поля, # Предназначен для Django CHOICES чтоб можно было передавать классы вместо просто описания поля,
# классы передавать для того чтоб по значению кода из базы понять какой класс нужно взять для нужной функциональности. # классы передавать для того чтоб по значению кода из базы понять какой класс нужно взять для нужной функциональности.
# Например по коду в базе вам нужно определять как считать тариф абонента, что реализовано в возвращаемом классе. # Например по коду в базе вам нужно определять как считать тариф абонента, что реализовано в возвращаемом классе.
@ -151,3 +125,28 @@ def check_sign(get_list, sign):
hashed = '_'.join(get_list) hashed = '_'.join(get_list)
my_sign = calc_hash(hashed) my_sign = calc_hash(hashed)
return sign == my_sign return sign == my_sign
#
# only one process for function
#
class ProcessLocked(OSError):
pass
def process_lock(fn):
@wraps(fn)
def wrapped(*args, **kwargs):
s = None
try:
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
# Create an abstract socket, by prefixing it with null.
s.bind('\0postconnect_djing_lock_func_%s' % fn.__name__)
return fn(*args, **kwargs)
except socket.error:
raise ProcessLocked
finally:
if s is not None:
s.close()
return wrapped

2
djing/lib/tln/__init__.py

@ -1,4 +1,4 @@
from .tln import * from .tln import *
__all__ = ('TelnetApi', 'ValidationError', 'ZTEFiberNumberNotFound', 'ZTEFiberIsFull',
__all__ = ('TelnetApi', 'ValidationError', 'ZTEFiberIsFull',
'OnuZteRegisterError', 'ZteOltConsoleError', 'register_onu_ZTE_F660') 'OnuZteRegisterError', 'ZteOltConsoleError', 'register_onu_ZTE_F660')

3
djing/lib/tln/tln.py

@ -5,6 +5,8 @@ from telnetlib import Telnet
from time import sleep from time import sleep
from typing import Generator, Dict, Optional, Tuple from typing import Generator, Dict, Optional, Tuple
from djing.lib import process_lock
class ZteOltConsoleError(Exception): class ZteOltConsoleError(Exception):
pass pass
@ -192,6 +194,7 @@ class OltZTERegister(TelnetApi):
))) + r ))) + r
@process_lock
def register_onu_ZTE_F660(olt_ip: str, onu_sn: bytes, login_passwd: Tuple[bytes, bytes], onu_mac: bytes): def register_onu_ZTE_F660(olt_ip: str, onu_sn: bytes, login_passwd: Tuple[bytes, bytes], onu_mac: bytes):
onu_type = b'ZTE-F660' onu_type = b'ZTE-F660'
line_profile = b'ZTE-F660-LINE' line_profile = b'ZTE-F660-LINE'

5
docs/dev.md

@ -77,8 +77,7 @@ class EltexSwitch(DLinkDevice):
tm = RuTimedelta(timedelta(seconds=uptimestamp/100)) or RuTimedelta(timedelta()) tm = RuTimedelta(timedelta(seconds=uptimestamp/100)) or RuTimedelta(timedelta())
return tm return tm
@staticmethod
def has_attachable_to_subscriber():
def has_attachable_to_subscriber(self) -> bool:
return False return False
@staticmethod @staticmethod
@ -99,7 +98,7 @@ class EltexSwitch(DLinkDevice):
Метод **@uptime**, понятно что возвращает, укажите нужный OID. Вернётся тип *RuTimedelta*, это переопределённый тип **timedelta**, я его реализовал Метод **@uptime**, понятно что возвращает, укажите нужный OID. Вернётся тип *RuTimedelta*, это переопределённый тип **timedelta**, я его реализовал
для локализации временного промежутка на русский. для локализации временного промежутка на русский.
Статический метод **@has_attachable_to_subscriber** возвращает правду если это устройство можно привязать к абоненту.
Метод **@has_attachable_to_subscriber** возвращает правду если это устройство можно привязать к абоненту.
Например у Dlink стоит True потому что Dlink стоит во многих местах на доступе, и его порты принадлежат Например у Dlink стоит True потому что Dlink стоит во многих местах на доступе, и его порты принадлежат
абонентам при авторизации. абонентам при авторизации.

2
statistics/migrations/0001_initial.py

@ -3,7 +3,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
from djing.lib import MyGenericIPAddressField
from djing.fields import MyGenericIPAddressField
import statistics.fields import statistics.fields

2
statistics/models.py

@ -3,7 +3,7 @@ from datetime import datetime, timedelta, date, time
from django.db import models, connection, ProgrammingError from django.db import models, connection, ProgrammingError
from django.utils.timezone import now from django.utils.timezone import now
from djing.lib import MyGenericIPAddressField
from djing.fields import MyGenericIPAddressField
from .fields import UnixDateTimeField from .fields import UnixDateTimeField

Loading…
Cancel
Save