From 8624ab3e10c0423b204be9c86a90d2d29e1aa820 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 7 Jan 2019 18:23:54 +0300 Subject: [PATCH 01/15] add task to abonapp --- abonapp/models.py | 45 +------------------------------- abonapp/tasks.py | 47 ++++++++++++++++++++++++++++++++++ abonapp/views.py | 31 ++++++++++++++-------- clientsideapp/views.py | 3 ++- gw_app/nas_managers/structs.py | 4 +-- 5 files changed, 72 insertions(+), 58 deletions(-) create mode 100644 abonapp/tasks.py diff --git a/abonapp/models.py b/abonapp/models.py index cdf3b86..9b4978f 100644 --- a/abonapp/models.py +++ b/abonapp/models.py @@ -7,7 +7,7 @@ from django.conf import settings from django.core import validators from django.core.validators import RegexValidator from django.db import models, connection, transaction -from django.db.models.signals import post_delete, pre_delete, post_init, \ +from django.db.models.signals import pre_delete, post_init, \ pre_save from django.dispatch import receiver from django.shortcuts import resolve_url @@ -348,24 +348,6 @@ class Abon(BaseAccount): except LogicError: pass - def nas_remove_self(self): - """ - Will remove this user to network access server - :return: - """ - if self.nas is None: - raise LogicError(_('gateway required')) - try: - agent_abon = self.build_agent_struct() - if agent_abon is not None: - mngr = self.nas.get_nas_manager() - mngr.remove_user(agent_abon) - except (NasFailedResult, NasNetworkError, ConnectionResetError) as e: - print('ERROR:', e) - return e - except LogicError: - pass - def get_absolute_url(self): return resolve_url('abonapp:abon_home', self.group.id, self.username) @@ -608,17 +590,6 @@ class PeriodicPayForId(models.Model): ordering = ('last_pay',) -@receiver(post_delete, sender=Abon) -def abon_del_signal(sender, **kwargs): - abon = kwargs.get("instance") - if abon is None: - raise ValueError('Instance does not passed to a signal') - try: - abon.nas_remove_self() - except (NasFailedResult, NasNetworkError, LogicError): - return True - - @receiver(post_init, sender=AbonTariff) def abon_tariff_post_init(sender, **kwargs): abon_tariff = kwargs["instance"] @@ -635,17 +606,3 @@ def abon_tariff_pre_save(sender, **kwargs): if getattr(abon_tariff, 'deadline') is None: calc_obj = abon_tariff.tariff.get_calc_type()(abon_tariff) abon_tariff.deadline = calc_obj.calc_deadline() - - -@receiver(pre_delete, sender=AbonTariff) -def abontariff_pre_delete(sender, **kwargs): - abon_tariff = kwargs.get("instance") - if abon_tariff is None: - raise ValueError('Instance does not passed to a signal') - try: - abon = Abon.objects.get(current_tariff=abon_tariff) - abon.nas_remove_self() - except (NasFailedResult, NasNetworkError, LogicError): - return True - except Abon.DoesNotExist: - print('Error: abontariff_pre_delete - user not found') diff --git a/abonapp/tasks.py b/abonapp/tasks.py new file mode 100644 index 0000000..22e8773 --- /dev/null +++ b/abonapp/tasks.py @@ -0,0 +1,47 @@ +from celery import shared_task + +from abonapp.models import Abon +from djing.lib import LogicError +from gw_app.models import NASModel +from gw_app.nas_managers import NasFailedResult, NasNetworkError, SubnetQueue + + +@shared_task +def customer_nas_command(customer_uid: int, command: str): + if command not in ('add', 'sync'): + return 'Command required' + try: + cust = Abon.objects.get(pk=customer_uid) + print(cust, command) + if command == 'sync': + r = cust.nas_sync_self() + if isinstance(r, Exception): + return 'ABONAPP SYNC ERROR: %s' % r + elif command == 'add': + cust.nas_add_self() + else: + return 'ABONAPP SYNC ERROR: Unknown command "%s"' % command + except Abon.DoesNotExist: + pass + except (LogicError, NasFailedResult, NasNetworkError, ConnectionResetError) as e: + return 'ABONAPP ERROR: %s' % e + + +@shared_task +def customer_nas_remove(customer_uid: int, ip_addr: str, speed: tuple, is_access: bool, nas_pk: int): + try: + if not isinstance(ip_addr, (str, int)): + ip_addr = str(ip_addr) + sq = SubnetQueue( + name="uid%d" % customer_uid, + network=ip_addr, + max_limit=speed, + is_access=is_access + ) + nas = NASModel.objects.get(pk=nas_pk) + mngr = nas.get_nas_manager() + mngr.remove_user(sq) + except (ValueError, NasFailedResult, NasNetworkError, LogicError) as e: + return 'ABONAPP ERROR: %s' % e + except NASModel.DoesNotExist: + return 'NASModel.DoesNotExist id=%d' % nas_pk diff --git a/abonapp/views.py b/abonapp/views.py index f68b4c5..f0075b2 100644 --- a/abonapp/views.py +++ b/abonapp/views.py @@ -1,6 +1,7 @@ from datetime import datetime from typing import Dict, Optional +from abonapp.tasks import customer_nas_command, customer_nas_remove from agent.commands.dhcp import dhcp_commit, dhcp_expiry, dhcp_release from devapp.models import Device, Port as DevPort from dialing_app.models import AsteriskCDR @@ -172,6 +173,13 @@ class DelAbonDeleteView(LoginAdminMixin, PermissionRequiredMixin, DeleteView): try: abon = self.get_object() gid = abon.group.id + if abon.current_tariff: + abon_tariff = abon.current_tariff.tariff + customer_nas_remove.delay( + customer_uid=abon.pk, ip_addr=abon.ip_address, + speed=(abon_tariff.speedIn, abon_tariff.speedOut), + is_access=abon.is_access(), nas_pk=abon.nas_id + ) abon.delete() request.user.log(request.META, 'dusr', ( '%(uname)s, "%(fio)s", %(group)s %(street)s %(house)s' % { @@ -336,9 +344,7 @@ class AbonHomeUpdateView(LoginAdminMixin, PermissionRequiredMixin, UpdateView): def form_valid(self, form): r = super(AbonHomeUpdateView, self).form_valid(form) abon = self.object - res = abon.nas_sync_self() - if isinstance(res, Exception): - messages.warning(self.request, res) + customer_nas_command.delay(abon.pk, 'sync') messages.success(self.request, _('edit abon success msg')) return r @@ -450,11 +456,8 @@ def pick_tariff(request, gid: int, uname): comment=log_comment) else: abon.pick_tariff(trf, request.user, comment=log_comment) - r = abon.nas_sync_self() - if r is None: - messages.success(request, _('Tariff has been picked')) - else: - messages.error(request, r) + customer_nas_command.delay(abon.pk, 'sync') + messages.success(request, _('Tariff has been picked')) return redirect('abonapp:abon_services', gid=gid, uname=abon.username) except (lib.LogicError, NasFailedResult) as e: @@ -489,6 +492,13 @@ def unsubscribe_service(request, gid: int, uname, abon_tariff_id: int): try: abon_tariff = get_object_or_404(models.AbonTariff, pk=int(abon_tariff_id)) + abon = abon_tariff.abon + trf = abon_tariff.tariff + customer_nas_remove.delay( + customer_uid=abon.pk, ip_addr=abon.ip_address, + speed=(trf.speedIn, trf.speedOut), + is_access=abon.is_access(), nas_pk=abon.nas_id + ) abon_tariff.delete() messages.success(request, _('User has been detached from service')) except NasFailedResult as e: @@ -610,9 +620,7 @@ class IpUpdateView(LoginAdminPermissionMixin, UpdateView): def form_valid(self, form): r = super(IpUpdateView, self).form_valid(form) abon = self.object - res = abon.nas_sync_self() - if isinstance(res, Exception): - messages.warning(self.request, res) + customer_nas_command.delay(abon.pk, 'sync') messages.success(self.request, _('Ip successfully updated')) return r @@ -1219,6 +1227,7 @@ def user_session_free(request, gid: int, uname): return redirect('abonapp:abon_home', gid, uname) if abon.ip_address: abon.free_ip_addr() + customer_nas_command.delay(abon.pk, 'remove') messages.success(request, _('Ip lease has been freed')) else: messages.error(request, _('User not have ip')) diff --git a/clientsideapp/views.py b/clientsideapp/views.py index 0a5c166..81a5ade 100644 --- a/clientsideapp/views.py +++ b/clientsideapp/views.py @@ -5,6 +5,7 @@ from django.db import transaction from django.utils.translation import gettext_lazy as _, gettext from abonapp.models import AbonLog, InvoiceForPayment, Abon +from abonapp.tasks import customer_nas_command from djing.lib.decorators import json_view from tariff_app.models import Tariff from taskapp.models import Task @@ -52,7 +53,7 @@ def buy_service(request, srv_id): if request.method == 'POST': abon.pick_tariff(service, None, _("Buy the service via user side, service '%s'") % service) - abon.nas_sync_self() + customer_nas_command.delay(abon.pk, 'sync') messages.success(request, _("The service '%s' wan successfully activated") % service.title) else: return render(request, 'clientsideapp/modal_service_buy.html', { diff --git a/gw_app/nas_managers/structs.py b/gw_app/nas_managers/structs.py index 7cd8230..d880808 100644 --- a/gw_app/nas_managers/structs.py +++ b/gw_app/nas_managers/structs.py @@ -23,7 +23,7 @@ class SubnetQueue(BaseStruct): return self._max_limit def set_max_limit(self, v): - if isinstance(v, tuple): + if isinstance(v, (tuple, list)): self._max_limit = v elif isinstance(v, str): s_in, s_out = v.split('/') @@ -32,7 +32,7 @@ class SubnetQueue(BaseStruct): sp = float(v) self._max_limit = sp, sp else: - raise ValueError('Unexpected format for max_limit') + raise ValueError('Unexpected format for max_limit %s' % v) max_limit = property(get_max_limit, set_max_limit) From c8a490b654d2bbe6180792b2d167b8a122a00104 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 9 Jan 2019 11:46:00 +0300 Subject: [PATCH 02/15] fix bug --- periodic.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/periodic.py b/periodic.py index c96d018..90e378e 100755 --- a/periodic.py +++ b/periodic.py @@ -7,8 +7,8 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings") django.setup() from django.utils import timezone from django.db import transaction -from django.db.models import signals, Count -from abonapp.models import Abon, AbonTariff, abontariff_pre_delete, PeriodicPayForId, AbonLog +from django.db.models import Count +from abonapp.models import Abon, AbonTariff, PeriodicPayForId, AbonLog from gw_app.nas_managers import NasNetworkError, NasFailedResult from gw_app.models import NASModel from djing.lib import LogicError @@ -34,7 +34,6 @@ class NasSyncThread(Thread): def main(): - signals.pre_delete.disconnect(abontariff_pre_delete, sender=AbonTariff) AbonTariff.objects.filter(abon=None).delete() now = timezone.now() fields = ('id', 'tariff__title', 'abon__id', 'abon__username') @@ -78,7 +77,7 @@ def main(): # make log about it l = AbonLog.objects.create( abon=abon, amount=-amount, - comment="Автоматическое продление услуги '%s'" % trf.title + comment="Автоматическое продление услуги '%s' для %s" % (trf.title, abon) ) print(l.comment) else: From de0bb5b9f2d8edf03e6828053b563c8854a6c0da Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 9 Jan 2019 12:14:08 +0300 Subject: [PATCH 03/15] float format for pay history --- abonapp/templates/abonapp/payHistory.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abonapp/templates/abonapp/payHistory.html b/abonapp/templates/abonapp/payHistory.html index ac0bc69..0099097 100644 --- a/abonapp/templates/abonapp/payHistory.html +++ b/abonapp/templates/abonapp/payHistory.html @@ -14,7 +14,7 @@ {% for ph in pay_history %} - {{ ph.amount }} + {{ ph.amount|floatformat:2 }} {{ ph.date|date:'d F Y, H:i:s' }} {% if ph.author %} From 2ffd970369f6791256a0b84f9d98c336dd8b45ad Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Thu, 10 Jan 2019 12:53:49 +0300 Subject: [PATCH 04/15] fix erro message --- accounts_app/views.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/accounts_app/views.py b/accounts_app/views.py index 27344e3..e4e3bb5 100644 --- a/accounts_app/views.py +++ b/accounts_app/views.py @@ -28,9 +28,8 @@ class CustomLoginView(LoginView): template_name = 'accounts/login.html' def form_invalid(self, form): - login_localed = gettext('profile username') - for msg in form.error_messages.values(): - messages.error(self.request, msg % {'username': login_localed}) + for msg in form.non_field_errors(): + messages.error(self.request, msg) return super().form_invalid(form) def get_success_url(self): From 2ac557b7068ba2b370f24ace4fba768e79f60d8f Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 14 Jan 2019 14:09:49 +0300 Subject: [PATCH 05/15] Fix bug --- gw_app/nas_managers/mod_mikrotik.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gw_app/nas_managers/mod_mikrotik.py b/gw_app/nas_managers/mod_mikrotik.py index d95a12e..f113df3 100644 --- a/gw_app/nas_managers/mod_mikrotik.py +++ b/gw_app/nas_managers/mod_mikrotik.py @@ -311,7 +311,8 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos, '=queue=Djing_pcq_up/Djing_pcq_down', '=burst-time=5/5', '=burst-limit=%.3fM/%.3fM' % tuple(i * 2 for i in queue.max_limit), - '=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit) + '=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit), + '=numbers=%s' % queue_gw.queue_id ] if queue.queue_id: cmd.insert(1, '=.id=%s' % queue.queue_id) From e79e795546d47ea0fcc829814d9c9171c189f306 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 14 Jan 2019 14:15:07 +0300 Subject: [PATCH 06/15] refactoring --- gw_app/nas_managers/mod_mikrotik.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gw_app/nas_managers/mod_mikrotik.py b/gw_app/nas_managers/mod_mikrotik.py index f113df3..acac62c 100644 --- a/gw_app/nas_managers/mod_mikrotik.py +++ b/gw_app/nas_managers/mod_mikrotik.py @@ -311,11 +311,10 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos, '=queue=Djing_pcq_up/Djing_pcq_down', '=burst-time=5/5', '=burst-limit=%.3fM/%.3fM' % tuple(i * 2 for i in queue.max_limit), - '=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit), - '=numbers=%s' % queue_gw.queue_id + '=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit) ] if queue.queue_id: - cmd.insert(1, '=.id=%s' % queue.queue_id) + cmd.insert(1, '=numbers=%s' % queue.queue_id) r = self._exec_cmd(cmd) return r From 1c46eb39edb327536081d4ac129c80ba50702f6d Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 14 Jan 2019 14:19:02 +0300 Subject: [PATCH 07/15] refactoring --- gw_app/nas_managers/mod_mikrotik.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gw_app/nas_managers/mod_mikrotik.py b/gw_app/nas_managers/mod_mikrotik.py index acac62c..7bd102c 100644 --- a/gw_app/nas_managers/mod_mikrotik.py +++ b/gw_app/nas_managers/mod_mikrotik.py @@ -301,7 +301,7 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos, if queue_gw is None: return self.add_queue(queue) else: - cmd = [ + cmd = ( '/queue/simple/set', '=name=%s' % queue.name, '=max-limit=%.3fM/%.3fM' % queue.max_limit, @@ -311,10 +311,9 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos, '=queue=Djing_pcq_up/Djing_pcq_down', '=burst-time=5/5', '=burst-limit=%.3fM/%.3fM' % tuple(i * 2 for i in queue.max_limit), - '=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit) - ] - if queue.queue_id: - cmd.insert(1, '=numbers=%s' % queue.queue_id) + '=burst-threshold=%.3fM/%.3fM' % tuple(i / 1.2 for i in queue.max_limit), + '=numbers=%s' % queue_gw.queue_id + ) r = self._exec_cmd(cmd) return r From efa00a9d3edb88ede0ccdf9fabdf663add86e8ef Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 21 Jan 2019 15:39:11 +0300 Subject: [PATCH 08/15] port list always shows, even if device is not available --- devapp/views.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/devapp/views.py b/devapp/views.py index 7f5c0d6..5e5310f 100644 --- a/devapp/views.py +++ b/devapp/views.py @@ -471,25 +471,27 @@ def devview(request, group_id: int, device_id: int): template_name = 'generic_switch.html' try: if device.ip_address: - if not ping(str(device.ip_address)): + if ping(str(device.ip_address)): + if device.man_passw: + manager = device.get_manager_object() + ports = tuple(manager.get_ports()) + if ports is not None and len(ports) > 0 and isinstance(ports[0], + Exception): + messages.error(request, ports[0]) + ports = ports[1] + template_name = manager.get_template_name() + else: + messages.warning(request, _('Not Set snmp device password')) + else: messages.error(request, _('Dot was not pinged')) - if device.man_passw: - manager = device.get_manager_object() - ports = tuple(manager.get_ports()) - if ports is not None and len(ports) > 0 and isinstance(ports[0], - Exception): - messages.error(request, ports[0]) - ports = ports[1] - template_name = manager.get_template_name() - else: - messages.warning(request, _('Not Set snmp device password')) return render(request, 'devapp/custom_dev_page/' + template_name, { 'dev': device, 'ports': ports, 'dev_accs': Abon.objects.filter(device=device), 'dev_manager': manager, 'ports_db': Port.objects.filter(device=device).annotate( - num_abons=Count('abon')), + num_abons=Count('abon') + ), }) except EasySNMPError as e: messages.error(request, From c58e7ab12b88f2dc98065d704e77d81709fc423a Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 21 Jan 2019 18:50:24 +0300 Subject: [PATCH 09/15] fix error typing --- djing/lib/decorators.py | 4 +++- gw_app/nas_managers/core.py | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/djing/lib/decorators.py b/djing/lib/decorators.py index cbdf61f..d903cd8 100644 --- a/djing/lib/decorators.py +++ b/djing/lib/decorators.py @@ -99,7 +99,9 @@ def json_view(fn): @wraps(fn) def wrapped(request, *args, **kwargs): r = fn(request, *args, **kwargs) - return JsonResponse(r, safe=False, json_dumps_params={ + if not isinstance(r['text'], str): + r['text'] = str(r['text']) + return JsonResponse(dict(r), safe=False, json_dumps_params={ 'ensure_ascii': False }) return wrapped diff --git a/gw_app/nas_managers/core.py b/gw_app/nas_managers/core.py index d50e9d2..9eb08f2 100644 --- a/gw_app/nas_managers/core.py +++ b/gw_app/nas_managers/core.py @@ -1,4 +1,4 @@ -from abc import ABC, abstractmethod, abstractproperty +from abc import ABC, abstractmethod from typing import Iterator, Tuple, Optional from djing import ping from gw_app.nas_managers.structs import SubnetQueue, VectorQueue @@ -16,7 +16,8 @@ class NasNetworkError(Exception): # Communicate with gw class BaseTransmitter(ABC): - @abstractproperty + @property + @abstractmethod def description(self): """ :return: Returnd a description of nas implementation From b59521e7f6c0a80681588b910c03931d5293342d Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Mon, 21 Jan 2019 20:20:34 +0300 Subject: [PATCH 10/15] fix bug --- djing/lib/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djing/lib/decorators.py b/djing/lib/decorators.py index d903cd8..587f099 100644 --- a/djing/lib/decorators.py +++ b/djing/lib/decorators.py @@ -99,7 +99,7 @@ def json_view(fn): @wraps(fn) def wrapped(request, *args, **kwargs): r = fn(request, *args, **kwargs) - if not isinstance(r['text'], str): + if 'text' in r.keys() and not isinstance(r['text'], str): r['text'] = str(r['text']) return JsonResponse(dict(r), safe=False, json_dumps_params={ 'ensure_ascii': False From f5778b359a322c95297462965a463ad966f9cad3 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Tue, 22 Jan 2019 12:40:08 +0300 Subject: [PATCH 11/15] fix device view --- devapp/views.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/devapp/views.py b/devapp/views.py index 5e5310f..4e7a45f 100644 --- a/devapp/views.py +++ b/devapp/views.py @@ -470,20 +470,19 @@ def devview(request, group_id: int, device_id: int): template_name = 'generic_switch.html' try: - if device.ip_address: - if ping(str(device.ip_address)): - if device.man_passw: - manager = device.get_manager_object() - ports = tuple(manager.get_ports()) - if ports is not None and len(ports) > 0 and isinstance(ports[0], - Exception): - messages.error(request, ports[0]) - ports = ports[1] - template_name = manager.get_template_name() - else: - messages.warning(request, _('Not Set snmp device password')) - else: - messages.error(request, _('Dot was not pinged')) + if device.ip_address and not ping(str(device.ip_address)): + messages.error(request, _('Dot was not pinged')) + if device.man_passw: + manager = device.get_manager_object() + ports = tuple(manager.get_ports()) + if ports is not None and len(ports) > 0 and isinstance(ports[0], + Exception): + messages.error(request, ports[0]) + ports = ports[1] + template_name = manager.get_template_name() + else: + messages.warning(request, _('Not Set snmp device password')) + return render(request, 'devapp/custom_dev_page/' + template_name, { 'dev': device, 'ports': ports, From 1f2f2bfa784d51b29687f37577a93686ac925d71 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Tue, 22 Jan 2019 15:03:55 +0300 Subject: [PATCH 12/15] fix --- djing/lib/decorators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/djing/lib/decorators.py b/djing/lib/decorators.py index 587f099..4e608fb 100644 --- a/djing/lib/decorators.py +++ b/djing/lib/decorators.py @@ -99,9 +99,9 @@ def json_view(fn): @wraps(fn) def wrapped(request, *args, **kwargs): r = fn(request, *args, **kwargs) - if 'text' in r.keys() and not isinstance(r['text'], str): + if r and 'text' in r.keys() and not isinstance(r['text'], str): r['text'] = str(r['text']) - return JsonResponse(dict(r), safe=False, json_dumps_params={ + return JsonResponse(dict(r or {'text': 'null'}), safe=False, json_dumps_params={ 'ensure_ascii': False }) return wrapped From a61c0c10692f5e36c2444c614616d037f380c6aa Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 23 Jan 2019 11:01:57 +0300 Subject: [PATCH 13/15] fix --- djing/lib/decorators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/djing/lib/decorators.py b/djing/lib/decorators.py index 4e608fb..8b2c8ff 100644 --- a/djing/lib/decorators.py +++ b/djing/lib/decorators.py @@ -99,9 +99,9 @@ def json_view(fn): @wraps(fn) def wrapped(request, *args, **kwargs): r = fn(request, *args, **kwargs) - if r and 'text' in r.keys() and not isinstance(r['text'], str): + if isinstance(r, dict) and not isinstance(r.get('text'), str): r['text'] = str(r['text']) - return JsonResponse(dict(r or {'text': 'null'}), safe=False, json_dumps_params={ + return JsonResponse(r, safe=False, json_dumps_params={ 'ensure_ascii': False }) return wrapped From 51cca66ff90094b45bb710d457a4e91c581fd997 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Wed, 23 Jan 2019 11:17:21 +0300 Subject: [PATCH 14/15] fix --- djing/lib/decorators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/djing/lib/decorators.py b/djing/lib/decorators.py index 8b2c8ff..0bd0b78 100644 --- a/djing/lib/decorators.py +++ b/djing/lib/decorators.py @@ -100,7 +100,7 @@ def json_view(fn): def wrapped(request, *args, **kwargs): r = fn(request, *args, **kwargs) if isinstance(r, dict) and not isinstance(r.get('text'), str): - r['text'] = str(r['text']) + r['text'] = str(r.get('text')) return JsonResponse(r, safe=False, json_dumps_params={ 'ensure_ascii': False }) From 8152f50ba2d79913e2584dfd647ee37894a9a661 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Tue, 29 Jan 2019 11:09:47 +0300 Subject: [PATCH 15/15] change django-jsonfield source --- requirements.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8ac946f..7e0b778 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,10 @@ pid django-guardian pinax-theme-bootstrap django-bootstrap3 -django-jsonfield + +# django-jsonfield +-e git://github.com/dmkoch/django-jsonfield.git#egg=django-jsonfield + requests webdavclient pyst2