From e7c8e6a49fa244e45ff1658643dd2920c60cd325 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 16 Aug 2017 12:10:59 +0300 Subject: [PATCH 01/22] =?UTF-8?q?FIXBUG:=20=D0=92=D1=8B=D0=BB=D0=B5=D1=82?= =?UTF-8?q?=D0=B0=D0=BB=D0=BE=20=D0=B5=D1=81=D0=BB=D0=B8=20=D0=BD=D0=B5?= =?UTF-8?q?=D1=82=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- taskapp/templates/taskapp/tasklist.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/taskapp/templates/taskapp/tasklist.html b/taskapp/templates/taskapp/tasklist.html index 860b025..f84b0cb 100644 --- a/taskapp/templates/taskapp/tasklist.html +++ b/taskapp/templates/taskapp/tasklist.html @@ -45,8 +45,13 @@ {{ task.get_mode_display }} {{ task.descr }} - {{ task.author.username }} + + {% if task.author %} + {{ task.author.username }} + {% else %} + {% trans 'Author does not exist' %} + {% endif %} + {{ task.time_of_create|date:'d E H:i' }} From 768cb57336591458a380e75b4043470201264933 Mon Sep 17 00:00:00 2001 From: bashmak Date: Tue, 29 Aug 2017 11:24:44 +0300 Subject: [PATCH 02/22] =?UTF-8?q?=D0=95=D1=81=D0=BB=D0=B8=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D0=B0=20=D1=8D=D0=BB=D0=B5=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=BE=D0=B2=20=D0=B2=D1=81=D0=B5=D0=B3=D0=BE?= =?UTF-8?q?=20=D0=BE=D0=B4=D0=BD=D0=B0=20=D1=82=D0=BE=20=D0=BD=D0=B5=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D0=B8=D0=BC=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=86=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D1=82=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/toolbar_page.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/toolbar_page.html b/templates/toolbar_page.html index 7e98819..f6da72a 100644 --- a/templates/toolbar_page.html +++ b/templates/toolbar_page.html @@ -1,3 +1,4 @@ +{% if pag.count > 1 %} {% load dpagination %}
@@ -22,3 +23,4 @@
+{% endif %} From 3cacdf682caf2318327c147647a2e8c53190b633 Mon Sep 17 00:00:00 2001 From: bashmak Date: Fri, 1 Sep 2017 16:01:48 +0300 Subject: [PATCH 03/22] FIXBUG --- abonapp/models.py | 20 ++++++++++++++++++-- agent/core.py | 4 +--- agent/mod_mikrotik.py | 10 ++++++---- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/abonapp/models.py b/abonapp/models.py index ce737ea..4f1d137 100644 --- a/abonapp/models.py +++ b/abonapp/models.py @@ -247,7 +247,7 @@ class PassportInfo(models.Model): date_of_acceptance = models.DateField() abon = models.OneToOneField(Abon, on_delete=models.SET_NULL, blank=True, null=True) - def __unicode__(self): + def __str__(self): return "%s %s" % (self.series, self.number) @@ -331,7 +331,7 @@ def abon_post_save(sender, instance, **kwargs): # обновляем абонента на NAS tm.update_user(agent_abon, ip_timeout=timeout) - except (NasFailedResult, NasNetworkError) as e: + except (NasFailedResult, NasNetworkError, ConnectionResetError) as e: print('ERROR:', e) return True @@ -357,6 +357,22 @@ def abon_tariff_post_init(sender, instance, **kwargs): instance.deadline = calc_obj.calc_deadline() +def abontariff_pre_delete(sender, instance, **kwargs): + try: + abon = Abon.objects.get(current_tariff=instance) + ab = abon.build_agent_struct() + if ab is None: + return True + tm = Transmitter() + tm.remove_user(ab) + except Abon.DoesNotExist: + print('ERROR: Abon.DoesNotExist') + except (NasFailedResult, NasNetworkError, ConnectionResetError) as e: + print('NetErr:', e) + return True + + models.signals.post_save.connect(abon_post_save, sender=Abon) models.signals.post_delete.connect(abon_del_signal, sender=Abon) models.signals.post_init.connect(abon_tariff_post_init, sender=AbonTariff) +models.signals.pre_delete.connect(abontariff_pre_delete, sender=AbonTariff) diff --git a/agent/core.py b/agent/core.py index 8299755..70a9818 100644 --- a/agent/core.py +++ b/agent/core.py @@ -19,8 +19,6 @@ class NasNetworkError(Exception): def check_input_type(*types): def real_check(fn): def wrapped(self, *args): - if len(types) != len(args): - raise AttributeError("length of @types must be equivalent for length of @args") for param_type, param in zip(types, args): if not isinstance(param, param_type): raise TypeError("%s must be %s, but is %s" % (str(param), str(param_type), type(param))) @@ -97,7 +95,7 @@ class BaseTransmitter(metaclass=ABCMeta): """ @abstractmethod - @check_input_type(str) + @check_input_type(str, int) def ping(self, host, count=10): """ :param host: ip адрес в текстовом виде, например '192.168.0.1' diff --git a/agent/mod_mikrotik.py b/agent/mod_mikrotik.py index dcb7069..d6ad1cc 100644 --- a/agent/mod_mikrotik.py +++ b/agent/mod_mikrotik.py @@ -6,7 +6,7 @@ from hashlib import md5 from .core import BaseTransmitter, NasFailedResult, NasNetworkError from mydefs import ping from .structs import TariffStruct, AbonStruct, IpStruct -from . import settings +from . import settings as local_settings from django.conf import settings import re @@ -144,15 +144,17 @@ class ApiRos: class TransmitterManager(BaseTransmitter, metaclass=ABCMeta): def __init__(self, login=None, password=None, ip=None, port=None): - ip = ip or settings.NAS_IP + ip = ip or getattr(local_settings, 'NAS_IP') + if ip is None: + raise NasNetworkError('Не передан ip адрес NAS') if not ping(ip): raise NasNetworkError('NAS %s не пингуется' % ip) try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.connect((ip, port or settings.NAS_PORT)) + s.connect((ip, port or getattr(local_settings, 'NAS_PORT', 8728))) self.s = s self.ar = ApiRos(s) - self.ar.login(login or settings.NAS_LOGIN, password or settings.NAS_PASSW) + self.ar.login(login or getattr(local_settings, 'NAS_LOGIN'), password or getattr(local_settings, 'NAS_PASSW')) except ConnectionRefusedError: raise NasNetworkError('Подключение к %s отклонено (Connection Refused)' % ip) From c673fe031bc19d022c8cc548c98fcd7c19342130 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Fri, 1 Sep 2017 16:12:10 +0300 Subject: [PATCH 04/22] fixbug --- agent/core.py | 4 ++-- cron.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/agent/core.py b/agent/core.py index 8299755..afcb9d8 100644 --- a/agent/core.py +++ b/agent/core.py @@ -32,12 +32,12 @@ def check_input_type(*types): # Общается с NAS'ом class BaseTransmitter(metaclass=ABCMeta): @abstractmethod - @check_input_type(AbonStruct) + @check_input_type(set) def add_user_range(self, user_list): """добавляем список абонентов в NAS""" @abstractmethod - @check_input_type(AbonStruct) + @check_input_type(set) def remove_user_range(self, users): """удаляем список абонентов""" diff --git a/cron.py b/cron.py index 1369392..221b2d6 100755 --- a/cron.py +++ b/cron.py @@ -10,8 +10,6 @@ from mydefs import LogicError def main(): - tm = None - users = Abon.objects.all() for user in users: try: @@ -34,15 +32,17 @@ def main(): continue # обновляем абонента если он статический. Иначе его обновит dhcp - if user.opt82 is None: - if tm is None: - tm = Transmitter() - tm.update_user(ab) + #if tm is None: + # tm = Transmitter() + #tm.update_user(ab) except (NasNetworkError, NasFailedResult) as er: print("Error:", er) except LogicError as er: print("Notice:", er) + tm = Transmitter() + users = Abon.objects.filter(is_dynamic_ip=False) + tm.sync_nas(users) if __name__ == "__main__": From 4edef3cf93922d7934908242f438d4ed7622da5f Mon Sep 17 00:00:00 2001 From: bashmak Date: Fri, 1 Sep 2017 16:45:23 +0300 Subject: [PATCH 05/22] =?UTF-8?q?FIXBUG:=20=D0=B2=20=D0=BD=D0=B0=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=B0=D1=85=20=D0=BC=D0=BE=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=20=D1=83=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D1=8B?= =?UTF-8?q?=20=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=B2=20=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=85=D0=BD=D0=B5=D0=BC=20=D1=80=D0=B5=D0=B3=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- abonapp/pay_systems.py | 4 ++-- djing/settings_example.py | 4 ++-- docs/install.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/abonapp/pay_systems.py b/abonapp/pay_systems.py index c159507..cd7bccb 100644 --- a/abonapp/pay_systems.py +++ b/abonapp/pay_systems.py @@ -6,8 +6,8 @@ from django.db import DatabaseError from django.conf import settings -SECRET = getattr(settings, 'pay_SECRET') -SERV_ID = getattr(settings, 'pay_SERV_ID') +SECRET = getattr(settings, 'PAY_SECRET') +SERV_ID = getattr(settings, 'PAY_SERV_ID') #?ACT=1&PAY_ACCOUNT=960849&SERVICE_ID=y832r92y8f9e&PAY_ID=3561234&TRADE_POINT=377&SIGN=32e533a72389fe4e93746509f9d672f8 diff --git a/djing/settings_example.py b/djing/settings_example.py index fc038d8..db346b8 100644 --- a/djing/settings_example.py +++ b/djing/settings_example.py @@ -158,8 +158,8 @@ LOGOUT_URL = reverse_lazy('acc_app:logout_link') PAGINATION_ITEMS_PER_PAGE=10 -pay_SERV_ID = '' -pay_SECRET = '' +PAY_SERV_ID = '' +PAY_SECRET = '' DIALING_MEDIA = 'path/to/asterisk_records' diff --git a/docs/install.md b/docs/install.md index 62ecd2a..f146701 100644 --- a/docs/install.md +++ b/docs/install.md @@ -198,7 +198,7 @@ plugin=python3 **PAGINATION_ITEMS_PER_PAGE** — Количество выводимых элементов списка на странце с таблицей. Например, если поставить 30, то на странице абонентов на одной странице будет выведено 30 строк абонентов. -**pay_SERV_ID** — Эта опция, так же как и **pay_SECRET** опции для платёжной системы *AllTime24*, если вы используете любую +**PAY_SERV_ID** — Эта опция, так же как и **PAY_SECRET** опции для платёжной системы *AllTime24*, если вы используете любую другую платёжную систему то можете удалить эти опции. **DIALING_MEDIA** — Путь, где биллинг сможет найти файлы записей asterisk чтоб вывести статистику звонков. From b74c5c0200a591ddde063d85b017e590d5cf0ebd Mon Sep 17 00:00:00 2001 From: bashmak Date: Sat, 2 Sep 2017 11:55:14 +0300 Subject: [PATCH 06/22] fix --- abonapp/models.py | 4 ++-- dialing_app/models.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/abonapp/models.py b/abonapp/models.py index 4f1d137..794744c 100644 --- a/abonapp/models.py +++ b/abonapp/models.py @@ -8,7 +8,7 @@ from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNet from tariff_app.models import Tariff from accounts_app.models import UserProfile from mydefs import MyGenericIPAddressField, ip2int, LogicError, ip_addr_regex -from djing import settings +from django.conf import settings class AbonGroup(models.Model): @@ -226,7 +226,7 @@ class Abon(UserProfile): return abon_tariff = self.active_tariff() if abon_tariff is None: - agent_trf = TariffStruct() + agent_trf = None else: trf = abon_tariff.tariff agent_trf = TariffStruct(trf.id, trf.speedIn, trf.speedOut) diff --git a/dialing_app/models.py b/dialing_app/models.py index ff6c720..e448e91 100644 --- a/dialing_app/models.py +++ b/dialing_app/models.py @@ -1,6 +1,6 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -from djing import settings +from django.conf import settings class AsteriskCDR(models.Model): From 2677d72b210d2a87d274ff3187d11c26f446b387 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Sat, 2 Sep 2017 15:47:25 +0300 Subject: [PATCH 07/22] fix --- templates/toolbar_page.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/toolbar_page.html b/templates/toolbar_page.html index f6da72a..58f6d33 100644 --- a/templates/toolbar_page.html +++ b/templates/toolbar_page.html @@ -1,4 +1,4 @@ -{% if pag.count > 1 %} +{% if pag.paginator.num_pages > 1 %} {% load dpagination %}
From 13a5cbb4d5d2740af404a33833b46f74b0c18173 Mon Sep 17 00:00:00 2001 From: bashmak Date: Mon, 4 Sep 2017 14:55:21 +0300 Subject: [PATCH 08/22] =?UTF-8?q?FIXBUG:=20=D0=92=20=D1=84=D1=83=D0=BD?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D0=B8=20bill=5Fservice=20=D0=B5=D1=81=D0=BB?= =?UTF-8?q?=D0=B8=20=D1=83=20=D0=B0=D0=B1=D0=BE=D0=BD=D0=B5=D0=BD=D1=82?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B5=D0=B1=D1=8B=D0=BB=D0=BE=20=D1=83=D1=81?= =?UTF-8?q?=D0=BB=D1=83=D0=B3=D0=B8=20=D1=82=D0=BE=20=D0=B2=D1=8B=D0=BB?= =?UTF-8?q?=D0=B5=D1=82=D0=B0=D0=BB=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- abonapp/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/abonapp/models.py b/abonapp/models.py index 794744c..ec59e76 100644 --- a/abonapp/models.py +++ b/abonapp/models.py @@ -203,6 +203,8 @@ class Abon(UserProfile): # Производим расчёт услуги абонента, т.е. завершаем если пришло время def bill_service(self, author): abon_tariff = self.active_tariff() + if abon_tariff is None: + return nw = timezone.now() # если услуга просрочена if nw > abon_tariff.deadline: From 232fe3f2e0d6c513e124b434b7198bd0cafbc36e Mon Sep 17 00:00:00 2001 From: bashmak Date: Mon, 4 Sep 2017 14:56:57 +0300 Subject: [PATCH 09/22] =?UTF-8?q?REFACTOR:=20=D0=B2=D1=8B=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=81=D0=BE=D0=BB=D1=8C=20?= =?UTF-8?q?=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=B5=D1=81=D0=BB=D0=B8?= =?UTF-8?q?=20=D0=B5=D1=81=D1=82=D1=8C=20=D1=87=D1=82=D0=BE=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B2=D0=BE=D0=B4=D0=B8=D1=82=D1=8C.=20=D0=95=D1=81=D0=BB?= =?UTF-8?q?=D0=B8=20=D1=81=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=BA=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=B4=D0=B0?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88?= =?UTF-8?q?=D0=B5=200=20=D1=82=D0=BE=20=D1=82=D0=BE=D0=B3=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=B8=D1=88=D0=B5=D0=BC=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=B8=20=D1=83=D0=B4=D0=B0=D0=BB=D1=8F=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- agent/core.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/agent/core.py b/agent/core.py index f984105..3b04294 100644 --- a/agent/core.py +++ b/agent/core.py @@ -124,11 +124,13 @@ class BaseTransmitter(metaclass=ABCMeta): def sync_nas(self, users_from_db): list_for_add, list_for_del = self._diff_users(users_from_db) - print('FOR DELETE') - for ld in list_for_del: - print(ld) - print('FOR ADD') - for la in list_for_add: - print(la) - self.remove_user_range( list_for_del ) - self.add_user_range( list_for_add ) + if len(list_for_del) > 0: + print('FOR DELETE') + for ld in list_for_del: + print(ld) + self.remove_user_range(list_for_del) + if len(list_for_add) > 0: + print('FOR ADD') + for la in list_for_add: + print(la) + self.add_user_range(list_for_add) From a52796a63695349938de03dfd6d25c8f377589de Mon Sep 17 00:00:00 2001 From: bashmak Date: Mon, 4 Sep 2017 14:57:45 +0300 Subject: [PATCH 10/22] fix --- agent/mod_mikrotik.py | 26 +++++++++++++++++++------- cron.py | 26 ++++---------------------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/agent/mod_mikrotik.py b/agent/mod_mikrotik.py index d6ad1cc..89bea50 100644 --- a/agent/mod_mikrotik.py +++ b/agent/mod_mikrotik.py @@ -274,8 +274,7 @@ class QueueManager(TransmitterManager, metaclass=ABCMeta): # читаем шейпер, возващаем записи о шейпере def read_queue_iter(self): - queues = self._exec_cmd_iter(['/queue/simple/print', '=detail']) - for queue in queues: + for queue in self._exec_cmd_iter(['/queue/simple/print', '=detail']): if queue[0] == '!done': return sobj = self._build_shape_obj(queue[1]) if sobj is not None: @@ -348,7 +347,7 @@ class IpAddressListManager(TransmitterManager, metaclass=ABCMeta): if len(ids) > 0: return self._exec_cmd([ '/ip/firewall/address-list/remove', - 'numbers=' + ','.join(ids) + '=numbers=*%s' % ',*'.join(ids) ]) def find(self, ip, list_name): @@ -361,10 +360,14 @@ class IpAddressListManager(TransmitterManager, metaclass=ABCMeta): ]) def read_ips_iter(self, list_name): - return self._exec_cmd([ + ips = self._exec_cmd_iter([ '/ip/firewall/address-list/print', 'where', - '?list=%s' % list_name + '?list=%s' % list_name, + '?dynamic=no' ]) + for code, dat in ips: + if dat != {}: + yield IpAddressListObj(dat['=address'], dat['=.id']) def disable(self, user): r = IpAddressListManager.find(self, user.ip, LIST_USERS_ALLOWED) @@ -500,6 +503,15 @@ class MikrotikTransmitter(QueueManager, IpAddressListManager): def read_users(self): # shapes is ShapeItem - # allowed_ips = IpAddressListManager.read_ips_iter(self, LIST_USERS_ALLOWED) - queues = QueueManager.read_queue_iter(self) + allowed_ips = set(IpAddressListManager.read_ips_iter(self, LIST_USERS_ALLOWED)) + queues = set(q for q in QueueManager.read_queue_iter(self) if q.ip in allowed_ips) + + ips_from_queues = set([q.ip for q in queues]) + allowed_ips = set(allowed_ips) + + # удаляем ip адреса которые есть в firewall/address-list и нет соответствующих в queues + diff = list(allowed_ips - ips_from_queues) + if len(diff) > 0: + IpAddressListManager.remove_range(self, diff) + return queues diff --git a/cron.py b/cron.py index 872c4f1..0f8d6b6 100755 --- a/cron.py +++ b/cron.py @@ -16,32 +16,12 @@ def main(): # бдим за услугами абонента user.bill_service(user) - # если нет ip то и нет смысла лезть в NAS - if user.ip_address is None: - continue - - # а есть-ли у абонента доступ к услуге - if not user.is_access(): - continue - - # строим структуру агента - ab = user.build_agent_struct() - if ab is None: - # если не построилась структура агента, значит нет ip - # а если нет ip то и синхронизировать абонента без ip нельзя - continue - - # обновляем абонента если он статический. Иначе его обновит dhcp - #if tm is None: - # tm = Transmitter() - #tm.update_user(ab) - except (NasNetworkError, NasFailedResult) as er: print("Error:", er) except LogicError as er: print("Notice:", er) tm = Transmitter() - users = Abon.objects.filter(is_dynamic_ip=False) + users = Abon.objects.filter(is_dynamic_ip=False, is_active=True).exclude(current_tariff=None) tm.sync_nas(users) @@ -49,4 +29,6 @@ if __name__ == "__main__": try: main() except (NasNetworkError, NasFailedResult) as e: - print('NAS:', e) + print("Error while sync nas:", e) + except LogicError as e: + print("Notice while sync nas:", e) From 8655427df6d787f788fdf1b303493e389a01f099 Mon Sep 17 00:00:00 2001 From: bashmak Date: Mon, 4 Sep 2017 16:21:28 +0300 Subject: [PATCH 11/22] =?UTF-8?q?=D0=A1=D0=B6=D0=B0=D1=82=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0001_squashed_0022_auto_20170816_1109.py | 334 ++++++++++++++++++ .../0001_squashed_0007_auto_20170816_1109.py | 92 +++++ devapp/migrations/0002_device_user_group.py | 22 ++ 3 files changed, 448 insertions(+) create mode 100644 abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py create mode 100644 devapp/migrations/0001_squashed_0007_auto_20170816_1109.py create mode 100644 devapp/migrations/0002_device_user_group.py diff --git a/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py b/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py new file mode 100644 index 0000000..9e94ff7 --- /dev/null +++ b/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py @@ -0,0 +1,334 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-09-04 16:15 +from __future__ import unicode_literals + +from django.conf import settings +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import mydefs +import re + + +class Migration(migrations.Migration): + + replaces = [('abonapp', '0001_initial'), ('abonapp', '0002_auto_20161206_2135'), ('abonapp', '0003_abongroup_profiles'), ('abonapp', '0004_auto_20161220_0102'), ('abonapp', '0005_auto_20161226_0054'), ('abonapp', '0006_auto_20170128_1626'), ('abonapp', '0007_auto_20170131_1650'), ('abonapp', '0008_auto_20170209_0002'), ('abonapp', '0009_abontariff_death_line'), ('abonapp', '0010_auto_20170220_1630'), ('abonapp', '0011_auto_20170222_2224'), ('abonapp', '0012_auto_20170227_1718'), ('abonapp', '0013_abongroup_tariffs'), ('abonapp', '0014_auto_20170330_1452'), ('abonapp', '0015_passportinfo'), ('abonapp', '0016_auto_20170415_1311'), ('abonapp', '0017_auto_20170416_1029'), ('abonapp', '0018_auto_20170418_1236'), ('abonapp', '0019_abon_ip_address'), ('abonapp', '0020_auto_20170517_1655'), ('abonapp', '0021_auto_20170705_1403'), ('abonapp', '0022_auto_20170816_1109')] + + initial = True + + dependencies = [ + ('devapp', '0001_squashed_0007_auto_20170816_1109'), + ('tariff_app', '0002_tariff_descr'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('accounts_app', '0001_initial'), + ('tariff_app', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Abon', + fields=[ + ('userprofile_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), + ('ballance', models.FloatField(default=0.0, validators=[django.core.validators.DecimalValidator])), + ('address', models.CharField(max_length=256)), + ], + options={ + 'db_table': 'abonent', + }, + bases=('accounts_app.userprofile',), + ), + migrations.CreateModel( + name='AbonGroup', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=127, unique=True)), + ], + options={ + 'db_table': 'abonent_groups', + }, + ), + migrations.CreateModel( + name='AbonLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('amount', models.FloatField(default=0.0)), + ('comment', models.CharField(max_length=128)), + ('date', models.DateTimeField(auto_now_add=True)), + ('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'abonent_log', + }, + ), + migrations.CreateModel( + name='AbonTariff', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('tariff_priority', models.PositiveSmallIntegerField(default=0)), + ('time_start', models.DateTimeField(blank=True, default=None, null=True)), + ('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), + ('tariff', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='linkto_tariff', to='tariff_app.Tariff')), + ], + options={ + 'ordering': ('tariff_priority',), + 'db_table': 'abonent_tariff', + }, + ), + migrations.CreateModel( + name='InvoiceForPayment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.BooleanField(default=False)), + ('amount', models.FloatField(default=0.0)), + ('comment', models.CharField(max_length=128)), + ('date_create', models.DateTimeField(auto_now_add=True)), + ('date_pay', models.DateTimeField(blank=True, null=True)), + ('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), + ('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ('date_create',), + 'db_table': 'abonent_inv_pay', + }, + ), + migrations.AddField( + model_name='abon', + name='current_tariffs', + field=models.ManyToManyField(through='abonapp.AbonTariff', to='tariff_app.Tariff'), + ), + migrations.AddField( + model_name='abon', + name='group', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonGroup'), + ), + migrations.AlterUniqueTogether( + name='abontariff', + unique_together=set([('abon', 'tariff', 'tariff_priority')]), + ), + migrations.AddField( + model_name='abongroup', + name='profiles', + field=models.ManyToManyField(blank=True, related_name='abon_groups', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterModelOptions( + name='abon', + options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'),)}, + ), + migrations.AlterModelOptions( + name='abongroup', + options={'permissions': (('can_add_ballance', 'Пополнение счёта'),)}, + ), + migrations.AlterModelOptions( + name='abontariff', + options={'ordering': ('tariff_priority',), 'permissions': (('can_complete_service', 'Досрочное завершение услуги абонента'), ('can_activate_service', 'Активация услуги абонента'))}, + ), + migrations.CreateModel( + name='AbonStreet', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=64)), + ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.AbonGroup')), + ], + ), + migrations.RemoveField( + model_name='abon', + name='address', + ), + migrations.AddField( + model_name='abon', + name='description', + field=models.TextField(blank=True, null=True), + ), + migrations.AddField( + model_name='abon', + name='house', + field=models.CharField(blank=True, max_length=12, null=True), + ), + migrations.AddField( + model_name='abon', + name='street', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonStreet'), + ), + migrations.CreateModel( + name='AllPayLog', + fields=[ + ('pay_id', models.CharField(max_length=64, primary_key=True, serialize=False)), + ('date_action', models.DateTimeField(auto_now_add=True)), + ('summ', models.FloatField(default=0.0)), + ('pay_system_name', models.CharField(max_length=16)), + ], + options={ + 'db_table': 'all_pay_log', + 'ordering': ('date_action',), + }, + ), + migrations.CreateModel( + name='AllTimePayLog', + fields=[ + ('pay_id', models.CharField(max_length=36, primary_key=True, serialize=False, unique=True)), + ('date_add', models.DateTimeField(auto_now_add=True)), + ('summ', models.FloatField(default=0.0)), + ], + options={ + 'db_table': 'all_time_pay_log', + 'ordering': ('date_add',), + }, + ), + migrations.CreateModel( + name='AbonRawPassword', + fields=[ + ('account', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='abonapp.Abon')), + ('passw_text', models.CharField(max_length=64)), + ], + options={ + 'db_table': 'abon_raw_password', + }, + ), + migrations.AlterModelTable( + name='abonstreet', + table='abon_street', + ), + migrations.AddField( + model_name='abontariff', + name='deadline', + field=models.DateTimeField(blank=True, default=None, null=True), + ), + migrations.CreateModel( + name='ExtraFieldsModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('field_type', models.CharField(choices=[('int', 'Цифровое поле'), ('str', 'Текстовое поле'), ('dbl', 'Дробное с плавающей точкой'), ('ipa', 'IP Адрес')], default='str', max_length=3)), + ('data', models.CharField(blank=True, max_length=64, null=True)), + ('title', models.CharField(default='no title', max_length=16)), + ], + options={ + 'db_table': 'abon_extra_fields', + }, + ), + migrations.AlterModelOptions( + name='abon', + options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Can view passport'))}, + ), + migrations.AlterModelOptions( + name='abontariff', + options={'ordering': ('tariff_priority',), 'permissions': (('can_complete_service', 'Снятие со счёта средств'), ('can_activate_service', 'Активация услуги абонента'))}, + ), + migrations.AlterField( + model_name='abon', + name='ballance', + field=models.FloatField(default=0.0), + ), + migrations.AlterModelOptions( + name='abon', + options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Может просматривать паспортные данные'))}, + ), + migrations.AddField( + model_name='abon', + name='extra_fields', + field=models.ManyToManyField(blank=True, to='abonapp.ExtraFieldsModel'), + ), + migrations.AddField( + model_name='abongroup', + name='tariffs', + field=models.ManyToManyField(blank=True, related_name='tariff_groups', to='tariff_app.Tariff'), + ), + migrations.AddField( + model_name='abon', + name='opt82', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='abonapp.Opt82'), + ), + migrations.CreateModel( + name='PassportInfo', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('series', models.CharField(max_length=4, validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z', 32), code='invalid', message='Enter a valid integer.')])), + ('number', models.CharField(max_length=6, validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z', 32), code='invalid', message='Enter a valid integer.')])), + ('distributor', models.CharField(max_length=64)), + ('date_of_acceptance', models.DateField()), + ('abon', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.Abon')), + ], + ), + migrations.AlterField( + model_name='abon', + name='opt82', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.Opt82'), + ), + migrations.CreateModel( + name='AbonDevice', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('abon', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), + ('device', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device')), + ], + options={ + 'db_table': 'abon_device', + }, + ), + migrations.AlterUniqueTogether( + name='abondevice', + unique_together=set([('abon', 'device')]), + ), + migrations.AlterField( + model_name='abondevice', + name='abon', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon'), + ), + migrations.AlterField( + model_name='abondevice', + name='device', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device'), + ), + migrations.AddField( + model_name='abon', + name='ip_address', + field=mydefs.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4'), + ), + migrations.RemoveField( + model_name='abon', + name='opt82', + ), + migrations.AddField( + model_name='abon', + name='dev_port', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Port'), + ), + migrations.AddField( + model_name='abon', + name='device', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Device'), + ), + migrations.AddField( + model_name='abon', + name='is_dynamic_ip', + field=models.BooleanField(default=False), + ), + migrations.DeleteModel( + name='AbonDevice', + ), + migrations.AlterModelOptions( + name='abontariff', + options={'permissions': (('can_complete_service', 'Снятие со счёта средств'),)}, + ), + migrations.RemoveField( + model_name='abon', + name='current_tariffs', + ), + migrations.AddField( + model_name='abon', + name='current_tariff', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonTariff'), + ), + migrations.AlterUniqueTogether( + name='abontariff', + unique_together=set([]), + ), + migrations.RemoveField( + model_name='abontariff', + name='abon', + ), + migrations.RemoveField( + model_name='abontariff', + name='tariff_priority', + ), + ] diff --git a/devapp/migrations/0001_squashed_0007_auto_20170816_1109.py b/devapp/migrations/0001_squashed_0007_auto_20170816_1109.py new file mode 100644 index 0000000..11827a5 --- /dev/null +++ b/devapp/migrations/0001_squashed_0007_auto_20170816_1109.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-09-04 16:14 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion +import djing.fields +import mydefs + + +class Migration(migrations.Migration): + + replaces = [('devapp', '0001_initial'), ('devapp', '0002_auto_20160909_1018'), ('devapp', '0003_device_map_dot'), ('devapp', '0004_device_user_group'), ('devapp', '0005_auto_20170502_2232'), ('devapp', '0006_auto_20170705_1403'), ('devapp', '0007_auto_20170816_1109')] + + initial = True + + dependencies = [ + ('mapapp', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Device', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ip_address', mydefs.MyGenericIPAddressField(max_length=8, protocol='ipv4')), + ('comment', models.CharField(max_length=256)), + ('devtype', models.CharField(choices=[('Dl', "Свич D'Link")], default='Dl', max_length=2)), + ('man_passw', models.CharField(blank=True, max_length=16, null=True)), + ], + ), + migrations.CreateModel( + name='Port', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('num', models.PositiveSmallIntegerField(default=0)), + ('speed', models.CharField(choices=[('h', '100Mbps'), ('k', '1Gbps'), ('d', '10Gbps')], default='h', max_length=1)), + ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device')), + ], + ), + migrations.AlterUniqueTogether( + name='port', + unique_together=set([('device', 'num')]), + ), + migrations.AlterModelTable( + name='device', + table='dev', + ), + migrations.AlterModelTable( + name='port', + table='dev_port', + ), + migrations.AddField( + model_name='device', + name='map_dot', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mapapp.Dot'), + ), + migrations.AlterField( + model_name='device', + name='devtype', + field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT')], default='Dl', max_length=2), + ), + migrations.RemoveField( + model_name='port', + name='speed', + ), + migrations.AddField( + model_name='device', + name='mac_addr', + field=djing.fields.MACAddressField(blank=True, integer=True, null=True, unique=True), + ), + migrations.AddField( + model_name='device', + name='parent_dev', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Device'), + ), + migrations.AddField( + model_name='port', + name='descr', + field=models.CharField(blank=True, max_length=60, null=True), + ), + migrations.AlterField( + model_name='device', + name='devtype', + field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU')], default='Dl', max_length=2), + ), + migrations.AlterField( + model_name='device', + name='devtype', + field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU'), ('Ex', 'Eltex switch')], default='Dl', max_length=2), + ), + ] diff --git a/devapp/migrations/0002_device_user_group.py b/devapp/migrations/0002_device_user_group.py new file mode 100644 index 0000000..7fbbecb --- /dev/null +++ b/devapp/migrations/0002_device_user_group.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-09-04 16:16 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('abonapp', '0001_squashed_0022_auto_20170816_1109'), + ('devapp', '0001_squashed_0007_auto_20170816_1109'), + ] + + operations = [ + migrations.AddField( + model_name='device', + name='user_group', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonGroup'), + ), + ] From 5704362e95b14a161da0b2e3ea307d8ebd2fb89b Mon Sep 17 00:00:00 2001 From: bashmak Date: Mon, 4 Sep 2017 16:28:05 +0300 Subject: [PATCH 12/22] =?UTF-8?q?=D0=A1=D0=B6=D0=B0=D0=BB=20=D0=BC=D0=B8?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20abonapp=20=D0=B8=20devap?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- abonapp/migrations/0001_initial.py | 108 ------------------ .../0001_squashed_0022_auto_20170816_1109.py | 2 - abonapp/migrations/0002_auto_20161206_2135.py | 23 ---- abonapp/migrations/0003_abongroup_profiles.py | 20 ---- abonapp/migrations/0004_auto_20161220_0102.py | 19 --- abonapp/migrations/0005_auto_20161226_0054.py | 25 ---- abonapp/migrations/0006_auto_20170128_1626.py | 41 ------- abonapp/migrations/0007_auto_20170131_1650.py | 42 ------- abonapp/migrations/0008_auto_20170209_0002.py | 27 ----- .../migrations/0009_abontariff_death_line.py | 20 ---- abonapp/migrations/0010_auto_20170220_1630.py | 43 ------- abonapp/migrations/0011_auto_20170222_2224.py | 24 ---- abonapp/migrations/0012_auto_20170227_1718.py | 24 ---- abonapp/migrations/0013_abongroup_tariffs.py | 21 ---- abonapp/migrations/0014_auto_20170330_1452.py | 42 ------- abonapp/migrations/0015_passportinfo.py | 35 ------ abonapp/migrations/0016_auto_20170415_1311.py | 32 ------ abonapp/migrations/0017_auto_20170416_1029.py | 22 ---- abonapp/migrations/0018_auto_20170418_1236.py | 26 ----- abonapp/migrations/0019_abon_ip_address.py | 21 ---- abonapp/migrations/0020_auto_20170517_1655.py | 25 ---- abonapp/migrations/0021_auto_20170705_1403.py | 42 ------- abonapp/migrations/0022_auto_20170816_1109.py | 41 ------- devapp/migrations/0001_initial.py | 51 --------- .../0001_squashed_0007_auto_20170816_1109.py | 2 - devapp/migrations/0002_auto_20160909_1018.py | 22 ---- devapp/migrations/0003_device_map_dot.py | 20 ---- devapp/migrations/0004_device_user_group.py | 22 ---- devapp/migrations/0005_auto_20170502_2232.py | 20 ---- devapp/migrations/0006_auto_20170705_1403.py | 48 -------- devapp/migrations/0007_auto_20170816_1109.py | 20 ---- 31 files changed, 930 deletions(-) delete mode 100644 abonapp/migrations/0001_initial.py delete mode 100644 abonapp/migrations/0002_auto_20161206_2135.py delete mode 100644 abonapp/migrations/0003_abongroup_profiles.py delete mode 100644 abonapp/migrations/0004_auto_20161220_0102.py delete mode 100644 abonapp/migrations/0005_auto_20161226_0054.py delete mode 100644 abonapp/migrations/0006_auto_20170128_1626.py delete mode 100644 abonapp/migrations/0007_auto_20170131_1650.py delete mode 100644 abonapp/migrations/0008_auto_20170209_0002.py delete mode 100644 abonapp/migrations/0009_abontariff_death_line.py delete mode 100644 abonapp/migrations/0010_auto_20170220_1630.py delete mode 100644 abonapp/migrations/0011_auto_20170222_2224.py delete mode 100644 abonapp/migrations/0012_auto_20170227_1718.py delete mode 100644 abonapp/migrations/0013_abongroup_tariffs.py delete mode 100644 abonapp/migrations/0014_auto_20170330_1452.py delete mode 100644 abonapp/migrations/0015_passportinfo.py delete mode 100644 abonapp/migrations/0016_auto_20170415_1311.py delete mode 100644 abonapp/migrations/0017_auto_20170416_1029.py delete mode 100644 abonapp/migrations/0018_auto_20170418_1236.py delete mode 100644 abonapp/migrations/0019_abon_ip_address.py delete mode 100644 abonapp/migrations/0020_auto_20170517_1655.py delete mode 100644 abonapp/migrations/0021_auto_20170705_1403.py delete mode 100644 abonapp/migrations/0022_auto_20170816_1109.py delete mode 100644 devapp/migrations/0001_initial.py delete mode 100644 devapp/migrations/0002_auto_20160909_1018.py delete mode 100644 devapp/migrations/0003_device_map_dot.py delete mode 100644 devapp/migrations/0004_device_user_group.py delete mode 100644 devapp/migrations/0005_auto_20170502_2232.py delete mode 100644 devapp/migrations/0006_auto_20170705_1403.py delete mode 100644 devapp/migrations/0007_auto_20170816_1109.py diff --git a/abonapp/migrations/0001_initial.py b/abonapp/migrations/0001_initial.py deleted file mode 100644 index 7b1368f..0000000 --- a/abonapp/migrations/0001_initial.py +++ /dev/null @@ -1,108 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-06-28 23:51 - -from django.conf import settings -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - initial = True - - dependencies = [ - ('accounts_app', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('tariff_app', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='Abon', - fields=[ - ('userprofile_ptr', - models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, - primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), - ('ballance', models.FloatField(default=0.0, validators=[django.core.validators.DecimalValidator])), - ('address', models.CharField(max_length=256)), - ], - options={ - 'db_table': 'abonent', - }, - bases=('accounts_app.userprofile',), - ), - migrations.CreateModel( - name='AbonGroup', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('title', models.CharField(max_length=127)), - ('address', models.CharField(blank=True, max_length=256, null=True)), - ], - options={ - 'db_table': 'abonent_groups', - }, - ), - migrations.CreateModel( - name='AbonLog', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('amount', models.FloatField(default=0.0)), - ('comment', models.CharField(max_length=128)), - ('date', models.DateTimeField(auto_now_add=True)), - ('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', - to=settings.AUTH_USER_MODEL)), - ], - options={ - 'db_table': 'abonent_log', - }, - ), - migrations.CreateModel( - name='AbonTariff', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('tariff_priority', models.PositiveSmallIntegerField(default=0)), - ('time_start', models.DateTimeField(blank=True, default=None, null=True)), - ('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), - ('tariff', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='linkto_tariff', - to='tariff_app.Tariff')), - ], - options={ - 'ordering': ('tariff_priority',), - 'db_table': 'abonent_tariff', - }, - ), - migrations.CreateModel( - name='InvoiceForPayment', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('status', models.BooleanField(default=False)), - ('amount', models.FloatField(default=0.0)), - ('comment', models.CharField(max_length=128)), - ('date_create', models.DateTimeField(auto_now_add=True)), - ('date_pay', models.DateTimeField(blank=True, null=True)), - ('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', - to=settings.AUTH_USER_MODEL)), - ], - options={ - 'ordering': ('date_create',), - 'db_table': 'abonent_inv_pay', - }, - ), - migrations.AddField( - model_name='abon', - name='current_tariffs', - field=models.ManyToManyField(through='abonapp.AbonTariff', to='tariff_app.Tariff'), - ), - migrations.AddField( - model_name='abon', - name='group', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, - to='abonapp.AbonGroup'), - ), - migrations.AlterUniqueTogether( - name='abontariff', - unique_together={('abon', 'tariff', 'tariff_priority')}, - ), - ] diff --git a/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py b/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py index 9e94ff7..b68d5ef 100644 --- a/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py +++ b/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py @@ -12,8 +12,6 @@ import re class Migration(migrations.Migration): - replaces = [('abonapp', '0001_initial'), ('abonapp', '0002_auto_20161206_2135'), ('abonapp', '0003_abongroup_profiles'), ('abonapp', '0004_auto_20161220_0102'), ('abonapp', '0005_auto_20161226_0054'), ('abonapp', '0006_auto_20170128_1626'), ('abonapp', '0007_auto_20170131_1650'), ('abonapp', '0008_auto_20170209_0002'), ('abonapp', '0009_abontariff_death_line'), ('abonapp', '0010_auto_20170220_1630'), ('abonapp', '0011_auto_20170222_2224'), ('abonapp', '0012_auto_20170227_1718'), ('abonapp', '0013_abongroup_tariffs'), ('abonapp', '0014_auto_20170330_1452'), ('abonapp', '0015_passportinfo'), ('abonapp', '0016_auto_20170415_1311'), ('abonapp', '0017_auto_20170416_1029'), ('abonapp', '0018_auto_20170418_1236'), ('abonapp', '0019_abon_ip_address'), ('abonapp', '0020_auto_20170517_1655'), ('abonapp', '0021_auto_20170705_1403'), ('abonapp', '0022_auto_20170816_1109')] - initial = True dependencies = [ diff --git a/abonapp/migrations/0002_auto_20161206_2135.py b/abonapp/migrations/0002_auto_20161206_2135.py deleted file mode 100644 index a865928..0000000 --- a/abonapp/migrations/0002_auto_20161206_2135.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-12-06 18:35 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='abongroup', - name='address', - ), - migrations.AlterField( - model_name='abongroup', - name='title', - field=models.CharField(max_length=127, unique=True), - ), - ] diff --git a/abonapp/migrations/0003_abongroup_profiles.py b/abonapp/migrations/0003_abongroup_profiles.py deleted file mode 100644 index f3b2d91..0000000 --- a/abonapp/migrations/0003_abongroup_profiles.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-12-16 19:14 -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('abonapp', '0002_auto_20161206_2135'), - ] - - operations = [ - migrations.AddField( - model_name='abongroup', - name='profiles', - field=models.ManyToManyField(related_name='abon_groups', to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/abonapp/migrations/0004_auto_20161220_0102.py b/abonapp/migrations/0004_auto_20161220_0102.py deleted file mode 100644 index b19ca18..0000000 --- a/abonapp/migrations/0004_auto_20161220_0102.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-12-19 22:02 -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0003_abongroup_profiles'), - ] - - operations = [ - migrations.AlterField( - model_name='abongroup', - name='profiles', - field=models.ManyToManyField(blank=True, related_name='abon_groups', to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/abonapp/migrations/0005_auto_20161226_0054.py b/abonapp/migrations/0005_auto_20161226_0054.py deleted file mode 100644 index 3b206ae..0000000 --- a/abonapp/migrations/0005_auto_20161226_0054.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-12-25 21:54 -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0004_auto_20161220_0102'), - ] - - operations = [ - migrations.AlterModelOptions( - name='abon', - options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'),)}, - ), - migrations.AlterModelOptions( - name='abongroup', - options={'permissions': (('can_add_ballance', 'Пополнение счёта'),)}, - ), - migrations.AlterModelOptions( - name='abontariff', - options={'ordering': ('tariff_priority',), 'permissions': (('can_complete_service', 'Досрочное завершение услуги абонента'), ('can_activate_service', 'Активация услуги абонента'))}, - ), - ] diff --git a/abonapp/migrations/0006_auto_20170128_1626.py b/abonapp/migrations/0006_auto_20170128_1626.py deleted file mode 100644 index 6274a5d..0000000 --- a/abonapp/migrations/0006_auto_20170128_1626.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-01-28 13:26 -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0005_auto_20161226_0054'), - ] - - operations = [ - migrations.CreateModel( - name='AbonStreets', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=64)), - ('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.AbonGroup')), - ], - ), - migrations.RemoveField( - model_name='abon', - name='address', - ), - migrations.AddField( - model_name='abon', - name='description', - field=models.TextField(blank=True, null=True), - ), - migrations.AddField( - model_name='abon', - name='house', - field=models.CharField(blank=True, max_length=12, null=True), - ), - migrations.AddField( - model_name='abon', - name='street', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonStreets'), - ), - ] diff --git a/abonapp/migrations/0007_auto_20170131_1650.py b/abonapp/migrations/0007_auto_20170131_1650.py deleted file mode 100644 index c1f4ae5..0000000 --- a/abonapp/migrations/0007_auto_20170131_1650.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-01-31 13:50 -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0006_auto_20170128_1626'), - ] - - operations = [ - migrations.CreateModel( - name='AllPayLog', - fields=[ - ('pay_id', models.CharField(max_length=64, primary_key=True, serialize=False)), - ('date_action', models.DateTimeField(auto_now_add=True)), - ('summ', models.FloatField(default=0.0)), - ('pay_system_name', models.CharField(max_length=16)), - ], - options={ - 'db_table': 'all_pay_log', - 'ordering': ('date_action',), - }, - ), - migrations.CreateModel( - name='AllTimePayLog', - fields=[ - ('pay_id', models.CharField(max_length=36, primary_key=True, serialize=False, unique=True)), - ('date_add', models.DateTimeField(auto_now_add=True)), - ('summ', models.FloatField(default=0.0)), - ], - options={ - 'db_table': 'all_time_pay_log', - 'ordering': ('date_add',), - }, - ), - migrations.RenameModel( - old_name='AbonStreets', - new_name='AbonStreet', - ), - ] diff --git a/abonapp/migrations/0008_auto_20170209_0002.py b/abonapp/migrations/0008_auto_20170209_0002.py deleted file mode 100644 index 8d24b5d..0000000 --- a/abonapp/migrations/0008_auto_20170209_0002.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-02-08 21:02 -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0007_auto_20170131_1650'), - ] - - operations = [ - migrations.CreateModel( - name='AbonRawPassword', - fields=[ - ('account', models.OneToOneField(primary_key=True, serialize=False, to='abonapp.Abon')), - ('passw_text', models.CharField(max_length=64)), - ], - options={ - 'db_table': 'abon_raw_password', - }, - ), - migrations.AlterModelTable( - name='abonstreet', - table='abon_street', - ), - ] diff --git a/abonapp/migrations/0009_abontariff_death_line.py b/abonapp/migrations/0009_abontariff_death_line.py deleted file mode 100644 index 1152d33..0000000 --- a/abonapp/migrations/0009_abontariff_death_line.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-02-16 12:22 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0008_auto_20170209_0002'), - ] - - operations = [ - migrations.AddField( - model_name='abontariff', - name='deadline', - field=models.DateTimeField(blank=True, default=None, null=True), - ), - ] diff --git a/abonapp/migrations/0010_auto_20170220_1630.py b/abonapp/migrations/0010_auto_20170220_1630.py deleted file mode 100644 index 69718b8..0000000 --- a/abonapp/migrations/0010_auto_20170220_1630.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-02-20 13:30 -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0009_abontariff_death_line'), - ] - - operations = [ - migrations.CreateModel( - name='ExtraFieldsModel', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('field_type', models.CharField(choices=[('int', 'Digital field'), ('str', 'Text field'), ('dbl', 'Floating field')], max_length=3)), - ('data', models.CharField(blank=True, max_length=64, null=True)), - ], - options={ - 'db_table': 'abon_extra_fields', - }, - ), - migrations.AlterModelOptions( - name='abon', - options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Can view passport'))}, - ), - migrations.AlterModelOptions( - name='abontariff', - options={'ordering': ('tariff_priority',), 'permissions': (('can_complete_service', 'Снятие со счёта средств'), ('can_activate_service', 'Активация услуги абонента'))}, - ), - migrations.AlterField( - model_name='abon', - name='ballance', - field=models.FloatField(default=0.0), - ), - migrations.AddField( - model_name='extrafieldsmodel', - name='account', - field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='abonapp.Abon'), - ), - ] diff --git a/abonapp/migrations/0011_auto_20170222_2224.py b/abonapp/migrations/0011_auto_20170222_2224.py deleted file mode 100644 index d197189..0000000 --- a/abonapp/migrations/0011_auto_20170222_2224.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-02-22 19:24 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0010_auto_20170220_1630'), - ] - - operations = [ - migrations.AlterModelOptions( - name='abon', - options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Может просматривать паспортные данные'))}, - ), - migrations.AlterField( - model_name='extrafieldsmodel', - name='field_type', - field=models.CharField(choices=[('int', 'Цифровое поле'), ('str', 'Текстовое поле'), ('dbl', 'Дробное с плавающей точкой')], max_length=3), - ), - ] diff --git a/abonapp/migrations/0012_auto_20170227_1718.py b/abonapp/migrations/0012_auto_20170227_1718.py deleted file mode 100644 index 63a66de..0000000 --- a/abonapp/migrations/0012_auto_20170227_1718.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-03-02 18:41 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0011_auto_20170222_2224'), - ] - - operations = [ - migrations.RemoveField( - model_name='extrafieldsmodel', - name='account', - ), - migrations.AddField( - model_name='abon', - name='extra_fields', - field=models.ManyToManyField(to='abonapp.ExtraFieldsModel'), - ), - ] diff --git a/abonapp/migrations/0013_abongroup_tariffs.py b/abonapp/migrations/0013_abongroup_tariffs.py deleted file mode 100644 index b67ffbd..0000000 --- a/abonapp/migrations/0013_abongroup_tariffs.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-03-21 11:30 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('tariff_app', '0002_tariff_descr'), - ('abonapp', '0012_auto_20170227_1718'), - ] - - operations = [ - migrations.AddField( - model_name='abongroup', - name='tariffs', - field=models.ManyToManyField(blank=True, related_name='tariff_groups', to='tariff_app.Tariff'), - ), - ] diff --git a/abonapp/migrations/0014_auto_20170330_1452.py b/abonapp/migrations/0014_auto_20170330_1452.py deleted file mode 100644 index c0985ab..0000000 --- a/abonapp/migrations/0014_auto_20170330_1452.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-03-30 11:52 -from __future__ import unicode_literals - -import django.db.models.deletion -import djing.fields -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0013_abongroup_tariffs'), - ] - - operations = [ - migrations.CreateModel( - name='Opt82', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('mac', djing.fields.MACAddressField(integer=True)), - ('port', models.PositiveSmallIntegerField(default=0)), - ], - options={ - 'db_table': 'opt_82', - }, - ), - migrations.AlterField( - model_name='abon', - name='extra_fields', - field=models.ManyToManyField(blank=True, to='abonapp.ExtraFieldsModel'), - ), - migrations.AlterUniqueTogether( - name='opt82', - unique_together=set([('mac', 'port')]), - ), - migrations.AddField( - model_name='abon', - name='opt82', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='abonapp.Opt82'), - ), - ] diff --git a/abonapp/migrations/0015_passportinfo.py b/abonapp/migrations/0015_passportinfo.py deleted file mode 100644 index 5207173..0000000 --- a/abonapp/migrations/0015_passportinfo.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-04-11 10:43 -from __future__ import unicode_literals - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion -import re - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0014_auto_20170330_1452'), - ] - - operations = [ - migrations.CreateModel( - name='PassportInfo', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('series', models.CharField(max_length=4, validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z', 32), code='invalid', message='Enter a valid integer.')])), - ('number', models.CharField(max_length=6, validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z', 32), code='invalid', message='Enter a valid integer.')])), - ('distributor', models.CharField(max_length=64)), - ('date_of_acceptance', models.DateField()), - ('abon', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.Abon')), - ], - ), - migrations.AlterField( - model_name='abon', - name='opt82', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, - to='abonapp.Opt82'), - ) - ] diff --git a/abonapp/migrations/0016_auto_20170415_1311.py b/abonapp/migrations/0016_auto_20170415_1311.py deleted file mode 100644 index 4070341..0000000 --- a/abonapp/migrations/0016_auto_20170415_1311.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-04-15 10:11 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('devapp', '0004_device_user_group'), - ('abonapp', '0015_passportinfo'), - ] - - operations = [ - migrations.CreateModel( - name='AbonDevice', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('abon', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), - ('device', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device')), - ], - options={ - 'db_table': 'abon_device', - }, - ), - migrations.AlterUniqueTogether( - name='abondevice', - unique_together=set([('abon', 'device')]), - ), - ] diff --git a/abonapp/migrations/0017_auto_20170416_1029.py b/abonapp/migrations/0017_auto_20170416_1029.py deleted file mode 100644 index fb70627..0000000 --- a/abonapp/migrations/0017_auto_20170416_1029.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-04-16 07:29 -from __future__ import unicode_literals - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0016_auto_20170415_1311'), - ] - - operations = [ - migrations.AlterField( - model_name='invoiceforpayment', - name='author', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/abonapp/migrations/0018_auto_20170418_1236.py b/abonapp/migrations/0018_auto_20170418_1236.py deleted file mode 100644 index 175a62b..0000000 --- a/abonapp/migrations/0018_auto_20170418_1236.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-04-18 09:36 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0017_auto_20170416_1029'), - ] - - operations = [ - migrations.AlterField( - model_name='abondevice', - name='abon', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon'), - ), - migrations.AlterField( - model_name='abondevice', - name='device', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device'), - ), - ] diff --git a/abonapp/migrations/0019_abon_ip_address.py b/abonapp/migrations/0019_abon_ip_address.py deleted file mode 100644 index 96c2613..0000000 --- a/abonapp/migrations/0019_abon_ip_address.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-05-10 23:17 -from __future__ import unicode_literals - -from django.db import migrations -import mydefs - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0018_auto_20170418_1236'), - ] - - operations = [ - migrations.AddField( - model_name='abon', - name='ip_address', - field=mydefs.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4'), - ), - ] diff --git a/abonapp/migrations/0020_auto_20170517_1655.py b/abonapp/migrations/0020_auto_20170517_1655.py deleted file mode 100644 index edcf585..0000000 --- a/abonapp/migrations/0020_auto_20170517_1655.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-05-17 13:55 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0019_abon_ip_address'), - ] - - operations = [ - migrations.AddField( - model_name='extrafieldsmodel', - name='title', - field=models.CharField(default='no title', max_length=16), - ), - migrations.AlterField( - model_name='extrafieldsmodel', - name='field_type', - field=models.CharField(choices=[('int', 'Цифровое поле'), ('str', 'Текстовое поле'), ('dbl', 'Дробное с плавающей точкой'), ('ipa', 'IP Адрес')], default='str', max_length=3), - ), - ] diff --git a/abonapp/migrations/0021_auto_20170705_1403.py b/abonapp/migrations/0021_auto_20170705_1403.py deleted file mode 100644 index 16a2a15..0000000 --- a/abonapp/migrations/0021_auto_20170705_1403.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-07-05 14:03 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('devapp', '0006_auto_20170705_1403'), - ('abonapp', '0020_auto_20170517_1655'), - ] - - operations = [ - migrations.RemoveField( - model_name='abon', - name='opt82', - ), - migrations.DeleteModel( - name='Opt82', - ), - migrations.AddField( - model_name='abon', - name='dev_port', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Port'), - ), - migrations.AddField( - model_name='abon', - name='device', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Device'), - ), - migrations.AddField( - model_name='abon', - name='is_dynamic_ip', - field=models.BooleanField(default=False), - ), - migrations.DeleteModel( - name='AbonDevice', - ), - ] diff --git a/abonapp/migrations/0022_auto_20170816_1109.py b/abonapp/migrations/0022_auto_20170816_1109.py deleted file mode 100644 index d514365..0000000 --- a/abonapp/migrations/0022_auto_20170816_1109.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-08-16 11:09 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0021_auto_20170705_1403'), - ] - - operations = [ - migrations.AlterModelOptions( - name='abontariff', - options={'permissions': (('can_complete_service', 'Снятие со счёта средств'),)}, - ), - migrations.RemoveField( - model_name='abon', - name='current_tariffs', - ), - migrations.AddField( - model_name='abon', - name='current_tariff', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonTariff'), - ), - migrations.AlterUniqueTogether( - name='abontariff', - unique_together=set([]), - ), - migrations.RemoveField( - model_name='abontariff', - name='abon', - ), - migrations.RemoveField( - model_name='abontariff', - name='tariff_priority', - ), - ] diff --git a/devapp/migrations/0001_initial.py b/devapp/migrations/0001_initial.py deleted file mode 100644 index 2bf13ba..0000000 --- a/devapp/migrations/0001_initial.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-06-28 23:51 - -from django.db import migrations, models -import django.db.models.deletion - -import mydefs - - -class Migration(migrations.Migration): - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='Device', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('ip_address', mydefs.MyGenericIPAddressField(max_length=8, protocol='ipv4')), - ('comment', models.CharField(max_length=256)), - ('devtype', - models.CharField(choices=[('Dl', "Свич D'Link")], default='Dl', max_length=2)), - ('man_passw', models.CharField(blank=True, max_length=16, null=True)), - ], - ), - migrations.CreateModel( - name='Port', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('num', models.PositiveSmallIntegerField(default=0)), - ('speed', - models.CharField(choices=[('h', '100Mbps'), ('k', '1Gbps'), ('d', '10Gbps')], default='h', - max_length=1)), - ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device')), - ], - ), - migrations.CreateModel( - name='PortStates', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('state_json_info', models.TextField()), - ('port', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='devapp.Port')), - ], - ), - migrations.AlterUniqueTogether( - name='port', - unique_together={('device', 'num')}, - ), - ] diff --git a/devapp/migrations/0001_squashed_0007_auto_20170816_1109.py b/devapp/migrations/0001_squashed_0007_auto_20170816_1109.py index 11827a5..bd3b9dc 100644 --- a/devapp/migrations/0001_squashed_0007_auto_20170816_1109.py +++ b/devapp/migrations/0001_squashed_0007_auto_20170816_1109.py @@ -10,8 +10,6 @@ import mydefs class Migration(migrations.Migration): - replaces = [('devapp', '0001_initial'), ('devapp', '0002_auto_20160909_1018'), ('devapp', '0003_device_map_dot'), ('devapp', '0004_device_user_group'), ('devapp', '0005_auto_20170502_2232'), ('devapp', '0006_auto_20170705_1403'), ('devapp', '0007_auto_20170816_1109')] - initial = True dependencies = [ diff --git a/devapp/migrations/0002_auto_20160909_1018.py b/devapp/migrations/0002_auto_20160909_1018.py deleted file mode 100644 index b1069bb..0000000 --- a/devapp/migrations/0002_auto_20160909_1018.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2016-09-09 07:18 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('devapp', '0001_initial'), - ] - - operations = [ - migrations.AlterModelTable( - name='device', - table='dev', - ), - migrations.AlterModelTable( - name='port', - table='dev_port', - ), - ] diff --git a/devapp/migrations/0003_device_map_dot.py b/devapp/migrations/0003_device_map_dot.py deleted file mode 100644 index eca2674..0000000 --- a/devapp/migrations/0003_device_map_dot.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-01-28 22:03 -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('mapapp', '0001_initial'), - ('devapp', '0002_auto_20160909_1018'), - ] - - operations = [ - migrations.AddField( - model_name='device', - name='map_dot', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mapapp.Dot'), - ), - ] diff --git a/devapp/migrations/0004_device_user_group.py b/devapp/migrations/0004_device_user_group.py deleted file mode 100644 index 00c16f2..0000000 --- a/devapp/migrations/0004_device_user_group.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-02-22 19:24 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('abonapp', '0011_auto_20170222_2224'), - ('devapp', '0003_device_map_dot'), - ] - - operations = [ - migrations.AddField( - model_name='device', - name='user_group', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonGroup'), - ), - ] diff --git a/devapp/migrations/0005_auto_20170502_2232.py b/devapp/migrations/0005_auto_20170502_2232.py deleted file mode 100644 index 91cbe61..0000000 --- a/devapp/migrations/0005_auto_20170502_2232.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-05-02 19:32 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('devapp', '0004_device_user_group'), - ] - - operations = [ - migrations.AlterField( - model_name='device', - name='devtype', - field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT')], default='Dl', max_length=2), - ), - ] diff --git a/devapp/migrations/0006_auto_20170705_1403.py b/devapp/migrations/0006_auto_20170705_1403.py deleted file mode 100644 index 33d3b75..0000000 --- a/devapp/migrations/0006_auto_20170705_1403.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-07-05 14:03 -from __future__ import unicode_literals - -from django.db import migrations, models -import django.db.models.deletion -import djing.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('devapp', '0005_auto_20170502_2232'), - ] - - operations = [ - migrations.RemoveField( - model_name='portstates', - name='port', - ), - migrations.RemoveField( - model_name='port', - name='speed', - ), - migrations.AddField( - model_name='device', - name='mac_addr', - field=djing.fields.MACAddressField(blank=True, integer=True, null=True, unique=True), - ), - migrations.AddField( - model_name='device', - name='parent_dev', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Device'), - ), - migrations.AddField( - model_name='port', - name='descr', - field=models.CharField(blank=True, max_length=60, null=True), - ), - migrations.AlterField( - model_name='device', - name='devtype', - field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU')], default='Dl', max_length=2), - ), - migrations.DeleteModel( - name='PortStates', - ), - ] diff --git a/devapp/migrations/0007_auto_20170816_1109.py b/devapp/migrations/0007_auto_20170816_1109.py deleted file mode 100644 index 3cc6c28..0000000 --- a/devapp/migrations/0007_auto_20170816_1109.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.9 on 2017-08-16 11:09 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('devapp', '0006_auto_20170705_1403'), - ] - - operations = [ - migrations.AlterField( - model_name='device', - name='devtype', - field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU'), ('Ex', 'Eltex switch')], default='Dl', max_length=2), - ), - ] From 4c6ba95eee5fa4afe40c8c40e71a40386c0528b4 Mon Sep 17 00:00:00 2001 From: bashmak Date: Tue, 5 Sep 2017 14:40:23 +0300 Subject: [PATCH 13/22] refactor --- agent/mod_mikrotik.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/agent/mod_mikrotik.py b/agent/mod_mikrotik.py index 89bea50..3d92201 100644 --- a/agent/mod_mikrotik.py +++ b/agent/mod_mikrotik.py @@ -248,8 +248,11 @@ class QueueManager(TransmitterManager, metaclass=ABCMeta): return self._exec_cmd(['/queue/simple/remove', '=.id=' + getattr(q, 'queue_id', '')]) def remove_range(self, q_ids): - if q_ids is not None and len(q_ids) > 0: + try: + q_ids = [q.queue_id for q in q_ids] return self._exec_cmd(['/queue/simple/remove', '=numbers=' + ','.join(q_ids)]) + except TypeError as e: + print(e) def update(self, user): if not isinstance(user, AbonStruct): @@ -274,9 +277,10 @@ class QueueManager(TransmitterManager, metaclass=ABCMeta): # читаем шейпер, возващаем записи о шейпере def read_queue_iter(self): - for queue in self._exec_cmd_iter(['/queue/simple/print', '=detail']): - if queue[0] == '!done': return - sobj = self._build_shape_obj(queue[1]) + for code, dat in self._exec_cmd_iter(['/queue/simple/print', '=detail']): + if code == '!done': + return + sobj = self._build_shape_obj(dat) if sobj is not None: yield sobj From 7cf2ac7e8b1a0e5d2273b689145f4ce2445cc374 Mon Sep 17 00:00:00 2001 From: bashmak Date: Tue, 5 Sep 2017 14:41:27 +0300 Subject: [PATCH 14/22] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BD=D0=BE=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D1=82=D0=B5=D0=BB=D0=B5=D1=84=D0=BE=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B2=20=D1=83=D1=87=D1=91=D1=82=D0=BA=D0=B5=20=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- abonapp/admin.py | 1 + abonapp/forms.py | 21 ++++++++- abonapp/locale/ru/LC_MESSAGES/django.po | 42 +++++++++++++++++ abonapp/models.py | 32 +++++++++++++ abonapp/templates/abonapp/editAbon.html | 8 +++- .../abonapp/modal_additional_telephones.html | 37 +++++++++++++++ abonapp/urls_abon.py | 6 ++- abonapp/views.py | 47 +++++++++++++++++++ 8 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 abonapp/templates/abonapp/modal_additional_telephones.html diff --git a/abonapp/admin.py b/abonapp/admin.py index c3e76ef..082d3d8 100644 --- a/abonapp/admin.py +++ b/abonapp/admin.py @@ -14,3 +14,4 @@ admin.site.register(models.AbonRawPassword) admin.site.register(models.ExtraFieldsModel) admin.site.register(models.AllPayLog) admin.site.register(models.PassportInfo) +admin.site.register(models.AdditionalTelephone) diff --git a/abonapp/forms.py b/abonapp/forms.py index b9e11d4..36fa6b5 100644 --- a/abonapp/forms.py +++ b/abonapp/forms.py @@ -6,6 +6,10 @@ from django.contrib.auth.hashers import make_password from random import choice from string import digits, ascii_lowercase from . import models +from django.conf import settings + + +TELEPHONE_REGEXP = getattr(settings, 'TELEPHONE_REGEXP', r'^\+[7,8,9,3]\d{10,11}$') def generate_random_username(length=6, chars=digits, split=2, delimiter=''): @@ -57,7 +61,7 @@ class AbonForm(forms.ModelForm): }), 'telephone': forms.TextInput(attrs={ 'placeholder': _('telephone placeholder'), - 'pattern': r'^\+[7,8,9,3]\d{10,11}$', + 'pattern': TELEPHONE_REGEXP, 'required': '', 'class': 'form-control' }), @@ -131,3 +135,18 @@ class AbonStreetForm(forms.ModelForm): 'name': forms.TextInput(attrs={'class': 'form-control', 'required':'', 'autofocus':''}), 'group': forms.Select(attrs={'class': 'form-control'}) } + + +class AdditionalTelephoneForm(forms.ModelForm): + class Meta: + model = models.AdditionalTelephone + exclude = ['abon'] + widgets = { + 'telephone': forms.TextInput(attrs={ + 'placeholder': _('telephone placeholder'), + 'pattern': TELEPHONE_REGEXP, + 'required': '', + 'class': 'form-control' + }), + 'owner_name': forms.TextInput(attrs={'class': 'form-control', 'required':''}) + } diff --git a/abonapp/locale/ru/LC_MESSAGES/django.po b/abonapp/locale/ru/LC_MESSAGES/django.po index 7e81d54..35afe9e 100644 --- a/abonapp/locale/ru/LC_MESSAGES/django.po +++ b/abonapp/locale/ru/LC_MESSAGES/django.po @@ -951,3 +951,45 @@ msgstr "Пользователь, который не является перс msgid "Ip not passed" msgstr "Ip адрес не передан" + +msgid "Additional telephone" +msgstr "Дополнительный телефон" + +msgid "Additional telephones" +msgstr "Дополнительные телефоны" + +msgid "Abon group" +msgstr "Группа абонентов" + +msgid "Abon groups" +msgstr "Группы абонентов" + +msgid "Abon service" +msgstr "Услуга абонента" + +msgid "Abon services" +msgstr "Услуги абонентов" + +msgid "Abon" +msgstr "Абонент" + +msgid "Abons" +msgstr "Абоненты" + +msgid "New telephone has been saved" +msgstr "Новый телефон сохранен" + +msgid "Add telephone" +msgstr "Добавить номер телефона" + +msgid "Telephone owner" +msgstr "Владелец телефона" + +msgid "Additional telephones not found" +msgstr "Дополнительные телефоны не найдены" + +msgid "Additional telephone successfully deleted" +msgstr "Номер телефона успешно удалён" + +msgid "Telephone not found" +msgstr "Телефон не найден" diff --git a/abonapp/models.py b/abonapp/models.py index ec59e76..d492f82 100644 --- a/abonapp/models.py +++ b/abonapp/models.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from django.core.exceptions import ValidationError +from django.core.validators import RegexValidator from django.utils import timezone from django.db import models from django.core import validators @@ -11,6 +12,9 @@ from mydefs import MyGenericIPAddressField, ip2int, LogicError, ip_addr_regex from django.conf import settings +TELEPHONE_REGEXP = getattr(settings, 'TELEPHONE_REGEXP', r'^\+[7,8,9,3]\d{10,11}$') + + class AbonGroup(models.Model): title = models.CharField(max_length=127, unique=True) profiles = models.ManyToManyField(UserProfile, blank=True, related_name='abon_groups') @@ -21,6 +25,8 @@ class AbonGroup(models.Model): permissions = ( ('can_add_ballance', _('fill account')), ) + verbose_name = _('Abon group') + verbose_name_plural = _('Abon groups') def __str__(self): return self.title @@ -68,6 +74,8 @@ class AbonTariff(models.Model): permissions = ( ('can_complete_service', _('finish service perm')), ) + verbose_name = _('Abon service') + verbose_name_plural = _('Abon services') class AbonStreet(models.Model): @@ -79,6 +87,8 @@ class AbonStreet(models.Model): class Meta: db_table = 'abon_street' + verbose_name = _('Street') + verbose_name_plural = _('Streets') class ExtraFieldsModel(models.Model): @@ -146,6 +156,8 @@ class Abon(UserProfile): ('can_buy_tariff', _('Buy service perm')), ('can_view_passport', _('Can view passport')) ) + verbose_name = _('Abon') + verbose_name_plural = _('Abons') # Платим за что-то def make_pay(self, curuser, how_match_to_pay=0.0): @@ -317,6 +329,26 @@ class AbonRawPassword(models.Model): db_table = 'abon_raw_password' +class AdditionalTelephone(models.Model): + abon = models.ForeignKey(Abon, related_name='additional_telephones') + telephone = models.CharField( + max_length=16, + verbose_name=_('Telephone'), + # unique=True, + validators=[RegexValidator(TELEPHONE_REGEXP)] + ) + owner_name = models.CharField(max_length=127) + + def __str__(self): + return "%s - (%s)" % (self.owner_name, self.telephone) + + class Meta: + db_table = 'additional_telephones' + ordering = ('owner_name',) + verbose_name = _('Additional telephone') + verbose_name_plural = _('Additional telephones') + + def abon_post_save(sender, instance, **kwargs): timeout = None if hasattr(instance, 'is_dhcp') and instance.is_dhcp: diff --git a/abonapp/templates/abonapp/editAbon.html b/abonapp/templates/abonapp/editAbon.html index e5883ae..4cf8744 100644 --- a/abonapp/templates/abonapp/editAbon.html +++ b/abonapp/templates/abonapp/editAbon.html @@ -31,9 +31,15 @@
{{ form.telephone }}{{ form.telephone.errors }} - + + + + + + +
diff --git a/abonapp/templates/abonapp/modal_additional_telephones.html b/abonapp/templates/abonapp/modal_additional_telephones.html new file mode 100644 index 0000000..5782e6b --- /dev/null +++ b/abonapp/templates/abonapp/modal_additional_telephones.html @@ -0,0 +1,37 @@ +{% load i18n %} + + + + diff --git a/abonapp/urls_abon.py b/abonapp/urls_abon.py index 2922a6b..9267cb1 100644 --- a/abonapp/urls_abon.py +++ b/abonapp/urls_abon.py @@ -33,5 +33,9 @@ urlpatterns = [ url(r'^(?P\d+)/clear_dev/$', views.clear_dev, name='clear_dev'), url(r'^(?P\d+)/task_log$', views.task_log, name='task_log'), - url(r'^(?P\d+)/user_dev$', views.save_user_dev_port, name='save_user_dev_port') + url(r'^(?P\d+)/user_dev$', views.save_user_dev_port, name='save_user_dev_port'), + + url(r'^(?P\d+)/tel$', views.tels, name='telephones'), + url(r'^(?P\d+)/tel/add$', views.tel_add, name='telephone_new'), + url(r'^(?P\d+)/tel/del$', views.tel_del, name='telephone_del') ] diff --git a/abonapp/views.py b/abonapp/views.py index b47f23d..92a62fc 100644 --- a/abonapp/views.py +++ b/abonapp/views.py @@ -871,6 +871,53 @@ def street_del(request, gid, sid): return redirect('abonapp:people_list', gid) +@login_required +@mydefs.only_admins +def tels(request, gid, uid): + abon = get_object_or_404(models.Abon, pk=uid) + telephones = abon.additional_telephones.all() + return render_to_text('abonapp/modal_additional_telephones.html', { + 'telephones': telephones, + 'gid': gid, + 'uid': uid + }, request=request) + + +@login_required +@permission_required('abnapp.add_additionaltelephone') +def tel_add(request, gid, uid): + if request.method == 'POST': + frm = forms.AdditionalTelephoneForm(request.POST) + if frm.is_valid(): + new_tel = frm.save(commit=False) + abon = get_object_or_404(models.Abon, pk=uid) + new_tel.abon = abon + new_tel.save() + messages.success(request, _('New telephone has been saved')) + return redirect('abonapp:abon_home', gid, uid) + else: + messages.error(request, _('fix form errors')) + else: + frm = forms.AdditionalTelephoneForm() + return render_to_text('abonapp/modal_add_phone.html', { + 'form': frm, + 'gid': gid, + 'uid': uid + }, request=request) + + +@login_required +@permission_required('abnapp.delete_additionaltelephone') +def tel_del(request, gid, uid): + try: + tid = mydefs.safe_int(request.GET.get('tid')) + tel = models.AdditionalTelephone.objects.get(pk=tid) + tel.delete() + messages.success(request, _('Additional telephone successfully deleted')) + except models.AdditionalTelephone.DoesNotExist: + messages.error(request, _('Telephone not found')) + return redirect('abonapp:abon_home', gid, uid) + # API's From 8ee2c8b1edb6bd31a6513cbe049ea0330458fabd Mon Sep 17 00:00:00 2001 From: bashmak Date: Tue, 5 Sep 2017 14:42:21 +0300 Subject: [PATCH 15/22] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D1=8F=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B4=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BD=D0=BE=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B0=20=D1=82=D0=B5=D0=BB=D0=B5=D1=84=D0=BE=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B2=20=D1=83=D1=87=D1=91=D1=82=D0=BA=D0=B5=20=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- abonapp/migrations/0002_auto_20170905_1248.py | 52 +++++++++++++++++++ .../templates/abonapp/modal_add_phone.html | 35 +++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 abonapp/migrations/0002_auto_20170905_1248.py create mode 100644 abonapp/templates/abonapp/modal_add_phone.html diff --git a/abonapp/migrations/0002_auto_20170905_1248.py b/abonapp/migrations/0002_auto_20170905_1248.py new file mode 100644 index 0000000..75bbac0 --- /dev/null +++ b/abonapp/migrations/0002_auto_20170905_1248.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-09-05 12:48 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('abonapp', '0001_squashed_0022_auto_20170816_1109'), + ] + + operations = [ + migrations.CreateModel( + name='AdditionalTelephone', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('telephone', models.CharField(max_length=16, validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')], verbose_name='Телефон')), + ('owner_name', models.CharField(max_length=127)), + ], + options={ + 'verbose_name': 'Дополнительный телефон', + 'verbose_name_plural': 'Дополнительные телефоны', + 'db_table': 'additional_telephones', + 'ordering': ('owner_name',), + }, + ), + migrations.AlterModelOptions( + name='abon', + options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Может просматривать паспортные данные')), 'verbose_name': 'Абонент', 'verbose_name_plural': 'Абоненты'}, + ), + migrations.AlterModelOptions( + name='abongroup', + options={'permissions': (('can_add_ballance', 'Пополнение счёта'),), 'verbose_name': 'Группа абонентов', 'verbose_name_plural': 'Группы абонентов'}, + ), + migrations.AlterModelOptions( + name='abonstreet', + options={'verbose_name': 'Улица', 'verbose_name_plural': 'Улицы'}, + ), + migrations.AlterModelOptions( + name='abontariff', + options={'permissions': (('can_complete_service', 'Снятие со счёта средств'),), 'verbose_name': 'Услуга абонента', 'verbose_name_plural': 'Услуги абонентов'}, + ), + migrations.AddField( + model_name='additionaltelephone', + name='abon', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='additional_telephones', to='abonapp.Abon'), + ), + ] diff --git a/abonapp/templates/abonapp/modal_add_phone.html b/abonapp/templates/abonapp/modal_add_phone.html new file mode 100644 index 0000000..1ca2916 --- /dev/null +++ b/abonapp/templates/abonapp/modal_add_phone.html @@ -0,0 +1,35 @@ +{% load i18n %} +
{% csrf_token %} + + + + +
From d4e337be0696abe047a01a0122628d2aa1812ab7 Mon Sep 17 00:00:00 2001 From: bashmak Date: Tue, 5 Sep 2017 14:43:03 +0300 Subject: [PATCH 16/22] =?UTF-8?q?=D1=81=D0=B6=D0=B8=D0=BC=D0=B0=D1=8E=20?= =?UTF-8?q?=D0=BC=D0=B8=D0=B3=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=BC=D0=BE?= =?UTF-8?q?=D0=B4=D1=83=D0=BB=D1=8F=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- taskapp/migrations/0001_initial.py | 2 +- .../0001_squashed_0015_auto_20170816_1109.py | 148 ++++++++++++++++++ taskapp/migrations/0005_auto_20161206_0013.py | 2 +- 3 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 taskapp/migrations/0001_squashed_0015_auto_20170816_1109.py diff --git a/taskapp/migrations/0001_initial.py b/taskapp/migrations/0001_initial.py index ffd281f..eec2166 100644 --- a/taskapp/migrations/0001_initial.py +++ b/taskapp/migrations/0001_initial.py @@ -13,7 +13,7 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('devapp', '0002_auto_20160909_1018'), + ('devapp', '0001_squashed_0007_auto_20170816_1109'), ] operations = [ diff --git a/taskapp/migrations/0001_squashed_0015_auto_20170816_1109.py b/taskapp/migrations/0001_squashed_0015_auto_20170816_1109.py new file mode 100644 index 0000000..d3e3853 --- /dev/null +++ b/taskapp/migrations/0001_squashed_0015_auto_20170816_1109.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-09-05 12:23 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import taskapp.models + + +class Migration(migrations.Migration): + + replaces = [('taskapp', '0001_initial'), ('taskapp', '0002_auto_20161006_0027'), ('taskapp', '0003_auto_20161130_1815'), ('taskapp', '0004_auto_20161202_1230'), ('taskapp', '0005_auto_20161206_0013'), ('taskapp', '0006_auto_20161206_2135'), ('taskapp', '0007_auto_20161206_2303'), ('taskapp', '0008_auto_20161213_1932'), ('taskapp', '0009_auto_20161216_2214'), ('taskapp', '0010_auto'), ('taskapp', '0011_auto_20170116_0126'), ('taskapp', '0012_auto_20170407_0124'), ('taskapp', '0013_auto_20170413_1944'), ('taskapp', '0014_auto_20170416_1029'), ('taskapp', '0015_auto_20170816_1109')] + + initial = True + + dependencies = [ + ('devapp', '0001_squashed_0007_auto_20170816_1109'), + ('abonapp', '0001_squashed_0022_auto_20170816_1109'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Task', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('descr', models.CharField(max_length=128)), + ('priority', models.CharField(choices=[('A', 'Высший'), ('B', 'Выше среднего'), ('C', 'Средний'), ('D', 'Ниже среднего'), ('E', 'Низкий')], default='C', max_length=1)), + ('out_date', models.DateField(blank=True, default=taskapp.models._delta_add_days, null=True)), + ('time_of_create', models.DateTimeField(auto_now_add=True)), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)), + ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='dev', to='devapp.Device')), + ('recipient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'db_table': 'task', + }, + ), + migrations.AlterModelOptions( + name='task', + options={'ordering': ('-id',)}, + ), + migrations.AddField( + model_name='task', + name='state', + field=models.CharField(choices=[('S', 'Новая'), ('C', 'На выполнении'), ('F', 'Выполнена')], default='S', max_length=1), + ), + migrations.AddField( + model_name='task', + name='attachment', + field=models.ImageField(blank=True, null=True, upload_to='task_attachments/%Y.%m.%d'), + ), + migrations.AddField( + model_name='task', + name='mode', + field=models.CharField(choices=[('na', 'не выбрано'), ('yt', 'жёлтый треугольник'), ('rc', 'красный крестик'), ('ls', 'слабая скорость'), ('cf', 'обрыв кабеля'), ('cn', 'подключение'), ('pf', 'переодическое пропадание'), ('cr', 'настройка роутера'), ('co', 'настроить onu'), ('fc', 'обжать кабель'), ('ot', 'другое')], default='na', max_length=2), + ), + migrations.AddField( + model_name='task', + name='abon', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='abonapp.Abon'), + ), + migrations.AlterField( + model_name='task', + name='priority', + field=models.CharField(choices=[('A', 'Высший'), ('C', 'Средний'), ('E', 'Низкий')], default='E', max_length=1), + ), + migrations.CreateModel( + name='ChangeLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('act_type', models.CharField(choices=[('e', 'Изменение задачи'), ('c', 'Создание задачи'), ('d', 'Удаление задачи')], max_length=1)), + ('when', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.AlterModelOptions( + name='task', + options={'ordering': ('-id',), 'permissions': (('can_viewall', 'Доступ ко всем задачам'),)}, + ), + migrations.AddField( + model_name='changelog', + name='task', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='taskapp.Task'), + ), + migrations.AddField( + model_name='changelog', + name='who', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.RemoveField( + model_name='task', + name='device', + ), + migrations.RemoveField( + model_name='task', + name='recipient', + ), + migrations.AddField( + model_name='task', + name='recipients', + field=models.ManyToManyField(related_name='them_task', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterModelOptions( + name='task', + options={'ordering': ('-id',), 'permissions': (('can_viewall', 'Доступ ко всем задачам'), ('can_remind', 'Напоминания о задачах'))}, + ), + migrations.AlterField( + model_name='changelog', + name='act_type', + field=models.CharField(choices=[('e', 'Изменение задачи'), ('c', 'Создание задачи'), ('d', 'Удаление задачи'), ('f', 'Завершение задачи'), ('b', 'Задача начата')], max_length=1), + ), + migrations.AlterField( + model_name='task', + name='descr', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AlterField( + model_name='task', + name='attachment', + field=models.ImageField(blank=True, null=True, upload_to='media/task_attachments/%Y.%m.%d'), + ), + migrations.AlterField( + model_name='task', + name='attachment', + field=models.ImageField(blank=True, null=True, upload_to='task_attachments/%Y.%m.%d'), + ), + migrations.AlterField( + model_name='task', + name='abon', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon'), + ), + migrations.AlterField( + model_name='task', + name='author', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterField( + model_name='changelog', + name='act_type', + field=models.CharField(choices=[('e', 'Изменение задачи'), ('c', 'Создание задачи'), ('d', 'Удаление задачи'), ('f', 'Завершение задачи'), ('b', 'Задача провалена')], max_length=1), + ), + migrations.AlterField( + model_name='task', + name='state', + field=models.CharField(choices=[('S', 'Новая'), ('C', 'Провалена'), ('F', 'Выполнена')], default='S', max_length=1), + ), + ] diff --git a/taskapp/migrations/0005_auto_20161206_0013.py b/taskapp/migrations/0005_auto_20161206_0013.py index 8891a9b..f6e2423 100644 --- a/taskapp/migrations/0005_auto_20161206_0013.py +++ b/taskapp/migrations/0005_auto_20161206_0013.py @@ -8,7 +8,7 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('abonapp', '0001_initial'), + ('abonapp', '0001_squashed_0022_auto_20170816_1109'), ('taskapp', '0004_auto_20161202_1230'), ] From aba3572673a67e78e4adad7299f4a9cf79f3f204 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 27 Sep 2017 15:01:23 +0300 Subject: [PATCH 17/22] fix --- devapp/templates/devapp/dev.html | 4 ++-- taskapp/views.py | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/devapp/templates/devapp/dev.html b/devapp/templates/devapp/dev.html index f7daeda..43e627d 100644 --- a/devapp/templates/devapp/dev.html +++ b/devapp/templates/devapp/dev.html @@ -89,10 +89,10 @@ {% if selected_parent_dev %} - + {% else %} - + {% endif %} {{ form.parent_dev.errors }}
diff --git a/taskapp/views.py b/taskapp/views.py index d8ec471..d5468be 100644 --- a/taskapp/views.py +++ b/taskapp/views.py @@ -181,8 +181,11 @@ def task_finish(request, task_id): @login_required @only_admins def task_failed(request, task_id): - task = get_object_or_404(Task, id=task_id) - task.do_fail(request.user) + try: + task = get_object_or_404(Task, id=task_id) + task.do_fail(request.user) + except TaskException as e: + messages.error(request, e) return redirect('taskapp:home') From de80ebba1176b782fbbed8873552c6a7a3dc4d65 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 27 Sep 2017 19:14:07 +0300 Subject: [PATCH 18/22] Add per object permissions support --- abonapp/locale/ru/LC_MESSAGES/django.po | 38 +-- .../0001_squashed_0022_auto_20170816_1109.py | 14 -- abonapp/migrations/0003_auto_20170927_1838.py | 43 ++++ abonapp/models.py | 73 ++++-- .../templates/abonapp/complete_service.html | 58 ----- abonapp/templates/abonapp/editAbon.html | 12 +- abonapp/templates/abonapp/group_list.html | 2 +- abonapp/templates/abonapp/payHistory.html | 16 +- abonapp/templates/abonapp/peoples.html | 9 +- abonapp/templates/abonapp/viewAbon.html | 2 + abonapp/urls.py | 4 +- abonapp/urls_abon.py | 1 - abonapp/views.py | 216 +++++++----------- accounts_app/forms.py | 30 ++- accounts_app/locale/ru/LC_MESSAGES/django.po | 70 +++--- .../migrations/0008_auto_20170927_1838.py | 19 ++ accounts_app/models.py | 10 + accounts_app/templates/accounts/ext.htm | 32 ++- accounts_app/templates/accounts/group.html | 50 ---- .../templates/accounts/group_list.html | 58 ----- .../accounts/perms/objects_of_type.html | 34 +++ .../accounts/perms/objects_types.html | 36 +++ .../templates/accounts/perms/perms_edit.html | 71 ++++++ .../templates/accounts/profile_chgroup.html | 8 +- .../accounts/set_abon_groups_permission.html | 25 ++ .../templates/accounts/settings/ext.htm | 7 - .../accounts/settings/permissions.html | 14 -- .../templates/accounts/settings/test.html | 14 ++ accounts_app/templatetags/__init__.py | 1 + accounts_app/templatetags/acc_tags.py | 18 ++ accounts_app/urls.py | 8 +- accounts_app/views.py | 133 +++++++---- .../templates/clientsideapp/ext.html | 5 +- devapp/locale/ru/LC_MESSAGES/django.po | 9 + devapp/migrations/0003_auto_20170927_1838.py | 23 ++ devapp/models.py | 11 + .../templates/devapp/custom_dev_page/onu.html | 37 +-- .../templates/devapp/devices_null_group.html | 12 +- devapp/views.py | 34 ++- djing/settings_example.py | 8 +- mapapp/views.py | 3 +- requirements.txt | 2 + tariff_app/views.py | 3 +- taskapp/views.py | 3 +- templates/all_base.html | 2 +- 45 files changed, 749 insertions(+), 529 deletions(-) create mode 100644 abonapp/migrations/0003_auto_20170927_1838.py delete mode 100644 abonapp/templates/abonapp/complete_service.html create mode 100644 accounts_app/migrations/0008_auto_20170927_1838.py delete mode 100644 accounts_app/templates/accounts/group.html delete mode 100644 accounts_app/templates/accounts/group_list.html create mode 100644 accounts_app/templates/accounts/perms/objects_of_type.html create mode 100644 accounts_app/templates/accounts/perms/objects_types.html create mode 100644 accounts_app/templates/accounts/perms/perms_edit.html create mode 100644 accounts_app/templates/accounts/set_abon_groups_permission.html delete mode 100644 accounts_app/templates/accounts/settings/permissions.html create mode 100644 accounts_app/templates/accounts/settings/test.html create mode 100644 accounts_app/templatetags/__init__.py create mode 100644 accounts_app/templatetags/acc_tags.py create mode 100644 devapp/migrations/0003_auto_20170927_1838.py diff --git a/abonapp/locale/ru/LC_MESSAGES/django.po b/abonapp/locale/ru/LC_MESSAGES/django.po index 35afe9e..ac9e7a6 100644 --- a/abonapp/locale/ru/LC_MESSAGES/django.po +++ b/abonapp/locale/ru/LC_MESSAGES/django.po @@ -389,10 +389,6 @@ msgstr "Дом" msgid "Is active" msgstr "Активен" -#: abonapp/templates/abonapp/editAbon.html:106 -msgid "Send account info to user" -msgstr "Отправить данные абоненту" - #: abonapp/templates/abonapp/editAbon.html:109 #: abonapp/templates/abonapp/editAbon.html:110 #, fuzzy @@ -473,7 +469,7 @@ msgstr "Принадлежность услуг к группам" #: abonapp/templates/abonapp/invoiceForPayment.html:10 #: abonapp/templates/abonapp/payHistory.html:39 msgid "Debts" -msgstr "Долги" +msgstr "Квитанции (долги)" #: abonapp/templates/abonapp/invoiceForPayment.html:15 msgid "Debtor" @@ -606,10 +602,6 @@ msgstr "Балланс" msgid "Subscribers not found" msgstr "Абоненты не найдены" -#: abonapp/templates/abonapp/peoples.html:130 -msgid "Refresh subscribers on NAS" -msgstr "Обновить абонентов в NAS" - #: abonapp/templates/abonapp/peoples.html:133 msgid "Tariffs in groups" msgstr "Тарифы в группах" @@ -736,10 +728,6 @@ msgstr "Адрес" msgid "delete abon success msg" msgstr "Абонент успешно удалён" -#: abonapp/views.py:180 -msgid "I not know what to delete" -msgstr "Не понятно что удалять" - #: abonapp/views.py:184 #, python-format msgid "NAS says: '%s'" @@ -993,3 +981,27 @@ msgstr "Номер телефона успешно удалён" msgid "Telephone not found" msgstr "Телефон не найден" + +msgid "Can view subscriber group" +msgstr "Может просматривать группу абонентов" + +msgid "Permission denied" +msgstr "Доступ запрещён" + +msgid "Can view subscriber logs" +msgstr "Может видеть логи абонента" + +msgid "Can view invoice for payment" +msgstr "Может видеть назначенные платежи" + +msgid "Debt" +msgstr "Квитанция (долг)" + +msgid "Passport Info" +msgstr "Паспортные данные" + +msgid "Can ping" +msgstr "Может пинговать" + +msgid "Can view additional telephones" +msgstr "Может видеть дополнительные телефоны" diff --git a/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py b/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py index b68d5ef..89e222c 100644 --- a/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py +++ b/abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py @@ -231,11 +231,6 @@ class Migration(migrations.Migration): name='tariffs', field=models.ManyToManyField(blank=True, related_name='tariff_groups', to='tariff_app.Tariff'), ), - migrations.AddField( - model_name='abon', - name='opt82', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='abonapp.Opt82'), - ), migrations.CreateModel( name='PassportInfo', fields=[ @@ -247,11 +242,6 @@ class Migration(migrations.Migration): ('abon', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.Abon')), ], ), - migrations.AlterField( - model_name='abon', - name='opt82', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.Opt82'), - ), migrations.CreateModel( name='AbonDevice', fields=[ @@ -282,10 +272,6 @@ class Migration(migrations.Migration): name='ip_address', field=mydefs.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4'), ), - migrations.RemoveField( - model_name='abon', - name='opt82', - ), migrations.AddField( model_name='abon', name='dev_port', diff --git a/abonapp/migrations/0003_auto_20170927_1838.py b/abonapp/migrations/0003_auto_20170927_1838.py new file mode 100644 index 0000000..f15a614 --- /dev/null +++ b/abonapp/migrations/0003_auto_20170927_1838.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-09-27 18:38 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('abonapp', '0002_auto_20170905_1248'), + ] + + operations = [ + migrations.AlterModelOptions( + name='abon', + options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Может просматривать паспортные данные'), ('can_add_ballance', 'Пополнение счёта'), ('can_ping', 'Может пинговать')), 'verbose_name': 'Абонент', 'verbose_name_plural': 'Абоненты'}, + ), + migrations.AlterModelOptions( + name='abongroup', + options={'permissions': (('can_view_abongroup', 'Может просматривать группу абонентов'),), 'verbose_name': 'Группа абонентов', 'verbose_name_plural': 'Группы абонентов'}, + ), + migrations.AlterModelOptions( + name='abonlog', + options={'permissions': (('can_view_abonlog', 'Может видеть логи абонента'),)}, + ), + migrations.AlterModelOptions( + name='additionaltelephone', + options={'ordering': ('owner_name',), 'permissions': (('can_view_additionaltelephones', 'Может видеть дополнительные телефоны'),), 'verbose_name': 'Дополнительный телефон', 'verbose_name_plural': 'Дополнительные телефоны'}, + ), + migrations.AlterModelOptions( + name='invoiceforpayment', + options={'ordering': ('date_create',), 'permissions': (('can_view_invoiceforpayment', 'Может видеть назначенные платежи'),), 'verbose_name': 'Квитанция (долг)', 'verbose_name_plural': 'Квитанции (долги)'}, + ), + migrations.AlterModelOptions( + name='passportinfo', + options={'verbose_name': 'Паспортные данные', 'verbose_name_plural': 'Паспортные данные'}, + ), + migrations.AlterModelTable( + name='passportinfo', + table='passport_info', + ), + ] diff --git a/abonapp/models.py b/abonapp/models.py index d492f82..212ae5c 100644 --- a/abonapp/models.py +++ b/abonapp/models.py @@ -1,13 +1,15 @@ # -*- coding: utf-8 -*- from django.core.exceptions import ValidationError from django.core.validators import RegexValidator +from django.db.models.signals import post_save, post_delete, pre_delete, post_init +from django.dispatch import receiver from django.utils import timezone from django.db import models from django.core import validators from django.utils.translation import ugettext as _ from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNetworkError from tariff_app.models import Tariff -from accounts_app.models import UserProfile +from accounts_app.models import UserProfile, MyUserManager from mydefs import MyGenericIPAddressField, ip2int, LogicError, ip_addr_regex from django.conf import settings @@ -23,7 +25,7 @@ class AbonGroup(models.Model): class Meta: db_table = 'abonent_groups' permissions = ( - ('can_add_ballance', _('fill account')), + ('can_view_abongroup', _('Can view subscriber group')), ) verbose_name = _('Abon group') verbose_name_plural = _('Abon groups') @@ -41,6 +43,9 @@ class AbonLog(models.Model): class Meta: db_table = 'abonent_log' + permissions = ( + ('can_view_abonlog', _('Can view subscriber logs')), + ) def __str__(self): return self.comment @@ -133,6 +138,13 @@ class ExtraFieldsModel(models.Model): db_table = 'abon_extra_fields' + +class AbonManager(MyUserManager): + + def get_queryset(self): + return super(MyUserManager, self).get_queryset().filter(is_admin=False) + + class Abon(UserProfile): current_tariff = models.ForeignKey(AbonTariff, null=True, blank=True, on_delete=models.SET_NULL) group = models.ForeignKey(AbonGroup, models.SET_NULL, blank=True, null=True) @@ -150,11 +162,15 @@ class Abon(UserProfile): def active_tariff(self): return self.current_tariff + objects = AbonManager() + class Meta: db_table = 'abonent' permissions = ( ('can_buy_tariff', _('Buy service perm')), - ('can_view_passport', _('Can view passport')) + ('can_view_passport', _('Can view passport')), + ('can_add_ballance', _('fill account')), + ('can_ping', _('Can ping')) ) verbose_name = _('Abon') verbose_name_plural = _('Abons') @@ -261,6 +277,11 @@ class PassportInfo(models.Model): date_of_acceptance = models.DateField() abon = models.OneToOneField(Abon, on_delete=models.SET_NULL, blank=True, null=True) + class Meta: + db_table = 'passport_info' + verbose_name = _('Passport Info') + verbose_name_plural = _('Passport Info') + def __str__(self): return "%s %s" % (self.series, self.number) @@ -287,6 +308,11 @@ class InvoiceForPayment(models.Model): class Meta: ordering = ('date_create',) db_table = 'abonent_inv_pay' + permissions = ( + ('can_view_invoiceforpayment', _('Can view invoice for payment')), + ) + verbose_name = _('Debt') + verbose_name_plural = _('Debts') # Log for pay system "AllTime" @@ -345,11 +371,16 @@ class AdditionalTelephone(models.Model): class Meta: db_table = 'additional_telephones' ordering = ('owner_name',) + permissions = ( + ('can_view_additionaltelephones', _('Can view additional telephones')), + ) verbose_name = _('Additional telephone') verbose_name_plural = _('Additional telephones') -def abon_post_save(sender, instance, **kwargs): +@receiver(post_save, sender=Abon) +def abon_post_save(sender, **kwargs): + instance, created = kwargs["instance"], kwargs["created"] timeout = None if hasattr(instance, 'is_dhcp') and instance.is_dhcp: timeout = getattr(settings, 'DHCP_TIMEOUT', 14400) @@ -358,7 +389,7 @@ def abon_post_save(sender, instance, **kwargs): return True try: tm = Transmitter() - if kwargs['created']: + if created: # создаём абонента tm.add_user(agent_abon, ip_timeout=timeout) else: @@ -370,9 +401,11 @@ def abon_post_save(sender, instance, **kwargs): return True -def abon_del_signal(sender, instance, **kwargs): +@receiver(post_delete, sender=Abon) +def abon_del_signal(sender, **kwargs): + abon = kwargs["instance"] try: - ab = instance.build_agent_struct() + ab = abon.build_agent_struct() if ab is None: return True # подключаемся к NAS'у @@ -383,17 +416,21 @@ def abon_del_signal(sender, instance, **kwargs): return True -def abon_tariff_post_init(sender, instance, **kwargs): - if getattr(instance, 'time_start') is None: - instance.time_start = timezone.now() - calc_obj = instance.tariff.get_calc_type()(instance) - if getattr(instance, 'deadline') is None: - instance.deadline = calc_obj.calc_deadline() +@receiver(post_init, sender=AbonTariff) +def abon_tariff_post_init(sender, **kwargs): + abon_tariff = kwargs["instance"] + if getattr(abon_tariff, 'time_start') is None: + abon_tariff.time_start = timezone.now() + calc_obj = abon_tariff.tariff.get_calc_type()(abon_tariff) + if getattr(abon_tariff, 'deadline') is None: + abon_tariff.deadline = calc_obj.calc_deadline() -def abontariff_pre_delete(sender, instance, **kwargs): +@receiver(pre_delete, sender=AbonTariff) +def abontariff_pre_delete(sender, **kwargs): + abon_tariff = kwargs["instance"] try: - abon = Abon.objects.get(current_tariff=instance) + abon = Abon.objects.get(current_tariff=abon_tariff) ab = abon.build_agent_struct() if ab is None: return True @@ -404,9 +441,3 @@ def abontariff_pre_delete(sender, instance, **kwargs): except (NasFailedResult, NasNetworkError, ConnectionResetError) as e: print('NetErr:', e) return True - - -models.signals.post_save.connect(abon_post_save, sender=Abon) -models.signals.post_delete.connect(abon_del_signal, sender=Abon) -models.signals.post_init.connect(abon_tariff_post_init, sender=AbonTariff) -models.signals.pre_delete.connect(abontariff_pre_delete, sender=AbonTariff) diff --git a/abonapp/templates/abonapp/complete_service.html b/abonapp/templates/abonapp/complete_service.html deleted file mode 100644 index d0939a2..0000000 --- a/abonapp/templates/abonapp/complete_service.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends request.is_ajax|yesno:'bajax.html,base.html' %} -{% load i18n %} -{% block main %} - - - - {% include 'message_block.html' %} - -
-
-

{% trans 'Finish service' %}

-
-
- -
{% csrf_token %} - - -

- {% blocktrans %}Early completion of the current service will cause that user will be denied access to services Resources (Net closes) -To continue to use the resources necessary to connect the required service{% endblocktrans %} -

- -

{% blocktrans %}Details:
-You complete tariff{% endblocktrans %} - - {% if perms.tariff_app.change_tariff %} - {{ abtar.tariff.title }}.
- {% else %} - {{ abtar.tariff.title }}.
- {% endif %} - - {% now "d F Y, H: i: s" as today %} - {% blocktrans with time_start=abtar.time_start|date:'d F Y, H: i: s' amount=abtar.tariff.amount %}The service has been connected: {{ time_start }}
-Today: {{ today }}
-Time of use: {{ time_use }}
-The total cost of the service: {{ amount }}
-Total cost: {{ tcost }}
-Cashback: {{ cashback }}{% endblocktrans %} -

- -
- -
- -
- -
-
- -{% endblock %} \ No newline at end of file diff --git a/abonapp/templates/abonapp/editAbon.html b/abonapp/templates/abonapp/editAbon.html index 4cf8744..5e93ebd 100644 --- a/abonapp/templates/abonapp/editAbon.html +++ b/abonapp/templates/abonapp/editAbon.html @@ -1,5 +1,6 @@ {% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} {% load i18n %} +{% load guardian_tags %} {% block content %}
@@ -108,9 +109,6 @@ - {% if perms.taskapp.add_task %} {% trans 'Add new task' %} @@ -119,7 +117,7 @@
- {% if ip %} + {% if ip and perms.abonapp.can_ping %} diff --git a/abonapp/templates/abonapp/group_list.html b/abonapp/templates/abonapp/group_list.html index 59fb7ed..d3518c9 100644 --- a/abonapp/templates/abonapp/group_list.html +++ b/abonapp/templates/abonapp/group_list.html @@ -38,7 +38,7 @@ {% if perms.abonapp.delete_abongroup %} {% if gr.usercount == 0 %} - + {% endif %} diff --git a/abonapp/templates/abonapp/payHistory.html b/abonapp/templates/abonapp/payHistory.html index f81a128..a6be2e6 100644 --- a/abonapp/templates/abonapp/payHistory.html +++ b/abonapp/templates/abonapp/payHistory.html @@ -1,5 +1,6 @@ {% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} {% load i18n %} +{% load guardian_tags %} {% block content %} @@ -30,12 +31,17 @@ diff --git a/abonapp/templates/abonapp/peoples.html b/abonapp/templates/abonapp/peoples.html index 905ea2e..9e787fe 100644 --- a/abonapp/templates/abonapp/peoples.html +++ b/abonapp/templates/abonapp/peoples.html @@ -104,7 +104,7 @@ diff --git a/abonapp/templates/abonapp/viewAbon.html b/abonapp/templates/abonapp/viewAbon.html index 914b7e9..b05df1a 100644 --- a/abonapp/templates/abonapp/viewAbon.html +++ b/abonapp/templates/abonapp/viewAbon.html @@ -61,6 +61,7 @@ + {% if perms.abonapp.can_view_passport %}
@@ -86,6 +87,7 @@
+ {% endif %} {% endblock %} \ No newline at end of file diff --git a/abonapp/urls.py b/abonapp/urls.py index 3aa6686..048f525 100644 --- a/abonapp/urls.py +++ b/abonapp/urls.py @@ -13,7 +13,7 @@ urlpatterns = [ url(r'^log$', views.log_page, name='log'), - url(r'^del$', views.delentity, name='del_abon'), + url(r'^del$', views.del_abon, name='del_abon'), url(r'^pay$', views.terminal_pay, name='terminal_pay'), @@ -21,8 +21,6 @@ urlpatterns = [ url(r'^ping$', views.abon_ping, name='ping'), - url(r'^refresh_group_nas(?P\d+)$', views.update_nas, name='update_nas'), - # Api's url(r'^api/abons$', views.abons), url(r'^api/abon_filter$', views.search_abon) diff --git a/abonapp/urls_abon.py b/abonapp/urls_abon.py index 9267cb1..d37a86c 100644 --- a/abonapp/urls_abon.py +++ b/abonapp/urls_abon.py @@ -19,7 +19,6 @@ urlpatterns = [ url(r'^(?P\d+)/addinvoice$', views.add_invoice, name='add_invoice'), url(r'^(?P\d+)/pick$', views.pick_tariff, name='pick_tariff'), url(r'^(?P\d+)/passport_view$', views.passport_view, name='passport_view'), - url(r'^(?P\d+)/complete_service(?P\d+)$', views.complete_service, name='compl_srv'), url(r'^(?P\d+)/chart$', views.charts, name='charts'), url(r'^(?P\d+)/dials$', views.dials, name='dials'), url(r'^(?P\d+)/extra_field$', views.make_extra_field, name='extra_field'), diff --git a/abonapp/views.py b/abonapp/views.py index 92a62fc..772083f 100644 --- a/abonapp/views.py +++ b/abonapp/views.py @@ -6,8 +6,7 @@ from django.db import IntegrityError, ProgrammingError from django.db.models import Count, Q from django.db.transaction import atomic from django.shortcuts import render, redirect, get_object_or_404, resolve_url -from django.contrib.auth.decorators import login_required, permission_required -from django.utils import timezone +from django.contrib.auth.decorators import login_required from django.http import HttpResponse from django.contrib import messages from django.utils.translation import ugettext_lazy as _ @@ -23,17 +22,22 @@ from datetime import datetime, date from taskapp.models import Task from dialing_app.models import AsteriskCDR from statistics.models import getModel, get_dates +from guardian.shortcuts import get_objects_for_user, assign_perm +from guardian.decorators import permission_required_or_403 as permission_required @login_required @mydefs.only_admins def peoples(request, gid): + abon_group = get_object_or_404(models.AbonGroup, pk=gid) + if not request.user.has_perm('abonapp.can_view_abongroup', abon_group): + raise PermissionDenied street_id = mydefs.safe_int(request.GET.get('street')) peoples_list = models.Abon.objects.select_related('group', 'street') if street_id > 0: - peoples_list = peoples_list.filter(group=gid, street=street_id) + peoples_list = peoples_list.filter(group=abon_group, street=street_id) else: - peoples_list = peoples_list.filter(group=gid) + peoples_list = peoples_list.filter(group=abon_group) # фильтр dr, field = mydefs.order_helper(request) @@ -72,7 +76,10 @@ def addgroup(request): if request.method == 'POST': frm = forms.AbonGroupForm(request.POST) if frm.is_valid(): - frm.save() + grp = frm.save() + assign_perm('abonapp.can_view_abongroup', request.user, grp) + assign_perm('abonapp.delete_abongroup', request.user, grp) + assign_perm('abonapp.change_abongroup', request.user, grp) messages.success(request, _('create group success msg')) return redirect('abonapp:group_list') else: @@ -91,6 +98,7 @@ def addgroup(request): @mydefs.only_admins def grouplist(request): groups = models.AbonGroup.objects.annotate(usercount=Count('abon')).order_by('title') + groups = get_objects_for_user(request.user, 'abonapp.can_view_abongroup', klass=groups, accept_global_perms=False) # фильтр directory, field = mydefs.order_helper(request) @@ -107,11 +115,13 @@ def grouplist(request): @login_required -@permission_required('abonapp.delete_abongroup') def delgroup(request): try: agd = mydefs.safe_int(request.GET.get('id')) - get_object_or_404(models.AbonGroup, pk=agd).delete() + abon_group = models.AbonGroup.objects.get(pk=agd) + if not request.user.has_perm('abonapp.delete_abongroup', abon_group): + raise PermissionDenied + abon_group.delete() messages.success(request, _('delete group success msg')) return mydefs.res_success(request, 'abonapp:group_list') except (NasFailedResult, NasNetworkError) as e: @@ -119,6 +129,8 @@ def delgroup(request): except mydefs.MultipleException as errs: for err in errs.err_list: messages.add_message(request, messages.constants.ERROR, err) + except models.AbonGroup.DoesNotExist: + return mydefs.res_error(request, 'Group with id=%d does not exist' % agd) return mydefs.res_error(request, 'abonapp:group_list') @@ -129,10 +141,17 @@ def addabon(request, gid): group = None try: group = get_object_or_404(models.AbonGroup, pk=gid) + if not request.user.has_perm('abonapp.can_view_abongroup', group): + raise PermissionDenied if request.method == 'POST': frm = forms.AbonForm(request.POST, initial={'group': group}) if frm.is_valid(): abon = frm.save() + assign_perm("abonapp.change_abon", request.user, abon) + assign_perm("abonapp.delete_abon", request.user, abon) + assign_perm("abonapp.can_buy_tariff", request.user, abon) + assign_perm("abonapp.can_view_passport", request.user, abon) + assign_perm('abonapp.can_add_ballance', request.user, abon) messages.success(request, _('create abon success msg')) return redirect('abonapp:abon_home', group.id, abon.pk) else: @@ -159,26 +178,18 @@ def addabon(request, gid): @login_required @mydefs.only_admins -def delentity(request): - typ = request.GET.get('t') +def del_abon(request): uid = request.GET.get('id') try: - if typ == 'a': - if not request.user.has_perm('abonapp.delete_abon'): - raise PermissionDenied - abon = get_object_or_404(models.Abon, pk=uid) - gid = abon.group.id - abon.delete() - messages.success(request, _('delete abon success msg')) - return mydefs.res_success(request, resolve_url('abonapp:people_list', gid=gid)) - elif typ == 'g': - if not request.user.has_perm('abonapp.delete_abongroup'): - raise PermissionDenied - get_object_or_404(models.AbonGroup, pk=uid).delete() - messages.success(request, _('delete group success msg')) - return mydefs.res_success(request, 'abonapp:group_list') - else: - messages.warning(request, _('I not know what to delete')) + abon = get_object_or_404(models.Abon, pk=uid) + if not request.user.has_perm('abonapp.delete_abon') or not request.user.has_perm( + 'abonapp.can_view_abongroup', abon.group): + raise PermissionDenied + gid = abon.group.id + abon.delete() + messages.success(request, _('delete abon success msg')) + return mydefs.res_success(request, resolve_url('abonapp:people_list', gid=gid)) + except NasNetworkError as e: messages.error(request, e) except NasFailedResult as e: @@ -190,12 +201,13 @@ def delentity(request): @login_required -@permission_required('abonapp.can_add_ballance') @atomic def abonamount(request, gid, uid): abon = get_object_or_404(models.Abon, pk=uid) try: if request.method == 'POST': + if not request.user.has_perm('abonapp.can_add_ballance', abon): + raise PermissionDenied abonid = mydefs.safe_int(request.POST.get('abonid')) if abonid == int(uid): amnt = mydefs.safe_float(request.POST.get('amount')) @@ -218,6 +230,7 @@ def abonamount(request, gid, uid): @login_required @mydefs.only_admins +@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid')) def invoice_for_payment(request, gid, uid): abon = get_object_or_404(models.Abon, pk=uid) invoices = models.InvoiceForPayment.objects.filter(abon=abon) @@ -231,6 +244,7 @@ def invoice_for_payment(request, gid, uid): @login_required @mydefs.only_admins +@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid')) def pay_history(request, gid, uid): abon = get_object_or_404(models.Abon, pk=uid) pay_history = models.AbonLog.objects.filter(abon=abon).order_by('-id') @@ -246,6 +260,8 @@ def pay_history(request, gid, uid): @mydefs.only_admins def abon_services(request, gid, uid): grp = get_object_or_404(models.AbonGroup, pk=gid) + if not request.user.has_perm('abonapp.can_view_abongroup', grp): + raise PermissionDenied abon = get_object_or_404(models.Abon, pk=uid) return render(request, 'abonapp/service.html', { @@ -265,7 +281,7 @@ def abonhome(request, gid, uid): passw = None try: if request.method == 'POST': - if not request.user.has_perm('abonapp.change_abon'): + if not request.user.has_perm('abonapp.change_abon', abon): raise PermissionDenied frm = forms.AbonForm(request.POST, instance=abon) if frm.is_valid(): @@ -303,6 +319,8 @@ def abonhome(request, gid, uid): 'dev_ports': DevPort.objects.filter(device=abon.device) if abon.device else None }) else: + if not request.user.has_perm('abonapp.can_view_abongroup', abon_group): + raise PermissionDenied return render(request, 'abonapp/viewAbon.html', { 'abon': abon, 'abon_group': abon_group, @@ -356,11 +374,12 @@ def add_invoice(request, gid, uid): @login_required -@permission_required('abonapp.can_buy_tariff') @atomic def pick_tariff(request, gid, uid): grp = get_object_or_404(models.AbonGroup, pk=gid) abon = get_object_or_404(models.Abon, pk=uid) + if not request.user.has_perm('abonapp.can_buy_tariff', abon): + raise PermissionDenied tariffs = grp.tariffs.all() try: if request.method == 'POST': @@ -395,70 +414,13 @@ def pick_tariff(request, gid, uid): @login_required -@permission_required('abonapp.can_complete_service') -@atomic -def complete_service(request, gid, uid, srvid): - abtar = get_object_or_404(models.AbonTariff, pk=srvid) - abon = abtar.abon - # считаем не использованные ресурсы - calc_obj = abtar.tariff.get_calc_type()(abtar) - # получаем сколько использовано - res_amount = calc_obj.calc_amount() - cashback = abtar.tariff.amount - res_amount - - if abtar.abon.group is None: - abon.group = get_object_or_404(models.AbonGroup, pk=gid) - abon.save(update_fields=['group']) - if int(abtar.abon.pk) != int(uid) or int(abtar.abon.group.pk) != int(gid): - # если что-то написали в урле вручную, то вернём на путь истинный - return redirect('abonapp:compl_srv', gid=abtar.abon.group.pk, uid=abtar.abon.pk, srvid=srvid) - time_use = None - try: - if request.method == 'POST': - # досрочно завершаем услугу - if request.POST.get('finish_confirm') == 'yes': - if cashback > 0.5: - # возвращаем деньги, которые абонент не использовал - abon.add_ballance( - request.user, - cashback, - _('Refunds for unused resources') - ) - abon.save(update_fields=['ballance']) - - # удаляем запись о текущей услуге. - abtar.delete() - messages.success(request, _('Service has been finished successfully')) - return redirect('abonapp:abon_services', gid, uid) - else: - raise mydefs.LogicError(_('Not confirmed')) - - time_use = mydefs.RuTimedelta(timezone.now() - abtar.time_start) - - except (mydefs.LogicError, NasFailedResult) as e: - messages.error(request, e) - except NasNetworkError as e: - messages.warning(request, e) - return redirect('abonapp:abon_home', gid, uid) - except mydefs.MultipleException as errs: - for err in errs.err_list: - messages.add_message(request, messages.constants.ERROR, err) - - return render(request, 'abonapp/complete_service.html', { - 'abtar': abtar, - 'abon': abon, - 'time_use': time_use, - 'abon_group': get_object_or_404(models.AbonGroup, pk=gid), - 'tcost': round(res_amount, 4), - 'cashback': round(cashback, 4) - }) - - -@login_required -@permission_required('abonapp.delete_abontariff') +@mydefs.only_admins def unsubscribe_service(request, gid, uid, abon_tariff_id): try: - get_object_or_404(models.AbonTariff, pk=int(abon_tariff_id)).delete() + abon_tariff = get_object_or_404(models.AbonTariff, pk=int(abon_tariff_id)) + if not request.user.has_perm('abonapp.delete_abontariff', abon_tariff): + raise PermissionDenied + abon_tariff.delete() messages.success(request, _('User has been detached from service')) except NasFailedResult as e: messages.error(request, e) @@ -471,7 +433,7 @@ def unsubscribe_service(request, gid, uid, abon_tariff_id): @login_required -@mydefs.only_admins +@permission_required('abonapp.can_view_abonlog') def log_page(request): logs = models.AbonLog.objects.all() logs = mydefs.pag_mn(request, logs) @@ -481,42 +443,17 @@ def log_page(request): @login_required -@mydefs.only_admins +@permission_required('abonapp.can_view_invoiceforpayment') def debtors(request): - # peoples_list = models.Abon.objects.filter(invoiceforpayment__status=True) - # peoples_list = mydefs.pag_mn(request, peoples_list) invs = models.InvoiceForPayment.objects.filter(status=True) invs = mydefs.pag_mn(request, invs) return render(request, 'abonapp/debtors.html', { - # 'peoples': peoples_list 'invoices': invs }) @login_required -@mydefs.only_admins -def update_nas(request, group_id): - users = models.Abon.objects.filter(group=group_id) - try: - tm = Transmitter() - for usr in users: - if not usr.ip_address: - continue - agent_abon = usr.build_agent_struct() - if agent_abon is not None: - tm.update_user(agent_abon) - except NasFailedResult as e: - messages.error(request, e) - except NasNetworkError as e: - messages.warning(request, e) - except mydefs.MultipleException as errs: - for err in errs.err_list: - messages.add_message(request, messages.constants.ERROR, err) - return redirect('abonapp:people_list', gid=group_id) - - -@login_required -@mydefs.only_admins +@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid')) def task_log(request, gid, uid): abon = get_object_or_404(models.Abon, pk=uid) tasks = Task.objects.filter(abon=abon) @@ -532,6 +469,8 @@ def task_log(request, gid, uid): def passport_view(request, gid, uid): try: abon = models.Abon.objects.get(pk=uid) + if not request.user.has_perm('abonapp.can_view_passport', abon): + raise PermissionDenied if request.method == 'POST': try: passport_instance = models.PassportInfo.objects.get(abon=abon) @@ -566,6 +505,8 @@ def passport_view(request, gid, uid): @mydefs.only_admins def chgroup_tariff(request, gid): grp = get_object_or_404(models.AbonGroup, pk=gid) + if not request.user.has_perm('abonapp.change_abongroup', grp): + raise PermissionDenied if request.method == 'POST': tr = request.POST.getlist('tr') grp.tariffs.clear() @@ -579,7 +520,7 @@ def chgroup_tariff(request, gid): @login_required -@mydefs.only_admins +@permission_required('abonapp.change_abon') def dev(request, gid, uid): abon_dev = None try: @@ -609,6 +550,8 @@ def dev(request, gid, uid): def clear_dev(request, gid, uid): try: abon = models.Abon.objects.get(pk=uid) + if not request.user.has_perm('abonapp.change_abon', abon): + raise PermissionDenied abon.device = None abon.save(update_fields=['device']) messages.success(request, _('Device has successfully unattached')) @@ -619,7 +562,7 @@ def clear_dev(request, gid, uid): @login_required -@mydefs.only_admins +@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid')) def charts(request, gid, uid): high = 100 @@ -673,7 +616,7 @@ def charts(request, gid, uid): @login_required -@permission_required('abonapp.add_extra_fields_model') +@permission_required('abonapp.add_extrafieldsmodel') def make_extra_field(request, gid, uid): abon = get_object_or_404(models.Abon, pk=uid) try: @@ -733,6 +676,7 @@ def extra_field_delete(request, gid, uid, fid): @login_required +@permission_required('abonapp.can_ping') def abon_ping(request): ip = request.GET.get('cmd_param') status = False @@ -753,7 +697,8 @@ def abon_ping(request): text = ' %s' % _('ok ping, %d/%d loses') % ping_result status = True else: - text = ' %s' % _('no ping, %d/%d loses') % ping_result + text = ' %s' % _( + 'no ping, %d/%d loses') % ping_result else: text = ' %s' % _('ping ok') + ' ' + str(ping_result) status = True @@ -773,6 +718,8 @@ def abon_ping(request): @mydefs.only_admins def dials(request, gid, uid): abon = get_object_or_404(models.Abon, pk=uid) + if not request.user.has_perm('abonapp.can_view_abongroup', abon.group): + raise PermissionDenied if hasattr(abon.group, 'pk') and abon.group.pk != int(gid): return redirect('abonapp:dials', abon.group.pk, abon.pk) if abon.telephone is not None and abon.telephone != '': @@ -804,6 +751,8 @@ def save_user_dev_port(request, gid, uid): else: port = DevPort.objects.get(pk=user_port) abon = models.Abon.objects.get(pk=uid) + if not request.user.has_perm('abonapp.change_abon', abon): + raise PermissionDenied abon.dev_port = port if abon.is_dynamic_ip != is_dynamic_ip: abon.is_dynamic_ip = is_dynamic_ip @@ -842,7 +791,8 @@ def street_add(request, gid): def street_edit(request, gid): try: if request.method == 'POST': - streets_pairs = [(int(sid), sname) for sid, sname in zip(request.POST.getlist('sid'), request.POST.getlist('sname'))] + streets_pairs = [(int(sid), sname) for sid, sname in + zip(request.POST.getlist('sid'), request.POST.getlist('sname'))] for sid, sname in streets_pairs: street = models.AbonStreet.objects.get(pk=sid) street.name = sname @@ -872,7 +822,7 @@ def street_del(request, gid, sid): @login_required -@mydefs.only_admins +@permission_required('abonapp.can_view_additionaltelephones') def tels(request, gid, uid): abon = get_object_or_404(models.Abon, pk=uid) telephones = abon.additional_telephones.all() @@ -923,17 +873,17 @@ def tel_del(request, gid, uid): def abons(request): ablist = [{ - 'id': abn.pk, - 'tarif_id': abn.active_tariff().tariff.pk if abn.active_tariff() is not None else 0, - 'ip': abn.ip_address.int_ip(), - 'is_active': abn.is_active - } for abn in models.Abon.objects.all()] + 'id': abn.pk, + 'tarif_id': abn.active_tariff().tariff.pk if abn.active_tariff() is not None else 0, + 'ip': abn.ip_address.int_ip(), + 'is_active': abn.is_active + } for abn in models.Abon.objects.all()] tarlist = [{ - 'id': trf.pk, - 'speedIn': trf.speedIn, - 'speedOut': trf.speedOut - } for trf in Tariff.objects.all()] + 'id': trf.pk, + 'speedIn': trf.speedIn, + 'speedOut': trf.speedOut + } for trf in Tariff.objects.all()] data = { 'subscribers': ablist, diff --git a/accounts_app/forms.py b/accounts_app/forms.py index fbedf6f..4288081 100644 --- a/accounts_app/forms.py +++ b/accounts_app/forms.py @@ -1,12 +1,24 @@ # -*- coding: utf-8 -*- -from django import forms -from .models import UserProfile +from guardian.forms import UserObjectPermissionsForm +from guardian.shortcuts import assign_perm, remove_perm -class SetupPerms(forms.ModelForm): - class Meta: - model = UserProfile - fields = ['user_permissions'] - widgets = { - 'user_permissions': forms.CheckboxSelectMultiple() - } +class MyUserObjectPermissionsForm(UserObjectPermissionsForm): + + def save_obj_perms(self): + """ + Saves selected object permissions by creating new ones and removing + those which were not selected but already exists. + + Should be called *after* form is validated. + """ + perms = set(self.cleaned_data[self.get_obj_perms_field_name()]) + model_perms = set([c[0] for c in self.get_obj_perms_field_choices()]) + init_perms = set(self.get_obj_perms_field_initial()) + + to_remove = (model_perms - perms) & init_perms + for perm in to_remove: + remove_perm(perm, self.user, self.obj) + + for perm in perms - init_perms: + assign_perm(perm, self.user, self.obj) diff --git a/accounts_app/locale/ru/LC_MESSAGES/django.po b/accounts_app/locale/ru/LC_MESSAGES/django.po index d3c7a5c..1de16c6 100644 --- a/accounts_app/locale/ru/LC_MESSAGES/django.po +++ b/accounts_app/locale/ru/LC_MESSAGES/django.po @@ -33,18 +33,6 @@ msgstr "Администраторы" msgid "Groups" msgstr "Группы" -#: accounts_app/templates/accounts/group.html:16 -msgid "The current distribution of rights for groups" -msgstr "Действующее распределение прав для группы" - -#: accounts_app/templates/accounts/group.html:22 -msgid "Available rights" -msgstr "Доступные права" - -#: accounts_app/templates/accounts/group.html:36 -msgid "Rights for the group" -msgstr "Права группы" - #: accounts_app/templates/accounts/group.html:44 #: accounts_app/templates/accounts/profile_chgroup.html:20 #: accounts_app/templates/accounts/settings/ch_info.html:66 @@ -58,22 +46,6 @@ msgstr "Сохранить" msgid "Reset" msgstr "Сбросить" -#: accounts_app/templates/accounts/group_list.html:11 -msgid "Admin groups list" -msgstr "Список групп администраторов" - -#: accounts_app/templates/accounts/group_list.html:20 -msgid "Group" -msgstr "Группа" - -#: accounts_app/templates/accounts/group_list.html:40 -msgid "Groups does not found" -msgstr "Нет групп" - -#: accounts_app/templates/accounts/group_list.html:47 -msgid "Add group" -msgstr "Добавить группу" - #: accounts_app/templates/accounts/index.html:8 #: accounts_app/templates/accounts/settings/ch_info.html:37 msgid "Telephone" @@ -186,11 +158,47 @@ msgstr "Настройка прав" msgid "Edit" msgstr "Редактировать" -msgid "Set a task" -msgstr "Дать задачу" - msgid "Please select an image" msgstr "Пожалуйста выберите изображение" msgid "Avatar successfully changed" msgstr "Аватар успешно изменён" + +msgid "Access to groups" +msgstr "Доступ к группам" + +msgid "The list of user groups to which the account has access" +msgstr "Список групп абонентов, к которым учётка имеет доступ" + +msgid "The responsibility of the staff of the group of subscribers" +msgstr "Ответственность работника за группы абонентов" + +msgid "Not set" +msgstr "Не найдено" + +msgid "Change permission for that object" +msgstr "Изменение прав доступа для выбранного объекта" + +msgid "Permissions has successfully updated" +msgstr "Права успешно обновлены" + +msgid "Profile is superuser, permissions to change it makes no sense" +msgstr "Учётная запись является суперпользователем, разрешения менять нет смысла" + +msgid "Staff account profile" +msgstr "Учётная запись работника" + +msgid "Staff account profiles" +msgstr "Учётные записи работников" + +msgid "Can view staff profile" +msgstr "Может просматривать учётку сотрудника" + +msgid "Pick object for edit permissions" +msgstr "Выберите объект для редактирования прав доступа" + +msgid "Pick the type of object" +msgstr "Выберите тип объекта" + +msgid "Profile has been deleted" +msgstr "Учётная запись удалена" diff --git a/accounts_app/migrations/0008_auto_20170927_1838.py b/accounts_app/migrations/0008_auto_20170927_1838.py new file mode 100644 index 0000000..fb3c6fe --- /dev/null +++ b/accounts_app/migrations/0008_auto_20170927_1838.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-09-27 18:38 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts_app', '0007_auto_20170816_1109'), + ] + + operations = [ + migrations.AlterModelOptions( + name='userprofile', + options={'permissions': (('can_view_userprofile', 'Может просматривать учётку сотрудника'),), 'verbose_name': 'Учётная запись работника', 'verbose_name_plural': 'Учётные записи работников'}, + ), + ] diff --git a/accounts_app/models.py b/accounts_app/models.py index a5f5238..94574d8 100644 --- a/accounts_app/models.py +++ b/accounts_app/models.py @@ -43,6 +43,9 @@ class MyUserManager(BaseUserManager): user.save(using=self._db) return user + def get_queryset(self): + return super(MyUserManager, self).get_queryset().filter(is_admin=True) + class UserProfile(AbstractBaseUser, PermissionsMixin): username = models.CharField(max_length=127, unique=True) @@ -91,3 +94,10 @@ class UserProfile(AbstractBaseUser, PermissionsMixin): def __str__(self): return self.get_full_name() + + class Meta: + permissions = ( + ('can_view_userprofile', _('Can view staff profile')), + ) + verbose_name = _('Staff account profile') + verbose_name_plural = _('Staff account profiles') diff --git a/accounts_app/templates/accounts/ext.htm b/accounts_app/templates/accounts/ext.htm index cc08e5c..2c7e829 100644 --- a/accounts_app/templates/accounts/ext.htm +++ b/accounts_app/templates/accounts/ext.htm @@ -22,11 +22,24 @@ {% endif %}
{% if userprofile == request.user %} - - {% trans 'Edit' %} + + + {% trans 'Edit' %} + + {% endif %} + {% if request.user.is_superuser %} + {% if userprofile.is_superuser %} + + + {% trans 'Permission options' %} + + {% else %} + + + {% trans 'Permission options' %} + + {% endif %} {% endif %} - - {% trans 'Set a task' %}
@@ -46,6 +59,15 @@ {% trans 'Groups' %} + {% if request.user.is_superuser %} + {% url 'acc_app:set_abon_groups_permission' uid as set_ag_perm %} + + + + {% trans 'Access to groups' %} + + + {% endif %}
@@ -55,4 +77,4 @@
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/accounts_app/templates/accounts/group.html b/accounts_app/templates/accounts/group.html deleted file mode 100644 index 96e0120..0000000 --- a/accounts_app/templates/accounts/group.html +++ /dev/null @@ -1,50 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block main %} - - - - {% include 'message_block.html' %} - -
-
-

{% trans 'The current distribution of rights for groups' %} {{ group.name }}

-
-
-
{% csrf_token %} - -
- - -
-
    -
  • -
  • -
-
- - -
-
- - - -
-
- -{% endblock %} \ No newline at end of file diff --git a/accounts_app/templates/accounts/group_list.html b/accounts_app/templates/accounts/group_list.html deleted file mode 100644 index fd90afd..0000000 --- a/accounts_app/templates/accounts/group_list.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block main %} - - - -

{% trans 'Admin groups list' %}

- - {% include 'message_block.html' %} - -
-
- {% if perms.abonapp.can_add_ballance %} - - {% trans 'Fill account' %} - + {% get_obj_perms request.user for abon as 'fill_perm' %} + {% if 'abonapp.can_add_ballance' in fill_perm %} + + {% trans 'Fill account' %} + + {% else %} + + {% trans 'Fill account' %} + {% endif %} - + {% trans 'Debts' %} {{ human.ballance }} {% if can_del_trf %} - + {% endif %} @@ -126,14 +126,11 @@
{% if perms.abonapp.add_abon %} - + {% trans 'Add abon' %} {% endif %} - - {% trans 'Refresh subscribers on NAS' %} - - + {% trans 'Tariffs in groups' %}
- - - - - - - - - {% for grp in groups %} - - - - - - {% empty %} - - - - {% endfor %} - - - - - - -
#{% trans 'Group' %}
{{ grp.id }}{{ grp.name }} - - - - - - -
{% trans 'Groups does not found' %}
- - - -
- - - {% include 'toolbar_page.html' with pag=groups %} - -{% endblock %} \ No newline at end of file diff --git a/accounts_app/templates/accounts/perms/objects_of_type.html b/accounts_app/templates/accounts/perms/objects_of_type.html new file mode 100644 index 0000000..e5adbcf --- /dev/null +++ b/accounts_app/templates/accounts/perms/objects_of_type.html @@ -0,0 +1,34 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block main %} + + + +

{% trans 'Pick object for edit permissions' %}

+ + {% include 'message_block.html' %} + +
+ + + + + + + + {% for obj in objects %}{% endfor %} + +
obj
+ {{ obj }} +
+
+ + {% include 'toolbar_page.html' with pag=objects %} + +{% endblock %} diff --git a/accounts_app/templates/accounts/perms/objects_types.html b/accounts_app/templates/accounts/perms/objects_types.html new file mode 100644 index 0000000..a831c76 --- /dev/null +++ b/accounts_app/templates/accounts/perms/objects_types.html @@ -0,0 +1,36 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load acc_tags %} +{% block main %} + + + +

{% trans 'Pick the type of object' %}

+ + {% include 'message_block.html' %} + +
+ + + + + + + + {% for klass in klasses %} + + + + {% endfor %} + +
{% trans 'Group' %}
+ <{{ klass }}> {% klass_name klass %} +
+
+ +{% endblock %} diff --git a/accounts_app/templates/accounts/perms/perms_edit.html b/accounts_app/templates/accounts/perms/perms_edit.html new file mode 100644 index 0000000..1e0cf96 --- /dev/null +++ b/accounts_app/templates/accounts/perms/perms_edit.html @@ -0,0 +1,71 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load guardian_tags %} +{% block main %} + + + +

{% trans 'Pick object for edit permissions' %}

+ + {% include 'message_block.html' %} + + {% if userprofile.is_superuser %} +
+ + + {% trans 'Profile is superuser, permissions to change it makes no sense' %} +
+ {% endif %} + +
+
+

{% trans 'Change permission for that object' %}

+
+
+ +
{% csrf_token %} + + {% get_obj_perms userprofile for obj as 'obj_perms' %} + + {% for field in form %} +
+ + +
+ +
+
+ {% endfor %} + +
+ + +
+
+
+
+ +{% endblock %} diff --git a/accounts_app/templates/accounts/profile_chgroup.html b/accounts_app/templates/accounts/profile_chgroup.html index 22156fa..c5ac443 100644 --- a/accounts_app/templates/accounts/profile_chgroup.html +++ b/accounts_app/templates/accounts/profile_chgroup.html @@ -2,15 +2,15 @@ {% load i18n %} {% block content %} - {% trans 'The responsibility of the administrator of the group of subscribers' %} + {% trans 'The responsibility of the staff of the group of subscribers' %}
{% csrf_token %} {% for ag in abongroups %}
@@ -21,4 +21,4 @@
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/accounts_app/templates/accounts/set_abon_groups_permission.html b/accounts_app/templates/accounts/set_abon_groups_permission.html new file mode 100644 index 0000000..b431f98 --- /dev/null +++ b/accounts_app/templates/accounts/set_abon_groups_permission.html @@ -0,0 +1,25 @@ +{% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %} +{% load i18n %} +{% block content %} + + {% trans 'The list of user groups to which the account has access' %} +
{% csrf_token %} + {% for ag in abongroups %} +
+ +
+ {% endfor %} +
+ + +
+
+ +{% endblock %} diff --git a/accounts_app/templates/accounts/settings/ext.htm b/accounts_app/templates/accounts/settings/ext.htm index 92c5b3c..342ecd1 100644 --- a/accounts_app/templates/accounts/settings/ext.htm +++ b/accounts_app/templates/accounts/settings/ext.htm @@ -36,13 +36,6 @@ {% trans 'Change self onfo' %} - {% if user.is_superuser %} -
  • - - {% trans 'Permission options' %} - -
  • - {% endif %}
    diff --git a/accounts_app/templates/accounts/settings/permissions.html b/accounts_app/templates/accounts/settings/permissions.html deleted file mode 100644 index 906b485..0000000 --- a/accounts_app/templates/accounts/settings/permissions.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends request.is_ajax|yesno:'nullcont.htm,accounts/settings/ext.htm' %} -{% block content %} - -
    {% csrf_token %} - {% for perm, pname in form.user_permissions.field.choices %} -
    - -
    - {% endfor %} -
    -{% endblock %} \ No newline at end of file diff --git a/accounts_app/templates/accounts/settings/test.html b/accounts_app/templates/accounts/settings/test.html new file mode 100644 index 0000000..62441f6 --- /dev/null +++ b/accounts_app/templates/accounts/settings/test.html @@ -0,0 +1,14 @@ +

    + + +

    diff --git a/accounts_app/templatetags/__init__.py b/accounts_app/templatetags/__init__.py new file mode 100644 index 0000000..3474bc8 --- /dev/null +++ b/accounts_app/templatetags/__init__.py @@ -0,0 +1 @@ +__author__ = 'bashmak' diff --git a/accounts_app/templatetags/acc_tags.py b/accounts_app/templatetags/acc_tags.py new file mode 100644 index 0000000..dd29299 --- /dev/null +++ b/accounts_app/templatetags/acc_tags.py @@ -0,0 +1,18 @@ +from django import template +from django.db.models import Model +from django.apps import apps +from six import string_types, class_types +register = template.Library() + + + +@register.simple_tag +def klass_name(klass): + if type(klass) is class_types and issubclass(klass, Model): + kl = klass + elif isinstance(klass, string_types): + app_label, model_name = klass.split('.', 1) + kl = apps.get_model(app_label, model_name) + else: + return 'Type not detected' + return kl._meta.verbose_name diff --git a/accounts_app/urls.py b/accounts_app/urls.py index adeb5ef..5224c1f 100644 --- a/accounts_app/urls.py +++ b/accounts_app/urls.py @@ -20,13 +20,11 @@ urlpatterns = [ url(r'^(?P\d+)$', views.profile_show, name='other_profile'), url(r'^(?P\d+)/perms$', views.perms, name='setup_perms'), + url(r'^(?P\d+)/perms/(?P[a-z_]+\.[a-zA-Z_]+)$', views.perms_klasses, name='perms_klasses'), + url(r'^(?P\d+)/perms/(?P[a-z_]+\.[a-zA-Z_]+)/(?P\d+)$', views.perms_edit, name='perms_edit'), url(r'^(?P\d+)/chgroup$', views.chgroup, name='profile_setup_group'), url(r'^(?P\d+)/del$', views.delete_profile, name='delete_profile'), - # назначить задание - url(r'^(?P\d+)/appoint_task$', views.appoint_task, name='appoint_task'), - - url(r'^group/$', views.groups, name='groups_list'), - url(r'^group/(?P\d+)$', views.group, name='group_link') + url(r'^(?P\d+)/user_group_access$', views.set_abon_groups_permission, name='set_abon_groups_permission') ] \ No newline at end of file diff --git a/accounts_app/views.py b/accounts_app/views.py index 0227436..8b6af02 100644 --- a/accounts_app/views.py +++ b/accounts_app/views.py @@ -1,10 +1,9 @@ # -*- coding: utf-8 -*- -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import login_required from django.contrib.auth import authenticate, login, logout from django.core.exceptions import PermissionDenied from django.core.urlresolvers import NoReverseMatch from django.shortcuts import render, redirect, get_object_or_404, resolve_url -from django.contrib.auth.models import Group, Permission from django.contrib import messages from django.utils.translation import ugettext as _ from abonapp.models import AbonGroup @@ -12,6 +11,8 @@ from abonapp.models import AbonGroup from photo_app.models import Photo from .models import UserProfile import mydefs +from guardian.decorators import permission_required_or_403 as permission_required +from guardian.shortcuts import get_objects_for_user, assign_perm, remove_perm @login_required @@ -62,6 +63,8 @@ def profile_show(request, uid=0): return redirect('acc_app:other_profile', uid=request.user.id) usr = get_object_or_404(UserProfile, id=uid) + if request.user != usr and not request.user.has_perm('accounts_app.can_view_userprofile', usr): + raise PermissionDenied if request.method == 'POST': usr.username = request.POST.get('username') usr.fio = request.POST.get('fio') @@ -85,12 +88,14 @@ def chgroup(request, uid): usr = request.user else: usr = get_object_or_404(UserProfile, id=uid) + if usr != request.user and not request.user.has_perm('accounts_app.change_userprofile', usr): + raise PermissionDenied if request.method == 'POST': ag = request.POST.getlist('ag') usr.abon_groups.clear() usr.abon_groups.add(*[int(d) for d in ag]) usr.save() - abongroups = AbonGroup.objects.all() + abongroups = AbonGroup.objects.only('pk', 'title') return render(request, 'accounts/profile_chgroup.html', { 'uid': uid, 'userprofile': usr, @@ -155,7 +160,7 @@ def ch_info(request): @login_required -@permission_required('acc_app.add_userprofile') +@permission_required('accounts_app.add_userprofile') def create_profile(request): if request.method == 'POST': username = request.POST.get('username') @@ -194,18 +199,20 @@ def create_profile(request): @login_required @mydefs.only_admins def delete_profile(request, uid): + prf = get_object_or_404(UserProfile, id=uid) if uid != request.user.id: - if not request.user.has_perm('acc_app.delete_userprofile'): + if not request.user.has_perm('acc_app.delete_userprofile', prf): raise PermissionDenied - prf = get_object_or_404(UserProfile, id=uid) prf.delete() + messages.success(request, _('Profile has been deleted')) return redirect('acc_app:accounts_list') @login_required @mydefs.only_admins def acc_list(request): - users = UserProfile.objects.filter(is_admin=True) + users = UserProfile.objects.filter(is_admin=True).exclude(pk=request.user.pk) + users = get_objects_for_user(request.user, 'accounts_app.can_view_userprofile', users) users = mydefs.pag_mn(request, users) return render(request, 'accounts/acc_list.html', { 'users': users @@ -213,54 +220,88 @@ def acc_list(request): @login_required -@mydefs.only_admins def perms(request, uid): - profile = get_object_or_404(UserProfile, id=uid) - own_permissions = UserProfile.get_all_permissions(profile) - return render(request, 'accounts/settings/permissions.html', { - 'uid': uid, - 'own_permissions': own_permissions + if not request.user.is_superuser: + raise PermissionDenied + userprofile = get_object_or_404(UserProfile, id=uid) + klasses = ( + 'abonapp.AbonGroup', 'abonapp.Abon', 'accounts_app.UserProfile', + 'abonapp.AbonTariff', 'abonapp.AbonStreet', 'devapp.Device', + 'abonapp.PassportInfo', 'abonapp.AdditionalTelephone' + ) + return render(request, 'accounts/perms/objects_types.html', { + 'userprofile': userprofile, + 'klasses': klasses }) @login_required -@mydefs.only_admins -def groups(request): - grps = Group.objects.all() - grps = mydefs.pag_mn(request, grps) - return render(request, 'accounts/group_list.html', { - 'groups': grps +def perms_klasses(request, uid, klass_name): + if not request.user.is_superuser: + raise PermissionDenied + from django.apps import apps + userprofile = get_object_or_404(UserProfile, pk=uid) + app_label, model_name = klass_name.split('.', 1) + klass = apps.get_model(app_label, model_name) + + objects = klass.objects.all() + objects = mydefs.pag_mn(request, objects) + + return render(request, 'accounts/perms/objects_of_type.html', { + 'userprofile': userprofile, + 'klass': klass_name, + 'klass_name': klass._meta.verbose_name, + 'objects': objects }) - @login_required -@mydefs.only_admins -def group(request, uid): - uid = mydefs.safe_int(uid) - grp = get_object_or_404(Group, id=uid) - - if request.method == 'POST': - group_rights = filter(lambda x: x[0] == 'group_rights', request.POST.lists())[0][1] - grp.permissions.clear() - for grr in group_rights: - rid = mydefs.safe_int(grr) - grp.permissions.add(rid) - grp.save() - return redirect('acc_app:profile_group_link', id=uid) - - grp_rights = grp.permissions.all() - all_rights = Permission.objects.exclude(group=grp) - - return render(request, 'accounts/group.html', { - 'group': grp, - 'all_rights': all_rights, - 'grp_rights': grp_rights +def perms_edit(request, uid, klass_name, obj_id): + if not request.user.is_superuser: + raise PermissionDenied + from django.apps import apps + from .forms import MyUserObjectPermissionsForm + userprofile = get_object_or_404(UserProfile, pk=uid) + app_label, model_name = klass_name.split('.', 1) + klass = apps.get_model(app_label, model_name) + obj = get_object_or_404(klass, pk=obj_id) + + frm = MyUserObjectPermissionsForm(userprofile, obj, request.POST or None) + if request.method == 'POST' and frm.is_valid(): + frm.save_obj_perms() + messages.success(request, _('Permissions has successfully updated')) + + return render(request, 'accounts/perms/perms_edit.html', { + 'userprofile': userprofile, + 'obj': obj, + 'form': frm, + 'klass': klass_name, + 'klass_name': klass._meta.verbose_name }) @login_required -@mydefs.only_admins -def appoint_task(req, uid): - uid = mydefs.safe_int(uid) - url = resolve_url('taskapp:add') - return redirect("%s?rp=%d" % (url, uid)) +def set_abon_groups_permission(request, uid): + # Only superuser can change object permissions + if not request.user.is_superuser: + raise PermissionDenied + userprofile = get_object_or_404(UserProfile, pk=uid) + + picked_groups = get_objects_for_user(userprofile, 'abonapp.can_view_abongroup', accept_global_perms=False) + picked_groups = picked_groups.values_list('pk', flat=True) + + if request.method == 'POST': + checked_groups = [int(ag) for ag in request.POST.getlist('ag', default=0)] + for abon_group in AbonGroup.objects.all(): + if abon_group.pk in checked_groups and abon_group.pk not in picked_groups: + assign_perm('abonapp.can_view_abongroup', userprofile, obj=abon_group) + elif abon_group.pk not in checked_groups and abon_group.pk in picked_groups: + remove_perm('abonapp.can_view_abongroup', userprofile, obj=abon_group) + return redirect('acc_app:set_abon_groups_permission', uid) + abongroups = AbonGroup.objects.only('pk', 'title') + + return render(request, 'accounts/set_abon_groups_permission.html', { + 'uid': uid, + 'userprofile': userprofile, + 'abongroups': abongroups, + 'picked_groups_ids': picked_groups + }) diff --git a/clientsideapp/templates/clientsideapp/ext.html b/clientsideapp/templates/clientsideapp/ext.html index b19ef15..ba81d1a 100644 --- a/clientsideapp/templates/clientsideapp/ext.html +++ b/clientsideapp/templates/clientsideapp/ext.html @@ -93,7 +93,10 @@ diff --git a/devapp/locale/ru/LC_MESSAGES/django.po b/devapp/locale/ru/LC_MESSAGES/django.po index 7a6f8e3..77cfd06 100644 --- a/devapp/locale/ru/LC_MESSAGES/django.po +++ b/devapp/locale/ru/LC_MESSAGES/django.po @@ -300,3 +300,12 @@ msgstr "Посмотреть устройство" msgid "Eltex switch" msgstr "Элтекс свич" + +msgid "Can view device" +msgstr "Может видеть устройство" + +msgid "Device" +msgstr "Устройство" + +msgid "Can toggle ports" +msgstr "Может переключать порты" diff --git a/devapp/migrations/0003_auto_20170927_1838.py b/devapp/migrations/0003_auto_20170927_1838.py new file mode 100644 index 0000000..490780c --- /dev/null +++ b/devapp/migrations/0003_auto_20170927_1838.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2017-09-27 18:38 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('devapp', '0002_device_user_group'), + ] + + operations = [ + migrations.AlterModelOptions( + name='device', + options={'permissions': (('can_view_device', 'Can view device'),), 'verbose_name': 'Device', 'verbose_name_plural': 'Devices'}, + ), + migrations.AlterModelOptions( + name='port', + options={'permissions': (('can_toggle_ports', 'Can toggle ports'),), 'verbose_name': 'Port', 'verbose_name_plural': 'Ports'}, + ), + ] diff --git a/devapp/models.py b/devapp/models.py index aaf0842..c21f07f 100644 --- a/devapp/models.py +++ b/devapp/models.py @@ -8,6 +8,7 @@ from . import dev_types from mapapp.models import Dot from subprocess import call from django.conf import settings +from django.utils.translation import ugettext_lazy as _ DEVICE_TYPES = ( @@ -34,6 +35,11 @@ class Device(models.Model): class Meta: db_table = 'dev' + permissions = ( + ('can_view_device', _('Can view device')), + ) + verbose_name = _('Device') + verbose_name_plural = _('Devices') def get_abons(self): pass @@ -69,6 +75,11 @@ class Port(models.Model): class Meta: db_table = 'dev_port' unique_together = (('device', 'num')) + permissions = ( + ('can_toggle_ports', _('Can toggle ports')), + ) + verbose_name = _('Port') + verbose_name_plural = _('Ports') def dev_post_save_signal(sender, instance, **kwargs): diff --git a/devapp/templates/devapp/custom_dev_page/onu.html b/devapp/templates/devapp/custom_dev_page/onu.html index 0a70d20..7ebb774 100644 --- a/devapp/templates/devapp/custom_dev_page/onu.html +++ b/devapp/templates/devapp/custom_dev_page/onu.html @@ -14,25 +14,28 @@
      -
    • {% trans 'Ip address' %}: {{ dev.ip_address }}
    • -
    • {% trans 'Mac' %}: {{ dev.mac_addr }}
    • -
    • {% trans 'Description' %} {{ dev.comment }}
    • +
    • {% trans 'Ip address' %}: {{ dev.ip_address }}
    • +
    • {% trans 'Mac' %}: {{ dev.mac_addr }}
    • +
    • {% trans 'Description' %} {{ dev.comment }}
    • {% for da in dev_accs %} -
    • {% trans 'Attached user' %}: - {% if da.group %} - {{ da.get_full_name }} - {% else %} - {{ da.get_full_name }} - {% endif %} -
    • +
    • {% trans 'Attached user' %}: + {% if da.group %} + {{ da.get_full_name }} + {% else %} + {{ da.get_full_name }} + {% endif %} +
    • {% endfor %} - {% if dev.parent_dev %} -
    • - {% with pdev=dev.parent_dev pdgrp=dev.parent_dev.user_group %} - {% trans 'Parent device' %}: {{ pdev.ip_address }} {{ pdev.comment }} - {% endwith %} -
    • - {% endif %} + {% if dev.parent_dev %} +
    • + {% with pdev=dev.parent_dev pdgrp=dev.parent_dev.user_group %} + {% trans 'Parent device' %}:{{ pdev.ip_address }} {{ pdev.comment }} + {% endwith %} +
    • + {% endif %}
    diff --git a/devapp/templates/devapp/devices_null_group.html b/devapp/templates/devapp/devices_null_group.html index 569825c..816bcbe 100644 --- a/devapp/templates/devapp/devices_null_group.html +++ b/devapp/templates/devapp/devices_null_group.html @@ -38,19 +38,20 @@ + {% with can_del_dev=perms.devapp.delete_device can_change_dev=perms.devapp.change_device %} {% for dev in devices %} - {{ dev.ip_address }} + {{ dev.ip_address }} {{ dev.comment }} {{ dev.get_devtype_display }} - {% if perms.devapp.delete_device %} - + {% if can_del_dev %} + {% endif %} - {% if perms.devapp.change_device %} - + {% if can_change_dev %} + {% endif %} @@ -61,6 +62,7 @@ {% trans 'Devices does not found' %}. {% trans 'Create' %} {% endfor %} + {% endwith %} diff --git a/devapp/views.py b/devapp/views.py index f332ef7..1b45b0a 100644 --- a/devapp/views.py +++ b/devapp/views.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import login_required from django.contrib.gis.shortcuts import render_to_text from django.core.exceptions import PermissionDenied from django.db.models import Q @@ -15,13 +15,18 @@ from mydefs import pag_mn, res_success, res_error, only_admins, ping, order_help from .forms import DeviceForm, PortForm from abonapp.models import AbonGroup, Abon from django.conf import settings +from guardian.decorators import permission_required_or_403 as permission_required +from guardian.shortcuts import get_objects_for_user @login_required @only_admins def devices(request, grp): group = get_object_or_404(AbonGroup, pk=grp) - devs = Device.objects.filter(user_group=grp) + if not request.user.has_perm('abonapp.can_view_abongroup', group): + raise PermissionDenied + devs = Device.objects.filter(user_group=grp).only('comment', 'mac_addr', 'devtype', 'user_group', 'pk', + 'ip_address') # фильтр dr, field = order_helper(request) @@ -41,7 +46,7 @@ def devices(request, grp): @login_required @only_admins def devices_null_group(request): - devs = Device.objects.filter(user_group=None) + devs = Device.objects.filter(user_group=None).only('comment', 'devtype', 'user_group', 'pk', 'ip_address') # фильтр dr, field = order_helper(request) if field: @@ -71,10 +76,12 @@ def devdel(request, did): @login_required -@only_admins +@permission_required('devapp.can_view_device') def dev(request, grp, devid=0): - devinst = get_object_or_404(Device, id=devid) if devid != 0 else None user_group = get_object_or_404(AbonGroup, pk=grp) + if not request.user.has_perm('abonapp.can_view_abongroup', user_group): + raise PermissionDenied + devinst = get_object_or_404(Device, id=devid) if devid != 0 else None already_dev = None if request.method == 'POST': @@ -294,7 +301,7 @@ def add_single_port(request, grp, did): @login_required -@only_admins +@permission_required('devapp.can_view_device') def devview(request, did): ports = None uptime = 0 @@ -318,7 +325,7 @@ def devview(request, did): except DeviceDBException as e: messages.error(request, e) - return render(request, 'devapp/custom_dev_page/'+template_name, { + return render(request, 'devapp/custom_dev_page/' + template_name, { 'dev': dev, 'ports': ports, 'uptime': uptime, @@ -327,7 +334,7 @@ def devview(request, did): @login_required -@only_admins +@permission_required('devapp.can_toggle_ports') def toggle_port(request, did, portid, status=0): portid = int(portid) status = int(status) @@ -338,9 +345,9 @@ def toggle_port(request, did, portid, status=0): manager = dev.get_manager_klass()(dev.ip_address, dev.man_passw) ports = manager.get_ports() if status: - ports[portid-1].enable() + ports[portid - 1].enable() else: - ports[portid-1].disable() + ports[portid - 1].disable() else: messages.warning(request, _('Not Set snmp device password')) else: @@ -353,7 +360,8 @@ def toggle_port(request, did, portid, status=0): @login_required @only_admins def group_list(request): - groups = AbonGroup.objects.all() + groups = AbonGroup.objects.all().order_by('title') + groups = get_objects_for_user(request.user, 'abonapp.can_view_abongroup', klass=groups, accept_global_perms=False) return render(request, 'devapp/group_list.html', { 'groups': groups }) @@ -365,6 +373,8 @@ def search_dev(request): if word is None: results = [{'id': 0, 'text': ''}] else: - results = Device.objects.filter(Q(comment__icontains=word) | Q(ip_address=word))[:16] + results = Device.objects.filter( + Q(comment__icontains=word) | Q(ip_address=word) + ).only('pk', 'ip_address', 'comment')[:16] results = [{'id': dev.pk, 'text': "%s: %s" % (dev.ip_address, dev.comment)} for dev in results] return HttpResponse(dumps(results, ensure_ascii=False)) diff --git a/djing/settings_example.py b/djing/settings_example.py index db346b8..b43ae49 100644 --- a/djing/settings_example.py +++ b/djing/settings_example.py @@ -16,6 +16,11 @@ DEBUG = True ALLOWED_HOSTS = ['*'] +# required for django-guardian +AUTHENTICATION_BACKENDS = ( + 'django.contrib.auth.backends.ModelBackend', # default + 'guardian.backends.ObjectPermissionBackend' +) # Application definition @@ -38,7 +43,8 @@ INSTALLED_APPS = [ 'clientsideapp', 'chatbot', 'django_messages', - 'dialing_app' + 'dialing_app', + 'guardian' ] MIDDLEWARE_CLASSES = [ diff --git a/mapapp/views.py b/mapapp/views.py index afb60ad..acdf717 100644 --- a/mapapp/views.py +++ b/mapapp/views.py @@ -1,5 +1,5 @@ from django.contrib import messages -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import login_required from django.contrib.gis.shortcuts import render_to_text from django.core.exceptions import PermissionDenied from django.http import HttpResponse @@ -9,6 +9,7 @@ from .models import Dot from .forms import DotForm from mydefs import pag_mn from devapp.models import Device +from guardian.decorators import permission_required_or_403 as permission_required @login_required diff --git a/requirements.txt b/requirements.txt index 7d485d0..447c20d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,5 @@ mysqlclient easysnmp rq pid +django-guardian +jsonfield diff --git a/tariff_app/views.py b/tariff_app/views.py index 9b8cd0c..4c766f9 100644 --- a/tariff_app/views.py +++ b/tariff_app/views.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import login_required from django.contrib.gis.shortcuts import render_to_text from django.utils.translation import ugettext as _ from django.shortcuts import render, get_object_or_404, redirect from django.contrib import messages from django.core.exceptions import PermissionDenied +from guardian.decorators import permission_required_or_403 as permission_required from .models import Tariff import mydefs diff --git a/taskapp/views.py b/taskapp/views.py index d8ec471..7ba4159 100644 --- a/taskapp/views.py +++ b/taskapp/views.py @@ -1,11 +1,12 @@ # coding=utf-8 -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.shortcuts import render, redirect, get_object_or_404 from django.contrib import messages from abonapp.models import Abon from django.utils.translation import ugettext as _ from datetime import date +from guardian.decorators import permission_required_or_403 as permission_required from .handle import TaskException from .models import Task diff --git a/templates/all_base.html b/templates/all_base.html index 956692e..9c89b2d 100644 --- a/templates/all_base.html +++ b/templates/all_base.html @@ -47,7 +47,7 @@