diff --git a/abonapp/migrations/0001_initial.py b/abonapp/migrations/0001_initial.py
index 2877a67..e929df1 100644
--- a/abonapp/migrations/0001_initial.py
+++ b/abonapp/migrations/0001_initial.py
@@ -7,7 +7,7 @@ from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
-import mydefs
+from djing import lib
import re
@@ -30,7 +30,7 @@ class Migration(migrations.Migration):
models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
primary_key=True, serialize=False, to='accounts_app.BaseAccount')),
('ballance', models.FloatField(default=0.0)),
- ('ip_address', mydefs.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4')),
+ ('ip_address', lib.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4')),
('description', models.TextField(blank=True, null=True, verbose_name='Comment')),
('house', models.CharField(blank=True, max_length=12, null=True, verbose_name='House')),
('is_dynamic_ip', models.BooleanField(default=False)),
diff --git a/abonapp/models.py b/abonapp/models.py
index 6cf8e74..650f226 100644
--- a/abonapp/models.py
+++ b/abonapp/models.py
@@ -14,7 +14,7 @@ from django.utils.translation import ugettext_lazy as _, gettext
from accounts_app.models import UserProfile, MyUserManager, BaseAccount
from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNetworkError
from group_app.models import Group
-from mydefs import MyGenericIPAddressField, ip2int, LogicError
+from djing.lib import ip2int, MyGenericIPAddressField, LogicError
from djing import IP_ADDR_REGEX
from tariff_app.models import Tariff, PeriodicPay
from bitfield import BitField
diff --git a/abonapp/pay_systems.py b/abonapp/pay_systems.py
index 90b025d..6fe737e 100644
--- a/abonapp/pay_systems.py
+++ b/abonapp/pay_systems.py
@@ -1,6 +1,6 @@
from hashlib import md5
from django.utils import timezone
-from mydefs import safe_int, safe_float
+from djing.lib import safe_int, safe_float
from .models import Abon, AllTimePayLog
from django.db import DatabaseError
from django.conf import settings
diff --git a/abonapp/views.py b/abonapp/views.py
index 5139d2a..5a36b85 100644
--- a/abonapp/views.py
+++ b/abonapp/views.py
@@ -20,7 +20,6 @@ from tariff_app.models import Tariff
from agent import NasFailedResult, Transmitter, NasNetworkError
from . import forms
from . import models
-import mydefs
from devapp.models import Device, Port as DevPort
from datetime import datetime, date, timedelta
from taskapp.models import Task
@@ -30,6 +29,7 @@ from group_app.models import Group
from guardian.shortcuts import get_objects_for_user, assign_perm
from guardian.decorators import permission_required_or_403 as permission_required
from djing import ping
+from djing import lib
from djing.global_base_views import OrderingMixin, BaseListWithFiltering, SecureApiView
PAGINATION_ITEMS_PER_PAGE = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
@@ -40,14 +40,14 @@ class BaseAbonListView(OrderingMixin, BaseListWithFiltering):
http_method_names = ('get',)
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
class PeoplesListView(BaseAbonListView):
context_object_name = 'peoples'
template_name = 'abonapp/peoples.html'
def get_queryset(self):
- street_id = mydefs.safe_int(self.request.GET.get('street'))
- gid = mydefs.safe_int(self.kwargs.get('gid'))
+ street_id = lib.safe_int(self.request.GET.get('street'))
+ gid = lib.safe_int(self.kwargs.get('gid'))
peoples_list = models.Abon.objects.all().select_related('group', 'street', 'current_tariff')
if street_id > 0:
peoples_list = peoples_list.filter(group__pk=gid, street=street_id)
@@ -61,7 +61,7 @@ class PeoplesListView(BaseAbonListView):
abon.stat_cache = StatCache.objects.get(ip=abon.ip_address)
except StatCache.DoesNotExist:
pass
- except mydefs.LogicError as e:
+ except lib.LogicError as e:
messages.warning(self.request, e)
ordering = self.get_ordering()
if ordering and isinstance(ordering, str):
@@ -70,7 +70,7 @@ class PeoplesListView(BaseAbonListView):
return peoples_list
def get_context_data(self, **kwargs):
- gid = mydefs.safe_int(self.kwargs.get('gid'))
+ gid = lib.safe_int(self.kwargs.get('gid'))
if gid < 1:
return HttpResponseBadRequest('group id is broken')
group = get_object_or_404(Group, pk=gid)
@@ -80,12 +80,12 @@ class PeoplesListView(BaseAbonListView):
context = super(PeoplesListView, self).get_context_data(**kwargs)
context['streets'] = models.AbonStreet.objects.filter(group=gid)
- context['street_id'] = mydefs.safe_int(self.request.GET.get('street'))
+ context['street_id'] = lib.safe_int(self.request.GET.get('street'))
context['group'] = group
return context
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
class GroupListView(BaseAbonListView):
context_object_name = 'groups'
template_name = 'abonapp/group_list.html'
@@ -98,7 +98,7 @@ class GroupListView(BaseAbonListView):
return queryset
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
@method_decorator(permission_required('abonapp.add_abon'), name='dispatch')
class AbonCreateView(CreateView):
group = None
@@ -142,9 +142,9 @@ class AbonCreateView(CreateView):
messages.success(self.request, _('create abon success msg'))
self.abon = abon
return super(AbonCreateView, self).form_valid(form)
- except (IntegrityError, NasFailedResult, NasNetworkError, mydefs.LogicError) as e:
+ except (IntegrityError, NasFailedResult, NasNetworkError, lib.LogicError) as e:
messages.error(self.request, e)
- except mydefs.MultipleException as errs:
+ except lib.MultipleException as errs:
for err in errs.err_list:
messages.error(self.request, err)
return self.render_to_response(self.get_context_data(form=form))
@@ -154,7 +154,7 @@ class AbonCreateView(CreateView):
return super(AbonCreateView, self).form_invalid(form)
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
@method_decorator(permission_required('abonapp.delete_abon'), name='dispatch')
class DelAbonDeleteView(DeleteView):
model = models.Abon
@@ -181,7 +181,7 @@ class DelAbonDeleteView(DeleteView):
messages.error(self.request, e)
except NasFailedResult as e:
messages.error(self.request, _("NAS says: '%s'") % e)
- except mydefs.MultipleException as errs:
+ except lib.MultipleException as errs:
for err in errs.err_list:
messages.error(self.request, err)
return HttpResponseRedirect(self.success_url)
@@ -196,7 +196,7 @@ def abonamount(request, gid, uname):
if request.method == 'POST':
abonuname = request.POST.get('abonuname')
if abonuname == uname:
- amnt = mydefs.safe_float(request.POST.get('amount'))
+ amnt = lib.safe_float(request.POST.get('amount'))
abon.add_ballance(request.user, amnt, comment=_('fill account through admin side'))
abon.save(update_fields=('ballance',))
messages.success(request, _('Account filled successfully on %.2f') % amnt)
@@ -205,7 +205,7 @@ def abonamount(request, gid, uname):
messages.error(request, _('I not know the account id'))
except (NasNetworkError, NasFailedResult) as e:
messages.error(request, e)
- except mydefs.MultipleException as errs:
+ except lib.MultipleException as errs:
for err in errs.err_list:
messages.error(request, err)
return render_to_text('abonapp/modal_abonamount.html', {
@@ -214,7 +214,7 @@ def abonamount(request, gid, uname):
}, request=request)
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
class DebtsListView(BaseAbonListView):
context_object_name = 'invoices'
@@ -232,7 +232,7 @@ class DebtsListView(BaseAbonListView):
return context
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
class PayHistoryListView(BaseAbonListView):
context_object_name = 'pay_history'
@@ -252,7 +252,7 @@ class PayHistoryListView(BaseAbonListView):
@login_required
-@mydefs.only_admins
+@lib.only_admins
def abon_services(request, gid, uname):
grp = get_object_or_404(Group, pk=gid)
if not request.user.has_perm('group_app.can_view_group', grp):
@@ -277,7 +277,7 @@ def abon_services(request, gid, uname):
})
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
@method_decorator(permission_required('abonapp.change_abon'), name='post')
class AbonHomeUpdateView(UpdateView):
model = models.Abon
@@ -291,11 +291,11 @@ class AbonHomeUpdateView(UpdateView):
def dispatch(self, request, *args, **kwargs):
try:
return super(AbonHomeUpdateView, self).dispatch(request, *args, **kwargs)
- except mydefs.LogicError as e:
+ except lib.LogicError as e:
messages.error(request, e)
except (NasFailedResult, NasNetworkError) as e:
messages.error(request, e)
- except mydefs.MultipleException as errs:
+ except lib.MultipleException as errs:
for err in errs.err_list:
messages.error(request, err)
return self.render_to_response(self.get_context_data())
@@ -342,11 +342,11 @@ class AbonHomeUpdateView(UpdateView):
def get_context_data(self, **kwargs):
abon = self.object
- dev = getattr(abon, 'device')
+ device = getattr(abon, 'device')
context = {
'group': self.group,
- 'device': dev,
- 'dev_ports': DevPort.objects.filter(device=dev) if dev else None
+ 'device': device,
+ 'dev_ports': DevPort.objects.filter(device=device) if device else None
}
context.update(kwargs)
return super(AbonHomeUpdateView, self).get_context_data(**context)
@@ -354,9 +354,9 @@ class AbonHomeUpdateView(UpdateView):
def get_success_url(self):
abon = self.object
return resolve_url('abonapp:abon_home',
- gid=getattr(abon.group, 'pk', 0),
- uname=abon.username
- )
+ gid=getattr(abon.group, 'pk', 0),
+ uname=abon.username
+ )
@transaction.atomic
@@ -377,7 +377,7 @@ def add_invoice(request, gid, uname):
try:
if request.method == 'POST':
- curr_amount = mydefs.safe_int(request.POST.get('curr_amount'))
+ curr_amount = lib.safe_int(request.POST.get('curr_amount'))
comment = request.POST.get('comment')
newinv = models.InvoiceForPayment()
@@ -395,7 +395,7 @@ def add_invoice(request, gid, uname):
except (NasNetworkError, NasFailedResult) as e:
messages.error(request, e)
- except mydefs.MultipleException as errs:
+ except lib.MultipleException as errs:
for err in errs.err_list:
messages.error(request, err)
return render(request, 'abonapp/addInvoice.html', {
@@ -406,7 +406,7 @@ def add_invoice(request, gid, uname):
@login_required
-@mydefs.only_admins
+@lib.only_admins
@permission_required('abonapp.can_buy_tariff')
@transaction.atomic
def pick_tariff(request, gid, uname):
@@ -429,14 +429,14 @@ def pick_tariff(request, gid, uname):
abon.sync_with_nas(created=False)
messages.success(request, _('Tariff has been picked'))
return redirect('abonapp:abon_services', gid=gid, uname=abon.username)
- except (mydefs.LogicError, NasFailedResult) as e:
+ except (lib.LogicError, NasFailedResult) as e:
messages.error(request, e)
except NasNetworkError as e:
messages.error(request, e)
return redirect('abonapp:abon_services', gid=gid, uname=abon.username)
except Tariff.DoesNotExist:
messages.error(request, _('Tariff your picked does not exist'))
- except mydefs.MultipleException as errs:
+ except lib.MultipleException as errs:
for err in errs.err_list:
messages.error(request, err)
except ValueError as e:
@@ -446,7 +446,7 @@ def pick_tariff(request, gid, uname):
'tariffs': tariffs,
'abon': abon,
'group': grp,
- 'selected_tariff': mydefs.safe_int(request.GET.get('selected_tariff'))
+ 'selected_tariff': lib.safe_int(request.GET.get('selected_tariff'))
})
@@ -463,7 +463,7 @@ def unsubscribe_service(request, gid, uname, abon_tariff_id):
messages.error(request, e)
except NasNetworkError as e:
messages.warning(request, e)
- except mydefs.MultipleException as errs:
+ except lib.MultipleException as errs:
for err in errs.err_list:
messages.error(request, err)
return redirect('abonapp:abon_services', gid=gid, uname=uname)
@@ -550,7 +550,7 @@ class PassportUpdateView(UpdateView):
@login_required
-@mydefs.only_admins
+@lib.only_admins
def chgroup_tariff(request, gid):
grp = get_object_or_404(Group, pk=gid)
if not request.user.has_perm('group_app.change_group', grp):
@@ -578,8 +578,7 @@ def dev(request, gid, uname):
try:
abon = models.Abon.objects.get(username=uname)
if request.method == 'POST':
- dev = Device.objects.get(pk=request.POST.get('dev'))
- abon.device = dev
+ abon.device = Device.objects.get(pk=request.POST.get('dev'))
abon.save(update_fields=('device',))
messages.success(request, _('Device has successfully attached'))
return redirect('abonapp:abon_home', gid=gid, uname=uname)
@@ -683,7 +682,7 @@ def make_extra_field(request, gid, uname):
except (NasNetworkError, NasFailedResult) as e:
messages.error(request, e)
frm = forms.ExtraFieldForm()
- except mydefs.MultipleException as errs:
+ except lib.MultipleException as errs:
for err in errs.err_list:
messages.error(request, err)
frm = forms.ExtraFieldForm()
@@ -731,7 +730,7 @@ def abon_ping(request):
text = ' %s' % _('no ping')
try:
if ip is None:
- raise mydefs.LogicError(_('Ip not passed'))
+ raise lib.LogicError(_('Ip not passed'))
tm = Transmitter()
ping_result = tm.ping(ip)
if ping_result is None:
@@ -756,7 +755,7 @@ def abon_ping(request):
text = ' %s' % _('ping ok') + ' ' + str(ping_result)
status = True
- except (NasFailedResult, mydefs.LogicError) as e:
+ except (NasFailedResult, lib.LogicError) as e:
messages.error(request, e)
except NasNetworkError as e:
messages.warning(request, e)
@@ -767,7 +766,7 @@ def abon_ping(request):
}
-@method_decorator((login_required, mydefs.only_admins,), name='dispatch')
+@method_decorator((login_required, lib.only_admins,), name='dispatch')
class DialsListView(BaseAbonListView):
context_object_name = 'logs'
template_name = 'abonapp/dial_log.html'
@@ -813,7 +812,7 @@ def save_user_dev_port(request, gid, uname):
if request.method != 'POST':
messages.error(request, _('Method is not POST'))
return redirect('abonapp:abon_home', gid, uname)
- user_port = mydefs.safe_int(request.POST.get('user_port'))
+ user_port = lib.safe_int(request.POST.get('user_port'))
is_dynamic_ip = request.POST.get('is_dynamic_ip')
is_dynamic_ip = True if is_dynamic_ip == 'on' else False
try:
@@ -948,7 +947,7 @@ def tel_add(request, gid, uname):
@permission_required('abnapp.delete_additionaltelephone')
def tel_del(request, gid, uname):
try:
- tid = mydefs.safe_int(request.GET.get('tid'))
+ tid = lib.safe_int(request.GET.get('tid'))
tel = models.AdditionalTelephone.objects.get(pk=tid)
tel.delete()
messages.success(request, _('Additional telephone successfully deleted'))
@@ -964,17 +963,17 @@ def phonebook(request, gid):
t1 = models.Abon.objects.filter(group__id=int(gid)).only('telephone', 'fio').values_list('telephone', 'fio')
t2 = models.AdditionalTelephone.objects.filter(abon__group__id=gid).only('telephone', 'owner_name').values_list(
'telephone', 'owner_name')
- tels = list(t1) + list(t2)
+ telephones = tuple(t1) + tuple(t2)
if res_format == 'csv':
import csv
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="phones.csv"'
writer = csv.writer(response, quoting=csv.QUOTE_NONNUMERIC)
- for row in tels:
+ for row in telephones:
writer.writerow(row)
return response
return render_to_text('abonapp/modal_phonebook.html', {
- 'tels': tels,
+ 'tels': telephones,
'gid': gid
}, request=request)
@@ -1029,7 +1028,7 @@ def reset_ip(request, gid, uname):
@login_required
-@mydefs.only_admins
+@lib.only_admins
def fin_report(request):
q = models.AllTimePayLog.objects.by_days()
res_format = request.GET.get('f')
@@ -1089,7 +1088,7 @@ def del_periodic_pay(request, gid, uname, periodic_pay_id):
return redirect('abonapp:abon_services', gid, uname)
-@method_decorator((login_required, mydefs.only_admins,), name='dispatch')
+@method_decorator((login_required, lib.only_admins,), name='dispatch')
class EditSibscriberMarkers(UpdateView):
http_method_names = ('get', 'post')
template_name = 'abonapp/modal_user_markers.html'
@@ -1120,7 +1119,7 @@ class EditSibscriberMarkers(UpdateView):
# API's
@login_required
-@mydefs.only_admins
+@lib.only_admins
@json_view
def abons(request):
ablist = ({
@@ -1145,7 +1144,7 @@ def abons(request):
@login_required
-@mydefs.only_admins
+@lib.only_admins
@json_view
def search_abon(request):
word = request.GET.get('s')
@@ -1172,15 +1171,14 @@ class DhcpLever(SecureApiView):
@staticmethod
def on_dhcp_event(data: Dict) -> Optional[str]:
- '''
+ """
data = {
'client_ip': ip2int('127.0.0.1'),
'client_mac': 'aa:bb:cc:dd:ee:ff',
'switch_mac': 'aa:bb:cc:dd:ee:ff',
'switch_port': 3,
'cmd': 'commit'
- }
- '''
+ }"""
r = None
try:
action = data['cmd']
@@ -1193,7 +1191,7 @@ class DhcpLever(SecureApiView):
r = dhcp_expiry(data['client_ip'])
elif action == 'release':
r = dhcp_release(data['client_ip'])
- except mydefs.LogicError as e:
+ except lib.LogicError as e:
print('LogicError', e)
r = str(e)
return r
diff --git a/accounts_app/views.py b/accounts_app/views.py
index d0bc04f..6cdd24e 100644
--- a/accounts_app/views.py
+++ b/accounts_app/views.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate, login, logout
from django.core.exceptions import PermissionDenied
@@ -15,7 +14,7 @@ from group_app.models import Group
from .models import UserProfile
from .forms import AvatarChangeForm
-import mydefs
+from djing import lib
from guardian.decorators import permission_required_or_403 as permission_required
from guardian.shortcuts import get_objects_for_user, assign_perm, remove_perm
@@ -62,9 +61,9 @@ class SignOut(RedirectView):
@login_required
-@mydefs.only_admins
+@lib.only_admins
def profile_show(request, uid=0):
- uid = mydefs.safe_int(uid)
+ uid = lib.safe_int(uid)
if uid == 0:
return redirect('acc_app:other_profile', uid=request.user.id)
@@ -87,7 +86,7 @@ def profile_show(request, uid=0):
})
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
class AvatarUpdateView(UpdateView):
form_class = AvatarChangeForm
template_name = 'accounts/settings/ch_info.html'
@@ -100,7 +99,7 @@ class AvatarUpdateView(UpdateView):
@login_required
-@mydefs.only_admins
+@lib.only_admins
def ch_info(request):
if request.method == 'POST':
user = request.user
@@ -169,7 +168,7 @@ def create_profile(request):
@login_required
-@mydefs.only_admins
+@lib.only_admins
def delete_profile(request, uid):
prf = get_object_or_404(UserProfile, id=uid)
if uid != request.user.id:
@@ -180,7 +179,7 @@ def delete_profile(request, uid):
return redirect('acc_app:accounts_list')
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
class AccountsListView(BaseAccListView):
template_name = 'accounts/acc_list.html'
context_object_name = 'users'
@@ -288,7 +287,7 @@ def set_abon_groups_permission(request, uid):
})
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
class ManageResponsibilityGroups(ListView):
http_method_names = ('get', 'post')
template_name = 'accounts/manage_responsibility_groups.html'
diff --git a/agent/mod_mikrotik.py b/agent/mod_mikrotik.py
index 03adb24..3f246ce 100644
--- a/agent/mod_mikrotik.py
+++ b/agent/mod_mikrotik.py
@@ -6,7 +6,7 @@ from abc import ABCMeta
from hashlib import md5
from typing import Iterable, Optional, Tuple
from .core import BaseTransmitter, NasFailedResult, NasNetworkError
-from mydefs import singleton
+from djing.lib import singleton
from .structs import TariffStruct, AbonStruct, IpStruct, VectorAbon, VectorTariff
from . import settings as local_settings
from django.conf import settings
diff --git a/agent/structs.py b/agent/structs.py
index 13f85b2..39c7bac 100644
--- a/agent/structs.py
+++ b/agent/structs.py
@@ -1,18 +1,18 @@
# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
from struct import pack, unpack, calcsize
-from typing import Iterable
-from .utils import int2ip, ip2int
+from typing import Iterable, Optional
+from djing.lib import int2ip, ip2int
class BaseStruct(object, metaclass=ABCMeta):
@abstractmethod
- def serialize(self):
- """привращаем инфу в бинарную строку"""
+ def serialize(self) -> Optional[bytes]:
+ """make binary"""
@abstractmethod
- def deserialize(self, data, *args):
- """создаём объект из бинарной строки"""
+ def deserialize(self, data: bytes, *args):
+ """restore from binary"""
def __ne__(self, other):
return not self == other
@@ -25,11 +25,11 @@ class IpStruct(BaseStruct):
else:
self.__ip = ip2int(str(ip))
- def serialize(self):
+ def serialize(self) -> Optional[bytes]:
dt = pack("!I", int(self.__ip))
return dt
- def deserialize(self, data, *args):
+ def deserialize(self, data: bytes, *args):
dt = unpack("!I", data)
self.__ip = int(dt[0])
return self
@@ -54,12 +54,12 @@ class IpStruct(BaseStruct):
# Как обслуживается абонент
class TariffStruct(BaseStruct):
- def __init__(self, tariff_id=0, speedIn=None, speedOut=None):
+ def __init__(self, tariff_id=0, speed_in=None, speed_out=None):
self.tid = int(tariff_id)
- self.speedIn = float(speedIn if speedIn is not None else 0.001)
- self.speedOut = float(speedOut if speedOut is not None else 0.001)
+ self.speedIn = speed_in or 0
+ self.speedOut = speed_out or 0
- def serialize(self):
+ def serialize(self) -> Optional[bytes]:
dt = pack("!Iff", int(self.tid), float(self.speedIn), float(self.speedOut))
return dt
@@ -67,7 +67,7 @@ class TariffStruct(BaseStruct):
def is_empty(self):
return self.tid == 0 and self.speedIn == 0.001 and self.speedOut == 0.001
- def deserialize(self, data, *args):
+ def deserialize(self, data: bytes, *args):
dt = unpack("!Iff", data)
self.tid = int(dt[0])
self.speedIn = float(dt[1])
@@ -96,7 +96,7 @@ class AbonStruct(BaseStruct):
self.tariff = tariff
self.is_active = is_active
- def serialize(self):
+ def serialize(self) -> Optional[bytes]:
if self.tariff is None:
return
if not isinstance(self.tariff, TariffStruct):
@@ -106,7 +106,7 @@ class AbonStruct(BaseStruct):
dt = pack("!LII?", self.uid, int(self.ip), self.tariff.tid, self.is_active)
return dt
- def deserialize(self, data, tariff=None):
+ def deserialize(self, data: bytes, tariff=None):
dt = unpack("!LII?", data)
self.uid = dt[0]
self.ip = IpStruct(dt[1])
@@ -137,12 +137,12 @@ class ShapeItem(BaseStruct):
self.abon = abon
self.sid = sid
- def serialize(self):
+ def serialize(self) -> Optional[bytes]:
abon_pack = self.abon.serialize()
dt = pack('!L', self.sid)
return dt + abon_pack
- def deserialize(self, data, *args):
+ def deserialize(self, data: bytes, *args):
sz = calcsize('!L')
dt = unpack('!L', data[:sz])
self.sid = dt
diff --git a/clientsideapp/views.py b/clientsideapp/views.py
index f95b796..68f9cfe 100644
--- a/clientsideapp/views.py
+++ b/clientsideapp/views.py
@@ -8,7 +8,7 @@ from django.utils.translation import gettext_lazy as _, gettext
from abonapp.models import AbonLog, InvoiceForPayment, Abon
from tariff_app.models import Tariff
from taskapp.models import Task
-from mydefs import LogicError
+from djing.lib import LogicError
from agent import NasFailedResult, NasNetworkError
diff --git a/devapp/migrations/0001_initial.py b/devapp/migrations/0001_initial.py
index fa24063..9103f5f 100644
--- a/devapp/migrations/0001_initial.py
+++ b/devapp/migrations/0001_initial.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djing.fields
-import mydefs
+from djing.lib import MyGenericIPAddressField
class Migration(migrations.Migration):
@@ -21,7 +21,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
(
- 'ip_address', mydefs.MyGenericIPAddressField(max_length=8, protocol='ipv4', verbose_name='Ip address')),
+ 'ip_address', MyGenericIPAddressField(max_length=8, protocol='ipv4', verbose_name='Ip address')),
('mac_addr', djing.fields.MACAddressField(blank=True, integer=True, null=True, unique=True,
verbose_name='Mac address')),
('comment', models.CharField(max_length=256, verbose_name='Comment')),
diff --git a/devapp/migrations/0002_auto_20180409_1318.py b/devapp/migrations/0002_auto_20180409_1318.py
index ea0fad0..891cd0c 100644
--- a/devapp/migrations/0002_auto_20180409_1318.py
+++ b/devapp/migrations/0002_auto_20180409_1318.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
from django.db import migrations
-import mydefs
+from djing.lib import MyGenericIPAddressField
class Migration(migrations.Migration):
@@ -20,7 +20,7 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='device',
name='ip_address',
- field=mydefs.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4',
+ field=MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4',
verbose_name='Ip address'),
),
]
diff --git a/dialing_app/views.py b/dialing_app/views.py
index ce5c203..0108d26 100644
--- a/dialing_app/views.py
+++ b/dialing_app/views.py
@@ -16,7 +16,7 @@ from jsonview.decorators import json_view
from abonapp.models import Abon
from djing.global_base_views import SecureApiView
from djing import JSONType
-from mydefs import only_admins, safe_int
+from djing.lib import only_admins, safe_int
from .models import AsteriskCDR, SMSModel, SMSOut
from .forms import SMSOutForm
diff --git a/djing/lib/__init__.py b/djing/lib/__init__.py
new file mode 100644
index 0000000..948f5d5
--- /dev/null
+++ b/djing/lib/__init__.py
@@ -0,0 +1,186 @@
+import socket
+import struct
+from datetime import timedelta
+from collections import Iterator
+from functools import wraps
+from json import dumps
+from django.http import HttpResponse, Http404, HttpResponseRedirect
+from django.shortcuts import redirect
+from django.db import models
+from django.conf import settings
+
+DEBUG = getattr(settings, 'DEBUG', False)
+
+
+def ip2int(addr):
+ try:
+ return struct.unpack("!I", socket.inet_aton(addr))[0]
+ except:
+ return 0
+
+
+def int2ip(addr):
+ try:
+ return socket.inet_ntoa(struct.pack("!I", addr))
+ except:
+ return ''
+
+
+def safe_float(fl):
+ try:
+ return 0.0 if fl is None or fl == '' else float(fl)
+ except ValueError:
+ return 0.0
+
+
+def safe_int(i):
+ try:
+ return 0 if i is None or i == '' else int(i)
+ except ValueError:
+ return 0
+
+
+def res_success(request, redirect_to='/'):
+ if request.is_ajax():
+ return HttpResponse(dumps({'errnum': 0}))
+ else:
+ return redirect(redirect_to)
+
+
+def res_error(request, text):
+ if request.is_ajax():
+ return HttpResponse(dumps({'errnum': 1, 'errtext': text}))
+ else:
+ raise Http404(text)
+
+
+class MyGenericIPAddressField(models.GenericIPAddressField):
+ description = "Int32 notation ip address"
+
+ def __init__(self, protocol='ipv4', *args, **kwargs):
+ super(MyGenericIPAddressField, self).__init__(protocol=protocol, *args, **kwargs)
+ self.max_length = 8
+
+ def get_prep_value(self, value):
+ # strIp to Int
+ value = super(MyGenericIPAddressField, self).get_prep_value(value)
+ return ip2int(value)
+
+ def to_python(self, value):
+ return value
+
+ def get_internal_type(self):
+ return 'PositiveIntegerField'
+
+ @staticmethod
+ def from_db_value(value, expression, connection, context):
+ return int2ip(value) if value != 0 else None
+
+ def int_ip(self):
+ return ip2int(self)
+
+
+# Предназначен для Django CHOICES чтоб можно было передавать классы вместо просто описания поля,
+# классы передавать для того чтоб по значению кода из базы понять какой класс нужно взять для нужной функциональности.
+# Например по коду в базе вам нужно определять как считать тариф абонента, что реализовано в возвращаемом классе.
+class MyChoicesAdapter(Iterator):
+ chs = tuple()
+ current_index = 0
+ _max_index = 0
+
+ # На вход принимает кортеж кортежей, вложенный из 2х элементов: кода и класса, как: TARIFF_CHOICES
+ def __init__(self, choices):
+ self._max_index = len(choices)
+ self.chs = choices
+
+ def __next__(self):
+ if self.current_index >= self._max_index:
+ raise StopIteration
+ else:
+ e = self.chs
+ ci = self.current_index
+ res = e[ci][0], e[ci][1].description()
+ self.current_index += 1
+ return res
+
+
+# Allow to view only admins
+def only_admins(fn):
+ @wraps(fn)
+ def wrapped(request, *args, **kwargs):
+ if request.user.is_admin:
+ return fn(request, *args, **kwargs)
+ else:
+ return redirect('client_side:home')
+
+ return wrapped
+
+
+# Russian localized timedelta
+class RuTimedelta(timedelta):
+ def __new__(cls, tm):
+ if isinstance(tm, timedelta):
+ return timedelta.__new__(
+ cls,
+ days=tm.days,
+ seconds=tm.seconds,
+ microseconds=tm.microseconds
+ )
+
+ def __str__(self):
+ # hours, remainder = divmod(self.seconds, 3600)
+ # minutes, seconds = divmod(remainder, 60)
+ # text_date = "%d:%d" % (
+ # hours,
+ # minutes
+ # )
+ if self.days > 1:
+ ru_days = 'дней'
+ if 5 > self.days > 1:
+ ru_days = 'дня'
+ elif self.days == 1:
+ ru_days = 'день'
+ # text_date = '%d %s %s' % (self.days, ru_days, text_date)
+ text_date = '%d %s' % (self.days, ru_days)
+ else:
+ text_date = ''
+ return text_date
+
+
+def require_ssl(view):
+ """
+ Decorator that requires an SSL connection. If the current connection is not SSL, we redirect to the SSL version of
+ the page.
+ from: https://gist.github.com/ckinsey/9709984
+ """
+
+ @wraps(view)
+ def wrapper(request, *args, **kwargs):
+ if not DEBUG and not request.is_secure():
+ target_url = "https://" + request.META['HTTP_HOST'] + request.path_info
+ return HttpResponseRedirect(target_url)
+ return view(request, *args, **kwargs)
+
+ return wrapper
+
+
+class MultipleException(Exception):
+ def __init__(self, err_list):
+ if not isinstance(err_list, (list, tuple)):
+ raise TypeError
+ self.err_list = err_list
+
+
+class LogicError(Exception):
+ pass
+
+
+def singleton(class_):
+ instances = {}
+
+ def getinstance(*args, **kwargs):
+ if class_ not in instances:
+ instances[class_] = class_(*args, **kwargs)
+ return instances[class_]
+
+ return getinstance
diff --git a/djing/settings.py b/djing/settings.py
index 4b38677..d73a627 100644
--- a/djing/settings.py
+++ b/djing/settings.py
@@ -25,7 +25,7 @@ ALLOWED_HOSTS = local_settings.ALLOWED_HOSTS
# required for django-guardian
AUTHENTICATION_BACKENDS = (
- 'djing.auth_backends.CustomAuthBackend',
+ 'djing.lib.auth_backends.CustomAuthBackend',
# 'django.contrib.auth.backends.ModelBackend', # default
'guardian.backends.ObjectPermissionBackend'
)
diff --git a/docs/dev.md b/docs/dev.md
index 09d00e4..ce2fff9 100644
--- a/docs/dev.md
+++ b/docs/dev.md
@@ -343,7 +343,7 @@ def check_news(request):
return HttpResponse(dumps(r))
```
-Убедитесь что вашему представлению не будет доступа от абонентов, об этом позаботится декоратор *only_admins* из *mydefs*. *mydefs* лежит в корне проекта.
+Убедитесь что вашему представлению не будет доступа от абонентов, об этом позаботится декоратор *only_admins* из *djing.lib*.
После получения сообщения надо вернуть словарь с параметрами:
diff --git a/mapapp/views.py b/mapapp/views.py
index f996f42..1b61c28 100644
--- a/mapapp/views.py
+++ b/mapapp/views.py
@@ -14,7 +14,7 @@ from jsonview.decorators import json_view
from group_app.models import Group
from .models import Dot
from .forms import DotForm
-from mydefs import safe_int
+from djing.lib import safe_int
from devapp.models import Device
from guardian.decorators import permission_required
diff --git a/periodic.py b/periodic.py
index 6d7b4cc..0657bb5 100755
--- a/periodic.py
+++ b/periodic.py
@@ -9,7 +9,7 @@ from django.db import transaction
from django.db.models import signals
from abonapp.models import Abon, AbonTariff, abontariff_pre_delete, PeriodicPayForId, AbonLog
from agent import Transmitter, NasNetworkError, NasFailedResult
-from mydefs import LogicError
+from djing.lib import LogicError
def main():
diff --git a/statistics/migrations/0001_initial.py b/statistics/migrations/0001_initial.py
index bd83354..4148c97 100644
--- a/statistics/migrations/0001_initial.py
+++ b/statistics/migrations/0001_initial.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
from django.db import migrations, models
-import mydefs
+from djing.lib import MyGenericIPAddressField
import statistics.fields
@@ -18,8 +18,7 @@ class Migration(migrations.Migration):
name='StatCache',
fields=[
('last_time', statistics.fields.UnixDateTimeField()),
- (
- 'ip', mydefs.MyGenericIPAddressField(max_length=8, primary_key=True, protocol='ipv4', serialize=False)),
+ ('ip', MyGenericIPAddressField(max_length=8, primary_key=True, protocol='ipv4', serialize=False)),
('octets', models.PositiveIntegerField(default=0)),
('packets', models.PositiveIntegerField(default=0)),
],
diff --git a/statistics/models.py b/statistics/models.py
index c5bc191..13ff2b4 100644
--- a/statistics/models.py
+++ b/statistics/models.py
@@ -3,7 +3,7 @@ from datetime import datetime, timedelta, date, time
from django.db import models, connection, ProgrammingError
from django.utils.timezone import now
-from mydefs import MyGenericIPAddressField
+from djing.lib import MyGenericIPAddressField
from .fields import UnixDateTimeField
diff --git a/tariff_app/base_intr.py b/tariff_app/base_intr.py
index cd2f8aa..970dbe9 100644
--- a/tariff_app/base_intr.py
+++ b/tariff_app/base_intr.py
@@ -17,7 +17,7 @@ class TariffBase(metaclass=ABCMeta):
@staticmethod
def description() -> AnyStr:
"""
- Usage in mydefs.MyChoicesAdapter for choices fields.
+ Usage in djing.lib.MyChoicesAdapter for choices fields.
:return: human readable description
"""
raise NotImplementedError
@@ -54,5 +54,5 @@ class PeriodicPayCalcBase(metaclass=ABCMeta):
@staticmethod
def description() -> AnyStr:
"""Return text description.
- Uses in mydefs.MyChoicesAdapter for CHOICES fields"""
+ Uses in djing.lib.MyChoicesAdapter for CHOICES fields"""
raise NotImplementedError
diff --git a/tariff_app/models.py b/tariff_app/models.py
index 3cb82cb..6ca5e04 100644
--- a/tariff_app/models.py
+++ b/tariff_app/models.py
@@ -5,7 +5,7 @@ from django.dispatch import receiver
from .base_intr import TariffBase, PeriodicPayCalcBase
from .custom_tariffs import TARIFF_CHOICES, PERIODIC_PAY_CHOICES
from group_app.models import Group
-from mydefs import MyChoicesAdapter
+from djing.lib import MyChoicesAdapter
from jsonfield import JSONField
diff --git a/tariff_app/views.py b/tariff_app/views.py
index 9dbdaaa..1f0d7d9 100644
--- a/tariff_app/views.py
+++ b/tariff_app/views.py
@@ -12,7 +12,7 @@ from guardian.decorators import permission_required_or_403 as permission_require
from djing.global_base_views import OrderingMixin
from .models import Tariff, PeriodicPay
-import mydefs
+from djing import lib
from . import forms
@@ -21,7 +21,7 @@ class BaseServiceListView(ListView):
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
-@method_decorator((login_required, mydefs.only_admins), name='dispatch')
+@method_decorator((login_required, lib.only_admins), name='dispatch')
class TariffsListView(BaseServiceListView, OrderingMixin):
"""
Show Services(Tariffs) list
@@ -33,7 +33,7 @@ class TariffsListView(BaseServiceListView, OrderingMixin):
@login_required
def edit_tarif(request, tarif_id=0):
- tarif_id = mydefs.safe_int(tarif_id)
+ tarif_id = lib.safe_int(tarif_id)
if tarif_id == 0:
if not request.user.has_perm('tariff_app.add_tariff'):
@@ -70,7 +70,7 @@ def del_tarif(request, tid):
messages.success(request, _('Service has been deleted'))
else:
messages.error(request, _('Not have a confirmations of delete'))
- return mydefs.res_success(request, 'tarifs:home')
+ return lib.res_success(request, 'tarifs:home')
return render_to_text('tariff_app/modal_del_warning.html', {'tid': tid}, request=request)
diff --git a/taskapp/handle.py b/taskapp/handle.py
index c973dc3..cabcdfc 100644
--- a/taskapp/handle.py
+++ b/taskapp/handle.py
@@ -2,7 +2,7 @@
from django.utils.translation import gettext as _
from chatbot.telebot import send_notify
from chatbot.models import ChatException
-from mydefs import MultipleException
+from djing.lib import MultipleException
class TaskException(Exception):
diff --git a/taskapp/migrations/0001_initial.py b/taskapp/migrations/0001_initial.py
index 06da89c..fe69535 100644
--- a/taskapp/migrations/0001_initial.py
+++ b/taskapp/migrations/0001_initial.py
@@ -51,7 +51,7 @@ class Migration(migrations.Migration):
('priority',
models.CharField(choices=[('A', 'Higher'), ('C', 'Average'), ('E', 'Low')], default='E', max_length=1,
verbose_name='A priority')),
- ('out_date', models.DateField(blank=True, default=taskapp.models._delta_add_days, null=True,
+ ('out_date', models.DateField(blank=True, default=taskapp.models.delta_add_days, null=True,
verbose_name='Reality')),
('time_of_create', models.DateTimeField(auto_now_add=True, verbose_name='Date of create')),
('state', models.CharField(choices=[('S', 'New'), ('C', 'Confused'), ('F', 'Completed')], default='S',
diff --git a/taskapp/views.py b/taskapp/views.py
index 949e521..b0624a8 100644
--- a/taskapp/views.py
+++ b/taskapp/views.py
@@ -1,5 +1,3 @@
-# coding=utf-8
-from json import dumps
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
@@ -15,12 +13,14 @@ from datetime import datetime
from django.views.generic.edit import FormMixin, DeleteView, UpdateView
from guardian.decorators import permission_required_or_403 as permission_required
+from jsonview.decorators import json_view
+
from chatbot.models import MessageQueue
from abonapp.models import Abon
from djing import httpresponse_to_referrer
+from djing.lib import only_admins, safe_int, MultipleException, RuTimedelta
from .handle import TaskException
from .models import Task, ExtraComment
-from mydefs import only_admins, safe_int, MultipleException, RuTimedelta
from .forms import TaskFrm, ExtraCommentForm
@@ -249,6 +249,7 @@ def remind(request, task_id):
return redirect('taskapp:home')
+@json_view
def check_news(request):
if request.user.is_authenticated and request.user.is_admin:
msg = MessageQueue.objects.pop(user=request.user, tag='taskap')