├── agent ├── __init__.py ├── netflow │ ├── __init__.py │ ├── djing_flow.tar.gz │ ├── start_netflow.sh │ ├── netflow_handler.sh │ └── netflow_collect.sh └── downloader.py ├── devapp ├── __init__.py ├── migrations │ └── __init__.py ├── apps.py ├── admin.py ├── expect_scripts │ ├── __init__.py │ └── dlink_DGS1100_reboot.exp ├── templates │ └── devapp │ │ ├── device_confirm_delete.html │ │ ├── manage_ports │ │ ├── modal_show_subscriber_on_port.html │ │ ├── modal_del_port.html │ │ ├── modal_add_edit_port.html │ │ └── fix_abon_device.html │ │ ├── modal_device_reboot.html │ │ ├── modal_device_extra_edit.html │ │ ├── ext.htm │ │ └── group_list.html ├── tasks.py └── tests.py ├── finapp ├── __init__.py ├── migrations │ └── __init__.py ├── apps.py ├── admin.py ├── forms.py ├── templates │ └── finapp │ │ ├── ext.htm │ │ ├── fin_report.html │ │ └── payHistory.html └── urls.py ├── mapapp ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0002_auto_20180808_1236.py │ └── 0001_initial.py ├── admin.py ├── apps.py ├── forms.py ├── templates │ └── maps │ │ ├── preload_devices_tmpl.html │ │ ├── modal_add_device.html │ │ ├── map_tooltip.html │ │ └── modal_add_dot.html ├── models.py └── urls.py ├── abonapp ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0009_auto_20181123_1556.py ├── apps.py ├── templates │ └── abonapp │ │ ├── abon_confirm_delete.html │ │ ├── modal_confirm_ip_free.html │ │ ├── modal_passport_view.html │ │ ├── modal_export.html │ │ ├── modal_current_networks.html │ │ ├── modal_abonamount.html │ │ ├── modal_addstreet.html │ │ ├── modal_phonebook.html │ │ ├── modal_add_phone.html │ │ ├── modal_periodic_pay.html │ │ ├── modal_attach_nas.html │ │ ├── modal_ip_form.html │ │ ├── modal_user_markers.html │ │ ├── modal_additional_telephones.html │ │ ├── modal_dev.html │ │ ├── group_tariffs.html │ │ └── modal_editstreet.html ├── admin.py └── tasks.py ├── docsapp ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── apps.py ├── forms.py ├── templates │ └── docsapp │ │ ├── documenttemplatemodel_confirm_delete.html │ │ ├── simple_list.html │ │ └── documenttemplatemodel_form.html ├── urls.py └── models.py ├── group_app ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0003_auto_20180808_1236.py │ ├── 0002_group_code.py │ └── 0001_initial.py ├── tests.py ├── admin.py ├── apps.py ├── forms.py ├── urls.py ├── templates │ └── group_app │ │ ├── group_confirm_delete.html │ │ ├── ext.html │ │ ├── add_group.html │ │ └── edit_group.html └── models.py ├── ip_pool ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_squashed_0004_auto_20190305_1243.py ├── templatetags │ ├── __init__.py │ └── ip_pool_tags.py ├── apps.py ├── admin.py ├── templates │ └── ip_pool │ │ ├── networkmodel_confirm_delete.html │ │ ├── ext.html │ │ ├── network_groups_available.html │ │ └── net_add.html ├── forms.py └── urls.py ├── msg_app ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0002_auto_20180808_1236.py ├── tests.py ├── apps.py ├── admin.py ├── context_processors.py ├── urls.py └── templates │ └── msg_app │ └── modal_new_conversation.html ├── searchapp ├── __init__.py ├── migrations │ └── __init__.py ├── admin.py ├── models.py ├── apps.py ├── urls.py ├── locale │ └── ru │ │ └── LC_MESSAGES │ │ └── django.po └── views.py ├── tariff_app ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0003_auto_20181115_1206.py │ └── 0002_auto_20180807_1548.py ├── admin.py ├── forms.py ├── templates │ └── tariff_app │ │ ├── tariff_confirm_delete.html │ │ └── ext.html └── urls.py ├── taskapp ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0002_auto_20180808_1236.py ├── apps.py ├── admin.py ├── context_proc.py ├── templates │ └── taskapp │ │ ├── notification.html │ │ ├── comments │ │ ├── extracomment_confirm_delete.html │ │ └── task_comments.html │ │ ├── footer_btns.html │ │ └── details.html ├── templatetags │ └── tasktags.py ├── urls.py └── handle.py ├── traf_stat ├── __init__.py ├── migrations │ ├── __init__.py │ └── 0001_initial.py ├── admin.py ├── tests.py ├── apps.py ├── urls.py ├── views.py ├── templates │ └── statistics │ │ └── index.html └── fields.py ├── accounts_app ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0004_userprofile_flags.py │ └── 0002_auto_20180807_1548.py ├── templatetags │ ├── __init__.py │ └── acc_tags.py ├── apps.py ├── admin.py ├── templates │ └── accounts │ │ ├── settings │ │ └── userprofile_form.html │ │ ├── perms │ │ ├── change_global_perms.html │ │ ├── object │ │ │ ├── objects_of_type.html │ │ │ └── objects_types.html │ │ └── ext.html │ │ ├── action_log.html │ │ ├── set_abon_groups_permission.html │ │ ├── manage_responsibility_groups.html │ │ └── index.html └── urls.py ├── clientsideapp ├── __init__.py ├── migrations │ └── __init__.py ├── admin.py ├── models.py ├── apps.py ├── urls.py └── templates │ └── clientsideapp │ ├── pays.html │ ├── index.html │ ├── modal_service_buy.html │ └── tasklist.html ├── new_customers ├── __init__.py ├── migrations │ └── __init__.py ├── apps.py ├── admin.py ├── forms.py ├── urls.py ├── templates │ └── new_customers │ │ └── potentialsubscriber_form.html ├── views.py └── models.py ├── djing ├── templatetags │ ├── __init__.py │ ├── globaltags.py │ └── dpagination.py ├── lib │ ├── messaging │ │ ├── __init__.py │ │ └── sms │ │ │ ├── pdu.py │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── consts.py │ │ │ └── wap.py │ └── mixins.py ├── views.py ├── celery.py ├── wsgi.py ├── formfields.py ├── locale │ └── ru │ │ └── LC_MESSAGES │ │ └── django.po ├── urls.py └── local_settings.py.example ├── gw_app ├── migrations │ ├── __init__.py │ ├── 0003_nasmodel_enabled.py │ ├── 0002_auto_20181101_1545.py │ └── 0001_initial.py ├── __init__.py ├── admin.py ├── apps.py ├── nas_managers │ └── __init__.py ├── urls.py ├── templates │ └── gw_app │ │ ├── nasmodel_confirm_delete.html │ │ ├── nasmodel_add.html │ │ └── nasmodel_update.html └── forms.py ├── messenger ├── migrations │ └── __init__.py ├── __init__.py ├── tests.py ├── apps.py ├── admin.py ├── templates │ └── messenger │ │ ├── add_messenger.html │ │ ├── vibersubscriber_list.html │ │ └── vibermessenger_form.html ├── forms.py └── urls.py ├── _config.yml ├── templates ├── bajax.html ├── nullcont.htm ├── site_base.html ├── custom_pages │ ├── footer.htm │ ├── main_page.htm │ ├── service_bottom.htm │ └── service.htm ├── base_no_lmenu.html ├── 403_for_modal.html ├── base_delete_modal.html ├── pagination.html ├── 403.html └── 500.html ├── docs ├── img │ ├── login.png │ └── pagination.png ├── bot.md ├── extra_func.md ├── tarifs.md ├── notifications.md └── user_page.md ├── install ├── robots.txt ├── djing.ini └── nginx_server.conf ├── static ├── img │ ├── bcgr.png │ ├── noticon.png │ ├── user_ava.gif │ ├── favicon_m.ico │ ├── user_ava_min.gif │ ├── user_markers.png │ └── icon-port-64x64-grey.png ├── clientside │ ├── bc.png │ ├── rj45.png │ ├── TL-WR840N-v2.jpg │ └── custom.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 └── bad_ie.html ├── .gitmodules ├── .dockerignore ├── systemd_units ├── djing.timer ├── djing_backup.timer ├── djing_backup.service ├── djing_rotate.timer ├── djing.service ├── djing_rotate.service ├── djing_celery.service ├── do_backup.sh └── webdav_backup.py ├── .gitignore ├── manage.py ├── update_release.sh ├── docker-compose.yml ├── Doc.txt ├── README.md ├── requirements.txt ├── LICENSE └── Dockerfile /agent/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /devapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /finapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mapapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /abonapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docsapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /group_app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ip_pool/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /msg_app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /searchapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tariff_app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /taskapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /traf_stat/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts_app/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /agent/netflow/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /clientsideapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /new_customers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /abonapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /devapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /djing/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docsapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /finapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /group_app/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gw_app/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ip_pool/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ip_pool/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mapapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /messenger/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /msg_app/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /searchapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tariff_app/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /taskapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /traf_stat/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /accounts_app/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /clientsideapp/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /new_customers/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-time-machine -------------------------------------------------------------------------------- /searchapp/admin.py: -------------------------------------------------------------------------------- 1 | # Register your models here. 2 | -------------------------------------------------------------------------------- /searchapp/models.py: -------------------------------------------------------------------------------- 1 | # Create your models here. 2 | -------------------------------------------------------------------------------- /templates/bajax.html: -------------------------------------------------------------------------------- 1 | {% block main %}{% endblock %} -------------------------------------------------------------------------------- /clientsideapp/admin.py: -------------------------------------------------------------------------------- 1 | # Register your models here. 2 | -------------------------------------------------------------------------------- /clientsideapp/models.py: -------------------------------------------------------------------------------- 1 | # Create your models here. 2 | -------------------------------------------------------------------------------- /templates/nullcont.htm: -------------------------------------------------------------------------------- 1 | {% block content %}{% endblock %} -------------------------------------------------------------------------------- /templates/site_base.html: -------------------------------------------------------------------------------- 1 | {% include 'all_base.html' %} 2 | -------------------------------------------------------------------------------- /accounts_app/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'bashmak' 2 | -------------------------------------------------------------------------------- /gw_app/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'gw_app.apps.GatewaysAppConfig' 2 | -------------------------------------------------------------------------------- /messenger/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'messenger.apps.messengerConfig' -------------------------------------------------------------------------------- /templates/custom_pages/footer.htm: -------------------------------------------------------------------------------- 1 | {# Your custom content here. #} 2 | -------------------------------------------------------------------------------- /djing/lib/messaging/__init__.py: -------------------------------------------------------------------------------- 1 | # see LICENSE 2 | 3 | VERSION = (0, 5, 12) 4 | -------------------------------------------------------------------------------- /templates/custom_pages/main_page.htm: -------------------------------------------------------------------------------- 1 | {#

You can change this page

#} 2 | -------------------------------------------------------------------------------- /docs/img/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/docs/img/login.png -------------------------------------------------------------------------------- /msg_app/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /group_app/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /gw_app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /install/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: /$ 3 | Allow: /accounts/login/ 4 | Disallow: / -------------------------------------------------------------------------------- /messenger/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /static/img/bcgr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/img/bcgr.png -------------------------------------------------------------------------------- /templates/custom_pages/service_bottom.htm: -------------------------------------------------------------------------------- 1 | {#

Your custom content on bottom

#} 2 | -------------------------------------------------------------------------------- /traf_stat/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /traf_stat/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /docs/img/pagination.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/docs/img/pagination.png -------------------------------------------------------------------------------- /static/img/noticon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/img/noticon.png -------------------------------------------------------------------------------- /static/img/user_ava.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/img/user_ava.gif -------------------------------------------------------------------------------- /static/clientside/bc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/clientside/bc.png -------------------------------------------------------------------------------- /static/img/favicon_m.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/img/favicon_m.ico -------------------------------------------------------------------------------- /docs/bot.md: -------------------------------------------------------------------------------- 1 | # Оповещения из биллнга 2 | Мгновенная связь с администратором и общение с сотрудниками. 3 | -------------------------------------------------------------------------------- /static/clientside/rj45.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/clientside/rj45.png -------------------------------------------------------------------------------- /static/img/user_ava_min.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/img/user_ava_min.gif -------------------------------------------------------------------------------- /static/img/user_markers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/img/user_markers.png -------------------------------------------------------------------------------- /agent/netflow/djing_flow.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/agent/netflow/djing_flow.tar.gz -------------------------------------------------------------------------------- /mapapp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Dot 3 | 4 | admin.site.register(Dot) 5 | -------------------------------------------------------------------------------- /devapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DevappConfig(AppConfig): 5 | name = 'devapp' 6 | -------------------------------------------------------------------------------- /finapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class FinappConfig(AppConfig): 5 | name = 'finapp' 6 | -------------------------------------------------------------------------------- /group_app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | admin.site.register(models.Group) 5 | -------------------------------------------------------------------------------- /ip_pool/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class IpPoolConfig(AppConfig): 5 | name = 'ip_pool' 6 | -------------------------------------------------------------------------------- /mapapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MapappConfig(AppConfig): 5 | name = 'mapapp' 6 | -------------------------------------------------------------------------------- /msg_app/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MsgAppConfig(AppConfig): 5 | name = 'msg_app' 6 | -------------------------------------------------------------------------------- /static/clientside/TL-WR840N-v2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/clientside/TL-WR840N-v2.jpg -------------------------------------------------------------------------------- /static/img/icon-port-64x64-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/img/icon-port-64x64-grey.png -------------------------------------------------------------------------------- /docsapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class DocsappConfig(AppConfig): 5 | name = 'docsapp' 6 | -------------------------------------------------------------------------------- /gw_app/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class GatewaysAppConfig(AppConfig): 5 | name = 'gw_app' 6 | -------------------------------------------------------------------------------- /taskapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TaskappConfig(AppConfig): 5 | name = 'taskapp' 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "djing_flow"] 2 | path = agent/netflow/djing_flow 3 | url = git://github.com/nerosketch/djing_flow.git 4 | -------------------------------------------------------------------------------- /accounts_app/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsAppConfig(AppConfig): 5 | name = 'acc_app' 6 | -------------------------------------------------------------------------------- /group_app/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class GroupAppConfig(AppConfig): 5 | name = 'group_app' 6 | -------------------------------------------------------------------------------- /messenger/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class messengerConfig(AppConfig): 5 | name = 'messenger' 6 | -------------------------------------------------------------------------------- /searchapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SearchappConfig(AppConfig): 5 | name = 'searchapp' 6 | -------------------------------------------------------------------------------- /tariff_app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from . import models 4 | 5 | admin.site.register(models.Tariff) 6 | -------------------------------------------------------------------------------- /traf_stat/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TrafStatConfig(AppConfig): 5 | name = 'traf_stat' 6 | -------------------------------------------------------------------------------- /ip_pool/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from ip_pool import models 3 | 4 | admin.site.register(models.NetworkModel) 5 | -------------------------------------------------------------------------------- /templates/custom_pages/service.htm: -------------------------------------------------------------------------------- 1 | {#

Your custom content

#} 2 | {#

You have service variable {{ active_service }}

#} 3 | -------------------------------------------------------------------------------- /new_customers/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NewCustomersConfig(AppConfig): 5 | name = 'new_customers' 6 | -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nerosketch/djing/HEAD/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /abonapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AbonappConfig(AppConfig): 5 | name = 'abonapp' 6 | verbose_name = 'Abonent app' 7 | -------------------------------------------------------------------------------- /devapp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from . import models 4 | 5 | admin.site.register(models.Device) 6 | admin.site.register(models.Port) 7 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.db 3 | media/* 4 | media/min/* 5 | .idea/ 6 | .git/ 7 | gmap/fixtures 8 | *.sqlite3 9 | *.json 10 | *.bak 11 | *.mo 12 | venv/ 13 | -------------------------------------------------------------------------------- /msg_app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | admin.site.register(models.Message) 5 | admin.site.register(models.Conversation) 6 | -------------------------------------------------------------------------------- /taskapp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from . import models 4 | 5 | admin.site.register(models.Task) 6 | admin.site.register(models.ChangeLog) 7 | -------------------------------------------------------------------------------- /new_customers/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from new_customers.models import PotentialSubscriber 3 | 4 | 5 | admin.site.register(PotentialSubscriber) 6 | -------------------------------------------------------------------------------- /finapp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from finapp import models 3 | 4 | admin.site.register(models.AllTimePayLog) 5 | admin.site.register(models.PayAllTimeGateway) 6 | -------------------------------------------------------------------------------- /clientsideapp/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ClientsideappConfig(AppConfig): 5 | name = 'clientsideapp' 6 | verbose_name = 'Client side application' 7 | -------------------------------------------------------------------------------- /accounts_app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import UserProfile, UserProfileLog 4 | 5 | admin.site.register(UserProfile) 6 | admin.site.register(UserProfileLog) 7 | -------------------------------------------------------------------------------- /searchapp/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'searchapp' 6 | 7 | urlpatterns = [ 8 | path(r'', views.home, name='home'), 9 | 10 | ] 11 | -------------------------------------------------------------------------------- /traf_stat/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from traf_stat.views import home 4 | 5 | app_name = 'traf_stat' 6 | 7 | urlpatterns = [ 8 | path('', home, name='home'), 9 | ] 10 | -------------------------------------------------------------------------------- /group_app/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from . import models 3 | 4 | 5 | class GroupForm(forms.ModelForm): 6 | class Meta: 7 | model = models.Group 8 | fields = '__all__' 9 | -------------------------------------------------------------------------------- /systemd_units/djing.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Run every night a job for djing 3 | 4 | [Timer] 5 | OnCalendar=*-*-* 01:59:00 6 | Unit=djing.service 7 | 8 | [Install] 9 | WantedBy=timers.target 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.db 3 | media/* 4 | media/min/* 5 | ~*/migrations/00*.py 6 | .idea/ 7 | djing/local_settings.py 8 | gmap/fixtures 9 | *.sqlite3 10 | *.json 11 | *.bak 12 | *.mo 13 | agent/netflow/djing_flow 14 | venv/ 15 | -------------------------------------------------------------------------------- /systemd_units/djing_backup.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Run backup periodically 3 | 4 | [Timer] 5 | OnCalendar=*-*-* 8,12,14,16,19,23:15:0 6 | Unit=djing_backup.service 7 | 8 | [Install] 9 | WantedBy=timers.target 10 | 11 | -------------------------------------------------------------------------------- /docsapp/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from docsapp.models import DocumentTemplateModel 3 | 4 | 5 | class DocumentTemplateModelForm(forms.ModelForm): 6 | class Meta: 7 | model = DocumentTemplateModel 8 | fields = '__all__' 9 | -------------------------------------------------------------------------------- /messenger/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from messenger import models 3 | 4 | admin.site.register(models.Messenger) 5 | admin.site.register(models.ViberMessenger) 6 | admin.site.register(models.ViberSubscriber) 7 | admin.site.register(models.ViberMessage) 8 | -------------------------------------------------------------------------------- /systemd_units/djing_backup.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Backup for djing 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/var/backups/do_backup.sh 7 | WorkingDirectory=/var/backups 8 | User=root 9 | Group=root 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /systemd_units/djing_rotate.timer: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Run every one minute rotate flows for djing 3 | 4 | [Timer] 5 | OnCalendar=*-*-* *:*:59 6 | Persistent=true 7 | RandomizedDelaySec=5 8 | Unit=djing_rotate.service 9 | 10 | [Install] 11 | WantedBy=timers.target 12 | -------------------------------------------------------------------------------- /djing/lib/messaging/sms/pdu.py: -------------------------------------------------------------------------------- 1 | # see LICENSE 2 | 3 | 4 | class Pdu(object): 5 | def __init__(self, pdu, len_smsc, cnt=1, seq=1): 6 | self.pdu = pdu.upper() 7 | self.length = len(pdu) / 2 - len_smsc 8 | self.cnt = cnt 9 | self.seq = seq 10 | -------------------------------------------------------------------------------- /devapp/expect_scripts/__init__.py: -------------------------------------------------------------------------------- 1 | from .f601 import register_onu as register_f601_onu 2 | from .f660 import register_onu as register_f660_onu 3 | from .base import ( 4 | ZteOltConsoleError, OnuZteRegisterError, 5 | ZTEFiberIsFull, ZteOltLoginFailed, ExpectValidationError 6 | ) 7 | -------------------------------------------------------------------------------- /djing/lib/messaging/sms/__init__.py: -------------------------------------------------------------------------------- 1 | # See LICENSE 2 | 3 | from djing.lib.messaging.sms.deliver import SmsDeliver 4 | from djing.lib.messaging.sms.submit import SmsSubmit 5 | from djing.lib.messaging.sms.gsm0338 import is_gsm_text 6 | 7 | __all__ = ("SmsSubmit", "SmsDeliver", "is_gsm_text") 8 | -------------------------------------------------------------------------------- /systemd_units/djing.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=A job for djing 3 | 4 | [Service] 5 | Type=oneshot 6 | ExecStart=/var/www/djing/venv/bin/python periodic.py 7 | WorkingDirectory=/var/www/djing 8 | User=www-data 9 | Group=www-data 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /traf_stat/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.contrib.auth.decorators import login_required 3 | from djing.lib.decorators import only_admins 4 | 5 | 6 | @login_required 7 | @only_admins 8 | def home(request): 9 | return render(request, 'statistics/index.html') 10 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /djing/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.decorators import login_required 2 | from django.shortcuts import redirect 3 | 4 | 5 | @login_required 6 | def home(request): 7 | if request.user.is_staff: 8 | return redirect('acc_app:setup_info') 9 | else: 10 | return redirect('client_side:home') 11 | -------------------------------------------------------------------------------- /msg_app/context_processors.py: -------------------------------------------------------------------------------- 1 | from .models import Conversation 2 | 3 | 4 | def get_new_messages_count(request): 5 | if request.user.is_anonymous: 6 | count = 0 7 | else: 8 | count = Conversation.objects.get_new_messages_count(request.user) 9 | return {'new_messages_count': count} 10 | -------------------------------------------------------------------------------- /install/djing.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | chdir=/var/www/djing 3 | module=djing.wsgi 4 | master=True 5 | processes=8 6 | socket=/run/uwsgi/app/djing/socket 7 | ;http-socket=:8000 8 | chmod-socket=644 9 | ;pidfile=/run/uwsgi/django-master.pid 10 | vacuum=True 11 | plugin=python3 12 | ;disable-logging=True 13 | venv=/var/www/djing/venv -------------------------------------------------------------------------------- /mapapp/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from .models import Dot 3 | 4 | 5 | class DotForm(forms.ModelForm): 6 | class Meta: 7 | model = Dot 8 | exclude = ('devices',) 9 | 10 | widgets = { 11 | 'title': forms.TextInput(attrs={'required': '', 'autofocus': ''}), 12 | } 13 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/abon_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'abonapp:del_abon' abon.group.pk abon.username %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Remove subscriber' %} 10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /systemd_units/djing_rotate.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=A job for rotate djing netflow data 3 | 4 | [Service] 5 | Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/bin" 6 | Type=oneshot 7 | ExecStart=/var/www/djing/agent/netflow/netflow_collect.sh 8 | User=root 9 | Group=root 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /djing/lib/messaging/sms/base.py: -------------------------------------------------------------------------------- 1 | # see LICENSE 2 | 3 | 4 | class SmsBase(object): 5 | def __init__(self): 6 | self.udh = None 7 | self.number = None 8 | self.text = None 9 | self.fmt = None 10 | self.dcs = None 11 | self.pid = None 12 | self.csca = None 13 | self.type = None 14 | -------------------------------------------------------------------------------- /mapapp/templates/maps/preload_devices_tmpl.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% for dev in all_devices %}
3 | 6 |
7 | {% empty %}{% trans 'no devices found' %}{% endfor %} -------------------------------------------------------------------------------- /djing/celery.py: -------------------------------------------------------------------------------- 1 | import os 2 | from celery import Celery 3 | 4 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings") 5 | app = Celery('djing', broker='redis://localhost:6379/0') 6 | app.config_from_object('django.conf:settings', namespace='CELERY') 7 | 8 | # Load task modules from all registered Django app configs. 9 | app.autodiscover_tasks() 10 | -------------------------------------------------------------------------------- /new_customers/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from new_customers.models import PotentialSubscriber 3 | 4 | 5 | class CustomerModelForm(forms.ModelForm): 6 | class Meta: 7 | model = PotentialSubscriber 8 | exclude = ('make_data',) 9 | widgets = { 10 | 'deadline': forms.DateInput(attrs={'type': 'date'}) 11 | } 12 | -------------------------------------------------------------------------------- /systemd_units/djing_celery.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Celery worker for djing 3 | 4 | [Service] 5 | Type=simple 6 | ExecStart=/var/www/djing/venv/bin/celery worker -A djing --loglevel=info --concurrency=4 7 | WorkingDirectory=/var/www/djing 8 | TimeoutSec=7 9 | Restart=always 10 | User=www-data 11 | Group=www-data 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /new_customers/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from new_customers import views 3 | 4 | 5 | app_name = 'new_customers' 6 | 7 | 8 | urlpatterns = [ 9 | path('', views.CustomersList.as_view(), name='customers_list'), 10 | path('new/', views.CustomerNew.as_view(), name='new_user'), 11 | path('/', views.CustomerDetail.as_view(), name='user'), 12 | ] 13 | -------------------------------------------------------------------------------- /tariff_app/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | 3 | from . import models 4 | 5 | 6 | class TariffForm(forms.ModelForm): 7 | class Meta: 8 | model = models.Tariff 9 | fields = '__all__' 10 | 11 | 12 | class PeriodicPayForm(forms.ModelForm): 13 | class Meta: 14 | model = models.PeriodicPay 15 | exclude = ('when_add', 'extra_info') 16 | -------------------------------------------------------------------------------- /gw_app/nas_managers/__init__.py: -------------------------------------------------------------------------------- 1 | from gw_app.nas_managers.mod_mikrotik import MikrotikTransmitter 2 | from gw_app.nas_managers.core import NasNetworkError, NasFailedResult 3 | from gw_app.nas_managers.structs import SubnetQueue 4 | 5 | # Указываем какие реализации шлюзов у нас есть, это будет использоваться в 6 | # web интерфейсе 7 | NAS_TYPES = ( 8 | ('mktk', MikrotikTransmitter), 9 | ) 10 | -------------------------------------------------------------------------------- /taskapp/context_proc.py: -------------------------------------------------------------------------------- 1 | from taskapp.models import Task 2 | from accounts_app.models import UserProfile 3 | 4 | 5 | def get_active_tasks_count(request): 6 | tasks_count = 0 7 | if isinstance(request.user, UserProfile): 8 | tasks_count = Task.objects.filter(recipients__in=[request.user], state='S').count() 9 | return { 10 | 'tasks_count': tasks_count 11 | } 12 | -------------------------------------------------------------------------------- /abonapp/migrations/0009_auto_20181123_1556.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1 on 2018-11-23 15:56 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('abonapp', '0008_auto_20181115_1206'), 10 | ] 11 | 12 | operations = [ 13 | migrations.DeleteModel( 14 | name='AllPayLog', 15 | ), 16 | ] 17 | -------------------------------------------------------------------------------- /update_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 4 | 5 | dock=$(which docker) 6 | if [ $? -eq 1 ]; then 7 | echo "docker not found. Check if it is installed." 8 | exit 1 9 | fi 10 | 11 | docker build -t djing:latest . 12 | docker tag djing:latest nerosketch/djing:latest 13 | docker push nerosketch/djing:latest 14 | docker rmi djing:latest 15 | 16 | -------------------------------------------------------------------------------- /djing/lib/messaging/sms/consts.py: -------------------------------------------------------------------------------- 1 | # see LICENSE 2 | SEVENBIT_SIZE = 160 3 | EIGHTBIT_SIZE = 140 4 | UCS2_SIZE = 70 5 | SEVENBIT_MP_SIZE = SEVENBIT_SIZE - 7 6 | EIGHTBIT_MP_SIZE = EIGHTBIT_SIZE - 6 7 | UCS2_MP_SIZE = UCS2_SIZE - 3 8 | 9 | # address type 10 | UNKNOWN = 0 11 | INTERNATIONAL = 1 12 | NATIONAL = 2 13 | NETWORK_SPECIFIC = 3 14 | SUBSCRIBER = 4 15 | ALPHANUMERIC = 5 16 | ABBREVIATED = 6 17 | RESERVED = 7 18 | -------------------------------------------------------------------------------- /templates/base_no_lmenu.html: -------------------------------------------------------------------------------- 1 | {% extends 'all_base.html' %} 2 | {% block base_content %} 3 | 4 | 5 |
6 |

7 | 8 |

9 | 10 | {% block main %}{% endblock %} 11 | 12 |
13 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /group_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = 'group_app' 5 | 6 | urlpatterns = [ 7 | path('', views.GroupListView.as_view(), name='group_list'), 8 | path('add/', views.AddGroupView.as_view(), name='add'), 9 | path('/edit/', views.EditGroupView.as_view(), name='edit'), 10 | path('/del/', views.DeleteGroupView.as_view(), name='del') 11 | ] 12 | -------------------------------------------------------------------------------- /ip_pool/templatetags/ip_pool_tags.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | from django.shortcuts import resolve_url 3 | 4 | from ip_pool.models import NetworkModel 5 | 6 | register = template.Library() 7 | 8 | 9 | @register.simple_tag 10 | def get_device_kinds(): 11 | return (( 12 | resolve_url('ip_pool:networks_%s/' % kind_code), 13 | kind_descr 14 | )for kind_code, kind_descr in NetworkModel.NETWORK_KINDS) 15 | -------------------------------------------------------------------------------- /gw_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from gw_app import views 3 | 4 | 5 | app_name = 'gw_app' 6 | 7 | 8 | urlpatterns = [ 9 | path('', view=views.NasListView.as_view(), name='home'), 10 | path('add/', view=views.NasCreateView.as_view(), name='add'), 11 | path('/del/', views.NasDeleteView.as_view(), name='del'), 12 | path('/edit/', views.NasUpdateView.as_view(), name='edit'), 13 | ] 14 | -------------------------------------------------------------------------------- /msg_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = 'msg_app' 5 | 6 | urlpatterns = [ 7 | path('', views.ConversationsListView.as_view(), name='home'), 8 | path('new/', views.new_conversation, name='new_conversation'), 9 | path('/', views.to_conversation, name='to_conversation'), 10 | path('//del/', views.remove_msg, name='remove_msg') 11 | ] 12 | -------------------------------------------------------------------------------- /devapp/templates/devapp/device_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'devapp:del' object.group.pk object.pk %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Remove device' %} 10 | {% endblock %} 11 | 12 | {% block modal_form_text %} 13 |

{% trans 'Are you sure you want to delete device?' %}

14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /abonapp/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from abonapp import models 4 | 5 | admin.site.register(models.Abon) 6 | admin.site.register(models.InvoiceForPayment) 7 | admin.site.register(models.AbonLog) 8 | admin.site.register(models.AbonTariff) 9 | admin.site.register(models.AbonStreet) 10 | admin.site.register(models.AbonRawPassword) 11 | admin.site.register(models.PassportInfo) 12 | admin.site.register(models.AdditionalTelephone) 13 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_confirm_ip_free.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'abonapp:user_session_free' gid object.username %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Free session' %} 10 | {% endblock %} 11 | 12 | {% block modal_form_text %} 13 |

{% trans 'Are you sure you want to free ip user session?' %}

14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /docsapp/templates/docsapp/documenttemplatemodel_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'docsapp:doc_del' object.pk %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Remove document' %} 10 | {% endblock %} 11 | 12 | {% block modal_form_text %} 13 |

{% trans 'Are you sure you want to delete this document?' %}

14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /djing/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for djing project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /group_app/templates/group_app/group_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'group_app:del' object.pk %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Remove group' %} 10 | {% endblock %} 11 | 12 | {% block modal_form_text %} 13 |

{% blocktrans %}Are you sure you want to delete group {{ object }}?{% endblocktrans %}

14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /taskapp/templates/taskapp/notification.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% blocktrans with abon_url=abon.get_absolute_url group=abon.group street=abon.street house=abon.house telephone=abon.telephone task_type=task.get_mode_display task_detail=task.descr %} 3 | {{ task_status }} 4 | {{ abon }} 5 | In group: {{ group }} 6 | Street: {{ street }} 7 | House: {{ house }} 8 | Tel: {{ telephone }} 9 | Task type: {{ task_type }} 10 | 11 | {{ task_detail }} 12 | {% endblocktrans %} 13 | -------------------------------------------------------------------------------- /gw_app/migrations/0003_nasmodel_enabled.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1 on 2018-11-15 13:27 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('gw_app', '0002_auto_20181101_1545'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='nasmodel', 15 | name='enabled', 16 | field=models.BooleanField(default=True, verbose_name='Enabled'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /tariff_app/migrations/0003_auto_20181115_1206.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1 on 2018-11-15 12:06 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('tariff_app', '0002_auto_20180807_1548'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterModelOptions( 14 | name='periodicpay', 15 | options={'ordering': ('-id',), 'verbose_name': 'Periodic pay', 'verbose_name_plural': 'Periodic pays'}, 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /devapp/templates/devapp/manage_ports/modal_show_subscriber_on_port.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /devapp/templates/devapp/modal_device_reboot.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n bootstrap3 %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'devapp:reboot' object.pk %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Reboot' %} 10 | {% endblock %} 11 | 12 | {% block modal_form_text %} 13 |

{% trans 'Are you sure you want to reboot that device?' %}

14 | {% bootstrap_form form %} 15 | {% endblock %} 16 | 17 | {% block modal_btn_delete_text %}{% trans 'Reboot' %}{% endblock %} 18 | -------------------------------------------------------------------------------- /tariff_app/templates/tariff_app/tariff_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'tarifs:del' tid %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Delete service' %} 10 | {% endblock %} 11 | 12 | {% block modal_form_text %} 13 | 14 |

{% blocktrans %}after delete the tariff, subscribers who use that tariff will be disconnected from it.{% endblocktrans %}

15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /agent/netflow/start_netflow.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/bin 4 | 5 | if ! [[ -n "$1" ]]; then 6 | echo 'Missing port parameter' 7 | exit 8 | fi 9 | 10 | port=$1 11 | DIRECTORY=`dirname $(readlink -e "$0")` 12 | 13 | tdir="/tmp/djing_flow/${port}" 14 | if [[ -d "${tdir}" ]]; then 15 | echo "Warning: directory '${tdir}' exists, clean all" 16 | rm -f ${tdir}/ft* 17 | else 18 | mkdir -p "${tdir}" 19 | fi 20 | 21 | 22 | flow-capture -R ${DIRECTORY}/netflow_handler.sh -p /run/flow.pid -w ${tdir} -n1 -N0 0/0/${port} 23 | -------------------------------------------------------------------------------- /docs/extra_func.md: -------------------------------------------------------------------------------- 1 | ## Дополнительный фунционал 2 | В процессе реализации проекта понадобился функционал, который отсутствует в базовой поставке **Django**. 3 | Его совсем не много, но без внимания оставить нельзя. 4 | 5 | Все вспомогательные модули можно найти в пакете **djing.lib**. 6 | 7 | ### messaging 8 | Этот модуль помогает работать с форматами СМС сообщений. 9 | 10 | ### init 11 | Содержит всякие мелкие примочки, код прост и с комментариями, зайдите посмотрите. 12 | 13 | ## auth_decorators 14 | Бэкенд авторизации 15 | 16 | ## decorators 17 | Дополнительные декораторы. 18 | -------------------------------------------------------------------------------- /gw_app/templates/gw_app/nasmodel_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'gw_app:del' object.pk %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Remove NAS' %} 10 | {% endblock %} 11 | 12 | {% block modal_form_text %} 13 |

14 | {% blocktrans trimmed %} 15 | If you remove this server, then all users than has been 16 | attached to them will lost parent NAS server. 17 | {% endblocktrans %} 18 |

19 | {% endblock %} -------------------------------------------------------------------------------- /group_app/migrations/0003_auto_20180808_1236.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-08-08 12:36 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('group_app', '0002_group_code'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='group', 17 | options={'ordering': ('title',), 'verbose_name': 'Group', 'verbose_name_plural': 'Groups'}, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /group_app/migrations/0002_group_code.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-04-26 15:43 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('group_app', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AddField( 16 | model_name='group', 17 | name='code', 18 | field=models.CharField(blank=True, max_length=12, verbose_name='Tech code'), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /mapapp/migrations/0002_auto_20180808_1236.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-08-08 12:36 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('mapapp', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='dot', 17 | options={'ordering': ('title',), 'permissions': (('can_view', 'Can view'),), 'verbose_name': 'Map point', 'verbose_name_plural': 'Map points'}, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /systemd_units/do_backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PATH=/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin 4 | 5 | cd /var/backups 6 | 7 | file="djing`date "+%Y-%m-%d_%H.%M.%S"`.sql.gz" 8 | 9 | mysql_passw=MYSQL ROOT PASSWORD 10 | 11 | echo show tables | mysql -uroot -p$mysql_passw djingdb | \ 12 | grep -v '^flowstat' | grep -v 'traflost' | grep -v '^Tables' | \ 13 | xargs mysqldump -R -Q --add-locks -uroot --password=$mysql_passw djingdb $1 | gzip > $file 14 | 15 | chmod 400 $file 16 | ./webdav_backup.py $file 17 | 18 | # удаляем старые 19 | find . -name "djing20??-??-??_??.??.??.sql.gz" -mtime +30 -type f -delete 20 | -------------------------------------------------------------------------------- /agent/netflow/netflow_handler.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -z "$1" ]]; then 4 | echo "missing filename" 5 | exit 6 | fi 7 | 8 | PATH=/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin 9 | tmpdir='/tmp/djing_flow' 10 | 11 | if [[ ! -d "$tmpdir" ]]; then 12 | mkdir -p "$tmpdir" 13 | fi 14 | 15 | cd "$tmpdir" 16 | fname=$1 17 | abspath=$(find -name "$fname") 18 | port=`echo "${abspath}" | tr / "\n" | head -2 | tail -n1` 19 | 20 | if [[ -z "$port" ]]; then 21 | echo "$fname not found in any directory" 22 | else 23 | mkdir -p ./dump/${port} 24 | mv ${abspath} ./dump/${port}/${fname}.dmp 25 | fi 26 | -------------------------------------------------------------------------------- /docsapp/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from docsapp import views 3 | 4 | app_name = 'docsapp' 5 | 6 | 7 | urlpatterns = [ 8 | path('', views.DocumentsListView.as_view(), name='docs_list'), 9 | path('add/', views.DocumentCreateView.as_view(), name='doc_add'), 10 | path('/', views.DocumentUpdateView.as_view(), name='doc_edit'), 11 | path('/del/', views.DocumentDeleteView.as_view(), name='doc_del'), 12 | path('//render/', views.RenderDocument.as_view(), name='doc_render'), 13 | path('/simple_list/', views.SimpleListView.as_view(), name='simple_list'), 14 | ] 15 | -------------------------------------------------------------------------------- /finapp/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from finapp.models import PayAllTimeGateway 3 | 4 | 5 | class PayAllTimeGatewayForm(forms.ModelForm): 6 | def __init__(self, *args, **kwargs): 7 | super().__init__(*args, **kwargs) 8 | instance = getattr(self, 'instance') 9 | if instance and instance.pk: 10 | self.fields['slug'].disabled = True 11 | 12 | def clean_slug(self): 13 | if self.instance and self.instance.pk: 14 | return self.instance.slug 15 | return self.data['slug'] 16 | 17 | class Meta: 18 | model = PayAllTimeGateway 19 | fields = '__all__' 20 | -------------------------------------------------------------------------------- /finapp/templates/finapp/ext.htm: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumb %}{% endblock %} 5 | 6 | {% block page-header %} 7 | {% trans 'Payment gateways' %} 8 | {% endblock %} 9 | 10 | {% block main %} 11 | 18 | 19 |
20 |
21 | {% block content %}{% endblock %} 22 |
23 |
24 | {% endblock %} 25 | -------------------------------------------------------------------------------- /taskapp/migrations/0002_auto_20180808_1236.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-08-08 12:36 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('taskapp', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='extracomment', 17 | options={'ordering': ('-date_create',), 'permissions': (('can_view_comments', 'Can view comments'),), 'verbose_name': 'Extra comment', 'verbose_name_plural': 'Extra comments'}, 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /templates/403_for_modal.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 6 | 10 | 13 | -------------------------------------------------------------------------------- /clientsideapp/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = 'clientsideapp' 5 | 6 | urlpatterns = [ 7 | path('', views.home, name='home'), 8 | path('pays/', views.pays, name='pays'), 9 | path('services/', views.services, name='services'), 10 | path('services//buy/', views.buy_service, name='buy_service'), 11 | path('debts/', views.debts_list, name='debts'), 12 | path('debts//', views.debt_buy, name='debt_buy'), 13 | path('tasks/', views.task_history, name='task_history'), 14 | path('set_auto_continue_service/', views.set_auto_continue_service, name='set_auto_continue_service') 15 | ] 16 | -------------------------------------------------------------------------------- /djing/templatetags/globaltags.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import unquote 2 | 3 | from django import template 4 | from django.conf import settings 5 | from django.utils.http import is_safe_url 6 | 7 | register = template.Library() 8 | 9 | 10 | @register.simple_tag 11 | def global_var(var_name): 12 | return getattr(settings, var_name, '') 13 | 14 | 15 | @register.simple_tag 16 | def back_url(request): 17 | url = request.META.get('HTTP_REFERER') 18 | if url: 19 | url = unquote(url) # HTTP_REFERER may be encoded. 20 | if not is_safe_url(url=url, allowed_hosts={request.get_host()}, require_https=request.is_secure()): 21 | url = '/' 22 | return url 23 | -------------------------------------------------------------------------------- /group_app/models.py: -------------------------------------------------------------------------------- 1 | from django.utils.translation import gettext_lazy as _ 2 | from django.shortcuts import resolve_url 3 | from django.db import models 4 | 5 | 6 | class Group(models.Model): 7 | title = models.CharField(_('Title'), max_length=127, unique=True) 8 | code = models.CharField(_('Tech code'), blank=True, max_length=12) 9 | 10 | def get_absolute_url(self): 11 | return resolve_url('group_app:edit', self.pk) 12 | 13 | class Meta: 14 | db_table = 'groups' 15 | verbose_name = _('Group') 16 | verbose_name_plural = _('Groups') 17 | ordering = ('title',) 18 | 19 | def __str__(self): 20 | return self.title 21 | -------------------------------------------------------------------------------- /ip_pool/templates/ip_pool/networkmodel_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base_delete_modal.html' %} 2 | {% load i18n %} 3 | 4 | {% block modal_form_url %} 5 | {% url 'ip_pool:net_delete' object.pk %} 6 | {% endblock %} 7 | 8 | {% block modal_form_title %} 9 | {% trans 'Remove network' %} 10 | {% endblock %} 11 | 12 | {% block modal_form_text %} 13 |

{% blocktrans trimmed with network_name=object %} 14 | To delete network '{{ network_name }}'? 15 | {% endblocktrans %}

16 |

{% blocktrans trimmed %} 17 | Attention! All leases in that network will be removed and services finished. 18 | {% endblocktrans %}

19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_passport_view.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 13 |
14 | -------------------------------------------------------------------------------- /accounts_app/migrations/0004_userprofile_flags.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.3 on 2018-12-24 15:52 2 | 3 | import bitfield.models 4 | from django.db import migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('accounts_app', '0003_new_user_profile_log'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AddField( 15 | model_name='userprofile', 16 | name='flags', 17 | field=bitfield.models.BitField((('notify_task', 'Notification about tasks'), ('notify_msg', 'Notification about messages'), ('notify_mon', 'Notification from monitoring')), default=0, verbose_name='Flags'), 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /agent/downloader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from urllib import request 3 | from hashlib import sha256 4 | 5 | API_AUTH_SECRET = 'your api key' 6 | FILE_LINK = 'http://localhost:8000/dev/nagios/hosts/' 7 | 8 | """ 9 | Example script that downloads config 10 | file from web via api hash. 11 | """ 12 | 13 | 14 | def calc_hash(data): 15 | if type(data) is str: 16 | result_data = data.encode('utf-8') 17 | else: 18 | result_data = bytes(data) 19 | return sha256(result_data).hexdigest() 20 | 21 | 22 | if __name__ == '__main__': 23 | sign = calc_hash(API_AUTH_SECRET) 24 | request.urlretrieve("%s?sign=%s" % (FILE_LINK, sign), 'nagios_objects.cfg') 25 | 26 | -------------------------------------------------------------------------------- /finapp/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from finapp import views 3 | 4 | 5 | app_name = 'finapp' 6 | 7 | urlpatterns = [ 8 | path('', views.AllTimeGatewaysListView.as_view(), name='alltime_gateways_list'), 9 | 10 | path('fin_report/', views.BasicFinReport.as_view(), name='fin_report'), 11 | 12 | path('add/', views.AddAllTimeGateway.as_view(), name='add_alltime_gateway'), 13 | 14 | path('/pay_history/', views.PayHistoryListView.as_view(), name='pay_history'), 15 | 16 | path('/make_pay/', views.AllTimePay.as_view(), name='all_time_pay'), 17 | 18 | path('/edit/', views.EditPayUpdateView.as_view(), name='edit_pay_gw'), 19 | ] 20 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_export.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 13 |
14 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | services: 3 | db: 4 | image: mariadb 5 | restart: always 6 | environment: 7 | - MARIADB_ROOT_PASSWORD=password 8 | - MARIADB_DATABASE=djing_db 9 | - MARIADB_INITDB_SKIP_TZINFO=y 10 | volumes: 11 | - db-data:/var/lib/mysql 12 | - /etc/localtime:/etc/localtime:ro 13 | app: 14 | image: nerosketch/djing:latest 15 | depends_on: 16 | - db 17 | stdin_open: true 18 | tty: true 19 | tmpfs: 20 | - /tmp 21 | volumes: 22 | - media-data:/var/www/djing/media 23 | - /etc/localtime:/etc/localtime:ro 24 | ports: 25 | - 8000:8000 26 | 27 | volumes: 28 | db-data: 29 | media-data: 30 | nginx_logs: 31 | -------------------------------------------------------------------------------- /messenger/templates/messenger/add_messenger.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 8 | 14 | 15 |
16 | -------------------------------------------------------------------------------- /static/bad_ie.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Старый браузер 5 | 6 | 7 | 8 | 9 |

Ваш InternetExplorer устарел, обновите ваш браузер на более современный

10 |

Можете воспользоваться ссылками ниже:

11 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/tarifs.md: -------------------------------------------------------------------------------- 1 | ## Услуги и тарифы 2 | 3 | ### Автопродление услуги 4 | 5 | Кнопка **автопродление услуги** предназначена для того чтоб абоненту не 6 | приходилось каждый месяц заходить в личный кабинет и подключать себе услугу. 7 | Кнопка моделирует поведение когда абонент пополнил счёт, и сразу начал 8 | пользоваться интернетом. Без этого абоненту нужно покупать услугу для доступа в 9 | интернет каждый раз когда старая услуга закончит своё действие. 10 | 11 | Нас транице абонента галочка находится в блоке *Текущая услуга абонента*. Так 12 | же она доступна на странице абонента в личном кабинете. 13 | 14 | Для того чтоб кнопка стала активной достаточно выставить галочку, и не нужно 15 | сохраняться, состояние кнопки сразу же сохранится навсегда в системе. 16 | -------------------------------------------------------------------------------- /tariff_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'tariff_app' 6 | 7 | urlpatterns = [ 8 | path('', views.TariffsListView.as_view(), name='home'), 9 | path('/', views.edit_tarif, name='edit'), 10 | path('/users/', views.ServiceUsers.as_view(), name='service_users'), 11 | path('add/', views.edit_tarif, name='add'), 12 | path('del//', views.TariffDeleteView.as_view(), name='del'), 13 | 14 | path('periodic_pays/', views.PeriodicPaysListView.as_view(), name='periodic_pays'), 15 | path('periodic_pays/add/', views.periodic_pay, name='periodic_pay_add'), 16 | path('periodic_pays//', views.periodic_pay, name='periodic_pay_edit') 17 | ] 18 | -------------------------------------------------------------------------------- /static/clientside/custom.css: -------------------------------------------------------------------------------- 1 | img.navbar-brand { 2 | width: 59px; 3 | height: 50px; 4 | padding: 0; 5 | margin: 0 15px 0 0; 6 | } 7 | 8 | .table thead { 9 | background-color: #ddd; 10 | } 11 | /* White background in tables */ 12 | .table tr:nth-of-type(2n) { 13 | background-color: white; 14 | } 15 | 16 | 17 | 18 | .modal-header{border-radius: 4px 4px 0 0;} 19 | .modal-header.warning {background-color: #d2322d;} 20 | .modal-header.success {background-color: #6ad245;} 21 | .modal-header.primary {background-color: #789cbb;} 22 | 23 | body{ 24 | padding: 88px 15px 0; 25 | } 26 | 27 | 28 | @media (min-width: 768px){ 29 | .dl-horizontal dt { 30 | width: 240px; 31 | } 32 | .dl-horizontal dd{ 33 | margin-left: 260px; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/settings/userprofile_form.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,accounts/settings/ext.htm' %} 2 | {% load globaltags i18n bootstrap3 %} 3 | {% block content %} 4 | 5 |
{% csrf_token %} 6 | 7 | {% bootstrap_form form %} 8 | 9 |
10 | 13 | 16 |
17 | 18 |
19 | 20 | {% endblock %} -------------------------------------------------------------------------------- /ip_pool/forms.py: -------------------------------------------------------------------------------- 1 | from ipaddress import ip_network 2 | 3 | from django import forms 4 | from django.core.exceptions import ValidationError 5 | 6 | from ip_pool import models 7 | 8 | 9 | class NetworkForm(forms.ModelForm): 10 | def clean_network(self): 11 | netw = self.data.get('network') 12 | if netw is None: 13 | return 14 | try: 15 | net = ip_network(netw) 16 | return net.compressed 17 | except ValueError as e: 18 | raise ValidationError(e, code='invalid') 19 | 20 | class Meta: 21 | model = models.NetworkModel 22 | fields = '__all__' 23 | widgets = { 24 | 'groups': forms.SelectMultiple(attrs={ 25 | 'size': 12 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /mapapp/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.utils.translation import gettext_lazy as _ 3 | from devapp.models import Device 4 | 5 | 6 | class Dot(models.Model): 7 | title = models.CharField(_('Map point title'), max_length=127) 8 | latitude = models.FloatField(_('Latitude')) 9 | longitude = models.FloatField(_('Longitude')) 10 | devices = models.ManyToManyField(Device, verbose_name=_('Devices'), db_table='dot_device') 11 | attachment = models.FileField(_('Attachment'), upload_to='map_attachments/%Y_%m_%d', null=True, blank=True) 12 | 13 | class Meta: 14 | db_table = 'dots' 15 | verbose_name = _('Map point') 16 | verbose_name_plural = _('Map points') 17 | ordering = ('title',) 18 | 19 | def __str__(self): 20 | return self.title 21 | -------------------------------------------------------------------------------- /taskapp/templatetags/tasktags.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | from datetime import datetime, date 3 | from django import template 4 | 5 | register = template.Library() 6 | 7 | 8 | @register.simple_tag 9 | def is_today(time: datetime): 10 | if type(time) is not datetime: 11 | raise TypeError 12 | now = datetime.now() 13 | return now.day == time.day 14 | 15 | 16 | @register.simple_tag 17 | def is_yesterday(time: datetime): 18 | if type(time) is not datetime: 19 | raise TypeError 20 | now = datetime.now() 21 | return now.day - 1 == time.day 22 | 23 | 24 | @register.filter 25 | def is_current_year(time: Union[datetime, date]): 26 | if not isinstance(time, (datetime, date)): 27 | raise TypeError 28 | now = datetime.now() 29 | return now.year == time.year 30 | -------------------------------------------------------------------------------- /new_customers/templates/new_customers/potentialsubscriber_form.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 8 | 17 |
18 | -------------------------------------------------------------------------------- /djing/templatetags/dpagination.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | register = template.Library() 4 | 5 | 6 | @register.simple_tag 7 | def url_page_replace(request, field, value): 8 | dict_ = request.GET.copy() 9 | dict_[field] = str(value) 10 | return dict_.urlencode() 11 | 12 | 13 | @register.simple_tag 14 | def url_order_by(request, **kwargs): 15 | dict_ = request.GET.copy() 16 | for k, v in kwargs.items(): 17 | dict_[k] = v 18 | direction = dict_.get('dir') 19 | if direction is None: 20 | direction = dict_.get('default_direction', 'up') 21 | if direction == 'down': 22 | direction = 'up' 23 | elif direction == 'up': 24 | direction = 'down' 25 | else: 26 | direction = '' 27 | dict_['dir'] = direction 28 | return dict_.urlencode() 29 | -------------------------------------------------------------------------------- /group_app/templates/group_app/ext.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans 'Groups' %}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 12 | {% endblock %} 13 | 14 | 15 | {% block page-header %} 16 | {% trans 'Groups' %} 17 | {% endblock %} 18 | 19 | 20 | {% block main %} 21 |
22 |
23 | {% block content %}{% endblock %} 24 |
25 |
26 | {% endblock %} 27 | -------------------------------------------------------------------------------- /docsapp/models.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import resolve_url 2 | from django.utils.translation import gettext_lazy as _ 3 | from django.core.validators import FileExtensionValidator 4 | from django.db import models 5 | 6 | from abonapp.models import Abon 7 | 8 | 9 | class DocumentTemplateModel(models.Model): 10 | title = models.CharField(_('Title'), max_length=80, unique=True) 11 | doc_template = models.FileField( 12 | _('File docx template'), upload_to='word_docs', 13 | validators=[FileExtensionValidator(allowed_extensions=('docx',))] 14 | ) 15 | 16 | def get_absolute_url(self): 17 | return resolve_url('docsapp:doc_edit', pk=self.pk) 18 | 19 | def __str__(self): 20 | return self.title 21 | 22 | class Meta: 23 | db_table = 'documents' 24 | ordering = ('title',) 25 | -------------------------------------------------------------------------------- /devapp/templates/devapp/manage_ports/modal_del_port.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 |
{% csrf_token %} 4 | 5 | 9 | 10 | 17 | 18 |
19 | -------------------------------------------------------------------------------- /ip_pool/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from ip_pool import views 3 | from ip_pool import models 4 | 5 | app_name = 'ip_pool' 6 | 7 | urlpatterns = [ 8 | path('', views.NetworksListView.as_view(), name='networks'), 9 | path('network_add/', views.NetworkCreateView.as_view(), name='net_add'), 10 | path('/edit/', views.NetworkUpdateView.as_view(), name='net_edit'), 11 | path('/del/', views.NetworkDeleteView.as_view(), name='net_delete'), 12 | path('/group_attach/', views.network_in_groups, name='net_groups') 13 | ] 14 | 15 | for dev_kind_code, _ in models.NetworkModel.NETWORK_KINDS: 16 | _url_name = 'networks_%s/' % dev_kind_code 17 | urlpatterns.append(path( 18 | _url_name, 19 | views.NetworksListView.as_view(device_kind_code=dev_kind_code), 20 | name=_url_name 21 | )) 22 | -------------------------------------------------------------------------------- /messenger/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from messenger import models 3 | 4 | 5 | class MessengerForm(forms.ModelForm): 6 | class Meta: 7 | model = models.Messenger 8 | fields = ('bot_type',) 9 | 10 | 11 | class MessengerViberForm(forms.ModelForm): 12 | def __init__(self, *args, **kwargs): 13 | kwargs['initial']['bot_type'] = 1 14 | super().__init__(*args, **kwargs) 15 | inst = getattr(self, 'instance') 16 | if inst: 17 | self.fields['bot_type'].disabled = True 18 | #self.fields['bot_type'].widget.attrs['disabled'] = True 19 | 20 | class Meta: 21 | model = models.ViberMessenger 22 | fields = '__all__' 23 | 24 | 25 | class MessengerViberMessageForm(forms.ModelForm): 26 | class Meta: 27 | model = models.ViberMessage 28 | fields = '__all__' 29 | -------------------------------------------------------------------------------- /taskapp/templates/taskapp/comments/extracomment_confirm_delete.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
{% csrf_token %} 3 | 4 | 8 | 9 | 12 | 13 | 18 | 19 |
20 | -------------------------------------------------------------------------------- /msg_app/templates/msg_app/modal_new_conversation.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 8 | 19 | 20 |
21 | -------------------------------------------------------------------------------- /group_app/templates/group_app/add_group.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,group_app/ext.html' %} 2 | {% load i18n bootstrap3%} 3 | {% block active_text %}{% trans 'Add group' %}{% endblock %} 4 | {% block content %} 5 |
{% csrf_token %} 6 | 10 | 13 | 18 |
19 | {% endblock %} -------------------------------------------------------------------------------- /group_app/templates/group_app/edit_group.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,group_app/ext.html' %} 2 | {% load i18n bootstrap3 %} 3 | {% block active_text %}{% trans 'Edit group' %}{% endblock %} 4 | {% block content %} 5 |
{% csrf_token %} 6 | 10 | 13 | 18 |
19 | {% endblock %} -------------------------------------------------------------------------------- /msg_app/migrations/0002_auto_20180808_1236.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-08-08 12:36 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('msg_app', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='conversation', 17 | options={'ordering': ('title',), 'permissions': (('can_view_conversation', 'Can view conversation'),), 'verbose_name': 'Conversation', 'verbose_name_plural': 'Conversations'}, 18 | ), 19 | migrations.AlterModelOptions( 20 | name='message', 21 | options={'ordering': ('-sent_at',), 'permissions': (('can_view_messages', 'Can view messages'),), 'verbose_name': 'Message', 'verbose_name_plural': 'Messages'}, 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /group_app/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-02-26 00:20 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='Group', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('title', models.CharField(max_length=127, unique=True, verbose_name='Title')), 20 | ], 21 | options={ 22 | 'verbose_name': 'Group', 23 | 'verbose_name_plural': 'Groups', 24 | 'db_table': 'groups', 25 | 'ordering': ('title',), 26 | }, 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_current_networks.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {% for net_item in networks %} 16 | 17 | 18 | 19 | 20 | {% empty %} 21 | 22 | 23 | 24 | {% endfor %} 25 | 26 |
{% trans 'Network' %}{% trans 'Scope' %}
{{ net_item }}{{ net_item.get_scope }}
{% trans 'Available networks not found' %}
27 | -------------------------------------------------------------------------------- /mapapp/templates/maps/modal_add_device.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 12 | 20 |
21 | -------------------------------------------------------------------------------- /taskapp/templates/taskapp/footer_btns.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 | 4 | {% if perms.taskapp.add_task %} 5 | 6 | {% trans 'Add new task' %} 7 | 8 | {% endif %} 9 | 10 | {% if perms.taskapp.can_viewall %} 11 | 12 | {% trans 'View all tasks' %} 13 | 14 | 15 | {% trans 'View all new tasks' %} 16 | 17 | {% endif %} 18 | 19 | 20 | {% trans 'View empty tasks' %} 21 | 22 | 23 |
24 | -------------------------------------------------------------------------------- /templates/base_delete_modal.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
{% csrf_token %} 3 | 10 | 19 |
20 | -------------------------------------------------------------------------------- /Doc.txt: -------------------------------------------------------------------------------- 1 | Состояние оплаты абонента определяется на основе присутствия у него тарифного плана, 2 | если тариф есть - то значит всё оплачено (абонент его купил) и может пользоваться услугами. 3 | Тарифный план имеет срок действия и стоимость. Его можно купить как билет :) 4 | 5 | 6 | Тарифный план, у которого есть дата начала является активным 7 | 8 | 9 | Свою логику расчёта по тарифу можно добавить в файле tariff_app/custom_tariffs.py 10 | Там надо добавить класс, наследованный от TariffBase и реализовать его абстрактные методы, 11 | потом добавить этот класс в кортеж TARIFF_CHOICES указав: 12 | код из 2х букв, сочетание должно быть уникальным 13 | и ваш класс для своей логики расчёта тарифа 14 | 15 | ВАЖНО! Для отработки своевременного выключения услуги, время на сервере биллинга и шлюза должно быть настроено точно. 16 | 17 | Таблицу кеша статистики лучше сделать в памяти т.к. будет часто обновляться 18 | ALTER TABLE flowcache ENGINE=MEMORY; 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # djing 2 | Бесплатная биллинговая система интернет провайдера. djing сокращение от **dj**ango-bill**ing**. Это web интерфейс управления абонентами 3 | интернет-провайдера. 4 | Сейчас идёт тестирование работы на Mikrotik, функционал пока минимальный, т.к. пишу в свободное время. 5 | Работает в реальной сети на реальных абонентах. 6 | Использовано python 3, django 2, bootstrap 3, и другое в файле requirements.txt 7 | 8 | ## Содержание 9 | ### Для пользователя 10 | * [Инструкция пользователя](./docs/user/user_doc.md) 11 | 12 | ### Для администратора 13 | * [Установка](./docs/install_debian.md) 14 | * [Сервисы и API](./docs/services.md) 15 | * [Менеджеры устройств](./docs/dev.md) 16 | * [Сбор информации трафика по netflow](./docs/netflow.md) 17 | * [Работа с представлениями](./docs/views.md) 18 | * [Карта](./docs/map.md) 19 | * [DHCP](./docs/dhcp.md) 20 | * [Страница абонента](./docs/user_page.md) 21 | * [Дополнительный функционал](./docs/extra_func.md) 22 | -------------------------------------------------------------------------------- /gw_app/migrations/0002_auto_20181101_1545.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1 on 2018-11-01 15:45 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('gw_app', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterModelOptions( 14 | name='nasmodel', 15 | options={'ordering': ('ip_address',), 'verbose_name': 'Network access server. Gateway', 'verbose_name_plural': 'Network access servers. Gateways'}, 16 | ), 17 | migrations.AlterField( 18 | model_name='nasmodel', 19 | name='auth_login', 20 | field=models.CharField(max_length=64, verbose_name='Auth login'), 21 | ), 22 | migrations.AlterField( 23 | model_name='nasmodel', 24 | name='auth_passw', 25 | field=models.CharField(max_length=127, verbose_name='Auth password'), 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /devapp/templates/devapp/manage_ports/modal_add_edit_port.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 | 3 | {% if object %} 4 | {% url 'devapp:edit_port' gid did object.pk as frm_url %} 5 | {% trans 'Edit' as modal_title %} 6 | {% else %} 7 | {% url 'devapp:add_port' gid did as frm_url %} 8 | {% trans 'Add' as modal_title %} 9 | {% endif %} 10 | 11 |
{% csrf_token %} 12 | 13 | 14 | 18 | 19 | 23 | 24 |
25 | -------------------------------------------------------------------------------- /docs/notifications.md: -------------------------------------------------------------------------------- 1 | ### Подключение мониторинга 2 | Для того чтобы отправлять события из мониторинга в биллинг можно воспользоваться скриптом **agent/monitoring_agent.py**. 3 | Скопируйте его в место, откуда он будет доступен мониторингу, задайте права, сделайте исполняемым. Так же его надо 4 | отредактировать, 2 параметра: *API_AUTH_SECRET* и *SERVER_DOMAIN*. 5 | 6 | **API_AUTH_SECRET** — Параметр с таким же именем есть в настройках биллинга, это секретное слово для авторизации 7 | скриптов, сгенерируйте секретное слово посложнее если сами настраивайте весь биллинг или узнайте его в настройках 8 | биллинга если оно уже есть. 9 | 10 | **SERVER_DOMAIN** — Полный url к биллингу по http\[s\]. 11 | 12 | Скрипт отправляет *HTTP GET* запросы с параметрами, например: 13 | http://domain/dev/on_device_event/?mac=ff:ff:ff:ff:ff:ff&status=\[UP|DOWN|UNREACHABLE\]&sign=\. 14 | 15 | После этого биллинг отмечает состояние устройства и рассылает оповещения для тех у кого эти оповещения включены. 16 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_abonamount.html: -------------------------------------------------------------------------------- 1 | {% load bootstrap3 i18n %} 2 |
{% csrf_token %} 3 | 7 | 8 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /docsapp/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.4 on 2019-09-12 12:52 2 | 3 | import django.core.validators 4 | from django.db import migrations, models 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='DocumentTemplateModel', 17 | fields=[ 18 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 19 | ('title', models.CharField(max_length=80, verbose_name='Title', unique=True)), 20 | ('doc_template', models.FileField(upload_to='word_docs', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=('docx',))], verbose_name='File docx template')), 21 | ], 22 | options={ 23 | 'db_table': 'documents', 24 | 'ordering': ('title',), 25 | }, 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /messenger/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from django.views.decorators.csrf import csrf_exempt 3 | 4 | from messenger import views 5 | 6 | 7 | app_name = 'messenger' 8 | 9 | urlpatterns = [ 10 | path('', views.MessengerListView.as_view(), name='messengers_list'), 11 | path('new/', views.AddMessengerCreateView.as_view(), name='add_messenger'), 12 | path('viber/new/', views.AddMessengerViberCreateView.as_view(), name='add_viber_messenger'), 13 | path('viber//update/', views.UpdateViberMessengerUpdateView.as_view(), name='update_viber_messenger'), 14 | path('viber//delete/', views.RemoveViberMessengerDeleteView.as_view(), name='delete_viber_messenger'), 15 | path('viber//listen/', csrf_exempt(views.ListenViberView.as_view()), name='listen_viber_bot'), 16 | path('viber//set_webhook/', views.SetWebhook.as_view(), name='webhook_viber_bot'), 17 | path('viber//subscribers/', views.SubscribersListView.as_view(), name='subscribers'), 18 | ] 19 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_addstreet.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 8 | {% include '_messages.html' %} 9 | 10 | 23 | 24 |
25 | -------------------------------------------------------------------------------- /clientsideapp/templates/clientsideapp/pays.html: -------------------------------------------------------------------------------- 1 | {% extends 'clientsideapp/ext.html' %} 2 | {% load i18n %} 3 | {% block client_main %} 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for pay in pay_history %} 18 | 19 | 20 | 21 | 22 | 23 | {% empty %} 24 | 25 | 26 | 27 | {% endfor %} 28 | 29 |
{% trans 'Transaction Amount (rubles)' %}{% trans 'Date of transaction' %}{% trans 'Comment' %}
{{ pay.amount }}{{ pay.date|date:'d b H:i' }}{{ pay.comment }}
{% trans 'You have not spent payments' %}
30 | 31 | {% endblock %} -------------------------------------------------------------------------------- /djing/lib/mixins.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin 2 | from guardian.mixins import PermissionRequiredMixin 3 | 4 | 5 | class OnlySuperUserMixin(AccessMixin): 6 | """Verify that the current user is superuser.""" 7 | def dispatch(self, request, *args, **kwargs): 8 | if not request.user.is_superuser: 9 | return self.handle_no_permission() 10 | return super().dispatch(request, *args, **kwargs) 11 | 12 | 13 | class OnlyAdminsMixin(AccessMixin): 14 | """Verify that the current user is admin.""" 15 | def dispatch(self, request, *args, **kwargs): 16 | if not request.user.is_admin: 17 | return self.handle_no_permission() 18 | return super().dispatch(request, *args, **kwargs) 19 | 20 | 21 | class LoginAdminMixin(LoginRequiredMixin, OnlyAdminsMixin): 22 | pass 23 | 24 | 25 | class LoginAdminPermissionMixin(LoginRequiredMixin, OnlyAdminsMixin, 26 | PermissionRequiredMixin): 27 | return_403 = True 28 | -------------------------------------------------------------------------------- /install/nginx_server.conf: -------------------------------------------------------------------------------- 1 | upstream djing{ 2 | server unix:///run/uwsgi/app/djing/socket; 3 | } 4 | 5 | # Для обращений в web серверу на localhost из скриптов 6 | server { 7 | listen 80; 8 | server_name localhost 127.0.0.1; 9 | location / { 10 | uwsgi_pass djing; 11 | include uwsgi_params; 12 | } 13 | access_log /dev/null; 14 | error_log /dev/null; 15 | } 16 | 17 | 18 | # обработка http запросов. 19 | server { 20 | listen 80 default_server; 21 | server_name _; 22 | root /var/www/djing/; 23 | charset utf-8; 24 | 25 | location = /favicon.ico { alias /var/www/djing/static/img/favicon_m.ico; } 26 | location = /robots.txt { alias /var/www/djing/robots.txt; } 27 | 28 | location /media { 29 | alias /var/www/djing/media; 30 | expires 7d; 31 | } 32 | 33 | location /static { 34 | alias /var/www/djing/static; 35 | expires 1d; 36 | } 37 | 38 | location / { 39 | uwsgi_pass djing; 40 | include uwsgi_params; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /mapapp/templates/maps/map_tooltip.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |

{{ dot.title }}

3 | 19 | 20 | {% if dot.attachment %} 21 | 22 | {{ dot.attachment.name }} 23 | {% endif %} 24 | -------------------------------------------------------------------------------- /mapapp/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from django.urls import path 3 | 4 | from . import views 5 | 6 | app_name = 'mapapp' 7 | 8 | urlpatterns = [ 9 | path('', views.home, name='home'), 10 | path('options/', views.OptionsListView.as_view(), name='options'), 11 | path('options/add/', views.dot_edit, name='add_dot'), 12 | path('options//edit/', views.dot_edit, name='edit_dot'), 13 | path('options//remove/', views.remove, name='remove_dot'), 14 | path('options//add_dev/', views.add_dev, name='add_dev'), 15 | path('preload_devices/', views.preload_devices, name='preload_devices'), 16 | path('get_dots/', views.get_dots, name='get_dots'), 17 | 18 | path('modal_add_dot/', views.modal_add_dot, name='modal_add_dot'), 19 | path('j_dot_tooltip/', views.dot_tooltip, name='dot_tooltip'), 20 | path('resolve_dots_by_group//', views.resolve_dots_by_group, name='resolve_dots_by_group'), 21 | 22 | path('to_single_dev/', views.to_single_dev, name='to_single_dev') 23 | ] 24 | -------------------------------------------------------------------------------- /accounts_app/migrations/0002_auto_20180807_1548.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-08-07 15:48 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('accounts_app', '0001_squashed_0003_auto_20180425_1135'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='baseaccount', 17 | options={'ordering': ('username',)}, 18 | ), 19 | migrations.AlterModelOptions( 20 | name='userprofile', 21 | options={'ordering': ('fio',), 'permissions': (('can_view_userprofile', 'Can view staff profile'),), 'verbose_name': 'Staff account profile', 'verbose_name_plural': 'Staff account profiles'}, 22 | ), 23 | migrations.AlterField( 24 | model_name='userprofile', 25 | name='email', 26 | field=models.EmailField(default='', max_length=254), 27 | ), 28 | ] 29 | -------------------------------------------------------------------------------- /docsapp/templates/docsapp/simple_list.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | 7 | 27 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_phonebook.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | {% for t in tels %} 16 | 17 | 18 | 19 | 20 | {% empty %} 21 | 22 | 23 | 24 | {% endfor %} 25 | 26 |
{% trans 'Telephone' %}{% trans 'Telephone owner' %}
{{ t.0 }}{{ t.1 }}
{% trans 'Telephone numbers not found' %}
27 | 28 | 33 | -------------------------------------------------------------------------------- /devapp/tasks.py: -------------------------------------------------------------------------------- 1 | from typing import Iterable 2 | from subprocess import run 3 | from celery import shared_task 4 | from devapp.models import Device 5 | 6 | 7 | @shared_task 8 | def onu_register(device_ids: Iterable[int]): 9 | with open('/etc/dhcp/macs.conf', 'w') as f: 10 | for dev_id in device_ids: 11 | dev = Device.objects.get(pk=dev_id) 12 | if not dev.has_attachable_to_subscriber() or dev.mac_addr is None: 13 | continue 14 | group_code = dev.group.code 15 | if not group_code: 16 | continue 17 | try: 18 | mn = dev.get_manager_klass() 19 | dev_code = mn.tech_code 20 | f.write('subclass "%(group_code)s.%(dev_code)s" "%(mac)s";\n' % { 21 | 'group_code': group_code, 22 | 'mac': dev.mac_addr, 23 | 'dev_code': dev_code 24 | }) 25 | except TypeError: 26 | continue 27 | run(('/usr/bin/sudo', 'systemctl', 'restart', 'isc-dhcp-server.service')) 28 | -------------------------------------------------------------------------------- /djing/lib/messaging/sms/wap.py: -------------------------------------------------------------------------------- 1 | # See LICENSE 2 | 3 | from array import array 4 | 5 | from djing.lib.messaging import MMSDecoder 6 | 7 | 8 | def is_a_wap_push_notification(s): 9 | if not isinstance(s, str): 10 | raise TypeError("data must be an array.array serialised to string") 11 | 12 | data = array("B", s) 13 | 14 | try: 15 | return data[1] == 0x06 16 | except IndexError: 17 | return False 18 | 19 | 20 | def extract_push_notification(s): 21 | data = array("B", s) 22 | 23 | wap_push, offset = data[1:3] 24 | assert wap_push == 0x06 25 | 26 | offset += 3 27 | data = data[offset:] 28 | 29 | # XXX: Not all WAP pushes are MMS 30 | return MMSDecoder().decode_data(data) 31 | 32 | 33 | def is_mms_notification(push): 34 | # XXX: Pretty poor, but until we decode generic WAP pushes 35 | # it will have to suffice. Ideally we would read the 36 | # content-type from the WAP push header and test 37 | return (push.headers.get('From') is not None and 38 | push.headers.get('Content-Location') is not None) 39 | -------------------------------------------------------------------------------- /devapp/templates/devapp/modal_device_extra_edit.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n bootstrap3 %} 3 | {% block main %} 4 |
{% csrf_token %} 5 | 9 | 21 |
22 | {% endblock %} -------------------------------------------------------------------------------- /gw_app/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.core.exceptions import ValidationError 3 | from django.utils.translation import gettext_lazy as _ 4 | from gw_app.models import NASModel 5 | from djing import IP_ADDR_REGEX 6 | 7 | 8 | class NasForm(forms.ModelForm): 9 | 10 | def clean_default(self): 11 | cd = self.cleaned_data 12 | default = cd.get('default') 13 | if default: 14 | try: 15 | if self.instance: 16 | NASModel.objects.filter(default=True).exclude(pk=self.instance.pk).get() 17 | else: 18 | NASModel.objects.get(default=True).exclude(pk=1).get() 19 | raise ValidationError(message=_('Can be only one default gateway'), code='unique') 20 | except NASModel.DoesNotExist: 21 | pass 22 | return default 23 | 24 | class Meta: 25 | model = NASModel 26 | fields = '__all__' 27 | widgets = { 28 | 'ip_address': forms.TextInput(attrs={ 29 | 'pattern': IP_ADDR_REGEX 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/perms/change_global_perms.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,accounts/perms/ext.html' %} 2 | {% load i18n bootstrap3 %} 3 | 4 | {% block breadcrumb %} 5 | 12 | {% endblock %} 13 | 14 | {% block page-header %} 15 | {% trans 'Select permissions for picked account' %} 16 | {% endblock %} 17 | 18 | {% block content %} 19 |
{% csrf_token %} 20 | {% bootstrap_form form %} 21 | {% bootstrap_button _('Save') button_type='submit' button_class='btn-primary' %} 22 |
23 | {% endblock %} -------------------------------------------------------------------------------- /traf_stat/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2019-03-06 18:07 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | import traf_stat.fields 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ('abonapp', '0001_squashed_0008_auto_20181115_1206'), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='StatCache', 19 | fields=[ 20 | ('last_time', traf_stat.fields.UnixDateTimeField()), 21 | ('abon', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='abonapp.Abon')), 22 | ('octets', models.PositiveIntegerField(default=0)), 23 | ('packets', models.PositiveIntegerField(default=0)), 24 | ], 25 | options={ 26 | 'db_table': 'flowcache', 27 | 'ordering': ('-last_time',), 28 | }, 29 | ), 30 | migrations.RunSQL(sql=(r'ALTER TABLE flowcache ENGINE=MEMORY;',)) 31 | ] 32 | -------------------------------------------------------------------------------- /docs/user_page.md: -------------------------------------------------------------------------------- 1 | ## Особенности страницы абонента. 2 | Находится она в разделе **Абоненты** внутри группы. На этой странице вы увидите несколько логических блоков, 3 | из которых самые важные, пожалуй, 2. Первый это **Изменение абонента** а второй **Выберите устройство**. 4 | На первом блоке можно редактировать базовую информацию абонента. Если снять галку *Активен* то абонент перестанет 5 | получать услуги даже при подключённой услуге. 6 | 7 | Блок с устройством содержит то самое устройство, к которому подключён абонент. Если это устройство не будет назначено 8 | то биллинг не сможет авторизовать абонента по dhcp option.82. Галочка **Динамические настройки по dhcp** означает что 9 | учётная запись абонента сможет получать динамический ip. Это означает что если галка не будет выставлена, то сколько бы 10 | запросов не приходило с этого устройства абонент не изменить свой ip, это полезно когда абонент работает со статическим 11 | ip. 12 | 13 | Вверху есть вкладки. с соответствующим названию функционалом. Например на вкладке **Тарифы** вы можете назначить 14 | абоненту услугу или добавить периодический платёж, который абонент увидит в своём личном кабинете. 15 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_add_phone.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 8 | 25 | 26 |
27 | -------------------------------------------------------------------------------- /accounts_app/templatetags/acc_tags.py: -------------------------------------------------------------------------------- 1 | from ipaddress import ip_address, AddressValueError 2 | 3 | from django import template 4 | from django.db.models import Model 5 | from django.apps import apps 6 | from abonapp.models import Abon 7 | from six import string_types, class_types 8 | 9 | register = template.Library() 10 | 11 | 12 | @register.simple_tag 13 | def klass_name(klass): 14 | if type(klass) is class_types and issubclass(klass, Model): 15 | kl = klass 16 | elif isinstance(klass, string_types): 17 | app_label, model_name = klass.split('.', 1) 18 | kl = apps.get_model(app_label, model_name) 19 | else: 20 | return 'Type not detected' 21 | return kl._meta.verbose_name 22 | 23 | 24 | @register.simple_tag 25 | def can_login_by_location(request): 26 | try: 27 | remote_ip = ip_address(request.META.get('REMOTE_ADDR')) 28 | if remote_ip.version == 4: 29 | has_exist = Abon.objects.filter( 30 | ip_address=str(remote_ip), 31 | is_active=True 32 | ).exists() 33 | return has_exist 34 | except AddressValueError: 35 | pass 36 | return False 37 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/action_log.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %} 2 | {% load i18n %} 3 | 4 | {% block content %} 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% for log in object_list %} 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% empty %} 24 | 25 | {% endfor %} 26 | 27 |
{% trans 'Date' %}{% trans 'Additional' %}{% trans 'Description' %}{% trans 'Meta information' %}
{{ log.action_date|date:'D d E Y H:i:s' }}{{ log.additional_text|default_if_none:'-' }}{{ log.get_do_type_display }}{{ log.meta_info }}
{% trans 'That admin has no logs' %}
28 |
29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/set_abon_groups_permission.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %} 2 | {% load i18n %} 3 | {% block content %} 4 | 5 | {% trans 'The list of user groups to which the account has access' %} 6 |
{% csrf_token %} 7 | {% for grp in groups %} 8 |
9 | 17 |
18 | {% endfor %} 19 |
20 | 21 | 22 |
23 |
24 | 25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /gw_app/templates/gw_app/nasmodel_add.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n bootstrap3 %} 3 | 4 | {% block title %}{% trans 'Add new gateway' %}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 12 | {% endblock %} 13 | 14 | {% block page-header %} 15 | {% trans 'Add new gateway' %} 16 | {% endblock %} 17 | 18 | {% block main %} 19 |
20 |
21 |

{% trans 'Add gateway' %}

22 |
23 |
24 |
{% csrf_token %} 25 | {% bootstrap_form form %} 26 | 29 |
30 |
31 |
32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/manage_responsibility_groups.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %} 2 | {% load i18n %} 3 | {% block content %} 4 | 5 | {% trans 'The responsibility of the administrator of the group of subscribers' %} 6 |
{% csrf_token %} 7 | {% for grp in groups %} 8 |
9 | 17 |
18 | {% endfor %} 19 |
20 | 21 | 22 |
23 |
24 | 25 | {% endblock %} 26 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_periodic_pay.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
{% csrf_token %} 3 | 7 | 8 | {% include '_messages.html' %} 9 | 10 | 27 | 28 |
29 | -------------------------------------------------------------------------------- /devapp/expect_scripts/dlink_DGS1100_reboot.exp: -------------------------------------------------------------------------------- 1 | #!/usr/bin/expect -f 2 | 3 | if { $argc <4 } { 4 | puts "Usage: dlink_reboot.exp \n" 5 | exit 2 6 | } 7 | 8 | set timeout -1 9 | set ip [lindex $argv 0] 10 | set login [lindex $argv 1] 11 | set passw [lindex $argv 2] 12 | set is_save [lindex $argv 3] 13 | 14 | spawn telnet -4 $ip 15 | 16 | expect { 17 | "UserName:" { 18 | send -- "$login\r" 19 | set prmpt "DGS-1100-06/ME:5" 20 | } 21 | "DGS-1100-10/ME login: " { 22 | send -- "$login\r" 23 | set prmpt "DGS-1100-10/ME:5" 24 | } 25 | } 26 | 27 | expect -exact "Password: " 28 | send -- "$passw\r" 29 | 30 | expect { 31 | "Incorrect Login/Password" { 32 | puts "Wrong password" 33 | exit 1 34 | } 35 | "$prmpt# " { 36 | puts "Login ok" 37 | } 38 | } 39 | 40 | if { $is_save == 1 } { 41 | puts "Save" 42 | send -- "save\r" 43 | } elseif { $is_save == 0 } { 44 | puts "Without save" 45 | } else { 46 | puts "Unexpected choice" 47 | exit 2 48 | } 49 | 50 | 51 | send -- "reboot\r" 52 | expect "Are you sure you want to proceed with the system reboot" 53 | 54 | send -- "y\r" 55 | expect -exact "rebooting" 56 | 57 | expect eof 58 | -------------------------------------------------------------------------------- /tariff_app/templates/tariff_app/ext.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans 'Services' %}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 11 | {% endblock %} 12 | 13 | {% block page-header %} 14 | {% trans 'Services' %} 15 | {% endblock %} 16 | 17 | {% block main %} 18 | 35 | 36 |
37 |
38 | {% block content %}{% endblock %} 39 |
40 |
41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_attach_nas.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
{% csrf_token %} 3 | 7 | 8 | 26 | 27 |
28 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | urllib3==1.25.10 2 | Django==2.2.17 3 | Pillow==7.2.0 4 | 5 | # for mac address field 6 | netaddr==0.8.0 7 | 8 | # for testing required xmltodict 9 | #xmltodict 10 | dicttoxml==1.7.4 11 | 12 | # db client for Mariadb 13 | mysqlclient 14 | 15 | https://github.com/nerosketch/easysnmp/archive/refs/tags/0.2.5.zip#egg=easysnmp 16 | pid==3.0.4 17 | django-guardian==2.3.0 18 | pinax-theme-bootstrap==8.0.1 19 | django-bootstrap3==14.1.0 20 | 21 | jsonfield 22 | 23 | requests==2.24.0 24 | webdavclient==1.0.8 25 | transliterate==1.10.2 26 | django-encrypted-model-fields==0.5.8 27 | 28 | # django-xmlview for pay system allpay 29 | https://github.com/nerosketch/django-xmlview/archive/refs/tags/v0.0.2.zip#egg=django-xmlview 30 | 31 | # django-bitfield 32 | https://github.com/disqus/django-bitfield/archive/refs/tags/2.2.0.zip#egg=django-bitfield 33 | 34 | # django_cleanup for clean unused media 35 | https://github.com/un1t/django-cleanup/archive/refs/tags/6.0.0.zip#egg=django_cleanup 36 | 37 | # viberbot 38 | https://github.com/Viber/viber-bot-python/archive/refs/tags/1.0.11.zip#egg=viberbot 39 | 40 | # pexpect 41 | https://github.com/pexpect/pexpect/archive/refs/tags/4.8.0.zip#egg=pexpect 42 | 43 | Celery 44 | redis==3.5.3 45 | celery[redis] 46 | 47 | docxtpl 48 | gunicorn 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /clientsideapp/templates/clientsideapp/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'clientsideapp/ext.html' %} 2 | {% load i18n %} 3 | 4 | {% block client_main %} 5 | 6 |
7 |
{% trans 'Account info' %}
8 |
9 | {% with user=request.user %} 10 |
11 |
{% trans 'Username' %}
12 |
{{ user.username }}
13 | 14 |
{% trans 'fio' %}
15 |
{{ user.fio }}
16 | 17 |
{% trans 'Primary telephone' %}
18 |
{{ user.telephone }}
19 | 20 |
{% trans 'Ip Address' %}
21 |
{{ user.ip_address|default:'-' }}
22 | 23 | {% if user.street %} 24 |
{% trans 'Address' %}
25 |
{{ user.street.name }}, {{ user.house|default:'' }}
26 | {% endif %} 27 | 28 | {% if num_active_tasks > 0 %} 29 |
{% trans 'Num of active tasks' %}
30 |
{{ num_active_tasks }}
31 | {% endif %} 32 | 33 |
34 | {% endwith %} 35 |
36 |
37 | 38 | {% include 'custom_pages/main_page.htm' %} 39 | {% endblock %} 40 | -------------------------------------------------------------------------------- /templates/pagination.html: -------------------------------------------------------------------------------- 1 | {% if paginator.num_pages > 1 %} 2 | {% load dpagination %} 3 |
4 |
5 | 24 |
25 |
26 | {% endif %} 27 | -------------------------------------------------------------------------------- /mapapp/templates/maps/modal_add_dot.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 globaltags %} 2 |
{% csrf_token %} 3 | 4 | 8 | 23 | 28 |
29 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_ip_form.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n bootstrap3 %} 3 | 4 | {% block breadcrumb %} 5 | 12 | {% endblock %} 13 | 14 | {% block main %} 15 |
{% csrf_token %} 16 | 20 | 26 |
27 | {% endblock %} -------------------------------------------------------------------------------- /djing/formfields.py: -------------------------------------------------------------------------------- 1 | from django.forms import CharField 2 | from django.forms.widgets import TextInput 3 | from django.core.validators import RegexValidator, _lazy_re_compile 4 | from django.forms.fields import EMPTY_VALUES 5 | from django.forms.utils import ValidationError 6 | from django.utils.translation import gettext_lazy as _ 7 | from netaddr import EUI, AddrFormatError 8 | from . import MAC_ADDR_REGEX 9 | 10 | mac_address_validator = RegexValidator( 11 | _lazy_re_compile(MAC_ADDR_REGEX), 12 | message=_('Enter a valid integer.'), 13 | code='invalid', 14 | ) 15 | 16 | 17 | class MACAddressField(CharField): 18 | widget = TextInput 19 | default_validators = [mac_address_validator] 20 | default_error_messages = { 21 | 'invalid': _('Enter a valid MAC Address.'), 22 | } 23 | 24 | def clean(self, value): 25 | """ 26 | Validates that EUI() can be called on the input. Returns the result 27 | of EUI(). Returns None for empty values. 28 | """ 29 | value = super(MACAddressField, self).clean(value) 30 | if value in EMPTY_VALUES: 31 | return None 32 | try: 33 | value = EUI(str(value), version=48) 34 | except (ValueError, TypeError, AddrFormatError): 35 | raise ValidationError(self.error_messages['invalid']) 36 | return value 37 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-alpine 2 | LABEL maintainer="nerosketch@gmail.com" 3 | 4 | ENV PYTHONUNBUFFERED 1 5 | ENV PYTHONOPTIMIZE 1 6 | ENV PYTHONIOENCODING UTF-8 7 | ENV DJANGO_SETTINGS_MODULE djing.settings 8 | ENV PYCURL_SSL_LIBRARY openssl 9 | 10 | RUN ["apk", "add", "net-snmp-dev", "arping", "gettext", "inetutils-telnet", "musl-dev", "libffi-dev", "libpq-dev", "make", "gcc", "curl-dev", "libjpeg-turbo-dev", "zlib-dev", "expect", "python3-dev", "mariadb-dev", "--no-cache"] 11 | RUN ["adduser", "-G", "www-data", "-SDH", "-h", "/var/www/djing2", "www-data"] 12 | RUN mkdir -p /var/www/djing/media && chown -R www-data. /var/www/djing 13 | 14 | COPY --chown=www-data:www-data ["requirements.txt", "/var/www/djing"] 15 | RUN ["pip", "install", "--no-cache-dir", "--upgrade", "-r", "/var/www/djing/requirements.txt"] 16 | 17 | EXPOSE 8000 18 | 19 | VOLUME /var/www/djing/media 20 | VOLUME /var/www/djing/static 21 | 22 | COPY --chown=www-data:www-data [".", "/var/www/djing/"] 23 | COPY --chown=www-data:www-data ["djing/local_settings.py.example", "/var/www/djing/djing/local_settings.py"] 24 | 25 | WORKDIR /var/www/djing 26 | USER www-data 27 | 28 | #RUN ["./manage.py", "collectstatic", "--no-input", "--link"] 29 | 30 | CMD ./manage.py migrate && \ 31 | ./manage.py compilemessages && \ 32 | exec gunicorn --bind 0.0.0.0:8000 --workers 15 djing.wsgi:application 33 | -------------------------------------------------------------------------------- /systemd_units/webdav_backup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | from sys import argv 4 | from datetime import datetime, timedelta 5 | import webdav.client as wc 6 | 7 | options = { 8 | 'webdav_hostname': "https://webdav.yandex.ru/", 9 | 'webdav_login': "YANDEX USERNAME", 10 | 'webdav_password': "YANDEX PASSWORD" 11 | } 12 | REMOTE_DIR = 'DjingBackups' 13 | 14 | 15 | def remove_old_files(border_time: datetime, client): 16 | # files that older than border_time will be removed 17 | for file in client.list(REMOTE_DIR): 18 | fdate = datetime.strptime(file, 'djing%Y-%m-%d_%H.%M.%S.sql.gz') 19 | if fdate < border_time: 20 | del_fname = os.path.join(REMOTE_DIR, file) 21 | client.clean(del_fname) 22 | print("rm %s" % del_fname) 23 | 24 | 25 | if __name__ == '__main__': 26 | reqfile = argv[1] 27 | try: 28 | client = wc.Client(options) 29 | if reqfile == 'rotate': 30 | border_time = datetime.now() - timedelta(weeks=12) 31 | remove_old_files(border_time, client) 32 | else: 33 | client.upload_sync( 34 | remote_path=os.path.join(REMOTE_DIR, reqfile), 35 | local_path=os.path.join(os.path.sep, 'var', 'backups', reqfile) 36 | ) 37 | except wc.WebDavException as we: 38 | print(we, type(we)) 39 | -------------------------------------------------------------------------------- /tariff_app/migrations/0002_auto_20180807_1548.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-08-07 15:48 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('tariff_app', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='periodicpay', 17 | options={'ordering': ('-id',), 'permissions': (('can_view_periodic_pay', 'Can view periodic pay'),), 'verbose_name': 'Periodic pay', 'verbose_name_plural': 'Periodic pays'}, 18 | ), 19 | migrations.AlterModelOptions( 20 | name='tariff', 21 | options={'ordering': ('title',), 'verbose_name': 'Service', 'verbose_name_plural': 'Services'}, 22 | ), 23 | migrations.AlterField( 24 | model_name='tariff', 25 | name='calc_type', 26 | field=models.CharField(choices=[('Df', 'Base calculate functionality'), ('Dp', 'IS'), ('Cp', 'Private service'), ('Dl', 'IS Daily service')], default='Df', max_length=2, verbose_name='Script'), 27 | ), 28 | migrations.AlterUniqueTogether( 29 | name='tariff', 30 | unique_together={('speedIn', 'speedOut', 'amount', 'calc_type')}, 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /taskapp/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | app_name = 'taskapp' 6 | 7 | urlpatterns = [ 8 | path('', views.NewTasksView.as_view(), name='home'), 9 | path('/', views.TaskUpdateView.as_view(), name='edit'), 10 | path('/delete/', views.task_delete, name='delete'), 11 | path('/fin/', views.task_finish, name='finish'), 12 | path('/fail/', views.task_failed, name='fail'), 13 | path('/remind/', views.remind, name='remind'), 14 | path('/comment/add/', views.NewCommentView.as_view(), name='comment_add'), 15 | path('/comment//remove/', views.DeleteCommentView.as_view(), 16 | name='comment_del'), 17 | path('add/', views.TaskUpdateView.as_view(), name='add'), 18 | path('failed/', views.FailedTasksView.as_view(), name='failed_tasks'), 19 | path('finished/', views.FinishedTaskListView.as_view(), name='finished_tasks'), 20 | path('own/', views.OwnTaskListView.as_view(), name='own_tasks'), 21 | path('my/', views.MyTaskListView.as_view(), name='my_tasks'), 22 | path('all/', views.AllTasksListView.as_view(), name='all_tasks'), 23 | path('all_new/', views.AllNewTasksListView.as_view(), name='all_new_tasks'), 24 | path('empty/', views.EmptyTasksListView.as_view(), name='empty_tasks') 25 | ] 26 | -------------------------------------------------------------------------------- /ip_pool/templates/ip_pool/ext.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n ip_pool_tags %} 3 | 4 | {% block breadcrumb %} 5 | 9 | {% endblock %} 10 | 11 | {% block page-header %} 12 | {% trans 'Networks' %} 13 | {% endblock %} 14 | 15 | 16 | {% block main %} 17 | 18 | 36 | 37 |
38 |
39 | {% block content %}{% endblock %} 40 |
41 |
42 | 43 | {% endblock %} 44 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/perms/object/objects_of_type.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,accounts/perms/ext.html' %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumb %} 5 | 12 | {% endblock %} 13 | 14 | 15 | {% block page-header %} 16 | {% trans 'Pick object for edit permissions' %} 17 | {% endblock %} 18 | 19 | 20 | {% block main %} 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | {% for obj in objects %}{% endfor %} 32 | 33 |
obj
30 | {{ obj }} 31 |
34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_user_markers.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
{% csrf_token %} 3 | 4 | 8 | 9 | 25 | 26 | 31 |
32 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_additional_telephones.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 6 | 7 | 37 | -------------------------------------------------------------------------------- /ip_pool/templates/ip_pool/network_groups_available.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumb %} 5 | 11 | {% endblock %} 12 | 13 | {% block page-header %} 14 | {% trans 'Make that pool available in specified groups' %} 15 | {% endblock %} 16 | 17 | {% block main %} 18 |
{% csrf_token %} 19 | {% for group in groups %} 20 |
21 | 29 |
30 | {% endfor %} 31 | 32 |
33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/perms/ext.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumb %} 5 | 11 | {% endblock %} 12 | 13 | {% block page-header %} 14 | {% trans 'Permission options' %} 15 | {% endblock %} 16 | 17 | {% block main %} 18 | 31 |
32 |
33 | {% block content %}{% endblock %} 34 |
35 |
36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /mapapp/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-02-26 00:20 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | initial = True 10 | 11 | dependencies = [ 12 | ('devapp', '0001_initial'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Dot', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('title', models.CharField(max_length=127, verbose_name='Map point title')), 21 | ('latitude', models.FloatField(verbose_name='Latitude')), 22 | ('longitude', models.FloatField(verbose_name='Longitude')), 23 | ('attachment', models.FileField(blank=True, null=True, upload_to='map_attachments/%Y_%m_%d', 24 | verbose_name='Attachment')), 25 | ('devices', models.ManyToManyField(db_table='dot_device', to='devapp.Device', verbose_name='Devices')), 26 | ], 27 | options={ 28 | 'verbose_name': 'Map point', 29 | 'verbose_name_plural': 'Map points', 30 | 'db_table': 'dots', 31 | 'permissions': (('can_view', 'Can view'),), 32 | }, 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /docsapp/templates/docsapp/documenttemplatemodel_form.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n bootstrap3 %} 3 | 4 | {% block main %} 5 | 6 | {% if object %} 7 | {% url 'docsapp:doc_edit' object.pk as objurl %} 8 | {% else %} 9 | {% url 'docsapp:doc_add' as objurl %} 10 | {% endif %} 11 | 12 |
{% csrf_token %} 13 | 26 | 38 |
39 | {% endblock %} 40 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/perms/object/objects_types.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,accounts/perms/ext.html' %} 2 | {% load i18n acc_tags %} 3 | 4 | {% block breadcrumb %} 5 | 12 | {% endblock %} 13 | 14 | {% block page-header %} 15 | {% trans 'Pick the type of object' %} 16 | {% endblock %} 17 | 18 | {% block content %} 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for klass in klasses %} 28 | 29 | 32 | 33 | {% endfor %} 34 | 35 |
{% trans 'Group' %}
30 | <{{ klass }}> {% klass_name klass %} 31 |
36 |
37 | {% endblock %} 38 | -------------------------------------------------------------------------------- /taskapp/handle.py: -------------------------------------------------------------------------------- 1 | from kombu.exceptions import OperationalError 2 | 3 | from django.template.loader import render_to_string 4 | from django.utils.translation import gettext as _ 5 | from djing.tasks import send_email_notify # , multicast_email_notify 6 | from messenger.tasks import multicast_viber_notify, send_viber_message 7 | 8 | 9 | class TaskException(Exception): 10 | pass 11 | 12 | 13 | def handle(task, author, recipients): 14 | profile_ids = [] 15 | for recipient in recipients: 16 | if not recipient.flags.notify_task: 17 | continue 18 | # If signal to myself then quietly 19 | if author == recipient: 20 | return 21 | profile_ids.append(recipient.pk) 22 | 23 | task_status = _('Task') 24 | 25 | # If task completed or failed 26 | if task.state in ('F', 'C'): 27 | task_status = _('Task completed') 28 | 29 | fulltext = render_to_string('taskapp/notification.html', { 30 | 'task': task, 31 | 'abon': task.abon, 32 | 'task_status': task_status 33 | }) 34 | 35 | try: 36 | if task.state in ('F', 'C'): 37 | # If task completed or failed than send one message to author 38 | send_email_notify.delay(fulltext, author.pk) 39 | send_viber_message.delay(None, author.pk, fulltext) 40 | else: 41 | # multicast_email_notify.delay(fulltext, profile_ids) 42 | multicast_viber_notify.delay(None, profile_ids, fulltext) 43 | except OperationalError as e: 44 | raise TaskException(e) 45 | -------------------------------------------------------------------------------- /clientsideapp/templates/clientsideapp/modal_service_buy.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
{% csrf_token %} 3 | 7 | 21 | 27 |
28 | -------------------------------------------------------------------------------- /messenger/templates/messenger/vibersubscriber_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load dpagination i18n %} 3 | 4 | {% block breadcrumb %} 5 | 10 | {% endblock %} 11 | 12 | {% block page-header %} 13 | {% trans 'Viber subscribers' %} 14 | {% endblock %} 15 | 16 | {% block main %} 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for subscriber in object_list %} 28 | 29 | 30 | 31 | 32 | 33 | {% empty %} 34 | 35 | 36 | 37 | {% endfor %} 38 | 39 |
{% trans 'uid' %}{% trans 'Name' %}{% trans 'Account' %}
{{ subscriber.uid }}{{ subscriber.name }}{{ subscriber.account.get_full_name }}
{% trans 'Subscribers was not found' %}
40 |
41 | {% endblock %} 42 | -------------------------------------------------------------------------------- /accounts_app/templates/accounts/index.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %} 2 | {% load i18n %} 3 | {% block content %} 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {% if request.user.is_superuser %} 29 | 30 | 31 | 32 | 33 | {% endif %} 34 | 35 |
{% trans 'Telephone' %}{{ userprofile.telephone }}
{% trans 'User name' %}{{ userprofile.username }}
{% trans 'Name and surname' %}{{ userprofile.fio }}
{% trans 'Is enable' %}
{% trans 'Last login' %}{{ userprofile.last_login|date:"l d E Y H:i" }}
{% trans 'Is superuser' %}
36 |
37 | 38 | {% endblock %} 39 | -------------------------------------------------------------------------------- /ip_pool/templates/ip_pool/net_add.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load i18n bootstrap3 globaltags %} 3 | 4 | {#{% block additional_link %}#} 5 | {# #} 6 | {#{% endblock %}#} 7 | 8 | {% block title %}{% trans 'Add network' %}{% endblock %} 9 | 10 | {% block breadcrumb %} 11 | 16 | {% endblock %} 17 | 18 | {% block page-header %} 19 | {% trans 'Add new subnet' %} 20 | {% endblock %} 21 | 22 | {% block main %} 23 |
{% csrf_token %} 24 |
25 |
26 |

{% trans 'Add network' %}

27 |
28 |
29 | {% bootstrap_form form %} 30 |
31 | 41 |
42 |
43 | {% endblock %} 44 | -------------------------------------------------------------------------------- /new_customers/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.mixins import PermissionRequiredMixin 2 | from django.views.generic import ListView, DetailView, CreateView 3 | 4 | from djing.global_base_views import OrderingMixin 5 | from djing.lib.mixins import LoginAdminMixin, LoginAdminPermissionMixin 6 | from new_customers.forms import CustomerModelForm 7 | from new_customers.models import PotentialSubscriber 8 | 9 | 10 | class CustomersList(LoginAdminMixin, OrderingMixin, ListView): 11 | model = PotentialSubscriber 12 | 13 | 14 | class CustomerDetail(LoginAdminPermissionMixin, DetailView): 15 | model = PotentialSubscriber 16 | pk_url_kwarg = 'uid' 17 | permission_required = 'new_customers.view_potentialsubscriber' 18 | 19 | def get_context_data(self, **kwargs): 20 | model_fields = filter(lambda x: hasattr(self.object, x.name), self.object._meta.fields) 21 | model_fields = filter(lambda x: getattr(self.object, x.name), model_fields) 22 | model_fields = filter(lambda x: x.name != 'id', model_fields) 23 | context = { 24 | 'form': CustomerModelForm(instance=self.object), 25 | 'model_fields': map(lambda f: { 26 | 'verbose_name': f.verbose_name, 27 | 'value': getattr(self.object, f.name) 28 | }, model_fields) 29 | } 30 | context.update(kwargs) 31 | return super().get_context_data(**context) 32 | 33 | 34 | class CustomerNew(LoginAdminMixin, PermissionRequiredMixin, CreateView): 35 | model = PotentialSubscriber 36 | form_class = CustomerModelForm 37 | permission_required = 'new_customers.add_potentialsubscriber' 38 | -------------------------------------------------------------------------------- /gw_app/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11 on 2018-08-17 17:18 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='NASModel', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('title', models.CharField(max_length=127, unique=True, verbose_name='Title')), 21 | ('ip_address', models.GenericIPAddressField(unique=True, verbose_name='Ip address')), 22 | ('ip_port', models.PositiveSmallIntegerField(verbose_name='Port')), 23 | ('auth_login', models.CharField(max_length=64, verbose_name='Login')), 24 | ('auth_passw', models.CharField(max_length=127, verbose_name='Password')), 25 | ('nas_type', models.CharField(choices=[('mktk', 'Mikrotik NAS')], default='mktk', max_length=4, verbose_name='Type')), 26 | ('default', models.BooleanField(default=False, verbose_name='Is default')), 27 | ], 28 | options={ 29 | 'verbose_name': 'Network access server. Gateway', 30 | 'verbose_name_plural': 'Network access servers. Gateways', 31 | 'db_table': 'nas', 32 | 'ordering': ('ip_address',), 33 | 'permissions': (('can_view_nas', 'Can view NAS'),), 34 | }, 35 | ), 36 | ] 37 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_dev.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 |
{% csrf_token %} 4 | 8 | 9 | {% include '_messages.html' %} 10 | 11 | 38 | 39 |
40 | -------------------------------------------------------------------------------- /devapp/templates/devapp/manage_ports/fix_abon_device.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'nullcont.htm,devapp/ext.htm' %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumb %} 5 | 12 | {% endblock %} 13 | 14 | {% block page-header %} 15 | {% trans 'Fix subscriber ports conflict' %} 16 | {% endblock %} 17 | 18 | {% block main %} 19 |
20 |
21 |

{% trans 'Subscribers list on port' %}

22 |
23 |
24 | {% trans 'Port' %} {{ port.num }}. {{ port.descr }} 25 |

{% blocktrans %}You may choose the subscriber who correctly attached to device port. When you have found right subscriber, remove the port from the other person{% endblocktrans %}

26 |
27 |
28 | {% for abon in abons %} 29 | {{ abon.get_full_name }} 30 | {% empty %} 31 | {% trans 'Abons not found' %} 32 | {% endfor %} 33 |
34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /djing/locale/ru/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # Dmitry Novikov nerosketch@gmail.com, 2018. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2018-08-09 14:59+0300\n" 11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 12 | "Last-Translator: Dmitry Novikov nerosketch@gmail.com\n" 13 | "Language: ru\n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=UTF-8\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" 18 | "%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" 19 | "%100>=11 && n%100<=14)? 2 : 3);\n" 20 | 21 | #: formfields.py:12 22 | msgid "Enter a valid integer." 23 | msgstr "Введите валидное число" 24 | 25 | #: formfields.py:21 26 | msgid "Enter a valid MAC Address." 27 | msgstr "Введите валидный мак-адрес" 28 | 29 | #: global_base_views.py:127 30 | msgid "Page is not 'last', nor can it be converted to an int." 31 | msgstr "" 32 | "Страница не является 'последней' и не может быть преобразована в " 33 | "целочисленное значение." 34 | 35 | #: global_base_views.py:136 36 | msgid "Filter does not contains data, filter without pagination" 37 | msgstr "Фильтр не содержит данных, фильтр без разбиения на страницы" 38 | 39 | #: global_base_views.py:138 40 | #, python-format 41 | msgid "Invalid page (%(page_number)s): %(message)s" 42 | msgstr "Неверная страница (%(page_number)s): %(message)s" 43 | 44 | #: settings.py:137 45 | msgid "Russian" 46 | msgstr "Русский" 47 | -------------------------------------------------------------------------------- /traf_stat/templates/statistics/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load i18n static %} 3 | 4 | {% block additional_link %} 5 | 6 | 7 | {% endblock %} 8 | 9 | {% block page-header %}{% trans 'Traffic' %}{% endblock %} 10 | 11 | {% block main %} 12 | 44 |
45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /finapp/templates/finapp/fin_report.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans 'Money by days' %}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 11 | {% endblock %} 12 | 13 | {% block page-header %} 14 | {% trans 'Money by days' %} 15 | {% endblock %} 16 | 17 | {% block main %} 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for l in logs %} 28 | 29 | 30 | 31 | 32 | {% empty %} 33 | 34 | 35 | 36 | {% endfor %} 37 | 38 | 39 | 40 | 41 | 46 | 47 | 48 | 49 |
{% trans 'Cost' %}{% trans 'Date' %}
{{ l.summ }}{{ l.pay_date|date:"d E Y" }}
{% trans 'Pays not found' %}
42 | 43 | 44 | 45 |
50 |
51 | {% endblock %} 52 | -------------------------------------------------------------------------------- /devapp/templates/devapp/ext.htm: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n %} 3 | 4 | {% block title %}{{ dev.comment }}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 17 | {% endblock %} 18 | 19 | 20 | {% block page-header %} 21 | {{ dev.comment|default:_('Not assigned') }} 22 | {% endblock %} 23 | 24 | 25 | {% block main %} 26 | 27 | 43 | 44 |
45 |
46 | {% block content %}{% endblock %} 47 |
48 |
49 | 50 | {% endblock %} 51 | -------------------------------------------------------------------------------- /searchapp/locale/ru/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # Dmitry Novikov nerosketch@gmail.com, 2018. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Report-Msgid-Bugs-To: \n" 10 | "POT-Creation-Date: 2018-04-24 23:27+0300\n" 11 | "Last-Translator: Dmitry Novikov nerosketch@gmail.com\n" 12 | "Language: ru\n" 13 | "MIME-Version: 1.0\n" 14 | "Content-Type: text/plain; charset=UTF-8\n" 15 | "Content-Transfer-Encoding: 8bit\n" 16 | "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" 17 | "%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" 18 | "%100>=11 && n%100<=14)? 2 : 3);\n" 19 | 20 | #: searchapp/templates/searchapp/index.html:8 21 | #, python-format 22 | msgid "Search by %(searchstring)s" 23 | msgstr "Поиск по %(searchstring)s" 24 | 25 | #: searchapp/templates/searchapp/index.html:16 26 | msgid "Change search string there" 27 | msgstr "Измените строку поиска" 28 | 29 | #: searchapp/templates/searchapp/index.html:21 30 | msgid "Find" 31 | msgstr "Найти" 32 | 33 | #: searchapp/templates/searchapp/index.html:48 34 | #: searchapp/templates/searchapp/index.html:85 35 | msgid "Nothing to found" 36 | msgstr "Ничего не найдено" 37 | 38 | #: searchapp/templates/searchapp/index.html:52 39 | #: searchapp/templates/searchapp/index.html:89 40 | msgid "You can change search string and try again" 41 | msgstr "Вы можете изменить строку поиска и попробовать ещё раз" 42 | 43 | #: searchapp/templates/searchapp/index.html:76 44 | #, python-format 45 | msgid "Network state is %(netw_status)s" 46 | msgstr "Сетевой статус: %(netw_status)s" 47 | 48 | msgid "Search" 49 | msgstr "Поиск" 50 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/group_tariffs.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans 'Belonging services for groups' %}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 13 | {% endblock %} 14 | 15 | {% block page-header %} 16 | {% trans 'Belonging services for groups' %} 17 | {% endblock %} 18 | 19 | {% block main %} 20 |
{% csrf_token %} 21 | {% for tariff in tariffs %} 22 |
23 | 31 |
32 | {% endfor %} 33 |
34 | 35 |
36 |
37 | {% endblock %} 38 | -------------------------------------------------------------------------------- /abonapp/tasks.py: -------------------------------------------------------------------------------- 1 | from celery import shared_task 2 | 3 | from abonapp.models import Abon 4 | from djing.lib import LogicError 5 | from gw_app.models import NASModel 6 | from gw_app.nas_managers import NasFailedResult, NasNetworkError, SubnetQueue 7 | 8 | 9 | @shared_task 10 | def customer_nas_command(customer_uid: int, command: str): 11 | if command not in ('add', 'sync'): 12 | return 'Command required' 13 | try: 14 | cust = Abon.objects.get(pk=customer_uid) 15 | if command == 'sync': 16 | r = cust.nas_sync_self() 17 | if isinstance(r, Exception): 18 | return 'ABONAPP SYNC ERROR: %s' % r 19 | elif command == 'add': 20 | cust.nas_add_self() 21 | else: 22 | return 'ABONAPP SYNC ERROR: Unknown command "%s"' % command 23 | except Abon.DoesNotExist: 24 | pass 25 | except (LogicError, NasFailedResult, NasNetworkError, ConnectionResetError) as e: 26 | return 'ABONAPP ERROR: %s' % e 27 | 28 | 29 | @shared_task 30 | def customer_nas_remove(customer_uid: int, ip_addr: str, speed: tuple, is_access: bool, nas_pk: int): 31 | try: 32 | if not isinstance(ip_addr, (str, int)): 33 | ip_addr = str(ip_addr) 34 | sq = SubnetQueue( 35 | name="uid%d" % customer_uid, 36 | network=ip_addr, 37 | max_limit=speed, 38 | is_access=is_access 39 | ) 40 | nas = NASModel.objects.get(pk=nas_pk) 41 | mngr = nas.get_nas_manager() 42 | mngr.remove_user(sq) 43 | except (ValueError, NasFailedResult, NasNetworkError, LogicError) as e: 44 | return 'ABONAPP ERROR: %s' % e 45 | except NASModel.DoesNotExist: 46 | return 'NASModel.DoesNotExist id=%d' % nas_pk 47 | -------------------------------------------------------------------------------- /abonapp/templates/abonapp/modal_editstreet.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
{% csrf_token %} 3 | 7 | 8 | {% include '_messages.html' %} 9 | 10 | 37 | 38 |
39 | -------------------------------------------------------------------------------- /templates/403.html: -------------------------------------------------------------------------------- 1 | {% load i18n static %} 2 | 3 | 4 | 5 | {% trans 'Permission denied' %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | 34 | 35 |
36 |
37 |
38 |

{% trans '403 - Permission denied' %}

39 |

{% trans 'You have no permissions for that page' %}

40 |
41 |
42 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /templates/500.html: -------------------------------------------------------------------------------- 1 | {% load i18n static %} 2 | 3 | 4 | 5 | {% trans 'Server error' %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 24 | 25 | 26 | 27 | 31 | 32 | 33 | 34 | 35 |
36 |
37 |
38 |

{% trans '500 - Server error' %}

39 |

{% trans 'A server has error occurred. Please contact the administrator.' %}

40 |
41 |
42 |
43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /searchapp/views.py: -------------------------------------------------------------------------------- 1 | import re 2 | from django.db.models import Q 3 | from django.shortcuts import render 4 | from django.utils.html import escape 5 | from abonapp.models import Abon 6 | from devapp.models import Device 7 | from djing import MAC_ADDR_REGEX 8 | from django.contrib.auth.decorators import login_required 9 | from djing.lib.decorators import only_admins 10 | 11 | 12 | def replace_without_case(orig, old, new): 13 | return re.sub(old, new, orig, flags=re.IGNORECASE) 14 | 15 | 16 | @login_required 17 | @only_admins 18 | def home(request): 19 | s = request.GET.get('s') 20 | s = s.replace('+', '') 21 | 22 | if s: 23 | abons = Abon.objects.filter( 24 | Q(fio__icontains=s) | Q(username__icontains=s) | 25 | Q(telephone__icontains=s) | 26 | Q(additional_telephones__telephone__icontains=s) | 27 | Q(ip_address__icontains=s) 28 | ) 29 | 30 | if re.match(MAC_ADDR_REGEX, s): 31 | devices = Device.objects.filter(mac_addr=s) 32 | else: 33 | devices = Device.objects.filter( 34 | Q(comment__icontains=s) | Q(ip_address__icontains=s) 35 | ) 36 | 37 | else: 38 | abons = () 39 | devices = () 40 | 41 | for abn in abons: 42 | abn.fio = replace_without_case(escape(abn.fio), s, "%s" % s) 43 | abn.username_display = replace_without_case(escape(abn.username), s, "%s" % s) 44 | abn.telephone = replace_without_case(escape(abn.telephone), s, "%s" % s) 45 | 46 | for dev in devices: 47 | dev.comment = replace_without_case(escape(dev.comment), s, "%s" % s) 48 | 49 | return render(request, 'searchapp/index.html', { 50 | 'abons': abons, 51 | 'devices': devices, 52 | 's': s 53 | }) 54 | -------------------------------------------------------------------------------- /accounts_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, re_path 2 | from django.contrib.auth.views import LogoutView 3 | 4 | from . import views 5 | 6 | app_name = 'account_app' 7 | 8 | urlpatterns = [ 9 | path('', views.AccountsListView.as_view(), name='accounts_list'), 10 | path('login/', views.CustomLoginView.as_view(), name='login'), 11 | path('logout/', LogoutView.as_view(next_page='acc_app:login'), name='logout'), 12 | path('login_by_location/', views.location_login, name='llogin'), 13 | 14 | path('add/', views.create_profile, name='create_profile'), 15 | 16 | path('settings/', views.UpdateSelfAccount.as_view(), name='setup_info'), 17 | path('settings/change_ava/', views.AvatarUpdateView.as_view(), name='setup_avatar'), 18 | 19 | path('/', views.ProfileShowDetailView.as_view(), name='other_profile'), 20 | path('/edit/', views.UpdateAccount.as_view(), name='edit_profile'), 21 | path('/perms/', views.PermsUpdateView.as_view(), name='setup_perms'), 22 | path('/perms/object/', views.perms_object, name='setup_perms_object'), 23 | 24 | re_path('^(?P\d+)/perms/object/(?P[a-z_]+\.[a-zA-Z_]+)/$', views.PermissionClassListView.as_view(), name='perms_klasses'), 25 | 26 | re_path('^(?P\d+)/perms/object/(?P[a-z_]+\.[a-zA-Z_]+)/(?P\d+)/$', views.perms_edit, name='perms_edit'), 27 | 28 | path('/del/', views.delete_profile, name='delete_profile'), 29 | 30 | path('/user_group_access/', views.set_abon_groups_permission, name='set_abon_groups_permission'), 31 | 32 | path('/manage_responsibility_groups/', views.ManageResponsibilityGroups.as_view(), name='manage_responsibility_groups'), 33 | 34 | path('/actions/', views.ActionListView.as_view(), name='action_log') 35 | ] 36 | -------------------------------------------------------------------------------- /devapp/templates/devapp/group_list.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load i18n %} 3 | 4 | {% block title %}{% trans 'Devices' %}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 11 | {% endblock %} 12 | 13 | {% block page-header %} 14 | {% trans 'Select group' %} 15 | {% endblock %} 16 | 17 | {% block main %} 18 |
19 |
20 |

{% trans 'Group title' %}

21 |
22 | 23 | 24 | {% for gr in groups %} 25 | 26 | 27 | 28 | {% empty %} 29 | 30 | 31 | 32 | {% endfor %} 33 | 34 | 35 | 36 | 44 | 45 | 46 |
{{ gr.title }}
{% trans 'Groups was not found' %}
37 | 38 | {% trans 'Devices without group' %} 39 | 40 | 41 | {% trans 'Export to nagios objects' %} 42 | 43 |
47 |
48 | {% endblock %} 49 | -------------------------------------------------------------------------------- /gw_app/templates/gw_app/nasmodel_update.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n bootstrap3 %} 3 | 4 | {% block title %}{% trans 'Edit gateway' %}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 12 | {% endblock %} 13 | 14 | {% block page-header %} 15 | {% trans 'Change gateways' %} 16 | {% endblock %} 17 | 18 | {% block main %} 19 |
20 |
21 |

{% trans 'Change gateway' %}

22 |
23 |
24 |
{% csrf_token %} 25 | {% bootstrap_form form %} 26 |
27 | 30 | {% if perms.gw_app.delete_nasmodel %} 31 | 32 | {% trans 'Delete' %} 33 | 34 | {% else %} 35 | 36 | {% trans 'Delete' %} 37 | 38 | {% endif %} 39 |
40 |
41 |
42 |
43 | {% endblock %} 44 | -------------------------------------------------------------------------------- /clientsideapp/templates/clientsideapp/tasklist.html: -------------------------------------------------------------------------------- 1 | {% extends 'clientsideapp/ext.html' %} 2 | {% load i18n tasktags %} 3 | {% block client_main %} 4 | 5 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% for task in tasks %} 21 | 22 | 23 | 30 | 31 | 38 | 39 | {% empty %} 40 | 41 | 45 | 46 | {% endfor %} 47 | 48 |
{% trans 'State' %}{% trans 'Date of create' %}{% trans 'The nature of the damage' %}{% trans 'Expected or real completion date' %}
{{ task.get_state_display }} 24 | {% if task.time_of_create|is_current_year %} 25 | {{ task.time_of_create|date:'d b H:i' }} 26 | {% else %} 27 | {{ task.time_of_create|date:'d b H:i. Y' }} 28 | {% endif %} 29 | {{ task.get_mode_display }} 32 | {% if task.out_date|is_current_year %} 33 | {{ task.out_date|date:'d E, l' }} 34 | {% else %} 35 | {{ task.out_date|date:'d E, l Y' }} 36 | {% endif %} 37 |
42 | {% trans "You didn't leave any requests for breakdowns." %} 43 | 44 |
49 |
50 | 51 | {% endblock %} -------------------------------------------------------------------------------- /ip_pool/migrations/0001_squashed_0004_auto_20190305_1243.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.1 on 2019-03-05 12:47 2 | 3 | from django.db import migrations, models 4 | import ip_pool.fields 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | replaces = [('ip_pool', '0001_initial'), ('ip_pool', '0002_change_unique'), ('ip_pool', '0003_auto_20181019_1230'), ('ip_pool', '0004_auto_20190305_1243')] 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ('group_app', '0002_group_code'), 15 | ] 16 | 17 | operations = [ 18 | migrations.CreateModel( 19 | name='NetworkModel', 20 | fields=[ 21 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 22 | ('network', ip_pool.fields.GenericIpAddressWithPrefix(help_text='Ip address of network. For example: 192.168.1.0 or fde8:6789:1234:1::', unique=True, verbose_name='IP network')), 23 | ('kind', models.CharField(choices=[('inet', 'Internet'), ('guest', 'Guest'), ('trust', 'Trusted'), ('device', 'Devices'), ('admin', 'Admin')], default='guest', max_length=6, verbose_name='Kind of network')), 24 | ('description', models.CharField(max_length=64, verbose_name='Description')), 25 | ('ip_start', models.GenericIPAddressField(verbose_name='Start work ip range')), 26 | ('ip_end', models.GenericIPAddressField(verbose_name='End work ip range')), 27 | ('groups', models.ManyToManyField(to='group_app.Group', verbose_name='Groups')), 28 | ], 29 | options={ 30 | 'verbose_name': 'Network', 31 | 'verbose_name_plural': 'Networks', 32 | 'db_table': 'ip_pool_network', 33 | 'ordering': ('network',), 34 | }, 35 | ) 36 | ] 37 | -------------------------------------------------------------------------------- /djing/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from django.conf import settings 3 | 4 | from .views import home 5 | 6 | urlpatterns = [ 7 | path('', home), 8 | path('accounts/', include('accounts_app.urls', namespace='acc_app')), 9 | path('abons/', include('abonapp.urls', namespace='abonapp')), 10 | path('tarifs/', include('tariff_app.urls', namespace='tarifs')), 11 | path('search/', include('searchapp.urls', namespace='searchapp')), 12 | path('dev/', include('devapp.urls', namespace='devapp')), 13 | path('map/', include('mapapp.urls', namespace='mapapp')), 14 | path('statistic/', include('traf_stat.urls', namespace='traf_stat')), 15 | path('tasks/', include('taskapp.urls', namespace='taskapp')), 16 | path('client/', include('clientsideapp.urls', namespace='client_side')), 17 | path('msg/', include('msg_app.urls', namespace='msg_app')), 18 | path('groups/', include('group_app.urls', namespace='group_app')), 19 | path('ip_pool/', include('ip_pool.urls', namespace='ip_pool')), 20 | path('messenger/', include('messenger.urls', namespace='messenger')), 21 | path('gw/', include('gw_app.urls', namespace='gw_app')), 22 | path('new_customers/', include('new_customers.urls', namespace='new_customers')), 23 | path('fin/', include('finapp.urls', namespace='finapp')), 24 | path('docs/', include('docsapp.urls', namespace='docsapp')) 25 | 26 | # Switch language 27 | #path(r'i18n/', include('django.conf.urls.i18n')), 28 | 29 | ] 30 | 31 | if settings.DEBUG: 32 | from django.conf.urls.static import static 33 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns 34 | from django.contrib import admin 35 | 36 | urlpatterns.extend(static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)) 37 | urlpatterns.extend(staticfiles_urlpatterns()) 38 | urlpatterns.append(path('admin/', admin.site.urls)) 39 | -------------------------------------------------------------------------------- /finapp/templates/finapp/payHistory.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | {% load i18n %} 3 | 4 | {% block title %}{{ pay_gw.title }}{% endblock %} 5 | 6 | {% block breadcrumb %} 7 | 12 | {% endblock %} 13 | 14 | {% block page-header %}{{ pay_gw.title }}{% endblock %} 15 | 16 | 17 | {% block main %} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | {% for pay in object_list %} 32 | 33 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {% empty %} 47 | 48 | 49 | 50 | {% endfor %} 51 | 52 |
{% trans 'User' %}{% trans 'Pay id' %}{% trans 'Date' %}{% trans 'Cost' %}{% trans 'Trade point' %}{% trans 'Receipt num' %}
34 | {% if pay.abon %} 35 | {{ pay.abon }} 36 | {% else %} 37 | {% trans 'Deleted' %} 38 | {% endif %} 39 | {{ pay.pay_id }}{{ pay.date_add|date:'D d E Y H:i:s' }}{{ pay.summ }}{{ pay.trade_point|default_if_none:'—' }}{{ pay.receipt_num }}
{% trans 'Payment history is empty' %}
53 | 54 | {% endblock %} 55 | -------------------------------------------------------------------------------- /djing/local_settings.py.example: -------------------------------------------------------------------------------- 1 | """ 2 | Custom settings for each system 3 | """ 4 | 5 | DEBUG = False 6 | 7 | ALLOWED_HOSTS = '*', 8 | 9 | DEFAULT_FROM_EMAIL = 'admin@yoursite.com' 10 | 11 | PAGINATION_ITEMS_PER_PAGE = 20 12 | 13 | # SECURITY WARNING: keep the secret key used in production secret! 14 | SECRET_KEY = '!!!!!!!!!!!!!!!!!!!!!!!!YOUR SECRET KEY!!!!!!!!!!!!!!!!!!!!!!!!' 15 | 16 | DATABASES = { 17 | 'default': { 18 | 'OPTIONS': { 19 | 'init_command': "SET sql_mode='STRICT_TRANS_TABLES', default_storage_engine=INNODB", 20 | 'isolation_level': 'read uncommitted' 21 | }, 22 | 'ENGINE': 'django.db.backends.mysql', 23 | 'NAME': 'djing_db', 24 | 'USER': 'root', # You can change the user name 25 | 'PASSWORD': 'password', # You can change the password 26 | 'HOST': 'db', 27 | 'TEST': { 28 | 'CHARSET': 'utf8', 29 | 'COLLATION': 'utf8_general_ci' 30 | } 31 | } 32 | } 33 | 34 | 35 | DEFAULT_SNMP_PASSWORD = 'public' 36 | 37 | # Telephone or empty 38 | TELEPHONE_REGEXP = r'^(\+[7893]\d{10,11})?$' 39 | 40 | # Secret word for auth to api views by hash 41 | API_AUTH_SECRET = 'your api secret' 42 | 43 | # Allowed subnet for api 44 | # Fox example: API_AUTH_SUBNET = ('127.0.0.0/8', '10.0.0.0/8', '192.168.0.0/16') 45 | API_AUTH_SUBNET = '127.0.0.0/8' 46 | 47 | # Company name 48 | COMPANY_NAME = 'Your company name' 49 | 50 | # Email config 51 | EMAIL_HOST_USER = 'YOUR-EMAIL@mailserver.com' 52 | EMAIL_HOST = 'smtp.mailserver.com' 53 | EMAIL_PORT = 587 54 | EMAIL_HOST_PASSWORD = 'password' 55 | EMAIL_USE_TLS = True 56 | 57 | # public url for Viber Bot 58 | VIBER_BOT_PUBLIC_URL = 'https://your_domain.name' 59 | 60 | # Encrypted fields 61 | # https://pypi.org/project/django-encrypted-model-fields/ 62 | # You must change this value 63 | #FIELD_ENCRYPTION_KEY = 'vZpDlDPQyU6Ha7NyUGj9uYMuPigejtEPMOZfkYXIQRw=' 64 | -------------------------------------------------------------------------------- /messenger/templates/messenger/vibermessenger_form.html: -------------------------------------------------------------------------------- 1 | {% extends request.is_ajax|yesno:'bajax.html,base.html' %} 2 | {% load i18n bootstrap3 %} 3 | 4 | 5 | {% block breadcrumb %} 6 | 16 | {% endblock %} 17 | 18 | 19 | {% block main %} 20 | 21 | {% if object %} 22 | {% url 'messenger:update_viber_messenger' object.slug as form_url %} 23 | {% trans 'Change messenger' as panel_title %} 24 | {% else %} 25 | {% url 'messenger:add_viber_messenger' as form_url %} 26 | {% trans 'Add new messenger' as panel_title %} 27 | {% endif %} 28 | 29 |
30 |
31 |

{{ panel_title }}

32 |
33 |
34 |
{% csrf_token %} 35 | {% bootstrap_form form %} 36 | 39 | {% if object %} 40 | 41 | {% trans 'Send webhook' %} 42 | 43 | {% endif %} 44 |
45 |
46 |
47 | {% endblock %} 48 | -------------------------------------------------------------------------------- /taskapp/templates/taskapp/details.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |
3 |
4 |

{% trans 'Task details' %}

5 |
6 |
7 | 8 |

{% trans 'Description' %}: {{ task.descr|default:'' }}

9 | 10 | {% trans 'Task author' %}: 11 | {% if task and task.author %} 12 | {{ task.author.username }} 13 | {% else %} 14 | {% trans 'Not assigned' %} 15 | {% endif %}
16 | 17 | {% trans 'Implementers' %}: 18 | 23 | {% trans 'A priority' %}: {{ task.get_priority_display }}
24 | {% trans 'The task is valid until' %} {{ task.out_date|date:'d E Y' }}
25 | {% trans 'Date of create' %} {{ task.time_of_create|date:'d E Y H:i:s' }}
26 | {{ time_diff }}
27 | {% trans 'Task type' %}: {{ task.get_mode_display }}
28 | {% trans 'Condition' %}: {{ task.get_state_display }}
29 | {% trans 'Subscriber' %} 30 | {% if task.abon %} 31 | {{ task.abon.get_full_name }} 32 | {% else %} 33 | {% trans 'Not assigned' %} 34 | {% endif %}
35 | {% if task.attachment %} 36 | {% trans 'Attachment' %}: 37 | 38 | 39 | 40 | {% endif %} 41 | 42 |
43 |
-------------------------------------------------------------------------------- /traf_stat/fields.py: -------------------------------------------------------------------------------- 1 | # 2 | # Get from https://github.com/Niklas9/django-unixdatetimefield 3 | # 4 | import datetime 5 | import time 6 | 7 | import django.db.models as models 8 | 9 | 10 | class UnixDateTimeField(models.DateTimeField): 11 | 12 | # TODO(niklas9): 13 | # * should we take care of transforming between time zones in any way here ? 14 | # * get default datetime format from settings ? 15 | DEFAULT_DATETIME_FMT = '%Y-%m-%d %H:%M:%S' 16 | TZ_CONST = '+' 17 | # TODO(niklas9): 18 | # * metaclass below just for Django < 1.9, fix a if stmt for it? 19 | #__metaclass__ = models.SubfieldBase 20 | description = "Unix timestamp integer to datetime object" 21 | 22 | def get_internal_type(self): 23 | return 'PositiveIntegerField' 24 | 25 | def to_python(self, val): 26 | if val is None or isinstance(val, datetime.datetime): 27 | return val 28 | if isinstance(val, datetime.date): 29 | return datetime.datetime(val.year, val.month, val.day) 30 | elif isinstance(val, str): 31 | # TODO(niklas9): 32 | # * not addressing time zone support as todo above for now 33 | if self.TZ_CONST in val: 34 | val = val.split(self.TZ_CONST)[0] 35 | return datetime.datetime.strptime(val, self.DEFAULT_DATETIME_FMT) 36 | else: 37 | return datetime.datetime.fromtimestamp(float(val)) 38 | 39 | def get_db_prep_value(self, val, *args, **kwargs): 40 | if val is None: 41 | if self.default == models.fields.NOT_PROVIDED: return None 42 | return self.default 43 | return int(time.mktime(val.timetuple())) 44 | 45 | def value_to_string(self, obj): 46 | val = self._get_val_from_obj(obj) 47 | return self.to_python(val).strftime(self.DEFAULT_DATETIME_FMT) 48 | 49 | def from_db_value(self, val, *args, **kwargs): 50 | return self.to_python(val) 51 | -------------------------------------------------------------------------------- /taskapp/templates/taskapp/comments/task_comments.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 |
3 |
4 |

{% trans 'Task comments' %}

5 |
6 |
7 |
8 | {% for comment in comments %} 9 | {% with author=comment.author %} 10 |
11 | {% if comment.author == request.user %} 12 | 13 | 14 | 15 | {% endif %} 16 |
{{ author.get_short_name }} 17 | {{ comment.date_create|date:'d M, H:i:s' }} 18 |
19 |

{{ comment.text }}

20 |
21 | {% endwith %} 22 | {% empty %} 23 |
24 |

{% trans 'Comment history is empty' %}

25 |
26 | {% endfor %} 27 |
28 | {% if perms.taskapp.add_extracomment %} 29 |
{% csrf_token %} 30 | {% bootstrap_form comment_form %} 31 | {% buttons %} 32 | 35 | {% endbuttons %} 36 |
37 | {% endif %} 38 |
39 |
40 | -------------------------------------------------------------------------------- /new_customers/models.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import resolve_url 2 | from django.utils.translation import gettext_lazy as _ 3 | from django.db import models 4 | from django.conf import settings 5 | from django.core.validators import RegexValidator 6 | 7 | from group_app.models import Group 8 | 9 | 10 | class PotentialSubscriber(models.Model): 11 | fio = models.CharField(_('fio'), max_length=256) 12 | telephone = models.CharField( 13 | max_length=16, 14 | verbose_name=_('Telephone'), 15 | blank=True, 16 | null=True, 17 | validators=(RegexValidator( 18 | getattr(settings, 'TELEPHONE_REGEXP', r'^(\+[7893]\d{10,11})?$') 19 | ),) 20 | ) 21 | group = models.ForeignKey( 22 | Group, 23 | on_delete=models.SET_NULL, 24 | blank=True, null=True, 25 | verbose_name=_('User group') 26 | ) 27 | town = models.CharField( 28 | _('Town'), 29 | help_text=_('Town, if group does not already exist'), 30 | max_length=127, blank=True, null=True 31 | ) 32 | street = models.CharField(_('Street'), max_length=127, blank=True, null=True) 33 | house = models.CharField( 34 | _('House'), 35 | max_length=12, 36 | null=True, 37 | blank=True 38 | ) 39 | description = models.TextField( 40 | _('Comment'), 41 | null=True, 42 | blank=True 43 | ) 44 | make_data = models.DateTimeField(_('Create date'), auto_now_add=True) 45 | deadline = models.DateField( 46 | _('Deadline connection'), 47 | help_text=_('Date when connection must be finished'), 48 | blank=True, null=True 49 | ) 50 | 51 | def get_absolute_url(self): 52 | return resolve_url('new_customers:user', uid=self.pk) 53 | 54 | class Meta: 55 | db_table = 'new_customers' 56 | verbose_name = _('Potential customer') 57 | verbose_name_plural = _('Potential customers') 58 | ordering = '-id', 59 | -------------------------------------------------------------------------------- /agent/netflow/netflow_collect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PATH=/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin 4 | 5 | DIRECTORY=`dirname $(readlink -e "$0")` 6 | tmp_ipuser_file='/tmp/ipuser.txt' 7 | 8 | cd "$DIRECTORY" 9 | 10 | read -r mysql_database mysql_user mysql_passw mysql_host mysql_port <<< `python3 -c "\ 11 | from importlib.util import spec_from_file_location, module_from_spec 12 | spec = spec_from_file_location('local_settings', '../../djing/local_settings.py') 13 | ls = module_from_spec(spec) 14 | spec.loader.exec_module(ls) 15 | db = ls.DATABASES 16 | ldb = db.get('default') 17 | print('%s %s %s %s %d' % (ldb['NAME'], ldb['USER'], 18 | ldb['PASSWORD'], ldb['HOST'], ldb.get('PORT', 3306)))"` 19 | 20 | if ! ping -c 1 ${mysql_host} &> /dev/null; then 21 | echo "Host ${mysql_host} is not accessible" 22 | fi 23 | 24 | # Формируем список абонентов и их id 25 | sql='SELECT INET_ATON(ip_address) as uip, baseaccount_ptr_id FROM abonent WHERE INET_ATON(ip_address) != "NULL";' 26 | 27 | count=`mysql -u${mysql_user} -h ${mysql_host} -p --password=${mysql_passw} -D ${mysql_database} -P ${mysql_port} -NBe "select COUNT(*) from abonent WHERE INET_ATON(ip_address) != 'NULL';"` 28 | echo "count: $count" > ${tmp_ipuser_file} 29 | 30 | mysql -u ${mysql_user} -h ${mysql_host} -p --password=${mysql_passw} -P ${mysql_port} -D ${mysql_database} -NBe "${sql}" | while read -r uip uid; 31 | do 32 | echo "${uip}-${uid}" >> ${tmp_ipuser_file} 33 | done 34 | 35 | # Сигналим коллекторам чтоб они сбросили дамп в папку /tmp/djing_flow/dump 36 | for fl in /run/flow.pid.*; do 37 | kill -HUP `cat ${fl}` 38 | sleep 0.1 39 | done 40 | sleep 1 41 | 42 | # Экспортируем всё в mysql 43 | export LD_LIBRARY_PATH=. 44 | 45 | flow-cat /tmp/djing_flow/dump/*/*.dmp | ./djing_flow -i ${tmp_ipuser_file} -c | mysql -u ${mysql_user} -h ${mysql_host} -p -D ${mysql_database} -P ${mysql_port} --password=${mysql_passw} 46 | 47 | rm -f ${tmp_ipuser_file} 48 | rm -f /tmp/djing_flow/dump/*/*.dmp 49 | rm -f /tmp/djing_flow/*/ft* 50 | -------------------------------------------------------------------------------- /devapp/tests.py: -------------------------------------------------------------------------------- 1 | from hashlib import sha256 2 | from django.shortcuts import resolve_url 3 | from django.test import TestCase, RequestFactory, override_settings 4 | 5 | from accounts_app.models import UserProfile 6 | from devapp.models import Device 7 | from group_app.models import Group 8 | 9 | rf = RequestFactory() 10 | API_SECRET = 'TestApiSecret' 11 | 12 | 13 | def calc_hash(data): 14 | if type(data) is str: 15 | result_data = data.encode('utf-8') 16 | else: 17 | result_data = bytes(data) 18 | return sha256(result_data).hexdigest() 19 | 20 | 21 | class DevTest(TestCase): 22 | def setUp(self): 23 | grp = Group.objects.create(title='Grp1') 24 | my_admin = UserProfile.objects.create_superuser('+79781234567', 'local_superuser', 'ps') 25 | # self.client.login(username=my_admin.username, password=my_admin.password) 26 | self.adminuser = my_admin 27 | Device.objects.create( 28 | ip_address='192.168.0.100', 29 | mac_addr='78:81:f2:1f:d2:a9', 30 | comment='Test device', 31 | devtype='On', 32 | man_passw='public', 33 | group=grp 34 | ) 35 | 36 | @override_settings(API_AUTH_SECRET=API_SECRET, API_AUTH_SUBNET='127.0.0.1') 37 | def test_secure_api_ok(self): 38 | self.client.force_login(self.adminuser) 39 | sign = calc_hash(API_SECRET) 40 | url = resolve_url('devapp:nagios_get_all_hosts') 41 | r = self.client.get(url, { 42 | 'sign': sign 43 | }) 44 | self.assertEqual(r.status_code, 200) 45 | 46 | @override_settings(API_AUTH_SECRET=API_SECRET, API_AUTH_SUBNET='127.0.0.1') 47 | def test_get_config_nagios_file(self): 48 | self.client.force_login(self.adminuser) 49 | sign = calc_hash(API_SECRET) 50 | url = resolve_url('devapp:nagios_objects_conf') 51 | r = self.client.get(url, { 52 | 'sign': sign 53 | }) 54 | self.assertEqual(r.status_code, 200) 55 | --------------------------------------------------------------------------------