Browse Source

Merge branch 'master' into konica_tv

devel
Dmitry Novikov 5 years ago
parent
commit
9b3b0701d1
  1. 4
      abonapp/locale/ru/LC_MESSAGES/django.po
  2. 4
      abonapp/templates/abonapp/editAbon.html
  3. 4
      abonapp/views.py
  4. 1
      accounts_app/forms.py
  5. 2
      agent/netflow/netflow_collect.sh
  6. 6
      clientsideapp/views.py
  7. 33
      devapp/dev_types.py
  8. 2
      devapp/locale/ru/LC_MESSAGES/django.po
  9. 4
      devapp/templates/devapp/custom_dev_page/onu.html
  10. 4
      devapp/templates/devapp/custom_dev_page/onu_for_zte.html
  11. 2
      devapp/templates/devapp/devices.html
  12. 2
      devapp/views.py
  13. 2
      djing/__init__.py
  14. 10
      djing/settings.py
  15. 3
      djing/urls.py
  16. 0
      docsapp/__init__.py
  17. 5
      docsapp/apps.py
  18. 8
      docsapp/forms.py
  19. 71
      docsapp/locale/ru/LC_MESSAGES/django.po
  20. 27
      docsapp/migrations/0001_initial.py
  21. 0
      docsapp/migrations/__init__.py
  22. 24
      docsapp/models.py
  23. 14
      docsapp/templates/docsapp/documenttemplatemodel_confirm_delete.html
  24. 39
      docsapp/templates/docsapp/documenttemplatemodel_form.html
  25. 77
      docsapp/templates/docsapp/documenttemplatemodel_list.html
  26. 26
      docsapp/templates/docsapp/simple_list.html
  27. 14
      docsapp/urls.py
  28. 101
      docsapp/views.py
  29. 2
      gw_app/nas_managers/mod_mikrotik.py
  30. 85
      migrate2v2_dump.py
  31. 2
      periodic.py
  32. 33
      requirements.txt
  33. 1
      systemd_units/djing.timer
  34. 1
      systemd_units/djing_backup.timer
  35. 7
      systemd_units/webdav_backup.py
  36. 8
      tariff_app/custom_tariffs.py
  37. 6
      templates/base.html
  38. 2
      templates/custom_pages/footer.htm
  39. 2
      templates/custom_pages/main_page.htm
  40. 4
      templates/custom_pages/service.htm
  41. 2
      templates/custom_pages/service_bottom.htm

4
abonapp/locale/ru/LC_MESSAGES/django.po

@ -1133,3 +1133,7 @@ msgstr "Выберите шлюз для абонента"
msgid "Are you sure you want to free ip user session?"
msgstr "Вы уверены что хотите удалить ip абонента?"
msgid "Document list"
msgstr "Документы"

4
abonapp/templates/abonapp/editAbon.html

@ -99,6 +99,10 @@
<span>{% trans 'Remove subscriber' %}</span>
</a>
{% endif %}
<a href="{% url 'docsapp:simple_list' abon.username %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-print"></span> {% trans 'Document list' %}
</a>
</div>
</div>

4
abonapp/views.py

@ -776,7 +776,7 @@ def abon_ping(request, gid: int, uname):
@json_view
def set_auto_continue_service(request, gid: int, uname):
checked = request.GET.get('checked')
checked = True if checked == 'true' else False
checked = checked == 'true'
abon = get_object_or_404(models.Abon, username=uname)
abon.autoconnect_service = checked
abon.save(update_fields=('autoconnect_service',))
@ -845,7 +845,7 @@ def save_user_dev_port(request, gid: int, uname):
return redirect('abonapp:abon_home', gid, uname)
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
is_dynamic_ip = is_dynamic_ip == 'on'
try:
abon = models.Abon.objects.get(username=uname)
if user_port == 0:

1
accounts_app/forms.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from guardian.forms import UserObjectPermissionsForm
from guardian.shortcuts import assign_perm, remove_perm
from django import forms

2
agent/netflow/netflow_collect.sh

@ -15,7 +15,7 @@ spec.loader.exec_module(ls)
db = ls.DATABASES
ldb = db.get('default')
print('%s %s %s %s %d' % (ldb['NAME'], ldb['USER'],
ldb['PASSWORD'], ldb['HOST'], ldb['PORT']))"`
ldb['PASSWORD'], ldb['HOST'], ldb.get('PORT', 3306)))"`
if ! ping -c 1 ${mysql_host} &> /dev/null; then
echo "Host ${mysql_host} is not accessible"

6
clientsideapp/views.py

@ -17,7 +17,7 @@ from gw_app.nas_managers import NasFailedResult, NasNetworkError
@login_required
def home(request):
num_active_tasks = Task.objects.filter(
abon=request.user, state='S'
abon=request.user, state=0
).count()
return render(request, 'clientsideapp/index.html', {
'num_active_tasks': num_active_tasks
@ -38,7 +38,7 @@ def services(request):
abon = request.user
all_tarifs = Tariff.objects.get_tariffs_by_group(
abon.group.pk
)# .filter(is_admin=False)
).filter(is_admin=False)
current_service = abon.active_tariff()
except Abon.DoesNotExist:
all_tarifs = None
@ -140,7 +140,7 @@ def task_history(request):
@json_view
def set_auto_continue_service(request):
checked = request.GET.get('checked')
checked = True if checked == 'true' else False
checked = checked == 'true'
abon = request.user
abon.autoconnect_service = checked
abon.save(update_fields=('autoconnect_service',))

33
devapp/dev_types.py

@ -113,7 +113,7 @@ class DLinkDevice(DevBase, SNMPBaseWorker):
uptimes = self.get_list('.1.3.6.1.2.1.2.2.1.9')
try:
for num in ints:
status = True if int(next(stats)) == 1 else False
status = int(next(stats)) == 1
yield DLinkPort(
num=num,
name=next(nams),
@ -187,7 +187,7 @@ class OLTDevice(DevBase, SNMPBaseWorker):
onu = ONUdev(
num=n,
name=self.get_item('.1.3.6.1.2.1.2.2.1.2.%d' % n),
status=True if status == '3' else False,
status=status == '3',
mac=self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.3.%d' % n),
speed=0,
signal=signal / 10 if signal else '',
@ -268,7 +268,7 @@ class OnuDevice(DevBase, SNMPBaseWorker):
distance = self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.27.%d' % num)
mac = self.get_item('.1.3.6.1.4.1.3320.101.10.1.1.3.%d' % num)
if mac is not None:
mac = ':'.join('%x' % ord(i) for i in mac)
mac = ':'.join('%x' % i for i in mac)
# uptime = self.get_item('.1.3.6.1.2.1.2.2.1.9.%d' % num)
if status is not None and status.isdigit():
return {
@ -276,7 +276,7 @@ class OnuDevice(DevBase, SNMPBaseWorker):
'signal': signal / 10 if signal else '',
'name': self.get_item('.1.3.6.1.2.1.2.2.1.2.%d' % num),
'mac': mac,
'distance': int(distance) / 10 if distance.isdigit() else 0
'distance': distance / 10 if distance else 0
}
except EasySNMPTimeoutError as e:
return {'err': "%s: %s" % (_('ONU not connected'), e)}
@ -391,27 +391,6 @@ class Olt_ZTE_C320(OLTDevice):
} for fiber_name, fiber_id in self.get_list_keyval('.1.3.6.1.4.1.3902.1012.3.13.1.1.1'))
return fibers
def get_ports_on_fiber(self, fiber_num: int) -> Iterable:
onu_types = self.get_list_keyval('.1.3.6.1.4.1.3902.1012.3.28.1.1.1.%d' % fiber_num)
onu_ports = self.get_list('.1.3.6.1.4.1.3902.1012.3.28.1.1.2.%d' % fiber_num)
onu_signals = safe_int(self.get_list('.1.3.6.1.4.1.3902.1012.3.50.12.1.1.10.%d' % fiber_num))
# Real sn in last 3 octets
onu_sns = self.get_list('.1.3.6.1.4.1.3902.1012.3.28.1.1.5.%d' % fiber_num)
onu_prefixs = self.get_list('.1.3.6.1.4.1.3902.1012.3.50.11.2.1.1.%d' % fiber_num)
onu_list = ({
'onu_type': onu_type_num[0],
'onu_port': onu_port,
'onu_signal': conv_zte_signal(onu_signal),
'onu_sn': onu_prefix + ''.join('%.2X' % ord(i) for i in onu_sn[-4:]), # Real sn in last 4 octets,
'snmp_extra': "%d.%d" % (fiber_num, safe_int(onu_type_num[1])),
} for onu_type_num, onu_port, onu_signal, onu_sn, onu_prefix in zip(
onu_types, onu_ports, onu_signals, onu_sns, onu_prefixs
))
return onu_list
def get_units_unregistered(self, fiber_num: int) -> Iterable:
sn_num_list = self.get_list_keyval('.1.3.6.1.4.1.3902.1012.3.13.3.1.2.%d' % fiber_num)
firmware_ver = self.get_list('.1.3.6.1.4.1.3902.1012.3.13.3.1.11.%d' % fiber_num)
@ -596,9 +575,9 @@ class HuaweiSwitch(EltexSwitch):
n = int(n)
speed = self.get_item('.1.3.6.1.2.1.2.2.1.5.%d' % n)
oper_status = safe_int(self.get_item('.1.3.6.1.2.1.2.2.1.7.%d' % n))
oper_status = True if oper_status == 1 else False
oper_status = oper_status == 1
link_status = safe_int(self.get_item('.1.3.6.1.2.1.2.2.1.8.%d' % n))
link_status = True if link_status == 1 else False
link_status = link_status == 1
ep = EltexPort(
self,
num=i+1,

2
devapp/locale/ru/LC_MESSAGES/django.po

@ -484,7 +484,7 @@ msgid "Are you sure you want to delete device?"
msgstr "Вы уверены что хотите удалить устройство?"
#: templates/devapp/devices.html:83 templates/devapp/devices_null_group.html:65
msgid "Devices does not found"
msgid "Devices not found"
msgstr "Нет созданных устройств"
#: templates/devapp/devices.html:83 templates/devapp/devices.html:93

4
devapp/templates/devapp/custom_dev_page/onu.html

@ -59,9 +59,9 @@
{% else %}
<div class="media">
<div class="media-left font-extra-large">
{% if onu_details.status == '3' %}
{% if onu_details.status == 3 %}
<span class="media-object glyphicon glyphicon-ok-sign text-success"></span>
{% elif onu_details.status == '2' %}
{% elif onu_details.status == 2 %}
<span class="media-object glyphicon glyphicon-remove-sign text-danger"></span>
{% else %}
<span class="media-object glyphicon glyphicon-question-sign"></span>

4
devapp/templates/devapp/custom_dev_page/onu_for_zte.html

@ -60,9 +60,9 @@
{% else %}
<div class="media">
<div class="media-left font-extra-large">
{% if onu_details.status == '1' %}
{% if onu_details.status == 1 %}
<span class="media-object glyphicon glyphicon-ok-sign text-success"></span>
{% elif onu_details.status == '2' %}
{% elif onu_details.status == 2 %}
<span class="media-object glyphicon glyphicon-remove-sign text-danger"></span>
{% else %}
<span class="media-object glyphicon glyphicon-question-sign"></span>

2
devapp/templates/devapp/devices.html

@ -82,7 +82,7 @@
</tr>
{% empty %}
<tr>
<td colspan="6">{% trans 'Devices does not found' %}. <a href="{% url 'devapp:add' group.pk %}">{% trans 'Create' %}</a></td>
<td colspan="6">{% trans 'Devices not found' %}. <a href="{% url 'devapp:add' group.pk %}">{% trans 'Create' %}</a></td>
</tr>
{% endfor %}
{% endwith %}

2
devapp/views.py

@ -681,7 +681,7 @@ def fix_onu(request):
})
for srcmac, snmpnum in ports:
# convert bytes mac address to str presentation mac address
real_mac = ':'.join('%x' % ord(i) for i in srcmac)
real_mac = ':'.join('%x' % i for i in srcmac)
if mac == real_mac:
onu.snmp_extra = str(snmpnum)
onu.save(update_fields=('snmp_extra',))

2
djing/__init__.py

@ -57,7 +57,7 @@ default_app_config = 'abonapp.apps.AbonappConfig'
def ping(ip_addr: str, count=1):
if re.match(IP_ADDR_REGEX, ip_addr):
response = os.system("`which ping` -4Anq -c%d -W1 %s > /dev/null" % (count, ip_addr))
return True if response == 0 else False
return response == 0
else:
return False

10
djing/settings.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*
import os
try:
@ -43,6 +42,10 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'encrypted_model_fields',
'django_cleanup.apps.CleanupConfig',
'guardian',
'pinax_theme_bootstrap',
'bootstrapform',
'bootstrap3',
'ip_pool',
'accounts_app',
'gw_app',
@ -59,10 +62,7 @@ INSTALLED_APPS = [
'msg_app',
'group_app',
'new_customers',
'guardian',
'pinax_theme_bootstrap',
'bootstrapform',
'bootstrap3'
'docsapp'
]
if DEBUG:

3
djing/urls.py

@ -20,7 +20,8 @@ urlpatterns = [
path('messenger/', include('messenger.urls', namespace='messenger')),
path('gw/', include('gw_app.urls', namespace='gw_app')),
path('new_customers/', include('new_customers.urls', namespace='new_customers')),
path('fin/', include('finapp.urls', namespace='finapp'))
path('fin/', include('finapp.urls', namespace='finapp')),
path('docs/', include('docsapp.urls', namespace='docsapp'))
# Switch language
#path(r'i18n/', include('django.conf.urls.i18n')),

0
docsapp/__init__.py

5
docsapp/apps.py

@ -0,0 +1,5 @@
from django.apps import AppConfig
class DocsappConfig(AppConfig):
name = 'docsapp'

8
docsapp/forms.py

@ -0,0 +1,8 @@
from django import forms
from docsapp.models import DocumentTemplateModel
class DocumentTemplateModelForm(forms.ModelForm):
class Meta:
model = DocumentTemplateModel
fields = '__all__'

71
docsapp/locale/ru/LC_MESSAGES/django.po

@ -0,0 +1,71 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Dmitry Novikov nerosketch@gmail.com, 2019.
#
#, fuzzy
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-09-12 13:57+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: models.py:8 templates/docsapp/documenttemplatemodel_list.html:25
msgid "Title"
msgstr "Название"
#: models.py:10
msgid "File docx template"
msgstr "Файл шаблон docx"
#: templates/docsapp/documenttemplatemodel_confirm_delete.html:9
msgid "Remove document"
msgstr "Удалить документ"
#: templates/docsapp/documenttemplatemodel_confirm_delete.html:13
msgid "Are you sure you want to delete this document?"
msgstr "Вы уверены что хотите удалить документ?"
#: templates/docsapp/documenttemplatemodel_form.html:19
msgid "Change document"
msgstr "Изменить документ"
#: templates/docsapp/documenttemplatemodel_form.html:21
#: templates/docsapp/documenttemplatemodel_list.html:58
#: templates/docsapp/documenttemplatemodel_list.html:69
msgid "Add document"
msgstr "Добавить документ"
#: templates/docsapp/documenttemplatemodel_form.html:30
msgid "Save"
msgstr "Сохранить"
#: templates/docsapp/documenttemplatemodel_form.html:34
msgid "Back"
msgstr "Назад"
#: templates/docsapp/documenttemplatemodel_list.html:5
#: templates/docsapp/documenttemplatemodel_list.html:11
#: templates/docsapp/documenttemplatemodel_list.html:16
msgid "Documents"
msgstr "Документы"
#: templates/docsapp/documenttemplatemodel_list.html:26
msgid "File"
msgstr "Файл"
#: templates/docsapp/documenttemplatemodel_list.html:27
msgid "Document type"
msgstr "Тип документа"
#: templates/docsapp/documenttemplatemodel_list.html:57
msgid "Documents not found"
msgstr "Документы не найдены"

27
docsapp/migrations/0001_initial.py

@ -0,0 +1,27 @@
# Generated by Django 2.2.4 on 2019-09-12 12:52
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='DocumentTemplateModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=80, verbose_name='Title', unique=True)),
('doc_template', models.FileField(upload_to='word_docs', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=('docx',))], verbose_name='File docx template')),
],
options={
'db_table': 'documents',
'ordering': ('title',),
},
),
]

0
docsapp/migrations/__init__.py

24
docsapp/models.py

@ -0,0 +1,24 @@
from django.shortcuts import resolve_url
from django.utils.translation import gettext_lazy as _
from django.core.validators import FileExtensionValidator
from django.db import models
from abonapp.models import Abon
class DocumentTemplateModel(models.Model):
title = models.CharField(_('Title'), max_length=80, unique=True)
doc_template = models.FileField(
_('File docx template'), upload_to='word_docs',
validators=[FileExtensionValidator(allowed_extensions=('docx',))]
)
def get_absolute_url(self):
return resolve_url('docsapp:doc_edit', pk=self.pk)
def __str__(self):
return self.title
class Meta:
db_table = 'documents'
ordering = ('title',)

14
docsapp/templates/docsapp/documenttemplatemodel_confirm_delete.html

@ -0,0 +1,14 @@
{% extends 'base_delete_modal.html' %}
{% load i18n %}
{% block modal_form_url %}
{% url 'docsapp:doc_del' object.pk %}
{% endblock %}
{% block modal_form_title %}
{% trans 'Remove document' %}
{% endblock %}
{% block modal_form_text %}
<h4>{% trans 'Are you sure you want to delete this document?' %}</h4>
{% endblock %}

39
docsapp/templates/docsapp/documenttemplatemodel_form.html

@ -0,0 +1,39 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% load i18n bootstrap3 %}
{% block main %}
{% if object %}
{% url 'docsapp:doc_edit' object.pk as objurl %}
{% else %}
{% url 'docsapp:doc_add' as objurl %}
{% endif %}
<form action="{{ objurl }}" method="post" enctype="multipart/form-data">{% csrf_token %}
<div class="modal-header primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">
<span class="glyphicon glyphicon-exclamation-sign"></span>
{% if object %}
{% trans 'Change document' %}
{% else %}
{% trans 'Add document' %}
{% endif %}
</h4>
</div>
<div class="modal-body">
{% bootstrap_form form %}
<div class="btn-group btn-group-sm">
{% bootstrap_button _('Save') button_type="submit" button_class="btn-primary" icon="save" %}
{% if not request.is_ajax %}
{% url 'docsapp:docs_list' as backurl %}
{% bootstrap_button _('Back') button_type="link" href=backurl icon="fast-backward" %}
{% endif %}
</div>
</div>
</form>
{% endblock %}

77
docsapp/templates/docsapp/documenttemplatemodel_list.html

@ -0,0 +1,77 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% load i18n %}
{% block title %}
{% trans 'Documents' %}
{% endblock %}
{% block breadcrumb %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li class="active">{% trans 'Documents' %}</li>
</ol>
{% endblock %}
{% block page-header %}
{% trans 'Documents' %}
{% endblock %}
{% block main %}
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>.</th>
<th class="col-md-2">{% trans 'Title' %}</th>
<th class="col-md-4">{% trans 'File' %}</th>
<th class="col-md-3">{% trans 'Document type' %}</th>
<th>#</th>
</tr>
</thead>
<tbody>
{% with can_del_doc=perms.docsapp.delete_documenttemplatemodel can_ch_doc=perms.docsapp.change_documenttemplatemodel %}
{% for doc in object_list %}
<tr>
<td>{{ doc.id }}</td>
<td>{{ doc.title }}</td>
<td>{{ doc.doc_template }}</td>
<td>DocX</td>
<td class="btn-group btn-group-xs btn-group-justified">
{% if can_del_doc %}
<a href="{% url 'docsapp:doc_del' doc.pk %}" class="btn btn-danger btn-modal">
<span class="glyphicon glyphicon-remove"></span>
</a>
{% endif %}
{% if can_ch_doc %}
<a href="{% url 'docsapp:doc_edit' doc.id %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-edit"></span>
</a>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="6">
{% trans 'Documents not found' %}.
<a href="{% url 'docsapp:doc_add' %}" class="btn-modal">{% trans 'Add document' %}</a>
</td>
</tr>
{% endfor %}
{% endwith %}
</tbody>
<tfoot>
<tr>
<td colspan="6">
<a href="{% url 'docsapp:doc_add' %}" class="btn btn-success btn-sm btn-modal">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add document' %}
</a>
</td>
</tr>
</tfoot>
</table>
</div>
{% endblock %}

26
docsapp/templates/docsapp/simple_list.html

@ -0,0 +1,26 @@
{% load i18n %}
<div class="modal-header primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">{% trans 'Documents' %}</h4>
</div>
<div class="modal-body">
<div class="panel panel-default">
<div class="panel-body">
<ul class="list-group">
{% for obj in object_list %}
<li class="list-group-item">
<b>{{ obj.title }}</b>
<a href="{% url 'docsapp:doc_render' obj.pk account_name %}" class="btn btn-default">
<span class="glyphicon glyphicon-print"></span> {% trans 'Render document' %}
</a>
</li>
{% empty %}
{% trans 'Documents not found' %}
{% endfor %}
</ul>
</div>
</div>
</div>

14
docsapp/urls.py

@ -0,0 +1,14 @@
from django.urls import path
from docsapp import views
app_name = 'docsapp'
urlpatterns = [
path('', views.DocumentsListView.as_view(), name='docs_list'),
path('add/', views.DocumentCreateView.as_view(), name='doc_add'),
path('<int:pk>/', views.DocumentUpdateView.as_view(), name='doc_edit'),
path('<int:pk>/del/', views.DocumentDeleteView.as_view(), name='doc_del'),
path('<int:pk>/<slug:uname>/render/', views.RenderDocument.as_view(), name='doc_render'),
path('<slug:account_name>/simple_list/', views.SimpleListView.as_view(), name='simple_list'),
]

101
docsapp/views.py

@ -0,0 +1,101 @@
from io import BytesIO
from django.contrib import messages
from django.utils.datetime_safe import datetime
from django.utils.translation import gettext_lazy as _
from django.views.generic import UpdateView, DeleteView, CreateView, DetailView, ListView
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ValidationError
from django.http import HttpResponse
from django.shortcuts import redirect, get_object_or_404
from django.urls import reverse_lazy
from docxtpl import DocxTemplate
from docx.opc.constants import CONTENT_TYPE
from jinja2.exceptions import UndefinedError, TemplateSyntaxError
from abonapp.models import Abon
from djing.global_base_views import OrderedFilteredList
from djing.lib.mixins import LoginAdminMixin, LoginAdminPermissionMixin
from docsapp.models import DocumentTemplateModel
from docsapp.forms import DocumentTemplateModelForm
class DocumentsListView(LoginAdminMixin, OrderedFilteredList):
model = DocumentTemplateModel
class SimpleListView(LoginAdminMixin, ListView):
template_name = 'docsapp/simple_list.html'
model = DocumentTemplateModel
def get_context_data(self, **kwargs):
kwargs.update({
'account_name': self.kwargs.get('account_name')
})
return super().get_context_data(**kwargs)
class DocumentUpdateView(LoginAdminPermissionMixin, UpdateView):
permission_required = 'docsapp.change_documenttemplatemodel'
model = DocumentTemplateModel
form_class = DocumentTemplateModelForm
class DocumentDeleteView(LoginAdminPermissionMixin, DeleteView):
permission_required = 'docsapp.delete_documenttemplatemodel'
model = DocumentTemplateModel
success_url = reverse_lazy('docsapp:docs_list')
class DocumentCreateView(LoginAdminMixin, PermissionRequiredMixin, CreateView):
model = DocumentTemplateModel
form_class = DocumentTemplateModelForm
permission_required = 'docsapp.add_documenttemplatemodel'
class RenderDocument(LoginAdminPermissionMixin, DetailView):
model = DocumentTemplateModel
permission_required = 'docsapp.view_documenttemplatemodel'
context_object_name = 'document'
extra_context = {
'date': datetime.now()
}
def get(self, request, *args, **kwargs):
obj = self.get_object()
self.object = obj
acc = get_object_or_404(Abon, username=self.kwargs.get('uname'))
try:
doc = DocxTemplate(
obj.doc_template.path
)
context = self.get_context_data(object=obj)
context.update(self.get_context_account(acc))
doc.render(context)
destination_document_file = BytesIO()
doc.get_docx().save(destination_document_file)
resp = HttpResponse(
destination_document_file.getvalue(),
content_type=CONTENT_TYPE.WML_DOCUMENT
)
resp['Content-Disposition'] = 'attachment; filename="document.docx"'
return resp
except (UndefinedError, ValidationError, TemplateSyntaxError) as e:
messages.error(request, str(e))
return redirect('docsapp:docs_list')
def get_context_account(self, account):
if not isinstance(account, Abon):
raise ValidationError(message=_('Account required and must be Abon'))
bp = '_' * 20
return {
'account': account,
'passport': getattr(account, 'passportinfo', {
'series': bp,
'number': bp,
'distributor': bp,
'date_of_acceptance': bp
})
}

2
gw_app/nas_managers/mod_mikrotik.py

@ -235,7 +235,7 @@ class MikrotikTransmitter(core.BaseTransmitter, ApiRos,
name = info.get('=name')
disabled = info.get('=disabled', False)
if disabled is not None:
disabled = True if disabled == 'true' else False
disabled = disabled == 'true'
if target and name:
# target may be '192.168.0.3/32,192.168.0.2/32'
net = target.split(',')[0]

85
migrate2v2_dump.py

@ -54,7 +54,7 @@ class BatchSaveStreamList(list):
# image fields
elif isinstance(field, ImageField):
val = getattr(obj, field.name)
return getattr(val, 'url') if val else None
return getattr(val, 'name') if val else None
# mac address validated by netaddr.EUI
elif isinstance(field, MACAddressField):
@ -84,10 +84,14 @@ class BatchSaveStreamList(list):
return 1
def batch_save(fname, *args, **kwargs):
def batch_save(app_label: str, fname: str, *args, **kwargs):
sa = BatchSaveStreamList(*args, **kwargs)
print(fname)
with open(fname, 'w') as f:
fixt_dir = os.path.join('fixtures', app_label, 'fixtures')
if not os.path.isdir(fixt_dir):
os.makedirs(fixt_dir, mode=0o750)
full_path = os.path.join(fixt_dir, fname)
print(full_path)
with open(full_path, 'w') as f:
dump(sa, f, ensure_ascii=False, indent=2, cls=DjangoJSONEncoder)
@ -96,14 +100,15 @@ def batch_save(fname, *args, **kwargs):
def dump_groups():
from group_app.models import Group
batch_save("groups.json", Group.objects.all(), 'groupapp.group')
batch_save(app_label='groupapp', fname="groups.json", model_queryset=Group.objects.all(), model_name='groupapp.group')
def dump_accounts():
from accounts_app.models import UserProfile, BaseAccount, UserProfileLog
batch_save('accounts_baseaccount.json', BaseAccount.objects.exclude(username='AnonymousUser'), 'profiles.baseaccount',
app_label = 'profiles'
batch_save(app_label=app_label, fname='accounts_baseaccount.json', model_queryset=BaseAccount.objects.exclude(username='AnonymousUser'), model_name='profiles.baseaccount',
except_fields=['groups', 'user_permissions'])
batch_save('accounts_userprofile.json', UserProfile.objects.exclude(username='AnonymousUser'), 'profiles.userprofile',
batch_save(app_label=app_label, fname='accounts_userprofile.json', model_queryset=UserProfile.objects.exclude(username='AnonymousUser'), model_name='profiles.userprofile',
except_fields=['groups', 'user_permissions'])
do_type_map = {
'cusr': 1, 'dusr': 2,
@ -111,7 +116,7 @@ def dump_accounts():
'cnas': 5, 'dnas': 6,
'csrv': 7, 'dsrv': 8
}
batch_save('accounts_userprofilelog.json', UserProfileLog.objects.all(), 'profiles.userprofilelog',
batch_save(app_label=app_label, fname='accounts_userprofilelog.json', model_queryset=UserProfileLog.objects.all(), model_name='profiles.userprofilelog',
except_fields=['meta_info'],
choice_list_map={
'do_type': do_type_map
@ -120,15 +125,17 @@ def dump_accounts():
def dump_messenger():
from messenger.models import Messenger, ViberMessenger, ViberMessage, ViberSubscriber
batch_save("messenger.json", Messenger.objects.all(), 'messenger.messenger')
batch_save("vibermessenger.json", ViberMessenger.objects.all(), 'messenger.vibermessenger')
batch_save("vibermessage.json", ViberMessage.objects.all(), 'messenger.vibermessage')
batch_save("vibersubscriber.json", ViberSubscriber.objects.all(), 'messenger.vibersubscriber')
app_label = 'messenger'
batch_save(app_label, "messenger.json", Messenger.objects.all(), 'messenger.messenger')
batch_save(app_label, "vibermessenger.json", ViberMessenger.objects.all(), 'messenger.vibermessenger')
batch_save(app_label, "vibermessage.json", ViberMessage.objects.all(), 'messenger.vibermessage')
batch_save(app_label, "vibersubscriber.json", ViberSubscriber.objects.all(), 'messenger.vibersubscriber')
def dump_services():
from tariff_app.models import Tariff, PeriodicPay
batch_save("services.json", Tariff.objects.all(), 'services.service', field_name_map={
app_label = 'services'
batch_save(app_label, "services.json", Tariff.objects.all(), 'services.service', field_name_map={
'speedIn': 'speed_in',
'speedOut': 'speed_out',
'amount': 'cost'
@ -140,7 +147,7 @@ def dump_services():
'Dl': 3
}
})
batch_save("services_periodicpay.json", PeriodicPay.objects.all(), 'services.periodicpay', choice_list_map={
batch_save(app_label, "services_periodicpay.json", PeriodicPay.objects.all(), 'services.periodicpay', choice_list_map={
'calc_type': {
'df': 0,
'cs': 1
@ -150,7 +157,8 @@ def dump_services():
def dump_gateways():
from gw_app.models import NASModel
batch_save("gateways.json", NASModel.objects.all(), 'gateways.gateway', field_name_map={
app_label = 'gateways'
batch_save(app_label, "gateways.json", NASModel.objects.all(), 'gateways.gateway', field_name_map={
'nas_type': 'gw_type',
'default': 'is_default'
}, choice_list_map={
@ -162,7 +170,8 @@ def dump_gateways():
def dump_devices():
from devapp.models import Device, Port
batch_save("devices.json", Device.objects.all(), 'devices.device', field_name_map={
app_label = 'devices'
batch_save(app_label, "devices.json", Device.objects.all(), 'devices.device', field_name_map={
'devtype': 'dev_type'
}, choice_list_map={
'devtype': {
@ -178,7 +187,7 @@ def dump_devices():
'dwn': 3
}
})
batch_save('devices_port.json', Port.objects.all(), 'devices.port')
batch_save(app_label, 'devices_port.json', Port.objects.all(), 'devices.port')
def dump_customers():
@ -187,41 +196,43 @@ def dump_customers():
PassportInfo, InvoiceForPayment, AbonRawPassword,
AdditionalTelephone, PeriodicPayForId
)
batch_save('customer.json', Abon.objects.exclude(username='AnonymousUser'), 'customers.customer', field_name_map={
app_label = 'customers'
batch_save(app_label, 'customer.json', Abon.objects.exclude(username='AnonymousUser'), 'customers.customer', field_name_map={
'current_tariff': 'current_service',
'ballance': 'balance',
'nas': 'gateway',
'autoconnect_service': 'auto_renewal_service',
'last_connected_tariff': 'last_connected_service'
}, except_fields=['groups', 'user_permissions'])
batch_save('customers_log.json', AbonLog.objects.all(), 'customers.customerlog', field_name_map={
batch_save(app_label, 'customers_log.json', AbonLog.objects.all(), 'customers.customerlog', field_name_map={
'abon': 'customer',
'amount': 'cost'
})
batch_save('customers_service.json', AbonTariff.objects.all(), 'customers.customerservice', field_name_map={
batch_save(app_label, 'customers_service.json', AbonTariff.objects.all(), 'customers.customerservice', field_name_map={
'tariff': 'service',
'time_start': 'start_time'
})
batch_save('customers_street.json', AbonStreet.objects.all(), 'customers.customerstreet')
batch_save('customers_passport.json', PassportInfo.objects.all(), 'customers.passportinfo', field_name_map={
batch_save(app_label, 'customers_street.json', AbonStreet.objects.all(), 'customers.customerstreet')
batch_save(app_label, 'customers_passport.json', PassportInfo.objects.all(), 'customers.passportinfo', field_name_map={
'abon': 'customer'
})
batch_save('customers_inv.json', InvoiceForPayment.objects.all(), 'customers.invoiceforpayment', field_name_map={
batch_save(app_label, 'customers_inv.json', InvoiceForPayment.objects.all(), 'customers.invoiceforpayment', field_name_map={
'abon': 'customer',
'amount': 'cost'
})
batch_save('customers_passw.json', AbonRawPassword.objects.all(), 'customers.customerrawpassword', field_name_map={
batch_save(app_label, 'customers_passw.json', AbonRawPassword.objects.all(), 'customers.customerrawpassword', field_name_map={
'account': 'customer'
})
batch_save('customers_tels.json', AdditionalTelephone.objects.all(), 'customers.additionaltelephone', field_name_map={
batch_save(app_label, 'customers_tels.json', AdditionalTelephone.objects.all(), 'customers.additionaltelephone', field_name_map={
'abon': 'customer'
})
batch_save('customers_tels.json', PeriodicPayForId.objects.all(), 'customers.periodicpayforid')
batch_save(app_label, 'customers_tels.json', PeriodicPayForId.objects.all(), 'customers.periodicpayforid')
def dump_networks():
from ip_pool.models import NetworkModel
batch_save('nets.json', NetworkModel.objects.all(), 'networks.networkmodel', choice_list_map={
app_label = 'networks'
batch_save(app_label, 'nets.json', NetworkModel.objects.all(), 'networks.networkmodel', choice_list_map={
'kind': {
'inet': 1,
'guest': 2,
@ -234,7 +245,8 @@ def dump_networks():
def dump_tasks():
from taskapp.models import Task, ExtraComment, ChangeLog
batch_save('task.json', Task.objects.all(), 'tasks.task', field_name_map={
app_label = 'tasks'
batch_save(app_label, 'task.json', Task.objects.all(), 'tasks.task', field_name_map={
'abon': 'customer'
}, except_fields=['attachment'], choice_list_map={
'priority': {
@ -257,8 +269,8 @@ def dump_tasks():
'ot': 12
}
})
batch_save('task_comments.json', ExtraComment.objects.all(), 'tasks.extracomment')
batch_save('task_log.json', ChangeLog.objects.all(), 'tasks.changelog', choice_list_map={
batch_save(app_label, 'task_comments.json', ExtraComment.objects.all(), 'tasks.extracomment')
batch_save(app_label, 'task_log.json', ChangeLog.objects.all(), 'tasks.changelog', choice_list_map={
'act_type': {
'e': 1, 'c': 2,
'd': 3, 'f': 4, 'b': 5
@ -266,10 +278,21 @@ def dump_tasks():
})
def dump_fin():
from finapp.models import PayAllTimeGateway, AllTimePayLog
app_label = 'fin_app'
batch_save(app_label, 'fin_gws.json', PayAllTimeGateway.objects.all(), 'fin_app.payalltimegateway')
batch_save(app_label, 'fin_logs.json', AllTimePayLog.objects.all(), 'fin_app.alltimepaylog', field_name_map={
'abon': 'customer',
'summ': 'sum'
})
all_migrs = (
dump_groups, dump_accounts, dump_messenger,
dump_services, dump_gateways, dump_devices,
dump_customers, dump_networks, dump_tasks
dump_customers, dump_networks, dump_tasks,
dump_fin
)
if __name__ == '__main__':

2
periodic.py

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/var/www/djing/venv/bin/python
import os
from threading import Thread
import django

33
requirements.txt

@ -1,31 +1,30 @@
wheel
urllib3
Django>=2
Pillow
urllib3==1.25.10
Django==2.2.17
Pillow==7.2.0
# for mac address field
netaddr
netaddr==0.8.0
# for testing required xmltodict
#xmltodict
dicttoxml
dicttoxml==1.7.4
# db client for Mariadb
mysqlclient
easysnmp
pid
django-guardian
pinax-theme-bootstrap
django-bootstrap3
git+git://github.com/nerosketch/easysnmp.git#egg=easysnmp
pid==3.0.4
django-guardian==2.3.0
pinax-theme-bootstrap==8.0.1
django-bootstrap3==14.1.0
# django-jsonfield
-e git://github.com/dmkoch/django-jsonfield.git#egg=django-jsonfield
requests
webdavclient
transliterate
django-encrypted-model-fields
requests==2.24.0
webdavclient==1.0.8
transliterate==1.10.2
django-encrypted-model-fields==0.5.8
# django-xmlview for pay system allpay
-e git://github.com/nerosketch/django-xmlview.git#egg=django-xmlview
@ -43,5 +42,7 @@ django-encrypted-model-fields
-e git://github.com/pexpect/pexpect.git#egg=pexpect
Celery
redis
redis==3.5.3
celery[redis]
docxtpl

1
systemd_units/djing.timer

@ -3,7 +3,6 @@ Description=Run every night a job for djing
[Timer]
OnCalendar=*-*-* 01:59:00
Persistent=true
Unit=djing.service
[Install]

1
systemd_units/djing_backup.timer

@ -3,7 +3,6 @@ Description=Run backup periodically
[Timer]
OnCalendar=*-*-* 8,12,14,16,19,23:15:0
Persistent=true
Unit=djing_backup.service
[Install]

7
systemd_units/webdav_backup.py

@ -9,14 +9,15 @@ options = {
'webdav_login': "YANDEX USERNAME",
'webdav_password': "YANDEX PASSWORD"
}
REMOTE_DIR = 'DjingBackups'
def remove_old_files(border_time: datetime, client):
# files that older than border_time will be removed
for file in client.list('ISBackups'):
for file in client.list(REMOTE_DIR):
fdate = datetime.strptime(file, 'djing%Y-%m-%d_%H.%M.%S.sql.gz')
if fdate < border_time:
del_fname = os.path.join('ISBackups', file)
del_fname = os.path.join(REMOTE_DIR, file)
client.clean(del_fname)
print("rm %s" % del_fname)
@ -30,7 +31,7 @@ if __name__ == '__main__':
remove_old_files(border_time, client)
else:
client.upload_sync(
remote_path=os.path.join('ISBackups', reqfile),
remote_path=os.path.join(REMOTE_DIR, reqfile),
local_path=os.path.join(os.path.sep, 'var', 'backups', reqfile)
)
except wc.WebDavException as we:

8
tariff_app/custom_tariffs.py

@ -1,14 +1,12 @@
# -*- coding: utf-8 -*-
from datetime import timedelta, datetime, date
from typing import AnyStr
from calendar import monthrange
from random import uniform
from django.utils import timezone
from django.utils.translation import gettext as _
from .base_intr import TariffBase, PeriodicPayCalcBase
from random import uniform
class TariffDefault(TariffBase):
description = _('Base calculate functionality')
@ -101,7 +99,7 @@ class PeriodicPayCalcDefault(PeriodicPayCalcBase):
today = date.today()
nw = datetime(today.year, today.month, today.day)
days = monthrange(nw.year, nw.month)[1]
return nw + timedelta(days - nw.day+1)
return nw + timedelta(days - nw.day + 1)
class PeriodicPayCalcCustom(PeriodicPayCalcDefault):

6
templates/base.html

@ -129,6 +129,12 @@
</a>
</li>
{% url 'docsapp:docs_list' as docslist %}
<li{% if docslist in request.path %} class="active"{% endif %}>
<a href="{{ docslist }}">
<span class="glyphicon glyphicon-book"></span> {% trans 'Documents' %}
</a>
</li>
</ul>
</div>

2
templates/custom_pages/footer.htm

@ -1 +1 @@
Your custom content <i>here</i>.
{# Your custom content <i>here</i>. #}

2
templates/custom_pages/main_page.htm

@ -1 +1 @@
<h1>You can change this page</h1>
{# <h1>You can change this page</h1> #}

4
templates/custom_pages/service.htm

@ -1,2 +1,2 @@
<h1>Your custom content</h1>
<p>You have service variable {{ active_service }}</p>
{# <h1>Your custom content</h1> #}
{# <p>You have service variable {{ active_service }}</p> #}

2
templates/custom_pages/service_bottom.htm

@ -1 +1 @@
<h1>Your custom content on bottom</h1>
{# <h1>Your custom content on bottom</h1> #}
Loading…
Cancel
Save