diff --git a/abonapp/templates/abonapp/peoples.html b/abonapp/templates/abonapp/peoples.html index c2854f7..f22e2e9 100644 --- a/abonapp/templates/abonapp/peoples.html +++ b/abonapp/templates/abonapp/peoples.html @@ -63,7 +63,7 @@ - {% with can_ch_trf=perms.tariff_app.change_tariff can_del_trf=perms.abonapp.delete_abon %} + {% with can_ch_trf=perms.tariff_app.change_tariff can_del_abon=perms.abonapp.delete_abon %} {% for human in peoples %} {% if human.is_active %} @@ -94,11 +94,11 @@ {{ human.house|default:'-' }} {{ human.telephone }} - {% if human.active_tariff %} - {% if perms.tariff_app.change_tariff %} - {{ human.active_tariff.tariff.title }} + {% if human.current_tariff %} + {% if can_ch_trf %} + {{ human.current_tariff.tariff.title }} {% else %} - {{ human.active_tariff.tariff.title }} + {{ human.current_tariff.tariff.title }} {% endif %} {% else %}——— {% endif %} @@ -109,7 +109,7 @@ {% endfor %} - {% if can_del_trf %} + {% if can_del_abon %} diff --git a/abonapp/views.py b/abonapp/views.py index 32e99bb..6e1f433 100644 --- a/abonapp/views.py +++ b/abonapp/views.py @@ -6,7 +6,7 @@ from django.db import IntegrityError, ProgrammingError, transaction from django.db.models import Count, Q from django.shortcuts import render, redirect, get_object_or_404, resolve_url from django.contrib.auth.decorators import login_required -from django.http import HttpResponse, HttpResponseBadRequest +from django.http import HttpResponse, Http404 from django.contrib import messages from django.utils.translation import gettext_lazy as _ from django.utils.decorators import method_decorator @@ -27,13 +27,13 @@ from statistics.models import getModel from group_app.models import Group from guardian.shortcuts import get_objects_for_user, assign_perm from guardian.decorators import permission_required_or_403 as permission_required -from djing.global_base_views import OrderingMixin +from djing.global_base_views import OrderingMixin, BaseListWithFiltering PAGINATION_ITEMS_PER_PAGE = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10) @method_decorator([login_required, mydefs.only_admins], name='dispatch') -class BaseAbonListView(ListView, OrderingMixin): +class BaseAbonListView(OrderingMixin, BaseListWithFiltering): paginate_by = PAGINATION_ITEMS_PER_PAGE http_method_names = ['get'] @@ -45,7 +45,7 @@ class PeoplesListView(BaseAbonListView): def get_queryset(self): street_id = mydefs.safe_int(self.request.GET.get('street')) gid = mydefs.safe_int(self.kwargs.get('gid')) - peoples_list = models.Abon.objects.select_related('group', 'street') + peoples_list = models.Abon.objects.all().select_related('group', 'street', 'current_tariff') if street_id > 0: peoples_list = peoples_list.filter(group__pk=gid, street=street_id) else: @@ -60,7 +60,11 @@ class PeoplesListView(BaseAbonListView): pass except mydefs.LogicError as e: messages.warning(self.request, e) - + ordering = self.get_ordering() + if ordering: + if isinstance(ordering, str): + ordering = (ordering,) + peoples_list = peoples_list.order_by(*ordering) return peoples_list def get_context_data(self, **kwargs): @@ -545,7 +549,8 @@ def clear_dev(request, gid, uid): try: abon = models.Abon.objects.get(pk=uid) abon.device = None - abon.save(update_fields=['device']) + abon.dev_port = None + abon.save(update_fields=['device', 'dev_port']) messages.success(request, _('Device has successfully unattached')) except models.Abon.DoesNotExist: messages.error(request, _('Abon does not exist')) diff --git a/accounts_app/views.py b/accounts_app/views.py index 19d6fa7..6e72be1 100644 --- a/accounts_app/views.py +++ b/accounts_app/views.py @@ -213,7 +213,7 @@ def perms(request, uid): klasses = ( 'abonapp.Abon', 'accounts_app.UserProfile', 'abonapp.AbonTariff', 'abonapp.AbonStreet', 'devapp.Device', - 'abonapp.PassportInfo', 'abonapp.AdditionalTelephone' + 'abonapp.PassportInfo', 'abonapp.AdditionalTelephone', 'tariff_app.PeriodicPay' ) return render(request, 'accounts/perms/objects_types.html', { 'userprofile': userprofile, diff --git a/agent/netflow/netflow_handler.py b/agent/netflow/netflow_handler.py index f88a4ea..41c23c1 100755 --- a/agent/netflow/netflow_handler.py +++ b/agent/netflow/netflow_handler.py @@ -4,6 +4,7 @@ import sys import os from importlib import import_module + if __name__ == '__main__': if len(sys.argv) < 2: print("File name of netflow required") @@ -48,8 +49,8 @@ if __name__ == '__main__': db.close() os.system( - '/usr/bin/bash -c ' - '"%(CUR_DIR)s/djing_flow %(TMP_IPUSER_FILE)s < %(TMP_DUMP)s | ' + 'bash -c "export LD_LIBRARY_PATH=. && ' + '%(CUR_DIR)s/djing_flow %(TMP_IPUSER_FILE)s < %(TMP_DUMP)s | ' '/usr/bin/mysql -u%(DB_USER)s -h %(HOST)s -p %(DB_NAME)s --password=%(DB_PASSW)s"' % { 'CUR_DIR': cur_dir, 'TMP_IPUSER_FILE': tmp_ipuser_file, diff --git a/chatbot/models.py b/chatbot/models.py index fffe6f1..b10f2bd 100644 --- a/chatbot/models.py +++ b/chatbot/models.py @@ -57,7 +57,7 @@ class MessageQueue(models.Model): ('r', 'Read') ) status = models.CharField(_('Status of message'), max_length=1, choices=STATUSES, default='n') - # tag каждое приложение ставит своим чтоб делить сообщения между этими приложениями + # tag: each application puts its own to separate messages between these applications tag = models.CharField(_('App tag'), max_length=6, default='none') objects = MessageQueueManager() diff --git a/clientsideapp/locale/ru/LC_MESSAGES/django.po b/clientsideapp/locale/ru/LC_MESSAGES/django.po index 23cef2a..b72ec63 100644 --- a/clientsideapp/locale/ru/LC_MESSAGES/django.po +++ b/clientsideapp/locale/ru/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-03-18 00:15+0300\n" +"POT-Creation-Date: 2018-03-20 01:51+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Dmitry Novikov nerosketch@gmail.com\n" "Language: ru\n" @@ -54,6 +54,91 @@ msgstr "Подтвердить" msgid "Cancel" msgstr "Отменить" +#: templates/clientsideapp/debts.html:6 +msgid "Your debt" +msgstr "Ваши долги" + +#: templates/clientsideapp/debts.html:11 +msgid "State" +msgstr "Состояние" + +#: templates/clientsideapp/debts.html:12 +msgid "Summ" +msgstr "Сумма" + +#: templates/clientsideapp/debts.html:13 +msgid "Description" +msgstr "Описание" + +#: templates/clientsideapp/debts.html:14 +msgid "Date of create" +msgstr "Дата создания" + +#: templates/clientsideapp/debts.html:15 +msgid "Date of pay" +msgstr "Дата платежа" + +#: templates/clientsideapp/debts.html:16 templates/clientsideapp/debts.html:38 +msgid "Pay" +msgstr "Оплатить" + +#: templates/clientsideapp/debts.html:23 templates/clientsideapp/ext.html:63 +#: templates/clientsideapp/modal_service_buy.html:19 +#: templates/clientsideapp/services.html:26 +#: templates/clientsideapp/services.html:55 +msgid "currency" +msgstr "руб." + +#: templates/clientsideapp/debts.html:31 +msgid "Created paid" +msgstr "Создан оплаченным" + +#: templates/clientsideapp/debts.html:33 +msgid "Not yet paid" +msgstr "Ещё не оплачен" + +#: templates/clientsideapp/debts.html:45 +msgid "You have no debt" +msgstr "У вас нет долгов" + +#: templates/clientsideapp/ext.html:7 templates/clientsideapp/ext.html:41 +msgid "Personal account" +msgstr "Личный кабинет" + +#: templates/clientsideapp/ext.html:46 +msgid "Pays" +msgstr "Платежи" + +#: templates/clientsideapp/ext.html:51 +msgid "Services" +msgstr "Услуги" + +#: templates/clientsideapp/ext.html:55 +msgid "Other" +msgstr "Другое" + +#: templates/clientsideapp/ext.html:57 +msgid "Show debts and pay it" +msgstr "Посмотреть долги и оплатить" + +#: templates/clientsideapp/ext.html:58 +msgid "Quit" +msgstr "Выйти" + +#: templates/clientsideapp/ext.html:63 +#, python-format +msgid "Your balance is %(ballance)s" +msgstr "Ваш балланс %(ballance)s" + +#: templates/clientsideapp/ext.html:74 +msgid "" +"Attantion! You are is admin, and do not be active here, " +"please back to admin side. Client side to you for reference only." +msgstr "" +"Кстати. Вы администратор, и не должны производить действия " +"из кабинета пользователя, производите их из админки. Кабинет клиента для вас " +"только для ознакомления." + #: templates/clientsideapp/modal_service_buy.html:5 msgid "Pick service" msgstr "Заказать услугу" @@ -62,20 +147,32 @@ msgstr "Заказать услугу" msgid "Are you sure you want to order the service?" msgstr "Вы уверены что хотите заказать услугу?" +#: templates/clientsideapp/modal_service_buy.html:9 +msgid "" +"Be careful, after purchasing the service you will withdraw money, and " +"you will be able to use the purchased service." +msgstr "" +"Будте внимательны, после заказа услуги с вашего счёта снимутся средства, и вы сможете пользоваться купленной услугой." + #: templates/clientsideapp/modal_service_buy.html:15 #, python-format msgid "" -"Inbound speed: %(speedIn)s MBit/s
\n" -"Outgoing speed: %(speedOut)s MBit/s
\n" -"Cost: %(amount)s rubles." +"Inbound speed: %(speedIn)s MBit/s
Outgoing speed: %(speedOut)s MBit/" +"s
Cost: %(amount)s rubles." msgstr "" -#: templates/clientsideapp/modal_service_buy.html:22 -#: templates/clientsideapp/services.html:59 +#: templates/clientsideapp/modal_service_buy.html:19 +#, python-format +msgid "The cost is %(amount)s" +msgstr "Стоимость %(amount)s" + +#: templates/clientsideapp/modal_service_buy.html:23 +#: templates/clientsideapp/services.html:63 msgid "Pick" msgstr "Заказать" -#: templates/clientsideapp/modal_service_buy.html:24 +#: templates/clientsideapp/modal_service_buy.html:25 msgid "Close" msgstr "Закрыть" @@ -99,9 +196,37 @@ msgstr "Комментарий" msgid "You have not spent payments" msgstr "У вас нет проведённых платежей" +#: templates/clientsideapp/services.html:14 +msgid "Your current service" +msgstr "Ваша текущая услуга" + +#: templates/clientsideapp/services.html:19 +msgid "The date of connection" +msgstr "Дата подключения" + +#: templates/clientsideapp/services.html:22 +msgid "The date of finish service" +msgstr "Дата завершения услуги" + #: templates/clientsideapp/services.html:25 -msgid "currency" -msgstr "руб." +msgid "Cost" +msgstr "Стоимость" + +#: templates/clientsideapp/services.html:35 +msgid "" +"Attantion! You have not yet a service, for use the services " +"please purchase service you want." +msgstr "" +"Внимание! У вас нет услуги, для использования ресурсов " +"приобретите нужную услугу из представленных тут." + +#: templates/clientsideapp/services.html:46 +msgid "Services available for ordering" +msgstr "Доступные для заказа услуги" + +#: templates/clientsideapp/services.html:68 +msgid "No services available for ordering" +msgstr "Нет доступных для заказа услуг" #: views.py:51 #, python-format diff --git a/clientsideapp/templates/clientsideapp/custom_pages/footer.htm b/clientsideapp/templates/clientsideapp/custom_pages/footer.htm new file mode 100644 index 0000000..55ce634 --- /dev/null +++ b/clientsideapp/templates/clientsideapp/custom_pages/footer.htm @@ -0,0 +1 @@ +Your custom content here. \ No newline at end of file diff --git a/clientsideapp/templates/clientsideapp/custom_pages/main_page.htm b/clientsideapp/templates/clientsideapp/custom_pages/main_page.htm new file mode 100644 index 0000000..27e1fca --- /dev/null +++ b/clientsideapp/templates/clientsideapp/custom_pages/main_page.htm @@ -0,0 +1 @@ +

You can change this page

\ No newline at end of file diff --git a/clientsideapp/templates/clientsideapp/custom_pages/service.htm b/clientsideapp/templates/clientsideapp/custom_pages/service.htm new file mode 100644 index 0000000..a987da4 --- /dev/null +++ b/clientsideapp/templates/clientsideapp/custom_pages/service.htm @@ -0,0 +1,2 @@ +

Your custom content

+

You have service variable {{ active_service }}

\ No newline at end of file diff --git a/clientsideapp/templates/clientsideapp/custom_pages/service_bottom.htm b/clientsideapp/templates/clientsideapp/custom_pages/service_bottom.htm new file mode 100644 index 0000000..89cbb76 --- /dev/null +++ b/clientsideapp/templates/clientsideapp/custom_pages/service_bottom.htm @@ -0,0 +1 @@ +

Your custom content on bottom

\ No newline at end of file diff --git a/clientsideapp/templates/clientsideapp/debts.html b/clientsideapp/templates/clientsideapp/debts.html index d7d1038..18563e3 100644 --- a/clientsideapp/templates/clientsideapp/debts.html +++ b/clientsideapp/templates/clientsideapp/debts.html @@ -1,25 +1,26 @@ {% extends 'clientsideapp/ext.html' %} +{% load i18n %} {% block client_main %} - - - - - - + + + + + + {% for debt in debts %} - + {% empty %} - + {% endfor %} diff --git a/clientsideapp/templates/clientsideapp/ext.html b/clientsideapp/templates/clientsideapp/ext.html index 08404a1..b9541b5 100644 --- a/clientsideapp/templates/clientsideapp/ext.html +++ b/clientsideapp/templates/clientsideapp/ext.html @@ -1,10 +1,10 @@ - +{% load globaltags %}{% load i18n %} - Личный кабинет + {% global_var 'COMPANY_NAME' %} - {% trans 'Personal account' %} @@ -19,6 +19,8 @@ + +{% url 'client_side:home' as client_side_home %} @@ -80,11 +70,12 @@
{% if request.user.is_staff %} -
- Кстати. - Вы администратор, и не должны производить действия из кабинета пользователя, производите их из админки. - Кабинет клиента для вас только для ознакомления. -
+
+ {% blocktrans trimmed %} + Attantion! + You are is admin, and do not be active here, please back to admin side. Client side to you for reference only. + {% endblocktrans %} +
{% endif %} {% include 'message_block.html' %} @@ -95,7 +86,7 @@ diff --git a/clientsideapp/templates/clientsideapp/index.html b/clientsideapp/templates/clientsideapp/index.html index a0ff0b2..a881d0e 100644 --- a/clientsideapp/templates/clientsideapp/index.html +++ b/clientsideapp/templates/clientsideapp/index.html @@ -1,73 +1,4 @@ {% extends 'clientsideapp/ext.html' %} {% block client_main %} - -
-
Наши реквизиты
-
-
    -
  • Режим работы: с 9:00 до 22:00
  • -
  • Телефоны: +79788328885, +79788318999
  • -
  • Адрес: пос. Нижнегорский, ул. Победы 38. 2й этаж старого дома быта, возле рынка
  • -
- -
-
- -
СостояниеСуммаОписаниеДата созданияДата платежаОплатить{% trans 'State' %}{% trans 'Summ' %}{% trans 'Description' %}{% trans 'Date of create' %}{% trans 'Date of pay' %}{% trans 'Pay' %}
{{ debt.amount }} руб.{{ debt.amount }} {% trans 'currency' %} {{ debt.comment }} {{ debt.date_create|date:'d b H:i' }} @@ -27,21 +28,21 @@ {{ debt.date_pay|date:'d b H:i' }} {% else %} {% if debt.status %} - Создан оплаченным + {% trans 'Created paid' %} {% else %} - Ещё не оплачен + {% trans 'Not yet paid' %} {% endif %} {% endif %} - +
У вас нет долгов {% trans 'You have no debt' %}
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
УслугаСтоимость (руб)
Выезд мастера. Цена зависит от удалённости от Нижнегорска100-200
Настройка роутера300
Установка и восстановление сетевых настроек100
Замена кабеля (витая пара)30 руб/метр
Замена конектора RJ-4550
Роутер TL-WR840N + настройка1800
Установка драйвера (с настройкой сетевых установок)100
"Что-то не работает" – по договорённости~
Замена блока питания200
Замена оптоволоконных линий связиот 500
- - + {% include 'clientsideapp/custom_pages/main_page.htm' %} {% endblock %} diff --git a/clientsideapp/templates/clientsideapp/modal_service_buy.html b/clientsideapp/templates/clientsideapp/modal_service_buy.html index 0077603..5fe1d2e 100644 --- a/clientsideapp/templates/clientsideapp/modal_service_buy.html +++ b/clientsideapp/templates/clientsideapp/modal_service_buy.html @@ -6,7 +6,7 @@ + {% include 'clientsideapp/custom_pages/service_bottom.htm' %} - - -
-
-
-
- - Как работает личный кабинет, раздел услуг -
-
-

Перед вами находится 2 столбца, в левом ваша текущая подключённая услуга, а в правом доступные для заказа услуги. - Когда у вас уже есть подключённая услуга то заказать новую вы не можете пока не завершится текущая.

-

Когда у вас нет действующей подключённой услуги то кнопка заказа станет активной, и вы сможете заказать для себя услугу. - Обратите внимание что именно в этот момент с вашего счёта снимутся деньги в соответствии со стоимостью услуги. -

-
-
-
-
{% endblock %} diff --git a/devapp/base_intr.py b/devapp/base_intr.py index 715dcc9..db61a66 100644 --- a/devapp/base_intr.py +++ b/devapp/base_intr.py @@ -1,8 +1,11 @@ -# -*- coding: utf-8 -*- from abc import ABCMeta, abstractmethod from easysnmp import Session +class DeviceImplementationError(Exception): + pass + + class DevBase(object, metaclass=ABCMeta): def __init__(self, dev_instance=None): @@ -10,19 +13,19 @@ class DevBase(object, metaclass=ABCMeta): @staticmethod def description(): - """Возвращает текстовое описание""" + pass @abstractmethod def reboot(self): - """Перезагружает устройство""" + pass @abstractmethod def get_ports(self): - """Получаем инфу о портах""" + pass @abstractmethod def get_device_name(self): - """Получаем имя устройства по snmp""" + """Return device name by snmp""" @abstractmethod def uptime(self): @@ -30,17 +33,17 @@ class DevBase(object, metaclass=ABCMeta): @abstractmethod def get_template_name(self): - """Получаем путь к html шаблону отображения устройства""" + """Return path to html template for device""" @staticmethod @abstractmethod def has_attachable_to_subscriber(): - """Можно-ли подключать устройство к абоненту""" + """Can connect device to subscriber""" @staticmethod @abstractmethod def is_use_device_port(): - """True если при авторизации по opt82 используется порт""" + """True if used device port while opt82 authorization""" class BasePort(object, metaclass=ABCMeta): @@ -70,7 +73,7 @@ class SNMPBaseWorker(object, metaclass=ABCMeta): self.ses = Session(hostname=ip, community=community, version=ver) def set_int_value(self, oid, value): - return self.ses.set(oid, value) + return self.ses.set(oid, value, 'i') def get_list(self, oid): for v in self.ses.walk(oid): diff --git a/devapp/dev_types.py b/devapp/dev_types.py index 5db0309..4d96ee8 100644 --- a/devapp/dev_types.py +++ b/devapp/dev_types.py @@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _ from mydefs import RuTimedelta, safe_int from datetime import timedelta from easysnmp import EasySNMPTimeoutError -from .base_intr import DevBase, SNMPBaseWorker, BasePort +from .base_intr import DevBase, SNMPBaseWorker, BasePort, DeviceImplementationError class DLinkPort(BasePort): @@ -41,21 +41,25 @@ class DLinkDevice(DevBase, SNMPBaseWorker): return self.get_item('.1.3.6.1.4.1.2021.8.1.101.1') def get_ports(self): + interfaces_count = safe_int(self.get_item('.1.3.6.1.2.1.2.1.0')) nams = list(self.get_list('.1.3.6.1.4.1.171.10.134.2.1.1.100.2.1.3')) stats = list(self.get_list('.1.3.6.1.2.1.2.2.1.7')) macs = list(self.get_list('.1.3.6.1.2.1.2.2.1.6')) - speeds = self.get_list('.1.3.6.1.2.1.31.1.1.1.15') + speeds = list(self.get_list('.1.3.6.1.2.1.2.2.1.5')) res = [] - for n, speed in enumerate(speeds): - status = True if int(stats[n]) == 1 else False - res.append(DLinkPort( - n+1, - nams[n] if len(nams) > 0 else _('does not fetch the name'), - status, - macs[n] if len(macs) > 0 else _('does not fetch the mac'), - int(speed or 0), - self)) - return res + try: + for n in range(interfaces_count): + status = True if int(stats[n]) == 1 else False + res.append(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 + except IndexError: + raise DeviceImplementationError('Dlink port index error') def get_device_name(self): return self.get_item('.1.3.6.1.2.1.1.1.0') diff --git a/devapp/models.py b/devapp/models.py index 1fa4fac..9ec5e4e 100644 --- a/devapp/models.py +++ b/devapp/models.py @@ -76,7 +76,7 @@ class Device(models.Model): ) verbose_name = _('Device') verbose_name_plural = _('Devices') - ordering = ['comment'] + ordering = ['id'] def get_abons(self): pass diff --git a/devapp/onu_register.sh b/devapp/onu_register.sh index c835550..fb64e5a 100755 --- a/devapp/onu_register.sh +++ b/devapp/onu_register.sh @@ -29,6 +29,6 @@ if grep "${MAC}" "${DHCP_PATH}/${PART_CODE}.conf" > /dev/null; then else # add new mac echo "subclass \"${PART_CODE}\" \"${MAC}\";" >> "${DHCP_PATH}/${PART_CODE}.conf" - /usr/bin/sudo /usr/bin/systemctl restart dhcpd.service + sudo systemctl restart isc-dhcp-server.service fi diff --git a/devapp/templates/devapp/custom_dev_page/ports.html b/devapp/templates/devapp/custom_dev_page/ports.html index 42f4b8b..add949a 100644 --- a/devapp/templates/devapp/custom_dev_page/ports.html +++ b/devapp/templates/devapp/custom_dev_page/ports.html @@ -18,16 +18,16 @@ {% for port in ports %} {% if port.st %} - {% if port.sp == 10 %} + {% if port.sp == 10000000 %}
10 mbps - {% elif port.sp == 100 %} + {% elif port.sp == 100000000 %}
100 mbps - {% elif port.sp == 1000 %} + {% elif port.sp == 1000000000 %}
1 gbps - {% elif port.sp == 10000 %} + {% elif port.sp == 10000000000 %}
10 gbps {% else %} diff --git a/devapp/views.py b/devapp/views.py index ee3a8cb..f4a0e12 100644 --- a/devapp/views.py +++ b/devapp/views.py @@ -13,6 +13,7 @@ from django.utils.translation import gettext_lazy as _, gettext from easysnmp import EasySNMPTimeoutError, EasySNMPError from django.views.generic import ListView, DetailView +from devapp.base_intr import DeviceImplementationError from mydefs import res_success, res_error, only_admins, ping, ip_addr_regex from abonapp.models import Abon from group_app.models import Group @@ -23,7 +24,7 @@ from guardian.shortcuts import get_objects_for_user from chatbot.telebot import send_notify from chatbot.models import ChatException from jsonview.decorators import json_view -from djing.global_base_views import HashAuthView, AllowedSubnetMixin, OrderingMixin +from djing import global_base_views from .models import Device, Port, DeviceDBException, DeviceMonitoringException from .forms import DeviceForm, PortForm from mydefs import safe_int @@ -35,7 +36,7 @@ class BaseDeviceListView(ListView): @method_decorator([login_required, only_admins], name='dispatch') -class DevicesListView(BaseDeviceListView, OrderingMixin): +class DevicesListView(BaseDeviceListView, global_base_views.OrderingMixin): context_object_name = 'devices' template_name = 'devapp/devices.html' @@ -62,7 +63,7 @@ class DevicesListView(BaseDeviceListView, OrderingMixin): @method_decorator([login_required, only_admins], name='dispatch') -class DevicesWithoutGroupsListView(BaseDeviceListView, OrderingMixin): +class DevicesWithoutGroupsListView(BaseDeviceListView, global_base_views.OrderingMixin): context_object_name = 'devices' template_name = 'devapp/devices_null_group.html' queryset = Device.objects.filter(group=None).only('comment', 'devtype', 'pk', 'ip_address') @@ -179,7 +180,7 @@ def manage_ports(request, device_id): @method_decorator([login_required, only_admins], name='dispatch') -class ShowSubscriberOnPort(DetailView): +class ShowSubscriberOnPort(global_base_views.RedirectWhenErrorMixin, DetailView): template_name = 'devapp/manage_ports/modal_show_subscriber_on_port.html' http_method_names = ['get'] @@ -190,6 +191,14 @@ class ShowSubscriberOnPort(DetailView): obj = Abon.objects.get(device_id=dev_id, dev_port_id=port_id) except Abon.DoesNotExist: raise Http404(gettext('Subscribers on port does not exist')) + except Abon.MultipleObjectsReturned: + errmsg = gettext('More than one subscriber on device port') + # messages.error(self.request, errmsg) + raise global_base_views.RedirectWhenError( + resolve_url('devapp:fix_port_conflict', group_id=self.kwargs.get('group_id'), device_id=dev_id, + port_id=port_id), + errmsg + ) return obj @@ -370,7 +379,7 @@ def devview(request, device_id): }) except EasySNMPError: messages.error(request, _('SNMP error on device')) - except DeviceDBException as e: + except (DeviceDBException, DeviceImplementationError) as e: messages.error(request, e) return render(request, 'devapp/custom_dev_page/' + template_name, { 'dev': dev @@ -399,7 +408,7 @@ def toggle_port(request, device_id, portid, status=0): except EasySNMPTimeoutError: messages.error(request, _('wait for a reply from the SNMP Timeout')) except EasySNMPError as e: - messages.error(request, e) + messages.error(request, 'EasySNMPError: %s' % e) return redirect('devapp:view', dev.group.pk if dev.group is not None else 0, device_id) @@ -466,8 +475,8 @@ def fix_onu(request): if parent is not None: manobj = parent.get_manager_object() ports = manobj.get_list_keyval('.1.3.6.1.4.1.3320.101.10.1.1.3') - text = ' ' %\ - (_('Device with mac address %(mac)s does not exist') % {'mac': mac}) + text = ' ' % \ + (_('Device with mac address %(mac)s does not exist') % {'mac': mac}) for srcmac, snmpnum in ports: # convert bytes mac address to str presentation mac address real_mac = ':'.join(['%x' % ord(i) for i in srcmac]) @@ -501,7 +510,7 @@ def fix_port_conflict(request, group_id, device_id, port_id): }) -class OnDevDown(AllowedSubnetMixin, HashAuthView): +class OnDevDown(global_base_views.AllowedSubnetMixin, global_base_views.HashAuthView): # # Api view for monitoring devices # diff --git a/djing/global_base_views.py b/djing/global_base_views.py index 5eeb350..51040f2 100644 --- a/djing/global_base_views.py +++ b/djing/global_base_views.py @@ -1,14 +1,27 @@ from hashlib import sha256 +from json import dumps from django.views.generic.base import View -from django.http.response import HttpResponseForbidden +from django.http.response import HttpResponseForbidden, Http404, HttpResponseRedirect, HttpResponse +from django.utils.translation import gettext_lazy as _ from django.conf import settings +from django.views.generic import ListView from netaddr import IPNetwork, IPAddress - +from django.core.paginator import InvalidPage, EmptyPage API_AUTH_SECRET = getattr(settings, 'API_AUTH_SECRET') API_AUTH_SUBNET = getattr(settings, 'API_AUTH_SUBNET') +class RedirectWhenError(Exception): + def __init__(self, url, failed_message=None): + self.url = url + if failed_message is not None: + self.message = failed_message + + def __str__(self): + return self.message or '' + + class HashAuthView(View): @staticmethod @@ -87,4 +100,54 @@ class OrderingMixin(object): if direction == 'down': dfx = '-' if order_by: - return ["%s%s" % (dfx, order_by)] + return "%s%s" % (dfx, order_by) + + +class RedirectWhenErrorMixin(object): + + def get(self, request, *args, **kwargs): + try: + return super(RedirectWhenErrorMixin, self).get(request, *args, **kwargs) + except RedirectWhenError as e: + if request.is_ajax(): + return HttpResponse(dumps({ + 'url': e.url, + 'text': e.message or '' + })) + else: + return HttpResponseRedirect(e.url) + + +class BaseListWithFiltering(RedirectWhenErrorMixin, ListView): + """ + When queryset contains filter and pagination than data may be missing, + and original code is raising 404 error. We want to redirect without pagination. + """ + + def paginate_queryset(self, queryset, page_size): + paginator = self.get_paginator( + queryset, page_size, orphans=self.get_paginate_orphans(), + allow_empty_first_page=self.get_allow_empty()) + page_kwarg = self.page_kwarg + page = self.kwargs.get(page_kwarg) or self.request.GET.get(page_kwarg) or 1 + try: + page_number = int(page) + except ValueError: + if page == 'last': + page_number = paginator.num_pages + else: + raise Http404(_("Page is not 'last', nor can it be converted to an int.")) + try: + page = paginator.page(page_number) + return paginator, page, page.object_list, page.has_other_pages() + except EmptyPage: + # remove pagination from url + url = self.request.GET.copy() + del url[self.page_kwarg] + raise RedirectWhenError("%s?%s" % (self.request.path, url.urlencode()), + _('Filter does not contains data, filter without pagination')) + except InvalidPage as e: + raise Http404(_('Invalid page (%(page_number)s): %(message)s') % { + 'page_number': page_number, + 'message': str(e) + }) diff --git a/djing/local_settings.py.template b/djing/local_settings.py.template index 8f251a4..f3ac692 100644 --- a/djing/local_settings.py.template +++ b/djing/local_settings.py.template @@ -57,3 +57,5 @@ API_AUTH_SECRET = 'your api secret' # Allowed subnet for api API_AUTH_SUBNET = '127.0.0.0/8' +# Company name +COMPANY_NAME = 'Your company name' diff --git a/djing/settings.py b/djing/settings.py index 2148af7..481d10b 100644 --- a/djing/settings.py +++ b/djing/settings.py @@ -86,6 +86,9 @@ TEMPLATES = [ 'taskapp.context_proc.get_active_tasks_count', 'msg_app.context_processors.get_new_messages_count' ], + 'libraries': { + 'globaltags': 'djing.templatetags.globaltags', + } }, }, ] @@ -187,3 +190,6 @@ API_AUTH_SECRET = local_settings.API_AUTH_SECRET # Allowed subnet for api API_AUTH_SUBNET = local_settings.API_AUTH_SUBNET + +# Company name +COMPANY_NAME = local_settings.COMPANY_NAME diff --git a/djing/templatetags/__init__.py b/djing/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/djing/templatetags/globaltags.py b/djing/templatetags/globaltags.py new file mode 100644 index 0000000..9b36fd9 --- /dev/null +++ b/djing/templatetags/globaltags.py @@ -0,0 +1,9 @@ +from django import template +from django.conf import settings + +register = template.Library() + + +@register.simple_tag +def global_var(var_name): + return getattr(settings, var_name, '') diff --git a/mapapp/templates/maps/dot.html b/mapapp/templates/maps/dot.html index a1396b7..a063840 100644 --- a/mapapp/templates/maps/dot.html +++ b/mapapp/templates/maps/dot.html @@ -1,6 +1,7 @@ {% extends 'base.html' %} {% load i18n %} {% load bootstrap3 %} +{% load globaltags %} {% block main %}