diff --git a/abonapp/views.py b/abonapp/views.py
index 51a5b16..b4a9bf9 100644
--- a/abonapp/views.py
+++ b/abonapp/views.py
@@ -30,16 +30,11 @@ from guardian.shortcuts import get_objects_for_user, assign_perm
from guardian.decorators import permission_required_or_403 as permission_required
from djing import ping
from djing import lib
-from djing.global_base_views import OrderingMixin, BaseListWithFiltering, SecureApiView
-
-
-class BaseAbonListView(OrderingMixin, BaseListWithFiltering):
- paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
- http_method_names = ('get',)
+from djing.global_base_views import BaseOrderedFilteringList, SecureApiView
@method_decorator((login_required, lib.decorators.only_admins), name='dispatch')
-class PeoplesListView(BaseAbonListView):
+class PeoplesListView(BaseOrderedFilteringList):
context_object_name = 'peoples'
template_name = 'abonapp/peoples.html'
@@ -84,7 +79,7 @@ class PeoplesListView(BaseAbonListView):
@method_decorator((login_required, lib.decorators.only_admins), name='dispatch')
-class GroupListView(BaseAbonListView):
+class GroupListView(BaseOrderedFilteringList):
context_object_name = 'groups'
template_name = 'abonapp/group_list.html'
queryset = Group.objects.annotate(usercount=Count('abon'))
@@ -212,7 +207,7 @@ def abonamount(request, gid, uname):
@method_decorator((login_required, lib.decorators.only_admins), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
-class DebtsListView(BaseAbonListView):
+class DebtsListView(BaseOrderedFilteringList):
context_object_name = 'invoices'
template_name = 'abonapp/invoiceForPayment.html'
@@ -230,7 +225,7 @@ class DebtsListView(BaseAbonListView):
@method_decorator((login_required, lib.decorators.only_admins), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
-class PayHistoryListView(BaseAbonListView):
+class PayHistoryListView(BaseOrderedFilteringList):
context_object_name = 'pay_history'
template_name = 'abonapp/payHistory.html'
@@ -756,7 +751,7 @@ def abon_ping(request):
@method_decorator((login_required, lib.decorators.only_admins,), name='dispatch')
-class DialsListView(BaseAbonListView):
+class DialsListView(BaseOrderedFilteringList):
context_object_name = 'logs'
template_name = 'abonapp/dial_log.html'
diff --git a/agent/commands/dhcp.py b/agent/commands/dhcp.py
index 92051a8..92fc7b5 100644
--- a/agent/commands/dhcp.py
+++ b/agent/commands/dhcp.py
@@ -9,7 +9,7 @@ def dhcp_commit(client_ip: str, client_mac: str, switch_mac: str, switch_port: i
dev = Device.objects.get(mac_addr=switch_mac)
mngr_class = dev.get_manager_klass()
- if mngr_class.is_use_device_port():
+ if mngr_class.get_is_use_device_port():
abon = Abon.objects.get(dev_port__device=dev,
dev_port__num=switch_port,
device=dev)
diff --git a/devapp/base_intr.py b/devapp/base_intr.py
index 3b63998..0345527 100644
--- a/devapp/base_intr.py
+++ b/devapp/base_intr.py
@@ -5,15 +5,13 @@ from easysnmp import Session
from django.utils.translation import gettext
-from djing.lib.decorators import abstract_static_method
-
ListOrError = Union[
Iterable,
Union[Exception, Iterable]
]
-class DeviceImplementationError(Exception):
+class DeviceImplementationError(NotImplementedError):
pass
@@ -25,10 +23,15 @@ class DevBase(object, metaclass=ABCMeta):
def __init__(self, dev_instance=None):
self.db_instance = dev_instance
- @abstract_static_method
- def description() -> AnyStr:
+ @property
+ @abstractmethod
+ def description(self) -> AnyStr:
pass
+ @classmethod
+ def get_description(cls):
+ return cls.description
+
@abstractmethod
def reboot(self):
pass
@@ -49,23 +52,29 @@ class DevBase(object, metaclass=ABCMeta):
def get_template_name(self) -> AnyStr:
"""Return path to html template for device"""
+ @property
@abstractmethod
def has_attachable_to_subscriber(self) -> bool:
"""Can connect device to subscriber"""
- @abstract_static_method
- def is_use_device_port() -> bool:
+ @property
+ @abstractmethod
+ def is_use_device_port(self) -> bool:
"""True if used device port while opt82 authorization"""
- # fixme: only that is abstract static
- @abstract_static_method
- def validate_extra_snmp_info(v: str) -> None:
+ @classmethod
+ def get_is_use_device_port(cls) -> bool:
+ return cls.is_use_device_port
+
+ @classmethod
+ def validate_extra_snmp_info(cls, v: str) -> None:
"""
Validate extra snmp field for each device.
If validation failed then raise en exception from djing.lib.tln.ValidationError
with description of error.
:param v: String value for validate
"""
+ raise NotImplementedError
@abstractmethod
def register_device(self, extra_data: Dict):
diff --git a/devapp/dev_types.py b/devapp/dev_types.py
index 7baf5e0..ee07a11 100644
--- a/devapp/dev_types.py
+++ b/devapp/dev_types.py
@@ -60,14 +60,14 @@ class DLinkPort(BasePort):
class DLinkDevice(DevBase, SNMPBaseWorker):
+ has_attachable_to_subscriber = True
+ description = _('DLink switch')
+ is_use_device_port = True
+
def __init__(self, dev_instance):
DevBase.__init__(self, dev_instance)
SNMPBaseWorker.__init__(self, dev_instance.ip_address, dev_instance.man_passw, 2)
- @staticmethod
- def description():
- return _('DLink switch')
-
def reboot(self):
return self.get_item('.1.3.6.1.4.1.2021.8.1.101.1')
@@ -103,15 +103,8 @@ class DLinkDevice(DevBase, SNMPBaseWorker):
def get_template_name(self):
return 'ports.html'
- def has_attachable_to_subscriber(self) -> bool:
- return True
-
- @staticmethod
- def is_use_device_port():
- return True
-
- @staticmethod
- def validate_extra_snmp_info(v: str) -> None:
+ @classmethod
+ def validate_extra_snmp_info(cls, v: str) -> None:
# Dlink has no require snmp info
pass
@@ -142,14 +135,14 @@ class ONUdev(BasePort):
class OLTDevice(DevBase, SNMPBaseWorker):
+ has_attachable_to_subscriber = False
+ description = _('PON OLT')
+ is_use_device_port = False
+
def __init__(self, dev_instance):
DevBase.__init__(self, dev_instance)
SNMPBaseWorker.__init__(self, dev_instance.ip_address, dev_instance.man_passw, 2)
- @staticmethod
- def description():
- return gettext('PON OLT')
-
def reboot(self):
pass
@@ -187,15 +180,8 @@ class OLTDevice(DevBase, SNMPBaseWorker):
def get_template_name(self):
return 'olt.html'
- def has_attachable_to_subscriber(self) -> bool:
- return False
-
- @staticmethod
- def is_use_device_port():
- return False
-
- @staticmethod
- def validate_extra_snmp_info(v: str) -> None:
+ @classmethod
+ def validate_extra_snmp_info(cls, v: str) -> None:
# Olt has no require snmp info
pass
@@ -208,6 +194,10 @@ class OLTDevice(DevBase, SNMPBaseWorker):
class OnuDevice(DevBase, SNMPBaseWorker):
+ has_attachable_to_subscriber = True
+ description = _('PON ONU')
+ is_use_device_port = False
+
def __init__(self, dev_instance):
DevBase.__init__(self, dev_instance)
dev_ip_addr = None
@@ -223,15 +213,11 @@ class OnuDevice(DevBase, SNMPBaseWorker):
))
SNMPBaseWorker.__init__(self, dev_ip_addr, dev_instance.man_passw, 2)
- @staticmethod
- def description() -> AnyStr:
- return gettext('PON ONU')
-
def reboot(self):
pass
def get_ports(self) -> ListOrError:
- return []
+ return ()
def get_device_name(self):
pass
@@ -242,13 +228,6 @@ class OnuDevice(DevBase, SNMPBaseWorker):
def get_template_name(self):
return "onu.html"
- def has_attachable_to_subscriber(self) -> bool:
- return True
-
- @staticmethod
- def is_use_device_port():
- return False
-
def get_details(self):
if self.db_instance is None:
return
@@ -274,7 +253,7 @@ class OnuDevice(DevBase, SNMPBaseWorker):
return {'err': "%s: %s" % (_('ONU not connected'), e)}
@staticmethod
- def validate_extra_snmp_info(v: str) -> None:
+ def validate_extra_snmp_info(cls, v: str) -> None:
# DBCOM Onu have en integer snmp port
try:
int(v)
@@ -330,9 +309,8 @@ class EltexPort(BasePort):
class EltexSwitch(DLinkDevice):
- @staticmethod
- def description():
- return _('Eltex switch')
+ description = _('Eltex switch')
+ is_use_device_port = False
def get_ports(self) -> ListOrError:
res = []
@@ -355,13 +333,6 @@ class EltexSwitch(DLinkDevice):
tm = RuTimedelta(timedelta(seconds=uptimestamp / 100)) or RuTimedelta(timedelta())
return tm
- def has_attachable_to_subscriber(self) -> bool:
- return True
-
- @staticmethod
- def is_use_device_port():
- return False
-
def monitoring_template(self, *args, **kwargs) -> Optional[str]:
device = self.db_instance
return plain_ip_device_mon_template(device)
@@ -378,9 +349,7 @@ def conv_signal(lvl: int) -> float:
class Olt_ZTE_C320(OLTDevice):
- @staticmethod
- def description():
- return gettext('OLT ZTE C320')
+ description = _('OLT ZTE C320')
def get_fibers(self):
fibers = ({
@@ -443,9 +412,7 @@ class Olt_ZTE_C320(OLTDevice):
class ZteOnuDevice(OnuDevice):
- @staticmethod
- def description():
- return _('ZTE PON ONU')
+ description = _('ZTE PON ONU')
def get_details(self) -> Optional[Dict]:
if self.db_instance is None:
@@ -472,8 +439,8 @@ class ZteOnuDevice(OnuDevice):
def get_template_name(self):
return 'onu_for_zte.html'
- @staticmethod
- def validate_extra_snmp_info(v: str) -> None:
+ @classmethod
+ def validate_extra_snmp_info(cls, v: str) -> None:
# for example 268501760.5
try:
fiber_num, onu_port = v.split('.')
diff --git a/devapp/models.py b/devapp/models.py
index 2b6575f..7933583 100644
--- a/devapp/models.py
+++ b/devapp/models.py
@@ -90,8 +90,8 @@ class Device(models.Model):
# Can attach device to subscriber in subscriber page
def has_attachable_to_subscriber(self) -> bool:
- mngr = self.get_manager_object()
- return mngr.has_attachable_to_subscriber()
+ mngr = self.get_manager_klass()
+ return mngr.has_attachable_to_subscriber
def __str__(self):
return "%s: (%s) %s %s" % (self.comment, self.get_devtype_display(), self.ip_address or '', self.mac_addr or '')
diff --git a/devapp/views.py b/devapp/views.py
index 73a5c87..f1adfec 100644
--- a/devapp/views.py
+++ b/devapp/views.py
@@ -650,7 +650,7 @@ class OnDeviceMonitoringEvent(global_base_views.SecureApiView):
recipients = UserProfile.objects.get_profiles_by_group(device_down.group.pk)
names = list()
- for recipient in recipients:
+ for recipient in recipients.iterator():
send_notify(
msg_text=gettext(notify_text) % {
'device_name': "%s(%s) %s" % (
diff --git a/djing/lib/__init__.py b/djing/lib/__init__.py
index 0442c0a..199547e 100644
--- a/djing/lib/__init__.py
+++ b/djing/lib/__init__.py
@@ -38,24 +38,16 @@ def safe_int(i):
# классы передавать для того чтоб по значению кода из базы понять какой класс нужно взять для нужной функциональности.
# Например по коду в базе вам нужно определять как считать тариф абонента, что реализовано в возвращаемом классе.
class MyChoicesAdapter(Iterator):
- chs = tuple()
- current_index = 0
- _max_index = 0
+ _chs = None
# На вход принимает кортеж кортежей, вложенный из 2х элементов: кода и класса, как: TARIFF_CHOICES
def __init__(self, choices):
- self._max_index = len(choices)
- self.chs = choices
+ self._chs = iter(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
+ obj = next(self._chs)
+ choice_code, choice_class = obj
+ return choice_code, choice_class.get_description()
# Russian localized timedelta
diff --git a/djing/lib/decorators.py b/djing/lib/decorators.py
index 2c0d49d..2a69fed 100644
--- a/djing/lib/decorators.py
+++ b/djing/lib/decorators.py
@@ -55,13 +55,3 @@ def hash_auth_view(fn):
else:
return HttpResponseForbidden('Access Denied')
return wrapped
-
-
-class abstract_static_method(staticmethod):
- __slots__ = ()
-
- def __init__(self, func):
- super(abstract_static_method, self).__init__(func)
- func.__isabstractmethod__ = True
-
- __isabstractmethod__ = True
diff --git a/docs/dev.md b/docs/dev.md
index b9f728e..09ca0ec 100644
--- a/docs/dev.md
+++ b/docs/dev.md
@@ -47,10 +47,9 @@ class EltexPort(BasePort):
Теперь реализация для свича:
```python
class EltexSwitch(DLinkDevice):
-
- @staticmethod
- def description():
- return _('Eltex switch')
+ has_attachable_to_subscriber = False
+ description = _('Eltex switch')
+ is_use_device_port = False
def get_ports(self):
#nams = self.get_list('.1.3.6.1.4.1.171.10.134.2.1.1.100.2.1.3')
@@ -77,14 +76,8 @@ class EltexSwitch(DLinkDevice):
tm = RuTimedelta(timedelta(seconds=uptimestamp/100)) or RuTimedelta(timedelta())
return tm
- def has_attachable_to_subscriber(self) -> bool:
- return False
-
- @staticmethod
- def is_use_device_port():
- return False
```
-Метод **@description** Просто отображает человекопонятное название вашего устройства в биллинге.
+Свойство **@description** Просто отображает человекопонятное название вашего устройства в биллинге.
Заметьте что строка на английском и заключена в процедуру **_** (это ugettext_lazy, см. в импорте вверху файла),
это локализация для текущего языка. Про локализацию можно почитать в соответствующем разделе [django translation](https://docs.djangoproject.com/en/1.11/topics/i18n/translation/).
@@ -98,11 +91,11 @@ class EltexSwitch(DLinkDevice):
Метод **@uptime**, понятно что возвращает, укажите нужный OID. Вернётся тип *RuTimedelta*, это переопределённый тип **timedelta**, я его реализовал
для локализации временного промежутка на русский.
-Метод **@has_attachable_to_subscriber** возвращает правду если это устройство можно привязать к абоненту.
+Свойство **@has_attachable_to_subscriber** возвращает правду если это устройство можно привязать к абоненту.
Например у Dlink стоит True потому что Dlink стоит во многих местах на доступе, и его порты принадлежат
абонентам при авторизации.
-Статический метод **@is_use_device_port** используется в DHCP чтоб понять что мы используем для привязки к абоненту всё устройство или
+Свойство **@is_use_device_port** используется в DHCP чтоб понять что мы используем для привязки к абоненту всё устройство или
только порт устройства. Например, если у устройства только 1 порт абонента (PON ONU), и мы привязываем этого абонента ко всему устройству
а не к порту, то нужно вернуть False, На обычных свичах где мы авторизуем абонента на порту возвращаем True.
diff --git a/ip_pool/templates/ip_pool/net_add.html b/ip_pool/templates/ip_pool/net_add.html
index 3dbb6cd..6fb8450 100644
--- a/ip_pool/templates/ip_pool/net_add.html
+++ b/ip_pool/templates/ip_pool/net_add.html
@@ -11,6 +11,8 @@
{% endblock %}
+{% block page-header %}{% trans 'Add new subnet' %}{% endblock %}
+
{% block main %}