From 578bffa4d2b6350aff5ae6679678a1df9cf391f4 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Fri, 2 Nov 2018 19:22:28 +0300 Subject: [PATCH 01/46] fix --- abonapp/forms.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/abonapp/forms.py b/abonapp/forms.py index 34f6096..cb53a79 100644 --- a/abonapp/forms.py +++ b/abonapp/forms.py @@ -184,7 +184,10 @@ class AddIpForm(forms.ModelForm): net = NetworkModel.objects.filter(groups=instance.group).first() if net is not None: ips = (ip.ip_address for ip in - models.Abon.objects.filter(group__in=net.groups.all()).order_by('ip_address').only( + models.Abon.objects.filter( + group__in=net.groups.all(), + nas=instance.nas + ).order_by('ip_address').only( 'ip_address').iterator()) free_ip = net.get_free_ip(ips) self.initial['ip_address'] = free_ip From caa24f63b238f516131575d72ed1263e350ac152 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Tue, 4 Dec 2018 10:46:32 +0300 Subject: [PATCH 02/46] more informative ZTE ONU page --- devapp/base_intr.py | 4 ++- devapp/dev_types.py | 20 ++++++++---- devapp/locale/ru/LC_MESSAGES/django.po | 31 +++++++++++-------- .../devapp/custom_dev_page/onu_for_zte.html | 6 ++-- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/devapp/base_intr.py b/devapp/base_intr.py index 5157232..bc080b9 100644 --- a/devapp/base_intr.py +++ b/devapp/base_intr.py @@ -139,4 +139,6 @@ class SNMPBaseWorker(object, metaclass=ABCMeta): def get_item(self, oid): self.start_ses() - return self.ses.get(oid).value + v = self.ses.get(oid).value + if v != 'NOSUCHINSTANCE': + return v diff --git a/devapp/dev_types.py b/devapp/dev_types.py index e4daec4..73156e5 100644 --- a/devapp/dev_types.py +++ b/devapp/dev_types.py @@ -432,18 +432,26 @@ class ZteOnuDevice(OnuDevice): status = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.12.1.1.1.%s.1' % fiber_addr) signal = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.12.1.1.10.%s.1' % fiber_addr) distance = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.12.1.1.18.%s.1' % fiber_addr) - name = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.11.2.1.1.%s' % fiber_addr) ip_addr = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.16.1.1.10.%s' % fiber_addr) vlans = self.get_item('.1.3.6.1.4.1.3902.1012.3.50.15.100.1.1.7.%s.1.1' % fiber_addr) + int_name = self.get_item('.1.3.6.1.4.1.3902.1012.3.28.1.1.3.%s' % fiber_addr) + onu_type = self.get_item('.1.3.6.1.4.1.3902.1012.3.28.1.1.1.%s' % fiber_addr) + + sn = self.get_item('.1.3.6.1.4.1.3902.1012.3.28.1.1.5.%s' % fiber_addr) + # sn = sn.encode() + sn = ''.join('%.2X' % ord(x) for x in sn[-4:]) + return { 'status': status, 'signal': conv_signal(safe_int(signal)), - 'name': name, - 'distance': int(distance) / 10 if distance != 'NOSUCHINSTANCE' else 0, - 'ip_addr': ip_addr if ip_addr != 'NOSUCHINSTANCE' and ip_addr else None, - 'vlans': vlans if vlans != 'NOSUCHINSTANCE' else None + 'distance': int(distance) / 10, + 'ip_addr': ip_addr if ip_addr else None, + 'vlans': vlans, + 'serial': "ZTEG%s" % ''.join(sn), + 'int_name': int_name, + 'onu_type': onu_type } - except ValueError: + except IndexError: pass def get_template_name(self): diff --git a/devapp/locale/ru/LC_MESSAGES/django.po b/devapp/locale/ru/LC_MESSAGES/django.po index 8719acf..9cfa2d7 100644 --- a/devapp/locale/ru/LC_MESSAGES/django.po +++ b/devapp/locale/ru/LC_MESSAGES/django.po @@ -337,7 +337,6 @@ msgid "ONU error" msgstr "ONU ошибка" #: templates/devapp/custom_dev_page/onu.html:72 -#: templates/devapp/custom_dev_page/onu_for_zte.html:75 msgid "Name on OLT" msgstr "Имя на OLT" @@ -642,20 +641,26 @@ msgstr "Не заполнено поле 'Техническая информа msgid "Fiber" msgstr "Интерфейс" -#~ msgid "Device %(device_name)s is up" -#~ msgstr "%(device_name)s в сети" +msgid "Onu type" +msgstr "Тип onu" -#~ msgid "Device %(device_name)s is down" -#~ msgstr "%(device_name)s не в сети" +msgid "Serial" +msgstr "Серийник" -#~ msgid "Device %(device_name)s is unreachable" -#~ msgstr "%(device_name)s недостижим" +msgid "Device %(device_name)s is up" +msgstr "%(device_name)s в сети" -#~ msgid "Device %(device_name)s getting undefined status code" -#~ msgstr "Устройство %(device_name)s получило не определённый код состояния" +msgid "Device %(device_name)s is down" +msgstr "%(device_name)s не в сети" -#~ msgid "View" -#~ msgstr "Посмотреть" +msgid "Device %(device_name)s is unreachable" +msgstr "%(device_name)s недостижим" -#~ msgid "Enter valid JSON" -#~ msgstr "Введите данные в формате JSON" +msgid "Device %(device_name)s getting undefined status code" +msgstr "Устройство %(device_name)s получило не определённый код состояния" + +msgid "View" +msgstr "Посмотреть" + +msgid "Enter valid JSON" +msgstr "Введите данные в формате JSON" diff --git a/devapp/templates/devapp/custom_dev_page/onu_for_zte.html b/devapp/templates/devapp/custom_dev_page/onu_for_zte.html index fa01ee6..c0729a8 100644 --- a/devapp/templates/devapp/custom_dev_page/onu_for_zte.html +++ b/devapp/templates/devapp/custom_dev_page/onu_for_zte.html @@ -73,15 +73,17 @@
- {% trans 'Name on OLT' %}: {{ onu_details.name }}
{% trans 'Distance(m)' %}: {{ onu_details.distance }}
{% trans 'Signal' %}: {{ onu_details.signal }}
{% if onu_details.ip_addr %} {% trans 'Ip addr' %}: {{ onu_details.ip_addr }}
{% endif %} {% if onu_details.vlans %} - {% trans 'VLan list' %}: {{ onu_details.vlans }} + {% trans 'VLan list' %}: {{ onu_details.vlans }}
{% endif %} + {% trans 'Serial' %}: {{ onu_details.serial }}
+ {% trans 'Onu type' %}: {{ onu_details.onu_type }}
+ {% trans 'Name' %}: {{ onu_details.int_name }}
From 8e949e76e90b2062d34f3a3ca0b871b0037c5f14 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 5 Dec 2018 10:32:19 +0300 Subject: [PATCH 03/46] Fix autoconnect service --- periodic.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/periodic.py b/periodic.py index 1d08ce8..c96d018 100755 --- a/periodic.py +++ b/periodic.py @@ -100,7 +100,8 @@ def main(): # connect service when autoconnect is True, and user have enough money for ab in Abon.objects.filter( is_active=True, - current_tariff=None + current_tariff=None, + autoconnect_service=True ).exclude(last_connected_tariff=None).iterator(): try: tariff = ab.last_connected_tariff From 47e4d5e9c3ab5abaf8d9cdb5857c7e46a9c65da0 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Thu, 6 Dec 2018 10:27:01 +0300 Subject: [PATCH 04/46] fix bug --- abonapp/locale/ru/LC_MESSAGES/django.po | 3 +++ devapp/dev_types.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/abonapp/locale/ru/LC_MESSAGES/django.po b/abonapp/locale/ru/LC_MESSAGES/django.po index 2d77f35..758df1c 100644 --- a/abonapp/locale/ru/LC_MESSAGES/django.po +++ b/abonapp/locale/ru/LC_MESSAGES/django.po @@ -1168,3 +1168,6 @@ msgstr "Балланс" msgid "Date joined" msgstr "Дата создания" + +msgid "Update ip address" +msgstr "Обновить ip адрес" diff --git a/devapp/dev_types.py b/devapp/dev_types.py index 73156e5..e1e16b1 100644 --- a/devapp/dev_types.py +++ b/devapp/dev_types.py @@ -161,7 +161,7 @@ class OLTDevice(DevBase, SNMPBaseWorker): status=True if status == '3' else False, mac=self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.3.%d' % n), speed=0, - signal=int(signal) / 10 if signal != 'NOSUCHINSTANCE' else 0, + signal=int(signal or 0), snmp_worker=self) res.append(onu) except EasySNMPTimeoutError as e: @@ -325,7 +325,7 @@ class EltexSwitch(DLinkDevice): self.get_item('.1.3.6.1.2.1.31.1.1.1.18.%d' % n), self.get_item('.1.3.6.1.2.1.2.2.1.8.%d' % n), self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), - int(speed) if speed != 'NOSUCHINSTANCE' else 0, + int(speed or 0), )) return res From 2beaed8325ee5b1453ad42346da410170c8f0213 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 7 Dec 2018 22:12:56 +0000 Subject: [PATCH 05/46] hotfix --- devapp/dev_types.py | 10 +++++----- .../templates/devapp/custom_dev_page/onu_for_zte.html | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/devapp/dev_types.py b/devapp/dev_types.py index 73156e5..05d8a5e 100644 --- a/devapp/dev_types.py +++ b/devapp/dev_types.py @@ -438,16 +438,16 @@ class ZteOnuDevice(OnuDevice): onu_type = self.get_item('.1.3.6.1.4.1.3902.1012.3.28.1.1.1.%s' % fiber_addr) sn = self.get_item('.1.3.6.1.4.1.3902.1012.3.28.1.1.5.%s' % fiber_addr) - # sn = sn.encode() - sn = ''.join('%.2X' % ord(x) for x in sn[-4:]) + if sn is not None: + sn = 'ZTEG%s' % ''.join('%.2X' % ord(x) for x in sn[-4:]) return { 'status': status, 'signal': conv_signal(safe_int(signal)), - 'distance': int(distance) / 10, - 'ip_addr': ip_addr if ip_addr else None, + 'distance': safe_int(distance) / 10, + 'ip_addr': ip_addr, 'vlans': vlans, - 'serial': "ZTEG%s" % ''.join(sn), + 'serial': sn, 'int_name': int_name, 'onu_type': onu_type } diff --git a/devapp/templates/devapp/custom_dev_page/onu_for_zte.html b/devapp/templates/devapp/custom_dev_page/onu_for_zte.html index c0729a8..f7a0d0f 100644 --- a/devapp/templates/devapp/custom_dev_page/onu_for_zte.html +++ b/devapp/templates/devapp/custom_dev_page/onu_for_zte.html @@ -73,7 +73,7 @@
- {% trans 'Distance(m)' %}: {{ onu_details.distance }}
+ {% trans 'Distance(m)' %}: {{ onu_details.distance|default:'-' }}
{% trans 'Signal' %}: {{ onu_details.signal }}
{% if onu_details.ip_addr %} {% trans 'Ip addr' %}: {{ onu_details.ip_addr }}
@@ -81,9 +81,9 @@ {% if onu_details.vlans %} {% trans 'VLan list' %}: {{ onu_details.vlans }}
{% endif %} - {% trans 'Serial' %}: {{ onu_details.serial }}
- {% trans 'Onu type' %}: {{ onu_details.onu_type }}
- {% trans 'Name' %}: {{ onu_details.int_name }} + {% trans 'Serial' %}: {{ onu_details.serial|default:'-' }}
+ {% trans 'Onu type' %}: {{ onu_details.onu_type|default:'-' }}
+ {% trans 'Name' %}: {{ onu_details.int_name|default:'-' }}
From 6e84640d7294be9f2f17f73e796713e93e43bb68 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Tue, 11 Dec 2018 01:25:00 +0300 Subject: [PATCH 06/46] fix --- devapp/dev_types.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/devapp/dev_types.py b/devapp/dev_types.py index bed0c93..5ce3dbd 100644 --- a/devapp/dev_types.py +++ b/devapp/dev_types.py @@ -240,10 +240,12 @@ class OnuDevice(DevBase, SNMPBaseWorker): status = self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.26.%d' % num) signal = self.get_item('.1.3.6.1.4.1.3320.101.10.5.1.5.%d' % num) distance = self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.27.%d' % num) - mac = ':'.join('%x' % ord(i) for i in self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.3.%d' % num)) + mac = self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.3.%d' % num) + if mac is not None: + mac = ':'.join('%x' % ord(i) for i in mac) # uptime = self.get_item('.1.3.6.1.2.1.2.2.1.9.%d' % num) signal = safe_int(signal) - if status.isdigit(): + if status is not None and status.isdigit(): return { 'status': status, 'signal': signal / 10 if signal != 0 else 0, From db4666915a41c331a419174b81c206083a850e46 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 17 Dec 2018 12:27:14 +0300 Subject: [PATCH 07/46] Fix burst --- gw_app/nas_managers/mod_mikrotik.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gw_app/nas_managers/mod_mikrotik.py b/gw_app/nas_managers/mod_mikrotik.py index f702544..d95a12e 100644 --- a/gw_app/nas_managers/mod_mikrotik.py +++ b/gw_app/nas_managers/mod_mikrotik.py @@ -272,8 +272,9 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos, '=target=%s' % queue.network, '=max-limit=%.3fM/%.3fM' % queue.max_limit, '=queue=Djing_pcq_up/Djing_pcq_down', - '=burst-time=1/5', - #'=total-queue=Djing_pcq_down' + '=burst-time=5/5', + '=burst-limit=%.3fM/%.3fM' % tuple(i * 2 for i in queue.max_limit), + '=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit) )) def remove_queue(self, queue: i_structs.SubnetQueue) -> None: @@ -308,7 +309,9 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos, # или =target-addresses или =target '=target=%s' % queue.network, '=queue=Djing_pcq_up/Djing_pcq_down', - '=burst-time=1/1' + '=burst-time=5/5', + '=burst-limit=%.3fM/%.3fM' % tuple(i * 2 for i in queue.max_limit), + '=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit) ] if queue.queue_id: cmd.insert(1, '=.id=%s' % queue.queue_id) From a51791b64311ad0ec2110592e7ebafa73a834221 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 19 Dec 2018 13:48:37 +0300 Subject: [PATCH 08/46] Make huawei support --- devapp/base_intr.py | 5 +- devapp/dev_types.py | 53 +++++++++++++------ devapp/models.py | 3 +- .../custom_dev_page/generic_switch.html | 18 ++++--- devapp/urls.py | 52 ++++++------------ 5 files changed, 72 insertions(+), 59 deletions(-) diff --git a/devapp/base_intr.py b/devapp/base_intr.py index bc080b9..415898b 100644 --- a/devapp/base_intr.py +++ b/devapp/base_intr.py @@ -120,7 +120,10 @@ class SNMPBaseWorker(object, metaclass=ABCMeta): def start_ses(self): if self.ses is None: - self.ses = Session(hostname=self._ip, community=self._community, version=self._ver) + self.ses = Session( + hostname=self._ip, community=self._community, + version=self._ver, use_numeric=True + ) def set_int_value(self, oid: str, value): self.start_ses() diff --git a/devapp/dev_types.py b/devapp/dev_types.py index 5ce3dbd..4df380e 100644 --- a/devapp/dev_types.py +++ b/devapp/dev_types.py @@ -78,20 +78,18 @@ class DLinkDevice(DevBase, SNMPBaseWorker): stats = tuple(self.get_list('.1.3.6.1.2.1.2.2.1.7')) macs = tuple(self.get_list('.1.3.6.1.2.1.2.2.1.6')) speeds = tuple(self.get_list('.1.3.6.1.2.1.2.2.1.5')) - res = [] try: for n in range(interfaces_count): status = True if int(stats[n]) == 1 else False - res.append(DLinkPort( + yield DLinkPort( n + 1, nams[n] if len(nams) > 0 else '', status, macs[n] if len(macs) > 0 else _('does not fetch the mac'), int(speeds[n]) if len(speeds) > 0 else 0, - self)) - return res + self) except IndexError: - return DeviceImplementationError('Dlink port index error'), res + return DeviceImplementationError('Dlink port index error') def get_device_name(self): return self.get_item('.1.3.6.1.2.1.1.1.0') @@ -293,11 +291,12 @@ class OnuDevice(DevBase, SNMPBaseWorker): class EltexPort(BasePort): - def __init__(self, snmp_worker, *args, **kwargs): + def __init__(self, snmp_worker, writable=True, *args, **kwargs): BasePort.__init__(self, *args, **kwargs) if not issubclass(snmp_worker.__class__, SNMPBaseWorker): raise TypeError self.snmp_worker = snmp_worker + self.writable = writable def disable(self): self.snmp_worker.set_int_value( @@ -319,17 +318,16 @@ class EltexSwitch(DLinkDevice): tech_code = 'eltex_sw' def get_ports(self) -> ListOrError: - res = [] for i, n in enumerate(range(49, 77), 1): speed = self.get_item('.1.3.6.1.2.1.2.2.1.5.%d' % n) - res.append(EltexPort(self, - i, - self.get_item('.1.3.6.1.2.1.31.1.1.1.18.%d' % n), - self.get_item('.1.3.6.1.2.1.2.2.1.8.%d' % n), - self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), - int(speed or 0), - )) - return res + yield EltexPort(self, + num=i, + name=self.get_item('.1.3.6.1.2.1.31.1.1.1.18.%d' % n), + status=self.get_item('.1.3.6.1.2.1.2.2.1.8.%d' % n), + mac=self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), + speed=int(speed or 0), + writable=False, + ) def get_device_name(self): return self.get_item('.1.3.6.1.2.1.1.5.0') @@ -544,3 +542,28 @@ class ZteOnuDevice(OnuDevice): return 'gpon-onu_1/%d/%d:%s' % ( rack_num, fiber_num, onu_port_num ) + + +class HuaweiSwitch(EltexSwitch): + description = _('Huawei switch') + is_use_device_port = True + has_attachable_to_subscriber = True + tech_code = 'huawei_s2300' + + def get_ports(self): + interfaces_ids = self.get_list('.1.3.6.1.2.1.17.1.4.1.2') + if interfaces_ids is None: + raise DeviceImplementationError('Switch returned null') + for i, n in enumerate(interfaces_ids): + n = int(n) + speed = self.get_item('.1.3.6.1.2.1.2.2.1.5.%d' % n) + status = self.get_item('.1.3.6.1.2.1.2.2.1.8.%d' % n) + yield EltexPort( + self, + num=i+1, + name=self.get_item('.1.3.6.1.2.1.2.2.1.2.%d' % n), # name + status=int(status or 0), # status + mac=self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), # mac + speed=int(speed or 0), # speed + writable=False + ) diff --git a/devapp/models.py b/devapp/models.py index a8ad8d5..c47ee6b 100644 --- a/devapp/models.py +++ b/devapp/models.py @@ -32,7 +32,8 @@ class Device(models.Model): ('On', dev_types.OnuDevice), ('Ex', dev_types.EltexSwitch), ('Zt', dev_types.Olt_ZTE_C320), - ('Zo', dev_types.ZteOnuDevice) + ('Zo', dev_types.ZteOnuDevice), + ('Hw', dev_types.HuaweiSwitch) ) devtype = models.CharField(_('Device type'), max_length=2, default=DEVICE_TYPES[0][0], choices=MyChoicesAdapter(DEVICE_TYPES)) diff --git a/devapp/templates/devapp/custom_dev_page/generic_switch.html b/devapp/templates/devapp/custom_dev_page/generic_switch.html index 8f9a633..f8d1765 100644 --- a/devapp/templates/devapp/custom_dev_page/generic_switch.html +++ b/devapp/templates/devapp/custom_dev_page/generic_switch.html @@ -40,13 +40,19 @@ {{ port.num }} - {% if port.st %} - - - + {% if port.writable %} + {% if port.st %} + + + + {% else %} + + + + {% endif %} {% else %} - - + + {% endif %} diff --git a/devapp/urls.py b/devapp/urls.py index fd84e72..c3d9daf 100644 --- a/devapp/urls.py +++ b/devapp/urls.py @@ -5,52 +5,32 @@ app_name = 'devapp' urlpatterns = [ path('', views.GroupsListView.as_view(), name='group_list'), - path('devices_without_groups/', - views.DevicesWithoutGroupsListView.as_view(), - name='devices_null_group'), + path('devices_without_groups/', views.DevicesWithoutGroupsListView.as_view(), name='devices_null_group'), path('fix_onu/', views.fix_onu, name='fix_onu'), path('/', views.DevicesListView.as_view(), name='devs'), path('/add/', views.DeviceCreateView.as_view(), name='add'), path('//', views.devview, name='view'), - path('//del/', - views.DeviceDeleteView.as_view(), name='del'), - path('//add/', views.add_single_port, - name='add_port'), - path('//edit/', views.DeviceUpdate.as_view(), - name='edit'), - path('//edit_extra/', - views.DeviceUpdateExtra.as_view(), name='extra_data_edit'), - path( - '//ports//fix_port_conflict/', - views.fix_port_conflict, - name='fix_port_conflict'), - path( - '//ports//show_subscriber_on_port/', - views.ShowSubscriberOnPort.as_view(), name='show_subscriber_on_port'), - path('//ports_add/', views.add_ports, - name='add_ports'), - path('//register_device/', - views.register_device, name='dev_register'), - re_path('^(\d+)/(?P\d+)/(?P\d+)_(?P[0-1]{1})$', - views.toggle_port, name='port_toggle'), - path('///del/', - views.delete_single_port, name='del_port'), - path('///edit/', - views.EditSinglePort.as_view(), name='edit_port'), - path('fix_device_group//', views.fix_device_group, - name='fix_device_group'), + path('//del/', views.DeviceDeleteView.as_view(), name='del'), + path('//add/', views.add_single_port, name='add_port'), + path('//edit/', views.DeviceUpdate.as_view(), name='edit'), + path('//edit_extra/', views.DeviceUpdateExtra.as_view(), name='extra_data_edit'), + path('//ports//fix_port_conflict/', views.fix_port_conflict, name='fix_port_conflict'), + path('//ports//show_subscriber_on_port/', views.ShowSubscriberOnPort.as_view(), name='show_subscriber_on_port'), + path('//ports_add/', views.add_ports, name='add_ports'), + path('//register_device/', views.register_device, name='dev_register'), + re_path('^(\d+)/(?P\d+)/(?P\d+)_(?P[0-1]{1})$', views.toggle_port, name='port_toggle'), + path('///del/', views.delete_single_port, name='del_port'), + path('///edit/', views.EditSinglePort.as_view(), name='edit_port'), + path('fix_device_group//', views.fix_device_group, name='fix_device_group'), path('search_dev/', views.search_dev), # ZTE ports under fibers - path('///', - views.zte_port_view_uncfg, name='zte_port_view_uncfg'), + path('///', views.zte_port_view_uncfg, name='zte_port_view_uncfg'), # Monitoring api path('on_device_event/', views.OnDeviceMonitoringEvent.as_view()), # Nagios mon generate - path('nagios/hosts/', views.nagios_objects_conf, - name='nagios_objects_conf'), - path('api/getall/', views.DevicesGetListView.as_view(), - name='nagios_get_all_hosts') + path('nagios/hosts/', views.nagios_objects_conf, name='nagios_objects_conf'), + path('api/getall/', views.DevicesGetListView.as_view(), name='nagios_get_all_hosts') ] From 65fa527faee528047cb6005dede87793dea16e21 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 19 Dec 2018 13:58:18 +0300 Subject: [PATCH 09/46] Task that have hight priority display on top --- taskapp/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taskapp/models.py b/taskapp/models.py index 09c6633..6a59a9d 100644 --- a/taskapp/models.py +++ b/taskapp/models.py @@ -75,7 +75,7 @@ class Task(models.Model): class Meta: db_table = 'task' - ordering = ('-id',) + ordering = ('priority', '-id') permissions = ( ('can_viewall', _('Access to all tasks')), ('can_remind', _('Reminders of tasks')) From b3c631a086e5f2788baf8a025d6bde8651a9405d Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 19 Dec 2018 14:56:02 +0300 Subject: [PATCH 10/46] fix revert --- devapp/base_intr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devapp/base_intr.py b/devapp/base_intr.py index 415898b..d54691b 100644 --- a/devapp/base_intr.py +++ b/devapp/base_intr.py @@ -122,7 +122,7 @@ class SNMPBaseWorker(object, metaclass=ABCMeta): if self.ses is None: self.ses = Session( hostname=self._ip, community=self._community, - version=self._ver, use_numeric=True + version=self._ver ) def set_int_value(self, oid: str, value): From 3977457347dcddf8617b6e709bd51663fb18fc96 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Fri, 21 Dec 2018 19:33:33 +0300 Subject: [PATCH 11/46] change writable port --- devapp/base_intr.py | 3 ++- devapp/dev_types.py | 17 +++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/devapp/base_intr.py b/devapp/base_intr.py index d54691b..fd525b0 100644 --- a/devapp/base_intr.py +++ b/devapp/base_intr.py @@ -89,12 +89,13 @@ class DevBase(object, metaclass=ABCMeta): class BasePort(object, metaclass=ABCMeta): - def __init__(self, num, name, status, mac, speed): + def __init__(self, num, name, status, mac, speed, writable=False): self.num = int(num) self.nm = name self.st = status self._mac = mac self.sp = speed + self.writable = writable @abstractmethod def disable(self): diff --git a/devapp/dev_types.py b/devapp/dev_types.py index 4df380e..952a662 100644 --- a/devapp/dev_types.py +++ b/devapp/dev_types.py @@ -43,7 +43,7 @@ def plain_ip_device_mon_template(device) -> Optional[AnyStr]: class DLinkPort(BasePort): def __init__(self, num, name, status, mac, speed, snmp_worker): - BasePort.__init__(self, num, name, status, mac, speed) + BasePort.__init__(self, num, name, status, mac, speed, writable=True) if not issubclass(snmp_worker.__class__, SNMPBaseWorker): raise TypeError self.snmp_worker = snmp_worker @@ -291,12 +291,11 @@ class OnuDevice(DevBase, SNMPBaseWorker): class EltexPort(BasePort): - def __init__(self, snmp_worker, writable=True, *args, **kwargs): + def __init__(self, snmp_worker, *args, **kwargs): BasePort.__init__(self, *args, **kwargs) if not issubclass(snmp_worker.__class__, SNMPBaseWorker): raise TypeError self.snmp_worker = snmp_worker - self.writable = writable def disable(self): self.snmp_worker.set_int_value( @@ -325,8 +324,7 @@ class EltexSwitch(DLinkDevice): name=self.get_item('.1.3.6.1.2.1.31.1.1.1.18.%d' % n), status=self.get_item('.1.3.6.1.2.1.2.2.1.8.%d' % n), mac=self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), - speed=int(speed or 0), - writable=False, + speed=int(speed or 0) ) def get_device_name(self): @@ -561,9 +559,8 @@ class HuaweiSwitch(EltexSwitch): yield EltexPort( self, num=i+1, - name=self.get_item('.1.3.6.1.2.1.2.2.1.2.%d' % n), # name - status=int(status or 0), # status - mac=self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), # mac - speed=int(speed or 0), # speed - writable=False + name=self.get_item('.1.3.6.1.2.1.2.2.1.2.%d' % n), # name + status=int(status or 0), # status + mac=self.get_item('.1.3.6.1.2.1.2.2.1.6.%d' % n), # mac + speed=int(speed or 0) # speed ) From e0c382001efb2aaa1a468d048c19f7cb4c145952 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 24 Dec 2018 11:50:17 +0300 Subject: [PATCH 12/46] Make editing another profiles --- accounts_app/locale/ru/LC_MESSAGES/django.po | 6 ++ accounts_app/templates/accounts/ext.htm | 7 ++ accounts_app/templates/accounts/index.html | 24 +++--- .../{ => settings}/userprofile_form.html | 0 accounts_app/urls.py | 5 +- accounts_app/views.py | 82 +++++++++---------- djing/lib/mixins.py | 8 ++ 7 files changed, 73 insertions(+), 59 deletions(-) rename accounts_app/templates/accounts/{ => settings}/userprofile_form.html (100%) diff --git a/accounts_app/locale/ru/LC_MESSAGES/django.po b/accounts_app/locale/ru/LC_MESSAGES/django.po index 3e62963..95c3cd4 100644 --- a/accounts_app/locale/ru/LC_MESSAGES/django.po +++ b/accounts_app/locale/ru/LC_MESSAGES/django.po @@ -376,3 +376,9 @@ msgstr "Сотрудник" msgid "Saved successfully" msgstr "Успешно сохранено" + +msgid "Options" +msgstr "Настройки" + +msgid "Name and surname" +msgstr "Имя и отчество" diff --git a/accounts_app/templates/accounts/ext.htm b/accounts_app/templates/accounts/ext.htm index 2c420bf..cdaaf6b 100644 --- a/accounts_app/templates/accounts/ext.htm +++ b/accounts_app/templates/accounts/ext.htm @@ -26,6 +26,13 @@ + {% else %} + {% if request.user.is_superuser %} + + + + + {% endif %} {% endif %} {% if request.user.is_superuser %} - {% trans 'Telephone' %} - {{ userprofile.telephone }} + {% trans 'Telephone' %} + {{ userprofile.telephone }} - {% trans 'User name' %} - {{ userprofile.username }} + {% trans 'User name' %} + {{ userprofile.username }} - {% trans 'Name and surname' %} - {{ userprofile.fio }} + {% trans 'Name and surname' %} + {{ userprofile.fio }} - {% trans 'Is enable' %} - + {% trans 'Is enable' %} + - {% trans 'Last login' %} - {{ userprofile.last_login|date:"l d E Y H:i" }} + {% trans 'Last login' %} + {{ userprofile.last_login|date:"l d E Y H:i" }} {% if request.user.is_superuser %} - {% trans 'All permissions' %} - + {% trans 'All permissions' %} + {% endif %} diff --git a/accounts_app/templates/accounts/userprofile_form.html b/accounts_app/templates/accounts/settings/userprofile_form.html similarity index 100% rename from accounts_app/templates/accounts/userprofile_form.html rename to accounts_app/templates/accounts/settings/userprofile_form.html diff --git a/accounts_app/urls.py b/accounts_app/urls.py index 45f5687..f2cc7e9 100644 --- a/accounts_app/urls.py +++ b/accounts_app/urls.py @@ -11,14 +11,15 @@ urlpatterns = [ path('logout/', LogoutView.as_view(next_page='acc_app:login'), name='logout'), path('login_by_location/', views.location_login, name='llogin'), - path('me/', views.profile_show, name='profile'), + path('me/', views.UpdateSelfAccount.as_view(), name='profile'), path('add/', views.create_profile, name='create_profile'), path('settings/', views.UpdateSelfAccount.as_view(), name='setup_info'), path('settings/change_ava/', views.AvatarUpdateView.as_view(), name='setup_avatar'), - path('/', views.profile_show, name='other_profile'), + path('/', views.ProfileShowDetailView.as_view(), name='other_profile'), + path('/edit/', views.UpdateAccount.as_view(), name='edit_profile'), path('/perms/', views.PermsUpdateView.as_view(), name='setup_perms'), path('/perms/object/', views.perms_object, name='setup_perms_object'), diff --git a/accounts_app/views.py b/accounts_app/views.py index 5417e14..80a6acf 100644 --- a/accounts_app/views.py +++ b/accounts_app/views.py @@ -1,6 +1,6 @@ from django.apps import apps from django.contrib.auth.decorators import login_required -from django.contrib.auth import logout, login, authenticate +from django.contrib.auth import login, authenticate from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.views import LoginView @@ -11,22 +11,19 @@ from django.contrib import messages from django.urls import NoReverseMatch from django.utils.decorators import method_decorator from django.utils.translation import ugettext as _ -from django.views.generic import ListView, UpdateView +from django.views.generic import ListView, UpdateView, DetailView from django.conf import settings from group_app.models import Group from .models import UserProfile, UserProfileLog from .forms import AvatarChangeForm, UserPermissionsForm, MyUserObjectPermissionsForm, UserProfileForm -from djing import lib from djing.lib.decorators import only_admins +from djing.lib.mixins import OnlyAdminsMixin, LoginAdminPermissionMixin, OnlySuperUserMixin from guardian.decorators import permission_required_or_403 as permission_required from guardian.shortcuts import get_objects_for_user, assign_perm, remove_perm -login_decs = login_required, only_admins - - class CustomLoginView(LoginView): template_name = 'accounts/login.html' @@ -63,34 +60,27 @@ def location_login(request): return redirect('client_side:home') -@login_required -@only_admins -def profile_show(request, uid=0): - uid = lib.safe_int(uid) +class ProfileShowDetailView(LoginRequiredMixin, OnlyAdminsMixin, DetailView): + model = UserProfile + pk_url_kwarg = 'uid' + template_name = 'accounts/index.html' + context_object_name = 'userprofile' - if uid == 0: - return redirect('acc_app:other_profile', uid=request.user.id) + def get_context_data(self, **kwargs): + context = { + 'uid': self.kwargs.get('uid') + } + context.update(kwargs) + return super(ProfileShowDetailView, self).get_context_data(**context) - usr = get_object_or_404(UserProfile, id=uid) - if request.user != usr and not request.user.has_perm('accounts_app.view_userprofile', usr): - raise PermissionDenied - if request.method == 'POST': - usr.username = request.POST.get('username') - usr.fio = request.POST.get('fio') - usr.telephone = request.POST.get('telephone') - usr.is_active = request.POST.get('stat') - usr.is_admin = request.POST.get('is_admin') - usr.save() - return redirect('acc_app:other_profile', uid=uid) - - return render(request, 'accounts/index.html', { - 'uid': uid, - 'userprofile': usr - }) + def dispatch(self, request, *args, **kwargs): + uid = self.kwargs.get('uid') + if uid == 0: + return redirect('acc_app:other_profile', uid=request.user.id) + return super(ProfileShowDetailView, self).dispatch(request, *args, **kwargs) -@method_decorator(login_decs, name='dispatch') -class AvatarUpdateView(UpdateView): +class AvatarUpdateView(LoginRequiredMixin, OnlyAdminsMixin, UpdateView): form_class = AvatarChangeForm template_name = 'accounts/settings/ch_info.html' @@ -101,20 +91,26 @@ class AvatarUpdateView(UpdateView): return resolve_url('acc_app:other_profile', uid=self.request.user.id) -class UpdateSelfAccount(LoginRequiredMixin, UpdateView): +class UpdateAccount(LoginRequiredMixin, OnlySuperUserMixin, UpdateView): form_class = UserProfileForm - model = UserProfile - template_name = 'accounts/userprofile_form.html' + pk_url_kwarg = 'uid' - def get_object(self, queryset=None): - return self.request.user + model = UserProfile + template_name = 'accounts/settings/userprofile_form.html' def form_valid(self, form): - r = super(UpdateSelfAccount, self).form_valid(form) + r = super(UpdateAccount, self).form_valid(form) messages.success(self.request, _('Saved successfully')) return r +class UpdateSelfAccount(UpdateAccount): + form_class = UserProfileForm + + def get_object(self, queryset=None): + return self.request.user + + @login_required @only_admins @permission_required('accounts_app.add_userprofile') @@ -165,8 +161,7 @@ def delete_profile(request, uid: int): return redirect('acc_app:accounts_list') -@method_decorator(login_decs, name='dispatch') -class AccountsListView(ListView): +class AccountsListView(LoginRequiredMixin, OnlyAdminsMixin, ListView): http_method_names = 'get', paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) template_name = 'accounts/acc_list.html' @@ -227,8 +222,7 @@ class PermsUpdateView(UpdateView): return super(PermsUpdateView, self).form_valid(form) -@method_decorator(login_decs, name='dispatch') -class PermissionClassListView(ListView): +class PermissionClassListView(LoginRequiredMixin, OnlyAdminsMixin, ListView): http_method_names = 'get', paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) template_name = 'accounts/perms/object/objects_of_type.html' @@ -308,8 +302,7 @@ def set_abon_groups_permission(request, uid: int): }) -@method_decorator(login_decs, name='dispatch') -class ManageResponsibilityGroups(ListView): +class ManageResponsibilityGroups(LoginRequiredMixin, OnlyAdminsMixin, ListView): http_method_names = ('get', 'post') template_name = 'accounts/manage_responsibility_groups.html' context_object_name = 'groups' @@ -339,11 +332,10 @@ class ManageResponsibilityGroups(ListView): return HttpResponseRedirect(self.get_success_url()) -@method_decorator(login_decs, name='dispatch') -@method_decorator(permission_required('accounts_app.view_userprofilelog'), name='dispatch') -class ActionListView(ListView): +class ActionListView(LoginAdminPermissionMixin, ListView): paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) template_name = 'accounts/action_log.html' + permission_required = 'accounts_app.view_userprofilelog' model = UserProfileLog def get_queryset(self): diff --git a/djing/lib/mixins.py b/djing/lib/mixins.py index c4326bf..23cc635 100644 --- a/djing/lib/mixins.py +++ b/djing/lib/mixins.py @@ -2,6 +2,14 @@ from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin from guardian.mixins import PermissionRequiredMixin +class OnlySuperUserMixin(AccessMixin): + """Verify that the current user is superuser.""" + def dispatch(self, request, *args, **kwargs): + if not request.user.is_superuser: + return self.handle_no_permission() + return super().dispatch(request, *args, **kwargs) + + class OnlyAdminsMixin(AccessMixin): """Verify that the current user is admin.""" def dispatch(self, request, *args, **kwargs): From e9c5e94f6b5bbfc590bb50675dfeefdaca05dc4d Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 24 Dec 2018 14:22:53 +0300 Subject: [PATCH 13/46] make new --- abonapp/views.py | 16 +++--- accounts_app/forms.py | 5 +- accounts_app/locale/ru/LC_MESSAGES/django.po | 11 +--- accounts_app/templates/accounts/index.html | 4 +- .../templates/accounts/settings/ext.htm | 12 ++-- .../accounts/settings/userprofile_form.html | 2 +- accounts_app/urls.py | 18 ++---- accounts_app/views.py | 49 +++++++++++----- djing/settings.py | 2 +- djing/views.py | 2 +- group_app/views.py | 7 +++ taskapp/locale/ru/LC_MESSAGES/django.po | 3 + taskapp/models.py | 2 +- taskapp/templates/taskapp/footer_btns.html | 7 +++ taskapp/urls.py | 1 + taskapp/views.py | 57 ++++++++----------- templates/all_base.html | 2 +- templates/base.html | 2 +- 18 files changed, 109 insertions(+), 93 deletions(-) diff --git a/abonapp/views.py b/abonapp/views.py index de135df..f68b4c5 100644 --- a/abonapp/views.py +++ b/abonapp/views.py @@ -73,8 +73,7 @@ class PeoplesListView(LoginRequiredMixin, OnlyAdminsMixin, context = super(PeoplesListView, self).get_context_data(**kwargs) - context['streets'] = models.AbonStreet.objects.filter(group=gid).only( - 'name') + context['streets'] = models.AbonStreet.objects.filter(group=gid).only('name') context['street_id'] = lib.safe_int(self.request.GET.get('street')) context['group'] = group return context @@ -83,14 +82,15 @@ class PeoplesListView(LoginRequiredMixin, OnlyAdminsMixin, class GroupListView(LoginRequiredMixin, OnlyAdminsMixin, OrderedFilteredList): context_object_name = 'groups' template_name = 'abonapp/group_list.html' - queryset = Group.objects.annotate(usercount=Count('abon')) def get_queryset(self): - queryset = super(GroupListView, self).get_queryset() - queryset = get_objects_for_user(self.request.user, - 'group_app.view_group', klass=queryset, - accept_global_perms=False) - return queryset + queryset = get_objects_for_user( + self.request.user, + 'group_app.view_group', klass=Group, + use_groups=False, + accept_global_perms=False + ) + return queryset.annotate(usercount=Count('abon')) class AbonCreateView(LoginRequiredMixin, OnlyAdminsMixin, diff --git a/accounts_app/forms.py b/accounts_app/forms.py index cc5dfba..84ffb6b 100644 --- a/accounts_app/forms.py +++ b/accounts_app/forms.py @@ -46,10 +46,11 @@ class UserPermissionsForm(forms.ModelForm): class Meta: model = UserProfile - fields = ('avatar', 'password', 'groups', 'user_permissions', 'responsibility_groups', 'is_superuser') + fields = ('user_permissions', 'is_superuser') class UserProfileForm(forms.ModelForm): class Meta: model = UserProfile - exclude = ('avatar', 'password', 'groups', 'user_permissions', 'responsibility_groups', 'is_superuser') + exclude = ('avatar', 'password', 'groups', 'user_permissions', + 'responsibility_groups', 'is_admin', 'is_superuser', 'last_login') diff --git a/accounts_app/locale/ru/LC_MESSAGES/django.po b/accounts_app/locale/ru/LC_MESSAGES/django.po index 95c3cd4..be71adc 100644 --- a/accounts_app/locale/ru/LC_MESSAGES/django.po +++ b/accounts_app/locale/ru/LC_MESSAGES/django.po @@ -241,10 +241,6 @@ msgstr "Включён-ли" msgid "Last login" msgstr "Последняя авторизация" -#: templates/accounts/index.html:30 -msgid "All permissions" -msgstr "Административный доступ (все права)" - #: templates/accounts/login.html:5 msgid "Auth" msgstr "Аутентификация" @@ -309,10 +305,6 @@ msgstr "Изменение прав доступа для выбранного msgid "The list of user groups to which the account has access" msgstr "Список групп абонентов, к которым учётка имеет доступ" -#: views.py:33 -msgid "Wrong login or password, please try again" -msgstr "Неправильный логин или пароль, попробуйте ещё раз" - #: views.py:121 msgid "New password is empty, fill it" msgstr "Новый пароль пустой, придумайте себе пароль" @@ -382,3 +374,6 @@ msgstr "Настройки" msgid "Name and surname" msgstr "Имя и отчество" + +msgid "Is superuser" +msgstr "Является суперпользователем" \ No newline at end of file diff --git a/accounts_app/templates/accounts/index.html b/accounts_app/templates/accounts/index.html index d3c067d..0392dee 100644 --- a/accounts_app/templates/accounts/index.html +++ b/accounts_app/templates/accounts/index.html @@ -27,8 +27,8 @@ {% if request.user.is_superuser %} - {% trans 'All permissions' %} - + {% trans 'Is superuser' %} + {% endif %} diff --git a/accounts_app/templates/accounts/settings/ext.htm b/accounts_app/templates/accounts/settings/ext.htm index c62ea2b..50efc15 100644 --- a/accounts_app/templates/accounts/settings/ext.htm +++ b/accounts_app/templates/accounts/settings/ext.htm @@ -5,7 +5,7 @@ {% endblock %} @@ -17,10 +17,9 @@ {% block main %}
-
{% csrf_token %} + {% csrf_token %} - ava + ava
@@ -30,11 +29,10 @@
-

{{ user.username|default:_('Not assigned') }}

+

{{ object.username|default:_('Not assigned') }}