Browse Source

Merge remote-tracking branch 'origin/global_group_update' into devel

devel
bashmak 8 years ago
parent
commit
2b13fa136e
  1. 1
      abonapp/admin.py
  2. 19
      abonapp/forms.py
  3. 23
      abonapp/locale/ru/LC_MESSAGES/django.po
  4. 308
      abonapp/migrations/0001_initial.py
  5. 52
      abonapp/migrations/0002_auto_20170905_1248.py
  6. 43
      abonapp/migrations/0003_auto_20170927_1838.py
  7. 130
      abonapp/migrations/0004_auto_20180122_1732.py
  8. 20
      abonapp/migrations/0005_auto_20180123_1353.py
  9. 23
      abonapp/migrations/0006_abon_markers.py
  10. 96
      abonapp/models.py
  11. 4
      abonapp/templates/abonapp/addAbon.html
  12. 39
      abonapp/templates/abonapp/addGroup.html
  13. 8
      abonapp/templates/abonapp/addInvoice.html
  14. 10
      abonapp/templates/abonapp/buy_tariff.html
  15. 2
      abonapp/templates/abonapp/charts.html
  16. 24
      abonapp/templates/abonapp/editAbon.html
  17. 16
      abonapp/templates/abonapp/ext.htm
  18. 12
      abonapp/templates/abonapp/group_list.html
  19. 6
      abonapp/templates/abonapp/group_tariffs.html
  20. 6
      abonapp/templates/abonapp/invoiceForPayment.html
  21. 7
      abonapp/templates/abonapp/log.html
  22. 3
      abonapp/templates/abonapp/modal_abonamount.html
  23. 2
      abonapp/templates/abonapp/passport_view.html
  24. 4
      abonapp/templates/abonapp/payHistory.html
  25. 40
      abonapp/templates/abonapp/peoples.html
  26. 14
      abonapp/templates/abonapp/service.html
  27. 2
      abonapp/urls.py
  28. 245
      abonapp/views.py
  29. 63
      accounts_app/migrations/0001_initial.py
  30. 20
      accounts_app/migrations/0002_userprofile_email.py
  31. 25
      accounts_app/migrations/0003_auto_20161206_2135.py
  32. 18
      accounts_app/migrations/0004_auto_20170128_1316.py
  33. 21
      accounts_app/migrations/0005_auto_20170222_2224.py
  34. 21
      accounts_app/migrations/0006_auto_20170416_1029.py
  35. 21
      accounts_app/migrations/0007_auto_20170816_1109.py
  36. 19
      accounts_app/migrations/0008_auto_20170927_1838.py
  37. 28
      accounts_app/models.py
  38. 6
      accounts_app/templates/accounts/ext.htm
  39. 24
      accounts_app/templates/accounts/profile_chgroup.html
  40. 10
      accounts_app/templates/accounts/set_abon_groups_permission.html
  41. 1
      accounts_app/urls.py
  42. 45
      accounts_app/views.py
  43. 17
      agent/commands/dhcp.py
  44. 32
      chatbot/migrations/0001_initial.py
  45. 59
      chatbot/migrations/0002_auto_20171214_1517.py
  46. 49
      clientsideapp/locale/ru/LC_MESSAGES/django.po
  47. 6
      clientsideapp/templates/clientsideapp/debt_buy.html
  48. 2
      clientsideapp/templates/clientsideapp/ext.html
  49. 3
      clientsideapp/templates/clientsideapp/modal_service_buy.html
  50. 23
      clientsideapp/views.py
  51. 5
      devapp/forms.py
  52. 4
      devapp/locale/ru/LC_MESSAGES/django.po
  53. 62
      devapp/migrations/0001_initial.py
  54. 90
      devapp/migrations/0001_squashed_0007_auto_20170816_1109.py
  55. 22
      devapp/migrations/0002_device_user_group.py
  56. 23
      devapp/migrations/0003_auto_20170927_1838.py
  57. 72
      devapp/migrations/0004_auto_20171103_0006.py
  58. 20
      devapp/migrations/0005_device_snmp_item_num.py
  59. 34
      devapp/migrations/0006_auto_20180129_1625.py
  60. 7
      devapp/models.py
  61. 2
      devapp/templates/devapp/add_dev.html
  62. 2
      devapp/templates/devapp/custom_dev_page/olt.html
  63. 2
      devapp/templates/devapp/custom_dev_page/onu.html
  64. 4
      devapp/templates/devapp/custom_dev_page/ports.html
  65. 2
      devapp/templates/devapp/dev.html
  66. 8
      devapp/templates/devapp/devices.html
  67. 6
      devapp/templates/devapp/devices_null_group.html
  68. 10
      devapp/templates/devapp/ext.htm
  69. 6
      devapp/templates/devapp/fix_dev_group.html
  70. 19
      devapp/templates/devapp/group_list.html
  71. 8
      devapp/templates/devapp/manage_ports/add_ports.html
  72. 4
      devapp/templates/devapp/manage_ports/fix_abon_device.html
  73. 8
      devapp/templates/devapp/manage_ports/list.html
  74. 80
      devapp/views.py
  75. 37
      dialing_app/migrations/0001_initial.py
  76. 35
      dialing_app/migrations/0002_auto_20171229_1353.py
  77. 31
      dialing_app/migrations/0003_smsout.py
  78. 10
      dialing_app/views.py
  79. 33
      djing/auth_backends.py
  80. 10
      djing/settings.py
  81. 1
      djing/urls.py
  82. 12
      global_context_processors.py
  83. 0
      group_app/__init__.py
  84. 4
      group_app/admin.py
  85. 5
      group_app/apps.py
  86. 8
      group_app/forms.py
  87. 69
      group_app/locale/ru/LC_MESSAGES/django.po
  88. 30
      group_app/migrations/0001_initial.py
  89. 0
      group_app/migrations/__init__.py
  90. 23
      group_app/models.py
  91. 20
      group_app/templates/group_app/add_group.html
  92. 20
      group_app/templates/group_app/edit_group.html
  93. 23
      group_app/templates/group_app/ext.html
  94. 59
      group_app/templates/group_app/group_list.html
  95. 3
      group_app/tests.py
  96. 10
      group_app/urls.py
  97. 52
      group_app/views.py
  98. 66
      locale/ru/LC_MESSAGES/django.po
  99. 16
      mapapp/migrations/0001_initial.py
  100. 45
      mapapp/migrations/0002_auto_20171103_0006.py

1
abonapp/admin.py

@ -3,7 +3,6 @@ from django.contrib import admin
from . import models from . import models
admin.site.register(models.AbonGroup)
admin.site.register(models.Abon) admin.site.register(models.Abon)
admin.site.register(models.InvoiceForPayment) admin.site.register(models.InvoiceForPayment)
admin.site.register(models.AbonLog) admin.site.register(models.AbonLog)

19
abonapp/forms.py

@ -12,7 +12,7 @@ from django.conf import settings
TELEPHONE_REGEXP = getattr(settings, 'TELEPHONE_REGEXP', r'^\+[7,8,9,3]\d{10,11}$') TELEPHONE_REGEXP = getattr(settings, 'TELEPHONE_REGEXP', r'^\+[7,8,9,3]\d{10,11}$')
def generate_random_username(length=6, chars=digits, split=2, delimiter=''):
def generate_random_chars(length=6, chars=digits, split=2, delimiter=''):
username = ''.join([choice(chars) for i in range(length)]) username = ''.join([choice(chars) for i in range(length)])
if split: if split:
@ -25,8 +25,13 @@ def generate_random_username(length=6, chars=digits, split=2, delimiter=''):
return username return username
def generate_random_username():
username = generate_random_chars(length=6, chars=digits)
return str(int(username))
def generate_random_password(): def generate_random_password():
return generate_random_username(length=8, chars=digits + ascii_lowercase)
return generate_random_chars(length=8, chars=digits + ascii_lowercase)
class AbonForm(forms.ModelForm): class AbonForm(forms.ModelForm):
@ -92,16 +97,6 @@ class AbonForm(forms.ModelForm):
return acc return acc
class AbonGroupForm(forms.ModelForm):
class Meta:
model = models.AbonGroup
fields = '__all__'
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'profiles': forms.TextInput(attrs={'class': 'form-control'})
}
class PassportForm(forms.ModelForm): class PassportForm(forms.ModelForm):
class Meta: class Meta:
model = models.PassportInfo model = models.PassportInfo

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

@ -96,10 +96,6 @@ msgstr "Динамический ip"
msgid "Fields" msgid "Fields"
msgstr "Поля" msgstr "Поля"
#: models.py:31
msgid "Can view subscriber group"
msgstr "Может просматривать группу абонентов"
#: models.py:33 #: models.py:33
msgid "Abon group" msgid "Abon group"
msgstr "Группа абонентов" msgstr "Группа абонентов"
@ -894,19 +890,11 @@ msgstr "Просмотр абонента"
msgid "yes,no" msgid "yes,no"
msgstr "Да,Нет" msgstr "Да,Нет"
#: views.py:94
msgid "create group success msg"
msgstr "Группа успешно создана"
#: views.py:97 views.py:161 views.py:308 views.py:423 views.py:500 views.py:642 #: views.py:97 views.py:161 views.py:308 views.py:423 views.py:500 views.py:642
#: views.py:812 views.py:884 views.py:953 views.py:1059 #: views.py:812 views.py:884 views.py:953 views.py:1059
msgid "fix form errors" msgid "fix form errors"
msgstr "Некоторые поля заполнены не правильно, проверте ещё раз" msgstr "Некоторые поля заполнены не правильно, проверте ещё раз"
#: views.py:128
msgid "delete group success msg"
msgstr "Группа успешно удалена"
#: views.py:158 #: views.py:158
msgid "create abon success msg" msgid "create abon success msg"
msgstr "Абонент успешно создан" msgstr "Абонент успешно создан"
@ -1128,7 +1116,7 @@ msgid "User flags has changed successfully"
msgstr "Флаги абонента изменены успешно" msgstr "Флаги абонента изменены успешно"
msgid "Services" msgid "Services"
msgstr "Услуги"
msgstr "Тарифы"
msgid "Payments" msgid "Payments"
msgstr "Финансы" msgstr "Финансы"
@ -1144,3 +1132,12 @@ msgstr "Инфо."
msgid "Dialing" msgid "Dialing"
msgstr "Звонки" msgstr "Звонки"
msgid "Subscribers"
msgstr "Абоненты"
msgid "Successfully saved"
msgstr "Успешно сохранено"
msgid "This user can not buy admin services"
msgstr "Этот пользователь не может назначать административные услуги"

308
abonapp/migrations/0001_squashed_0022_auto_20170816_1109.py → abonapp/migrations/0001_initial.py

@ -1,7 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-09-04 16:15
# Generated by Django 1.11 on 2018-02-26 00:20
from __future__ import unicode_literals from __future__ import unicode_literals
import bitfield.models
from django.conf import settings from django.conf import settings
import django.core.validators import django.core.validators
from django.db import migrations, models from django.db import migrations, models
@ -15,8 +16,8 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('devapp', '0001_squashed_0007_auto_20170816_1109'),
('tariff_app', '0002_tariff_descr'),
('devapp', '0001_initial'),
('group_app', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('accounts_app', '0001_initial'), ('accounts_app', '0001_initial'),
('tariff_app', '0001_initial'), ('tariff_app', '0001_initial'),
@ -26,128 +27,82 @@ class Migration(migrations.Migration):
migrations.CreateModel( migrations.CreateModel(
name='Abon', name='Abon',
fields=[ fields=[
('userprofile_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)),
('ballance', models.FloatField(default=0.0, validators=[django.core.validators.DecimalValidator])),
('address', models.CharField(max_length=256)),
('baseaccount_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='accounts_app.BaseAccount')),
('ballance', models.FloatField(default=0.0)),
('ip_address', mydefs.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4')),
('description', models.TextField(blank=True, null=True, verbose_name='Comment')),
('house', models.CharField(blank=True, max_length=12, null=True, verbose_name='House')),
('is_dynamic_ip', models.BooleanField(default=False)),
('markers', bitfield.models.BitField((('icon_donkey', 'Donkey'), ('icon_fire', 'Fire'), ('icon_ok', 'Ok'), ('icon_king', 'King'), ('icon_tv', 'TV'), ('icon_smile', 'Smile'), ('icon_dollar', 'Dollar'), ('icon_service', 'Service'), ('icon_mrk', 'Marker')), default=0)),
], ],
options={ options={
'verbose_name': 'Abon',
'verbose_name_plural': 'Abons',
'db_table': 'abonent', 'db_table': 'abonent',
'ordering': ['fio'],
'permissions': (('can_buy_tariff', 'Buy service perm'), ('can_view_passport', 'Can view passport'), ('can_add_ballance', 'fill account'), ('can_ping', 'Can ping')),
}, },
bases=('accounts_app.userprofile',),
bases=('accounts_app.baseaccount',),
), ),
migrations.CreateModel( migrations.CreateModel(
name='AbonGroup',
name='AbonLog',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=127, unique=True)),
('amount', models.FloatField(default=0.0)),
('comment', models.CharField(max_length=128)),
('date', models.DateTimeField(auto_now_add=True)),
], ],
options={ options={
'db_table': 'abonent_groups',
'db_table': 'abonent_log',
'ordering': ['-date'],
'permissions': (('can_view_abonlog', 'Can view subscriber logs'),),
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='AbonLog',
name='AbonStreet',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('amount', models.FloatField(default=0.0)),
('comment', models.CharField(max_length=128)),
('date', models.DateTimeField(auto_now_add=True)),
('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)),
('name', models.CharField(max_length=64)),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='group_app.Group')),
], ],
options={ options={
'db_table': 'abonent_log',
'verbose_name': 'Street',
'verbose_name_plural': 'Streets',
'db_table': 'abon_street',
'ordering': ['name'],
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='AbonTariff', name='AbonTariff',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('tariff_priority', models.PositiveSmallIntegerField(default=0)),
('time_start', models.DateTimeField(blank=True, default=None, null=True)), ('time_start', models.DateTimeField(blank=True, default=None, null=True)),
('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')),
('deadline', models.DateTimeField(blank=True, default=None, null=True)),
('tariff', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='linkto_tariff', to='tariff_app.Tariff')), ('tariff', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='linkto_tariff', to='tariff_app.Tariff')),
], ],
options={ options={
'ordering': ('tariff_priority',),
'verbose_name': 'Abon service',
'verbose_name_plural': 'Abon services',
'db_table': 'abonent_tariff', 'db_table': 'abonent_tariff',
'ordering': ['time_start'],
'permissions': (('can_complete_service', 'finish service perm'),),
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='InvoiceForPayment',
name='AdditionalTelephone',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('status', models.BooleanField(default=False)),
('amount', models.FloatField(default=0.0)),
('comment', models.CharField(max_length=128)),
('date_create', models.DateTimeField(auto_now_add=True)),
('date_pay', models.DateTimeField(blank=True, null=True)),
('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')),
('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('telephone', models.CharField(max_length=16, validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')], verbose_name='Telephone')),
('owner_name', models.CharField(max_length=127)),
], ],
options={ options={
'ordering': ('date_create',),
'db_table': 'abonent_inv_pay',
'verbose_name': 'Additional telephone',
'verbose_name_plural': 'Additional telephones',
'db_table': 'additional_telephones',
'ordering': ('owner_name',),
'permissions': (('can_view_additionaltelephones', 'Can view additional telephones'),),
}, },
), ),
migrations.AddField(
model_name='abon',
name='current_tariffs',
field=models.ManyToManyField(through='abonapp.AbonTariff', to='tariff_app.Tariff'),
),
migrations.AddField(
model_name='abon',
name='group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonGroup'),
),
migrations.AlterUniqueTogether(
name='abontariff',
unique_together=set([('abon', 'tariff', 'tariff_priority')]),
),
migrations.AddField(
model_name='abongroup',
name='profiles',
field=models.ManyToManyField(blank=True, related_name='abon_groups', to=settings.AUTH_USER_MODEL),
),
migrations.AlterModelOptions(
name='abon',
options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'),)},
),
migrations.AlterModelOptions(
name='abongroup',
options={'permissions': (('can_add_ballance', 'Пополнение счёта'),)},
),
migrations.AlterModelOptions(
name='abontariff',
options={'ordering': ('tariff_priority',), 'permissions': (('can_complete_service', 'Досрочное завершение услуги абонента'), ('can_activate_service', 'Активация услуги абонента'))},
),
migrations.CreateModel(
name='AbonStreet',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=64)),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.AbonGroup')),
],
),
migrations.RemoveField(
model_name='abon',
name='address',
),
migrations.AddField(
model_name='abon',
name='description',
field=models.TextField(blank=True, null=True),
),
migrations.AddField(
model_name='abon',
name='house',
field=models.CharField(blank=True, max_length=12, null=True),
),
migrations.AddField(
model_name='abon',
name='street',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonStreet'),
),
migrations.CreateModel( migrations.CreateModel(
name='AllPayLog', name='AllPayLog',
fields=[ fields=[
@ -158,7 +113,7 @@ class Migration(migrations.Migration):
], ],
options={ options={
'db_table': 'all_pay_log', 'db_table': 'all_pay_log',
'ordering': ('date_action',),
'ordering': ['-date_action'],
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
@ -167,70 +122,44 @@ class Migration(migrations.Migration):
('pay_id', models.CharField(max_length=36, primary_key=True, serialize=False, unique=True)), ('pay_id', models.CharField(max_length=36, primary_key=True, serialize=False, unique=True)),
('date_add', models.DateTimeField(auto_now_add=True)), ('date_add', models.DateTimeField(auto_now_add=True)),
('summ', models.FloatField(default=0.0)), ('summ', models.FloatField(default=0.0)),
('trade_point', models.CharField(blank=True, default=None, max_length=20, null=True, verbose_name='Trade point')),
('receipt_num', models.BigIntegerField(default=0, verbose_name='Receipt number')),
], ],
options={ options={
'db_table': 'all_time_pay_log', 'db_table': 'all_time_pay_log',
'ordering': ('date_add',),
'ordering': ['-date_add'],
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='AbonRawPassword',
name='ExtraFieldsModel',
fields=[ fields=[
('account', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='abonapp.Abon')),
('passw_text', models.CharField(max_length=64)),
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(default='no title', max_length=16)),
('field_type', models.CharField(choices=[('int', 'Digital field'), ('str', 'Text field'), ('dbl', 'Floating field'), ('ipa', 'Ip Address')], default='str', max_length=3)),
('data', models.CharField(blank=True, max_length=64, null=True)),
], ],
options={ options={
'db_table': 'abon_raw_password',
'db_table': 'abon_extra_fields',
}, },
), ),
migrations.AlterModelTable(
name='abonstreet',
table='abon_street',
),
migrations.AddField(
model_name='abontariff',
name='deadline',
field=models.DateTimeField(blank=True, default=None, null=True),
),
migrations.CreateModel( migrations.CreateModel(
name='ExtraFieldsModel',
name='InvoiceForPayment',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('field_type', models.CharField(choices=[('int', 'Цифровое поле'), ('str', 'Текстовое поле'), ('dbl', 'Дробное с плавающей точкой'), ('ipa', 'IP Адрес')], default='str', max_length=3)),
('data', models.CharField(blank=True, max_length=64, null=True)),
('title', models.CharField(default='no title', max_length=16)),
('status', models.BooleanField(default=False)),
('amount', models.FloatField(default=0.0)),
('comment', models.CharField(max_length=128)),
('date_create', models.DateTimeField(auto_now_add=True)),
('date_pay', models.DateTimeField(blank=True, null=True)),
], ],
options={ options={
'db_table': 'abon_extra_fields',
'verbose_name': 'Debt',
'verbose_name_plural': 'Debts',
'db_table': 'abonent_inv_pay',
'ordering': ('date_create',),
'permissions': (('can_view_invoiceforpayment', 'Can view invoice for payment'),),
}, },
), ),
migrations.AlterModelOptions(
name='abon',
options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Can view passport'))},
),
migrations.AlterModelOptions(
name='abontariff',
options={'ordering': ('tariff_priority',), 'permissions': (('can_complete_service', 'Снятие со счёта средств'), ('can_activate_service', 'Активация услуги абонента'))},
),
migrations.AlterField(
model_name='abon',
name='ballance',
field=models.FloatField(default=0.0),
),
migrations.AlterModelOptions(
name='abon',
options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Может просматривать паспортные данные'))},
),
migrations.AddField(
model_name='abon',
name='extra_fields',
field=models.ManyToManyField(blank=True, to='abonapp.ExtraFieldsModel'),
),
migrations.AddField(
model_name='abongroup',
name='tariffs',
field=models.ManyToManyField(blank=True, related_name='tariff_groups', to='tariff_app.Tariff'),
),
migrations.CreateModel( migrations.CreateModel(
name='PassportInfo', name='PassportInfo',
fields=[ fields=[
@ -239,38 +168,83 @@ class Migration(migrations.Migration):
('number', models.CharField(max_length=6, validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z', 32), code='invalid', message='Enter a valid integer.')])), ('number', models.CharField(max_length=6, validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z', 32), code='invalid', message='Enter a valid integer.')])),
('distributor', models.CharField(max_length=64)), ('distributor', models.CharField(max_length=64)),
('date_of_acceptance', models.DateField()), ('date_of_acceptance', models.DateField()),
('abon', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.Abon')),
], ],
options={
'verbose_name': 'Passport Info',
'verbose_name_plural': 'Passport Info',
'db_table': 'passport_info',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='AbonDevice',
name='PeriodicPayForId',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('abon', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')),
('device', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device')),
('last_pay', models.DateTimeField(blank=True, null=True, verbose_name='Last pay time')),
('next_pay', models.DateTimeField(verbose_name='Next time to pay')),
], ],
options={ options={
'db_table': 'abon_device',
'db_table': 'periodic_pay_for_id',
}, },
), ),
migrations.AlterUniqueTogether(
name='abondevice',
unique_together=set([('abon', 'device')]),
migrations.CreateModel(
name='AbonRawPassword',
fields=[
('account', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='abonapp.Abon')),
('passw_text', models.CharField(max_length=64)),
],
options={
'db_table': 'abon_raw_password',
},
),
migrations.AddField(
model_name='periodicpayforid',
name='account',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon', verbose_name='Account'),
), ),
migrations.AlterField(
model_name='abondevice',
migrations.AddField(
model_name='periodicpayforid',
name='periodic_pay',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tariff_app.PeriodicPay', verbose_name='Periodic pay'),
),
migrations.AddField(
model_name='passportinfo',
name='abon',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.Abon'),
),
migrations.AddField(
model_name='invoiceforpayment',
name='abon', name='abon',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon'), field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon'),
), ),
migrations.AlterField(
model_name='abondevice',
name='device',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device'),
migrations.AddField(
model_name='invoiceforpayment',
name='author',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='alltimepaylog',
name='abon',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, to='abonapp.Abon'),
),
migrations.AddField(
model_name='additionaltelephone',
name='abon',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='additional_telephones', to='abonapp.Abon'),
),
migrations.AddField(
model_name='abonlog',
name='abon',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon'),
),
migrations.AddField(
model_name='abonlog',
name='author',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL),
), ),
migrations.AddField( migrations.AddField(
model_name='abon', model_name='abon',
name='ip_address',
field=mydefs.MyGenericIPAddressField(blank=True, max_length=8, null=True, protocol='ipv4'),
name='current_tariff',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonTariff'),
), ),
migrations.AddField( migrations.AddField(
model_name='abon', model_name='abon',
@ -284,35 +258,17 @@ class Migration(migrations.Migration):
), ),
migrations.AddField( migrations.AddField(
model_name='abon', model_name='abon',
name='is_dynamic_ip',
field=models.BooleanField(default=False),
),
migrations.DeleteModel(
name='AbonDevice',
),
migrations.AlterModelOptions(
name='abontariff',
options={'permissions': (('can_complete_service', 'Снятие со счёта средств'),)},
name='extra_fields',
field=models.ManyToManyField(blank=True, to='abonapp.ExtraFieldsModel'),
), ),
migrations.RemoveField(
migrations.AddField(
model_name='abon', model_name='abon',
name='current_tariffs',
name='group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='group_app.Group', verbose_name='User group'),
), ),
migrations.AddField( migrations.AddField(
model_name='abon', model_name='abon',
name='current_tariff',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonTariff'),
),
migrations.AlterUniqueTogether(
name='abontariff',
unique_together=set([]),
),
migrations.RemoveField(
model_name='abontariff',
name='abon',
),
migrations.RemoveField(
model_name='abontariff',
name='tariff_priority',
name='street',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonStreet', verbose_name='Street'),
), ),
] ]

52
abonapp/migrations/0002_auto_20170905_1248.py

@ -1,52 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-09-05 12:48
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('abonapp', '0001_squashed_0022_auto_20170816_1109'),
]
operations = [
migrations.CreateModel(
name='AdditionalTelephone',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('telephone', models.CharField(max_length=16, validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')], verbose_name='Телефон')),
('owner_name', models.CharField(max_length=127)),
],
options={
'verbose_name': 'Дополнительный телефон',
'verbose_name_plural': 'Дополнительные телефоны',
'db_table': 'additional_telephones',
'ordering': ('owner_name',),
},
),
migrations.AlterModelOptions(
name='abon',
options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Может просматривать паспортные данные')), 'verbose_name': 'Абонент', 'verbose_name_plural': 'Абоненты'},
),
migrations.AlterModelOptions(
name='abongroup',
options={'permissions': (('can_add_ballance', 'Пополнение счёта'),), 'verbose_name': 'Группа абонентов', 'verbose_name_plural': 'Группы абонентов'},
),
migrations.AlterModelOptions(
name='abonstreet',
options={'verbose_name': 'Улица', 'verbose_name_plural': 'Улицы'},
),
migrations.AlterModelOptions(
name='abontariff',
options={'permissions': (('can_complete_service', 'Снятие со счёта средств'),), 'verbose_name': 'Услуга абонента', 'verbose_name_plural': 'Услуги абонентов'},
),
migrations.AddField(
model_name='additionaltelephone',
name='abon',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='additional_telephones', to='abonapp.Abon'),
),
]

43
abonapp/migrations/0003_auto_20170927_1838.py

@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-09-27 18:38
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('abonapp', '0002_auto_20170905_1248'),
]
operations = [
migrations.AlterModelOptions(
name='abon',
options={'permissions': (('can_buy_tariff', 'Покупка тарифа абоненту'), ('can_view_passport', 'Может просматривать паспортные данные'), ('can_add_ballance', 'Пополнение счёта'), ('can_ping', 'Может пинговать')), 'verbose_name': 'Абонент', 'verbose_name_plural': 'Абоненты'},
),
migrations.AlterModelOptions(
name='abongroup',
options={'permissions': (('can_view_abongroup', 'Может просматривать группу абонентов'),), 'verbose_name': 'Группа абонентов', 'verbose_name_plural': 'Группы абонентов'},
),
migrations.AlterModelOptions(
name='abonlog',
options={'permissions': (('can_view_abonlog', 'Может видеть логи абонента'),)},
),
migrations.AlterModelOptions(
name='additionaltelephone',
options={'ordering': ('owner_name',), 'permissions': (('can_view_additionaltelephones', 'Может видеть дополнительные телефоны'),), 'verbose_name': 'Дополнительный телефон', 'verbose_name_plural': 'Дополнительные телефоны'},
),
migrations.AlterModelOptions(
name='invoiceforpayment',
options={'ordering': ('date_create',), 'permissions': (('can_view_invoiceforpayment', 'Может видеть назначенные платежи'),), 'verbose_name': 'Квитанция (долг)', 'verbose_name_plural': 'Квитанции (долги)'},
),
migrations.AlterModelOptions(
name='passportinfo',
options={'verbose_name': 'Паспортные данные', 'verbose_name_plural': 'Паспортные данные'},
),
migrations.AlterModelTable(
name='passportinfo',
table='passport_info',
),
]

130
abonapp/migrations/0004_auto_20180122_1732.py

@ -1,130 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-01-22 17:32
from __future__ import unicode_literals
from django.conf import settings
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('tariff_app', '0006_auto_20180122_1732'),
('abonapp', '0003_auto_20170927_1838'),
]
operations = [
migrations.CreateModel(
name='PeriodicPayForId',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('last_pay', models.DateTimeField(blank=True, null=True, verbose_name='Last pay time')),
('next_pay', models.DateTimeField(verbose_name='Next time to pay')),
],
options={
'db_table': 'periodic_pay_for_id',
},
),
migrations.AlterModelOptions(
name='abon',
options={'ordering': ['fio'], 'permissions': (('can_buy_tariff', 'Buy service perm'), ('can_view_passport', 'Can view passport'), ('can_add_ballance', 'fill account'), ('can_ping', 'Can ping')), 'verbose_name': 'Abon', 'verbose_name_plural': 'Abons'},
),
migrations.AlterModelOptions(
name='abongroup',
options={'ordering': ['title'], 'permissions': (('can_view_abongroup', 'Can view subscriber group'),), 'verbose_name': 'Abon group', 'verbose_name_plural': 'Abon groups'},
),
migrations.AlterModelOptions(
name='abonlog',
options={'ordering': ['-date'], 'permissions': (('can_view_abonlog', 'Can view subscriber logs'),)},
),
migrations.AlterModelOptions(
name='abonstreet',
options={'ordering': ['name'], 'verbose_name': 'Street', 'verbose_name_plural': 'Streets'},
),
migrations.AlterModelOptions(
name='abontariff',
options={'ordering': ['time_start'], 'permissions': (('can_complete_service', 'finish service perm'),), 'verbose_name': 'Abon service', 'verbose_name_plural': 'Abon services'},
),
migrations.AlterModelOptions(
name='additionaltelephone',
options={'ordering': ('owner_name',), 'permissions': (('can_view_additionaltelephones', 'Can view additional telephones'),), 'verbose_name': 'Additional telephone', 'verbose_name_plural': 'Additional telephones'},
),
migrations.AlterModelOptions(
name='allpaylog',
options={'ordering': ['-date_action']},
),
migrations.AlterModelOptions(
name='alltimepaylog',
options={'ordering': ['-date_add']},
),
migrations.AlterModelOptions(
name='invoiceforpayment',
options={'ordering': ('date_create',), 'permissions': (('can_view_invoiceforpayment', 'Can view invoice for payment'),), 'verbose_name': 'Debt', 'verbose_name_plural': 'Debts'},
),
migrations.AlterModelOptions(
name='passportinfo',
options={'verbose_name': 'Passport Info', 'verbose_name_plural': 'Passport Info'},
),
migrations.AddField(
model_name='alltimepaylog',
name='abon',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, to='abonapp.Abon'),
),
migrations.AddField(
model_name='alltimepaylog',
name='receipt_num',
field=models.IntegerField(default=0, verbose_name='Receipt number'),
),
migrations.AddField(
model_name='alltimepaylog',
name='trade_point',
field=models.CharField(blank=True, default=None, max_length=20, null=True, verbose_name='Trade point'),
),
migrations.AlterField(
model_name='abon',
name='description',
field=models.TextField(blank=True, null=True, verbose_name='Comment'),
),
migrations.AlterField(
model_name='abon',
name='group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonGroup', verbose_name='User group'),
),
migrations.AlterField(
model_name='abon',
name='house',
field=models.CharField(blank=True, max_length=12, null=True, verbose_name='House'),
),
migrations.AlterField(
model_name='abon',
name='street',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonStreet', verbose_name='Street'),
),
migrations.AlterField(
model_name='abonlog',
name='author',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='additionaltelephone',
name='telephone',
field=models.CharField(max_length=16, validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')], verbose_name='Telephone'),
),
migrations.AlterField(
model_name='extrafieldsmodel',
name='field_type',
field=models.CharField(choices=[('int', 'Digital field'), ('str', 'Text field'), ('dbl', 'Floating field'), ('ipa', 'Ip Address')], default='str', max_length=3),
),
migrations.AddField(
model_name='periodicpayforid',
name='account',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon', verbose_name='Account'),
),
migrations.AddField(
model_name='periodicpayforid',
name='periodic_pay',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tariff_app.PeriodicPay', verbose_name='Periodic pay'),
),
]

20
abonapp/migrations/0005_auto_20180123_1353.py

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-01-23 13:53
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('abonapp', '0004_auto_20180122_1732'),
]
operations = [
migrations.AlterField(
model_name='alltimepaylog',
name='receipt_num',
field=models.BigIntegerField(default=0, verbose_name='Receipt number'),
),
]

23
abonapp/migrations/0006_abon_markers.py

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-02-13 14:06
from __future__ import unicode_literals
import bitfield.models
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('abonapp', '0005_auto_20180123_1353'),
]
operations = [
migrations.AddField(
model_name='abon',
name='markers',
field=bitfield.models.BitField((('icon_donkey', 'Donkey'), ('icon_fire', 'Fire'), ('icon_ok', 'Ok'),
('icon_king', 'King'), ('icon_tv', 'TV'), ('icon_smile', 'Smile'),
('icon_dollar', 'Dollar'), ('icon_service', 'Service'),
('icon_mrk', 'Marker')), default=None),
),
]

96
abonapp/models.py

@ -5,13 +5,14 @@ from django.core import validators
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.db import models, connection, transaction from django.db import models, connection, transaction
from django.db.models.signals import post_save, post_delete, pre_delete, post_init
from django.db.models.signals import post_delete, pre_delete, post_init
from django.dispatch import receiver from django.dispatch import receiver
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _, gettext
from accounts_app.models import UserProfile, MyUserManager
from accounts_app.models import UserProfile, MyUserManager, BaseAccount
from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNetworkError from agent import Transmitter, AbonStruct, TariffStruct, NasFailedResult, NasNetworkError
from group_app.models import Group
from mydefs import MyGenericIPAddressField, ip2int, LogicError, ip_addr_regex from mydefs import MyGenericIPAddressField, ip2int, LogicError, ip_addr_regex
from tariff_app.models import Tariff, PeriodicPay from tariff_app.models import Tariff, PeriodicPay
from bitfield import BitField from bitfield import BitField
@ -20,24 +21,6 @@ from bitfield import BitField
TELEPHONE_REGEXP = getattr(settings, 'TELEPHONE_REGEXP', r'^\+[7,8,9,3]\d{10,11}$') TELEPHONE_REGEXP = getattr(settings, 'TELEPHONE_REGEXP', r'^\+[7,8,9,3]\d{10,11}$')
class AbonGroup(models.Model):
title = models.CharField(max_length=127, unique=True)
profiles = models.ManyToManyField(UserProfile, blank=True, related_name='abon_groups')
tariffs = models.ManyToManyField(Tariff, blank=True, related_name='tariff_groups')
class Meta:
db_table = 'abonent_groups'
permissions = (
('can_view_abongroup', _('Can view subscriber group')),
)
verbose_name = _('Abon group')
verbose_name_plural = _('Abon groups')
ordering = ['title']
def __str__(self):
return self.title
class AbonLog(models.Model): class AbonLog(models.Model):
abon = models.ForeignKey('Abon', models.CASCADE) abon = models.ForeignKey('Abon', models.CASCADE)
amount = models.FloatField(default=0.0) amount = models.FloatField(default=0.0)
@ -89,7 +72,7 @@ class AbonTariff(models.Model):
class AbonStreet(models.Model): class AbonStreet(models.Model):
name = models.CharField(max_length=64) name = models.CharField(max_length=64)
group = models.ForeignKey(AbonGroup, models.CASCADE)
group = models.ForeignKey(Group, models.CASCADE)
def __str__(self): def __str__(self):
return self.name return self.name
@ -149,9 +132,9 @@ class AbonManager(MyUserManager):
return super(MyUserManager, self).get_queryset().filter(is_admin=False) return super(MyUserManager, self).get_queryset().filter(is_admin=False)
class Abon(UserProfile):
class Abon(BaseAccount):
current_tariff = models.ForeignKey(AbonTariff, null=True, blank=True, on_delete=models.SET_NULL) current_tariff = models.ForeignKey(AbonTariff, null=True, blank=True, on_delete=models.SET_NULL)
group = models.ForeignKey(AbonGroup, models.SET_NULL, blank=True, null=True, verbose_name=_('User group'))
group = models.ForeignKey(Group, models.SET_NULL, blank=True, null=True, verbose_name=_('User group'))
ballance = models.FloatField(default=0.0) ballance = models.FloatField(default=0.0)
ip_address = MyGenericIPAddressField(blank=True, null=True) ip_address = MyGenericIPAddressField(blank=True, null=True)
description = models.TextField(_('Comment'), null=True, blank=True) description = models.TextField(_('Comment'), null=True, blank=True)
@ -204,13 +187,6 @@ class Abon(UserProfile):
verbose_name_plural = _('Abons') verbose_name_plural = _('Abons')
ordering = ['fio'] ordering = ['fio']
# pay something
def make_pay(self, curuser, how_match_to_pay=0.0):
post_save.disconnect(abon_post_save, sender=Abon)
self.ballance -= how_match_to_pay
self.save(update_fields=['ballance'])
post_save.connect(abon_post_save, sender=Abon)
def add_ballance(self, current_user, amount, comment): def add_ballance(self, current_user, amount, comment):
AbonLog.objects.create( AbonLog.objects.create(
abon=self, abon=self,
@ -226,8 +202,11 @@ class Abon(UserProfile):
amount = round(tariff.amount, 2) amount = round(tariff.amount, 2)
if not author.is_staff and tariff.is_admin:
raise LogicError(_('User that is no staff can not buy admin services'))
if tariff.is_admin:
if author is not None and not author.is_staff:
raise LogicError(_('User that is no staff can not buy admin services'))
else:
raise LogicError(_('This user can not buy admin services'))
if self.current_tariff is not None: if self.current_tariff is not None:
if self.current_tariff.tariff == tariff: if self.current_tariff.tariff == tariff:
@ -298,6 +277,23 @@ class Abon(UserProfile):
raise LogicError(_('Ip address already exist')) raise LogicError(_('Ip address already exist'))
super(Abon, self).save(*args, **kwargs) super(Abon, self).save(*args, **kwargs)
def sync_with_nas(self, created: bool):
timeout = None
if hasattr(self, 'is_dhcp') and self.is_dhcp:
timeout = getattr(settings, 'DHCP_TIMEOUT', 14400)
agent_abon = self.build_agent_struct()
if agent_abon is None:
return True
try:
tm = Transmitter()
if created:
tm.add_user(agent_abon, ip_timeout=timeout)
else:
tm.update_user(agent_abon, ip_timeout=timeout)
except (NasFailedResult, NasNetworkError, ConnectionResetError) as e:
print('ERROR:', e)
return True
class PassportInfo(models.Model): class PassportInfo(models.Model):
series = models.CharField(max_length=4, validators=[validators.integer_validator]) series = models.CharField(max_length=4, validators=[validators.integer_validator])
@ -354,7 +350,6 @@ class AllTimePayLogManager(models.Manager):
r = cur.fetchone() r = cur.fetchone()
if r is None: break if r is None: break
summ, dat = r summ, dat = r
print(summ, dat)
yield {'summ': summ, 'pay_date': datetime.strptime(dat, '%Y-%m-%d')} yield {'summ': summ, 'pay_date': datetime.strptime(dat, '%Y-%m-%d')}
@ -443,14 +438,10 @@ class PeriodicPayForId(models.Model):
next_pay_date = pp.get_next_time_to_pay(self.last_pay) next_pay_date = pp.get_next_time_to_pay(self.last_pay)
abon = self.account abon = self.account
with transaction.atomic(): with transaction.atomic():
abon.make_pay(author, amount)
AbonLog.objects.create(
abon=abon, amount=-amount,
author=author,
comment=comment or _('Charge for "%(service)s"') % {
'service': self.periodic_pay
}
)
abon.add_ballance(author, -amount, comment=gettext('Charge for "%(service)s"') % {
'service': self.periodic_pay
})
abon.save(update_fields=['ballance'])
self.last_pay = now self.last_pay = now
self.next_pay = next_pay_date self.next_pay = next_pay_date
self.save(update_fields=['last_pay', 'next_pay']) self.save(update_fields=['last_pay', 'next_pay'])
@ -462,27 +453,6 @@ class PeriodicPayForId(models.Model):
db_table = 'periodic_pay_for_id' db_table = 'periodic_pay_for_id'
@receiver(post_save, sender=Abon)
def abon_post_save(sender, **kwargs):
instance, created = kwargs["instance"], kwargs["created"]
timeout = None
if hasattr(instance, 'is_dhcp') and instance.is_dhcp:
timeout = getattr(settings, 'DHCP_TIMEOUT', 14400)
agent_abon = instance.build_agent_struct()
if agent_abon is None:
return True
try:
tm = Transmitter()
if created:
tm.add_user(agent_abon, ip_timeout=timeout)
else:
tm.update_user(agent_abon, ip_timeout=timeout)
except (NasFailedResult, NasNetworkError, ConnectionResetError) as e:
print('ERROR:', e)
return True
@receiver(post_delete, sender=Abon) @receiver(post_delete, sender=Abon)
def abon_del_signal(sender, **kwargs): def abon_del_signal(sender, **kwargs):
abon = kwargs["instance"] abon = kwargs["instance"]

4
abonapp/templates/abonapp/addAbon.html

@ -5,7 +5,7 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li> <li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li><a href="{% url 'abonapp:people_list' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonapp:people_list' group.id %}">{{ group.title }}</a></li>
<li class="active">{% trans 'Add abon' %}</li> <li class="active">{% trans 'Add abon' %}</li>
</ol> </ol>
@ -16,7 +16,7 @@
<h3 class="panel-title">{% trans 'Add abon' %}</h3> <h3 class="panel-title">{% trans 'Add abon' %}</h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form role="form" action="{% url 'abonapp:add_abon' abon_group.id %}" method="post">{% csrf_token %}
<form role="form" action="{% url 'abonapp:add_abon' group.id %}" method="post">{% csrf_token %}
<div class="form-group"> <div class="form-group">
<label for="login">{% trans 'login' %}</label> <label for="login">{% trans 'login' %}</label>

39
abonapp/templates/abonapp/addGroup.html

@ -1,39 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li class="active">{% trans 'Add group' %}</li>
</ol>
{% include 'message_block.html' %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'Add group' %}</h3>
</div>
<div class="panel-body">
<form role="form" action="{% url 'abonapp:add_group' %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="gtitle">{% trans 'Group title' %}</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-bookmark"></span></span>
<input id="gtitle" type="text" name="title" required class="form-control">{{ form.title.errors }}
</div>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> {% trans 'Save' %}
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Reset' %}
</button>
</div>
</form>
</div>
</div>
{% endblock %}

8
abonapp/templates/abonapp/addInvoice.html

@ -5,8 +5,8 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li> <li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li><a href="{% url 'abonapp:people_list' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonapp:abon_home' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li><a href="{% url 'abonapp:people_list' group.id %}">{{ group.title }}</a></li>
<li><a href="{% url 'abonapp:abon_home' group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">{% trans 'Add debt' %}</li> <li class="active">{% trans 'Add debt' %}</li>
</ol> </ol>
@ -15,11 +15,11 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title">{% trans 'Add receipt for' %} <h3 class="panel-title">{% trans 'Add receipt for' %}
<u><a href="{% url 'abonapp:abon_home' abon_group.id abon.id %}">{{ abon.fio }}</a></u>
<u><a href="{% url 'abonapp:abon_home' group.id abon.id %}">{{ abon.fio }}</a></u>
</h3> </h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form role="form" action="{% url 'abonapp:add_invoice' abon_group.id abon.id %}"
<form role="form" action="{% url 'abonapp:add_invoice' group.id abon.id %}"
method="post">{% csrf_token %} method="post">{% csrf_token %}
<div class="form-group"> <div class="form-group">
<label for="pamount">{% trans 'Sum of pay' %}</label> <label for="pamount">{% trans 'Sum of pay' %}</label>

10
abonapp/templates/abonapp/buy_tariff.html

@ -5,8 +5,8 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li> <li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li><a href="{% url 'abonapp:people_list' abon_group.pk %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonapp:abon_home' abon_group.pk abon.pk %}">{{ abon.fio }}</a></li>
<li><a href="{% url 'abonapp:people_list' group.pk %}">{{ group.title }}</a></li>
<li><a href="{% url 'abonapp:abon_home' group.pk abon.pk %}">{{ abon.fio }}</a></li>
<li class="active">{% trans 'Pick a service' %}</li> <li class="active">{% trans 'Pick a service' %}</li>
</ol> </ol>
@ -15,11 +15,11 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title">{% trans 'Pick a service for' %} <h3 class="panel-title">{% trans 'Pick a service for' %}
<a href="{% url 'abonapp:abon_home' abon_group.pk abon.pk %}"><u>{% trans 'Sub' %}</u></a>
<a href="{% url 'abonapp:abon_home' group.pk abon.pk %}"><u>{% trans 'Sub' %}</u></a>
</h3> </h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form role="form" action="{% url 'abonapp:pick_tariff' abon_group.pk abon.pk %}"
<form role="form" action="{% url 'abonapp:pick_tariff' group.pk abon.pk %}"
method="post">{% csrf_token %} method="post">{% csrf_token %}
<div class="form-group"> <div class="form-group">
{% if tariffs %} {% if tariffs %}
@ -59,7 +59,7 @@
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign"></span> <span class="glyphicon glyphicon-exclamation-sign"></span>
{% trans 'This group has no services' %}, {% trans 'This group has no services' %},
<a href="{% url 'abonapp:ch_group_tariff' abon_group.pk %}">
<a href="{% url 'abonapp:ch_group_tariff' group.pk %}">
{% trans 'Attach serices to groups' %} {% trans 'Attach serices to groups' %}
</a> </a>
</div> </div>

2
abonapp/templates/abonapp/charts.html

@ -11,7 +11,7 @@
<div class="panel-body"> <div class="panel-body">
{% if charts_data %} {% if charts_data %}
<div id="chrt"></div> <div id="chrt"></div>
<form action="{% url 'abonapp:charts' abon_group.pk abon.pk %}" method="get" class="input-group">
<form action="{% url 'abonapp:charts' group.pk abon.pk %}" method="get" class="input-group">
<span class="input-group-btn"> <span class="input-group-btn">
<button class="btn btn-default" type="submit"> <button class="btn btn-default" type="submit">
<span class="glyphicon glyphicon-calendar"></span> {% trans 'Show graph by date' %} <span class="glyphicon glyphicon-calendar"></span> {% trans 'Show graph by date' %}

24
abonapp/templates/abonapp/editAbon.html

@ -10,7 +10,7 @@
<h3 class="panel-title">{% trans 'Change subscriber' %}</h3> <h3 class="panel-title">{% trans 'Change subscriber' %}</h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form autocomplete="off" class="form-horizontal" action="{% url 'abonapp:abon_home' abon_group.pk abon.pk %}" method="post">{% csrf_token %}
<form autocomplete="off" class="form-horizontal" action="{% url 'abonapp:abon_home' group.pk abon.pk %}" method="post">{% csrf_token %}
{% bootstrap_field form.username label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %} {% bootstrap_field form.username label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
{% bootstrap_field form.fio label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %} {% bootstrap_field form.fio label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
@ -24,10 +24,10 @@
<a href="sip:{{ form.telephone.value }}" class="btn btn-default" data-toggle="tooltip" title="{% trans 'Call to' %}"> <a href="sip:{{ form.telephone.value }}" class="btn btn-default" data-toggle="tooltip" title="{% trans 'Call to' %}">
<span class="glyphicon glyphicon-earphone"></span> <span class="glyphicon glyphicon-earphone"></span>
</a> </a>
<a href="{% url 'abonapp:telephones' abon_group.pk abon.pk %}" class="btn btn-default btn-modal" data-toggle="tooltip" title="{% trans 'Additional telephones' %}">
<a href="{% url 'abonapp:telephones' group.pk abon.pk %}" class="btn btn-default btn-modal" data-toggle="tooltip" title="{% trans 'Additional telephones' %}">
<span class="glyphicon glyphicon-list"></span> <span class="glyphicon glyphicon-list"></span>
</a> </a>
<a href="{% url 'abonapp:telephone_new' abon_group.pk abon.pk %}" class="btn btn-default btn-modal" data-toggle="tooltip" title="{% trans 'Add telephone' %}">
<a href="{% url 'abonapp:telephone_new' group.pk abon.pk %}" class="btn btn-default btn-modal" data-toggle="tooltip" title="{% trans 'Add telephone' %}">
<span class="glyphicon glyphicon-plus"></span> <span class="glyphicon glyphicon-plus"></span>
</a> </a>
</span> </span>
@ -41,7 +41,7 @@
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<input type="text" value="{{ ip|default:'' }}" class="form-control" name="ip" placeholder="{% trans 'Not assigned' %}" id="ipfield" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"{% if abon.is_dynamic_ip %} disabled{% endif %}/> <input type="text" value="{{ ip|default:'' }}" class="form-control" name="ip" placeholder="{% trans 'Not assigned' %}" id="ipfield" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"{% if abon.is_dynamic_ip %} disabled{% endif %}/>
<span class="input-group-btn"> <span class="input-group-btn">
<a href="{% url 'abonapp:reset_ip' abon_group.pk abon.pk %}" class="btn btn-default btn-cmd" data-toggle="tooltip" title="{% trans 'Reset ip' %}" onclick="$('#ipfield').val('');">
<a href="{% url 'abonapp:reset_ip' group.pk abon.pk %}" class="btn btn-default btn-cmd" data-toggle="tooltip" title="{% trans 'Reset ip' %}" onclick="$('#ipfield').val('');">
<span class="glyphicon glyphicon-refresh"></span> <span class="glyphicon glyphicon-refresh"></span>
</a> </a>
</span> </span>
@ -116,20 +116,20 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form class="form-horizontal" action="{% url 'abonapp:save_user_dev_port' abon_group.pk abon.pk %}" method="post">{% csrf_token %}
<form class="form-horizontal" action="{% url 'abonapp:save_user_dev_port' group.pk abon.pk %}" method="post">{% csrf_token %}
<div class="form-group-sm"> <div class="form-group-sm">
<label for="id_method" class="col-sm-4 control-label">{% trans 'Device' %}</label> <label for="id_method" class="col-sm-4 control-label">{% trans 'Device' %}</label>
<div class="col-sm-8 btn-group btn-group-sm"> <div class="col-sm-8 btn-group btn-group-sm">
{% if device %} {% if device %}
<a href="{% url 'devapp:view' abon_group.pk device.pk %}" target="_blank" class="btn btn-sm btn-default" title="{% trans 'Mac Address' %}: {{ device.mac_addr|default:_('Not assigned') }}">
<a href="{% url 'devapp:view' group.pk device.pk %}" target="_blank" class="btn btn-sm btn-default" title="{% trans 'Mac Address' %}: {{ device.mac_addr|default:_('Not assigned') }}">
<span class="glyphicon glyphicon-hdd"></span> <span class="hidden-md">{{ device.comment|truncatechars:11 }} {{ device.ip_address }}</span> <span class="glyphicon glyphicon-hdd"></span> <span class="hidden-md">{{ device.comment|truncatechars:11 }} {{ device.ip_address }}</span>
</a> </a>
<a href="{% url 'abonapp:clear_dev' abon_group.pk abon.pk %}" class="btn btn-sm btn-danger">
<a href="{% url 'abonapp:clear_dev' group.pk abon.pk %}" class="btn btn-sm btn-danger">
<span class="glyphicon glyphicon-remove-circle"></span> <span class="hidden-xs hidden-lg">{% trans 'Remove clutch' %}</span> <span class="glyphicon glyphicon-remove-circle"></span> <span class="hidden-xs hidden-lg">{% trans 'Remove clutch' %}</span>
</a> </a>
{% else %} {% else %}
<a href="{% url 'abonapp:dev' abon_group.pk abon.pk %}" class="btn btn-success btn-sm btn-modal">
<a href="{% url 'abonapp:dev' group.pk abon.pk %}" class="btn btn-success btn-sm btn-modal">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add clutch' %} <span class="glyphicon glyphicon-plus"></span> {% trans 'Add clutch' %}
</a> </a>
{% endif %} {% endif %}
@ -177,7 +177,7 @@
<h3 class="panel-title">{% trans 'Extra fields' %}</h3> <h3 class="panel-title">{% trans 'Extra fields' %}</h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form class="form-horizontal" action="{% url 'abonapp:extra_field_edit' abon_group.pk abon.pk %}" method="post">{% csrf_token %}
<form class="form-horizontal" action="{% url 'abonapp:extra_field_edit' group.pk abon.pk %}" method="post">{% csrf_token %}
{% for ef in abon.extra_fields.all %} {% for ef in abon.extra_fields.all %}
<div class="form-group-sm"> <div class="form-group-sm">
@ -188,7 +188,7 @@
<input type="text" value="{{ ef.data|default:_('Not assigned') }}" class="form-control" pattern="{{ ef.get_regexp }}" name="ex"> <input type="text" value="{{ ef.data|default:_('Not assigned') }}" class="form-control" pattern="{{ ef.get_regexp }}" name="ex">
<input type="hidden" value="{{ ef.pk }}" name="ed"> <input type="hidden" value="{{ ef.pk }}" name="ed">
<span class="input-group-btn"> <span class="input-group-btn">
<a href="{% url 'abonapp:extra_field_delete' abon_group.pk abon.pk ef.pk %}" class="btn btn-danger" title="{% trans 'Delete' %}">
<a href="{% url 'abonapp:extra_field_delete' group.pk abon.pk ef.pk %}" class="btn btn-danger" title="{% trans 'Delete' %}">
<span class="glyphicon glyphicon-remove"></span> <span class="glyphicon glyphicon-remove"></span>
</a> </a>
</span> </span>
@ -202,7 +202,7 @@
<div class="form-group-sm"> <div class="form-group-sm">
<div class="col-sm-offset-4 col-sm-8 btn-group btn-group-sm"> <div class="col-sm-offset-4 col-sm-8 btn-group btn-group-sm">
<a href="{% url 'abonapp:extra_field' abon_group.pk abon.pk %}" class="btn btn-success btn-modal" title="{% trans 'Add extra field' %}">
<a href="{% url 'abonapp:extra_field' group.pk abon.pk %}" class="btn btn-success btn-modal" title="{% trans 'Add extra field' %}">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %} <span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %}
</a> </a>
@ -227,7 +227,7 @@
</div> </div>
<div class="panel-footer"> <div class="panel-footer">
<div class="btn-group"> <div class="btn-group">
<a href="{% url 'abonapp:markers_edit' abon_group.pk abon.pk %}" class="btn btn-default btn-modal">
<a href="{% url 'abonapp:markers_edit' group.pk abon.pk %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-edit"></span> {% trans 'Edit' %} <span class="glyphicon glyphicon-edit"></span> {% trans 'Edit' %}
</a> </a>
</div> </div>

16
abonapp/templates/abonapp/ext.htm

@ -5,7 +5,7 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li> <li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li><a href="{% url 'abonapp:people_list' abon_group.pk %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonapp:people_list' group.pk %}">{{ group.title }}</a></li>
<li class="active">{{ abon.fio }}</li> <li class="active">{{ abon.fio }}</li>
</ol> </ol>
@ -21,39 +21,39 @@
<ul class="nav nav-tabs nav-justified"> <ul class="nav nav-tabs nav-justified">
{% url 'abonapp:abon_home' abon_group.pk abon.pk as abon_home %}
{% url 'abonapp:abon_home' group.pk abon.pk as abon_home %}
<li{% if abon_home == request.path %} class="active"{% endif %}> <li{% if abon_home == request.path %} class="active"{% endif %}>
<a href="{{ abon_home }}">{% trans 'Sub information' %}</a> <a href="{{ abon_home }}">{% trans 'Sub information' %}</a>
</li> </li>
{% url 'abonapp:abon_services' abon_group.pk abon.pk as abserv %}
{% url 'abonapp:abon_services' group.pk abon.pk as abserv %}
<li{% if abserv == request.path %} class="active"{% endif %}> <li{% if abserv == request.path %} class="active"{% endif %}>
<a href="{{ abserv }}">{% trans 'Services' %}</a> <a href="{{ abserv }}">{% trans 'Services' %}</a>
</li> </li>
{% if perms.abonapp.can_view_passport %} {% if perms.abonapp.can_view_passport %}
{% url 'abonapp:passport_view' abon_group.pk abon.pk as passport_view_url %}
{% url 'abonapp:passport_view' group.pk abon.pk as passport_view_url %}
<li{% if passport_view_url == request.path %} class="active"{% endif %}> <li{% if passport_view_url == request.path %} class="active"{% endif %}>
<a href="{{ passport_view_url }}">{% trans 'Passport information' %}</a> <a href="{{ passport_view_url }}">{% trans 'Passport information' %}</a>
</li> </li>
{% endif %} {% endif %}
{% url 'abonapp:abon_phistory' abon_group.pk abon.pk as abphist %}
{% url 'abonapp:abon_phistory' group.pk abon.pk as abphist %}
<li{% if abphist == request.path %} class="active"{% endif %}> <li{% if abphist == request.path %} class="active"{% endif %}>
<a href="{{ abphist }}">{% trans 'Payments' %}</a> <a href="{{ abphist }}">{% trans 'Payments' %}</a>
</li> </li>
{% url 'abonapp:task_log' abon_group.pk abon.pk as abtasklog %}
{% url 'abonapp:task_log' group.pk abon.pk as abtasklog %}
<li{% if abtasklog == request.path %} class="active"{% endif %}> <li{% if abtasklog == request.path %} class="active"{% endif %}>
<a href="{{ abtasklog }}">{% trans 'History of tasks' %}</a> <a href="{{ abtasklog }}">{% trans 'History of tasks' %}</a>
</li> </li>
{% url 'abonapp:charts' abon_group.pk abon.pk as abtasklog %}
{% url 'abonapp:charts' group.pk abon.pk as abtasklog %}
<li{% if abtasklog == request.path %} class="active"{% endif %}> <li{% if abtasklog == request.path %} class="active"{% endif %}>
<a href="{{ abtasklog }}">{% trans 'Charts' %}</a> <a href="{{ abtasklog }}">{% trans 'Charts' %}</a>
</li> </li>
{% url 'abonapp:dials' abon_group.pk abon.pk as abdials %}
{% url 'abonapp:dials' group.pk abon.pk as abdials %}
<li{% if abdials == request.path %} class="active"{% endif %}> <li{% if abdials == request.path %} class="active"{% endif %}>
<a href="{{ abdials }}">{% trans 'Dialing' %}</a> <a href="{{ abdials }}">{% trans 'Dialing' %}</a>
</li> </li>

12
abonapp/templates/abonapp/group_list.html

@ -35,13 +35,6 @@
<td><a href="{% url 'abonapp:people_list' gr.pk %}">{{ gr.title }}</a></td> <td><a href="{% url 'abonapp:people_list' gr.pk %}">{{ gr.title }}</a></td>
<td class="hidden-xs">{{ gr.usercount }}</td> <td class="hidden-xs">{{ gr.usercount }}</td>
<td class="btn-group"> <td class="btn-group">
{% if perms.abonapp.delete_abongroup %}
{% if gr.usercount == 0 %}
<a href="{% url 'abonapp:del_group' %}?id={{ gr.pk }}" class="btn btn-sm btn-danger">
<span class="glyphicon glyphicon-remove-circle"></span>
</a>
{% endif %}
{% endif %}
<a href="{% url 'abonapp:ch_group_tariff' gr.pk %}" class="btn btn-sm btn-default" <a href="{% url 'abonapp:ch_group_tariff' gr.pk %}" class="btn btn-sm btn-default"
title="{% trans 'User groups' %}"> title="{% trans 'User groups' %}">
<span class="glyphicon glyphicon-cog"></span> <span class="glyphicon glyphicon-cog"></span>
@ -57,11 +50,6 @@
<tfoot> <tfoot>
<tr> <tr>
<td colspan="4" class="btn-group btn-group-sm"> <td colspan="4" class="btn-group btn-group-sm">
{% if perms.abonapp.add_abongroup %}
<a href="{% url 'abonapp:add_group' %}" class="btn btn-success">
<span class="glyphicon glyphicon-plus"></span> <span class="hidden-xs">{% trans 'Add group' %}</span>
</a>
{% endif %}
{% if perms.abonapp.can_view_abonlog %} {% if perms.abonapp.can_view_abonlog %}
<a href="{% url 'abonapp:log' %}" class="btn btn-default"> <a href="{% url 'abonapp:log' %}" class="btn btn-default">
<span class="glyphicon glyphicon-record"></span> <span class="hidden-xs">{% trans 'Subscribers actions' %}</span> <span class="glyphicon glyphicon-record"></span> <span class="hidden-xs">{% trans 'Subscribers actions' %}</span>

6
abonapp/templates/abonapp/group_tariffs.html

@ -5,18 +5,18 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li> <li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li><a href="{% url 'abonapp:people_list' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonapp:people_list' group.id %}">{{ group.title }}</a></li>
<li class="active">{% trans 'Belonging services for groups' %}</li> <li class="active">{% trans 'Belonging services for groups' %}</li>
</ol> </ol>
{% include 'message_block.html' %} {% include 'message_block.html' %}
<legend>{% trans 'Belonging services for groups' %}</legend> <legend>{% trans 'Belonging services for groups' %}</legend>
<form action="{% url 'abonapp:ch_group_tariff' abon_group.pk %}" method="post" role="form">{% csrf_token %}
<form action="{% url 'abonapp:ch_group_tariff' group.pk %}" method="post" role="form">{% csrf_token %}
{% for tariff in tariffs %} {% for tariff in tariffs %}
<div class="checkbox"> <div class="checkbox">
<label> <label>
{% if tariff in abon_group.tariffs.all %}
{% if tariff.pk in seleted_tariffs %}
<input name="tr" type="checkbox" value="{{ tariff.pk }}" checked/> <input name="tr" type="checkbox" value="{{ tariff.pk }}" checked/>
{% else %} {% else %}
<input name="tr" type="checkbox" value="{{ tariff.pk }}"/> <input name="tr" type="checkbox" value="{{ tariff.pk }}"/>

6
abonapp/templates/abonapp/invoiceForPayment.html

@ -5,8 +5,8 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li> <li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li><a href="{% url 'abonapp:people_list' abon_group.pk %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonapp:abon_phistory' abon_group.pk abon.pk %}">{{ abon.fio }}</a></li>
<li><a href="{% url 'abonapp:people_list' group.pk %}">{{ group.title }}</a></li>
<li><a href="{% url 'abonapp:abon_phistory' group.pk abon.pk %}">{{ abon.fio }}</a></li>
<li class="active">{% trans 'Debts' %}</li> <li class="active">{% trans 'Debts' %}</li>
</ol> </ol>
@ -57,7 +57,7 @@
<tfoot> <tfoot>
<tr> <tr>
<th colspan="7"> <th colspan="7">
<a href="{% url 'abonapp:add_invoice' abon_group.id abon.id %}" class="btn btn-success btn-sm">
<a href="{% url 'abonapp:add_invoice' group.id abon.id %}" class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add debt' %} <span class="glyphicon glyphicon-plus"></span> {% trans 'Add debt' %}
</a> </a>
</th> </th>

7
abonapp/templates/abonapp/log.html

@ -39,7 +39,12 @@
</td> </td>
<td>{{ l.comment }}</td> <td>{{ l.comment }}</td>
<td>{{ l.date|date:"D d E Y H:i:s" }}</td> <td>{{ l.date|date:"D d E Y H:i:s" }}</td>
<td><a href="{% url 'acc_app:other_profile' l.author.id %}">{{ l.author.username }}</a></td>
<td>
{% if l.author %}
<a href="{% url 'acc_app:other_profile' l.author.id %}">{{ l.author.username }}</a></td>
{% else %}
---
{% endif %}
</tr> </tr>
{% empty %} {% empty %}
<tr> <tr>

3
abonapp/templates/abonapp/modal_abonamount.html

@ -1,6 +1,5 @@
{% load i18n %} {% load i18n %}
<form role="form" action="{% url 'abonapp:abon_amount' abon_group.id abon.id %}" method="post"> {% csrf_token %}
<form role="form" action="{% url 'abonapp:abon_amount' group_id abon.id %}" method="post"> {% csrf_token %}
<div class="modal-header primary"> <div class="modal-header primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title"><span class="glyphicon glyphicon-shopping-cart"></span>{% trans 'Additional sum' %}</h4> <h4 class="modal-title"><span class="glyphicon glyphicon-shopping-cart"></span>{% trans 'Additional sum' %}</h4>

2
abonapp/templates/abonapp/passport_view.html

@ -9,7 +9,7 @@
<h3 class="panel-title">{% trans 'Passport information' %}</h3> <h3 class="panel-title">{% trans 'Passport information' %}</h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form role="form" class="form-horizontal" action="{% url 'abonapp:passport_view' abon_group.pk abon.pk %}" method="post">{% csrf_token %}
<form role="form" class="form-horizontal" action="{% url 'abonapp:passport_view' group.pk abon.pk %}" method="post">{% csrf_token %}
<div class="form-group-sm"> <div class="form-group-sm">
<label for="id_series" class="col-sm-3 control-label">{% trans 'Pasport serial' %}</label> <label for="id_series" class="col-sm-3 control-label">{% trans 'Pasport serial' %}</label>

4
abonapp/templates/abonapp/payHistory.html

@ -36,7 +36,7 @@
<tr> <tr>
<td colspan="4" class="btn-group btn-group-sm"> <td colspan="4" class="btn-group btn-group-sm">
{% if perms.abonapp.can_add_ballance %} {% if perms.abonapp.can_add_ballance %}
<a href="{% url 'abonapp:abon_amount' abon_group.pk abon.pk %}" class="btn btn-default btn-modal">
<a href="{% url 'abonapp:abon_amount' group.pk abon.pk %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-credit-card"></span> {% trans 'Fill account' %} <span class="glyphicon glyphicon-credit-card"></span> {% trans 'Fill account' %}
</a> </a>
{% else %} {% else %}
@ -44,7 +44,7 @@
<span class="glyphicon glyphicon-credit-card"></span> {% trans 'Fill account' %} <span class="glyphicon glyphicon-credit-card"></span> {% trans 'Fill account' %}
</a> </a>
{% endif %} {% endif %}
<a href="{% url 'abonapp:abon_debts' abon_group.pk abon.pk %}" class="btn btn-default">
<a href="{% url 'abonapp:abon_debts' group.pk abon.pk %}" class="btn btn-default">
<span class="glyphicon glyphicon-gbp"></span> {% trans 'Debts' %} <span class="glyphicon glyphicon-gbp"></span> {% trans 'Debts' %}
</a> </a>
</td> </td>

40
abonapp/templates/abonapp/peoples.html

@ -3,13 +3,13 @@
{% load dpagination %} {% load dpagination %}
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li class="active">{{ abon_group.title }}</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abonapp:group_list' %}">{% trans 'User groups' %}</a></li>
<li class="active">{{ group.title }}</li>
</ol>
{% include 'message_block.html' %}
{% include 'message_block.html' %}
<h3>{% trans 'The people in the selected group' %}</h3> <h3>{% trans 'The people in the selected group' %}</h3>
<div class="row"> <div class="row">
@ -20,32 +20,32 @@
<tr> <tr>
<th>#</th> <th>#</th>
<th class="col-xs-1"> <th class="col-xs-1">
<a href="{% url 'abonapp:people_list' abon_group.pk %}?{% url_replace request order_by='username' dir=dir|default:'down' %}">
<a href="{% url 'abonapp:people_list' group.pk %}?{% url_replace request order_by='username' dir=dir|default:'down' %}">
{% trans 'Sub' %} {% trans 'Sub' %}
</a> </a>
{% if order_by == 'username' %}<span class="glyphicon glyphicon-filter"></span>{% endif %} {% if order_by == 'username' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th> </th>
<th class="hidden-xs">{% trans 'Last traffic' %}</th> <th class="hidden-xs">{% trans 'Last traffic' %}</th>
<th class="col-xs-1 hidden-md"> <th class="col-xs-1 hidden-md">
<a href="{% url 'abonapp:people_list' abon_group.pk %}?{% url_replace request order_by='ip_address' dir=dir|default:'down' %}">
<a href="{% url 'abonapp:people_list' group.pk %}?{% url_replace request order_by='ip_address' dir=dir|default:'down' %}">
{% trans 'Ip address' %} {% trans 'Ip address' %}
</a> </a>
{% if order_by == 'ip_address' %}<span class="glyphicon glyphicon-filter"></span>{% endif %} {% if order_by == 'ip_address' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th> </th>
<th class="col-xs-2"> <th class="col-xs-2">
<a href="{% url 'abonapp:people_list' abon_group.pk %}?{% url_replace request order_by='fio' dir=dir|default:'down' %}">
<a href="{% url 'abonapp:people_list' group.pk %}?{% url_replace request order_by='fio' dir=dir|default:'down' %}">
{% trans 'fio' %} {% trans 'fio' %}
</a> </a>
{% if order_by == 'fio' %}<span class="glyphicon glyphicon-filter"></span>{% endif %} {% if order_by == 'fio' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th> </th>
<th class="col-xs-2"> <th class="col-xs-2">
<a href="{% url 'abonapp:people_list' abon_group.pk %}?{% url_replace request order_by='street' dir=dir|default:'down' %}">
<a href="{% url 'abonapp:people_list' group.pk %}?{% url_replace request order_by='street' dir=dir|default:'down' %}">
{% trans 'Street' %} {% trans 'Street' %}
</a> </a>
{% if order_by == 'street' %}<span class="glyphicon glyphicon-filter"></span>{% endif %} {% if order_by == 'street' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th> </th>
<th class="col-xs-1"> <th class="col-xs-1">
<a href="{% url 'abonapp:people_list' abon_group.pk %}?{% url_replace request order_by='house' dir=dir|default:'down' %}">
<a href="{% url 'abonapp:people_list' group.pk %}?{% url_replace request order_by='house' dir=dir|default:'down' %}">
{% trans 'Apartment' %} {% trans 'Apartment' %}
</a> </a>
{% if order_by == 'house' %}<span class="glyphicon glyphicon-filter"></span>{% endif %} {% if order_by == 'house' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
@ -53,7 +53,7 @@
<th class="col-xs-2">{% trans 'Telephone' %}</th> <th class="col-xs-2">{% trans 'Telephone' %}</th>
<th class="col-xs-2">{% trans 'Service' %}</th> <th class="col-xs-2">{% trans 'Service' %}</th>
<th class="hidden-xs col-sm-1"> <th class="hidden-xs col-sm-1">
<a href="{% url 'abonapp:people_list' abon_group.pk %}?{% url_replace request order_by='ballance' dir=dir|default:'down' %}">
<a href="{% url 'abonapp:people_list' group.pk %}?{% url_replace request order_by='ballance' dir=dir|default:'down' %}">
{% trans 'Ballance' %} {% trans 'Ballance' %}
</a> </a>
{% if order_by == 'ballance' %}<span class="glyphicon glyphicon-filter"></span>{% endif %} {% if order_by == 'ballance' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
@ -121,7 +121,7 @@
<td colspan="12"> <td colspan="12">
{% trans 'Subscribers not found' %}. {% trans 'Subscribers not found' %}.
{% if perms.abonapp.add_abon %} {% if perms.abonapp.add_abon %}
<a href="{% url 'abonapp:add_abon' abon_group.pk %}">{% trans 'Add abon' %}</a>
<a href="{% url 'abonapp:add_abon' group.pk %}">{% trans 'Add abon' %}</a>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
@ -132,17 +132,17 @@
<tr> <tr>
<td colspan="12" class="btn-group btn-group-sm"> <td colspan="12" class="btn-group btn-group-sm">
{% if perms.abonapp.add_abon %} {% if perms.abonapp.add_abon %}
<a href="{% url 'abonapp:add_abon' abon_group.pk %}" class="btn btn-default" title="{% trans 'Add' %}" data-toggle="tooltip">
<a href="{% url 'abonapp:add_abon' group.pk %}" class="btn btn-default" title="{% trans 'Add' %}" data-toggle="tooltip">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add abon' %} <span class="glyphicon glyphicon-plus"></span> {% trans 'Add abon' %}
</a> </a>
{% endif %} {% endif %}
<a href="{% url 'abonapp:ch_group_tariff' abon_group.pk %}" class="btn btn-default" title="{% trans 'User groups' %}" data-toggle="tooltip">
<a href="{% url 'abonapp:ch_group_tariff' group.pk %}" class="btn btn-default" title="{% trans 'User groups' %}" data-toggle="tooltip">
<span class="glyphicon glyphicon-subscript"></span> {% trans 'Tariffs in groups' %} <span class="glyphicon glyphicon-subscript"></span> {% trans 'Tariffs in groups' %}
</a> </a>
<a href="{% url 'abonapp:phonebook' abon_group.pk %}" class="btn btn-default btn-modal">
<a href="{% url 'abonapp:phonebook' group.pk %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-earphone"></span> {% trans 'Phonebook' %} <span class="glyphicon glyphicon-earphone"></span> {% trans 'Phonebook' %}
</a> </a>
<a href="{% url 'abonapp:abon_export' abon_group.pk %}" class="btn btn-default btn-modal">
<a href="{% url 'abonapp:abon_export' group.pk %}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-export"></span> {% trans 'Export users' %} <span class="glyphicon glyphicon-export"></span> {% trans 'Export users' %}
</a> </a>
</td> </td>
@ -156,15 +156,15 @@
<div class="panel-heading">{% trans 'Streets' %}</div> <div class="panel-heading">{% trans 'Streets' %}</div>
<div class="list-group"> <div class="list-group">
{% for street in streets %} {% for street in streets %}
<a href="{% url 'abonapp:people_list' abon_group.pk %}?{% url_page_replace request 'street' street.pk %}" class="list-group-item{% if street_id == street.pk %} active{% endif %}">{{ street.name }}</a>
<a href="{% url 'abonapp:people_list' group.pk %}?{% url_page_replace request 'street' street.pk %}" class="list-group-item{% if street_id == street.pk %} active{% endif %}">{{ street.name }}</a>
{% empty %} {% empty %}
<a href="#" class="list-group-item">{% trans 'No streets found for that group' %}</a> <a href="#" class="list-group-item">{% trans 'No streets found for that group' %}</a>
{% endfor %} {% endfor %}
<div class="btn-group btn-group-sm btn-group-justified"> <div class="btn-group btn-group-sm btn-group-justified">
<a href="{% url 'abonapp:street_add' abon_group.pk %}" class="btn btn-success btn-modal" data-toggle="tooltip" title="{% trans 'Add street' %}">
<a href="{% url 'abonapp:street_add' group.pk %}" class="btn btn-success btn-modal" data-toggle="tooltip" title="{% trans 'Add street' %}">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %} <span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %}
</a> </a>
<a href="{% url 'abonapp:street_edit' abon_group.pk %}" class="btn btn-primary btn-modal" data-toggle="tooltip" title="{% trans 'Edit streets' %}">
<a href="{% url 'abonapp:street_edit' group.pk %}" class="btn btn-primary btn-modal" data-toggle="tooltip" title="{% trans 'Edit streets' %}">
<span class="glyphicon glyphicon-edit"></span> {% trans 'Edit' %} <span class="glyphicon glyphicon-edit"></span> {% trans 'Edit' %}
</a> </a>
</div> </div>

14
abonapp/templates/abonapp/service.html

@ -49,13 +49,13 @@
{% else %} {% else %}
{% trans 'Subscriber has no service' %}. {% trans 'Subscriber has no service' %}.
<a href="{% url 'abonapp:pick_tariff' abon_group.pk abon.pk %}">
<a href="{% url 'abonapp:pick_tariff' group.pk abon.pk %}">
{% trans 'Buy service' %} {% trans 'Buy service' %}
</a> </a>
{% endif %} {% endif %}
{% if abon_tariff %} {% if abon_tariff %}
<a href="{% url 'abonapp:unsubscribe_service' abon_group.pk abon.pk abon_tariff.pk %}" class="btn btn-sm btn-danger">
<a href="{% url 'abonapp:unsubscribe_service' group.pk abon.pk abon_tariff.pk %}" class="btn btn-sm btn-danger">
<span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Finish service' %} <span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Finish service' %}
</a> </a>
{% endif %} {% endif %}
@ -82,7 +82,7 @@
{% with can_ch_trf=perms.tariff_app.change_tariff %} {% with can_ch_trf=perms.tariff_app.change_tariff %}
{% for service in services %} {% for service in services %}
<tr> <tr>
<td><a href="{% url 'abonapp:pick_tariff' abon_group.pk abon.pk %}?selected_tariff={{ service.pk }}"
<td><a href="{% url 'abonapp:pick_tariff' group.pk abon.pk %}?selected_tariff={{ service.pk }}"
class="btn btn-sm btn-default" title="{{ service.get_calc_type_display }}" data-toggle="tooltip"{% if abon_tariff %} disabled{% endif %}> class="btn btn-sm btn-default" title="{{ service.get_calc_type_display }}" data-toggle="tooltip"{% if abon_tariff %} disabled{% endif %}>
<span class="glyphicon glyphicon-shopping-cart"></span> <span class="glyphicon glyphicon-shopping-cart"></span>
</a></td> </a></td>
@ -100,7 +100,7 @@
{% empty %} {% empty %}
<tr><td colspan="5"> <tr><td colspan="5">
{% trans 'This group has no services' %} {% trans 'This group has no services' %}
<a href="{% url 'abonapp:ch_group_tariff' abon_group.pk %}" class="btn btn-sm btn-default" title="{% trans 'User groups' %}">
<a href="{% url 'abonapp:ch_group_tariff' group.pk %}" class="btn btn-sm btn-default" title="{% trans 'User groups' %}">
<span class="glyphicon glyphicon-cog"></span> {% trans 'Tariffs in groups' %} <span class="glyphicon glyphicon-cog"></span> {% trans 'Tariffs in groups' %}
</a> </a>
</td></tr> </td></tr>
@ -108,7 +108,7 @@
{% endwith %} {% endwith %}
</tbody> </tbody>
</table> </table>
<a href="{% url 'abonapp:ch_group_tariff' abon_group.pk %}" class="btn btn-sm btn-primary" title="{% trans 'User groups' %}">
<a href="{% url 'abonapp:ch_group_tariff' group.pk %}" class="btn btn-sm btn-primary" title="{% trans 'User groups' %}">
<span class="glyphicon glyphicon-cog"></span> {% trans 'Attach services to group' %} <span class="glyphicon glyphicon-cog"></span> {% trans 'Attach services to group' %}
</a> </a>
</div> </div>
@ -131,11 +131,11 @@
<dt>{% trans 'Next time to pay' %}</dt> <dt>{% trans 'Next time to pay' %}</dt>
<dd>{{ periodic_pay.next_pay|date:'d E Y' }}</dd> <dd>{{ periodic_pay.next_pay|date:'d E Y' }}</dd>
</dl> </dl>
<a href="{% url 'abonapp:del_periodic_pay' abon_group.pk abon.pk periodic_pay.pk %}" class="btn btn-sm btn-danger">
<a href="{% url 'abonapp:del_periodic_pay' group.pk abon.pk periodic_pay.pk %}" class="btn btn-sm btn-danger">
<span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Remove periodic pay' %} <span class="glyphicon glyphicon-remove-circle"></span> {% trans 'Remove periodic pay' %}
</a> </a>
{% else %} {% else %}
<a href="{% url 'abonapp:add_periodic_pay' abon_group.pk abon.pk %}" class="btn btn-primary btn-sm btn-modal">
<a href="{% url 'abonapp:add_periodic_pay' group.pk abon.pk %}" class="btn btn-primary btn-sm btn-modal">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add periodic pay' %} <span class="glyphicon glyphicon-plus"></span> {% trans 'Add periodic pay' %}
</a> </a>
{% endif %} {% endif %}

2
abonapp/urls.py

@ -8,8 +8,6 @@ app_name = 'abonapp'
urlpatterns = [ urlpatterns = [
url(r'^$', views.GroupListView.as_view(), name='group_list'), url(r'^$', views.GroupListView.as_view(), name='group_list'),
url(r'^addgroup$', views.addgroup, name='add_group'),
url(r'^delgroup', views.delgroup, name='del_group'),
url(r'^fin_report$', views.fin_report, name='fin_report'), url(r'^fin_report$', views.fin_report, name='fin_report'),

245
abonapp/views.py

@ -3,7 +3,7 @@ from json import dumps
from django.contrib.gis.shortcuts import render_to_text from django.contrib.gis.shortcuts import render_to_text
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db import IntegrityError, ProgrammingError, transaction from django.db import IntegrityError, ProgrammingError, transaction
from django.db.models import Count, Q, signals
from django.db.models import Count, Q
from django.shortcuts import render, redirect, get_object_or_404, resolve_url from django.shortcuts import render, redirect, get_object_or_404, resolve_url
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
@ -24,6 +24,7 @@ from datetime import datetime, date, timedelta
from taskapp.models import Task from taskapp.models import Task
from dialing_app.models import AsteriskCDR from dialing_app.models import AsteriskCDR
from statistics.models import getModel from statistics.models import getModel
from group_app.models import Group
from guardian.shortcuts import get_objects_for_user, assign_perm from guardian.shortcuts import get_objects_for_user, assign_perm
from guardian.decorators import permission_required_or_403 as permission_required from guardian.decorators import permission_required_or_403 as permission_required
from djing.global_base_views import OrderingMixin, BaseListWithFiltering from djing.global_base_views import OrderingMixin, BaseListWithFiltering
@ -69,85 +70,39 @@ class PeoplesListView(BaseAbonListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
gid = mydefs.safe_int(self.kwargs.get('gid')) gid = mydefs.safe_int(self.kwargs.get('gid'))
if gid == 0: if gid == 0:
return Http404('group id is broken')
abon_group = get_object_or_404(models.AbonGroup, pk=gid)
if not self.request.user.has_perm('abonapp.can_view_abongroup', abon_group):
return HttpResponseBadRequest('group id is broken')
group = get_object_or_404(Group, pk=gid)
if not self.request.user.has_perm('group_app.can_view_group', group):
raise PermissionDenied raise PermissionDenied
context = super(PeoplesListView, self).get_context_data(**kwargs) context = super(PeoplesListView, self).get_context_data(**kwargs)
context['streets'] = models.AbonStreet.objects.filter(group=gid) context['streets'] = models.AbonStreet.objects.filter(group=gid)
context['street_id'] = mydefs.safe_int(self.request.GET.get('street')) context['street_id'] = mydefs.safe_int(self.request.GET.get('street'))
context['abon_group'] = abon_group
context['group'] = group
return context return context
@login_required
@permission_required('abonapp.add_abongroup')
def addgroup(request):
frm = forms.AbonGroupForm()
try:
if request.method == 'POST':
frm = forms.AbonGroupForm(request.POST)
if frm.is_valid():
grp = frm.save()
assign_perm('abonapp.can_view_abongroup', request.user, grp)
assign_perm('abonapp.delete_abongroup', request.user, grp)
assign_perm('abonapp.change_abongroup', request.user, grp)
messages.success(request, _('create group success msg'))
return redirect('abonapp:group_list')
else:
messages.error(request, _('fix form errors'))
except (NasFailedResult, NasNetworkError) as e:
messages.error(request, e)
except mydefs.MultipleException as errs:
for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
return render(request, 'abonapp/addGroup.html', {
'form': frm
})
class GroupListView(BaseAbonListView): class GroupListView(BaseAbonListView):
context_object_name = 'groups' context_object_name = 'groups'
template_name = 'abonapp/group_list.html' template_name = 'abonapp/group_list.html'
queryset = models.AbonGroup.objects.annotate(usercount=Count('abon')).order_by('title')
queryset = Group.objects.annotate(usercount=Count('abon'))
def get_queryset(self): def get_queryset(self):
queryset = super(GroupListView, self).get_queryset() queryset = super(GroupListView, self).get_queryset()
queryset = get_objects_for_user(self.request.user, 'abonapp.can_view_abongroup', klass=queryset,
queryset = get_objects_for_user(self.request.user, 'group_app.can_view_group', klass=queryset,
accept_global_perms=False) accept_global_perms=False)
return queryset return queryset
@login_required
def delgroup(request):
try:
agd = mydefs.safe_int(request.GET.get('id'))
abon_group = models.AbonGroup.objects.get(pk=agd)
if not request.user.has_perm('abonapp.delete_abongroup', abon_group):
raise PermissionDenied
abon_group.delete()
messages.success(request, _('delete group success msg'))
return mydefs.res_success(request, 'abonapp:group_list')
except (NasFailedResult, NasNetworkError) as e:
messages.error(request, e)
except mydefs.MultipleException as errs:
for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
except models.AbonGroup.DoesNotExist:
return mydefs.res_error(request, 'Group with id=%d does not exist' % agd)
return mydefs.res_error(request, 'abonapp:group_list')
@login_required @login_required
@permission_required('abonapp.add_abon') @permission_required('abonapp.add_abon')
def addabon(request, gid): def addabon(request, gid):
frm = None frm = None
group = None group = None
try: try:
group = get_object_or_404(models.AbonGroup, pk=gid)
if not request.user.has_perm('abonapp.can_view_abongroup', group):
group = get_object_or_404(Group, pk=gid)
if not request.user.has_perm('group_app.can_view_group', group):
raise PermissionDenied raise PermissionDenied
if request.method == 'POST': if request.method == 'POST':
frm = forms.AbonForm(request.POST, initial={'group': group}) frm = forms.AbonForm(request.POST, initial={'group': group})
@ -158,6 +113,7 @@ def addabon(request, gid):
assign_perm("abonapp.can_buy_tariff", request.user, abon) assign_perm("abonapp.can_buy_tariff", request.user, abon)
assign_perm("abonapp.can_view_passport", request.user, abon) assign_perm("abonapp.can_view_passport", request.user, abon)
assign_perm('abonapp.can_add_ballance', request.user, abon) assign_perm('abonapp.can_add_ballance', request.user, abon)
abon.sync_with_nas(created=True)
messages.success(request, _('create abon success msg')) messages.success(request, _('create abon success msg'))
return redirect('abonapp:abon_home', group.id, abon.pk) return redirect('abonapp:abon_home', group.id, abon.pk)
else: else:
@ -167,7 +123,7 @@ def addabon(request, gid):
messages.error(request, e) messages.error(request, e)
except mydefs.MultipleException as errs: except mydefs.MultipleException as errs:
for err in errs.err_list: for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
messages.error(request, err)
if not frm: if not frm:
frm = forms.AbonForm(initial={ frm = forms.AbonForm(initial={
@ -178,7 +134,7 @@ def addabon(request, gid):
return render(request, 'abonapp/addAbon.html', { return render(request, 'abonapp/addAbon.html', {
'form': frm, 'form': frm,
'abon_group': group
'group': group
}) })
@ -189,10 +145,11 @@ def del_abon(request):
try: try:
abon = get_object_or_404(models.Abon, pk=uid) abon = get_object_or_404(models.Abon, pk=uid)
if not request.user.has_perm('abonapp.delete_abon') or not request.user.has_perm( if not request.user.has_perm('abonapp.delete_abon') or not request.user.has_perm(
'abonapp.can_view_abongroup', abon.group):
'group_app.can_view_group', abon.group):
raise PermissionDenied raise PermissionDenied
gid = abon.group.id gid = abon.group.id
abon.delete() abon.delete()
abon.sync_with_nas(created=False)
messages.success(request, _('delete abon success msg')) messages.success(request, _('delete abon success msg'))
return mydefs.res_success(request, resolve_url('abonapp:people_list', gid=gid)) return mydefs.res_success(request, resolve_url('abonapp:people_list', gid=gid))
@ -202,7 +159,7 @@ def del_abon(request):
messages.error(request, _("NAS says: '%s'") % e) messages.error(request, _("NAS says: '%s'") % e)
except mydefs.MultipleException as errs: except mydefs.MultipleException as errs:
for err in errs.err_list: for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
messages.error(request, err)
return redirect('abonapp:group_list') return redirect('abonapp:group_list')
@ -226,14 +183,14 @@ def abonamount(request, gid, uid):
messages.error(request, e) messages.error(request, e)
except mydefs.MultipleException as errs: except mydefs.MultipleException as errs:
for err in errs.err_list: for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
messages.error(request, err)
return render_to_text('abonapp/modal_abonamount.html', { return render_to_text('abonapp/modal_abonamount.html', {
'abon': abon, 'abon': abon,
'abon_group': get_object_or_404(models.AbonGroup, pk=gid)
'group_id': gid
}, request=request) }, request=request)
@method_decorator(permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid')), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
class DebtsListView(BaseAbonListView): class DebtsListView(BaseAbonListView):
context_object_name = 'invoices' context_object_name = 'invoices'
template_name = 'abonapp/invoiceForPayment.html' template_name = 'abonapp/invoiceForPayment.html'
@ -245,12 +202,12 @@ class DebtsListView(BaseAbonListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(DebtsListView, self).get_context_data(**kwargs) context = super(DebtsListView, self).get_context_data(**kwargs)
context['abon_group'] = self.abon.group
context['group'] = self.abon.group
context['abon'] = self.abon context['abon'] = self.abon
return context return context
@method_decorator(permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid')), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
class PayHistoryListView(BaseAbonListView): class PayHistoryListView(BaseAbonListView):
context_object_name = 'pay_history' context_object_name = 'pay_history'
template_name = 'abonapp/payHistory.html' template_name = 'abonapp/payHistory.html'
@ -263,7 +220,7 @@ class PayHistoryListView(BaseAbonListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(PayHistoryListView, self).get_context_data(**kwargs) context = super(PayHistoryListView, self).get_context_data(**kwargs)
context['abon_group'] = self.abon.group
context['group'] = self.abon.group
context['abon'] = self.abon context['abon'] = self.abon
return context return context
@ -271,8 +228,8 @@ class PayHistoryListView(BaseAbonListView):
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
def abon_services(request, gid, uid): def abon_services(request, gid, uid):
grp = get_object_or_404(models.AbonGroup, pk=gid)
if not request.user.has_perm('abonapp.can_view_abongroup', grp):
grp = get_object_or_404(Group, pk=gid)
if not request.user.has_perm('group_app.can_view_group', grp):
raise PermissionDenied raise PermissionDenied
abon = get_object_or_404(models.Abon, pk=uid) abon = get_object_or_404(models.Abon, pk=uid)
@ -288,8 +245,8 @@ def abon_services(request, gid, uid):
return render(request, 'abonapp/service.html', { return render(request, 'abonapp/service.html', {
'abon': abon, 'abon': abon,
'abon_tariff': abon.current_tariff, 'abon_tariff': abon.current_tariff,
'abon_group': abon.group,
'services': grp.tariffs.all(),
'group': abon.group,
'services': Tariff.objects.get_tariffs_by_group(abon.group.pk),
'periodic_pay': periodic_pay 'periodic_pay': periodic_pay
}) })
@ -298,8 +255,8 @@ def abon_services(request, gid, uid):
@mydefs.only_admins @mydefs.only_admins
def abonhome(request, gid, uid): def abonhome(request, gid, uid):
abon = get_object_or_404(models.Abon, pk=uid) abon = get_object_or_404(models.Abon, pk=uid)
abon_group = get_object_or_404(models.AbonGroup, pk=gid)
if not request.user.has_perm('abonapp.can_view_abongroup', abon_group):
group = get_object_or_404(Group, pk=gid)
if not request.user.has_perm('group_app.can_view_group', group):
raise PermissionDenied raise PermissionDenied
frm = None frm = None
passw = None passw = None
@ -312,7 +269,8 @@ def abonhome(request, gid, uid):
newip = request.POST.get('ip') newip = request.POST.get('ip')
if newip: if newip:
abon.ip_address = newip abon.ip_address = newip
frm.save()
abon = frm.save()
abon.sync_with_nas(created=False)
messages.success(request, _('edit abon success msg')) messages.success(request, _('edit abon success msg'))
else: else:
messages.warning(request, _('fix form errors')) messages.warning(request, _('fix form errors'))
@ -332,13 +290,13 @@ def abonhome(request, gid, uid):
messages.warning(request, _('User has not have password, and cannot login')) messages.warning(request, _('User has not have password, and cannot login'))
except mydefs.MultipleException as errs: except mydefs.MultipleException as errs:
for err in errs.err_list: for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
messages.error(request, err)
if request.user.has_perm('abonapp.change_abon'): if request.user.has_perm('abonapp.change_abon'):
return render(request, 'abonapp/editAbon.html', { return render(request, 'abonapp/editAbon.html', {
'form': frm or forms.AbonForm(instance=abon, initial={'password': passw}), 'form': frm or forms.AbonForm(instance=abon, initial={'password': passw}),
'abon': abon, 'abon': abon,
'abon_group': abon_group,
'group': group,
'ip': abon.ip_address, 'ip': abon.ip_address,
'is_bad_ip': getattr(abon, 'is_bad_ip', False), 'is_bad_ip': getattr(abon, 'is_bad_ip', False),
'device': abon.device, 'device': abon.device,
@ -347,7 +305,7 @@ def abonhome(request, gid, uid):
else: else:
return render(request, 'abonapp/viewAbon.html', { return render(request, 'abonapp/viewAbon.html', {
'abon': abon, 'abon': abon,
'abon_group': abon_group,
'group': group,
'ip': abon.ip_address, 'ip': abon.ip_address,
'passw': passw 'passw': passw
}) })
@ -365,7 +323,7 @@ def terminal_pay(request):
def add_invoice(request, gid, uid): def add_invoice(request, gid, uid):
uid = mydefs.safe_int(uid) uid = mydefs.safe_int(uid)
abon = get_object_or_404(models.Abon, pk=uid) abon = get_object_or_404(models.Abon, pk=uid)
grp = get_object_or_404(models.AbonGroup, pk=gid)
grp = get_object_or_404(Group, pk=gid)
try: try:
if request.method == 'POST': if request.method == 'POST':
@ -389,21 +347,22 @@ def add_invoice(request, gid, uid):
messages.error(request, e) messages.error(request, e)
except mydefs.MultipleException as errs: except mydefs.MultipleException as errs:
for err in errs.err_list: for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
messages.error(request, err)
return render(request, 'abonapp/addInvoice.html', { return render(request, 'abonapp/addInvoice.html', {
'abon': abon, 'abon': abon,
'invcount': models.InvoiceForPayment.objects.filter(abon=abon).count(), 'invcount': models.InvoiceForPayment.objects.filter(abon=abon).count(),
'abon_group': grp
'group': grp
}) })
@login_required @login_required
@mydefs.only_admins
@permission_required('abonapp.can_buy_tariff') @permission_required('abonapp.can_buy_tariff')
@transaction.atomic @transaction.atomic
def pick_tariff(request, gid, uid): def pick_tariff(request, gid, uid):
grp = get_object_or_404(models.AbonGroup, pk=gid)
grp = get_object_or_404(Group, pk=gid)
abon = get_object_or_404(models.Abon, pk=uid) abon = get_object_or_404(models.Abon, pk=uid)
tariffs = grp.tariffs.all()
tariffs = Tariff.objects.get_tariffs_by_group(grp.pk)
try: try:
if request.method == 'POST': if request.method == 'POST':
trf = Tariff.objects.get(pk=request.POST.get('tariff')) trf = Tariff.objects.get(pk=request.POST.get('tariff'))
@ -417,6 +376,7 @@ def pick_tariff(request, gid, uid):
deadline = datetime.strptime(deadline, '%Y-%m-%d') deadline = datetime.strptime(deadline, '%Y-%m-%d')
deadline += timedelta(hours=23, minutes=59, seconds=59) deadline += timedelta(hours=23, minutes=59, seconds=59)
abon.pick_tariff(trf, request.user, deadline=deadline, comment=log_comment) abon.pick_tariff(trf, request.user, deadline=deadline, comment=log_comment)
abon.sync_with_nas(created=False)
messages.success(request, _('Tariff has been picked')) messages.success(request, _('Tariff has been picked'))
return redirect('abonapp:abon_services', gid=gid, uid=abon.id) return redirect('abonapp:abon_services', gid=gid, uid=abon.id)
except (mydefs.LogicError, NasFailedResult) as e: except (mydefs.LogicError, NasFailedResult) as e:
@ -428,14 +388,14 @@ def pick_tariff(request, gid, uid):
messages.error(request, _('Tariff your picked does not exist')) messages.error(request, _('Tariff your picked does not exist'))
except mydefs.MultipleException as errs: except mydefs.MultipleException as errs:
for err in errs.err_list: for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
messages.error(request, err)
except ValueError as e: except ValueError as e:
messages.error(request, "%s: %s" % (_('fix form errors'), e)) messages.error(request, "%s: %s" % (_('fix form errors'), e))
return render(request, 'abonapp/buy_tariff.html', { return render(request, 'abonapp/buy_tariff.html', {
'tariffs': tariffs, 'tariffs': tariffs,
'abon': abon, 'abon': abon,
'abon_group': grp,
'group': grp,
'selected_tariff': mydefs.safe_int(request.GET.get('selected_tariff')) 'selected_tariff': mydefs.safe_int(request.GET.get('selected_tariff'))
}) })
@ -444,7 +404,9 @@ def pick_tariff(request, gid, uid):
@permission_required('abonapp.delete_abontariff') @permission_required('abonapp.delete_abontariff')
def unsubscribe_service(request, gid, uid, abon_tariff_id): def unsubscribe_service(request, gid, uid, abon_tariff_id):
try: try:
abon = get_object_or_404(models.Abon, pk=uid)
abon_tariff = get_object_or_404(models.AbonTariff, pk=int(abon_tariff_id)) abon_tariff = get_object_or_404(models.AbonTariff, pk=int(abon_tariff_id))
abon.sync_with_nas(created=False)
abon_tariff.delete() abon_tariff.delete()
messages.success(request, _('User has been detached from service')) messages.success(request, _('User has been detached from service'))
except NasFailedResult as e: except NasFailedResult as e:
@ -453,7 +415,7 @@ def unsubscribe_service(request, gid, uid, abon_tariff_id):
messages.warning(request, e) messages.warning(request, e)
except mydefs.MultipleException as errs: except mydefs.MultipleException as errs:
for err in errs.err_list: for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
messages.error(request, err)
return redirect('abonapp:abon_services', gid=gid, uid=uid) return redirect('abonapp:abon_services', gid=gid, uid=uid)
@ -478,7 +440,7 @@ class DebtorsListView(ListView):
@method_decorator(login_required, name='dispatch') @method_decorator(login_required, name='dispatch')
@method_decorator(permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid')), name='dispatch')
@method_decorator(permission_required('group_app.can_view_group', (Group, 'pk', 'gid')), name='dispatch')
class TaskLogListView(ListView): class TaskLogListView(ListView):
paginate_by = PAGINATION_ITEMS_PER_PAGE paginate_by = PAGINATION_ITEMS_PER_PAGE
http_method_names = ['get'] http_method_names = ['get']
@ -492,7 +454,7 @@ class TaskLogListView(ListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(TaskLogListView, self).get_context_data(**kwargs) context = super(TaskLogListView, self).get_context_data(**kwargs)
context['abon_group'] = self.abon.group
context['group'] = self.abon.group
context['abon'] = self.abon context['abon'] = self.abon
return context return context
@ -500,8 +462,8 @@ class TaskLogListView(ListView):
@login_required @login_required
@permission_required('abonapp.can_view_passport') @permission_required('abonapp.can_view_passport')
def passport_view(request, gid, uid): def passport_view(request, gid, uid):
abon = get_object_or_404(models.Abon, pk=uid)
try: try:
abon = models.Abon.objects.get(pk=uid)
if request.method == 'POST': if request.method == 'POST':
try: try:
passport_instance = models.PassportInfo.objects.get(abon=abon) passport_instance = models.PassportInfo.objects.get(abon=abon)
@ -526,7 +488,7 @@ def passport_view(request, gid, uid):
messages.warning(request, _('Passport info for the user does not exist')) messages.warning(request, _('Passport info for the user does not exist'))
frm = forms.PassportForm() frm = forms.PassportForm()
return render(request, 'abonapp/passport_view.html', { return render(request, 'abonapp/passport_view.html', {
'abon_group': get_object_or_404(models.AbonGroup, pk=gid),
'group': get_object_or_404(Group, pk=gid),
'abon': abon, 'abon': abon,
'frm': frm 'frm': frm
}) })
@ -535,17 +497,21 @@ def passport_view(request, gid, uid):
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
def chgroup_tariff(request, gid): def chgroup_tariff(request, gid):
grp = get_object_or_404(models.AbonGroup, pk=gid)
if not request.user.has_perm('abonapp.change_abongroup', grp):
grp = get_object_or_404(Group, pk=gid)
if not request.user.has_perm('group_app.change_group', grp):
raise PermissionDenied raise PermissionDenied
if request.method == 'POST': if request.method == 'POST':
tr = request.POST.getlist('tr') tr = request.POST.getlist('tr')
grp.tariffs.clear()
grp.tariffs.add(*[int(d) for d in tr])
grp.tariff_set.clear()
grp.tariff_set.add(*[int(d) for d in tr])
grp.save() grp.save()
messages.success(request, _('Successfully saved'))
return redirect('abonapp:ch_group_tariff', gid)
tariffs = Tariff.objects.all() tariffs = Tariff.objects.all()
seleted_tariffs_id = [pk[0] for pk in grp.tariff_set.only('pk').values_list('pk')]
return render(request, 'abonapp/group_tariffs.html', { return render(request, 'abonapp/group_tariffs.html', {
'abon_group': grp,
'group': grp,
'seleted_tariffs': seleted_tariffs_id,
'tariffs': tariffs 'tariffs': tariffs
}) })
@ -570,7 +536,7 @@ def dev(request, gid, uid):
messages.error(request, _('Abon does not exist')) messages.error(request, _('Abon does not exist'))
return redirect('abonapp:people_list', gid=gid) return redirect('abonapp:people_list', gid=gid)
return render(request, 'abonapp/modal_dev.html', { return render(request, 'abonapp/modal_dev.html', {
'devices': Device.objects.filter(user_group=gid),
'devices': Device.objects.filter(group=gid),
'dev': abon_dev, 'dev': abon_dev,
'gid': gid, 'uid': uid 'gid': gid, 'uid': uid
}) })
@ -578,7 +544,7 @@ def dev(request, gid, uid):
@login_required @login_required
@permission_required('abonapp.change_abon') @permission_required('abonapp.change_abon')
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def clear_dev(request, gid, uid): def clear_dev(request, gid, uid):
try: try:
abon = models.Abon.objects.get(pk=uid) abon = models.Abon.objects.get(pk=uid)
@ -593,7 +559,7 @@ def clear_dev(request, gid, uid):
@login_required @login_required
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def charts(request, gid, uid): def charts(request, gid, uid):
high = 100 high = 100
@ -607,9 +573,8 @@ def charts(request, gid, uid):
StatElem = getModel(wandate) StatElem = getModel(wandate)
abon = models.Abon.objects.get(pk=uid) abon = models.Abon.objects.get(pk=uid)
if abon.group is None: if abon.group is None:
abon.group = models.AbonGroup.objects.get(pk=gid)
abon.group = Group.objects.get(pk=gid)
abon.save(update_fields=['group']) abon.save(update_fields=['group'])
abongroup = abon.group
if abon.ip_address is None: if abon.ip_address is None:
charts_data = None charts_data = None
@ -630,7 +595,7 @@ def charts(request, gid, uid):
except models.Abon.DoesNotExist: except models.Abon.DoesNotExist:
messages.error(request, _('Abon does not exist')) messages.error(request, _('Abon does not exist'))
return redirect('abonapp:people_list', gid) return redirect('abonapp:people_list', gid)
except models.AbonGroup.DoesNotExist:
except Group.DoesNotExist:
messages.error(request, _("Group what you want doesn't exist")) messages.error(request, _("Group what you want doesn't exist"))
return redirect('abonapp:group_list') return redirect('abonapp:group_list')
except ProgrammingError as e: except ProgrammingError as e:
@ -638,7 +603,7 @@ def charts(request, gid, uid):
return redirect('abonapp:abon_home', gid=gid, uid=uid) return redirect('abonapp:abon_home', gid=gid, uid=uid)
return render(request, 'abonapp/charts.html', { return render(request, 'abonapp/charts.html', {
'abon_group': abongroup,
'group': abon.group,
'abon': abon, 'abon': abon,
'charts_data': ',\n'.join(charts_data) if charts_data is not None else None, 'charts_data': ',\n'.join(charts_data) if charts_data is not None else None,
'high': high, 'high': high,
@ -668,7 +633,7 @@ def make_extra_field(request, gid, uid):
frm = forms.ExtraFieldForm() frm = forms.ExtraFieldForm()
except mydefs.MultipleException as errs: except mydefs.MultipleException as errs:
for err in errs.err_list: for err in errs.err_list:
messages.add_message(request, messages.constants.ERROR, err)
messages.error(request, err)
frm = forms.ExtraFieldForm() frm = forms.ExtraFieldForm()
return render_to_text('abonapp/modal_extra_field.html', { return render_to_text('abonapp/modal_extra_field.html', {
'abon': abon, 'abon': abon,
@ -724,14 +689,17 @@ def abon_ping(request):
else: else:
if type(ping_result) is tuple: if type(ping_result) is tuple:
loses_percent = (ping_result[0] / ping_result[1] if ping_result[1] != 0 else 1) loses_percent = (ping_result[0] / ping_result[1] if ping_result[1] != 0 else 1)
ping_result = {'all':ping_result[0], 'return': ping_result[1]}
ping_result = {'all': ping_result[0], 'return': ping_result[1]}
if loses_percent > 1.0: if loses_percent > 1.0:
text = '<span class="glyphicon glyphicon-exclamation-sign"></span> %s' % _('IP Conflict! %(all)d/%(return)d results') % ping_result
text = '<span class="glyphicon glyphicon-exclamation-sign"></span> %s' % _(
'IP Conflict! %(all)d/%(return)d results') % ping_result
elif loses_percent > 0.5: elif loses_percent > 0.5:
text = '<span class="glyphicon glyphicon-ok"></span> %s' % _('ok ping, %(all)d/%(return)d loses') % ping_result
text = '<span class="glyphicon glyphicon-ok"></span> %s' % _(
'ok ping, %(all)d/%(return)d loses') % ping_result
status = True status = True
else: else:
text = '<span class="glyphicon glyphicon-exclamation-sign"></span> %s' % _('no ping, %(all)d/%(return)d loses') % ping_result
text = '<span class="glyphicon glyphicon-exclamation-sign"></span> %s' % _(
'no ping, %(all)d/%(return)d loses') % ping_result
else: else:
text = '<span class="glyphicon glyphicon-ok"></span> %s' % _('ping ok') + ' ' + str(ping_result) text = '<span class="glyphicon glyphicon-ok"></span> %s' % _('ping ok') + ' ' + str(ping_result)
status = True status = True
@ -753,7 +721,7 @@ class DialsListView(BaseAbonListView):
def get_queryset(self): def get_queryset(self):
abon = get_object_or_404(models.Abon, pk=self.kwargs.get('uid')) abon = get_object_or_404(models.Abon, pk=self.kwargs.get('uid'))
if not self.request.user.has_perm('abonapp.can_view_abongroup', abon.group):
if not self.request.user.has_perm('group_app.can_view_group', abon.group):
raise PermissionDenied raise PermissionDenied
self.abon = abon self.abon = abon
if abon.telephone is not None and abon.telephone != '': if abon.telephone is not None and abon.telephone != '':
@ -767,7 +735,7 @@ class DialsListView(BaseAbonListView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(DialsListView, self).get_context_data(**kwargs) context = super(DialsListView, self).get_context_data(**kwargs)
context['abon_group'] = get_object_or_404(models.AbonGroup, pk=self.kwargs.get('gid'))
context['group'] = get_object_or_404(Group, pk=self.kwargs.get('gid'))
context['abon'] = self.abon context['abon'] = self.abon
return context return context
@ -776,6 +744,15 @@ class DialsListView(BaseAbonListView):
return redirect('abonapp:dials', self.abon.group.pk, self.abon.pk) return redirect('abonapp:dials', self.abon.group.pk, self.abon.pk)
return super(DialsListView, self).render_to_response(context, **response_kwargs) return super(DialsListView, self).render_to_response(context, **response_kwargs)
def get(self, request, *args, **kwargs):
try:
return super(DialsListView, self).get(request, *args, **kwargs)
except ProgrammingError as e:
messages.error(request, e)
return redirect('abonapp:abon_home',
self.kwargs.get('gid'),
self.kwargs.get('uid'))
@login_required @login_required
@permission_required('abonapp.change_abon') @permission_required('abonapp.change_abon')
@ -796,16 +773,17 @@ def save_user_dev_port(request, gid, uid):
other_abon = models.Abon.objects.get(device=abon.device, dev_port=port) other_abon = models.Abon.objects.get(device=abon.device, dev_port=port)
if other_abon != abon: if other_abon != abon:
user_url = resolve_url('abonapp:abon_home', other_abon.group.id, other_abon.id) user_url = resolve_url('abonapp:abon_home', other_abon.group.id, other_abon.id)
messages.error(request, _("<a href='%(user_url)s'>%(user_name)s</a> already pinned to this port on this device") % {
'user_url': user_url,
'user_name': other_abon.get_full_name()
})
messages.error(request, _(
"<a href='%(user_url)s'>%(user_name)s</a> already pinned to this port on this device") % {
'user_url': user_url,
'user_name': other_abon.get_full_name()
})
return redirect('abonapp:abon_home', gid, uid) return redirect('abonapp:abon_home', gid, uid)
except models.Abon.DoesNotExist: except models.Abon.DoesNotExist:
pass pass
except models.Abon.MultipleObjectsReturned: except models.Abon.MultipleObjectsReturned:
messages.error(request, _('Multiple users on the same device port')) messages.error(request, _('Multiple users on the same device port'))
return redirect('devapp:manage_ports', abon.device.user_group.pk, abon.device.pk)
return redirect('devapp:manage_ports', abon.device.group.pk, abon.device.pk)
abon.dev_port = port abon.dev_port = port
if abon.is_dynamic_ip != is_dynamic_ip: if abon.is_dynamic_ip != is_dynamic_ip:
@ -826,7 +804,7 @@ def save_user_dev_port(request, gid, uid):
@login_required @login_required
@permission_required('abonapp.add_abonstreet') @permission_required('abonapp.add_abonstreet')
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def street_add(request, gid): def street_add(request, gid):
if request.method == 'POST': if request.method == 'POST':
frm = forms.AbonStreetForm(request.POST) frm = forms.AbonStreetForm(request.POST)
@ -846,7 +824,7 @@ def street_add(request, gid):
@login_required @login_required
@permission_required('abonapp.change_abonstreet') @permission_required('abonapp.change_abonstreet')
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def street_edit(request, gid): def street_edit(request, gid):
try: try:
if request.method == 'POST': if request.method == 'POST':
@ -871,7 +849,7 @@ def street_edit(request, gid):
@login_required @login_required
@permission_required('abonapp.delete_abonstreet') @permission_required('abonapp.delete_abonstreet')
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def street_del(request, gid, sid): def street_del(request, gid, sid):
try: try:
models.AbonStreet.objects.get(pk=sid, group=gid).delete() models.AbonStreet.objects.get(pk=sid, group=gid).delete()
@ -883,7 +861,7 @@ def street_del(request, gid, sid):
@login_required @login_required
@permission_required('abonapp.can_view_additionaltelephones') @permission_required('abonapp.can_view_additionaltelephones')
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def tels(request, gid, uid): def tels(request, gid, uid):
abon = get_object_or_404(models.Abon, pk=uid) abon = get_object_or_404(models.Abon, pk=uid)
telephones = abon.additional_telephones.all() telephones = abon.additional_telephones.all()
@ -931,11 +909,12 @@ def tel_del(request, gid, uid):
@login_required @login_required
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def phonebook(request, gid): def phonebook(request, gid):
res_format = request.GET.get('f') res_format = request.GET.get('f')
t1 = models.Abon.objects.filter(group__id=int(gid)).only('telephone', 'fio').values_list('telephone', 'fio') t1 = models.Abon.objects.filter(group__id=int(gid)).only('telephone', 'fio').values_list('telephone', 'fio')
t2 = models.AdditionalTelephone.objects.filter(abon__group__id=gid).only('telephone', 'owner_name').values_list('telephone', 'owner_name')
t2 = models.AdditionalTelephone.objects.filter(abon__group__id=gid).only('telephone', 'owner_name').values_list(
'telephone', 'owner_name')
tels = list(t1) + list(t2) tels = list(t1) + list(t2)
if res_format == 'csv': if res_format == 'csv':
import csv import csv
@ -952,7 +931,7 @@ def phonebook(request, gid):
@login_required @login_required
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def abon_export(request, gid): def abon_export(request, gid):
res_format = request.GET.get('f') res_format = request.GET.get('f')
@ -988,13 +967,11 @@ def abon_export(request, gid):
@login_required @login_required
@permission_required('abonapp.change_abon') @permission_required('abonapp.change_abon')
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def reset_ip(request, gid, uid): def reset_ip(request, gid, uid):
abon = get_object_or_404(models.Abon, pk=uid) abon = get_object_or_404(models.Abon, pk=uid)
signals.post_save.disconnect(models.abon_post_save, sender=models.Abon)
abon.ip_address = None abon.ip_address = None
abon.save(update_fields=['ip_address']) abon.save(update_fields=['ip_address'])
signals.post_save.connect(models.abon_post_save, sender=models.Abon)
return HttpResponse(dumps({ return HttpResponse(dumps({
'status': 0, 'status': 0,
'dat': "<span class='glyphicon glyphicon-refresh'></span>" 'dat': "<span class='glyphicon glyphicon-refresh'></span>"
@ -1020,7 +997,7 @@ def fin_report(request):
@login_required @login_required
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
def add_edit_periodic_pay(request, gid, uid, periodic_pay_id=0): def add_edit_periodic_pay(request, gid, uid, periodic_pay_id=0):
if periodic_pay_id == 0: if periodic_pay_id == 0:
if not request.user.has_perm('abonapp.add_periodicpayforid'): if not request.user.has_perm('abonapp.add_periodicpayforid'):
@ -1051,7 +1028,7 @@ def add_edit_periodic_pay(request, gid, uid, periodic_pay_id=0):
@login_required @login_required
@permission_required('abonapp.can_view_abongroup', (models.AbonGroup, 'pk', 'gid'))
@permission_required('group_app.can_view_group', (Group, 'pk', 'gid'))
@permission_required('abonapp.delete_periodicpayforid') @permission_required('abonapp.delete_periodicpayforid')
def del_periodic_pay(request, gid, uid, periodic_pay_id): def del_periodic_pay(request, gid, uid, periodic_pay_id):
periodic_pay_instance = get_object_or_404(models.PeriodicPayForId, pk=periodic_pay_id) periodic_pay_instance = get_object_or_404(models.PeriodicPayForId, pk=periodic_pay_id)
@ -1082,12 +1059,12 @@ class EditSibscriberMarkers(UpdateView):
return context return context
def form_invalid(self, form): def form_invalid(self, form):
messages.add_message(self.request, messages.ERROR, _('fix form errors'))
messages.error(self.request, _('fix form errors'))
return super(EditSibscriberMarkers, self).form_invalid(form) return super(EditSibscriberMarkers, self).form_invalid(form)
def form_valid(self, form): def form_valid(self, form):
v = super(EditSibscriberMarkers, self).form_valid(form) v = super(EditSibscriberMarkers, self).form_valid(form)
messages.add_message(self.request, messages.SUCCESS, _('User flags has changed successfully'))
messages.success(self.request, _('User flags has changed successfully'))
return v return v
@ -1095,17 +1072,17 @@ class EditSibscriberMarkers(UpdateView):
def abons(request): def abons(request):
ablist = [{ ablist = [{
'id': abn.pk,
'tarif_id': abn.active_tariff().tariff.pk if abn.active_tariff() is not None else 0,
'ip': abn.ip_address.int_ip(),
'is_active': abn.is_active
} for abn in models.Abon.objects.all()]
'id': abn.pk,
'tarif_id': abn.active_tariff().tariff.pk if abn.active_tariff() is not None else 0,
'ip': abn.ip_address.int_ip(),
'is_active': abn.is_active
} for abn in models.Abon.objects.all()]
tarlist = [{ tarlist = [{
'id': trf.pk,
'speedIn': trf.speedIn,
'speedOut': trf.speedOut
} for trf in Tariff.objects.all()]
'id': trf.pk,
'speedIn': trf.speedIn,
'speedOut': trf.speedOut
} for trf in Tariff.objects.all()]
data = { data = {
'subscribers': ablist, 'subscribers': ablist,

63
accounts_app/migrations/0001_initial.py

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-06-28 23:51
# Generated by Django 1.11 on 2018-02-26 00:20
from __future__ import unicode_literals
import django.core.validators import django.core.validators
from django.db import migrations, models from django.db import migrations, models
@ -7,44 +8,58 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('auth', '0007_alter_validators_add_error_messages'),
('auth', '0008_alter_user_username_max_length'),
('group_app', '0001_initial'),
('photo_app', '0001_initial'), ('photo_app', '0001_initial'),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='UserProfile',
name='BaseAccount',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')), ('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.',
verbose_name='superuser status')),
('username', models.CharField(max_length=127, unique=True)),
('fio', models.CharField(max_length=256)),
('birth_day', models.DateField(auto_now_add=True)),
('is_active', models.BooleanField(default=True)),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(max_length=127, unique=True, verbose_name='profile username')),
('fio', models.CharField(max_length=256, verbose_name='fio')),
('birth_day', models.DateField(auto_now_add=True, verbose_name='birth day')),
('is_active', models.BooleanField(default=True, verbose_name='Is active')),
('is_admin', models.BooleanField(default=False)), ('is_admin', models.BooleanField(default=False)),
('telephone', models.CharField(max_length=16, unique=True, validators=[
django.core.validators.RegexValidator(r'^\\+[7,8,9,3]\\d{10,11}$')],
verbose_name='Telephone number')),
('skype', models.CharField(blank=True, max_length=20)),
('avatar', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE,
to='photo_app.Photo')),
('groups', models.ManyToManyField(blank=True,
help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.',
related_name='user_set', related_query_name='user', to='auth.Group',
verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.',
related_name='user_set', related_query_name='user',
to='auth.Permission', verbose_name='user permissions')),
('telephone', models.CharField(max_length=16, validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')], verbose_name='Telephone')),
], ],
options={ options={
'abstract': False,
'db_table': 'base_accounts',
}, },
), ),
migrations.CreateModel(
name='UserProfile',
fields=[
('baseaccount_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='accounts_app.BaseAccount')),
('email', models.EmailField(default='admin@example.ru', max_length=254)),
('avatar', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='photo_app.Photo')),
('responsibility_groups', models.ManyToManyField(blank=True, to='group_app.Group', verbose_name='Responsibility groups')),
],
options={
'verbose_name': 'Staff account profile',
'verbose_name_plural': 'Staff account profiles',
'ordering': ['fio'],
'permissions': (('can_view_userprofile', 'Can view staff profile'),),
},
bases=('accounts_app.baseaccount',),
),
migrations.AddField(
model_name='baseaccount',
name='groups',
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'),
),
migrations.AddField(
model_name='baseaccount',
name='user_permissions',
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'),
),
] ]

20
accounts_app/migrations/0002_userprofile_email.py

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-11-30 15:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts_app', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='userprofile',
name='email',
field=models.EmailField(default='ex@host.loc', max_length=254),
preserve_default=False,
),
]

25
accounts_app/migrations/0003_auto_20161206_2135.py

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-12-06 18:35
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts_app', '0002_userprofile_email'),
]
operations = [
migrations.RemoveField(
model_name='userprofile',
name='skype',
),
migrations.AlterField(
model_name='userprofile',
name='telephone',
field=models.CharField(max_length=16,
validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')],
verbose_name='Telephone number'),
),
]

18
accounts_app/migrations/0004_auto_20170128_1316.py

@ -1,18 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-01-28 10:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts_app', '0003_auto_20161206_2135'),
]
operations = [
migrations.AlterField(
model_name='userprofile',
name='email',
field=models.EmailField(default='admin@example.ru', max_length=254),
),
]

21
accounts_app/migrations/0005_auto_20170222_2224.py

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-02-22 19:24
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts_app', '0004_auto_20170128_1316'),
]
operations = [
migrations.AlterField(
model_name='userprofile',
name='telephone',
field=models.CharField(max_length=16, validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')], verbose_name='Номер телефона'),
),
]

21
accounts_app/migrations/0006_auto_20170416_1029.py

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-04-16 07:29
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('accounts_app', '0005_auto_20170222_2224'),
]
operations = [
migrations.AlterField(
model_name='userprofile',
name='avatar',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='photo_app.Photo'),
),
]

21
accounts_app/migrations/0007_auto_20170816_1109.py

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-08-16 11:09
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts_app', '0006_auto_20170416_1029'),
]
operations = [
migrations.AlterField(
model_name='userprofile',
name='telephone',
field=models.CharField(max_length=16, validators=[django.core.validators.RegexValidator('^\\+[7,8,9,3]\\d{10,11}$')], verbose_name='Телефон'),
),
]

19
accounts_app/migrations/0008_auto_20170927_1838.py

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-09-27 18:38
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounts_app', '0007_auto_20170816_1109'),
]
operations = [
migrations.AlterModelOptions(
name='userprofile',
options={'permissions': (('can_view_userprofile', 'Может просматривать учётку сотрудника'),), 'verbose_name': 'Учётная запись работника', 'verbose_name_plural': 'Учётные записи работников'},
),
]

28
accounts_app/models.py

@ -6,6 +6,7 @@ from django.core.validators import RegexValidator
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.conf import settings from django.conf import settings
from photo_app.models import Photo from photo_app.models import Photo
from group_app.models import Group
DEFAULT_PICTURE = getattr(settings, 'DEFAULT_PICTURE', '/static/img/user_ava.gif') DEFAULT_PICTURE = getattr(settings, 'DEFAULT_PICTURE', '/static/img/user_ava.gif')
@ -45,7 +46,7 @@ class MyUserManager(BaseUserManager):
return user return user
class UserProfile(AbstractBaseUser, PermissionsMixin):
class BaseAccount(AbstractBaseUser, PermissionsMixin):
username = models.CharField(_('profile username'), max_length=127, unique=True) username = models.CharField(_('profile username'), max_length=127, unique=True)
fio = models.CharField(_('fio'), max_length=256) fio = models.CharField(_('fio'), max_length=256)
birth_day = models.DateField(_('birth day'), auto_now_add=True) birth_day = models.DateField(_('birth day'), auto_now_add=True)
@ -57,8 +58,6 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
#unique=True, #unique=True,
validators=[RegexValidator(TELEPHONE_REGEXP)] validators=[RegexValidator(TELEPHONE_REGEXP)]
) )
avatar = models.ForeignKey(Photo, null=True, blank=True, on_delete=models.SET_NULL)
email = models.EmailField(default='admin@example.ru')
USERNAME_FIELD = 'username' USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['telephone'] REQUIRED_FIELDS = ['telephone']
@ -78,6 +77,26 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
# Simplest possible answer: All admins are staff # Simplest possible answer: All admins are staff
return self.is_admin return self.is_admin
def __str__(self):
return self.get_full_name()
class Meta:
db_table = 'base_accounts'
class UserProfileManager(MyUserManager):
def get_profiles_by_group(self, group_id):
return self.filter(responsibility_groups__id__in=[group_id], is_admin=True, is_active=True)
class UserProfile(BaseAccount):
avatar = models.ForeignKey(Photo, null=True, blank=True, on_delete=models.SET_NULL)
email = models.EmailField(default='admin@example.ru')
responsibility_groups = models.ManyToManyField(Group, blank=True, verbose_name=_('Responsibility groups'))
objects = UserProfileManager()
def get_big_ava(self): def get_big_ava(self):
if self.avatar: if self.avatar:
path = self.avatar.big() path = self.avatar.big()
@ -99,9 +118,6 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
else: else:
return DEFAULT_PICTURE return DEFAULT_PICTURE
def __str__(self):
return self.get_full_name()
class Meta: class Meta:
permissions = ( permissions = (
('can_view_userprofile', _('Can view staff profile')), ('can_view_userprofile', _('Can view staff profile')),

6
accounts_app/templates/accounts/ext.htm

@ -53,12 +53,6 @@
{% trans 'Administrator' %} {% trans 'Administrator' %}
</a> </a>
</li> </li>
{% url 'acc_app:profile_setup_group' uid as profilegroups_url %}
<li{% if profilegroups_url == request.path %} class="active"{% endif %}>
<a href="{{ profilegroups_url }}">
{% trans 'Groups' %}
</a>
</li>
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
{% url 'acc_app:set_abon_groups_permission' uid as set_ag_perm %} {% url 'acc_app:set_abon_groups_permission' uid as set_ag_perm %}
<li{% if set_ag_perm == request.path %} class="active"{% endif %}> <li{% if set_ag_perm == request.path %} class="active"{% endif %}>

24
accounts_app/templates/accounts/profile_chgroup.html

@ -1,24 +0,0 @@
{% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %}
{% load i18n %}
{% block content %}
<legend>{% trans 'The responsibility of the staff of the group of subscribers' %}</legend>
<form action="{% url 'acc_app:profile_setup_group' userprofile.id %}" method="post" role="form">{% csrf_token %}
{% for ag in abongroups %}
<div class="checkbox">
<label>
{% if userprofile in ag.profiles.all %}
<input name="ag" type="checkbox" value="{{ ag.pk }}" checked/>
{% else %}
<input name="ag" type="checkbox" value="{{ ag.pk }}"/>
{% endif %}
{{ ag.title }}
</label>
</div>
{% endfor %}
<div class="btn-group">
<input type="submit" class="btn btn-primary" value="{% trans 'Save' %}"> <input type="reset" class="btn btn-default" value="{% trans 'Reset' %}">
</div>
</form>
{% endblock %}

10
accounts_app/templates/accounts/set_abon_groups_permission.html

@ -4,15 +4,15 @@
<legend>{% trans 'The list of user groups to which the account has access' %}</legend> <legend>{% trans 'The list of user groups to which the account has access' %}</legend>
<form action="{% url 'acc_app:set_abon_groups_permission' userprofile.pk %}" method="post" role="form">{% csrf_token %} <form action="{% url 'acc_app:set_abon_groups_permission' userprofile.pk %}" method="post" role="form">{% csrf_token %}
{% for ag in abongroups %}
{% for grp in groups %}
<div class="checkbox"> <div class="checkbox">
<label> <label>
{% if ag.pk in picked_groups_ids %}
<input name="ag" type="checkbox" value="{{ ag.pk }}" checked/>
{% if grp.pk in picked_groups_ids %}
<input name="grp" type="checkbox" value="{{ grp.pk }}" checked/>
{% else %} {% else %}
<input name="ag" type="checkbox" value="{{ ag.pk }}"/>
<input name="grp" type="checkbox" value="{{ grp.pk }}"/>
{% endif %} {% endif %}
{{ ag.title }}
{{ grp.title }}
</label> </label>
</div> </div>
{% endfor %} {% endfor %}

1
accounts_app/urls.py

@ -24,7 +24,6 @@ urlpatterns = [
url(r'^(?P<uid>\d+)/perms$', views.perms, name='setup_perms'), url(r'^(?P<uid>\d+)/perms$', views.perms, name='setup_perms'),
url(r'^(?P<uid>\d+)/perms/(?P<klass_name>[a-z_]+\.[a-zA-Z_]+)$', views.PermissionClassListView.as_view(), name='perms_klasses'), url(r'^(?P<uid>\d+)/perms/(?P<klass_name>[a-z_]+\.[a-zA-Z_]+)$', views.PermissionClassListView.as_view(), name='perms_klasses'),
url(r'^(?P<uid>\d+)/perms/(?P<klass_name>[a-z_]+\.[a-zA-Z_]+)/(?P<obj_id>\d+)$', views.perms_edit, name='perms_edit'), url(r'^(?P<uid>\d+)/perms/(?P<klass_name>[a-z_]+\.[a-zA-Z_]+)/(?P<obj_id>\d+)$', views.perms_edit, name='perms_edit'),
url(r'^(?P<uid>\d+)/chgroup$', views.chgroup, name='profile_setup_group'),
url(r'^(?P<uid>\d+)/del$', views.delete_profile, name='delete_profile'), url(r'^(?P<uid>\d+)/del$', views.delete_profile, name='delete_profile'),
url(r'^(?P<uid>\d+)/user_group_access$', views.set_abon_groups_permission, name='set_abon_groups_permission') url(r'^(?P<uid>\d+)/user_group_access$', views.set_abon_groups_permission, name='set_abon_groups_permission')

45
accounts_app/views.py

@ -10,7 +10,7 @@ from django.utils.translation import ugettext as _
from django.views.generic import ListView from django.views.generic import ListView
from django.conf import settings from django.conf import settings
from abonapp.models import AbonGroup
from group_app.models import Group
from photo_app.models import Photo from photo_app.models import Photo
from .models import UserProfile from .models import UserProfile
@ -89,29 +89,6 @@ def profile_show(request, uid=0):
}) })
@login_required
@mydefs.only_admins
def chgroup(request, uid):
uid = mydefs.safe_int(uid)
if uid == 0:
usr = request.user
else:
usr = get_object_or_404(UserProfile, id=uid)
if usr != request.user and not request.user.has_perm('accounts_app.change_userprofile', usr):
raise PermissionDenied
if request.method == 'POST':
ag = request.POST.getlist('ag')
usr.abon_groups.clear()
usr.abon_groups.add(*[int(d) for d in ag])
usr.save()
abongroups = AbonGroup.objects.only('pk', 'title')
return render(request, 'accounts/profile_chgroup.html', {
'uid': uid,
'userprofile': usr,
'abongroups': abongroups
})
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
def ch_ava(request): def ch_ava(request):
@ -234,7 +211,7 @@ def perms(request, uid):
raise PermissionDenied raise PermissionDenied
userprofile = get_object_or_404(UserProfile, id=uid) userprofile = get_object_or_404(UserProfile, id=uid)
klasses = ( klasses = (
'abonapp.AbonGroup', 'abonapp.Abon', 'accounts_app.UserProfile',
'abonapp.Abon', 'accounts_app.UserProfile',
'abonapp.AbonTariff', 'abonapp.AbonStreet', 'devapp.Device', 'abonapp.AbonTariff', 'abonapp.AbonStreet', 'devapp.Device',
'abonapp.PassportInfo', 'abonapp.AdditionalTelephone', 'tariff_app.PeriodicPay' 'abonapp.PassportInfo', 'abonapp.AdditionalTelephone', 'tariff_app.PeriodicPay'
) )
@ -303,22 +280,22 @@ def set_abon_groups_permission(request, uid):
raise PermissionDenied raise PermissionDenied
userprofile = get_object_or_404(UserProfile, pk=uid) userprofile = get_object_or_404(UserProfile, pk=uid)
picked_groups = get_objects_for_user(userprofile, 'abonapp.can_view_abongroup', accept_global_perms=False)
picked_groups = get_objects_for_user(userprofile, 'group_app.can_view_group', accept_global_perms=False)
picked_groups = picked_groups.values_list('pk', flat=True) picked_groups = picked_groups.values_list('pk', flat=True)
if request.method == 'POST': if request.method == 'POST':
checked_groups = [int(ag) for ag in request.POST.getlist('ag', default=0)]
for abon_group in AbonGroup.objects.all():
if abon_group.pk in checked_groups and abon_group.pk not in picked_groups:
assign_perm('abonapp.can_view_abongroup', userprofile, obj=abon_group)
elif abon_group.pk not in checked_groups and abon_group.pk in picked_groups:
remove_perm('abonapp.can_view_abongroup', userprofile, obj=abon_group)
checked_groups = [int(ag) for ag in request.POST.getlist('grp', default=0)]
for grp in Group.objects.all():
if grp.pk in checked_groups and grp.pk not in picked_groups:
assign_perm('groupapp.can_view_group', userprofile, obj=grp)
elif grp.pk not in checked_groups and grp.pk in picked_groups:
remove_perm('groupapp.can_view_group', userprofile, obj=grp)
return redirect('acc_app:set_abon_groups_permission', uid) return redirect('acc_app:set_abon_groups_permission', uid)
abongroups = AbonGroup.objects.only('pk', 'title')
groups = Group.objects.only('pk', 'title')
return render(request, 'accounts/set_abon_groups_permission.html', { return render(request, 'accounts/set_abon_groups_permission.html', {
'uid': uid, 'uid': uid,
'userprofile': userprofile, 'userprofile': userprofile,
'abongroups': abongroups,
'groups': groups,
'picked_groups_ids': picked_groups 'picked_groups_ids': picked_groups
}) })

17
agent/commands/dhcp.py

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.core.exceptions import MultipleObjectsReturned from django.core.exceptions import MultipleObjectsReturned
from django.utils.translation import ugettext as _
from abonapp.models import Abon from abonapp.models import Abon
from devapp.models import Device, Port from devapp.models import Device, Port
@ -16,21 +15,23 @@ def dhcp_commit(client_ip, client_mac, switch_mac, switch_port):
else: else:
abon = Abon.objects.get(device=dev) abon = Abon.objects.get(device=dev)
if not abon.is_dynamic_ip: if not abon.is_dynamic_ip:
print('D:', _('User settings is not dynamic'))
print('D:', 'User settings is not dynamic')
return return
if not abon.is_access(): if not abon.is_access():
print('D:', 'User %s is not access to service' % abon.username) print('D:', 'User %s is not access to service' % abon.username)
return return
abon.ip_address = client_ip abon.ip_address = client_ip
abon.is_dhcp = True
abon.save(update_fields=['ip_address']) abon.save(update_fields=['ip_address'])
#print('S:', _("Ip address:'%s' update for '%s' successfull, on port: %s") % (client_ip, abon.get_short_name(), port))
abon.sync_with_nas(created=False)
except Abon.DoesNotExist: except Abon.DoesNotExist:
print('N:', _("User with device '%s' does not exist") % dev)
print('N:', "User with device '%s' does not exist" % dev)
except Device.DoesNotExist: except Device.DoesNotExist:
print('N:', _('Device with mac %s not found') % switch_mac)
print('N:', 'Device with mac %s not found' % switch_mac)
except Port.DoesNotExist: except Port.DoesNotExist:
print('N:', _('Port %d on device with mac %s does not exist') % (int(switch_port), switch_mac))
print('N:', 'Port %(switch_port)d on device with mac %(switch_mac)s does not exist' % {
'switch_port': int(switch_port),
'switch_mac': switch_mac
})
except MultipleObjectsReturned as e: except MultipleObjectsReturned as e:
print('E:', 'MultipleObjectsReturned:', type(e), e, port, dev) print('E:', 'MultipleObjectsReturned:', type(e), e, port, dev)
@ -39,8 +40,8 @@ def dhcp_expiry(client_ip):
try: try:
abon = Abon.objects.get(ip_address=client_ip) abon = Abon.objects.get(ip_address=client_ip)
abon.ip_address = None abon.ip_address = None
abon.is_dhcp = True
abon.save(update_fields=['ip_address']) abon.save(update_fields=['ip_address'])
abon.sync_with_nas(created=False)
except Abon.DoesNotExist: except Abon.DoesNotExist:
pass pass

32
chatbot/migrations/0001_initial.py

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-01-15 20:55
# Generated by Django 1.11 on 2018-02-26 00:20
from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@ -23,13 +24,38 @@ class Migration(migrations.Migration):
('date_sent', models.DateTimeField(auto_now_add=True)), ('date_sent', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
], ],
options={
'verbose_name': 'Message history',
'verbose_name_plural': 'Message histories',
'db_table': 'chat_message_history',
},
),
migrations.CreateModel(
name='MessageQueue',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('message', models.CharField(max_length=255, verbose_name='Message')),
('status', models.CharField(choices=[('n', 'New'), ('r', 'Read')], default='n', max_length=1, verbose_name='Status of message')),
('tag', models.CharField(default='none', max_length=6, verbose_name='App tag')),
('target_employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Target employee')),
],
options={
'verbose_name': 'Message queue',
'verbose_name_plural': 'Message queue',
'db_table': 'chat_message_queue',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='TelegramBot', name='TelegramBot',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('chat_id', models.PositiveIntegerField(default=0)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('chat_id', models.PositiveIntegerField(default=0, verbose_name='Telegram chat id')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Employee')),
], ],
options={
'verbose_name': 'Telegram bot',
'verbose_name_plural': 'Telegram bots',
'db_table': 'chat_telegram_bot',
},
), ),
] ]

59
chatbot/migrations/0002_auto_20171214_1517.py

@ -1,59 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-12-14 15:17
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('chatbot', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='MessageQueue',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('message', models.CharField(max_length=255, verbose_name='Message')),
('status', models.CharField(choices=[('n', 'New'), ('r', 'Read')], default='n', max_length=1, verbose_name='Status of message')),
('tag', models.CharField(default='none', max_length=6, verbose_name='App tag')),
('target_employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Target employee')),
],
options={
'verbose_name': 'Message queue',
'verbose_name_plural': 'Message queue',
'db_table': 'chat_message_queue',
},
),
migrations.AlterModelOptions(
name='messagehistory',
options={'verbose_name': 'Message history', 'verbose_name_plural': 'Message histories'},
),
migrations.AlterModelOptions(
name='telegrambot',
options={'verbose_name': 'Telegram bot', 'verbose_name_plural': 'Telegram bots'},
),
migrations.AlterField(
model_name='telegrambot',
name='chat_id',
field=models.PositiveIntegerField(default=0, verbose_name='Telegram chat id'),
),
migrations.AlterField(
model_name='telegrambot',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Employee'),
),
migrations.AlterModelTable(
name='messagehistory',
table='chat_message_history',
),
migrations.AlterModelTable(
name='telegrambot',
table='chat_telegram_bot',
),
]

49
clientsideapp/locale/ru/LC_MESSAGES/django.po

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-03-13 11:49+0300\n"
"POT-Creation-Date: 2018-03-20 01:51+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n" "Last-Translator: Dmitry Novikov nerosketch@gmail.com\n"
"Language: ru\n" "Language: ru\n"
@ -31,25 +31,26 @@ msgstr "Оплатить задолженность"
msgid "Are you sure you want to spend a payment?" msgid "Are you sure you want to spend a payment?"
msgstr "Вы уверены что хотите провести платёж?" msgstr "Вы уверены что хотите провести платёж?"
#: templates/clientsideapp/debt_buy.html:22
#: templates/clientsideapp/debt_buy.html:21
#, python-format
msgid "" msgid ""
"From your account, they withdraw funds in <b>%(amount)s</b> rub.<br/> As a " "From your account, they withdraw funds in <b>%(amount)s</b> rub.<br/> As a "
"result, you will remain on your account %(ballance_after)s rubles.<br/> The " "result, you will remain on your account %(ballance_after)s rubles.<br/> The "
"administrator can immediately see that you shut down the debt." "administrator can immediately see that you shut down the debt."
msgstr "" msgstr ""
"С вашего счёта снимутся средства в размере <b>%(amount)s</b> руб.<br/>\n"
"В результате у вас на счету останется %(ballance_after)s руб.<br/>\n"
"Администратор сразу сможет видеть что у вас закрыта задолженность."
"С вашего счёта снимутся средства в размере <b>%(amount)s</b> руб.<br/>В "
"результате у вас на счету останется %(ballance_after)s руб.<br/"
">Администратор сразу сможет видеть что у вас закрыта задолженность."
#: templates/clientsideapp/debt_buy.html:28
#: templates/clientsideapp/debt_buy.html:26
msgid "Description of payment" msgid "Description of payment"
msgstr "Описание платежа" msgstr "Описание платежа"
#: templates/clientsideapp/debt_buy.html:36
#: templates/clientsideapp/debt_buy.html:34
msgid "Confirm" msgid "Confirm"
msgstr "Подтвердить" msgstr "Подтвердить"
#: templates/clientsideapp/debt_buy.html:39
#: templates/clientsideapp/debt_buy.html:37
msgid "Cancel" msgid "Cancel"
msgstr "Отменить" msgstr "Отменить"
@ -82,7 +83,7 @@ msgid "Pay"
msgstr "Оплатить" msgstr "Оплатить"
#: templates/clientsideapp/debts.html:23 templates/clientsideapp/ext.html:63 #: templates/clientsideapp/debts.html:23 templates/clientsideapp/ext.html:63
#: templates/clientsideapp/modal_service_buy.html:18
#: templates/clientsideapp/modal_service_buy.html:19
#: templates/clientsideapp/services.html:26 #: templates/clientsideapp/services.html:26
#: templates/clientsideapp/services.html:55 #: templates/clientsideapp/services.html:55
msgid "currency" msgid "currency"
@ -151,28 +152,27 @@ msgid ""
"Be careful, after purchasing the service you will <b>withdraw money</b>, and " "Be careful, after purchasing the service you will <b>withdraw money</b>, and "
"you will be able to use the purchased service." "you will be able to use the purchased service."
msgstr "" msgstr ""
"Будте внимательны, после заказа услуги с вашего счёта <b>снимутся средства</b>, "
"и вы сможете пользоваться купленной услугой."
"Будте внимательны, после заказа услуги с вашего счёта <b>снимутся средства</"
"b>, и вы сможете пользоваться купленной услугой."
#: templates/clientsideapp/modal_service_buy.html:15 #: templates/clientsideapp/modal_service_buy.html:15
#, python-format #, python-format
msgid "" msgid ""
"Inbound speed: %(speedIn)s MBit/s<br>\n"
"Outgoing speed: %(speedOut)s MBit/s<br>\n"
"Cost: %(amount)s rubles."
"Inbound speed: %(speedIn)s MBit/s<br> Outgoing speed: %(speedOut)s MBit/"
"s<br> Cost: %(amount)s rubles."
msgstr "" msgstr ""
#: templates/clientsideapp/modal_service_buy.html:18
#: templates/clientsideapp/modal_service_buy.html:19
#, python-format #, python-format
msgid "The cost is %(amount)s" msgid "The cost is %(amount)s"
msgstr "Стоимость %(amount)s" msgstr "Стоимость %(amount)s"
#: templates/clientsideapp/modal_service_buy.html:22
#: templates/clientsideapp/modal_service_buy.html:23
#: templates/clientsideapp/services.html:63 #: templates/clientsideapp/services.html:63
msgid "Pick" msgid "Pick"
msgstr "Заказать" msgstr "Заказать"
#: templates/clientsideapp/modal_service_buy.html:24
#: templates/clientsideapp/modal_service_buy.html:25
msgid "Close" msgid "Close"
msgstr "Закрыть" msgstr "Закрыть"
@ -217,8 +217,8 @@ msgid ""
"<strong>Attantion!</strong> You have not yet a service, for use the services " "<strong>Attantion!</strong> You have not yet a service, for use the services "
"please purchase service you want." "please purchase service you want."
msgstr "" msgstr ""
"<strong>Внимание!</strong> У вас нет услуги, для использования ресурсов приобретите "
"нужную услугу из представленных тут."
"<strong>Внимание!</strong> У вас нет услуги, для использования ресурсов "
"приобретите нужную услугу из представленных тут."
#: templates/clientsideapp/services.html:46 #: templates/clientsideapp/services.html:46
msgid "Services available for ordering" msgid "Services available for ordering"
@ -233,15 +233,20 @@ msgstr "Нет доступных для заказа услуг"
msgid "Buy the service via user side, service '%s'" msgid "Buy the service via user side, service '%s'"
msgstr "Покупка тарифного плана через личный кабинет, тариф '%s'" msgstr "Покупка тарифного плана через личный кабинет, тариф '%s'"
#: views.py:53
#: views.py:54
#, python-format #, python-format
msgid "The service '%s' wan successfully activated" msgid "The service '%s' wan successfully activated"
msgstr "Услуга '%s' успешно подключена" msgstr "Услуга '%s' успешно подключена"
#: views.py:83
#: views.py:84
msgid "Are you not sure that you want buy the service?" msgid "Are you not sure that you want buy the service?"
msgstr "Вы не уверены что хотите оплатить долг?" msgstr "Вы не уверены что хотите оплатить долг?"
#: views.py:85
#: views.py:86
msgid "Your account have not enough money" msgid "Your account have not enough money"
msgstr "Недостаточно средств на счету" msgstr "Недостаточно средств на счету"
#: views.py:89
#, python-format
msgid "%(username)s paid the debt %(amount).2f"
msgstr "%(username)s заплатил долг в размере %(amount).2f"

6
clientsideapp/templates/clientsideapp/debt_buy.html

@ -18,13 +18,11 @@
{% trans 'Are you sure you want to spend a payment?' %} {% trans 'Are you sure you want to spend a payment?' %}
</label> </label>
</div> </div>
<p>
{% blocktrans trimmed %}
<p>{% blocktrans trimmed %}
From your account, they withdraw funds in <b>{{ amount }}</b> rub.<br/> From your account, they withdraw funds in <b>{{ amount }}</b> rub.<br/>
As a result, you will remain on your account {{ ballance_after }} rubles.<br/> As a result, you will remain on your account {{ ballance_after }} rubles.<br/>
The administrator can immediately see that you shut down the debt. The administrator can immediately see that you shut down the debt.
{% endblocktrans %}
</p>
{% endblocktrans %}</p>
<h4>{% trans 'Description of payment' %}</h4> <h4>{% trans 'Description of payment' %}</h4>
<div class="alert alert-info"> <div class="alert alert-info">

2
clientsideapp/templates/clientsideapp/ext.html

@ -60,7 +60,7 @@
</li> </li>
</ul> </ul>
<span class="navbar-text"> <span class="navbar-text">
{% blocktrans with ballance=subscriber.ballance|floatformat:2 %}Your balance is <b>{{ ballance }}</b>{% endblocktrans %} {% trans 'currency' %}
{% blocktrans with ballance=request.user.ballance|floatformat:2 %}Your balance is <b>{{ ballance }}</b>{% endblocktrans %} {% trans 'currency' %}
</span> </span>
</div><!--/.nav-collapse --> </div><!--/.nav-collapse -->
</div> </div>

3
clientsideapp/templates/clientsideapp/modal_service_buy.html

@ -12,7 +12,8 @@
<p>{{ service.descr }}</p> <p>{{ service.descr }}</p>
<!--<p>{% blocktrans with speedIn=service.speedIn speedOut=service.speedOut amount=service.amount %}Inbound speed: {{ speedIn }} MBit/s<br>
<!--<p>{# {% blocktrans trimmed with speedIn=service.speedIn speedOut=service.speedOut amount=service.amount %}
Inbound speed: {{ speedIn }} MBit/s<br>
Outgoing speed: {{ speedOut }} MBit/s<br> Outgoing speed: {{ speedOut }} MBit/s<br>
Cost: {{ amount }} rubles.{% endblocktrans %}</p>--> Cost: {{ amount }} rubles.{% endblocktrans %}</p>-->
<p>{% blocktrans with amount=service.amount|floatformat:2 %}The cost is {{ amount }}{% endblocktrans %} {% trans 'currency' %}</p> <p>{% blocktrans with amount=service.amount|floatformat:2 %}The cost is {{ amount }}{% endblocktrans %} {% trans 'currency' %}</p>

23
clientsideapp/views.py

@ -4,7 +4,7 @@ from django.contrib.gis.shortcuts import render_to_text
from django.shortcuts import render, get_object_or_404, redirect from django.shortcuts import render, get_object_or_404, redirect
from django.contrib import messages from django.contrib import messages
from django.db import transaction from django.db import transaction
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_lazy as _, gettext
from abonapp.models import AbonLog, InvoiceForPayment, Abon from abonapp.models import AbonLog, InvoiceForPayment, Abon
from tariff_app.models import Tariff from tariff_app.models import Tariff
@ -28,10 +28,10 @@ def pays(request):
@login_required @login_required
def services(request): def services(request):
try: try:
abon = Abon.objects.get(pk=request.user.pk)
all_tarifs = abon.group.tariffs.filter(is_admin=False)
abon = request.user
all_tarifs = Tariff.objects.get_tariffs_by_group(abon.group.pk)
current_service = abon.active_tariff() current_service = abon.active_tariff()
except:
except Abon.DoesNotExist:
all_tarifs = None all_tarifs = None
current_service = None current_service = None
return render(request, 'clientsideapp/services.html', { return render(request, 'clientsideapp/services.html', {
@ -43,13 +43,14 @@ def services(request):
@login_required @login_required
@transaction.atomic @transaction.atomic
def buy_service(request, srv_id): def buy_service(request, srv_id):
abon = get_object_or_404(Abon, pk=request.user.pk)
abon = request.user
service = get_object_or_404(Tariff, pk=srv_id) service = get_object_or_404(Tariff, pk=srv_id)
try: try:
current_service = abon.active_tariff() current_service = abon.active_tariff()
if request.method == 'POST': if request.method == 'POST':
abon.pick_tariff(service, request.user, _("Buy the service via user side, service '%s'")
abon.pick_tariff(service, None, _("Buy the service via user side, service '%s'")
% service) % service)
abon.sync_with_nas(created=False)
messages.success(request, _("The service '%s' wan successfully activated") % service.title) messages.success(request, _("The service '%s' wan successfully activated") % service.title)
else: else:
return render_to_text('clientsideapp/modal_service_buy.html', { return render_to_text('clientsideapp/modal_service_buy.html', {
@ -75,7 +76,7 @@ def debts_list(request):
@transaction.atomic @transaction.atomic
def debt_buy(request, d_id): def debt_buy(request, d_id):
debt = get_object_or_404(InvoiceForPayment, id=d_id) debt = get_object_or_404(InvoiceForPayment, id=d_id)
abon = get_object_or_404(Abon, id=request.user.id)
abon = request.user
if request.method == 'POST': if request.method == 'POST':
try: try:
sure = request.POST.get('sure') sure = request.POST.get('sure')
@ -84,9 +85,13 @@ def debt_buy(request, d_id):
if abon.ballance < debt.amount: if abon.ballance < debt.amount:
raise LogicError(_('Your account have not enough money')) raise LogicError(_('Your account have not enough money'))
abon.make_pay(request.user, debt.amount)
debt.set_ok()
amount = -debt.amount
abon.add_ballance(None, amount, comment=gettext('%(username)s paid the debt %(amount).2f') % {
'username': abon.get_full_name(),
'amount': amount
})
abon.save(update_fields=['ballance']) abon.save(update_fields=['ballance'])
debt.set_ok()
debt.save(update_fields=['status', 'date_pay']) debt.save(update_fields=['status', 'date_pay'])
return redirect('client_side:debts') return redirect('client_side:debts')
except LogicError as e: except LogicError as e:

5
devapp/forms.py

@ -28,10 +28,7 @@ class DeviceForm(forms.ModelForm):
'comment': forms.TextInput(attrs={ 'comment': forms.TextInput(attrs={
'required': True 'required': True
}), }),
'man_passw': forms.PasswordInput(render_value=True),
'user_group': forms.Select(attrs={
'class': 'form-control'
})
'man_passw': forms.PasswordInput(render_value=True)
} }

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

@ -411,7 +411,7 @@ msgid "You have redirected to existing device"
msgstr "Вы были переадресованы на существующее устройство" msgstr "Вы были переадресованы на существующее устройство"
#: views.py:113 views.py:329 views.py:419 #: views.py:113 views.py:329 views.py:419
msgid "Please attach user group for device"
msgid "Please attach group for device"
msgstr "Пожалуйста назначте устройству группу в настройках" msgstr "Пожалуйста назначте устройству группу в настройках"
#: views.py:117 views.py:275 views.py:304 views.py:421 #: views.py:117 views.py:275 views.py:304 views.py:421
@ -424,7 +424,7 @@ msgid "Duplicate user and port: %s"
msgstr "Пользователь с таким портом и устройством уже есть: %s" msgstr "Пользователь с таким портом и устройством уже есть: %s"
#: views.py:159 views.py:198 #: views.py:159 views.py:198
msgid "Device is not have a group, please fix that"
msgid "Device does not have a group, please fix that"
msgstr "У устройства нет группы, пожалуйста, исправьте это" msgstr "У устройства нет группы, пожалуйста, исправьте это"
#: views.py:164 views.py:231 views.py:316 #: views.py:164 views.py:231 views.py:316

62
devapp/migrations/0001_initial.py

@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-02-26 00:20
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djing.fields
import mydefs
class Migration(migrations.Migration):
initial = True
dependencies = [
('group_app', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Device',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip_address', mydefs.MyGenericIPAddressField(max_length=8, protocol='ipv4', verbose_name='Ip address')),
('mac_addr', djing.fields.MACAddressField(blank=True, integer=True, null=True, unique=True, verbose_name='Mac address')),
('comment', models.CharField(max_length=256, verbose_name='Comment')),
('devtype', models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU'), ('Ex', 'Eltex switch')], default='Dl', max_length=2, verbose_name='Device type')),
('man_passw', models.CharField(blank=True, max_length=16, null=True, verbose_name='SNMP password')),
('snmp_item_num', models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='SNMP Number')),
('status', models.CharField(choices=[('und', 'Undefined'), ('up', 'Up'), ('unr', 'Unreachable'), ('dwn', 'Down')], default='und', max_length=3, verbose_name='Status')),
('is_noticeable', models.BooleanField(default=False, verbose_name='Send notify when monitoring state changed')),
('group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='group_app.Group', verbose_name='Device group')),
('parent_dev', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Device', verbose_name='Parent device')),
],
options={
'verbose_name': 'Device',
'verbose_name_plural': 'Devices',
'db_table': 'dev',
'ordering': ['comment'],
'permissions': (('can_view_device', 'Can view device'),),
},
),
migrations.CreateModel(
name='Port',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('num', models.PositiveSmallIntegerField(default=0, verbose_name='Number')),
('descr', models.CharField(blank=True, max_length=60, null=True, verbose_name='Description')),
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device', verbose_name='Device')),
],
options={
'verbose_name': 'Port',
'verbose_name_plural': 'Ports',
'db_table': 'dev_port',
'permissions': (('can_toggle_ports', 'Can toggle ports'),),
},
),
migrations.AlterUniqueTogether(
name='port',
unique_together=set([('device', 'num')]),
),
]

90
devapp/migrations/0001_squashed_0007_auto_20170816_1109.py

@ -1,90 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-09-04 16:14
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djing.fields
import mydefs
class Migration(migrations.Migration):
initial = True
dependencies = [
('mapapp', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Device',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('ip_address', mydefs.MyGenericIPAddressField(max_length=8, protocol='ipv4')),
('comment', models.CharField(max_length=256)),
('devtype', models.CharField(choices=[('Dl', "Свич D'Link")], default='Dl', max_length=2)),
('man_passw', models.CharField(blank=True, max_length=16, null=True)),
],
),
migrations.CreateModel(
name='Port',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('num', models.PositiveSmallIntegerField(default=0)),
('speed', models.CharField(choices=[('h', '100Mbps'), ('k', '1Gbps'), ('d', '10Gbps')], default='h', max_length=1)),
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device')),
],
),
migrations.AlterUniqueTogether(
name='port',
unique_together=set([('device', 'num')]),
),
migrations.AlterModelTable(
name='device',
table='dev',
),
migrations.AlterModelTable(
name='port',
table='dev_port',
),
migrations.AddField(
model_name='device',
name='map_dot',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mapapp.Dot'),
),
migrations.AlterField(
model_name='device',
name='devtype',
field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT')], default='Dl', max_length=2),
),
migrations.RemoveField(
model_name='port',
name='speed',
),
migrations.AddField(
model_name='device',
name='mac_addr',
field=djing.fields.MACAddressField(blank=True, integer=True, null=True, unique=True),
),
migrations.AddField(
model_name='device',
name='parent_dev',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Device'),
),
migrations.AddField(
model_name='port',
name='descr',
field=models.CharField(blank=True, max_length=60, null=True),
),
migrations.AlterField(
model_name='device',
name='devtype',
field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU')], default='Dl', max_length=2),
),
migrations.AlterField(
model_name='device',
name='devtype',
field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU'), ('Ex', 'Eltex switch')], default='Dl', max_length=2),
),
]

22
devapp/migrations/0002_device_user_group.py

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-09-04 16:16
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('abonapp', '0001_squashed_0022_auto_20170816_1109'),
('devapp', '0001_squashed_0007_auto_20170816_1109'),
]
operations = [
migrations.AddField(
model_name='device',
name='user_group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonGroup'),
),
]

23
devapp/migrations/0003_auto_20170927_1838.py

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-09-27 18:38
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('devapp', '0002_device_user_group'),
]
operations = [
migrations.AlterModelOptions(
name='device',
options={'permissions': (('can_view_device', 'Can view device'),), 'verbose_name': 'Device', 'verbose_name_plural': 'Devices'},
),
migrations.AlterModelOptions(
name='port',
options={'permissions': (('can_toggle_ports', 'Can toggle ports'),), 'verbose_name': 'Port', 'verbose_name_plural': 'Ports'},
),
]

72
devapp/migrations/0004_auto_20171103_0006.py

@ -1,72 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-11-03 00:06
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import djing.fields
import mydefs
class Migration(migrations.Migration):
dependencies = [
('devapp', '0003_auto_20170927_1838'),
]
operations = [
migrations.RemoveField(
model_name='device',
name='map_dot',
),
migrations.AlterField(
model_name='device',
name='comment',
field=models.CharField(max_length=256, verbose_name='Comment'),
),
migrations.AlterField(
model_name='device',
name='devtype',
field=models.CharField(choices=[('Dl', 'DLink switch'), ('Pn', 'PON OLT'), ('On', 'PON ONU'), ('Ex', 'Eltex switch')], default='Dl', max_length=2, verbose_name='Device type'),
),
migrations.AlterField(
model_name='device',
name='ip_address',
field=mydefs.MyGenericIPAddressField(max_length=8, protocol='ipv4', verbose_name='Ip address'),
),
migrations.AlterField(
model_name='device',
name='mac_addr',
field=djing.fields.MACAddressField(blank=True, integer=True, null=True, unique=True, verbose_name='Mac address'),
),
migrations.AlterField(
model_name='device',
name='man_passw',
field=models.CharField(blank=True, max_length=16, null=True, verbose_name='SNMP password'),
),
migrations.AlterField(
model_name='device',
name='parent_dev',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='devapp.Device', verbose_name='Parent device'),
),
migrations.AlterField(
model_name='device',
name='user_group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonGroup', verbose_name='User group'),
),
migrations.AlterField(
model_name='port',
name='descr',
field=models.CharField(blank=True, max_length=60, null=True, verbose_name='Description'),
),
migrations.AlterField(
model_name='port',
name='device',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device', verbose_name='Device'),
),
migrations.AlterField(
model_name='port',
name='num',
field=models.PositiveSmallIntegerField(default=0, verbose_name='Number'),
),
]

20
devapp/migrations/0005_device_snmp_item_num.py

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-11-07 16:19
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('devapp', '0004_auto_20171103_0006'),
]
operations = [
migrations.AddField(
model_name='device',
name='snmp_item_num',
field=models.PositiveSmallIntegerField(default=0),
),
]

34
devapp/migrations/0006_auto_20180129_1625.py

@ -1,34 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-01-29 16:25
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('devapp', '0005_device_snmp_item_num'),
]
operations = [
migrations.AlterModelOptions(
name='device',
options={'ordering': ['comment'], 'permissions': (('can_view_device', 'Can view device'),), 'verbose_name': 'Device', 'verbose_name_plural': 'Devices'},
),
migrations.AddField(
model_name='device',
name='is_noticeable',
field=models.BooleanField(default=False, verbose_name='Send notify when monitoring state changed'),
),
migrations.AddField(
model_name='device',
name='status',
field=models.CharField(choices=[('und', 'Undefined'), ('up', 'Up'), ('unr', 'Unreachable'), ('dwn', 'Down')], default='und', max_length=3, verbose_name='Status'),
),
migrations.AlterField(
model_name='device',
name='snmp_item_num',
field=models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='SNMP Number'),
),
]

7
devapp/models.py

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import requests import requests
from django.db import models
from django.db import models, ProgrammingError
from djing.fields import MACAddressField from djing.fields import MACAddressField
from .base_intr import DevBase from .base_intr import DevBase
from mydefs import MyGenericIPAddressField, MyChoicesAdapter, ip2int from mydefs import MyGenericIPAddressField, MyChoicesAdapter, ip2int
@ -9,6 +9,7 @@ from subprocess import run
from django.conf import settings from django.conf import settings
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from json.decoder import JSONDecodeError from json.decoder import JSONDecodeError
from group_app.models import Group
DEVICE_TYPES = ( DEVICE_TYPES = (
@ -51,7 +52,7 @@ class Device(models.Model):
comment = models.CharField(_('Comment'), max_length=256) comment = models.CharField(_('Comment'), max_length=256)
devtype = models.CharField(_('Device type'), max_length=2, default=DEVICE_TYPES[0][0], choices=MyChoicesAdapter(DEVICE_TYPES)) devtype = models.CharField(_('Device type'), max_length=2, default=DEVICE_TYPES[0][0], choices=MyChoicesAdapter(DEVICE_TYPES))
man_passw = models.CharField(_('SNMP password'), max_length=16, null=True, blank=True) man_passw = models.CharField(_('SNMP password'), max_length=16, null=True, blank=True)
user_group = models.ForeignKey('abonapp.AbonGroup', verbose_name=_('User group'), on_delete=models.SET_NULL, null=True, blank=True)
group = models.ForeignKey(Group, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Device group'))
parent_dev = models.ForeignKey('self', verbose_name=_('Parent device'), blank=True, null=True, on_delete=models.SET_NULL) parent_dev = models.ForeignKey('self', verbose_name=_('Parent device'), blank=True, null=True, on_delete=models.SET_NULL)
snmp_item_num = models.PositiveSmallIntegerField(_('SNMP Number'), default=0, blank=True) snmp_item_num = models.PositiveSmallIntegerField(_('SNMP Number'), default=0, blank=True)
@ -106,6 +107,8 @@ class Device(models.Model):
def update_dhcp(self): def update_dhcp(self):
if self.devtype not in ('On','Dl'): if self.devtype not in ('On','Dl'):
return return
raise ProgrammingError('переделать это безобразие')
# FIXME: переделать это безобразие
grp = self.user_group.id grp = self.user_group.id
code = '' code = ''
if grp == 87: if grp == 87:

2
devapp/templates/devapp/add_dev.html

@ -40,7 +40,7 @@
{% bootstrap_field form.man_passw addon_before=ic %} {% bootstrap_field form.man_passw addon_before=ic %}
{% bootstrap_icon 'subscript' as ic %} {% bootstrap_icon 'subscript' as ic %}
{% bootstrap_field form.user_group addon_before=ic %}
{% bootstrap_field form.group addon_before=ic %}
<div class="form-group"> <div class="form-group">
<label for="id_parent_dev">{% trans 'Parent device' %}</label> <label for="id_parent_dev">{% trans 'Parent device' %}</label>

2
devapp/templates/devapp/custom_dev_page/olt.html

@ -23,7 +23,7 @@
</thead> </thead>
<tbody> <tbody>
{% with dip=dev.ip_address grp=dev.user_group.pk %}
{% with dip=dev.ip_address grp=dev.group.pk %}
{% for port in ports %} {% for port in ports %}
<tr> <tr>
<td>{% if port.st %}<span class="glyphicon glyphicon-ok text-success"></span> <td>{% if port.st %}<span class="glyphicon glyphicon-ok text-success"></span>

2
devapp/templates/devapp/custom_dev_page/onu.html

@ -30,7 +30,7 @@
{% endfor %} {% endfor %}
{% if dev.parent_dev %} {% if dev.parent_dev %}
<li class="list-group-item"> <li class="list-group-item">
{% with pdev=dev.parent_dev pdgrp=dev.parent_dev.user_group %}
{% with pdev=dev.parent_dev pdgrp=dev.parent_dev.group %}
{% trans 'Parent device' %}:<a href="{% url 'devapp:view' pdgrp.pk pdev.pk %}" {% trans 'Parent device' %}:<a href="{% url 'devapp:view' pdgrp.pk pdev.pk %}"
title="{{ pdev.mac_addr|default:'' }}" title="{{ pdev.mac_addr|default:'' }}"
target="_blank">{{ pdev.ip_address }} {{ pdev.comment }}</a> target="_blank">{{ pdev.ip_address }} {{ pdev.comment }}</a>

4
devapp/templates/devapp/custom_dev_page/ports.html

@ -41,11 +41,11 @@
<b>{{ port.num }}</b> <b>{{ port.num }}</b>
</a> </a>
{% if port.st %} {% if port.st %}
<a href="{% url 'devapp:port_toggle' dev.user_group.pk|default:0 dev.id port.num 0 %}" class="btn btn-xs btn-danger" title="{% trans 'Disable port' %}">
<a href="{% url 'devapp:port_toggle' dev.group.pk|default:0 dev.id port.num 0 %}" class="btn btn-xs btn-danger" title="{% trans 'Disable port' %}">
<span class="glyphicon glyphicon-off"></span> <span class="glyphicon glyphicon-off"></span>
</a> </a>
{% else %} {% else %}
<a href="{% url 'devapp:port_toggle' dev.user_group.pk|default:0 dev.id port.num 1 %}" class="btn btn-xs btn-success" title="{% trans 'Enable port' %}">
<a href="{% url 'devapp:port_toggle' dev.group.pk|default:0 dev.id port.num 1 %}" class="btn btn-xs btn-success" title="{% trans 'Enable port' %}">
<span class="glyphicon glyphicon-ok"></span> <span class="glyphicon glyphicon-ok"></span>
</a> </a>
{% endif %} {% endif %}

2
devapp/templates/devapp/dev.html

@ -27,7 +27,7 @@
{% bootstrap_field form.man_passw addon_before=ic %} {% bootstrap_field form.man_passw addon_before=ic %}
{% bootstrap_icon 'subscript' as ic %} {% bootstrap_icon 'subscript' as ic %}
{% bootstrap_field form.user_group addon_before=ic %}
{% bootstrap_field form.group addon_before=ic %}
<div class="form-group"> <div class="form-group">
<label for="id_parent_dev">{% trans 'Parent device' %}</label> <label for="id_parent_dev">{% trans 'Parent device' %}</label>

8
devapp/templates/devapp/devices.html

@ -41,7 +41,7 @@
</thead> </thead>
<tbody> <tbody>
{% with can_del_dev=perms.devapp.delete_device can_ch_dev=perms.devapp.change_device %}
{% with can_del_dev=perms.devapp.delete_device can_ch_dev=perms.devapp.change_device grpid=group.id %}
{% for dev in devices %} {% for dev in devices %}
<tr> <tr>
@ -57,19 +57,19 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
</td> </td>
<td><a href="{% url 'devapp:view' dev.user_group.pk dev.pk %}">{{ dev.ip_address }}</a></td>
<td><a href="{% url 'devapp:view' grpid dev.pk %}">{{ dev.ip_address }}</a></td>
<td>{{ dev.comment }}</td> <td>{{ dev.comment }}</td>
<td>{{ dev.mac_addr|default:_('Not assigned') }}</td> <td>{{ dev.mac_addr|default:_('Not assigned') }}</td>
{# <td class="hidden-xs hidden-sm">{{ dev.mon.plugin_output|default:'&ndash;' }}</td> #} {# <td class="hidden-xs hidden-sm">{{ dev.mon.plugin_output|default:'&ndash;' }}</td> #}
<td>{{ dev.get_devtype_display }}</td> <td>{{ dev.get_devtype_display }}</td>
<td class="btn-group btn-group-xs btn-group-justified"> <td class="btn-group btn-group-xs btn-group-justified">
{% if can_del_dev %} {% if can_del_dev %}
<a href="{% url 'devapp:del' dev.user_group.pk dev.pk %}" class="btn btn-danger">
<a href="{% url 'devapp:del' grpid dev.pk %}" class="btn btn-danger">
<span class="glyphicon glyphicon-remove"></span> <span class="glyphicon glyphicon-remove"></span>
</a> </a>
{% endif %} {% endif %}
{% if can_ch_dev %} {% if can_ch_dev %}
<a href="{% url 'devapp:edit' dev.user_group.pk dev.id %}" class="btn btn-default">
<a href="{% url 'devapp:edit' grpid dev.id %}" class="btn btn-default">
<span class="glyphicon glyphicon-edit"></span> <span class="glyphicon glyphicon-edit"></span>
</a> </a>
{% endif %} {% endif %}

6
devapp/templates/devapp/devices_null_group.html

@ -41,17 +41,17 @@
{% with can_del_dev=perms.devapp.delete_device can_change_dev=perms.devapp.change_device %} {% with can_del_dev=perms.devapp.delete_device can_change_dev=perms.devapp.change_device %}
{% for dev in devices %} {% for dev in devices %}
<tr> <tr>
<td><a href="{% url 'devapp:view' dev.user_group.pk|default:0 dev.pk %}">{{ dev.ip_address }}</a></td>
<td><a href="{% url 'devapp:view' 0 dev.pk %}">{{ dev.ip_address }}</a></td>
<td>{{ dev.comment }}</td> <td>{{ dev.comment }}</td>
<td>{{ dev.get_devtype_display }}</td> <td>{{ dev.get_devtype_display }}</td>
<td class="btn-group btn-group-sm"> <td class="btn-group btn-group-sm">
{% if can_del_dev %} {% if can_del_dev %}
<a href="{% url 'devapp:del' dev.user_group.pk|default:0 dev.pk %}" class="btn btn-danger btn-sm">
<a href="{% url 'devapp:del' 0 dev.pk %}" class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-remove"></span> <span class="glyphicon glyphicon-remove"></span>
</a> </a>
{% endif %} {% endif %}
{% if can_change_dev %} {% if can_change_dev %}
<a href="{% url 'devapp:edit' dev.user_group.pk|default:0 dev.pk %}" class="btn btn-default btn-sm">
<a href="{% url 'devapp:edit' 0 dev.pk %}" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-edit"></span> <span class="glyphicon glyphicon-edit"></span>
</a> </a>
{% endif %} {% endif %}

10
devapp/templates/devapp/ext.htm

@ -5,8 +5,8 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'devapp:group_list' %}">{% trans 'Groups' %}</a></li> <li><a href="{% url 'devapp:group_list' %}">{% trans 'Groups' %}</a></li>
{% if dev.user_group %}
<li><a href="{% url 'devapp:devs' dev.user_group.pk %}">{{ dev.user_group.title }}</a></li>
{% if dev.group %}
<li><a href="{% url 'devapp:devs' dev.group.pk %}">{{ dev.group.title }}</a></li>
{% else %} {% else %}
<li>{% trans 'Not assigned' %}</li> <li>{% trans 'Not assigned' %}</li>
{% endif %} {% endif %}
@ -21,7 +21,7 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
{% url 'devapp:view' dev.user_group.pk|default:0 dev.pk as devapp_view %}
{% url 'devapp:view' dev.group.pk|default:0 dev.pk as devapp_view %}
<li{% if devapp_view == request.path %} class="active"{% endif %}> <li{% if devapp_view == request.path %} class="active"{% endif %}>
<a href="{{ devapp_view }}"> <a href="{{ devapp_view }}">
{% trans 'Ports' %} {{ dev.ip_address }} {% trans 'Ports' %} {{ dev.ip_address }}
@ -29,12 +29,12 @@
</li> </li>
{% if perms.devapp.change_device %} {% if perms.devapp.change_device %}
{% url 'devapp:edit' dev.user_group.pk|default:0 dev.pk as devapp_edit %}
{% url 'devapp:edit' dev.group.pk|default:0 dev.pk as devapp_edit %}
<li{% if devapp_edit == request.path %} class="active"{% endif %}> <li{% if devapp_edit == request.path %} class="active"{% endif %}>
<a href="{{ devapp_edit }}">{% trans 'Edit' %}</a> <a href="{{ devapp_edit }}">{% trans 'Edit' %}</a>
</li> </li>
{% url 'devapp:manage_ports' dev.user_group.pk|default:0 dev.pk as devapp_mports %}
{% url 'devapp:manage_ports' dev.group.pk|default:0 dev.pk as devapp_mports %}
<li{% if devapp_mports == request.path %} class="active"{% endif %}> <li{% if devapp_mports == request.path %} class="active"{% endif %}>
<a href="{{ devapp_mports }}">{% trans 'Ports' %}</a> <a href="{{ devapp_mports }}">{% trans 'Ports' %}</a>
</li> </li>

6
devapp/templates/devapp/fix_dev_group.html

@ -36,12 +36,12 @@
{% bootstrap_field form.man_passw addon_before=ic %} {% bootstrap_field form.man_passw addon_before=ic %}
<div class="form-group"> <div class="form-group">
<label class="control-label" for="{{ form.user_group.id_for_label }}">{{ form.user_group.label }}</label>
<div class="input-group{% if not dev.user_group %} has-error{% endif %}">
<label class="control-label" for="{{ form.group.id_for_label }}">{{ form.group.label }}</label>
<div class="input-group{% if not dev.group %} has-error{% endif %}">
<span class="input-group-addon"> <span class="input-group-addon">
{% bootstrap_icon 'subscript' %} {% bootstrap_icon 'subscript' %}
</span> </span>
{{ form.user_group }}
{{ form.group }}
</div> </div>
</div> </div>

19
devapp/templates/devapp/group_list.html

@ -7,17 +7,13 @@
<li class="active">{% trans 'Groups' %}</li> <li class="active">{% trans 'Groups' %}</li>
</ol> </ol>
<h3>{% trans 'Groups' %}</h3>
{% include 'message_block.html' %} {% include 'message_block.html' %}
<div class="table-responsive">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'Group title' %}</h3>
</div>
<table class="table table-striped table-bordered"> <table class="table table-striped table-bordered">
<thead>
<tr>
<th>{% trans 'Group title' %}</th>
</tr>
</thead>
<tbody> <tbody>
{% for gr in groups %} {% for gr in groups %}
<tr> <tr>
@ -31,12 +27,7 @@
</tbody> </tbody>
<tfoot> <tfoot>
<tr> <tr>
<td class="btn-group">
{% if perms.abonapp.add_abongroup %}
<a href="{% url 'abonapp:add_group' %}" class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-plus"></span> <span class="hidden-xs">{% trans 'Add group' %}</span>
</a>
{% endif %}
<td>
<a href="{% url 'devapp:devices_null_group' %}" class="btn btn-primary btn-sm"> <a href="{% url 'devapp:devices_null_group' %}" class="btn btn-primary btn-sm">
<span class="glyphicon glyphicon-list-alt"></span> {% trans 'Devices without group' %} <span class="glyphicon glyphicon-list-alt"></span> {% trans 'Devices without group' %}
</a> </a>

8
devapp/templates/devapp/manage_ports/add_ports.html

@ -5,8 +5,8 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'devapp:group_list' %}">{% trans 'Groups' %}</a></li> <li><a href="{% url 'devapp:group_list' %}">{% trans 'Groups' %}</a></li>
<li><a href="{% url 'devapp:devs' dev.user_group.pk %}">{{ dev.user_group.title }}</a></li>
<li><a href="{% url 'devapp:view' dev.user_group.pk dev.pk %}">{{ dev.comment }}</a></li>
<li><a href="{% url 'devapp:devs' dev.group.pk %}">{{ dev.group.title }}</a></li>
<li><a href="{% url 'devapp:view' dev.group.pk dev.pk %}">{{ dev.comment }}</a></li>
<li class="active">{% trans 'Add ports' %}</li> <li class="active">{% trans 'Add ports' %}</li>
</ol> </ol>
@ -22,7 +22,7 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<form class="table-responsive" role="form" action="{% url 'devapp:add_ports' dev.user_group.pk dev.pk %}" method="post">{% csrf_token %}
<form class="table-responsive" role="form" action="{% url 'devapp:add_ports' dev.group.pk dev.pk %}" method="post">{% csrf_token %}
<table class="table table-striped table-bordered"> <table class="table table-striped table-bordered">
<thead> <thead>
@ -34,7 +34,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% with gid=dev.user_group.pk did=dev.pk can_del_port=perms.devapp.delete_port %}
{% with gid=dev.group.pk did=dev.pk can_del_port=perms.devapp.delete_port %}
{% for port in ports %} {% for port in ports %}
<tr> <tr>
<td>{% if port.status %} <td>{% if port.status %}

4
devapp/templates/devapp/manage_ports/fix_abon_device.html

@ -5,8 +5,8 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li> <li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'devapp:group_list' %}">{% trans 'Groups' %}</a></li> <li><a href="{% url 'devapp:group_list' %}">{% trans 'Groups' %}</a></li>
<li><a href="{% url 'devapp:devs' user_group.pk %}">{{ user_group.title }}</a></li>
<li><a href="{% url 'devapp:view' user_group.pk device.pk %}">{{ device.comment }}</a></li>
<li><a href="{% url 'devapp:devs' group.pk %}">{{ group.title }}</a></li>
<li><a href="{% url 'devapp:view' group.pk device.pk %}">{{ device.comment }}</a></li>
<li class="active">{% trans 'Fix subscriber ports conflict' %}</li> <li class="active">{% trans 'Fix subscriber ports conflict' %}</li>
</ol> </ol>

8
devapp/templates/devapp/manage_ports/list.html

@ -16,19 +16,19 @@
</thead> </thead>
<tbody> <tbody>
{% with gid=dev.user_group.pk did=dev.pk can_del_port=perms.devapp.delete_port can_edit_port=perms.devapp.change_port %}
{% with gid=dev.group.pk did=dev.pk can_del_port=perms.devapp.delete_port can_edit_port=perms.devapp.change_port %}
{% for port in ports %} {% for port in ports %}
<tr> <tr>
<td>{{ port.num }}</td> <td>{{ port.num }}</td>
<td>{{ port.descr }}</td> <td>{{ port.descr }}</td>
{% if port.num_abons > 1 %} {% if port.num_abons > 1 %}
{% url 'devapp:fix_port_conflict' dev.user_group.id dev.id port.id as fixurl %}
{% url 'devapp:fix_port_conflict' gid did port.id as fixurl %}
<td class="text-danger"><b>{{ port.num_abons }}</b>. {% blocktrans with furl=fixurl %}Port should not have more than one subscriber, <a href='{{ furl }}'>fix that</a>{% endblocktrans %}</td> <td class="text-danger"><b>{{ port.num_abons }}</b>. {% blocktrans with furl=fixurl %}Port should not have more than one subscriber, <a href='{{ furl }}'>fix that</a>{% endblocktrans %}</td>
{% else %} {% else %}
<td>{{ port.num_abons }}</td> <td>{{ port.num_abons }}</td>
{% endif %} {% endif %}
<td class="btn-group btn-group-sm"> <td class="btn-group btn-group-sm">
<a href="{% url 'devapp:show_subscriber_on_port' dev.user_group.id dev.id port.id %}" class="btn btn-default btn-modal" title="{% trans 'Show subscriber on port' %}" data-toggle="tooltip">
<a href="{% url 'devapp:show_subscriber_on_port' gid did port.id %}" class="btn btn-default btn-modal" title="{% trans 'Show subscriber on port' %}" data-toggle="tooltip">
<span class="glyphicon glyphicon-eye-open"></span> <span class="glyphicon glyphicon-eye-open"></span>
</a> </a>
{% if can_del_port %} {% if can_del_port %}
@ -54,7 +54,7 @@
<tr> <tr>
<td colspan="4" class="btn-group"> <td colspan="4" class="btn-group">
{% if perms.devapp.add_port %} {% if perms.devapp.add_port %}
<a href="{% url 'devapp:add_ports' dev.user_group.pk dev.pk %}" class="btn btn-sm btn-default" title="{% trans 'Add' %}">
<a href="{% url 'devapp:add_ports' dev.group.pk dev.pk %}" class="btn btn-sm btn-default" title="{% trans 'Add' %}">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add ports' %} <span class="glyphicon glyphicon-plus"></span> {% trans 'Add ports' %}
</a> </a>
{% endif %} {% endif %}

80
devapp/views.py

@ -15,7 +15,9 @@ from django.views.generic import ListView, DetailView
from devapp.base_intr import DeviceImplementationError from devapp.base_intr import DeviceImplementationError
from mydefs import res_success, res_error, only_admins, ping, ip_addr_regex from mydefs import res_success, res_error, only_admins, ping, ip_addr_regex
from abonapp.models import AbonGroup, Abon
from abonapp.models import Abon
from group_app.models import Group
from accounts_app.models import UserProfile
from django.conf import settings from django.conf import settings
from guardian.decorators import permission_required_or_403 as permission_required from guardian.decorators import permission_required_or_403 as permission_required
from guardian.shortcuts import get_objects_for_user from guardian.shortcuts import get_objects_for_user
@ -27,8 +29,6 @@ from .models import Device, Port, DeviceDBException, DeviceMonitoringException
from .forms import DeviceForm, PortForm from .forms import DeviceForm, PortForm
from mydefs import safe_int from mydefs import safe_int
PAGINATION_ITEMS_PER_PAGE = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
class BaseDeviceListView(ListView): class BaseDeviceListView(ListView):
http_method_names = ['get'] http_method_names = ['get']
@ -42,15 +42,15 @@ class DevicesListView(BaseDeviceListView, global_base_views.OrderingMixin):
def get_queryset(self): def get_queryset(self):
group_id = safe_int(self.kwargs.get('group_id')) group_id = safe_int(self.kwargs.get('group_id'))
queryset = Device.objects.filter(user_group__pk=group_id) \
.select_related('user_group') \
.only('comment', 'mac_addr', 'devtype', 'user_group', 'pk', 'ip_address')
queryset = Device.objects.filter(group__pk=group_id) \
.select_related('group') \
.only('comment', 'mac_addr', 'devtype', 'group', 'pk', 'ip_address')
return queryset return queryset
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
group_id = safe_int(self.kwargs.get('group_id')) group_id = safe_int(self.kwargs.get('group_id'))
context = super(DevicesListView, self).get_context_data(**kwargs) context = super(DevicesListView, self).get_context_data(**kwargs)
context['group'] = get_object_or_404(AbonGroup, pk=group_id)
context['group'] = get_object_or_404(Group, pk=group_id)
return context return context
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
@ -66,7 +66,7 @@ class DevicesListView(BaseDeviceListView, global_base_views.OrderingMixin):
class DevicesWithoutGroupsListView(BaseDeviceListView, global_base_views.OrderingMixin): class DevicesWithoutGroupsListView(BaseDeviceListView, global_base_views.OrderingMixin):
context_object_name = 'devices' context_object_name = 'devices'
template_name = 'devapp/devices_null_group.html' template_name = 'devapp/devices_null_group.html'
queryset = Device.objects.filter(user_group=None).only('comment', 'devtype', 'user_group', 'pk', 'ip_address')
queryset = Device.objects.filter(group=None).only('comment', 'devtype', 'pk', 'ip_address')
@login_required @login_required
@ -74,7 +74,7 @@ class DevicesWithoutGroupsListView(BaseDeviceListView, global_base_views.Orderin
def devdel(request, device_id): def devdel(request, device_id):
try: try:
dev = Device.objects.get(pk=device_id) dev = Device.objects.get(pk=device_id)
back_url = resolve_url('devapp:devs', group_id=dev.user_group.pk if dev.user_group else 0)
back_url = resolve_url('devapp:devs', group_id=dev.group.pk if dev.group else 0)
dev.delete() dev.delete()
return res_success(request, back_url) return res_success(request, back_url)
except Device.DoesNotExist: except Device.DoesNotExist:
@ -86,8 +86,8 @@ def devdel(request, device_id):
@login_required @login_required
@permission_required('devapp.can_view_device') @permission_required('devapp.can_view_device')
def dev(request, group_id, device_id=0): def dev(request, group_id, device_id=0):
user_group = get_object_or_404(AbonGroup, pk=group_id)
if not request.user.has_perm('abonapp.can_view_abongroup', user_group):
device_group = get_object_or_404(Group, pk=group_id)
if not request.user.has_perm('group_app.can_view_group', device_group):
raise PermissionDenied raise PermissionDenied
devinst = get_object_or_404(Device, id=device_id) if device_id != 0 else None devinst = get_object_or_404(Device, id=device_id) if device_id != 0 else None
already_dev = None already_dev = None
@ -106,11 +106,11 @@ def dev(request, group_id, device_id=0):
# check if that device is exist # check if that device is exist
try: try:
already_dev = Device.objects.exclude(pk=device_id).get(mac_addr=request.POST.get('mac_addr')) already_dev = Device.objects.exclude(pk=device_id).get(mac_addr=request.POST.get('mac_addr'))
if already_dev.user_group:
if already_dev.group:
messages.warning(request, _('You have redirected to existing device')) messages.warning(request, _('You have redirected to existing device'))
return redirect('devapp:view', already_dev.user_group.pk, already_dev.pk)
return redirect('devapp:view', already_dev.group.pk, already_dev.pk)
else: else:
messages.warning(request, _('Please attach user group for device'))
messages.warning(request, _('Please attach group for device'))
return redirect('devapp:fix_device_group', already_dev.pk) return redirect('devapp:fix_device_group', already_dev.pk)
except Device.DoesNotExist: except Device.DoesNotExist:
pass pass
@ -120,7 +120,7 @@ def dev(request, group_id, device_id=0):
# change device info in dhcpd.conf # change device info in dhcpd.conf
ndev.update_dhcp() ndev.update_dhcp()
messages.success(request, _('Device info has been saved')) messages.success(request, _('Device info has been saved'))
return redirect('devapp:edit', ndev.user_group.pk, ndev.pk)
return redirect('devapp:edit', ndev.group.pk, ndev.pk)
else: else:
messages.error(request, _('Form is invalid, check fields and try again')) messages.error(request, _('Form is invalid, check fields and try again'))
except IntegrityError as e: except IntegrityError as e:
@ -131,7 +131,7 @@ def dev(request, group_id, device_id=0):
else: else:
if devinst is None: if devinst is None:
frm = DeviceForm(initial={ frm = DeviceForm(initial={
'user_group': user_group,
'group': device_group,
'devtype': request.GET.get('t'), 'devtype': request.GET.get('t'),
'mac_addr': request.GET.get('mac'), 'mac_addr': request.GET.get('mac'),
'comment': request.GET.get('c'), 'comment': request.GET.get('c'),
@ -145,7 +145,7 @@ def dev(request, group_id, device_id=0):
if devinst is None: if devinst is None:
return render(request, 'devapp/add_dev.html', { return render(request, 'devapp/add_dev.html', {
'form': frm, 'form': frm,
'group': user_group,
'group': device_group,
'already_dev': already_dev 'already_dev': already_dev
}) })
else: else:
@ -153,7 +153,7 @@ def dev(request, group_id, device_id=0):
'form': frm, 'form': frm,
'dev': devinst, 'dev': devinst,
'selected_parent_dev': devinst.parent_dev, 'selected_parent_dev': devinst.parent_dev,
'group': user_group,
'group': device_group,
'already_dev': already_dev 'already_dev': already_dev
}) })
@ -163,8 +163,8 @@ def dev(request, group_id, device_id=0):
def manage_ports(request, device_id): def manage_ports(request, device_id):
try: try:
dev = Device.objects.get(pk=device_id) dev = Device.objects.get(pk=device_id)
if dev.user_group is None:
messages.error(request, _('Device is not have a group, please fix that'))
if dev.group is None:
messages.error(request, _('Device does not have a group, please fix that'))
return redirect('devapp:fix_device_group', dev.pk) return redirect('devapp:fix_device_group', dev.pk)
ports = Port.objects.filter(device=dev).annotate(num_abons=Count('abon')) ports = Port.objects.filter(device=dev).annotate(num_abons=Count('abon'))
@ -220,13 +220,13 @@ def add_ports(request, device_id):
return self.pid return self.pid
def __str__(self): def __str__(self):
return "p:%d\tM:%s\tT:%s" % (self.pid, self.text)
return "p:%d\tT:%s" % (self.pid, self.text)
try: try:
res_ports = list() res_ports = list()
dev = Device.objects.get(pk=device_id) dev = Device.objects.get(pk=device_id)
if dev.user_group is None:
messages.error(request, _('Device is not have a group, please fix that'))
if dev.group is None:
messages.error(request, _('Device does not have a group, please fix that'))
return redirect('devapp:fix_device_group', dev.pk) return redirect('devapp:fix_device_group', dev.pk)
if request.method == 'POST': if request.method == 'POST':
ports = zip( ports = zip(
@ -356,8 +356,8 @@ def devview(request, device_id):
ports, manager = None, None ports, manager = None, None
dev = get_object_or_404(Device, id=device_id) dev = get_object_or_404(Device, id=device_id)
if not dev.user_group:
messages.warning(request, _('Please attach user group for device'))
if not dev.group:
messages.warning(request, _('Please attach group for device'))
return redirect('devapp:fix_device_group', dev.pk) return redirect('devapp:fix_device_group', dev.pk)
template_name = 'ports.html' template_name = 'ports.html'
@ -409,18 +409,18 @@ def toggle_port(request, device_id, portid, status=0):
messages.error(request, _('wait for a reply from the SNMP Timeout')) messages.error(request, _('wait for a reply from the SNMP Timeout'))
except EasySNMPError as e: except EasySNMPError as e:
messages.error(request, 'EasySNMPError: %s' % e) messages.error(request, 'EasySNMPError: %s' % e)
return redirect('devapp:view', dev.user_group.pk if dev.user_group is not None else 0, device_id)
return redirect('devapp:view', dev.group.pk if dev.group is not None else 0, device_id)
@method_decorator([login_required, only_admins], name='dispatch') @method_decorator([login_required, only_admins], name='dispatch')
class GroupsListView(BaseDeviceListView): class GroupsListView(BaseDeviceListView):
context_object_name = 'groups' context_object_name = 'groups'
template_name = 'devapp/group_list.html' template_name = 'devapp/group_list.html'
model = AbonGroup
model = Group
def get_queryset(self): def get_queryset(self):
groups = super(GroupsListView, self).get_queryset() groups = super(GroupsListView, self).get_queryset()
groups = get_objects_for_user(self.request.user, 'abonapp.can_view_abongroup', klass=groups,
groups = get_objects_for_user(self.request.user, 'group_app.can_view_group', klass=groups,
accept_global_perms=False) accept_global_perms=False)
return groups return groups
@ -446,11 +446,11 @@ def fix_device_group(request, device_id):
frm = DeviceForm(request.POST, instance=dev) frm = DeviceForm(request.POST, instance=dev)
if frm.is_valid(): if frm.is_valid():
ch_dev = frm.save() ch_dev = frm.save()
if ch_dev.user_group:
if ch_dev.group:
messages.success(request, _('Device fixed')) messages.success(request, _('Device fixed'))
return redirect('devapp:devs', ch_dev.user_group.pk)
return redirect('devapp:devs', ch_dev.group.pk)
else: else:
messages.error(request, _('Please attach user group for device'))
messages.error(request, _('Please attach group for device'))
else: else:
messages.error(request, _('Form is invalid, check fields and try again')) messages.error(request, _('Form is invalid, check fields and try again'))
else: else:
@ -478,6 +478,7 @@ def fix_onu(request):
text = '<span class="glyphicon glyphicon-ok"></span> <span class="hidden-xs">%s</span>' % \ text = '<span class="glyphicon glyphicon-ok"></span> <span class="hidden-xs">%s</span>' % \
(_('Device with mac address %(mac)s does not exist') % {'mac': mac}) (_('Device with mac address %(mac)s does not exist') % {'mac': mac})
for srcmac, snmpnum in ports: for srcmac, snmpnum in ports:
# convert bytes mac address to str presentation mac address
real_mac = ':'.join(['%x' % ord(i) for i in srcmac]) real_mac = ':'.join(['%x' % ord(i) for i in srcmac])
if mac == real_mac: if mac == real_mac:
onu.snmp_item_num = snmpnum onu.snmp_item_num = snmpnum
@ -497,13 +498,13 @@ def fix_onu(request):
@login_required @login_required
def fix_port_conflict(request, group_id, device_id, port_id): def fix_port_conflict(request, group_id, device_id, port_id):
user_group = get_object_or_404(AbonGroup, pk=group_id)
dev_group = get_object_or_404(Group, pk=group_id)
device = get_object_or_404(Device, pk=device_id) device = get_object_or_404(Device, pk=device_id)
port = get_object_or_404(Port, pk=port_id) port = get_object_or_404(Port, pk=port_id)
abons = Abon.objects.filter(device__id=device_id, dev_port__id=port_id) abons = Abon.objects.filter(device__id=device_id, dev_port__id=port_id)
return render(request, 'devapp/manage_ports/fix_abon_device.html', { return render(request, 'devapp/manage_ports/fix_abon_device.html', {
'abons': abons, 'abons': abons,
'user_group': user_group,
'group': dev_group,
'device': device, 'device': device,
'port': port 'port': port
}) })
@ -527,19 +528,14 @@ class OnDevDown(global_base_views.AllowedSubnetMixin, global_base_views.HashAuth
if not bool(re.match(ip_addr_regex, dev_ip)): if not bool(re.match(ip_addr_regex, dev_ip)):
return {'text': 'ip address %s is not valid' % dev_ip} return {'text': 'ip address %s is not valid' % dev_ip}
possible_devices = Device.objects.filter(ip_address=dev_ip)
if possible_devices.count() < 1:
return {
'text': 'Devices with ip %s does not exist' % dev_ip
}
else:
device_down = possible_devices[0]
device_down = Device.objects.filter(ip_address=dev_ip).first()
if device_down is None:
return {'text': 'Devices with ip %s does not exist' % dev_ip}
if not device_down.is_noticeable: if not device_down.is_noticeable:
return {'text': 'Notification for %s is unnecessary' % device_down.ip_address} return {'text': 'Notification for %s is unnecessary' % device_down.ip_address}
recipients = device_down.user_group.profiles.all()
recipients = UserProfile.objects.get_profiles_by_group(device_down.group.pk)
names = list() names = list()
if dev_status == 'UP': if dev_status == 'UP':

37
dialing_app/migrations/0001_initial.py

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-05-30 13:33
# Generated by Django 1.11 on 2018-02-26 00:20
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -38,6 +38,41 @@ class Migration(migrations.Migration):
], ],
options={ options={
'db_table': 'cdr', 'db_table': 'cdr',
'ordering': ['-calldate'],
'managed': False,
},
),
migrations.CreateModel(
name='SMSModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('when', models.DateTimeField(auto_now_add=True)),
('who', models.CharField(max_length=32)),
('dev', models.CharField(max_length=20)),
('text', models.CharField(max_length=255)),
],
options={
'verbose_name': 'SMS',
'verbose_name_plural': 'SMS',
'db_table': 'sms',
'ordering': ['-when'],
'permissions': (('can_view_sms', 'Can view sms'),),
},
),
migrations.CreateModel(
name='SMSOut',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('when', models.DateTimeField(auto_now_add=True, verbose_name='When')),
('dst', models.CharField(max_length=16, verbose_name='Telephone')),
('text', models.CharField(max_length=255, verbose_name='Text')),
('status', models.CharField(choices=[('nw', 'New'), ('st', 'Sent'), ('fd', 'Failed')], default='nw', max_length=2, verbose_name='Status')),
],
options={
'verbose_name': 'Out SMS',
'verbose_name_plural': 'Out SMS',
'db_table': 'out_sms',
'permissions': (('can_view_sms', 'Can view sms'), ('can_send_sms', 'Can send sms')),
}, },
), ),
] ]

35
dialing_app/migrations/0002_auto_20171229_1353.py

@ -1,35 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-12-29 13:53
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dialing_app', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='SMSModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('when', models.DateTimeField(auto_now_add=True)),
('who', models.CharField(max_length=32)),
('dev', models.CharField(max_length=20)),
('text', models.CharField(max_length=255)),
],
options={
'verbose_name': 'SMS',
'verbose_name_plural': 'SMS',
'db_table': 'sms',
'permissions': (('can_view_sms', 'Can view sms'),),
},
),
migrations.AlterModelOptions(
name='asteriskcdr',
options={'managed': False},
),
]

31
dialing_app/migrations/0003_smsout.py

@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2018-01-04 18:16
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dialing_app', '0002_auto_20171229_1353'),
]
operations = [
migrations.CreateModel(
name='SMSOut',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('when', models.DateTimeField(auto_now_add=True, verbose_name='When')),
('dst', models.CharField(max_length=16, verbose_name='Telephone')),
('text', models.CharField(max_length=255, verbose_name='Text')),
('status', models.CharField(choices=[('nw', 'New'), ('st', 'Sent'), ('fd', 'Failed')], default='nw', max_length=2, verbose_name='Status')),
],
options={
'verbose_name': 'Out SMS',
'verbose_name_plural': 'Out SMS',
'db_table': 'out_sms',
'permissions': (('can_view_sms', 'Can view sms'), ('can_send_sms', 'Can send sms')),
},
),
]

10
dialing_app/views.py

@ -3,7 +3,8 @@ from subprocess import run
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib import messages from django.contrib import messages
from django.contrib.gis.shortcuts import render_to_text from django.contrib.gis.shortcuts import render_to_text
from django.shortcuts import render, redirect
from django.db import ProgrammingError
from django.shortcuts import redirect
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.generic import ListView from django.views.generic import ListView
@ -28,6 +29,13 @@ class LastCallsListView(BaseListView):
context_object_name = 'logs' context_object_name = 'logs'
queryset = AsteriskCDR.objects.exclude(userfield='request') queryset = AsteriskCDR.objects.exclude(userfield='request')
def get(self, request, *args, **kwargs):
try:
return super(LastCallsListView, self).get(request, *args, **kwargs)
except ProgrammingError as e:
messages.error(self.request, e)
return redirect('abonapp:group_list')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(LastCallsListView, self).get_context_data(**kwargs) context = super(LastCallsListView, self).get_context_data(**kwargs)
context['title'] = _('Last calls') context['title'] = _('Last calls')

33
djing/auth_backends.py

@ -0,0 +1,33 @@
from django.contrib.auth.backends import ModelBackend
from accounts_app.models import BaseAccount, UserProfile
from abonapp.models import Abon
class CustomAuthBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(BaseAccount.USERNAME_FIELD)
try:
user = BaseAccount._default_manager.get_by_natural_key(username)
if user.check_password(password):
if user.is_staff:
auser = UserProfile.objects.get_by_natural_key(username)
else:
auser = Abon.objects.get_by_natural_key(username)
if self.user_can_authenticate(auser):
return auser
except BaseAccount.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
BaseAccount().set_password(password)
def get_user(self, user_id):
try:
user = BaseAccount._default_manager.get(pk=user_id)
if user.is_staff:
user = UserProfile._default_manager.get(pk=user_id)
else:
user = Abon._default_manager.get(pk=user_id)
except BaseAccount.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None

10
djing/settings.py

@ -19,13 +19,14 @@ from django.urls import reverse_lazy
SECRET_KEY = local_settings.SECRET_KEY SECRET_KEY = local_settings.SECRET_KEY
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = local_settings.DEBUG or False
DEBUG = local_settings.DEBUG
ALLOWED_HOSTS = local_settings.ALLOWED_HOSTS ALLOWED_HOSTS = local_settings.ALLOWED_HOSTS
# required for django-guardian # required for django-guardian
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # default
'djing.auth_backends.CustomAuthBackend',
#'django.contrib.auth.backends.ModelBackend', # default
'guardian.backends.ObjectPermissionBackend' 'guardian.backends.ObjectPermissionBackend'
) )
@ -51,11 +52,11 @@ INSTALLED_APPS = [
'chatbot', 'chatbot',
'msg_app', 'msg_app',
'dialing_app', 'dialing_app',
'group_app',
'guardian', 'guardian',
'pinax_theme_bootstrap', 'pinax_theme_bootstrap',
'bootstrapform', 'bootstrapform',
'bootstrap3' 'bootstrap3'
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -78,12 +79,11 @@ TEMPLATES = [
'APP_DIRS': True, 'APP_DIRS': True,
'OPTIONS': { 'OPTIONS': {
'context_processors': [ 'context_processors': [
'django.template.context_processors.debug',
#'django.template.context_processors.debug',
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'taskapp.context_proc.get_active_tasks_count', 'taskapp.context_proc.get_active_tasks_count',
'global_context_processors.context_processor_additional_profile',
'msg_app.context_processors.get_new_messages_count' 'msg_app.context_processors.get_new_messages_count'
], ],
'libraries': { 'libraries': {

1
djing/urls.py

@ -17,6 +17,7 @@ urlpatterns = [
url(r'^client/', include('clientsideapp.urls', namespace='client_side')), url(r'^client/', include('clientsideapp.urls', namespace='client_side')),
url(r'^msg/', include('msg_app.urls', namespace='msg_app')), url(r'^msg/', include('msg_app.urls', namespace='msg_app')),
url(r'^dialing/', include('dialing_app.urls', namespace='dialapp')), url(r'^dialing/', include('dialing_app.urls', namespace='dialapp')),
url(r'^groups/', include('group_app.urls', namespace='group_app')),
url(r'^admin/', admin.site.urls) url(r'^admin/', admin.site.urls)
] ]

12
global_context_processors.py

@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
from django.shortcuts import get_object_or_404
from abonapp.models import Abon
from django.conf import settings
# От сюда можно получать на клиентской стороне профиль абонента
def context_processor_additional_profile(request):
if request.user.is_staff or request.user.is_anonymous():
return {'subscriber': request.user, 'FILE_UPLOAD_MAX_MEMORY_SIZE': settings.FILE_UPLOAD_MAX_MEMORY_SIZE}
else:
return {'subscriber': get_object_or_404(Abon, id=request.user.pk), 'FILE_UPLOAD_MAX_MEMORY_SIZE': settings.FILE_UPLOAD_MAX_MEMORY_SIZE}

0
group_app/__init__.py

4
group_app/admin.py

@ -0,0 +1,4 @@
from django.contrib import admin
from . import models
admin.site.register(models.Group)

5
group_app/apps.py

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

8
group_app/forms.py

@ -0,0 +1,8 @@
from django import forms
from . import models
class GroupForm(forms.ModelForm):
class Meta:
model = models.Group
fields = ['title']

69
group_app/locale/ru/LC_MESSAGES/django.po

@ -0,0 +1,69 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2018-02-26 01:47+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Dmitry Novikov <nerosketch@gmail.com>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n"
#: models.py:7
msgid "Title"
msgstr "Название"
#: models.py:16
msgid "Can view group"
msgstr "Может видеть группы"
#: models.py:18
msgid "Group"
msgstr "Группа"
#: models.py:19 templates/group_app/ext.html:7 templates/group_app/ext.html:8
#: templates/group_app/ext.html:14 templates/group_app/group_list.html:7
#: templates/group_app/group_list.html:10
msgid "Groups"
msgstr "Группы"
#: templates/group_app/add_group.html:9 templates/group_app/group_list.html:49
msgid "Add group"
msgstr "Добавить группу"
#: templates/group_app/add_group.html:16
msgid "Add"
msgstr "Добавить"
#: templates/group_app/edit_group.html:4 templates/group_app/edit_group.html:9
msgid "Edit group"
msgstr "Изменить группу"
#: templates/group_app/edit_group.html:16
msgid "Save"
msgstr "Сохранить"
#: templates/group_app/group_list.html:41
msgid "Groups was not found"
msgstr "Не найдено ни одной группы"
#: views.py:31
msgid "Group changes has been saved"
msgstr "Изменения сохранены"
#: views.py:35 views.py:51
msgid "Please fix form errors"
msgstr "Исправьте ошибки формы"
#: views.py:47
msgid "New group are created"
msgstr "Новая группа успешно создана"

30
group_app/migrations/0001_initial.py

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-02-26 00:20
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Group',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=127, unique=True, verbose_name='Title')),
],
options={
'verbose_name': 'Group',
'verbose_name_plural': 'Groups',
'db_table': 'groups',
'ordering': ['title'],
'permissions': (('can_view_group', 'Can view group'),),
},
),
]

0
group_app/migrations/__init__.py

23
group_app/models.py

@ -0,0 +1,23 @@
from django.utils.translation import gettext_lazy as _
from django.shortcuts import resolve_url
from django.db import models
class Group(models.Model):
title = models.CharField(_('Title'), max_length=127, unique=True)
def get_absolute_url(self):
url = resolve_url('group_app:edit', self.pk)
return url
class Meta:
db_table = 'groups'
permissions = (
('can_view_group', _('Can view group')),
)
verbose_name = _('Group')
verbose_name_plural = _('Groups')
ordering = ['title']
def __str__(self):
return self.title

20
group_app/templates/group_app/add_group.html

@ -0,0 +1,20 @@
{% extends request.is_ajax|yesno:'nullcont.htm,group_app/ext.html' %}
{% load i18n %}
{% load bootstrap3 %}
{% block active_text %}{% trans 'Add group' %}{% endblock %}
{% block content %}
<form action="{% url 'group_app:add' %}" method="post">{% csrf_token %}
<div class="modal-header success">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title"><span class="glyphicon glyphicon-info-sign"></span>{% trans 'Add group' %}</h4>
</div>
<div class="modal-body">
{% bootstrap_form form %}
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-success">
<span class="glyphicon glyphicon-plus"></span> {% trans 'Add' %}
</button>
</div>
</form>
{% endblock %}

20
group_app/templates/group_app/edit_group.html

@ -0,0 +1,20 @@
{% extends request.is_ajax|yesno:'nullcont.htm,group_app/ext.html' %}
{% load i18n %}
{% load bootstrap3 %}
{% block active_text %}{% trans 'Edit group' %}{% endblock %}
{% block content %}
<form action="{% url 'group_app:edit' object.pk %}" method="post">{% csrf_token %}
<div class="modal-header primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title"><span class="glyphicon glyphicon-info-sign"></span>{% trans 'Edit group' %}</h4>
</div>
<div class="modal-body">
{% bootstrap_form form %}
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">
<span class="glyphicon glyphicon-save"></span> {% trans 'Save' %}
</button>
</div>
</form>
{% endblock %}

23
group_app/templates/group_app/ext.html

@ -0,0 +1,23 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% load i18n %}
{% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'group_app:group_list' %}">{% trans 'Groups' %}</a></li>
<li class="active">{% block active_text %}{% trans 'Groups' %}{% endblock %}</li>
</ol>
{% include 'message_block.html' %}
<div class="page-header">
<h2>{% trans 'Groups' %}</h2>
</div>
<div class="panel panel-default">
<div class="panel-body">
{% block content %}{% endblock %}
</div>
</div>
{% endblock %}

59
group_app/templates/group_app/group_list.html

@ -0,0 +1,59 @@
{% extends 'base.html' %}
{% load i18n %}
{% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li class="active">{% trans 'Groups' %}</li>
</ol>
<h3>{% trans 'Groups' %}</h3>
{% include 'message_block.html' %}
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="50">#</th>
<th>
<a href="{% url 'group_app:group_list' %}?order_by=title&dir={{ dir|default:'down' }}">
{% trans 'Title' %}
</a>
{% if order_by == 'title' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th width="100">#</th>
</tr>
</thead>
<tbody>
{% for gr in groups %}
<tr>
<td>{{ gr.pk }}</td>
<td><a href="{% url 'group_app:edit' gr.pk %}" class="btn-modal">{{ gr.title }}</a></td>
<td class="btn-group">
<a href="{% url 'group_app:edit' gr.pk %}" class="btn btn-sm btn-default btn-modal">
<span class="glyphicon glyphicon-cog"></span>
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="3"><a href="#">{% trans 'Groups was not found' %}</a></td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="btn-group btn-group-sm">
<a href="{% url 'group_app:add' %}" class="btn btn-success btn-modal">
<span class="glyphicon glyphicon-plus"></span> <span class="hidden-xs">{% trans 'Add group' %}</span>
</a>
</td>
</tr>
</tfoot>
</table>
</div>
{% include 'pagination.html' %}
{% endblock %}

3
group_app/tests.py

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

10
group_app/urls.py

@ -0,0 +1,10 @@
from django.conf.urls import url
from . import views
app_name = 'group_app'
urlpatterns = [
url(r'^$', views.GroupListView.as_view(), name='group_list'),
url(r'^add/$', views.AddGroupView.as_view(), name='add'),
url(r'^(?P<group_id>\d{1,6})/edit/$', views.EditGroupView.as_view(), name='edit')
]

52
group_app/views.py

@ -0,0 +1,52 @@
from django.views.generic import ListView, UpdateView, CreateView
from django.contrib.auth.decorators import login_required
from django.utils.translation import gettext_lazy as _
from django.utils.decorators import method_decorator
from django.urls import reverse_lazy
from django.contrib import messages
from django.conf import settings
from . import models
from . import forms
@method_decorator(login_required, name='dispatch')
class GroupListView(ListView):
http_method_names = ['get']
paginate_by = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
template_name = 'group_app/group_list.html'
model = models.Group
context_object_name = 'groups'
@method_decorator(login_required, name='dispatch')
class EditGroupView(UpdateView):
http_method_names = ['get', 'post']
template_name = 'group_app/edit_group.html'
form_class = forms.GroupForm
model = models.Group
pk_url_kwarg = 'group_id'
success_url = reverse_lazy('group_app:group_list')
def form_valid(self, form):
messages.success(self.request, _('Group changes has been saved'))
return super(EditGroupView, self).form_valid(form)
def form_invalid(self, form):
messages.success(self.request, _('Please fix form errors'))
return super(EditGroupView, self).form_invalid(form)
@method_decorator(login_required, name='dispatch')
class AddGroupView(CreateView):
http_method_names = ['get', 'post']
template_name = 'group_app/add_group.html'
form_class = forms.GroupForm
success_url = reverse_lazy('group_app:group_list')
def form_valid(self, form):
messages.success(self.request, _('New group are created'))
return super(AddGroupView, self).form_valid(form)
def form_invalid(self, form):
messages.success(self.request, _('Please fix form errors'))
return super(AddGroupView, self).form_invalid(form)

66
locale/ru/LC_MESSAGES/django.po

@ -7,10 +7,9 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-01-26 19:22+0300\n"
"POT-Creation-Date: 2018-02-26 02:06+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Dmitry Novikov nerosketch@gmail.com\n" "Last-Translator: Dmitry Novikov nerosketch@gmail.com\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: ru\n" "Language: ru\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
@ -19,37 +18,13 @@ msgstr ""
"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" "%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
"%100>=11 && n%100<=14)? 2 : 3);\n" "%100>=11 && n%100<=14)? 2 : 3);\n"
#: agent/commands/dhcp.py:19
msgid "User settings is not dynamic"
msgstr ""
#: agent/commands/dhcp.py:29
#, python-format
msgid "User with device '%s' does not exist"
msgstr ""
#: agent/commands/dhcp.py:31
#, python-format
msgid "Device with mac %s not found"
msgstr ""
#: agent/commands/dhcp.py:33
#, python-format
msgid "Port %d on device with mac %s does not exist"
msgstr ""
#: cron.py:30
#, python-format
msgid "Service '%(service_name)s' has expired"
msgstr "Срок действия услуги '%(service_name)s' истёк"
#: djing/formfields.py:13 #: djing/formfields.py:13
msgid "Enter a valid integer." msgid "Enter a valid integer."
msgstr ""
msgstr "Введите число"
#: djing/formfields.py:22 #: djing/formfields.py:22
msgid "Enter a valid MAC Address." msgid "Enter a valid MAC Address."
msgstr ""
msgstr "Введите мак адрес"
#: templates/403.html:5 #: templates/403.html:5
msgid "Permission denied" msgid "Permission denied"
@ -67,3 +42,38 @@ msgstr "У вас нет прав просматривать эту страни
#: templates/403_for_modal.html:11 #: templates/403_for_modal.html:11
msgid "Close" msgid "Close"
msgstr "Закрыть" msgstr "Закрыть"
#: templates/base.html:28
msgid "Administrators"
msgstr "Сотрудники"
#: templates/base.html:35
msgid "Subscribers"
msgstr "Абоненты"
#: templates/base.html:41
msgid "Tasks"
msgstr "Задачи"
#: templates/base.html:48
msgid "Groups"
msgstr "Группы"
#: templates/base.html:54
msgid "Services"
msgstr "Тарифы"
#: templates/base.html:61
msgid "Map settings"
msgstr "Настройки карты"
#: templates/base.html:68
msgid "Messages"
msgstr "Сообщения"
#: templates/base.html:85
msgid "Devices"
msgstr "Устрофства"
#~ msgid "Service '%(service_name)s' has expired"
#~ msgstr "Срок действия услуги '%(service_name)s' истёк"

16
mapapp/migrations/0001_initial.py

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-01-25 16:02
# Generated by Django 1.11 on 2018-02-26 00:20
from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -8,6 +10,7 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('devapp', '0001_initial'),
] ]
operations = [ operations = [
@ -15,12 +18,17 @@ class Migration(migrations.Migration):
name='Dot', name='Dot',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=127)),
('latitude', models.FloatField()),
('longitude', models.FloatField()),
('title', models.CharField(max_length=127, verbose_name='Map point title')),
('latitude', models.FloatField(verbose_name='Latitude')),
('longitude', models.FloatField(verbose_name='Longitude')),
('attachment', models.FileField(blank=True, null=True, upload_to='map_attachments/%Y_%m_%d', verbose_name='Attachment')),
('devices', models.ManyToManyField(db_table='dot_device', to='devapp.Device', verbose_name='Devices')),
], ],
options={ options={
'verbose_name': 'Map point',
'verbose_name_plural': 'Map points',
'db_table': 'dots', 'db_table': 'dots',
'permissions': (('can_view', 'Can view'),),
}, },
), ),
] ]

45
mapapp/migrations/0002_auto_20171103_0006.py

@ -1,45 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2017-11-03 00:06
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('devapp', '0004_auto_20171103_0006'),
('mapapp', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='dot',
options={'permissions': (('can_view', 'Can view'),), 'verbose_name': 'Map dot', 'verbose_name_plural': 'Map dots'},
),
migrations.AddField(
model_name='dot',
name='attachment',
field=models.FileField(blank=True, null=True, upload_to='map_attachments/%Y_%m_%d', verbose_name='Attachment'),
),
migrations.AddField(
model_name='dot',
name='devices',
field=models.ManyToManyField(db_table='dot_device', to='devapp.Device', verbose_name='Devices'),
),
migrations.AlterField(
model_name='dot',
name='latitude',
field=models.FloatField(verbose_name='Latitude'),
),
migrations.AlterField(
model_name='dot',
name='longitude',
field=models.FloatField(verbose_name='Longitude'),
),
migrations.AlterField(
model_name='dot',
name='title',
field=models.CharField(max_length=127, verbose_name='Map point title'),
),
]

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save