Browse Source

continue...

devel
Dmitry 9 years ago
parent
commit
8e542b00a4
  1. 5
      .gitignore
  2. 2
      abonapp/forms.py
  3. 20
      abonapp/migrations/0001_initial.py
  4. 80
      abonapp/models.py
  5. 2
      abonapp/tests.py
  6. 3
      abonapp/urls_abon.py
  7. 10
      abonapp/views.py
  8. 21
      accounts_app/migrations/0001_initial.py
  9. 7
      accounts_app/models.py
  10. 22
      accounts_app/views.py
  11. 1
      agent.py
  12. 5
      agent/firewall.py
  13. 9
      agent/main.py
  14. 1
      agent/models.py
  15. 4
      agent/netflow/to_mysql.py
  16. 2
      agent/settings.py
  17. 21
      agent/sslTransmitter.py
  18. 4
      clientsideapp/views.py
  19. 2
      cron.py
  20. 1
      devapp/base_intr.py
  21. 1
      devapp/dev_types.py
  22. 8
      devapp/migrations/0001_initial.py
  23. 3
      devapp/models.py
  24. 9
      djing/settings_example.py
  25. 3
      djing/urls.py
  26. 1
      global_context_processors.py
  27. 0
      gmap/__init__.py
  28. 43
      gmap/admin.py
  29. 2
      gmap/apps.py
  30. 20
      gmap/forms.py
  31. 0
      gmap/migrations/__init__.py
  32. 369
      gmap/models.py
  33. 0
      gmap/tests.py
  34. 16
      gmap/urls.py
  35. 143
      gmap/utils.py
  36. 250
      gmap/views.py
  37. 31
      install.sql
  38. 1
      ip_pool/migrations/0001_initial.py
  39. 5
      ip_pool/models.py
  40. 4
      ip_pool/views.py
  41. 6
      mapapp/admin.py
  42. 25
      mapapp/migrations/0001_initial.py
  43. 10
      mapapp/models.py
  44. 9
      mapapp/urls.py
  45. 22
      mapapp/views.py
  46. 6
      mydefs.py
  47. 1
      photo_app/migrations/0001_initial.py
  48. 6
      photo_app/models.py
  49. 2
      photo_app/urls.py
  50. 7
      privatemessage/migrations/0001_initial.py
  51. 1
      privatemessage/models.py
  52. 1
      privatemessage/tests.py
  53. 6
      privatemessage/views.py
  54. 16
      static/bad_ie.html
  55. 4
      static/clientside/custom.css
  56. 416
      static/css/bootstrap-datetimepicker.min.css
  57. 470
      static/css/bootstrap-theme.min.css
  58. 7022
      static/css/bootstrap.min.css
  59. 106
      static/css/custom.css
  60. 50
      static/css/custom_login.css
  61. 4
      static/css/gmap.css
  62. 694
      static/js/bootstrap-datetimepicker.min.js
  63. 703
      static/js/bootstrap.min.js
  64. 91
      static/js/gmap.js
  65. 2116
      static/js/jquery-2.2.4.min.js
  66. 3414
      static/js/moment-with-locales.min.js
  67. 84
      static/js/my.js
  68. 1
      statistics/migrations/0001_initial.py
  69. 2
      tariff_app/base_intr.py
  70. 6
      tariff_app/custom_tariffs.py
  71. 7
      tariff_app/migrations/0001_initial.py
  72. 1
      tariff_app/models.py
  73. 55
      taskapp/forms.py
  74. 13
      taskapp/models.py
  75. 43
      taskapp/views.py
  76. 16
      templates/abonapp/abonamount.html
  77. 52
      templates/abonapp/activate_service.html
  78. 128
      templates/abonapp/addAbon.html
  79. 76
      templates/abonapp/addGroup.html
  80. 79
      templates/abonapp/addInvoice.html
  81. 74
      templates/abonapp/buy_tariff.html
  82. 89
      templates/abonapp/complete_service.html
  83. 64
      templates/abonapp/debtors.html
  84. 14
      templates/abonapp/editAbon.html
  85. 38
      templates/abonapp/ext.htm
  86. 116
      templates/abonapp/group_list.html
  87. 94
      templates/abonapp/invoiceForPayment.html
  88. 56
      templates/abonapp/log.html
  89. 51
      templates/abonapp/payHistory.html
  90. 116
      templates/abonapp/peoples.html
  91. 127
      templates/abonapp/services.html
  92. 119
      templates/accounts/acc_list.html
  93. 166
      templates/accounts/create_acc.html
  94. 24
      templates/accounts/ext.htm
  95. 77
      templates/accounts/group.html
  96. 76
      templates/accounts/group_list.html
  97. 16
      templates/accounts/index.html
  98. 110
      templates/accounts/login.html
  99. 9
      templates/accounts/profile_chgroup.html
  100. 27
      templates/accounts/settings/ch_info.html

5
.gitignore

@ -3,7 +3,8 @@
*/*/*.txt */*/*.txt
media/* media/*
media/min/* media/min/*
~*/migrations/000*.py
~*/migrations/00*.py
.idea/ .idea/
djing/settings.py djing/settings.py
*/migrations/000*.py
*/migrations/00*.py
gmap/fixtures

2
abonapp/forms.py

@ -48,7 +48,7 @@ class AbonForm(forms.Form):
address = forms.CharField( address = forms.CharField(
max_length=256, max_length=256,
required=False, required=False,
widget = forms.TextInput(attrs={'class': 'form-control', 'id': 'address'})
widget=forms.TextInput(attrs={'class': 'form-control', 'id': 'address'})
) )

20
abonapp/migrations/0001_initial.py

@ -9,7 +9,6 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@ -23,7 +22,9 @@ 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)),
('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])), ('ballance', models.FloatField(default=0.0, validators=[django.core.validators.DecimalValidator])),
('address', models.CharField(max_length=256)), ('address', models.CharField(max_length=256)),
], ],
@ -51,7 +52,8 @@ class Migration(migrations.Migration):
('comment', models.CharField(max_length=128)), ('comment', models.CharField(max_length=128)),
('date', models.DateTimeField(auto_now_add=True)), ('date', models.DateTimeField(auto_now_add=True)),
('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), ('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)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+',
to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'db_table': 'abonent_log', 'db_table': 'abonent_log',
@ -64,7 +66,8 @@ class Migration(migrations.Migration):
('tariff_priority', models.PositiveSmallIntegerField(default=0)), ('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')), ('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')),
('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',), 'ordering': ('tariff_priority',),
@ -81,7 +84,8 @@ class Migration(migrations.Migration):
('date_create', models.DateTimeField(auto_now_add=True)), ('date_create', models.DateTimeField(auto_now_add=True)),
('date_pay', models.DateTimeField(blank=True, null=True)), ('date_pay', models.DateTimeField(blank=True, null=True)),
('abon', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='abonapp.Abon')), ('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)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+',
to=settings.AUTH_USER_MODEL)),
], ],
options={ options={
'ordering': ('date_create',), 'ordering': ('date_create',),
@ -96,12 +100,14 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='abon', model_name='abon',
name='group', name='group',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='abonapp.AbonGroup'),
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
to='abonapp.AbonGroup'),
), ),
migrations.AddField( migrations.AddField(
model_name='abon', model_name='abon',
name='ip_address', name='ip_address',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ip_pool.IpPoolItem'),
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
to='ip_pool.IpPoolItem'),
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='abontariff', name='abontariff',

80
abonapp/models.py

@ -8,14 +8,13 @@ from django.db import models
from django.conf import settings from django.conf import settings
from django.core.validators import DecimalValidator from django.core.validators import DecimalValidator
from agent import get_TransmitterClientKlass
from agent import get_TransmitterClientKlass, NetExcept
from ip_pool.models import IpPoolItem from ip_pool.models import IpPoolItem
from tariff_app.models import Tariff from tariff_app.models import Tariff
from accounts_app.models import UserProfile from accounts_app.models import UserProfile
class LogicError(Exception): class LogicError(Exception):
def __init__(self, value, err_id=None): def __init__(self, value, err_id=None):
self.value = value self.value = value
if err_id: if err_id:
@ -54,7 +53,6 @@ class AbonLog(models.Model):
class AbonTariffManager(models.Manager): class AbonTariffManager(models.Manager):
@staticmethod @staticmethod
def update_priorities(abonent): def update_priorities(abonent):
abon_tariff_list = AbonTariff.objects.filter(abon=abonent).order_by('tariff_priority') abon_tariff_list = AbonTariff.objects.filter(abon=abonent).order_by('tariff_priority')
@ -209,20 +207,20 @@ class Abon(UserProfile):
# Платим за что-то # Платим за что-то
def make_pay(self, curuser, how_match_to_pay=0.0, u_comment=u'Снятие со счёта средств'): def make_pay(self, curuser, how_match_to_pay=0.0, u_comment=u'Снятие со счёта средств'):
AbonLog.objects.create( AbonLog.objects.create(
abon = self,
amount = -how_match_to_pay,
author = curuser,
comment = u_comment
abon=self,
amount=-how_match_to_pay,
author=curuser,
comment=u_comment
) )
self.ballance -= how_match_to_pay self.ballance -= how_match_to_pay
# Пополняем счёт # Пополняем счёт
def add_ballance(self, current_user, amount): def add_ballance(self, current_user, amount):
AbonLog.objects.create( AbonLog.objects.create(
abon = self,
amount = amount,
author = current_user,
comment = u'Пополнение счёта через админку'
abon=self,
amount=amount,
author=current_user,
comment=u'Пополнение счёта через админку'
) )
self.ballance += amount self.ballance += amount
@ -238,7 +236,7 @@ class Abon(UserProfile):
new_abtar = AbonTariff( new_abtar = AbonTariff(
abon=self, abon=self,
tariff=tariff, tariff=tariff,
tariff_priority=abtrf.tariff_priority+1 if abtrf else -1
tariff_priority=abtrf.tariff_priority + 1 if abtrf else -1
) )
# Если это первая услуга в списке (фильтр по приоритету ничего не вернул) # Если это первая услуга в списке (фильтр по приоритету ничего не вернул)
@ -250,9 +248,9 @@ class Abon(UserProfile):
# Запись об этом в лог # Запись об этом в лог
AbonLog.objects.create( AbonLog.objects.create(
abon = self, amount = -tariff.amount,
author = author,
comment = u'Покупка тарифного плана через админку, тариф "%s"' % tariff.title
abon=self, amount=-tariff.amount,
author=author,
comment=u'Покупка тарифного плана через админку, тариф "%s"' % tariff.title
) )
# Пробует подключить новую услугу если пришло время # Пробует подключить новую услугу если пришло время
@ -276,7 +274,7 @@ class Abon(UserProfile):
print u'Заказ из прошлого месяца, срок действия закончен' print u'Заказ из прошлого месяца, срок действия закончен'
# выберем следующую по приоритету # выберем следующую по приоритету
#next_tarifs = AbonTariff.objects.filter(tariff_priority__gt = self.tariff_priority, abon=self.abon)
# next_tarifs = AbonTariff.objects.filter(tariff_priority__gt = self.tariff_priority, abon=self.abon)
next_tarifs = filter(lambda tr: tr.tariff_priority > at.tariff_priority, ats)[:2] next_tarifs = filter(lambda tr: tr.tariff_priority > at.tariff_priority, ats)[:2]
# и если что-нибудь вернулось то активируем, давая время начала действия # и если что-нибудь вернулось то активируем, давая время начала действия
@ -289,10 +287,10 @@ class Abon(UserProfile):
# Создаём лог о завершении услуги # Создаём лог о завершении услуги
AbonLog.objects.create( AbonLog.objects.create(
abon = self,
amount = 0,
author = author,
comment = u'Завершение услуги по истечению срока действия'
abon=self,
amount=0,
author=author,
comment=u'Завершение услуги по истечению срока действия'
) )
# есть-ли доступ у абонента к услуге, смотрим в tariff_app.custom_tariffs.<TariffBase>.manage_access() # есть-ли доступ у абонента к услуге, смотрим в tariff_app.custom_tariffs.<TariffBase>.manage_access()
@ -306,7 +304,6 @@ class Abon(UserProfile):
return False return False
class InvoiceForPayment(models.Model): class InvoiceForPayment(models.Model):
abon = models.ForeignKey(Abon) abon = models.ForeignKey(Abon)
status = models.BooleanField(default=False) status = models.BooleanField(default=False)
@ -332,22 +329,22 @@ class InvoiceForPayment(models.Model):
def abon_post_save(sender, instance, **kwargs): def abon_post_save(sender, instance, **kwargs):
if kwargs['created']:
print 'abon_post_save CREATED'
else:
print 'abon_post_save CHANGED'
try:
tc = get_TransmitterClientKlass()() tc = get_TransmitterClientKlass()()
# обновляем абонента на NAS # обновляем абонента на NAS
tc.signal_abon_refresh(instance) tc.signal_abon_refresh(instance)
except NetExcept:
pass
def abon_del_signal(sender, instance, **kwargs): def abon_del_signal(sender, instance, **kwargs):
print 'abon_del_signal'
# подключаемся к NAS'у
tc = get_TransmitterClientKlass()()
# удаляем абонента на NAS
tc.signal_abon_remove(instance)
try:
# подключаемся к NAS'у
tc = get_TransmitterClientKlass()()
# удаляем абонента на NAS
tc.signal_abon_remove(instance)
except NetExcept:
pass
'''def tarif_pre_save(sender, instance, **kwargs): '''def tarif_pre_save(sender, instance, **kwargs):
@ -359,19 +356,20 @@ def abon_del_signal(sender, instance, **kwargs):
def abontariff_post_save(sender, instance, **kwargs): def abontariff_post_save(sender, instance, **kwargs):
if kwargs['created']:
print('abontariff CREATED', kwargs)
else:
print('abontariff CHANGED', kwargs)
# Тут или подключение абону услуги, или изменение приоритета
tc = get_TransmitterClientKlass()()
tc.signal_abon_refresh(instance.abon)
try:
# Тут или подключение абону услуги, или изменение приоритета
tc = get_TransmitterClientKlass()()
tc.signal_abon_refresh(instance.abon)
except NetExcept:
pass
def abontariff_del_signal(sender, instance, **kwargs): def abontariff_del_signal(sender, instance, **kwargs):
print('abontariff_del_signal', instance.abon)
tc = get_TransmitterClientKlass()()
tc.signal_abon_refresh(instance.abon)
try:
tc = get_TransmitterClientKlass()()
tc.signal_abon_refresh(instance.abon)
except NetExcept:
pass
models.signals.post_save.connect(abon_post_save, sender=Abon) models.signals.post_save.connect(abon_post_save, sender=Abon)

2
abonapp/tests.py

@ -7,7 +7,6 @@ from tariff_app.models import Tariff
class AbonTariffTestCase(TestCase): class AbonTariffTestCase(TestCase):
def setUp(self): def setUp(self):
abon1 = Abon.objects.create( abon1 = Abon.objects.create(
telephone='+79784653751', telephone='+79784653751',
@ -44,7 +43,6 @@ class AbonTariffTestCase(TestCase):
# берём купленные услуги # берём купленные услуги
ats = AbonTariff.objects.filter(abon=abn) ats = AbonTariff.objects.filter(abon=abn)
for at in ats: for at in ats:
# и пробуем назначить # и пробуем назначить
at.activate_next_tariff() at.activate_next_tariff()

3
abonapp/urls_abon.py

@ -20,5 +20,6 @@ urlpatterns = [
url(r'^(?P<uid>\d+)/complete_service(?P<srvid>\d+)$', views.complete_service, name='abonapp_compl_srv'), url(r'^(?P<uid>\d+)/complete_service(?P<srvid>\d+)$', views.complete_service, name='abonapp_compl_srv'),
url(r'^(?P<uid>\d+)/activate_service(?P<srvid>\d+)$', views.activate_service, name='abonapp_activate_service'), url(r'^(?P<uid>\d+)/activate_service(?P<srvid>\d+)$', views.activate_service, name='abonapp_activate_service'),
url(r'^(?P<uid>\d+)/unsubscribe_service(?P<srvid>\d+)$', views.unsubscribe_service, name='abonapp_unsubscribe_service')
url(r'^(?P<uid>\d+)/unsubscribe_service(?P<srvid>\d+)$', views.unsubscribe_service,
name='abonapp_unsubscribe_service')
] ]

10
abonapp/views.py

@ -8,8 +8,8 @@ from django.contrib.auth.decorators import login_required
from django.utils import timezone from django.utils import timezone
from django.template.context_processors import csrf from django.template.context_processors import csrf
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from ip_pool.models import IpPoolItem from ip_pool.models import IpPoolItem
from tariff_app.models import Tariff from tariff_app.models import Tariff
from agent import NetExcept from agent import NetExcept
@ -239,7 +239,7 @@ def abonhome(request, gid, uid):
abon.is_active = 1 if cd['is_active'] else 0 abon.is_active = 1 if cd['is_active'] else 0
abon.save() abon.save()
#return redirect('abonhome_link', gid, uid)
# return redirect('abonhome_link', gid, uid)
else: else:
warntext = u'Не правильные значения, проверте поля и попробуйте ещё' warntext = u'Не правильные значения, проверте поля и попробуйте ещё'
else: else:
@ -332,8 +332,8 @@ def buy_tariff(request, gid, uid):
warntext = e.value warntext = e.value
except NetExcept as e: except NetExcept as e:
warntext = e.value+u', но услуга уже подключена, она будет применена когда будет восстановлен доступ к NAS серверу.'\
u' <a href="%s">Вернуться</a>' % resolve_url('abonhome_link', gid=gid, uid=abon.id)
warntext = e.value + u', но услуга уже подключена, она будет применена когда будет восстановлен доступ к NAS серверу.' \
u' <a href="%s">Вернуться</a>' % resolve_url('abonhome_link', gid=gid, uid=abon.id)
return render(request, 'abonapp/buy_tariff.html', { return render(request, 'abonapp/buy_tariff.html', {
'warntext': warntext, 'warntext': warntext,
@ -449,7 +449,7 @@ def log_page(request):
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
def debtors(request): def debtors(request):
#peoples_list = models.Abon.objects.filter(invoiceforpayment__status=True)
# peoples_list = models.Abon.objects.filter(invoiceforpayment__status=True)
#peoples_list = mydefs.pag_mn(request, peoples_list) #peoples_list = mydefs.pag_mn(request, peoples_list)
invs = models.InvoiceForPayment.objects.filter(status=True) invs = models.InvoiceForPayment.objects.filter(status=True)

21
accounts_app/migrations/0001_initial.py

@ -8,7 +8,6 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@ -23,17 +22,27 @@ class Migration(migrations.Migration):
('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')),
('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)), ('username', models.CharField(max_length=127, unique=True)),
('fio', models.CharField(max_length=256)), ('fio', models.CharField(max_length=256)),
('birth_day', models.DateField(auto_now_add=True)), ('birth_day', models.DateField(auto_now_add=True)),
('is_active', models.BooleanField(default=True)), ('is_active', models.BooleanField(default=True)),
('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(b'^\\+[7,8,9,3]\\d{10,11}$')], verbose_name=b'Telephone number')),
('telephone', models.CharField(max_length=16, unique=True, validators=[
django.core.validators.RegexValidator(b'^\\+[7,8,9,3]\\d{10,11}$')],
verbose_name=b'Telephone number')),
('skype', models.CharField(blank=True, max_length=20)), ('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')),
('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')),
], ],
options={ options={
'abstract': False, 'abstract': False,

7
accounts_app/models.py

@ -8,7 +8,6 @@ from photo_app.models import Photo
class MyUserManager(BaseUserManager): class MyUserManager(BaseUserManager):
def create_user(self, telephone, username, password=None): def create_user(self, telephone, username, password=None):
""" """
Creates and saves a User with the given email, date of Creates and saves a User with the given email, date of
@ -32,8 +31,8 @@ class MyUserManager(BaseUserManager):
birth and password. birth and password.
""" """
user = self.create_user(telephone, user = self.create_user(telephone,
password=password,
username=username
password=password,
username=username
) )
user.is_admin = True user.is_admin = True
user.is_superuser = True user.is_superuser = True
@ -95,7 +94,7 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
return self.username return self.username
#from django.db.models.signals import post_save
# from django.db.models.signals import post_save
'''def create_custom_user(sender, instance, created, **kwargs): '''def create_custom_user(sender, instance, created, **kwargs):

22
accounts_app/views.py

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.contrib.auth.decorators import login_required#, permission_required
from django.contrib.auth.decorators import login_required # , permission_required
from django.contrib.auth import authenticate, login, logout from django.contrib.auth import authenticate, login, logout
from django.core.urlresolvers import NoReverseMatch from django.core.urlresolvers import NoReverseMatch
from django.shortcuts import render, redirect, get_object_or_404, resolve_url from django.shortcuts import render, redirect, get_object_or_404, resolve_url
@ -82,7 +82,7 @@ def chgroup(request, uid):
usr = get_object_or_404(UserProfile, id=uid) usr = get_object_or_404(UserProfile, id=uid)
usergroups = usr.groups.all() usergroups = usr.groups.all()
othergroups = filter(lambda g: g not in usergroups, Group.objects.all()) othergroups = filter(lambda g: g not in usergroups, Group.objects.all())
#Group.objects.exclude(user__in=usergroups)
# Group.objects.exclude(user__in=usergroups)
return render(request, 'accounts/profile_chgroup.html', { return render(request, 'accounts/profile_chgroup.html', {
'uid': uid, 'uid': uid,
@ -114,7 +114,7 @@ def ch_ava(request):
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
def ch_info(request): def ch_info(request):
warntext=''
warntext = ''
if request.method == 'POST': if request.method == 'POST':
user = request.user user = request.user
user.username = request.POST.get('username') user.username = request.POST.get('username')
@ -157,13 +157,13 @@ def create_profile(request):
passwd = request.POST.get('passwd') passwd = request.POST.get('passwd')
conpasswd = request.POST.get('conpasswd') conpasswd = request.POST.get('conpasswd')
if not passwd: if not passwd:
return render(request, 'accounts/create_acc.html',{
return render(request, 'accounts/create_acc.html', {
'warntext': u'Забыли указать пароль для нового аккаунта', 'warntext': u'Забыли указать пароль для нового аккаунта',
'csrf_token': csrf(request)['csrf_token'], 'csrf_token': csrf(request)['csrf_token'],
'newuser': user 'newuser': user
}) })
if not conpasswd: if not conpasswd:
return render(request, 'accounts/create_acc.html',{
return render(request, 'accounts/create_acc.html', {
'warntext': u'Забыли повторить пароль для нового аккаунта', 'warntext': u'Забыли повторить пароль для нового аккаунта',
'csrf_token': csrf(request)['csrf_token'], 'csrf_token': csrf(request)['csrf_token'],
'newuser': user 'newuser': user
@ -176,23 +176,23 @@ def create_profile(request):
user.save() user.save()
return redirect('accounts_list') return redirect('accounts_list')
else: else:
return render(request, 'accounts/create_acc.html',{
return render(request, 'accounts/create_acc.html', {
'warntext': u'Пользователь с таким именем уже есть', 'warntext': u'Пользователь с таким именем уже есть',
'csrf_token': csrf(request)['csrf_token'], 'csrf_token': csrf(request)['csrf_token'],
'newuser': user 'newuser': user
}) })
else: else:
return render(request, 'accounts/create_acc.html',{
return render(request, 'accounts/create_acc.html', {
'warntext': u'Пароли не совпадают, попробуйте ещё раз', 'warntext': u'Пароли не совпадают, попробуйте ещё раз',
'csrf_token': csrf(request)['csrf_token'], 'csrf_token': csrf(request)['csrf_token'],
'newuser': user 'newuser': user
}) })
return render(request, 'accounts/create_acc.html', {'csrf_token': csrf(request)['csrf_token'],})
return render(request, 'accounts/create_acc.html', {'csrf_token': csrf(request)['csrf_token'], })
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
#@permission_required('accounts_app.del_userprofile')
# @permission_required('accounts_app.del_userprofile')
def delete_profile(request, uid): def delete_profile(request, uid):
prf = get_object_or_404(UserProfile, id=uid) prf = get_object_or_404(UserProfile, id=uid)
prf.delete() prf.delete()
@ -213,7 +213,7 @@ def acc_list(request):
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
#@permission_required('accounts_app.change_userprofile')
# @permission_required('accounts_app.change_userprofile')
def perms(request, id): def perms(request, id):
ingroups = filter(lambda x: x[0] == 'ingroups', request.POST.lists())[0][1] ingroups = filter(lambda x: x[0] == 'ingroups', request.POST.lists())[0][1]
id = mydefs.safe_int(id) id = mydefs.safe_int(id)
@ -243,7 +243,7 @@ def groups(request):
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
#@permission_required('auth.change_group')
# @permission_required('auth.change_group')
def group(request, id): def group(request, id):
id = mydefs.safe_int(id) id = mydefs.safe_int(id)
grp = get_object_or_404(Group, id=id) grp = get_object_or_404(Group, id=id)

1
agent.py

@ -1,6 +1,7 @@
#!/bin/env python2 #!/bin/env python2
import os import os
from agent import main from agent import main

5
agent/firewall.py

@ -3,13 +3,12 @@ from agent.models import Abonent, Tariff
class FirewallManager(object): class FirewallManager(object):
f = r'/sbin/ipfw -q' f = r'/sbin/ipfw -q'
# вызывает комманду shell # вызывает комманду shell
def exec_cmd(self, cmd): def exec_cmd(self, cmd):
print cmd print cmd
#os.execv(cmd, [''])
# os.execv(cmd, [''])
# ставит заглушку на абонента # ставит заглушку на абонента
def set_cap(self, user): def set_cap(self, user):
@ -23,7 +22,7 @@ class FirewallManager(object):
return return
cmd = r"%s table 12 add %s/32 %d && %s table 13 add %s/32 %d" % ( cmd = r"%s table 12 add %s/32 %d && %s table 13 add %s/32 %d" % (
self.f, user.ip_str(), user.tariff.tid, self.f, user.ip_str(), user.tariff.tid,
self.f, user.ip_str(), user.tariff.tid+1000
self.f, user.ip_str(), user.tariff.tid + 1000
) )
self.exec_cmd(cmd) self.exec_cmd(cmd)

9
agent/main.py

@ -9,14 +9,14 @@ from agent.models import Abonent, Tariff
def filter_user_by_id(users, uid): def filter_user_by_id(users, uid):
#users = filter(lambda usr: isinstance(usr, Abonent), users)
# users = filter(lambda usr: isinstance(usr, Abonent), users)
users = filter(lambda usr: usr.uid == uid, users) users = filter(lambda usr: usr.uid == uid, users)
if len(users) > 0: if len(users) > 0:
return users[0] return users[0]
def filter_tariff_by_id(tariffs, tid): def filter_tariff_by_id(tariffs, tid):
#tariffs = filter(lambda trf: isinstance(trf, Tariff), tariffs)
# tariffs = filter(lambda trf: isinstance(trf, Tariff), tariffs)
tariffs = filter(lambda trf: trf.tid == tid, tariffs) tariffs = filter(lambda trf: trf.tid == tid, tariffs)
if len(tariffs) > 0: if len(tariffs) > 0:
return tariffs[0] return tariffs[0]
@ -63,11 +63,12 @@ def main(debug=False):
events = ts.get_data() events = ts.get_data()
# Проходим по появившимся событиям # Проходим по появившимся событиям
for event in events: for event in events:
#event.toa, event.id, event.dt
# event.toa, event.id, event.dt
# Смотрим тип события # Смотрим тип события
toa = int(event.toa) toa = int(event.toa)
if toa == 0: continue
if toa == 0:
continue
# создаём абонента # создаём абонента
elif toa == 1: elif toa == 1:

1
agent/models.py

@ -128,7 +128,6 @@ class Abonent(Serializer):
class EventNAS(Serializer): class EventNAS(Serializer):
# Type Of Action # Type Of Action
toa = 0 toa = 0

4
agent/netflow/to_mysql.py

@ -30,7 +30,7 @@ def convert(query):
return sql return sql
if __name__=='__main__':
if __name__ == '__main__':
f = sys.stdin f = sys.stdin
table_name = "flowstat_%s" % datetime.now().strftime("%d%m%Y") table_name = "flowstat_%s" % datetime.now().strftime("%d%m%Y")
print("CREATE TABLE IF NOT EXISTS %s (" % table_name) print("CREATE TABLE IF NOT EXISTS %s (" % table_name)
@ -50,7 +50,7 @@ if __name__=='__main__':
f.readline() f.readline()
while True: while True:
n=0xfff
n = 0xfff
rs = convert(f.readline()) rs = convert(f.readline())
if not rs: exit() if not rs: exit()
# without first comma # without first comma

2
agent/settings.py

@ -7,7 +7,7 @@ SELF_PORT = 2134
# Main server ip and port # Main server ip and port
SERVER_IP = '127.0.0.1' SERVER_IP = '127.0.0.1'
SERVER_PORT = 8000 #8443
SERVER_PORT = 8000 # 8443
# Certificates # Certificates
CERTFILE = "/etc/ssl/server.crt" CERTFILE = "/etc/ssl/server.crt"

21
agent/sslTransmitter.py

@ -26,7 +26,7 @@ class SSLTransmitterServer(object):
@staticmethod @staticmethod
def _on_data_recive(v, data): def _on_data_recive(v, data):
print "do_something:", data print "do_something:", data
#with lock:
# with lock:
dat = EventNAS().deserialize(data) dat = EventNAS().deserialize(data)
if dat is not None: if dat is not None:
v.append(dat) v.append(dat)
@ -45,9 +45,9 @@ class SSLTransmitterServer(object):
while True: while True:
newsocket, fromaddr = self.bindsocket.accept() newsocket, fromaddr = self.bindsocket.accept()
connstream = ssl.wrap_socket(newsocket, connstream = ssl.wrap_socket(newsocket,
server_side=True,
certfile=settings.CERTFILE,
keyfile=settings.KEYFILE)
server_side=True,
certfile=settings.CERTFILE,
keyfile=settings.KEYFILE)
try: try:
self._deal_with_client(connstream, v) self._deal_with_client(connstream, v)
finally: finally:
@ -56,7 +56,6 @@ class SSLTransmitterServer(object):
class PlainTransmitterServer(SSLTransmitterServer): class PlainTransmitterServer(SSLTransmitterServer):
def process(self, v): def process(self, v):
while True: while True:
newsocket, fromaddr = self.bindsocket.accept() newsocket, fromaddr = self.bindsocket.accept()
@ -82,6 +81,7 @@ def agent_abon_typer(fn):
abon.is_active abon.is_active
) )
fn(self, abn) fn(self, abn)
return wrapped return wrapped
@ -98,6 +98,7 @@ def agent_tariff_typer(fn):
tariff.speedOut tariff.speedOut
) )
fn(self, trf) fn(self, trf)
return wrapped return wrapped
@ -110,8 +111,8 @@ class SSLTransmitterClient(object):
# Require a certificate from the server. We used a self-signed certificate # Require a certificate from the server. We used a self-signed certificate
# so here ca_certs must be the server certificate itself. # so here ca_certs must be the server certificate itself.
self.s = ssl.wrap_socket(s, self.s = ssl.wrap_socket(s,
ca_certs=settings.CERTFILE,
cert_reqs=ssl.CERT_REQUIRED)
ca_certs=settings.CERTFILE,
cert_reqs=ssl.CERT_REQUIRED)
self.s.connect(( self.s.connect((
ip or settings.SELF_IP, ip or settings.SELF_IP,
port or settings.SELF_PORT port or settings.SELF_PORT
@ -180,7 +181,6 @@ class SSLTransmitterClient(object):
class PlainTransmitterClient(SSLTransmitterClient): class PlainTransmitterClient(SSLTransmitterClient):
def __init__(self, ip=None, port=None): def __init__(self, ip=None, port=None):
try: try:
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -220,12 +220,11 @@ def proc_entrypoint(obj, v, lock, ip, port):
class TransmitServer(object): class TransmitServer(object):
def __init__(self, ip, port): def __init__(self, ip, port):
mngr = Manager() mngr = Manager()
self.v = mngr.list() self.v = mngr.list()
#self.lock = Lock()
self.p = Process(target=proc_entrypoint, args=(self, self.v, None, ip, port))#self.lock))
# self.lock = Lock()
self.p = Process(target=proc_entrypoint, args=(self, self.v, None, ip, port)) #self.lock))
def get_data(self): def get_data(self):
if len(self.v) > 0: if len(self.v) > 0:

4
clientsideapp/views.py

@ -47,7 +47,7 @@ def debts_list(request):
@login_required @login_required
def debt_buy(request, d_id): def debt_buy(request, d_id):
warntext=u''
warntext = u''
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 = get_object_or_404(Abon, id=request.user.id)
if request.method == 'POST': if request.method == 'POST':
@ -64,7 +64,7 @@ def debt_buy(request, d_id):
debt.save(update_fields=['status', 'date_pay']) debt.save(update_fields=['status', 'date_pay'])
return redirect('client_debts') return redirect('client_debts')
except LogicError, e: except LogicError, e:
warntext=e.value
warntext = e.value
return render(request, 'clientsideapp/debt_buy.html', { return render(request, 'clientsideapp/debt_buy.html', {
'warntext': warntext, 'warntext': warntext,
'debt': debt, 'debt': debt,

2
cron.py

@ -1,6 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import django import django
@ -12,7 +13,6 @@ if __name__ == "__main__":
users = Abon.objects.all() users = Abon.objects.all()
for usr in users: for usr in users:
usr.activate_next_tariff() usr.activate_next_tariff()
AbonTariff.objects.update_priorities(usr) AbonTariff.objects.update_priorities(usr)

1
devapp/base_intr.py

@ -33,7 +33,6 @@ class DevBase(object):
class Port(object): class Port(object):
def __init__(self, num, name, status, mac, speed): def __init__(self, num, name, status, mac, speed):
self.num = int(num) self.num = int(num)
self.nm = name self.nm = name

1
devapp/dev_types.py

@ -3,7 +3,6 @@ from base_intr import DevBase, SNMPBaseWorker
class DLinkDevice(DevBase): class DLinkDevice(DevBase):
@staticmethod @staticmethod
def description(): def description():
return u"Свич D'Link" return u"Свич D'Link"

8
devapp/migrations/0001_initial.py

@ -9,7 +9,6 @@ import mydefs
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@ -22,7 +21,8 @@ class Migration(migrations.Migration):
('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')),
('ip_address', mydefs.MyGenericIPAddressField(max_length=8, protocol=b'IPv4')), ('ip_address', mydefs.MyGenericIPAddressField(max_length=8, protocol=b'IPv4')),
('comment', models.CharField(max_length=256)), ('comment', models.CharField(max_length=256)),
('devtype', models.CharField(choices=[(b'Dl', "\u0421\u0432\u0438\u0447 D'Link")], default=b'Dl', max_length=2)),
('devtype',
models.CharField(choices=[(b'Dl', "\u0421\u0432\u0438\u0447 D'Link")], default=b'Dl', max_length=2)),
('man_passw', models.CharField(blank=True, max_length=16, null=True)), ('man_passw', models.CharField(blank=True, max_length=16, null=True)),
], ],
), ),
@ -31,7 +31,9 @@ class Migration(migrations.Migration):
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')),
('num', models.PositiveSmallIntegerField(default=0)), ('num', models.PositiveSmallIntegerField(default=0)),
('speed', models.CharField(choices=[(b'h', b'100Mbps'), (b'k', b'1Gbps'), (b'd', b'10Gbps')], default=b'h', max_length=1)),
('speed',
models.CharField(choices=[(b'h', b'100Mbps'), (b'k', b'1Gbps'), (b'd', b'10Gbps')], default=b'h',
max_length=1)),
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device')), ('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='devapp.Device')),
], ],
), ),

3
devapp/models.py

@ -7,7 +7,6 @@ from dev_types import DEVICE_TYPES
class _DeviceChoicesAdapter(MyChoicesAdapter): class _DeviceChoicesAdapter(MyChoicesAdapter):
def __init__(self): def __init__(self):
super(_DeviceChoicesAdapter, self).__init__(DEVICE_TYPES) super(_DeviceChoicesAdapter, self).__init__(DEVICE_TYPES)
@ -17,7 +16,7 @@ class Device(models.Model):
comment = models.CharField(max_length=256) comment = models.CharField(max_length=256)
devtype = models.CharField(max_length=2, default=DEVICE_TYPES[0][0], choices=_DeviceChoicesAdapter()) devtype = models.CharField(max_length=2, default=DEVICE_TYPES[0][0], choices=_DeviceChoicesAdapter())
man_passw = models.CharField(max_length=16, null=True, blank=True) man_passw = models.CharField(max_length=16, null=True, blank=True)
#map_dot = models.ForeignKey()
# map_dot = models.ForeignKey()
class Meta: class Meta:
db_table = 'dev' db_table = 'dev'

9
djing/settings_example.py

@ -34,7 +34,7 @@ INSTALLED_APPS = [
'ip_pool', 'ip_pool',
'searchapp', 'searchapp',
'devapp', 'devapp',
'mapapp',
'gmap',
'statistics', 'statistics',
'taskapp', 'taskapp',
'clientsideapp' 'clientsideapp'
@ -80,12 +80,12 @@ WSGI_APPLICATION = 'djing.wsgi.application'
DATABASES = { DATABASES = {
'default': { 'default': {
#'ENGINE': 'django.db.backends.sqlite3',
# 'ENGINE': 'django.db.backends.sqlite3',
#'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), #'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'ENGINE': 'django.db.backends.mysql', 'ENGINE': 'django.db.backends.mysql',
'NAME': 'djingdb', 'NAME': 'djingdb',
'USER': 'USER', # You can change the user name
'PASSWORD': 'PASSWORD', # You can change the password
'USER': 'USER', # You can change the user name
'PASSWORD': 'PASSWORD', # You can change the password
'HOST': 'localhost' 'HOST': 'localhost'
} }
} }
@ -138,7 +138,6 @@ if DEBUG:
# Пример вывода: 16 сентября 2012 # Пример вывода: 16 сентября 2012
DATE_FORMAT = 'd E Y' DATE_FORMAT = 'd E Y'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/' MEDIA_URL = '/media/'

3
djing/urls.py

@ -14,14 +14,13 @@ urlpatterns = [
url(r'^ip_pool/', include('ip_pool.urls')), url(r'^ip_pool/', include('ip_pool.urls')),
url(r'^search/', include('searchapp.urls')), url(r'^search/', include('searchapp.urls')),
url(r'^dev/', include('devapp.urls')), url(r'^dev/', include('devapp.urls')),
url(r'^map/', include('mapapp.urls')),
url(r'^gmap/', include('gmap.urls')),
url(r'^statistic/', include('statistics.urls')), url(r'^statistic/', include('statistics.urls')),
url(r'^tasks/', include('taskapp.urls')), url(r'^tasks/', include('taskapp.urls')),
url(r'^client/', include('clientsideapp.urls')), url(r'^client/', include('clientsideapp.urls')),
url(r'^admin/', admin.site.urls) url(r'^admin/', admin.site.urls)
] ]
if settings.DEBUG: if settings.DEBUG:
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.contrib.staticfiles.urls import staticfiles_urlpatterns

1
global_context_processors.py

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from abonapp.models import Abon from abonapp.models import Abon

0
mapapp/__init__.py → gmap/__init__.py

43
gmap/admin.py

@ -0,0 +1,43 @@
from django.contrib import admin
from gmap.models import MapMarker, MarkerCategory, MarkerSubCategory, SalesDirector, SalesBoundary, CountryISOCode
class MarkerAdmin(admin.ModelAdmin):
list_display = [
'name',
'contact_title',
'category',
'contact_name',
'airport_code',
'address',
'platinum',
'airport_name',
'phone',
'fax',
'email',
'url'
]
exclude = ('latitude', 'longitude')
class MarkerInline(admin.TabularInline):
model = MapMarker
exclude = ('latitude', 'longitude')
extra = 1
class BoundaryAdmin(admin.ModelAdmin):
list_display = ['boundary_code', 'owner']
class DirectorAdmin(admin.ModelAdmin):
list_display = ['name', 'country']
admin.site.register(MapMarker, MarkerAdmin)
admin.site.register(MarkerCategory)
admin.site.register(MarkerSubCategory)
admin.site.register(CountryISOCode)
admin.site.register(SalesDirector, DirectorAdmin)
admin.site.register(SalesBoundary, BoundaryAdmin)

2
mapapp/apps.py → gmap/apps.py

@ -4,4 +4,4 @@ from django.apps import AppConfig
class MapappConfig(AppConfig): class MapappConfig(AppConfig):
name = 'mapapp'
name = 'gmap'

20
gmap/forms.py

@ -0,0 +1,20 @@
from django import forms
from gmap.models import MapMarker, CountryISOCode
class ModifiedChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
if 'long_name' in obj:
return obj['long_name']
if 'state' in obj:
return obj['state']
return 'No Data'
class MapSearchForm(forms.Form):
state = ModifiedChoiceField(
queryset=MapMarker.objects.filter(country__iso_3='USA').values('state').order_by('state').distinct(), label='')
country = ModifiedChoiceField(queryset=CountryISOCode.objects.order_by('long_name').values('long_name'), label='')

0
mapapp/migrations/__init__.py → gmap/migrations/__init__.py

369
gmap/models.py

@ -0,0 +1,369 @@
from django.db import models
from gmap.utils import geolocate
CATEGORY_LOOKUP = {u'1': 'Cirrus Authorized Service Center (ASC)', u'2': 'Cirrus Sales Representative or Center',
u'3': 'Cirrus Training Center (CTC)', u'4': 'Cirrus Standardized Instructor Pilot (CSIP)'}
INVERSE_CATEGORY = dict((v, k) for k, v in CATEGORY_LOOKUP.iteritems())
SUBCATEGORY_LOOKUP = {
u'1': 'Composite & Paint Repair',
u'2': 'Pickup & Delivery Service',
u'3': 'Parts Distributor',
u'4': 'Air Conditioning Service',
u'5': 'Garmin Service',
u'6': 'Avidyne Service',
u'7': 'Full Avionics Facility',
u'8': 'Oxygen Service',
u'9': 'Wi-Fi Equipped',
u'10': 'CAPS Overhaul',
u'11': 'Cirrus Platinum Service Partner',
u'12': 'Ice Protection System Maintenance',
u'13': 'SR20 Rental',
u'14': 'SR22 Rental',
u'15': 'SR22T Rental',
u'16': 'Cirrus Perspective Avionics Available',
u'17': 'Avidyne Entegra Avionics Available',
u'18': 'Cirrus Platinum Training Partner',
u'19': 'Simulator Available',
u'20': 'Cirrus Perspective Qualified',
u'21': 'Avidyne Entegra Qualified',
u'22': 'New Cirrus Sales',
u'23': 'Used Cirrus Sales',
u'24': 'n/a'
}
INVERSE_SUBCATEGORY = dict((v, k) for k, v in SUBCATEGORY_LOOKUP.iteritems())
# name, category, platinum partner, contacT_name, contact_title, airport_name, airport_code, address, phone, fax, email, url, sub_category1, ..., sub_categoryN
SUBCAT_IDX = 18
# SUBCAT_IDX = 12
# NAME_COLUMN = 2
NAME_COLUMN = 0
#CATEGORY_COLUMN = 3
CATEGORY_COLUMN = 1
#ADDRESS_COLUMN = 9
ADDRESS_COLUMN = 7
SUBCATEGORY_COLUMN = SUBCAT_IDX
class SalesBoundary(models.Model):
boundary_code = models.CharField('Boundary Code', max_length=75)
owner = models.ForeignKey('SalesDirector');
class Meta:
unique_together = ("boundary_code", "owner")
def __unicode__(self):
return self.boundary_code
class SalesDirector(models.Model):
name = models.CharField('Name', max_length=100, unique=True)
title = models.CharField(max_length=50, blank=True)
phone = models.CharField('Phone Number', max_length=40, blank=True)
email = models.EmailField('Email', blank=True)
airport_code = models.CharField(max_length=8, blank=True)
airport_name = models.CharField(max_length=50, blank=True)
address = models.TextField(max_length=200, blank=True)
city = models.CharField(max_length=200, blank=True)
state = models.CharField(max_length=100, blank=True)
zipcode = models.CharField(max_length=10, blank=True)
url = models.URLField(blank=True)
country = models.ForeignKey('CountryISOCode', blank=True)
def from_csv(self, row, row_id, errors):
local_errors = False
'''
self.name, cat, plat, self.contact_name, self.contact_title = row[0:5]
self.airport_name, self.airport_code, self.address, self.phone, self.fax = row[5:10]
self.email, self.url = row[10:12]
subcategories = row[12:]
'''
cat, plat = '', ''
subcategories = []
try:
self.name, cat, plat, self.contact_name, self.title = row[0:5]
self.airport_name, self.airport_code, self.address, self.phone, fax = row[5:10]
self.email, self.url, self.state, iso_3, self.city, self.zipcode, latitude, longitude = row[10:SUBCAT_IDX]
subcat_string = row[SUBCAT_IDX]
if ',' in subcat_string:
subcategories = subcat_string.split(',')
else:
subcategories = [subcat_string]
except IndexError:
error_string = "Entry does not contain required number of fields: %s < %s" % (len(row), SUBCAT_IDX)
errors.append(('%s : %s' % (row_id, error_string)))
return
except ValueError:
error_string = "Entry does not contain required number of fields: %s < %s" % (len(row), SUBCAT_IDX)
errors.append(('%s : %s' % (row_id, error_string)))
return
if not self.name:
local_errors = True
row[NAME_COLUMN] = '<font color="red">INSERT_NAME</font>'
if local_errors:
error_string = ', '.join(row)
errors.append(('%s : %s' % (row_id, error_string)))
return
try:
self.country = CountryISOCode.objects.get(long_name=iso_3)
except:
try:
self.country = CountryISOCode.objects.get(iso_3=iso_3)
except:
try:
self.country = CountryISOCode.objects.get(iso_2=iso_3)
except:
error_string = "Unable to map %s to ISO long name, two letter abbreviation, or three letter abbreviation" % iso_3
errors.append(('%s : %s' % (row_id, error_string)))
# Ask django really, really nicely not to insert our object twice
self.save()
def __unicode__(self):
return self.name
class MarkerCategoryManager(models.Manager):
def get_by_natural_key(self, name):
return self.get(name=name)
class MarkerCategory(models.Model):
objects = MarkerCategoryManager()
name = models.CharField('type', max_length=200, unique=True)
position = models.IntegerField(default=0);
icon = models.ImageField('icon', blank=True, upload_to='gmap-icons/')
platinum_icon = models.ImageField('platinum icon', blank=True, upload_to='gmap-icons/')
shadow = models.ImageField('icon shadow', blank=True, upload_to='gmap-icons/')
def natural_key(self):
return self.name
def __unicode__(self):
return self.name
class MarkerSubCategory(models.Model):
objects = MarkerCategoryManager()
name = models.CharField('Name', max_length=200, unique=True)
def natural_key(self):
return self.name
def __unicode__(self):
return self.name
class GeolocateFailure(Exception):
def __init__(self, message, address):
self.message = message
self.address = address
def __str__(self):
return '%s - %s' % (self.message, self.address)
class CountryISOCode(models.Model):
long_name = models.CharField(max_length=200)
iso_3 = models.CharField(max_length=10, blank=True)
iso_2 = models.CharField(max_length=10, blank=True)
def natural_key(self):
return self.long_name
def __unicode__(self):
return self.long_name
class MapMarker(models.Model):
name = models.CharField(max_length=200)
latitude = models.CharField(max_length=30, blank=True)
longitude = models.CharField(max_length=30, blank=True)
category = models.ForeignKey('MarkerCategory')
platinum = models.BooleanField('Platinum Partner', default=False)
sub_categories = models.ManyToManyField(MarkerSubCategory, related_name='sub_categories')
contact_name = models.CharField(max_length=50, blank=True)
contact_title = models.CharField(max_length=50, blank=True)
airport_name = models.CharField(max_length=100, blank=True)
airport_code = models.CharField(max_length=6, blank=True)
address = models.TextField(max_length=200, blank=True)
city = models.CharField(max_length=200, blank=True)
state = models.CharField(max_length=50, blank=True)
zipcode = models.CharField(max_length=10, blank=True)
country = models.ForeignKey('CountryISOCode', null=True, blank=True)
phone = models.CharField(max_length=40, blank=True)
fax = models.CharField(max_length=40, blank=True)
email = models.EmailField(blank=True)
url = models.URLField(blank=True)
# Make sure we update the lat/long with the location
def save(self, *args, **kwargs):
if not self.latitude and not self.longitude:
full_address = "%s, %s, %s, %s, %s" % (self.address, self.city, self.state, self.zipcode, self.country)
latlng = geolocate(repr(full_address))
if latlng != None:
self.latitude = latlng['latitude']
self.longitude = latlng['longitude']
else:
raise GeolocateFailure("Failed to geolocate address for %s" % self.name, full_address)
super(MapMarker, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
def from_csv(self, row, row_id, errors):
local_errors = False
'''
self.name, cat, plat, self.contact_name, self.contact_title = row[0:5]
self.airport_name, self.airport_code, self.address, self.phone, self.fax = row[5:10]
self.email, self.url = row[10:12]
subcategories = row[12:]
'''
cat, plat = '', ''
subcategories = []
try:
self.name, cat, plat, self.contact_name, self.contact_title = row[0:5]
self.airport_name, self.airport_code, self.address, self.phone, self.fax = row[5:10]
self.email, self.url, self.state, iso_3, self.city, self.zipcode, self.latitude, self.longitude = row[
10:SUBCAT_IDX]
subcat_string = row[SUBCAT_IDX]
if ',' in subcat_string:
subcategories = subcat_string.split(',')
else:
subcategories = [subcat_string]
except IndexError:
error_string = "Entry does not contain required number of fields: %s < %s" % (len(row), SUBCAT_IDX)
errors.append(('%s : %s' % (row_id, error_string)))
return
except ValueError:
error_string = "Entry does not contain required number of fields: %s < %s" % (len(row), SUBCAT_IDX)
errors.append(('%s : %s' % (row_id, error_string)))
return
if not self.name:
local_errors = True
row[NAME_COLUMN] = '<font color="red">INSERT_NAME</font>'
if not cat:
local_errors = True
row[CATEGORY_COLUMN] = '<font color="red">INSERT_CATEGORY</font>'
#if not self.address:
# local_errors = True
# row[ADDRESS_COLUMN] = '<font color="red">INSERT_ADDRESS</font>'
if not len(subcategories):
local_errors = True
row.append('<font color="red">INSERT_SUBCATEGORY</font>')
elif not subcategories[0]:
local_errors = True
row[SUBCATEGORY_COLUMN] = '<font color="red">INSERT_SUBCATEGORY</font>'
if local_errors:
error_string = ', '.join(row)
errors.append(('%s : %s' % (row_id, error_string)))
return
self.platinum = True if plat == '1' else False
self.category = MarkerCategory.objects.get(pk=cat.strip().strip("'"))
try:
self.country = CountryISOCode.objects.get(long_name=iso_3)
except:
try:
self.country = CountryISOCode.objects.get(iso_3=iso_3)
except:
try:
self.country = CountryISOCode.objects.get(iso_2=iso_3)
except:
error_string = "Unable to map %s to ISO long name, two letter abbreviation, or three letter abbreviation" % iso_3
errors.append(('%s : %s' % (row_id, error_string)))
# object's gotta be in the DB before it can get M2M mapping...
#
try:
self.save()
except GeolocateFailure as inst:
errors.append('%s : %s' % (row_id, inst))
return
# ...like this one!
for subcategory in subcategories:
if subcategory:
self.sub_categories.add(MarkerSubCategory.objects.get(pk=subcategory.strip().strip("'")))
# Ask django really, really nicely not to insert our object twice
self.save(force_update=True)
# Expected csv format:
#
# name, category, platinum partner, contacT_name, contact_title, airport_name, airport_code, address, phone, fax, email, url, sub_category1, ..., sub_categoryN
#
def csv_row(self):
# my baseline doesn't have: plat partner, contact_name, contact_title, airport_name,
# TODO: now it does!
'''
return [self.latitude, self.longitude, self.name, INVERSE_CATEGORY[self.category.name], str(self.platinum), self.contact_name, self.contact_title,
self.airport_name, self.airport_code, self.address, self.phone, self.fax,
self.email, self.url] + [INVERSE_SUBCATEGORY[subcat.name] for subcat in self.sub_categories.all()]
'''
return [self.name, INVERSE_CATEGORY[self.category.name], str(self.platinum), self.contact_name,
self.contact_title,
self.airport_name, self.airport_code, self.address, self.phone, self.fax,
self.email, self.url] + [INVERSE_SUBCATEGORY[subcat.name] for subcat in self.sub_categories.all()]

0
mapapp/tests.py → gmap/tests.py

16
gmap/urls.py

@ -0,0 +1,16 @@
from django.conf.urls import url
from gmap.views import index, showmap, markers, gmap_search, categories, dump_csv, director_by_boundary, director_import
app_name = 'gmap'
urlpatterns = [
url(r'^$', index, name="index"),
url(r'^markers.json$', markers, name="markers"),
url(r'^categories.json$', categories, name="categories"),
url(r'^directors/(?P<boundary_code>.+)/$', director_by_boundary, name="directors"),
url(r'^boundary_import/$', director_import, name="boundary_import"),
url(r'^search/?', gmap_search, name="gmap_search"),
url(r'^(?P<address>\w+)$', showmap, name="show_map"),
url(r'^csv/?', dump_csv, name="dump_csv"),
]

143
gmap/utils.py

@ -0,0 +1,143 @@
import json
import urllib
import urllib2
import csv
import codecs
import cStringIO
def csvByLine(csvFile, lineHandler):
errors = ''
for row_id, line in enumerate(UnicodeReader(csvFile)):
print "Calling Line handler for %s" % line
errors = ''.join([errors, lineHandler(line)])
return errors
def geolocate(location, sensor=False):
"""
Take a "location" and return its latitude and longitude
Keyword arguments:
location - String defining a geographical location (address, zip code, etc)
sensor - Boolean defining whether the location was taken from
an on-device sensor
Output:
latitude and logitude in an dict
"""
sensor = str(sensor).lower()
url = "http://maps.googleapis.com/maps/api/geocode/json?"
url += urllib.urlencode({'address': location, 'sensor': sensor})
data = urllib2.urlopen(url).read()
data = json.loads(data)
if data and data['status'] == 'OK':
return ({
'latitude': data['results'][0]['geometry']['location']['lat'],
'longitude': data['results'][0]['geometry']['location']['lng']
})
else:
return None
def georeverse(lat, lon):
# construct url for reverse geocoding with google-maps
url = "http://maps.googleapis.com/maps/api/geocode/json?"
url += urllib.urlencode({'latlng': lat + ',' + lon, 'sensor': 'false'})
# retrieve and load google-map data
data = urllib2.urlopen(url).read()
data = json.loads(data)
# if request goes through, return the state and country of the location
if data['status'] == 'OK':
address_components = data['results'][0]['address_components']
# these probably shouldn't be booleans (test with None data-type at some point)
country = False
state = False
for component in address_components:
try:
if component['types'][0] == 'country':
country = component['long_name']
if component['types'][0] == 'administrative_area_level_1':
state = component['long_name']
except Exception:
pass
return ({
'state': state,
'country': country
})
return ({
'state': False,
'country': False
})
class UTF8Recoder:
"""
Iterator that reads an encoded stream and reencodes the input to UTF-8
"""
def __init__(self, f, encoding):
self.reader = codecs.getreader(encoding)(f)
def __iter__(self):
return self
def next(self):
# return self.reader.next().decode("cp1252").encode("utf-8")
return self.reader.next().encode("utf-8")
class UnicodeReader:
"""
A CSV reader which will iterate over lines in the CSV file "f",
which is encoded in the given encoding.
"""
# def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
def __init__(self, f, dialect=csv.excel, encoding="cp1252", **kwds):
f = UTF8Recoder(f, encoding)
self.reader = csv.reader(f, dialect=dialect, **kwds)
def next(self):
row = self.reader.next()
return [unicode(s, "utf-8") for s in row]
def __iter__(self):
return self
class UnicodeWriter:
"""
A CSV writer which will write rows to CSV file "f",
which is encoded in the given encoding.
"""
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
# Redirect output to a queue
self.queue = cStringIO.StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, row):
self.writer.writerow([s.encode("utf-8") for s in row])
# Fetch UTF-8 output from the queue ...
data = self.queue.getvalue()
data = data.decode("utf-8")
# ... and reencode it into the target encoding
data = self.encoder.encode(data)
# write to the target stream
self.stream.write(data)
# empty queue
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)

250
gmap/views.py

@ -0,0 +1,250 @@
import csv
import tempfile
import time
from django.conf import settings
from django.core import serializers
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, render_to_response
from gmap.utils import geolocate, georeverse, csvByLine
from gmap.models import MapMarker, MarkerCategory, SalesDirector, SalesBoundary
from gmap.forms import MapSearchForm
import gmap.utils
def index(request):
form = MapSearchForm()
response = render(request, 'maps/gmap.html', {'form': form})
response['Cache-Control'] = 'no-cache'
return response
def newsales(args):
try:
director_name, code = tuple(args)
except:
err = open("Errors.log", "a")
err_text = "Issues getting tuple from: %s\n" % args
err.write(err_text)
err.close()
return err_text
director, new_director = SalesDirector.objects.get_or_create(name=director_name)
boundary, created = SalesBoundary.objects.get_or_create(boundary_code=code, owner=director)
if (new_director):
err = open("Errors.log", "a")
err_text = "We had to make a new director named: %s\n" % director_name
err.write(err_text)
err.close()
return err_text
return ""
def director_import(request):
errors = csvByLine(request.FILES['datafile'], newsales)
return HttpResponse(errors.replace('\n', '<br />'))
def showmap(request, address='', category=''):
context = {}
context['media_url'] = settings.MEDIA_URL
if request.method == 'POST':
address = request.POST.get('address', address)
category = request.POST.get('category', category)
if request.method == 'GET':
address = request.GET.get('address', address)
category = request.GET.get('category', category)
if category:
context['gmap_markers'] = MapMarker.objects.get(
marker_type__category_name__iexact=category
)
else:
context['gmap_markers'] = MapMarker.objects.all()
if address:
latlng = geolocate(address)
if latlng:
context['gmap_center_lat'] = latlng['latitude']
context['gmap_center_lng'] = latlng['longitude']
else:
context['error'] = "Please try another address."
return render(request, 'maps/gmap.html', context)
def markers(request):
# Show all categories but Sales Centers
data = serializers.serialize("json", MapMarker.objects.all().order_by('category__position', 'city'),
use_natural_keys=True)
return HttpResponse(data, mimetype='applicaton/javascript')
def categories(request):
data = serializers.serialize("json", MarkerCategory.objects.all().order_by('position'), use_natural_keys=True)
return HttpResponse(data, mimetype='applicaton/javascript')
def director_by_boundary(request, boundary_code):
# get a director based on a boundarycode (zip/postal/country code)
data = serializers.serialize("json", SalesDirector.objects.filter(salesboundary__boundary_code=boundary_code),
use_natural_keys=True)
return HttpResponse(data, mimetype='applicaton/javascript')
def gmap_search(request):
context = {}
return render(request, 'maps/gmap_search.html', context)
def dump_csv(request):
all_markers = MapMarker.objects.all()
print '# markers: ', len(all_markers)
# all_markers should now have all the things...
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=map_markers.csv'
# writer = csv.writer(response, quoting=csv.QUOTE_MINIMAL, lineterminator='\n')
writer = gmap.utils.UnicodeWriter(response, quoting=csv.QUOTE_MINIMAL, lineterminator='\n')
for marker in all_markers:
row = marker.csv_row()
# print 'row is: ', row
# repr because there are non-ascii characters somewhere
writer.writerow(row)
'''
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
'''
return response
def populatefields(request):
all_markers = MapMarker.objects.all()
start_time = time.time()
# loop over all map markers and update their state and country fields
for marker in all_markers:
reverse_addy = georeverse(marker.latitude, marker.longitude)
if reverse_addy['country']:
marker.country = reverse_addy['country']
if reverse_addy['state']:
marker.state = reverse_addy['state']
marker.save()
end_time = time.time()
return HttpResponse(end_time - start_time)
def process_sales_row(row_id, row, errors):
try:
sales_director = SalesDirector.objects.get(name=row[0])
except SalesDirector.DoesNotExist:
sales_director = SalesDirector()
sales_director.from_csv(row, row_id + 1, errors)
def process_marker_row(row_id, row, errors):
try:
marker = MapMarker.objects.get(name=row[0], zipcode=row[15])
except:
marker = MapMarker()
marker.from_csv(row, row_id + 1, errors)
# TODO: return errors?
def process_row(row_id, row, errors):
if row[1] == '2':
process_sales_row(row_id, row, errors)
else:
process_marker_row(row_id, row, errors)
def read_csv(request):
if request.method == 'POST' and request.FILES.has_key('datafile'):
# it's conceivable the user could upload a file large enough
# it gets split into chunks - to handle this we just direct all
# the chunks to a temp file and process that
# note that the tempfile will be deleted as soon as
# the with block is completes
num_processed = -1
delta = 0
errors = []
if request.FILES['datafile'].multiple_chunks():
MapMarker.objects.all().delete()
delta = time.clock()
with tempfile.TemporaryFile() as local_file:
for chunk in request.FILES['datafile'].chunks():
local_file.write(chunk)
local_file.seek(0)
for row_id, row in enumerate(gmap.utils.UnicodeReader(local_file)):
try:
process_row(row_id, row, errors)
except Exception as inst:
errors.append("%s : Unable to import entry - %s" % (row_id, inst))
num_processed = row_id
delta = time.clock() - delta
else:
delta = time.clock()
for row_id, row in enumerate(gmap.utils.UnicodeReader(request.FILES['datafile'])):
# try:
process_row(row_id, row, errors)
# except Exception as inst:
# errors.append("%s : Unable to import entry - %s" % (row_id, inst))
num_processed = row_id
delta = time.clock() - delta
if len(errors) > 1:
# Strip off errors result from Excel export garbage (the bottom two entries)
#
bottoms = errors[-2:]
rows = [row.split(':')[0].strip() for row in bottoms]
if int(rows[0]) == row_id:
errors = errors[0:-2]
if errors:
return render_to_response('maps/gmap_import_errors.html', {'errors': errors})
else:
return HttpResponseRedirect('/gmap/mapmarker/')
else:
# todo - can I make django redirect to referring page?
return HttpResponseRedirect('/gmap/')

31
install.sql

@ -1,17 +1,18 @@
create table flowstat (
`id` int(10) AUTO_INCREMENT NOT NULL,
`src_ip` CHAR(8) NOT NULL,
`dst_ip` CHAR(8) NOT NULL,
`proto` smallint(2) unsigned NOT NULL DEFAULT 0,
`src_port` smallint(5) unsigned NOT NULL DEFAULT 0,
`dst_port` smallint(5) unsigned NOT NULL DEFAULT 0,
`octets` INT unsigned NOT NULL DEFAULT 0,
`packets` INT unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE flowstat (
`id` INT(10) AUTO_INCREMENT NOT NULL,
`src_ip` CHAR(8) NOT NULL,
`dst_ip` CHAR(8) NOT NULL,
`proto` SMALLINT(2) UNSIGNED NOT NULL DEFAULT 0,
`src_port` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0,
`dst_port` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0,
`octets` INT UNSIGNED NOT NULL DEFAULT 0,
`packets` INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
)
ENGINE =MyISAM
DEFAULT CHARSET =utf8;
INSERT INTO flowstat(`src_ip`, `dst_ip`, `proto`, `src_port`, `dst_port`, `octets`, `packets`) VALUES
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13),
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13)
INSERT INTO flowstat (`src_ip`, `dst_ip`, `proto`, `src_port`, `dst_port`, `octets`, `packets`) VALUES
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13),
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13)

1
ip_pool/migrations/0001_initial.py

@ -8,7 +8,6 @@ import mydefs
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [

5
ip_pool/models.py

@ -4,7 +4,6 @@ from mydefs import ip2int, MyGenericIPAddressField
class IpPoolItemManager(models.Manager): class IpPoolItemManager(models.Manager):
def get_pools(self): def get_pools(self):
ips = self.raw(r'SELECT id, ip FROM ip_pool_ippoolitem ORDER BY id') ips = self.raw(r'SELECT id, ip FROM ip_pool_ippoolitem ORDER BY id')
ips_len = len(list(ips)) ips_len = len(list(ips))
@ -27,12 +26,12 @@ class IpPoolItemManager(models.Manager):
def add_pool(self, start_ip, end_ip): def add_pool(self, start_ip, end_ip):
start_ip = ip2int(start_ip) start_ip = ip2int(start_ip)
end_ip = ip2int(end_ip)
end_ip = ip2int(end_ip)
if (end_ip - start_ip) > 5000: if (end_ip - start_ip) > 5000:
raise Exception(u'Not add over 5000 ip\'s') raise Exception(u'Not add over 5000 ip\'s')
sql_strs = map(lambda tip: r"(%d)" % tip, range(start_ip, end_ip+1))
sql_strs = map(lambda tip: r"(%d)" % tip, range(start_ip, end_ip + 1))
sql = r'INSERT INTO ip_pool_ippoolitem (ip) VALUES %s' % r",".join(sql_strs) sql = r'INSERT INTO ip_pool_ippoolitem (ip) VALUES %s' % r",".join(sql_strs)
print sql print sql

4
ip_pool/views.py

@ -25,7 +25,7 @@ def home(request):
@mydefs.only_admins @mydefs.only_admins
def ips(request): def ips(request):
ip_start = request.GET.get('ips') ip_start = request.GET.get('ips')
ip_end = request.GET.get('ipe')
ip_end = request.GET.get('ipe')
pool_ips = IpPoolItem.objects.filter(ip__gte=ip_start) pool_ips = IpPoolItem.objects.filter(ip__gte=ip_start)
pool_ips = pool_ips.filter(ip__lte=ip_end) pool_ips = pool_ips.filter(ip__lte=ip_end)
@ -43,7 +43,7 @@ def ips(request):
@mydefs.only_admins @mydefs.only_admins
def del_pool(request): def del_pool(request):
ip_start = request.GET.get('ips') ip_start = request.GET.get('ips')
ip_end = request.GET.get('ipe')
ip_end = request.GET.get('ipe')
pool_ips = IpPoolItem.objects.filter(ip__gte=ip_start) pool_ips = IpPoolItem.objects.filter(ip__gte=ip_start)
pool_ips = pool_ips.filter(ip__lte=ip_end) pool_ips = pool_ips.filter(ip__lte=ip_end)

6
mapapp/admin.py

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

25
mapapp/migrations/0001_initial.py

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-06-28 23:51
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Dot',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=64)),
('posX', models.FloatField()),
('posY', models.FloatField()),
],
),
]

10
mapapp/models.py

@ -1,10 +0,0 @@
from django.db import models
class Dot(models.Model):
title = models.CharField(max_length=64)
posX = models.FloatField()
posY = models.FloatField()
def __unicode__(self):
return self.title

9
mapapp/urls.py

@ -1,9 +0,0 @@
from django.conf.urls import url
import views
urlpatterns = [
url(r'^$', views.home, name='maps_home_link'),
url(r'^get_dots$', views.get_dots, name='maps_get_dots')
]

22
mapapp/views.py

@ -1,22 +0,0 @@
from json import dumps
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.shortcuts import render
from models import Dot
from mydefs import only_admins
@login_required
@only_admins
def home(request):
return render(request, 'maps/index.html')
def get_dots(r):
dots = Dot.objects.all()
return HttpResponse(dumps({
'dots': map(lambda d: (d.id, d.posX, d.posY, d.title), dots)
}))

6
mydefs.py

@ -38,13 +38,13 @@ def res_success(request, redirect_to='/'):
def res_error(request, text): def res_error(request, text):
if request.is_ajax(): if request.is_ajax():
return HttpResponse(dumps({'errnum':1, 'errtext':text}))
return HttpResponse(dumps({'errnum': 1, 'errtext': text}))
else: else:
raise Http404(text) raise Http404(text)
# Pagination # Pagination
def pag_mn(request, objs, count_per_page=10):
def pag_mn(request, objs, count_per_page=50):
page = request.GET.get('p') page = request.GET.get('p')
pgn = Paginator(objs, count_per_page) pgn = Paginator(objs, count_per_page)
try: try:
@ -57,7 +57,6 @@ def pag_mn(request, objs, count_per_page=10):
class MyGenericIPAddressField(models.GenericIPAddressField): class MyGenericIPAddressField(models.GenericIPAddressField):
description = "Int32 notation ip address" description = "Int32 notation ip address"
def __init__(self, protocol='IPv4', *args, **kwargs): def __init__(self, protocol='IPv4', *args, **kwargs):
@ -130,4 +129,5 @@ def only_admins(fn):
return fn(request, *args, **kwargs) return fn(request, *args, **kwargs)
else: else:
return redirect('client_home') return redirect('client_home')
return wrapped return wrapped

1
photo_app/migrations/0001_initial.py

@ -6,7 +6,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [

6
photo_app/models.py

@ -43,8 +43,8 @@ class Photo(models.Model):
super(Photo, self).save() super(Photo, self).save()
#class Meta:
# unique_together = (('image',),)
# class Meta:
# unique_together = (('image',),)
def resize_image(sender, instance, **kwargs): def resize_image(sender, instance, **kwargs):
@ -56,7 +56,6 @@ def resize_image(sender, instance, **kwargs):
im.save(fullpath) im.save(fullpath)
def post_delete_photo(sender, instance, **kwargs): def post_delete_photo(sender, instance, **kwargs):
min_fname = instance.image.path.split('/')[-1:][0] min_fname = instance.image.path.split('/')[-1:][0]
try: try:
@ -66,6 +65,5 @@ def post_delete_photo(sender, instance, **kwargs):
pass pass
models.signals.post_save.connect(resize_image, sender=Photo) models.signals.post_save.connect(resize_image, sender=Photo)
models.signals.post_delete.connect(post_delete_photo, sender=Photo) models.signals.post_delete.connect(post_delete_photo, sender=Photo)

2
photo_app/urls.py

@ -1,7 +1,7 @@
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
urlpatterns = [ urlpatterns = [
#url(r'^$', 'photo_albums', name='media_home_link'),
# url(r'^$', 'photo_albums', name='media_home_link'),
#url(r'^(?P<id>\d+)$', 'photo_albums', name='media_home_link_by_id'), #url(r'^(?P<id>\d+)$', 'photo_albums', name='media_home_link_by_id'),
#url(r'^album(?P<id>\d+)$', 'photos', name='media_photos_link'), #url(r'^album(?P<id>\d+)$', 'photos', name='media_photos_link'),

7
privatemessage/migrations/0001_initial.py

@ -8,7 +8,6 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@ -22,8 +21,10 @@ class Migration(migrations.Migration):
('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)), ('title', models.CharField(max_length=127)),
('date_create', models.DateTimeField(auto_now_add=True)), ('date_create', models.DateTimeField(auto_now_add=True)),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)),
('recepient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to=settings.AUTH_USER_MODEL)),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+',
to=settings.AUTH_USER_MODEL)),
('recepient', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+',
to=settings.AUTH_USER_MODEL)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(

1
privatemessage/models.py

@ -3,7 +3,6 @@ from django.conf import settings
class MessagesManager(models.Manager): class MessagesManager(models.Manager):
def get_my_messages(self, request): def get_my_messages(self, request):
if request.user.is_authenticated(): if request.user.is_authenticated():
num = self.filter(recepient=request.user, is_viewed=False).count() num = self.filter(recepient=request.user, is_viewed=False).count()

1
privatemessage/tests.py

@ -5,7 +5,6 @@ import models
class PaysTest(TestCase): class PaysTest(TestCase):
def setUp(self): def setUp(self):
self.msg = models.PrivateMessages.objects.create( self.msg = models.PrivateMessages.objects.create(
sender=User.objects.all()[0], sender=User.objects.all()[0],

6
privatemessage/views.py

@ -6,10 +6,10 @@ from django.shortcuts import render, redirect
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.http import HttpResponse from django.http import HttpResponse
from django.template.context_processors import csrf from django.template.context_processors import csrf
from django.contrib.auth import get_user_model
from models import PrivateMessages from models import PrivateMessages
import mydefs import mydefs
from django.contrib.auth import get_user_model
@login_required @login_required
@ -24,7 +24,7 @@ def home(request):
@login_required @login_required
@mydefs.only_admins @mydefs.only_admins
def delitem(request, id=0): def delitem(request, id=0):
r = {'errnum': 0,'errtext': u''}
r = {'errnum': 0, 'errtext': u''}
try: try:
PrivateMessages.objects.get(id=id).delete() PrivateMessages.objects.get(id=id).delete()
except PrivateMessages.DoesNotExist: except PrivateMessages.DoesNotExist:
@ -40,7 +40,7 @@ def delitem(request, id=0):
def send_message(request): def send_message(request):
UserModel = get_user_model() UserModel = get_user_model()
if request.method == 'GET': if request.method == 'GET':
return HttpResponse(render_to_string('private_messages/send_form.html',{
return HttpResponse(render_to_string('private_messages/send_form.html', {
'csrf_token': csrf(request)['csrf_token'], 'csrf_token': csrf(request)['csrf_token'],
'a': request.GET.get('a') 'a': request.GET.get('a')
})) }))

16
static/bad_ie.html

@ -1,11 +1,11 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<title>Старый браузер</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>У вас старый ослик, обновитесь хотяб до IE10</h1>
</body>
<head>
<title>Старый браузер</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h1>У вас старый ослик, обновитесь хотяб до IE10</h1>
</body>
</html> </html>

4
static/clientside/custom.css

@ -4,9 +4,11 @@ img.navbar-brand {
padding: 0; padding: 0;
margin: 0 15px 0 0; margin: 0 15px 0 0;
} }
body > .container { body > .container {
padding: 60px 15px 0;
padding: 60px 15px 0;
} }
.table thead { .table thead {
background-color: #ddd; background-color: #ddd;
} }

416
static/css/bootstrap-datetimepicker.min.css
File diff suppressed because it is too large
View File

470
static/css/bootstrap-theme.min.css
File diff suppressed because it is too large
View File

7022
static/css/bootstrap.min.css
File diff suppressed because it is too large
View File

106
static/css/custom.css

@ -4,17 +4,16 @@
/* Move down content because we have a fixed navbar that is 50px tall */ /* Move down content because we have a fixed navbar that is 50px tall */
body { body {
padding-top: 50px;
padding-top: 50px;
} }
/* /*
* Global add-ons * Global add-ons
*/ */
.sub-header { .sub-header {
padding-bottom: 10px;
border-bottom: 1px solid #eee;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
} }
/* /*
@ -26,76 +25,80 @@ body {
background-position-x: 16px; background-position-x: 16px;
} }
/* /*
* Sidebar * Sidebar
*/ */
/* Hide for mobile, show later */ /* Hide for mobile, show later */
.sidebar { .sidebar {
display: none;
display: none;
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.sidebar {
position: fixed;
top: 39px;
bottom: 0;
left: 0;
z-index: 1000;
display: block;
padding: 20px;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
background-color: #303840;
border-right: 1px solid #eee;
}
.sidebar {
position: fixed;
top: 39px;
bottom: 0;
left: 0;
z-index: 1000;
display: block;
padding: 20px;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
background-color: #303840;
border-right: 1px solid #eee;
}
} }
/* Sidebar navigation */ /* Sidebar navigation */
.nav-sidebar { .nav-sidebar {
margin-right: -21px; /* 20px padding + 1px border */
margin-bottom: 20px;
margin-left: -20px;
border-top: 1px solid #576a7d;
margin-right: -21px; /* 20px padding + 1px border */
margin-bottom: 20px;
margin-left: -20px;
border-top: 1px solid #576a7d;
} }
.nav-sidebar > li > a { .nav-sidebar > li > a {
padding-right: 20px;
padding-left: 20px;
color: #b3c3d2;
padding-right: 20px;
padding-left: 20px;
color: #b3c3d2;
} }
.nav>li>a:focus, .nav>li>a:hover {
.nav > li > a:focus, .nav > li > a:hover {
background-color: #1f2429; background-color: #1f2429;
color: #b2bfcc; color: #b2bfcc;
} }
.nav-sidebar > .active > a { .nav-sidebar > .active > a {
background-color: #44596b;
background-color: #44596b;
} }
.profile_img{
.profile_img {
color: aliceblue; color: aliceblue;
padding-bottom: 9px; padding-bottom: 9px;
} }
.main{
.main {
margin-top: 10px; margin-top: 10px;
} }
.table-responsive thead{
.table-responsive thead {
background-color: gainsboro; background-color: gainsboro;
} }
td.btn-group{
td.btn-group {
display: table-cell; display: table-cell;
} }
.table > tbody > tr > td { .table > tbody > tr > td {
vertical-align: middle; vertical-align: middle;
} }
.modal-header.warning{
.modal-header.warning {
background-color: #d2322d; background-color: #d2322d;
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
} }
.tab-pane { .tab-pane {
border-left: 1px solid #ddd; border-left: 1px solid #ddd;
border-right: 1px solid #ddd; border-right: 1px solid #ddd;
@ -104,21 +107,21 @@ td.btn-group{
padding: 10px; padding: 10px;
} }
/* search form */ /* search form */
.stylish-input-group .input-group-addon{
background: white !important;
}
.stylish-input-group .form-control{
border-right:0;
box-shadow:0 0 0;
border-color:#ccc;
.stylish-input-group .input-group-addon {
background: white !important;
} }
.stylish-input-group button{
border:0;
background:transparent;
.stylish-input-group .form-control {
border-right: 0;
box-shadow: 0 0 0;
border-color: #ccc;
} }
.stylish-input-group button {
border: 0;
background: transparent;
}
/*---------Switch----------*/ /*---------Switch----------*/
.switch_ports { .switch_ports {
@ -126,9 +129,11 @@ td.btn-group{
border-radius: 7px; border-radius: 7px;
box-shadow: 3px 3px 8px #2B2B2B; box-shadow: 3px 3px 8px #2B2B2B;
} }
.switch_ports h4 { .switch_ports h4 {
margin: 10px 0 3px 10px; margin: 10px 0 3px 10px;
} }
.port { .port {
display: inline-block; display: inline-block;
margin: 10px; margin: 10px;
@ -138,19 +143,22 @@ td.btn-group{
width: 64px; width: 64px;
height: 64px; height: 64px;
} }
.port.giga { .port.giga {
background-color: #B5FFB5; background-color: #B5FFB5;
} }
.port.kilo { .port.kilo {
background-color: #FBEB79; background-color: #FBEB79;
} }
/*-------END-Switch--------*/
/*-------END-Switch--------*/
/* Table filter */ /* Table filter */
.table th>a {
.table th > a {
color: inherit; color: inherit;
cursor: pointer; cursor: pointer;
text-decoration: none; text-decoration: none;
} }
/* end */ /* end */

50
static/css/custom_login.css

@ -1,40 +1,46 @@
body { body {
padding-top: 40px;
padding-bottom: 40px;
background-color: #eee;
padding-top: 40px;
padding-bottom: 40px;
background-color: #eee;
} }
.form-signin { .form-signin {
max-width: 330px;
padding: 15px;
margin: 0 auto;
max-width: 330px;
padding: 15px;
margin: 0 auto;
} }
.form-signin .form-signin-heading, .form-signin .form-signin-heading,
.form-signin .checkbox { .form-signin .checkbox {
margin-bottom: 10px;
margin-bottom: 10px;
} }
.form-signin .checkbox { .form-signin .checkbox {
font-weight: normal;
font-weight: normal;
} }
.form-signin .form-control { .form-signin .form-control {
position: relative;
height: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
position: relative;
height: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
} }
.form-signin .form-control:focus { .form-signin .form-control:focus {
z-index: 2;
z-index: 2;
} }
.form-signin input[type="email"] { .form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
} }
.form-signin input[type="password"] { .form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
} }

4
static/css/gmap.css

@ -0,0 +1,4 @@
#gmap_canvas {
width: 500px;
height: 300px;
}

694
static/js/bootstrap-datetimepicker.min.js
File diff suppressed because it is too large
View File

703
static/js/bootstrap.min.js
File diff suppressed because it is too large
View File

91
static/js/gmap.js

@ -0,0 +1,91 @@
function toggleCategory(category) {
$.each(gmap_markers, function (key, marker) {
if (marker.category == category) {
if (marker.getVisible() == true) {
marker.setVisible(false)
} else {
marker.setVisible(true)
}
}
})
}
function toggleTag(tag) {
$.each(gmap_markers, function (key, marker) {
$.each(marker.tags, function (key, this_tag) {
if (this_tag == tag) {
if (marker.getVisible() == true) {
marker.setVisible(false)
} else {
marker.setVisible(true)
}
}
})
})
}
$(document).ready(function () {
var myLatlng = new Array();
var open_marker = '';
myLatlng[0] = new google.maps.LatLng(28.5000, -81.4500);
var map = new google.maps.Map(document.getElementById("gmap_canvas"), {
zoom: 1,
center: myLatlng[0],
mapTypeId: google.maps.MapTypeId.ROADMAP
});
$.getJSON('/map/markers.json', function (data) {
var categories = new Array();
var tags = new Array();
var infowindow = new google.maps.InfoWindow({content: ''})
gmap_markers = []
$.each(data, function (key, item) {
var content = '<span class="name">' + item.fields.name + '</span><br/><span class="phone">' + item.fields.phone + '</span><br/><span class="email">' + item.fields.email + '</span><br/><span class="url">' + item.fields.url + '</span><br/>'
var latLng = new google.maps.LatLng(item.fields.latitude, item.fields.longitude)
var marker = new google.maps.Marker({
position: latLng,
map: map,
title: item.fields.name,
category: item.fields.category,
tags: item.fields.sub_categories,
})
google.maps.event.addListener(marker, "click", function () {
infowindow.content = content
infowindow.open(map, marker);
});
gmap_markers.push(marker)
if ($.inArray(item.fields.category, categories) == -1) {
categories.push(item.fields.category)
}
$.each(item.fields.sub_categories, function (key, item) {
if ($.inArray(item, tags) == -1) {
tags.push(item)
}
})
})
$.each(categories, function (key, category) {
var $button = $(' <a href="#category_' + category + '">' + category + '</a> ').bind('click', function () {
toggleCategory(category)
})
$('#gmap_categories').append($button)
})
$.each(tags, function (key, tag) {
var $button = $(' <a href="#tag_' + tag + '">' + tag + '</a> ').bind('click', function () {
toggleTag(tag)
})
$('#gmap_sub_categories').append($button)
})
})
google.maps.event.addListener(map, 'click', function () {
if (open_marker != '') {
open_marker.close();
}
open_marker = '';
});
})

2116
static/js/jquery-2.2.4.min.js
File diff suppressed because it is too large
View File

3414
static/js/moment-with-locales.min.js
File diff suppressed because it is too large
View File

84
static/js/my.js

@ -1,4 +1,4 @@
function errShow(errContent){
function errShow(errContent) {
//window.history.back(); //window.history.back();
$('#modContent').html('<div class="modal-header warning">\ $('#modContent').html('<div class="modal-header warning">\
@ -7,9 +7,9 @@ function errShow(errContent){
Ошибка\ Ошибка\
</h4>\ </h4>\
</div>\ </div>\
<div class="modal-body">'+
errContent
+'</div>\
<div class="modal-body">' +
errContent
+ '</div>\
<div class="modal-footer">\ <div class="modal-footer">\
<button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>\ <button type="button" class="btn btn-default" data-dismiss="modal">Закрыть</button>\
</div>'); </div>');
@ -17,52 +17,52 @@ function errShow(errContent){
} }
$(document).ajaxError(function(ev, jqXHR, ajaxSettings, thrownError ){
$(document).ajaxError(function (ev, jqXHR, ajaxSettings, thrownError) {
//loaderShow(false); //loaderShow(false);
errShow(jqXHR.status+': '+jqXHR.statusText);
errShow(jqXHR.status + ': ' + jqXHR.statusText);
}); });
$(document).ready(function(){
$(document).ready(function () {
// ajax tabs
$('.nav-tabs a').on('show.bs.tab', function(e) {
var ct = $(e.target).attr('href');
var remoteUrl = $(this).attr('data-tab-remote');
if (remoteUrl !== ''){
$(ct).load(remoteUrl);
}
});
// ajax tabs
$('.nav-tabs a').on('show.bs.tab', function (e) {
var ct = $(e.target).attr('href');
var remoteUrl = $(this).attr('data-tab-remote');
if (remoteUrl !== '') {
$(ct).load(remoteUrl);
}
});
// Live html5 image preview
if(window.File && window.FileReader && window.FileList && window.Blob) {
$('input[type=file].live_review').on('change', function (){
var reader = new FileReader();
var img = $('img[alt=ava]')[0];
reader.readAsDataURL(this.files[0]);
reader.onload = function (e) {
img.src = e.target.result;
}
});
}else{
console.warn( "Ваш браузер не поддерживает FileAPI");
}
// Live html5 image preview
if (window.File && window.FileReader && window.FileList && window.Blob) {
$('input[type=file].live_review').on('change', function () {
var reader = new FileReader();
var img = $('img[alt=ava]')[0];
reader.readAsDataURL(this.files[0]);
reader.onload = function (e) {
img.src = e.target.result;
}
});
} else {
console.warn("Ваш браузер не поддерживает FileAPI");
}
// Validate inputs of form
$('input.form-control[pattern]').keyup(function(){
var pr = $(this).closest('.form-group-sm,.form-group');
pr.removeClass('has-success');
pr.removeClass('has-error');
pr.find('.form-control-feedback').remove();
if($(this)[0].checkValidity()){
pr.addClass('has-success');
$(this).after('<span class="glyphicon glyphicon-ok form-control-feedback"></span>');
}else{
pr.addClass('has-error');
$(this).after('<span class="glyphicon glyphicon-remove form-control-feedback"></span>');
}
// Validate inputs of form
$('input.form-control[pattern]').keyup(function () {
var pr = $(this).closest('.form-group-sm,.form-group');
pr.removeClass('has-success');
pr.removeClass('has-error');
pr.find('.form-control-feedback').remove();
if ($(this)[0].checkValidity()) {
pr.addClass('has-success');
$(this).after('<span class="glyphicon glyphicon-ok form-control-feedback"></span>');
} else {
pr.addClass('has-error');
$(this).after('<span class="glyphicon glyphicon-remove form-control-feedback"></span>');
}
});
});
}); });

1
statistics/migrations/0001_initial.py

@ -8,7 +8,6 @@ import mydefs
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [

2
tariff_app/base_intr.py

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
#from abonapp import Abon
# from abonapp import Abon
class TariffBase: class TariffBase:

6
tariff_app/custom_tariffs.py

@ -5,11 +5,10 @@ from django.utils import timezone
from base_intr import TariffBase from base_intr import TariffBase
#from abonapp import AbonTariff
# from abonapp import AbonTariff
class TariffDefault(TariffBase): class TariffDefault(TariffBase):
# Базовый функционал считает стоимость пропорционально использованному времени # Базовый функционал считает стоимость пропорционально использованному времени
def calc_amount(self, abon_tariff): def calc_amount(self, abon_tariff):
#assert isinstance(abon_tariff, AbonTariff) #assert isinstance(abon_tariff, AbonTariff)
@ -20,7 +19,7 @@ class TariffDefault(TariffBase):
time_diff = nw - abon_tariff.time_start time_diff = nw - abon_tariff.time_start
# времени в этом месяце # времени в этом месяце
curr_month_time = datetime(nw.year, nw.month+1, 1) - timedelta(days = 1)
curr_month_time = datetime(nw.year, nw.month + 1, 1) - timedelta(days=1)
curr_month_time = timedelta(days=curr_month_time.day) curr_month_time = timedelta(days=curr_month_time.day)
# Сколько это в процентах от всего месяца (k - коеффициент, т.е. без %) # Сколько это в процентах от всего месяца (k - коеффициент, т.е. без %)
@ -49,7 +48,6 @@ class TariffDp(TariffBase):
class TariffCp(TariffBase): class TariffCp(TariffBase):
def calc_amount(self, abon_tariff): def calc_amount(self, abon_tariff):
return 12.6 return 12.6

7
tariff_app/migrations/0001_initial.py

@ -6,7 +6,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
@ -22,7 +21,11 @@ class Migration(migrations.Migration):
('speedOut', models.FloatField(default=0.0)), ('speedOut', models.FloatField(default=0.0)),
('amount', models.FloatField(default=0.0)), ('amount', models.FloatField(default=0.0)),
('time_of_action', models.IntegerField(default=30)), ('time_of_action', models.IntegerField(default=30)),
('calc_type', models.CharField(choices=[(b'Df', '\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u0440\u0430\u0441\u0447\u0451\u0442\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b'), (b'Dp', '\u041a\u0430\u043a \u0432 IS'), (b'Cp', '\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439')], default=b'Df', max_length=2)),
('calc_type', models.CharField(choices=[(b'Df',
'\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u0440\u0430\u0441\u0447\u0451\u0442\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b'),
(b'Dp', '\u041a\u0430\u043a \u0432 IS'), (b'Cp',
'\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439')],
default=b'Df', max_length=2)),
], ],
), ),
] ]

1
tariff_app/models.py

@ -10,7 +10,6 @@ from agent import get_TransmitterClientKlass
# Класс похож на адаптер. Предназначен для Django CHOICES чтоб можно было передавать классывместо просто описания поля, # Класс похож на адаптер. Предназначен для Django CHOICES чтоб можно было передавать классывместо просто описания поля,
# классы передавать для того чтоб по значению из базы понять какой класс нужно взять для расчёта стоимости тарифа. # классы передавать для того чтоб по значению из базы понять какой класс нужно взять для расчёта стоимости тарифа.
class _TariffChoicesAdapter(MyChoicesAdapter): class _TariffChoicesAdapter(MyChoicesAdapter):
# На вход принимает кортеж кортежей, вложенный из 2х элементов: кода и класса, как: TARIFF_CHOICES # На вход принимает кортеж кортежей, вложенный из 2х элементов: кода и класса, как: TARIFF_CHOICES
def __init__(self): def __init__(self):
super(_TariffChoicesAdapter, self).__init__(TARIFF_CHOICES) super(_TariffChoicesAdapter, self).__init__(TARIFF_CHOICES)

55
taskapp/forms.py

@ -1,40 +1,27 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django import forms from django import forms
from models import Task
from models import TASK_PRIORITIES, TASK_STATES
from accounts_app.models import UserProfile
from devapp.models import Device
class TaskFrm(forms.ModelForm):
class TaskFrm(forms.Form):
descr = forms.CharField(max_length=128, required=True, widget=forms.TextInput(attrs={
'placeholder': u'Краткое описание',
'class': "form-control",
'required':''
}))
recipient = forms.ModelChoiceField(
queryset=UserProfile.objects.all(),
widget=forms.Select(attrs={'class': 'form-control', 'required':''})
)
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
widget=forms.Select(attrs={'class': 'form-control', 'required':''})
)
priority = forms.ChoiceField(
choices=TASK_PRIORITIES,
widget=forms.Select(attrs={'class': 'form-control'}),
required=False,
initial=TASK_PRIORITIES[2][0]
)
state = forms.ChoiceField(
choices=TASK_STATES,
widget=forms.Select(attrs={'class': 'form-control'}),
required=False,
initial=TASK_PRIORITIES[0][0]
)
out_date = forms.DateField(
widget=forms.DateInput(attrs={'class': 'form-control',}),
initial=datetime.now()+timedelta(days=7)
)
class Meta:
model = Task
exclude = ['time_of_create', 'author']
widgets = {
'descr': forms.TextInput(attrs={
'placeholder': u'Краткое описание',
'class': "form-control",
'required': ''
}),
'recipient': forms.Select(attrs={'class': 'form-control', 'required':''}),
'device': forms.Select(attrs={'class': 'form-control', 'required':''}),
'priority': forms.Select(attrs={'class': 'form-control'}),
'state': forms.Select(attrs={'class': 'form-control'}),
'out_date': forms.DateInput(attrs={'class': 'form-control'}),
'attachment': forms.FileInput(attrs={'class': 'form-control'})
}
initials = {
'out_date': datetime.now()+timedelta(days=7)
}

13
taskapp/models.py

@ -30,9 +30,10 @@ class Task(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+') author = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+')
device = models.ForeignKey(Device, related_name='dev') device = models.ForeignKey(Device, related_name='dev')
priority = models.CharField(max_length=1, choices=TASK_PRIORITIES, default=TASK_PRIORITIES[2][0]) priority = models.CharField(max_length=1, choices=TASK_PRIORITIES, default=TASK_PRIORITIES[2][0])
out_date = models.DateField(null=True, blank=True, default=datetime.now()+timedelta(days=7))
out_date = models.DateField(null=True, blank=True, default=datetime.now() + timedelta(days=7))
time_of_create = models.DateTimeField(auto_now_add=True) time_of_create = models.DateTimeField(auto_now_add=True)
state = models.CharField(max_length=1, choices=TASK_STATES, default=TASK_STATES[0][0]) state = models.CharField(max_length=1, choices=TASK_STATES, default=TASK_STATES[0][0])
attachment = models.ImageField(upload_to='task_attachments/%Y.%m.%d', blank=True, null=True)
def __unicode__(self): def __unicode__(self):
return self.descr return self.descr
@ -41,16 +42,6 @@ class Task(models.Model):
db_table = 'task' db_table = 'task'
ordering = ('-id',) ordering = ('-id',)
def save_form(self, frm_instance, auth_user):
cl = frm_instance.cleaned_data
self.descr = cl['descr']
self.recipient = cl['recipient']
self.author = auth_user
self.device = cl['device']
self.priority = cl['priority']
self.out_date = cl['out_date']
self.state = cl['state']
def finish(self, current_user): def finish(self, current_user):
self.state = 'F' # Выполнена self.state = 'F' # Выполнена
self.out_date = datetime.now() # Время завершения self.out_date = datetime.now() # Время завершения

43
taskapp/views.py

@ -13,7 +13,7 @@ def home(request):
tasks = Task.objects.filter(recipient=request.user, state='S') # Новые задачи tasks = Task.objects.filter(recipient=request.user, state='S') # Новые задачи
# filter # filter
#dir, field = order_helper(request)
# dir, field = order_helper(request)
#if field: #if field:
# tasks = tasks.order_by(field) # tasks = tasks.order_by(field)
@ -67,7 +67,9 @@ def all_tasks(request):
@login_required @login_required
@only_admins @only_admins
def task_delete(request, task_id): def task_delete(request, task_id):
get_object_or_404(Task, id=task_id).delete()
task = get_object_or_404(Task, id=task_id)
if request.user != task.recipient:
task.delete()
return redirect('task_home') return redirect('task_home')
@ -79,40 +81,31 @@ def task_add_edit(request, task_id=0):
# чтоб при добавлении сразу был выбран исполнитель # чтоб при добавлении сразу был выбран исполнитель
frm_recipient_id = safe_int(request.GET.get('rp')) frm_recipient_id = safe_int(request.GET.get('rp'))
if task_id == 0:
tsk = Task()
tsk.author = request.user
else:
tsk = get_object_or_404(Task, id=task_id)
if request.method == 'POST': if request.method == 'POST':
frm = TaskFrm(request.POST)
frm = TaskFrm(request.POST, request.FILES, instance=tsk)
if frm.is_valid(): if frm.is_valid():
if task_id == 0:
tsk = Task()
else:
tsk = get_object_or_404(Task, id=task_id)
tsk.save_form(frm, request.user)
tsk.save()
frm.save()
return redirect('task_home') return redirect('task_home')
else: else:
warntext = u'Исправте ошибки' warntext = u'Исправте ошибки'
if task_id == 0:
task = Task()
frm = TaskFrm(initial={
'recipient': frm_recipient_id
})
else: else:
task = get_object_or_404(Task, id=task_id)
frm = TaskFrm({
'descr': task.descr,
'recipient': task.recipient.id,
'device': task.device.id,
'priority': task.priority,
'out_date': task.out_date,
'state': task.state
})
if task_id == 0:
frm = TaskFrm(initial={
'recipient': frm_recipient_id
})
else:
frm = TaskFrm(instance=tsk)
return render(request, 'taskapp/add_edit_task.html', { return render(request, 'taskapp/add_edit_task.html', {
'warntext': warntext, 'warntext': warntext,
'form': frm, 'form': frm,
'task': task
'task_id': tsk.id
}) })

16
templates/abonapp/abonamount.html

@ -4,25 +4,29 @@
<legend>Начисление средств на счёт</legend> <legend>Начисление средств на счёт</legend>
{% if warntext %} {% if warntext %}
<div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
{{ warntext }}
</div>
<div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
{{ warntext }}
</div>
{% endif %} {% endif %}
<div class="row"> <div class="row">
<div class="col-sm-4"> <div class="col-sm-4">
<form role="form" action="{% url 'abon_amount_link' abon_group.id abon.id %}" method="post"> {% csrf_token %}
<form role="form" action="{% url 'abon_amount_link' abon_group.id abon.id %}"
method="post"> {% csrf_token %}
<div class="form-group-sm"> <div class="form-group-sm">
<label for="amount">Количество денег</label> <label for="amount">Количество денег</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon">&#8399;</span> <span class="input-group-addon">&#8399;</span>
<input id="amount" type="text" name="amount" placeholder="0.0" class="form-control" required pattern="\d+">
<input id="amount" type="text" name="amount" placeholder="0.0" class="form-control" required
pattern="\d+">
</div> </div>
</div> </div>
<input type="hidden" name="abonid" value="{{ abon.id }}"><br> <input type="hidden" name="abonid" value="{{ abon.id }}"><br>
<div class="btn-group"> <div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary"> <button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Пополнить <span class="glyphicon glyphicon-save"></span> Пополнить

52
templates/abonapp/activate_service.html

@ -2,35 +2,37 @@
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">Активировать услугу</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">Активировать услугу</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Активировать услугу</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'abonapp_activate_service' abon_group.id abon.id abtar.id %}" method="post">{% csrf_token %}
<input name="finish_confirm" value="yes" type="hidden">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Активировать услугу</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'abonapp_activate_service' abon_group.id abon.id abtar.id %}"
method="post">{% csrf_token %}
<input name="finish_confirm" value="yes" type="hidden">
<p>Вы уверены что хотите активировать абоненту эту услугу?<br>
Обратите внимание что с его счёта <b>снимутся деньги</b> и откроется доступ к ресурсам оплаченной услуги.<br>
Стоимость услуги: {{ amount }}руб. На счету {{ abon.ballance }} руб, останется {{ diff }} руб.</p>
<p>Вы уверены что хотите активировать абоненту эту услугу?<br>
Обратите внимание что с его счёта <b>снимутся деньги</b> и откроется доступ к ресурсам оплаченной
услуги.<br>
Стоимость услуги: {{ amount }}руб. На счету {{ abon.ballance }} руб, останется {{ diff }} руб.</p>
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Подтвердить
</button>
</form>
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Подтвердить
</button>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

128
templates/abonapp/addAbon.html

@ -1,75 +1,81 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %} {% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li class="active">Добавить абонента</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li class="active">Добавить абонента</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Добавьте аккаунт абонента</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'addabon_link' abon_group.id %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="login">Логин абонента</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
{{ form.username }}{{ form.username.errors }}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Добавьте аккаунт абонента</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'addabon_link' abon_group.id %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="login">Логин абонента</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
{{ form.username }}{{ form.username.errors }}
</div>
</div>
<div class="form-group">
<label for="fio">Фамилия Имя</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-bookmark"></span></span>
{{ form.fio }}{{ form.fio.errors }}
</div>
</div> </div>
</div>
<div class="form-group">
<label for="fio">Фамилия Имя</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-bookmark"></span></span>
{{ form.fio }}{{ form.fio.errors }}
<div class="form-group">
<label for="ip">IP Адрес</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-ice-lolly"></span></span>
{{ form.ip_address }}{{ form.ip_address.errors }}
</div>
</div> </div>
</div>
<div class="form-group">
<label for="ip">IP Адрес</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-ice-lolly"></span></span>
{{ form.ip_address }}{{ form.ip_address.errors }}
<div class="form-group">
<label for="telephone">Телефон</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-phone"></span></span>
{{ form.telephone }}{{ form.telephone.errors }}
</div>
</div> </div>
</div>
<div class="form-group">
<label for="telephone">Телефон</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-phone"></span></span>
{{ form.telephone }}{{ form.telephone.errors }}
<div class="form-group">
<label for="grp">Группа абонентов</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-grain"></span></span>
{{ form.group }}{{ form.group.errors }}
</div>
</div> </div>
</div>
<div class="form-group">
<label for="grp">Группа абонентов</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-grain"></span></span>
{{ form.group }}{{ form.group.errors }}
<div class="form-group">
<label for="address">Адрес проживания</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-map-marker"></span></span>
{{ form.address }}
</div>
</div> </div>
</div>
<div class="form-group">
<label for="address">Адрес проживания</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-map-marker"></span></span>
{{ form.address }}
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div> </div>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div>
</form>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

76
templates/abonapp/addGroup.html

@ -2,46 +2,50 @@
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li class="active">Добавить группу</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li class="active">Добавить группу</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Добавьте группу абонентов</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'addgroup_link' %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="gtitle">Название группы</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-bookmark"></span></span>
<input id="gtitle" type="text" name="title" placeholder="Название" required class="form-control">{{ form.title.errors }}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Добавьте группу абонентов</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'addgroup_link' %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="gtitle">Название группы</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-bookmark"></span></span>
<input id="gtitle" type="text" name="title" placeholder="Название" required
class="form-control">{{ form.title.errors }}
</div>
</div>
<div class="form-group">
<label for="gpos">Местоположение</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-map-marker"></span></span>
<input id="gpos" type="text" name="address" placeholder="Где находится"
class="form-control">{{ form.address.errors }}
</div>
</div> </div>
</div>
<div class="form-group">
<label for="gpos">Местоположение</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-map-marker"></span></span>
<input id="gpos" type="text" name="address" placeholder="Где находится" class="form-control">{{ form.address.errors }}
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div> </div>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div>
</form>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

79
templates/abonapp/addInvoice.html

@ -3,48 +3,53 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">Добавить долг</li>
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">Добавить долг</li>
</ol> </ol>
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Добавьте платёж на оплату для
<u><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></u>
</h3>
</div>
<div class="panel-body">
<form role="form" action="{% url 'abonapp_addinvoice_link' abon_group.id abon.id %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="pamount">Сумма для платежа</label>
<div class="input-group">
<span class="input-group-addon">&#8381;</span>
<input id="pamount" type="text" name="curr_amount" placeholder="0" required pattern="^\d+$" class="form-control">
<div class="panel-heading">
<h3 class="panel-title">Добавьте платёж на оплату для
<u><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></u>
</h3>
</div>
<div class="panel-body">
<form role="form" action="{% url 'abonapp_addinvoice_link' abon_group.id abon.id %}"
method="post">{% csrf_token %}
<div class="form-group">
<label for="pamount">Сумма для платежа</label>
<div class="input-group">
<span class="input-group-addon">&#8381;</span>
<input id="pamount" type="text" name="curr_amount" placeholder="0" required pattern="^\d+$"
class="form-control">
</div>
</div>
<div class="checkbox">
<label>
<input id="paystat" type="checkbox" name="status"{% if invcount == 0 %} checked{% endif %}>
Статус оплаты
</label>
</div>
<div class="form-group">
<label for="comm">Комментарий</label>
<textarea id="comm" name="comment" required maxlength="128" rows="3"
class="form-control"></textarea>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div> </div>
</div>
<div class="checkbox">
<label>
<input id="paystat" type="checkbox" name="status"{% if invcount == 0 %} checked{% endif %}> Статус оплаты
</label>
</div>
<div class="form-group">
<label for="comm">Комментарий</label>
<textarea id="comm" name="comment" required maxlength="128" rows="3" class="form-control"></textarea>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div>
</form>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

74
templates/abonapp/buy_tariff.html

@ -2,44 +2,48 @@
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">Заказать услугу</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">Заказать услугу</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Купить новую услугу (заказать тариф) для <a href="{% url 'abonhome_link' abon_group.id abon.id %}" title="На страницу абонента">абонента</a></h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert alert-danger alert-dismissable">
<button class="close" type="button" aria-hidden="true" data-dismiss="alert">&times;</button>
<strong>Внимание!</strong> {{ warntext|safe }}
</div>
{% endif %}
<form role="form" action="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="tariff">Выбирите тарифф</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-bullhorn"></span></span>
{{ form.tariff }}{{ form.tariff.errors }}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Купить новую услугу (заказать тариф) для <a
href="{% url 'abonhome_link' abon_group.id abon.id %}" title="На страницу абонента">абонента</a>
</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert alert-danger alert-dismissable">
<button class="close" type="button" aria-hidden="true" data-dismiss="alert">&times;</button>
<strong>Внимание!</strong> {{ warntext|safe }}
</div>
{% endif %}
<form role="form" action="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}"
method="post">{% csrf_token %}
<div class="form-group">
<label for="tariff">Выбирите тарифф</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-bullhorn"></span></span>
{{ form.tariff }}{{ form.tariff.errors }}
</div>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div> </div>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div>
</form>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

89
templates/abonapp/complete_service.html

@ -2,54 +2,57 @@
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">Завершить услугу</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Завершить услугу</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'abonapp_compl_srv' abon_group.id abon.id abtar.id %}" method="post">{% csrf_token %}
<input name="finish_confirm" value="yes" type="hidden">
<p>Досрочное завершение текущей услуги приведёт к тому что пользователю будет запрещён доступ к ресурсам услуги (закроется инет)<br/>
Для продолжения пользования ресурсами надо подключить нужную услугу</p>
<p>Подробнее:<br/>
Вы завершаете тариф <a href="{% url 'tarifs_edit_link' abtar.tariff.id %}" target="_blank">{{ abtar.tariff.title }}</a>.<br/>
Услуга была подключена: {{ abtar.time_start|date:'d F Y, H:i:s' }}<br/>
Сегодня: {% now "d F Y, H:i:s" %}<br/>
Время использования: {% if time_use.days %}{{ time_use.days }} дней.{% endif %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ abon.fio }}</a></li>
<li class="active">Завершить услугу</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Завершить услугу</h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'abonapp_compl_srv' abon_group.id abon.id abtar.id %}"
method="post">{% csrf_token %}
<input name="finish_confirm" value="yes" type="hidden">
<p>Досрочное завершение текущей услуги приведёт к тому что пользователю будет запрещён доступ к ресурсам
услуги (закроется инет)<br/>
Для продолжения пользования ресурсами надо подключить нужную услугу</p>
<p>Подробнее:<br/>
Вы завершаете тариф <a href="{% url 'tarifs_edit_link' abtar.tariff.id %}"
target="_blank">{{ abtar.tariff.title }}</a>.<br/>
Услуга была подключена: {{ abtar.time_start|date:'d F Y, H:i:s' }}<br/>
Сегодня: {% now "d F Y, H:i:s" %}<br/>
Время использования: {% if time_use.days %}{{ time_use.days }} дней.{% endif %}
{{ time_use.hours }} часов и {{ time_use.minutes }} минут.<br/> {{ time_use.hours }} часов и {{ time_use.minutes }} минут.<br/>
Полная стоимость услуги: {{ abtar.tariff.amount }}<br/>
Итоговая стоимость: {{ abtar.calc_amount_service }}
</p>
Полная стоимость услуги: {{ abtar.tariff.amount }}<br/>
Итоговая стоимость: {{ abtar.calc_amount_service }}
</p>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
<button type="reset" class="btn btn-sm btn-default">
<span class="glyphicon glyphicon-remove-circle"></span> Сбросить
</button>
</div>
</form>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

64
templates/abonapp/debtors.html

@ -3,44 +3,46 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li class="active">Должники</li>
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li class="active">Должники</li>
</ol> </ol>
<h3>Народ, у которого есть неоплаченные услуги</h3> <h3>Народ, у которого есть неоплаченные услуги</h3>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="15">#</th>
<th>Абонент</th>
<th>Цена</th>
<th>Комментарий</th>
<th>Дата создания</th>
<th>Автор</th>
</tr>
</thead>
<tbody>
{% for invoice in invoices %}
<table class="table table-striped table-bordered">
<thead>
<tr> <tr>
<td>{{ invoice.id }}</td>
<td><a href="{% url 'abonhome_link' invoice.abon.group.id invoice.abon.id %}" target="_blank">{{ invoice.abon.username }}</a></td>
<td>{{ invoice.amount }}</td>
<td>{{ invoice.comment}}</td>
<td>{{ invoice.date_create|date:'d b H:i' }}</td>
<td><a href="{% url 'other_profile' invoice.author.id %}" target="_blank">{{ invoice.author.username }}</a></td>
<th width="15">#</th>
<th>Абонент</th>
<th>Цена</th>
<th>Комментарий</th>
<th>Дата создания</th>
<th>Автор</th>
</tr> </tr>
{% empty %}
<tr>
<td colspan="7">
Нет должников
</td>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for invoice in invoices %}
<tr>
<td>{{ invoice.id }}</td>
<td><a href="{% url 'abonhome_link' invoice.abon.group.id invoice.abon.id %}"
target="_blank">{{ invoice.abon.username }}</a></td>
<td>{{ invoice.amount }}</td>
<td>{{ invoice.comment }}</td>
<td>{{ invoice.date_create|date:'d b H:i' }}</td>
<td><a href="{% url 'other_profile' invoice.author.id %}"
target="_blank">{{ invoice.author.username }}</a></td>
</tr>
{% empty %}
<tr>
<td colspan="7">
Нет должников
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div> </div>
{% include 'toolbar_page.html' with pag=peoples %} {% include 'toolbar_page.html' with pag=peoples %}

14
templates/abonapp/editAbon.html

@ -3,10 +3,10 @@
{% if warntext %} {% if warntext %}
<div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
{{ warntext }}
</div>
<div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
{{ warntext }}
</div>
{% endif %} {% endif %}
<div class="row"> <div class="row">
@ -55,7 +55,8 @@
<br> <br>
<button type="submit" class="btn btn-default btn-sm"> <button type="submit" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-save"></span> Сохранить</button>
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
</form> </form>
</div> </div>
@ -77,7 +78,8 @@
<br> <br>
<button type="submit" class="btn btn-default btn-sm"> <button type="submit" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-save"></span> Сохранить</button>
<span class="glyphicon glyphicon-save"></span> Сохранить
</button>
</form> </form>
</div> </div>
<div class="col-sm-4"> <div class="col-sm-4">

38
templates/abonapp/ext.htm

@ -2,30 +2,38 @@
{% block main %} {% block main %}
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li class="active">{{ abon.fio }}</li>
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li><a href="{% url 'people_list_link' abon_group.id %}">{{ abon_group.title }}</a></li>
<li class="active">{{ abon.fio }}</li>
</ol> </ol>
{% if warntext %} {% if warntext %}
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<strong>Предупреждение!</strong> {{ warntext }}
</div>
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<strong>Предупреждение!</strong> {{ warntext }}
</div>
{% endif %} {% endif %}
<div class="page-header"> <div class="page-header">
<h2>{{ abon.fio|default:"Имя абонента" }} <small>Балланс <i class="glyphicon glyphicon-ruble"></i>
<b>{{ ballance }}</b> руб</small></h2>
<h2>{{ abon.fio|default:"Имя абонента" }}
<small>Балланс <i class="glyphicon glyphicon-ruble"></i>
<b>{{ ballance }}</b> руб
</small>
</h2>
</div> </div>
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="#livetab_content" data-tab-remote="{% url 'abonhome_link' abon_group.id abon.id %}" role="tab" data-toggle="tab">Информация абонента</a></li>
<li><a href="#livetab_content" data-tab-remote="{% url 'abon_services_link' abon_group.id abon.id %}" role="tab" data-toggle="tab">Услуги</a></li>
<li><a href="#livetab_content" data-tab-remote="{% url 'abon_amount_link' abon_group.id abon.id %}" role="tab" data-toggle="tab">Пополнить счёт</a></li>
<li><a href="#livetab_content" data-tab-remote="{% url 'abon_debts_link' abon_group.id abon.id %}" role="tab" data-toggle="tab">Долги</a></li>
<li><a href="#livetab_content" data-tab-remote="{% url 'abon_phistory_link' abon_group.id abon.id %}" role="tab" data-toggle="tab">История платежей</a></li>
<li class="active"><a href="#livetab_content" data-tab-remote="{% url 'abonhome_link' abon_group.id abon.id %}"
role="tab" data-toggle="tab">Информация абонента</a></li>
<li><a href="#livetab_content" data-tab-remote="{% url 'abon_services_link' abon_group.id abon.id %}" role="tab"
data-toggle="tab">Услуги</a></li>
<li><a href="#livetab_content" data-tab-remote="{% url 'abon_amount_link' abon_group.id abon.id %}" role="tab"
data-toggle="tab">Пополнить счёт</a></li>
<li><a href="#livetab_content" data-tab-remote="{% url 'abon_debts_link' abon_group.id abon.id %}" role="tab"
data-toggle="tab">Долги</a></li>
<li><a href="#livetab_content" data-tab-remote="{% url 'abon_phistory_link' abon_group.id abon.id %}" role="tab"
data-toggle="tab">История платежей</a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">

116
templates/abonapp/group_list.html

@ -3,74 +3,74 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li class="active">Группы абонентов</li>
<li><span class="glyphicon glyphicon-home"></span></li>
<li class="active">Группы абонентов</li>
</ol> </ol>
<h3>Группы абонентов</h3> <h3>Группы абонентов</h3>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="50">#</th>
<th>
<a href="{% url 'abongroup_list_link' %}?order_by=title&dir={{ dir|default:"down" }}">
Название группы
</a>
{% if order_by == 'title' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th>
<a href="{% url 'abongroup_list_link' %}?order_by=address&dir={{ dir|default:"down" }}">
Адресс группы
</a>
{% if order_by == 'address' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th>
Количество абонентов
</th>
<th width="100">Do</th>
</tr>
</thead>
<tbody>
{% for gr in groups %}
<table class="table table-striped table-bordered">
<thead>
<tr> <tr>
<td>{{ gr.id }}</td>
<td><a href="{% url 'people_list_link' gr.id %}">{{ gr.title }}</a></td>
<td>{{ gr.address }}</td>
<td>{{ gr.usercount }}</td>
<td>
{% if gr.usercount > 0 %}
<a href="#" class="btn btn-sm btn-default disabled">
{% else %}
<a href="{% url 'people_delgroup_link' %}?t=a&id={{ gr.id }}" class="btn btn-sm btn-danger">
{% endif %}
<span class="glyphicon glyphicon-remove-circle"></span></a>
</td>
<th width="50">#</th>
<th>
<a href="{% url 'abongroup_list_link' %}?order_by=title&dir={{ dir|default:"down" }}">
Название группы
</a>
{% if order_by == 'title' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th>
<a href="{% url 'abongroup_list_link' %}?order_by=address&dir={{ dir|default:"down" }}">
Адресс группы
</a>
{% if order_by == 'address' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th>
Количество абонентов
</th>
<th width="100">Do</th>
</tr> </tr>
{% empty %}
</thead>
<tbody>
{% for gr in groups %}
<tr>
<td>{{ gr.id }}</td>
<td><a href="{% url 'people_list_link' gr.id %}">{{ gr.title }}</a></td>
<td>{{ gr.address }}</td>
<td>{{ gr.usercount }}</td>
<td>
{% if gr.usercount > 0 %}
<a href="#" class="btn btn-sm btn-default disabled">
{% else %}
<a href="{% url 'people_delgroup_link' %}?t=a&id={{ gr.id }}" class="btn btn-sm btn-danger">
{% endif %}
<span class="glyphicon glyphicon-remove-circle"></span></a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="5"><a href="#">Ещё нет групп</a></td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr> <tr>
<td colspan="5"><a href="#">Ещё нет групп</a></td>
<td colspan="5" class="btn-group">
<a href="{% url 'addgroup_link' %}" class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-plus"></span> Создать группу
</a>
<a href="{% url 'abonapp_log_link' %}" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-record"></span> Действия абонентов
</a>
<a href="{% url 'abonapp_debtors' %}" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-exclamation-sign"></span> Список должников
</a>
</td>
</tr> </tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="5" class="btn-group">
<a href="{% url 'addgroup_link' %}" class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-plus"></span> Создать группу
</a>
<a href="{% url 'abonapp_log_link' %}" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-record"></span> Действия абонентов
</a>
<a href="{% url 'abonapp_debtors' %}" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-exclamation-sign"></span> Список должников
</a>
</td>
</tr>
</tfoot>
</table>
</tfoot>
</table>
</div> </div>
{% include 'toolbar_page.html' with pag=groups %} {% include 'toolbar_page.html' with pag=groups %}

94
templates/abonapp/invoiceForPayment.html

@ -1,50 +1,54 @@
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} {% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %}
{% block content %} {% block content %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Статус</th>
<th>Месяц</th>
<th>Стоимость</th>
<th>Комментарий</th>
<th>Дата создания</th>
<th>Дата оплаты</th>
<th>Назначил</th>
</tr>
</thead>
<tbody>
{% for inv in invoices %}
<tr>
<td>{% if inv.status %}
<span class="glyphicon glyphicon-ok"></span>
{% else %}
<span class="glyphicon glyphicon-time"></span>
{% endif %}</td>
<td>{{ inv.date_create|date:"F" }}</td>
<td>{{ inv.amount }}</td>
<td>{{ inv.comment }}</td>
<td>{{ inv.date_create|date:"D d E Y H:i:s" }}</td>
<td>
{% if inv.date_pay %}
{{ inv.date_pay|date:"D d M Y H:i:s" }}
{% else %}
{{ inv.status|yesno:'Создан оплаченным,Ещё не оплачено' }}
{% endif %}
</td>
<td><a href="{% url 'other_profile' inv.author.id %}" target="_blank">{{ inv.author.username }}</a></td>
</tr>
{% empty %}
<tr><td colspan="7">Назначенные платежи отсутствуют</td></tr>
{% endfor %}
</tbody>
<tfoot>
<tr><th colspan="7">
<a href="{% url 'abonapp_addinvoice_link' abon_group.id abon.id %}" class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-plus"></span> Добавить
</a>
</th></tr>
</tfoot>
</table>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Статус</th>
<th>Месяц</th>
<th>Стоимость</th>
<th>Комментарий</th>
<th>Дата создания</th>
<th>Дата оплаты</th>
<th>Назначил</th>
</tr>
</thead>
<tbody>
{% for inv in invoices %}
<tr>
<td>{% if inv.status %}
<span class="glyphicon glyphicon-ok"></span>
{% else %}
<span class="glyphicon glyphicon-time"></span>
{% endif %}</td>
<td>{{ inv.date_create|date:"F" }}</td>
<td>{{ inv.amount }}</td>
<td>{{ inv.comment }}</td>
<td>{{ inv.date_create|date:"D d E Y H:i:s" }}</td>
<td>
{% if inv.date_pay %}
{{ inv.date_pay|date:"D d M Y H:i:s" }}
{% else %}
{{ inv.status|yesno:'Создан оплаченным,Ещё не оплачено' }}
{% endif %}
</td>
<td><a href="{% url 'other_profile' inv.author.id %}" target="_blank">{{ inv.author.username }}</a></td>
</tr>
{% empty %}
<tr>
<td colspan="7">Назначенные платежи отсутствуют</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<th colspan="7">
<a href="{% url 'abonapp_addinvoice_link' abon_group.id abon.id %}" class="btn btn-success btn-sm">
<span class="glyphicon glyphicon-plus"></span> Добавить
</a>
</th>
</tr>
</tfoot>
</table>
{% endblock %} {% endblock %}

56
templates/abonapp/log.html

@ -2,16 +2,16 @@
{% block main %} {% block main %}
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li class="active">История действий абонентов</li>
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li class="active">История действий абонентов</li>
</ol> </ol>
<h3>История абонента</h3> <h3>История абонента</h3>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<table class="table table-striped table-bordered">
<thead>
<tr> <tr>
<th>Сумма</th> <th>Сумма</th>
<th>Абонент</th> <th>Абонент</th>
@ -19,29 +19,29 @@
<th width="250">Время</th> <th width="250">Время</th>
<th width="150">Автор</th> <th width="150">Автор</th>
</tr> </tr>
</thead>
<tbody>
{% for l in logs %}
<tr>
<td>{% if l.amount >= 0 %}
<span class="glyphicon glyphicon-hand-up"></span>
{% else %}
<span class="glyphicon glyphicon-hand-down"></span>
{% endif %} {{ l.amount }}</td>
<td><a href="{% url 'abonhome_link' l.abon.group.id l.abon.id %}">{{ l.abon.username }}</a></td>
<td>{{ l.comment }}</td>
<td>{{ l.date|date:"D d E Y H:i:s" }}</td>
<td><a href="{% url 'other_profile' l.author.id %}">{{ l.author.username }}</a></td>
</tr>
{% empty %}
<tr>
<td colspan="5">Нет событий</td>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for l in logs %}
<tr>
<td>{% if l.amount >= 0 %}
<span class="glyphicon glyphicon-hand-up"></span>
{% else %}
<span class="glyphicon glyphicon-hand-down"></span>
{% endif %} {{ l.amount }}</td>
<td><a href="{% url 'abonhome_link' l.abon.group.id l.abon.id %}">{{ l.abon.username }}</a></td>
<td>{{ l.comment }}</td>
<td>{{ l.date|date:"D d E Y H:i:s" }}</td>
<td><a href="{% url 'other_profile' l.author.id %}">{{ l.author.username }}</a></td>
</tr>
{% empty %}
<tr>
<td colspan="5">Нет событий</td>
</tr>
{% endfor %}
</tbody>
</table>
</div> </div>
{% include 'toolbar_page.html' with pag=logs %} {% include 'toolbar_page.html' with pag=logs %}

51
templates/abonapp/payHistory.html

@ -1,30 +1,33 @@
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} {% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %}
{% block content %} {% block content %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Абонент</th>
<th>Сумма</th>
<th>Дата транзакции</th>
<th>Автор платежа</th>
<th>Комментарий</th>
</tr>
</thead>
<tbody>
{% for ph in pay_history %}<tr>
<td><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ ph.abon.username }}</a></td>
<td>{{ ph.amount }}</td>
<td>{{ ph.date|date:'d F Y, H:i:s' }}</td>
<td><a target="_blank" href="{% url 'other_profile' ph.author.id %}">{{ ph.author.username }}</a></td>
<td>{{ ph.comment }}</td>
</tr>
{% empty %}
<tr><td colspan="5">История платежей пуста</td></tr>
{% endfor %}
</tbody>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Абонент</th>
<th>Сумма</th>
<th>Дата транзакции</th>
<th>Автор платежа</th>
<th>Комментарий</th>
</tr>
</thead>
<tbody>
{% for ph in pay_history %}
<tr>
<td><a href="{% url 'abonhome_link' abon_group.id abon.id %}">{{ ph.abon.username }}</a></td>
<td>{{ ph.amount }}</td>
<td>{{ ph.date|date:'d F Y, H:i:s' }}</td>
<td><a target="_blank" href="{% url 'other_profile' ph.author.id %}">{{ ph.author.username }}</a></td>
<td>{{ ph.comment }}</td>
</tr>
{% empty %}
<tr>
<td colspan="5">История платежей пуста</td>
</tr>
{% endfor %}
</tbody>
</table>
</table>
{% include 'toolbar_page.html' with pag=pay_history %}
{% include 'toolbar_page.html' with pag=pay_history %}
{% endblock %} {% endblock %}

116
templates/abonapp/peoples.html

@ -3,52 +3,54 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li class="active">{{ abon_group.title }}</li>
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'abongroup_list_link' %}">Группы абонентов</a></li>
<li class="active">{{ abon_group.title }}</li>
</ol> </ol>
<h3>Народ в выбранной группе</h3> <h3>Народ в выбранной группе</h3>
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="15">#</th>
<th>
<a href="{% url 'people_list_link' abon_group.id %}?order_by=username&dir={{ dir|default:"down" }}">
Абонент
</a>
{% if order_by == 'username' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th>
<a href="{% url 'people_list_link' abon_group.id %}?order_by=ip_address&dir={{ dir|default:"down" }}">
IP Адрес
</a>
{% if order_by == 'ip_address' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th>
<a href="{% url 'people_list_link' abon_group.id %}?order_by=fio&dir={{ dir|default:"down" }}">
ФИО
</a>
{% if order_by == 'fio' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th width="50">
<a href="{% url 'people_list_link' abon_group.id %}?order_by=ballance&dir={{ dir|default:"down" }}">
Балланс
</a>
{% if order_by == 'ballance' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th width="150">Телефон</th>
<th width="150">Тариф</th>
<th width="100">Do</th>
</tr>
</thead>
<tbody>
{% for human in peoples %}
{% if human.is_active %}<tr>
{% else %}<tr class="danger">
{% endif %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="15">#</th>
<th>
<a href="{% url 'people_list_link' abon_group.id %}?order_by=username&dir={{ dir|default:"down" }}">
Абонент
</a>
{% if order_by == 'username' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th>
<a href="{% url 'people_list_link' abon_group.id %}?order_by=ip_address&dir={{ dir|default:"down" }}">
IP Адрес
</a>
{% if order_by == 'ip_address' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th>
<a href="{% url 'people_list_link' abon_group.id %}?order_by=fio&dir={{ dir|default:"down" }}">
ФИО
</a>
{% if order_by == 'fio' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th width="50">
<a href="{% url 'people_list_link' abon_group.id %}?order_by=ballance&dir={{ dir|default:"down" }}">
Балланс
</a>
{% if order_by == 'ballance' %}<span class="glyphicon glyphicon-filter"></span>{% endif %}
</th>
<th width="150">Телефон</th>
<th width="150">Тариф</th>
<th width="100">Do</th>
</tr>
</thead>
<tbody>
{% for human in peoples %}
{% if human.is_active %}
<tr>
{% else %}
<tr class="danger">
{% endif %}
<td>{{ human.id }}</td> <td>{{ human.id }}</td>
<td><a href="{% url 'abonhome_link' human.group.id human.id %}">{{ human.username }}</a></td> <td><a href="{% url 'abonhome_link' human.group.id human.id %}">{{ human.username }}</a></td>
<td>{{ human.ip_address|default:'Не назначен' }}</td> <td>{{ human.ip_address|default:'Не назначен' }}</td>
@ -58,31 +60,31 @@
<td> <td>
{% if human.active_tariff %} {% if human.active_tariff %}
<a href="{% url 'tarifs_edit_link' human.active_tariff.id %}">{{ human.active_tariff.title }}</a> <a href="{% url 'tarifs_edit_link' human.active_tariff.id %}">{{ human.active_tariff.title }}</a>
{% else %}&mdash;&mdash;&mdash;
{% else %}&mdash;&mdash;&mdash;
{% endif %} {% endif %}
</td> </td>
<td><a href="{% url 'abonapp_del_link' %}?t=a&id={{ human.id }}" class="btn btn-danger btn-sm"> <td><a href="{% url 'abonapp_del_link' %}?t=a&id={{ human.id }}" class="btn btn-danger btn-sm">
<span class="glyphicon glyphicon-remove"></span> <span class="glyphicon glyphicon-remove"></span>
</a></td> </a></td>
</tr>
{% empty %}
</tr>
{% empty %}
<tr>
<td colspan="8">
Ещё нет абонентов, <a href="{% url 'addabon_link' abon_group.id %}">добавить</a>
</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr> <tr>
<td colspan="8"> <td colspan="8">
Ещё нет абонентов, <a href="{% url 'addabon_link' abon_group.id %}">добавить</a>
<a href="{% url 'addabon_link' abon_group.id %}" class="btn btn-sm btn-default" title="Добавить">
<span class="glyphicon glyphicon-plus"></span> Добавить абонента
</a>
</td> </td>
</tr> </tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="8">
<a href="{% url 'addabon_link' abon_group.id %}" class="btn btn-sm btn-default" title="Добавить">
<span class="glyphicon glyphicon-plus"></span> Добавить абонента
</a>
</td>
</tr>
</tfoot>
</table>
</tfoot>
</table>
</div> </div>
{% include 'toolbar_page.html' with pag=peoples %} {% include 'toolbar_page.html' with pag=peoples %}

127
templates/abonapp/services.html

@ -1,68 +1,79 @@
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %} {% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %}
{% block content %} {% block content %}
<legend>Купленные абонентом услуги (назначенные тарифные планы)</legend>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="50">Приоритет</th>
<th>Тариф</th>
<th>Стоимость</th>
<th>Входящая скорость</th>
<th>Исходящая скорость</th>
<th>Время действия</th>
<th>Ред.</th>
</tr>
</thead>
<legend>Купленные абонентом услуги (назначенные тарифные планы)</legend>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="50">Приоритет</th>
<th>Тариф</th>
<th>Стоимость</th>
<th>Входящая скорость</th>
<th>Исходящая скорость</th>
<th>Время действия</th>
<th>Ред.</th>
</tr>
</thead>
<tbody>
{% for trf in abon_tarifs %}
<tr{% if trf.id == active_abontariff_id %} class="active"{% endif %}>
<td>{{ trf.tariff_priority }}</td>
<td><a href="{% url 'tarifs_edit_link' trf.tariff.id %}" title="{{ trf.time_start|default:'' }}">{{ trf.tariff.title }}</a></td>
<td>{{ trf.tariff.amount }}</td>
<td>{{ trf.tariff.speedIn }}</td>
<td>{{ trf.tariff.speedOut }}</td>
<td>{{ trf.tariff.time_of_action }}</td>
{% if trf.id != active_abontariff_id %}
<td class="btn-group">
{% if not active_abontariff_id %}
<a href="{% url 'abonapp_activate_service' abon_group.id abon.id trf.id %}" class="btn btn-success btn-sm" title="Активировать услугу">
<i class="glyphicon glyphicon-shopping-cart"></i>
</a>
<tbody>
{% for trf in abon_tarifs %}
<tr{% if trf.id == active_abontariff_id %} class="active"{% endif %}>
<td>{{ trf.tariff_priority }}</td>
<td><a href="{% url 'tarifs_edit_link' trf.tariff.id %}"
title="{{ trf.time_start|default:'' }}">{{ trf.tariff.title }}</a></td>
<td>{{ trf.tariff.amount }}</td>
<td>{{ trf.tariff.speedIn }}</td>
<td>{{ trf.tariff.speedOut }}</td>
<td>{{ trf.tariff.time_of_action }}</td>
{% if trf.id != active_abontariff_id %}
<td class="btn-group">
{% if not active_abontariff_id %}
<a href="{% url 'abonapp_activate_service' abon_group.id abon.id trf.id %}"
class="btn btn-success btn-sm" title="Активировать услугу">
<i class="glyphicon glyphicon-shopping-cart"></i>
</a>
{% endif %}
<a href="{% url 'abonapp_chpriority_tariff' abon_group.id abon.id %}?t={{ trf.id }}&a=up"
class="btn btn-default btn-sm" title="Повысить приоритет">
<i class="glyphicon glyphicon-hand-up"></i>
</a>
<a href="{% url 'abonapp_chpriority_tariff' abon_group.id abon.id %}?t={{ trf.id }}&a=down"
class="btn btn-default btn-sm" title="Понизить приоритет">
<i class="glyphicon glyphicon-hand-down"></i>
</a>
<a href="{% url 'abonapp_unsubscribe_service' abon_group.id abon.id trf.id %}"
class="btn btn-danger btn-sm" title="Удалить услугу">
<i class="glyphicon glyphicon-remove"></i>
</a>
</td>
{% else %}
<td>
<a href="{% url 'abonapp_compl_srv' abon_group.id abon.id trf.id %}"
title="Завершить услугу досрочно" class="btn btn-danger btn-sm">
<i class="glyphicon glyphicon-remove"></i> Завершить
</a>
</td>
{% endif %} {% endif %}
<a href="{% url 'abonapp_chpriority_tariff' abon_group.id abon.id %}?t={{ trf.id }}&a=up" class="btn btn-default btn-sm" title="Повысить приоритет">
<i class="glyphicon glyphicon-hand-up"></i>
</a>
<a href="{% url 'abonapp_chpriority_tariff' abon_group.id abon.id %}?t={{ trf.id }}&a=down" class="btn btn-default btn-sm" title="Понизить приоритет">
<i class="glyphicon glyphicon-hand-down"></i>
</a>
<a href="{% url 'abonapp_unsubscribe_service' abon_group.id abon.id trf.id %}" class="btn btn-danger btn-sm" title="Удалить услугу">
<i class="glyphicon glyphicon-remove"></i>
</a>
</td>
{% else %}
<td>
<a href="{% url 'abonapp_compl_srv' abon_group.id abon.id trf.id %}" title="Завершить услугу досрочно" class="btn btn-danger btn-sm">
<i class="glyphicon glyphicon-remove"></i> Завершить
</a>
</td>
{% endif %}
</tr>
{% empty %}
<tr><td colspan="7">Нет подключённых абоненту услуг, <a href="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" class="lgtbx">купить</a></td></tr>
{% endfor %}
</tbody>
</tr>
{% empty %}
<tr>
<td colspan="7">Нет подключённых абоненту услуг, <a
href="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" class="lgtbx">купить</a></td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr><th colspan="7">
<a href="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" class="btn btn-sm btn-success">
<span class="glyphicon glyphicon-plus"></span> Купить услугу
</a>
</th></tr>
</tfoot>
<tfoot>
<tr>
<th colspan="7">
<a href="{% url 'abonapp_buy_tariff' abon_group.id abon.id %}" class="btn btn-sm btn-success">
<span class="glyphicon glyphicon-plus"></span> Купить услугу
</a>
</th>
</tr>
</tfoot>
</table>
</table>
{% endblock %} {% endblock %}

119
templates/accounts/acc_list.html

@ -1,67 +1,72 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li class="active">Администраторы</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li class="active">Администраторы</li>
</ol>
<h3>Список аккаунтов администраторов</h3>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th class="col-sm-1">Фото</th>
<th>Ник</th>
<th>ФИО (или ник если нет)</th>
<th class="col-sm-2">Телефон</th>
<th class="col-sm-2">Skype</th>
<th width="150">&mdash;</th>
</tr>
</thead>
<tbody>
{% for usr in users %}
<h3>Список аккаунтов администраторов</h3>
<div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr> <tr>
<td><a href="{% url 'other_profile' usr.id %}">
<img width="50" src="{{ usr.avatar.min|default:"/static/img/user_ava.gif" }}" alt="{{ usr.username }}"/>
</a></td>
<td><a href="{% url 'other_profile' usr.id %}">{{ usr.username }}</a></td>
<td>{{ usr.get_full_name }}</td>
<td>{% if usr.telephone %}<a href="tel:{{ usr.telephone }}">{{ usr.telephone }}</a>{% else %}Нету{% endif %}</td>
<td>{% if usr.skype %}<a href="skype:{{ usr.skype }}?call">{{ usr.skype }}{% else %}Нету{% endif %}</a></td>
<td class="btn-group">
<a href="{% url 'profile_appoint_task' usr.id %}" class="btn btn-sm btn-default" title="Дать задание">
<span class="glyphicon glyphicon-tasks"></span>
</a>
<a href="{% url 'privmsg_send_message' %}?a={{ usr.id }}" class="btn btn-sm btn-info" title="Отправить сообщение">
<span class="glyphicon glyphicon-envelope"></span>
</a>
<a href="#" class="btn btn-sm btn-danger">
<span class="glyphicon glyphicon-remove"></span>
</a>
</td>
<th class="col-sm-1">Фото</th>
<th>Ник</th>
<th>ФИО (или ник если нет)</th>
<th class="col-sm-2">Телефон</th>
<th class="col-sm-2">Skype</th>
<th width="150">&mdash;</th>
</tr> </tr>
{% empty %}
<tr>
<td colspan="6"><b>Нет пользователей</b></td>
</tr>
{% endfor %}
</tbody>
{% if request.user.is_superuser %}
<tfoot>
<tr>
<th colspan="6">
<a href="{% url 'create_profile_link' %}" class="btn btn-default" title="Добавить аккаунт">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
</th>
</tr>
</tfoot>
{% endif %}
</table>
</div>
</thead>
<tbody>
{% for usr in users %}
<tr>
<td><a href="{% url 'other_profile' usr.id %}">
<img width="50" src="{{ usr.avatar.min|default:"/static/img/user_ava.gif" }}"
alt="{{ usr.username }}"/>
</a></td>
<td><a href="{% url 'other_profile' usr.id %}">{{ usr.username }}</a></td>
<td>{{ usr.get_full_name }}</td>
<td>{% if usr.telephone %}<a href="tel:{{ usr.telephone }}">{{ usr.telephone }}</a>{% else %}
Нету{% endif %}</td>
<td>{% if usr.skype %}<a href="skype:{{ usr.skype }}?call">{{ usr.skype }}{% else %}
Нету{% endif %}</a></td>
<td class="btn-group">
<a href="{% url 'profile_appoint_task' usr.id %}" class="btn btn-sm btn-default"
title="Дать задание">
<span class="glyphicon glyphicon-tasks"></span>
</a>
<a href="{% url 'privmsg_send_message' %}?a={{ usr.id }}" class="btn btn-sm btn-info"
title="Отправить сообщение">
<span class="glyphicon glyphicon-envelope"></span>
</a>
<a href="#" class="btn btn-sm btn-danger">
<span class="glyphicon glyphicon-remove"></span>
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6"><b>Нет пользователей</b></td>
</tr>
{% endfor %}
</tbody>
{% if request.user.is_superuser %}
<tfoot>
<tr>
<th colspan="6">
<a href="{% url 'create_profile_link' %}" class="btn btn-default" title="Добавить аккаунт">
<span class="glyphicon glyphicon-plus-sign"></span>
</a>
</th>
</tr>
</tfoot>
{% endif %}
</table>
</div>
{% include 'toolbar_page.html' with pag=users %}
{% include 'toolbar_page.html' with pag=users %}
{% endblock %} {% endblock %}

166
templates/accounts/create_acc.html

@ -1,93 +1,111 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %} {% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li>
<li class="active">Добавить</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li>
<li class="active">Добавить</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Создайте новый аккаунт</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-3">
<div class="thumbnail">
<img alt="Avatar" src="/static/img/user_ava.gif"/>
<div class="caption">
<input type="file" name="avatar"/>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Создайте новый аккаунт</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-3">
<div class="thumbnail">
<img alt="Avatar" src="/static/img/user_ava.gif"/>
<div class="caption">
<input type="file" name="avatar"/>
</div>
</div> </div>
</div> </div>
</div>
<div class="col-sm-9">
{% if warntext %}
<div class="alert-info">{{ warntext }}</div>
{% endif %}
<div class="col-sm-9">
{% if warntext %}
<div class="alert-info">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'create_profile_link' %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="login">Логин</label>
<form role="form" action="{% url 'create_profile_link' %}" method="post">{% csrf_token %}
<div class="form-group">
<label for="login">Логин</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="login" type="text" name="username" placeholder="Имя пользователя" required value="{{ newuser.username }}" class="form-control">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="login" type="text" name="username" placeholder="Имя пользователя" required
value="{{ newuser.username }}" class="form-control">
</div>
</div> </div>
</div>
<div class="form-group">
<label for="fio">Фамилия Имя</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-folder-close"></span></span>
<input id="fio" type="text" name="fio" placeholder="ФИО" value="{{ newuser.fio }}" class="form-control">
<div class="form-group">
<label for="fio">Фамилия Имя</label>
<div class="input-group">
<span class="input-group-addon"><span
class="glyphicon glyphicon-folder-close"></span></span>
<input id="fio" type="text" name="fio" placeholder="ФИО" value="{{ newuser.fio }}"
class="form-control">
</div>
</div> </div>
</div>
<div class="form-group">
<label for="mail">Почта</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span></span>
<input id='mail' type="text" name="email" placeholder="Email" value="{{ newuser.email }}" class="form-control">
<div class="form-group">
<label for="mail">Почта</label>
<div class="input-group">
<span class="input-group-addon"><span
class="glyphicon glyphicon-envelope"></span></span>
<input id='mail' type="text" name="email" placeholder="Email"
value="{{ newuser.email }}" class="form-control">
</div>
</div> </div>
</div>
<div class="form-group">
<label for="tel">Телефон</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-phone"></span></span>
<input id="tel" type="tel" pattern="\+[7,8,9,3]\d{10,11}" name="telephone" placeholder="+[7,8,9,3] и 10,11 цифр" value="{{ newuser.telephone }}" class="form-control" required>
<div class="form-group">
<label for="tel">Телефон</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-phone"></span></span>
<input id="tel" type="tel" pattern="\+[7,8,9,3]\d{10,11}" name="telephone"
placeholder="+[7,8,9,3] и 10,11 цифр" value="{{ newuser.telephone }}"
class="form-control" required>
</div>
</div> </div>
</div>
<div class="form-group">
<label for="skype"><a title="Что это" target="_blank" href="http://lurkmore.to/Skype">Skype</a></label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-earphone"></span></span>
<input id="skype" type="text" value="{{ newuser.skype }}" name="skype" placeholder="Skype" class="form-control">
<div class="form-group">
<label for="skype"><a title="Что это" target="_blank"
href="http://lurkmore.to/Skype">Skype</a></label>
<div class="input-group">
<span class="input-group-addon"><span
class="glyphicon glyphicon-earphone"></span></span>
<input id="skype" type="text" value="{{ newuser.skype }}" name="skype"
placeholder="Skype" class="form-control">
</div>
</div> </div>
</div>
<div class="form-group">
<label for="passw1">Введите пароль</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
<input id="passw1" type="password" name="passwd" required class="form-control">
<div class="form-group">
<label for="passw1">Введите пароль</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
<input id="passw1" type="password" name="passwd" required class="form-control">
</div>
</div> </div>
</div>
<div class="form-group">
<label for="passw2">Повторите пароль</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
<input id="passw2" type="password" name="conpasswd" required class="form-control">
<div class="form-group">
<label for="passw2">Повторите пароль</label>
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
<input id="passw2" type="password" name="conpasswd" required class="form-control">
</div>
</div> </div>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-primary">
<span class="glyphicon glyphicon-floppy-disk"></span> Сохранить
</button>
<button type="reset" class="btn btn-default">
<span class="glyphicon glyphicon-remove"></span> Сбросить
</button>
</div>
</form>
<div class="btn-group">
<button type="submit" class="btn btn-primary">
<span class="glyphicon glyphicon-floppy-disk"></span> Сохранить
</button>
<button type="reset" class="btn btn-default">
<span class="glyphicon glyphicon-remove"></span> Сбросить
</button>
</div>
</form>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}

24
templates/accounts/ext.htm

@ -1,11 +1,11 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %} {% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li>
<li class="active">{{ userprofile.username }}</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li>
<li class="active">{{ userprofile.username }}</li>
</ol>
<div class="row"> <div class="row">
@ -16,9 +16,11 @@
{% else %} {% else %}
<img alt="ava" src="/static/img/user_ava.gif"/> <img alt="ava" src="/static/img/user_ava.gif"/>
{% endif %} {% endif %}
<div class="caption">
<a href="{% url 'settings_chinfo_link' %}" class="btn btn-primary" role="button">Редактировать</a>
<a href="#" class="btn btn-default" role="button" data-toggle="modal" data-target="#modFrm">###</a>
<div class="caption btn-group btn-group-sm">
<a href="{% url 'settings_chinfo_link' %}" class="btn btn-primary btn-sm" role="button">
<span class="glyphicon glyphicon-edit"></span> Редактировать</a>
<a href="{% url 'task_add' %}?rp={{ userprofile.id }}" class="btn btn-default btn-sm" role="button">
<span class="glyphicon glyphicon-star-empty"></span> Дать задачу</a>
</div> </div>
</div> </div>
</div> </div>
@ -27,12 +29,14 @@
<h3>{{ userprofile.username|default:"&lt;Нет ника&gt;" }}</h3> <h3>{{ userprofile.username|default:"&lt;Нет ника&gt;" }}</h3>
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"> <li class="active">
<a href="#livetab_content" data-tab-remote="{% url 'other_profile' uid %}" role="tab" data-toggle="tab">
<a href="#livetab_content" data-tab-remote="{% url 'other_profile' uid %}" role="tab"
data-toggle="tab">
Администратор Администратор
</a> </a>
</li> </li>
<li> <li>
<a href="#livetab_content" data-tab-remote="{% url 'profile_chgroup_link' uid %}" role="tab" data-toggle="tab">
<a href="#livetab_content" data-tab-remote="{% url 'profile_chgroup_link' uid %}" role="tab"
data-toggle="tab">
Группы Группы
</a> </a>
</li> </li>

77
templates/accounts/group.html

@ -2,46 +2,51 @@
{% block main %} {% block main %}
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li>
<li><a href="{% url 'profile_groups_list' %}">Группы</a></li>
<li class="active">{{ group.name }}</li>
</ol>
<ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li>
<li><a href="{% url 'profile_groups_list' %}">Группы</a></li>
<li class="active">{{ group.name }}</li>
</ol>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Действующее распределение прав для группы <b>{{ group.name }}</b></h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'profile_group_link' group.id %}" method="post">{% csrf_token %}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Действующее распределение прав для группы <b>{{ group.name }}</b></h3>
</div>
<div class="panel-body">
{% if warntext %}
<div class="alert-danger">{{ warntext }}</div>
{% endif %}
<form role="form" action="{% url 'profile_group_link' group.id %}" method="post">{% csrf_token %}
<div class="choice_wrapper">
<label for="sel_left">Доступные права</label>
<select name="allrights" multiple id="sel_left">
{% for rgt in all_rights %}<option value="{{ rgt.id }}">{{ rgt.content_type }} &lt;{{ rgt.name }}&gt;</option>
{% endfor %}
</select>
</div>
<ul class="select_choose">
<li><a href="javascript:chooser_select('sel_left','sel_right');" class="btn btn-blue"><i class="black icon-arrow-right"></i></a></li>
<li><a href="javascript:chooser_select('sel_right','sel_left');" class="btn btn-blue"><i class="black icon-arrow-left"></i></a></li>
</ul>
<div class="choice_wrapper">
<label for="sel_right">Права группы</label>
<select name="group_rights" multiple id="sel_right">
{% for rgt in grp_rights %}<option value="{{ rgt.id }}">{{ rgt.content_type }} &lt;{{ rgt.name }}&gt;</option>
{% endfor %}
</select>
</div><br/>
<input type="submit" value="Сохранить"> <input type="reset" value="Сбросить">
<div class="choice_wrapper">
<label for="sel_left">Доступные права</label>
<select name="allrights" multiple id="sel_left">
{% for rgt in all_rights %}
<option value="{{ rgt.id }}">{{ rgt.content_type }} &lt;{{ rgt.name }}&gt;</option>
{% endfor %}
</select>
</div>
<ul class="select_choose">
<li><a href="javascript:chooser_select('sel_left','sel_right');" class="btn btn-blue"><i
class="black icon-arrow-right"></i></a></li>
<li><a href="javascript:chooser_select('sel_right','sel_left');" class="btn btn-blue"><i
class="black icon-arrow-left"></i></a></li>
</ul>
<div class="choice_wrapper">
<label for="sel_right">Права группы</label>
<select name="group_rights" multiple id="sel_right">
{% for rgt in grp_rights %}
<option value="{{ rgt.id }}">{{ rgt.content_type }} &lt;{{ rgt.name }}&gt;</option>
{% endfor %}
</select>
</div>
<br/>
<input type="submit" value="Сохранить"> <input type="reset" value="Сбросить">
</form>
</form>
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}

76
templates/accounts/group_list.html

@ -3,9 +3,9 @@
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li>
<li class="active">Группы</li>
<li><span class="glyphicon glyphicon-home"></span></li>
<li><a href="{% url 'accounts_list' %}">Администраторы</a></li>
<li class="active">Группы</li>
</ol> </ol>
@ -14,40 +14,42 @@
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="50">#</th>
<th>Группа</th>
<th class="col-sm-1">&mdash;</th>
</tr>
</thead>
<tbody>
{% for grp in groups %}
<tr>
<td>{{ grp.id }}</td>
<td><a href="{% url 'profile_group_link' grp.id %}">{{ grp.name }}</a></td>
<td class="btn-group">
<a href="#" class="btn btn-sm btn-info">
<span class="glyphicon glyphicon-edit"></span>
</a>
<a href="#" class="btn btn-sm btn-danger">
<span class="glyphicon glyphicon-remove"></span>
</a>
</td>
</tr>
{% empty %}
<tr><td colspan="3"><a href="#">Нет групп</a></td></tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="3">
<a href="#" class="btn btn-primary btn-sm" title="Добавить группу"><i class="icon-plus"></i></a>
</td>
</tr>
</tfoot>
</table>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th width="50">#</th>
<th>Группа</th>
<th class="col-sm-1">&mdash;</th>
</tr>
</thead>
<tbody>
{% for grp in groups %}
<tr>
<td>{{ grp.id }}</td>
<td><a href="{% url 'profile_group_link' grp.id %}">{{ grp.name }}</a></td>
<td class="btn-group">
<a href="#" class="btn btn-sm btn-info">
<span class="glyphicon glyphicon-edit"></span>
</a>
<a href="#" class="btn btn-sm btn-danger">
<span class="glyphicon glyphicon-remove"></span>
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="3"><a href="#">Нет групп</a></td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="3">
<a href="#" class="btn btn-primary btn-sm" title="Добавить группу"><i class="icon-plus"></i></a>
</td>
</tr>
</tfoot>
</table>
</div> </div>
{% include 'toolbar_page.html' with pag=groups %} {% include 'toolbar_page.html' with pag=groups %}

16
templates/accounts/index.html

@ -1,8 +1,8 @@
{% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %} {% extends request.is_ajax|yesno:'nullcont.htm,accounts/ext.htm' %}
{% block content %} {% block content %}
<table class="table table-striped table-bordered">
<tbody>
<table class="table table-striped table-bordered">
<tbody>
<tr> <tr>
<td class="col-sm-4">Телефон</td> <td class="col-sm-4">Телефон</td>
<td><a href="tel:{{ userprofile.telephone }}">{{ userprofile.telephone }}</a></td> <td><a href="tel:{{ userprofile.telephone }}">{{ userprofile.telephone }}</a></td>
@ -28,12 +28,12 @@
<td>&lt;10.155.13.43&gt;</td> <td>&lt;10.155.13.43&gt;</td>
</tr> </tr>
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<tr>
<td>Административный доступ (все права)</td>
<td><input type="checkbox"{{ userprofile.is_staff|yesno:' checked,' }}></td>
</tr>
<tr>
<td>Административный доступ (все права)</td>
<td><input type="checkbox"{{ userprofile.is_staff|yesno:' checked,' }}></td>
</tr>
{% endif %} {% endif %}
</tbody>
</table>
</tbody>
</table>
{% endblock %} {% endblock %}

110
templates/accounts/login.html

@ -5,63 +5,69 @@
<title>Аутентификация</title> <title>Аутентификация</title>
<link rel="shortcut icon" href="/static/img/favicon_m.ico"> <link rel="shortcut icon" href="/static/img/favicon_m.ico">
<style> <style>
h3,h4,label{
color: #383838;
}
body{
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 15px;
}
form{
background-color: #ECECEC;
padding: 30px 71px;
border-radius: 4px;
position: fixed;
left: 50%;
width: 322px;
margin-top: 100px;
margin-left: -275px;
box-shadow: 4px 4px 8px #484848;
border-top: 1px solid #FFF;
border-left: 1px solid #FFF;
}
form * {
display: block;
}
form input{
width: 100%;
border-radius: 5px;
padding: 4px 8px;
}
.err{
background-color: #FFBDBD;
padding: 1px 25px;
color: #520000;
border-radius: 3px;
}
h3, h4, label {
color: #383838;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 15px;
}
form {
background-color: #ECECEC;
padding: 30px 71px;
border-radius: 4px;
position: fixed;
left: 50%;
width: 322px;
margin-top: 100px;
margin-left: -275px;
box-shadow: 4px 4px 8px #484848;
border-top: 1px solid #FFF;
border-left: 1px solid #FFF;
}
form * {
display: block;
}
form input {
width: 100%;
border-radius: 5px;
padding: 4px 8px;
}
.err {
background-color: #FFBDBD;
padding: 1px 25px;
color: #520000;
border-radius: 3px;
}
</style> </style>
</head> </head>
<body> <body>
<form id="frm" action="{% url 'login_link' %}?next={{ next }}" method="POST" accept-charset="utf-8">{% csrf_token %}
{% if errmsg %}<div class="err">
<h4>{{ errmsg }}</h4>
<form id="frm" action="{% url 'login_link' %}?next={{ next }}" method="POST" accept-charset="utf-8">{% csrf_token %}
{% if errmsg %}
<div class="err">
<h4>{{ errmsg }}</h4>
</div>{% endif %} </div>{% endif %}
<h3>Аутентификация, ваш ip:{{ client_ipaddress }}</h3>
<label for="inp_uname">Имя пользователя</label>
<input type="text" id="inp_uname" placeholder="username" name="login" autofocus>
<br>
<label for="inp_pass">Пароль</label>
<input type="password" id="inp_pass" name="password">
<br>
<input type="submit" value="Войти">
</form>
<h3>Аутентификация, ваш ip:{{ client_ipaddress }}</h3>
<label for="inp_uname">Имя пользователя</label>
<input type="text" id="inp_uname" placeholder="username" name="login" autofocus>
<br>
<label for="inp_pass">Пароль</label>
<input type="password" id="inp_pass" name="password">
<br>
<input type="submit" value="Войти">
</form>
<script> <script>
function resz(){
var y = window.innerHeight|| document.documentElement.clientHeight|| document.getElementsByTagName('body')[0].clientHeight;
document.body.style.height = y-16+'px';
}
window.onload = resz;
document.body.onresize = resz;
function resz() {
var y = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight;
document.body.style.height = y - 16 + 'px';
}
window.onload = resz;
document.body.onresize = resz;
</script> </script>
</body> </body>
</html> </html>

9
templates/accounts/profile_chgroup.html

@ -6,7 +6,8 @@
<div class="form-group"> <div class="form-group">
<label for="sel_left">Доступные группы</label> <label for="sel_left">Доступные группы</label>
<select name="allgroups" multiple id="sel_left" class="form-group"> <select name="allgroups" multiple id="sel_left" class="form-group">
{% for gr in allgroups %}<option value="{{ gr.id }}">{{ gr.name }}</option>
{% for gr in allgroups %}
<option value="{{ gr.id }}">{{ gr.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -21,10 +22,12 @@
<div class="form-group"> <div class="form-group">
<label for="sel_right">Группы пользователя</label> <label for="sel_right">Группы пользователя</label>
<select name="ingroups" multiple id="sel_right" class="form-group"> <select name="ingroups" multiple id="sel_right" class="form-group">
{% for gr in usergroups %}<option value="{{ gr.id }}">{{ gr.name }}</option>
{% for gr in usergroups %}
<option value="{{ gr.id }}">{{ gr.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div><br/>
</div>
<br/>
<input type="submit" value="Сохранить"> <input type="reset" value="Сбросить"> <input type="submit" value="Сохранить"> <input type="reset" value="Сбросить">
</form> </form>

27
templates/accounts/settings/ch_info.html

@ -2,24 +2,27 @@
{% block content %} {% block content %}
{% if warntext %} {% if warntext %}
<div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
{{ warntext }}
</div>
<div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
{{ warntext }}
</div>
{% endif %} {% endif %}
<form role="form" action="{% url 'settings_chinfo_link' %}" method="post">{% csrf_token %} <form role="form" action="{% url 'settings_chinfo_link' %}" method="post">{% csrf_token %}
<div class="form-group"> <div class="form-group">
<label for="login">Логин</label> <label for="login">Логин</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="login" type="text" value="{{ user.username }}" name="username" placeholder="Имя пользователя" required class="form-control">
<input id="login" type="text" value="{{ user.username }}" name="username" placeholder="Имя пользователя"
required class="form-control">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="fio">Фамилия Имя</label> <label for="fio">Фамилия Имя</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="fio" type="text" value="{{ user.fio }}" name="fio" placeholder="ФИО" class="form-control"> <input id="fio" type="text" value="{{ user.fio }}" name="fio" placeholder="ФИО" class="form-control">
@ -28,30 +31,37 @@
<div class="form-group"> <div class="form-group">
<label for="mail">Мыло</label> <label for="mail">Мыло</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="mail" type="text" value="{{ user.email }}" name="email" placeholder="Email" class="form-control">
<input id="mail" type="text" value="{{ user.email }}" name="email" placeholder="Email"
class="form-control">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="tel">Телефон</label> <label for="tel">Телефон</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="tel" type="text" value="{{ user.telephone }}" pattern="\+[7,8,9,3]\d{10,11}" name="telephone" placeholder="+[7,8,9,3] и 10,11 цифр" class="form-control">
<input id="tel" type="text" value="{{ user.telephone }}" pattern="\+[7,8,9,3]\d{10,11}" name="telephone"
placeholder="+[7,8,9,3] и 10,11 цифр" class="form-control">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="skype"><a title="Что это" target="_blank" href="http://lurkmore.to/Skype">Skype</a></label> <label for="skype"><a title="Что это" target="_blank" href="http://lurkmore.to/Skype">Skype</a></label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="skype" type="text" value="{{ user.skype }}" name="skype" placeholder="Skype" class="form-control">
<input id="skype" type="text" value="{{ user.skype }}" name="skype" placeholder="Skype"
class="form-control">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="oldpassw">Старый пароль</label> <label for="oldpassw">Старый пароль</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="oldpassw" type="password" name="oldpasswd" class="form-control"> <input id="oldpassw" type="password" name="oldpasswd" class="form-control">
@ -60,6 +70,7 @@
<div class="form-group"> <div class="form-group">
<label for="npassw">Новый пароль</label> <label for="npassw">Новый пароль</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span> <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
<input id="npassw" type="Password" name="newpasswd" class="form-control"> <input id="npassw" type="Password" name="newpasswd" class="form-control">

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

Loading…
Cancel
Save