Browse Source

Merge branch 'devel' of https://github.com/nerosketch/djing into devel

devel
www-data 8 years ago
parent
commit
25c5042cad
  1. 21
      abonapp/forms.py
  2. 4
      abonapp/locale/ru/LC_MESSAGES/django.po
  3. 11
      abonapp/models.py
  4. 145
      abonapp/templates/abonapp/editAbon.html
  5. 78
      abonapp/templates/abonapp/viewAbon.html
  6. 2
      abonapp/urls.py
  7. 139
      abonapp/views.py
  8. 3
      accounts_app/templates/accounts/create_acc.html
  9. 3
      accounts_app/templates/accounts/settings/ch_info.html
  10. 12
      djing/settings.py

21
abonapp/forms.py

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from django.utils.translation import ugettext as _
from django import forms
@ -7,6 +6,7 @@ from random import choice
from string import digits, ascii_lowercase
from . import models
from django.conf import settings
from djing import IP_ADDR_REGEX
TELEPHONE_REGEXP = getattr(settings, 'TELEPHONE_REGEXP', r'^\+[7,8,9,3]\d{10,11}$')
@ -36,29 +36,36 @@ def generate_random_password():
class AbonForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(AbonForm, self).__init__(*args, **kwargs)
if self.instance is not None and self.instance.group is not None:
abon_group_queryset = models.AbonStreet.objects.filter(group=self.instance.group)
instance = getattr(self, 'instance')
if instance is not None and instance.group is not None:
abon_group_queryset = models.AbonStreet.objects.filter(group=instance.group)
elif 'group' in self.initial.keys() and self.initial['group'] is not None:
abon_group_queryset = models.AbonStreet.objects.filter(group=self.initial['group'])
else:
abon_group_queryset = None
if abon_group_queryset is not None:
self.fields['street'].queryset = abon_group_queryset
if instance is not None and instance.is_dynamic_ip:
self.fields['ip_address'].widget.attrs['readonly'] = True
username = forms.CharField(max_length=127, required=False, initial=generate_random_username,
widget=forms.TextInput(attrs={
'placeholder': _('login'),
'required': '',
'pattern': r'^\w{1,127}$'
}))
}), label=_('login'))
password = forms.CharField(max_length=64, initial=generate_random_password, widget=forms.TextInput(attrs={
'class': 'form-control', 'type': 'password', 'autocomplete': 'new-password'
}))
'type': 'password', 'autocomplete': 'new-password'
}), label=_('Password'))
ip_address = forms.CharField(widget=forms.TextInput(attrs={
'pattern': IP_ADDR_REGEX
}), label=_('Ip Address'), required=False)
class Meta:
model = models.Abon
fields = ['username', 'telephone', 'fio', 'group', 'description', 'street', 'house', 'is_active']
fields = ['username', 'telephone', 'fio', 'group', 'description', 'street', 'house', 'is_active', 'ip_address']
widgets = {
'fio': forms.TextInput(attrs={
'placeholder': _('fio'),

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

@ -876,10 +876,6 @@ msgstr "Нет исполнителей"
msgid "Tasks not found"
msgstr "Нет задач"
#: templates/abonapp/viewAbon.html:10
msgid "View the subscriber"
msgstr "Просмотр абонента"
#: templates/abonapp/viewAbon.html:24
msgid "yes,no"
msgstr "Да,Нет"

11
abonapp/models.py

@ -136,7 +136,7 @@ class Abon(BaseAccount):
current_tariff = models.ForeignKey(AbonTariff, null=True, blank=True, on_delete=models.SET_NULL)
group = models.ForeignKey(Group, models.SET_NULL, blank=True, null=True, verbose_name=_('User group'))
ballance = models.FloatField(default=0.0)
ip_address = MyGenericIPAddressField(blank=True, null=True)
ip_address = MyGenericIPAddressField(blank=True, null=True, verbose_name=_('Ip Address'))
description = models.TextField(_('Comment'), null=True, blank=True)
street = models.ForeignKey(AbonStreet, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_('Street'))
house = models.CharField(_('House'), max_length=12, null=True, blank=True)
@ -263,17 +263,18 @@ class Abon(BaseAccount):
else:
return
abon_tariff = self.active_tariff()
if abon_tariff is None:
return
trf = abon_tariff.tariff
agent_trf = TariffStruct(trf.id, trf.speedIn, trf.speedOut)
return AbonStruct(self.pk, user_ip, agent_trf, bool(self.is_active))
def save(self, *args, **kwargs):
def clean(self):
# check if ip address already busy
if self.ip_address is not None and Abon.objects.filter(ip_address=self.ip_address).exclude(
pk=self.pk).count() > 0:
self.is_bad_ip = True
raise LogicError(_('Ip address already exist'))
super(Abon, self).save(*args, **kwargs)
raise ValidationError({'ip_address': [gettext('Ip address already exist')]})
return super(Abon, self).clean()
def sync_with_nas(self, created: bool) -> Optional[Exception]:
agent_abon = self.build_agent_struct()

145
abonapp/templates/abonapp/editAbon.html

@ -10,86 +10,99 @@
<h3 class="panel-title">{% trans 'Change subscriber' %}</h3>
</div>
<div class="panel-body">
<form autocomplete="off" class="form-horizontal" action="{% url 'abonapp:abon_home' group.pk abon.username %}" method="post">{% csrf_token %}
{% bootstrap_field form.username label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
{% bootstrap_field form.fio label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
{% if perms.abonapp.change_abon %}
{% url 'abonapp:abon_home' group.pk abon.username as ahlink %}
{% endif %}
<div class="form-group-sm">
<label for="id_telephone" class="col-sm-4 control-label">{% trans 'Telephone' %}</label>
<div class="col-sm-8">
<div class="input-group input-group-sm">
{{ form.telephone }}{{ form.telephone.errors }}
<span class="input-group-btn">
<a href="sip:{{ form.telephone.value }}" class="btn btn-default" data-toggle="tooltip" title="{% trans 'Call to' %}">
<span class="glyphicon glyphicon-earphone"></span>
</a>
<a href="{% url 'abonapp:telephones' group.pk abon.username %}" class="btn btn-default btn-modal" data-toggle="tooltip" title="{% trans 'Additional telephones' %}">
<span class="glyphicon glyphicon-list"></span>
</a>
<a href="{% url 'abonapp:telephone_new' group.pk abon.username %}" class="btn btn-default btn-modal" data-toggle="tooltip" title="{% trans 'Add telephone' %}">
<span class="glyphicon glyphicon-plus"></span>
</a>
</span>
</div>
</div>
</div>
<form autocomplete="off" class="form-horizontal" action="{{ ahlink|default:'#' }}" method="post">{% csrf_token %}
<div class="form-group-sm{% if is_bad_ip %} has-error{% endif %}">
<label for="id_ip" class="col-sm-4 control-label">{% trans 'Ip Address' %}</label>
<div class="col-sm-8">
<div class="input-group input-group-sm">
<input type="text" value="{{ ip|default:'' }}" class="form-control" name="ip" placeholder="{% trans 'Not assigned' %}" id="ipfield" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"{% if abon.is_dynamic_ip %} disabled{% endif %}/>
<span class="input-group-btn">
<a href="{% url 'abonapp:reset_ip' group.pk abon.username %}" class="btn btn-default btn-cmd" data-toggle="tooltip" title="{% trans 'Reset ip' %}" onclick="$('#ipfield').val('');">
<span class="glyphicon glyphicon-refresh"></span>
</a>
</span>
</div>
</div>
</div>
{% bootstrap_field form.username form_group_class='form-group-sm' %}
{% bootstrap_field form.fio form_group_class='form-group-sm' %}
{% bootstrap_field form.street label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
{% bootstrap_field form.house label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
{% bootstrap_field form.is_active label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
{% bootstrap_field form.group label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
<div class="form-group-sm">
<label for="id_password" class="col-sm-4 control-label">{% trans 'Password' %}</label>
<div class="col-sm-8">
<div class="input-group input-group-sm">
{{ form.password }}{{ form.password.errors }}
<span class="input-group-btn">
<button type="button" class="btn btn-default" onmousedown="document.getElementById('id_password').type='text'" onmouseup="document.getElementById('id_password').type='password'">
<span class="glyphicon glyphicon-eye-open"></span>
</button>
</span>
</div>
</div>
</div>
{# telephone field #}
{% trans 'Call to' as tx %}
{% bootstrap_button '' button_type='link' icon='earphone' button_class='btn-default' title=tx href='sip:'|add:form.telephone.value size='sm' as btn_call %}
{% bootstrap_field form.description label_class='col-sm-4' field_class='col-sm-8' form_group_class='form-group-sm' %}
{% trans 'Additional telephones' as tx %}
{% url 'abonapp:telephones' group.pk abon.username as url %}
{% bootstrap_button '' button_type='link' icon='list' button_class='btn-default btn-modal' title=tx href=url size='sm' as btn_teleph_list %}
{% trans 'Add telephone' as tx %}
{% url 'abonapp:telephone_new' group.pk abon.username as url %}
{% bootstrap_button '' button_type='link' icon='plus' button_class='btn-default btn-modal' title=tx href=url size='sm' as btn_teleph_add %}
{% with ''|add:btn_call|add:btn_teleph_list|add:btn_teleph_add as bt %}
{% bootstrap_field form.telephone form_group_class='form-group-sm' addon_after_class='input-group-btn' addon_after=bt %}
{% endwith %}
{# Ip address field #}
{% trans 'Reset ip' as tx %}
{% url 'abonapp:reset_ip' group.pk abon.username as url %}
{% bootstrap_button '' button_type='link' icon='refresh' button_class='btn-default btn-cmd' id='iprefreshbtn' href=url size='sm' title=tx as bt %}
{% bootstrap_field form.ip_address form_group_class='form-group-sm' addon_after_class='input-group-btn' addon_after=bt %}
{% bootstrap_field form.street form_group_class='form-group-sm' %}
{% bootstrap_field form.house form_group_class='form-group-sm' %}
{% bootstrap_field form.is_active form_group_class='form-group-sm' %}
{% bootstrap_field form.group form_group_class='form-group-sm' %}
{# password field #}
{% bootstrap_button '' button_type='button' icon='eye-open' button_class='btn-default' id='passwdtoggler' size='sm' as bt %}
{% bootstrap_field form.password form_group_class='form-group-sm' addon_after_class='input-group-btn' addon_after=bt %}
<script type="text/javascript">
$(function () {
$("#iprefreshbtn").on('click', function(){
$("#{{ form.ip_address.id_for_label }}").val('');
});
$('#passwdtoggler').on('mousedown', function(){
document.getElementById("{{ form.password.id_for_label }}").type='text';
}).on('mouseup', function(){
document.getElementById("{{ form.password.id_for_label }}").type='password';
});
});
</script>
{% bootstrap_field form.description form_group_class='form-group-sm' %}
<div class="form-group-sm">
<div class="col-sm-offset-4 col-sm-8 btn-group btn-group-sm">
<div class="btn-group btn-group-sm">
{% trans 'Save' as tx %}
{% bootstrap_button tx button_type='submit' icon='floppy-disk' button_class='btn-primary' %}
{% if perms.abonapp.change_abon %}
{% bootstrap_button tx button_type='submit' icon='floppy-disk' button_class='btn-primary' %}
{% else %}
{% bootstrap_button tx button_type='button' icon='floppy-disk' button_class='btn-primary disabled' %}
{% endif %}
{% if perms.taskapp.add_task %}
<a href="{% url 'taskapp:add' %}?uid={{ abon.username }}" class="btn btn-success" title="{% trans 'Add new task' %}">
<span class="glyphicon glyphicon-plus"></span> <span class="hidden-xs">{% trans 'Add new task' %}</span>
<span class="glyphicon glyphicon-plus"></span>
{% trans 'Add new task' %}
</a>
{% else %}
<a href="#" class="btn btn-success disabled" title="{% trans 'Permission denied' %}">
<span class="glyphicon glyphicon-plus"></span>
{% trans 'Add new task' %}
</a>
{% endif %}
</div>
</div>
<div class="form-group-sm">
<div class="col-sm-offset-4 col-sm-8 btn-group btn-group-sm">
{% if ip and perms.abonapp.can_ping %}
<a href="{% url 'abonapp:ping' %}" class="btn btn-default btn-cmd" title="Ping" data-param="{{ ip }}">
<span class="glyphicon glyphicon-flash"></span> Ping
</a>
{% if form.ip_address.value %}
{% if perms.abonapp.can_ping %}
<a href="{% url 'abonapp:ping' %}" class="btn btn-default btn-cmd" title="Ping" data-param="{{ form.ip_address.value }}">
<span class="glyphicon glyphicon-flash"></span> Ping
</a>
{% else %}
<a href="#" class="btn btn-default disabled" title="{% trans 'Permission denied' %}">
<span class="glyphicon glyphicon-flash"></span> Ping
</a>
{% endif %}
{% else %}
<a href="#" class="btn btn-default disabled">
<span class="glyphicon glyphicon-flash"></span> {% trans 'No have ip' %}
@ -100,6 +113,10 @@
<a href="{% url 'dialapp:send_sms' %}?path={{ request.path|urlencode }}&dst={{ form.telephone.value|urlencode }}" class="btn btn-default btn-modal">
<span class="glyphicon glyphicon-envelope"></span> {% trans 'Send sms' %}
</a>
{% else %}
<a href="#" class="btn btn-default disabled" title="{% trans 'Permission denied' %}">
<span class="glyphicon glyphicon-envelope"></span> {% trans 'Send sms' %}
</a>
{% endif %}
</div>
</div>

78
abonapp/templates/abonapp/viewAbon.html

@ -1,78 +0,0 @@
{% extends request.is_ajax|yesno:'nullcont.htm,abonapp/ext.htm' %}
{% load i18n %}
{% block content %}
<div class="row">
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'View the subscriber' %}</h3>
</div>
<div class="panel-body">
<table class="table borderbot">
<tbody>
<tr>
<td>{% trans 'User group' %}</td>
<td>
<i>{{ abon.group|default:_('Not assigned') }}</i>
</td>
</tr>
<tr>
<td>{% trans 'Is active' %}</td>
<td>
<i>{{ abon.is_active|yesno:_('yes,no') }}</i>
</td>
</tr>
<tr>
<td>{% trans 'login' %}</td>
<td><i>{{ abon.username|default:_('Not assigned') }}</i></td>
</tr>
<tr>
<td>{% trans 'fio' %}</td>
<td><i>{{ abon.fio|default:_('Not assigned') }}</i></td>
</tr>
<tr>
<td>{% trans 'Telephone' %}</td>
<td><i>{{ abon.telephone|default:_('Not assigned') }}</i></td>
</tr>
<tr>
<td>{% trans 'Street' %}</td>
<td>
<i>{{ abon.street|default:_('Not assigned') }}</i>
</td>
</tr>
<tr>
<td>{% trans 'House' %}</td>
<td><i>{{ abon.house|default:_('Not assigned') }}</i></td>
</tr>
<tr>
<td>{% trans 'Ip Address' %}</td>
<td><i>{{ abon.ip_address|default:_('Not assigned') }}</i></td>
</tr>
<tr>
<td>{% trans 'Password' %}</td>
<td><i>{{ passw }}</i></td>
</tr>
</tbody>
</table>
{% if abon.description %}<p>{{ abon.description }}</p>{% endif %}
</div>
</div>
</div>
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{% trans 'User flags' %}</h3>
</div>
<div class="panel-body">
{% for user_icon in abon.get_flag_icons %}
<span class="m-icon {{ user_icon }}"></span>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock %}

2
abonapp/urls.py

@ -5,7 +5,7 @@ from . import views
app_name = 'abonapp'
subscriber_patterns = [
url(r'^$', views.abonhome, name='abon_home'),
url(r'^$', views.AbonHomeUpdateView.as_view(), name='abon_home'),
url(r'^services/$', views.abon_services, name='abon_services'),
url(r'^amount/$', views.abonamount, name='abon_amount'),
url(r'^debts/$', views.DebtsListView.as_view(), name='abon_debts'),

139
abonapp/views.py

@ -28,6 +28,7 @@ from statistics.models import getModel
from group_app.models import Group
from guardian.shortcuts import get_objects_for_user, assign_perm
from guardian.decorators import permission_required_or_403 as permission_required
from djing import ping
from djing.global_base_views import OrderingMixin, BaseListWithFiltering, SecureApiView
PAGINATION_ITEMS_PER_PAGE = getattr(settings, 'PAGINATION_ITEMS_PER_PAGE', 10)
@ -267,66 +268,82 @@ def abon_services(request, gid, uname):
})
@login_required
@mydefs.only_admins
def abonhome(request, gid, uname):
abon = get_object_or_404(models.Abon, username=uname)
group = get_object_or_404(Group, pk=gid)
if not request.user.has_perm('group_app.can_view_group', group):
raise PermissionDenied
frm = None
passw = None
try:
if request.method == 'POST':
if not request.user.has_perm('abonapp.change_abon'):
raise PermissionDenied
frm = forms.AbonForm(request.POST, instance=abon)
if frm.is_valid():
newip = request.POST.get('ip')
if newip:
abon.ip_address = newip
abon = frm.save()
res = abon.sync_with_nas(created=False)
if isinstance(res, Exception):
messages.warning(request, res)
messages.success(request, _('edit abon success msg'))
else:
messages.warning(request, _('fix form errors'))
else:
passw = models.AbonRawPassword.objects.get(account=abon).passw_text
frm = forms.AbonForm(instance=abon, initial={'password': passw})
if abon.device is None:
messages.warning(request, _('User device was not found'))
except mydefs.LogicError as e:
messages.error(request, e)
@method_decorator([login_required, mydefs.only_admins], name='dispatch')
@method_decorator(permission_required('abonapp.change_abon'), name='post')
class AbonHomeUpdateView(UpdateView):
model = models.Abon
form_class = forms.AbonForm
slug_field = 'username'
slug_url_kwarg = 'uname'
template_name = 'abonapp/editAbon.html'
context_object_name = 'abon'
group = None
def dispatch(self, request, *args, **kwargs):
try:
return super(AbonHomeUpdateView, self).dispatch(request, *args, **kwargs)
except mydefs.LogicError as e:
messages.error(request, e)
except (NasFailedResult, NasNetworkError) as e:
messages.error(request, e)
except models.AbonRawPassword.DoesNotExist:
messages.warning(request, _('User has not have password, and cannot login'))
except mydefs.MultipleException as errs:
for err in errs.err_list:
messages.error(request, err)
return self.render_to_response(self.get_context_data())
def get_object(self, queryset=None):
gid = self.kwargs.get('gid')
self.group = get_object_or_404(Group, pk=gid)
if not self.request.user.has_perm('group_app.can_view_group', self.group):
raise PermissionDenied
return super(AbonHomeUpdateView, self).get_object(queryset)
def form_valid(self, form):
r = super(AbonHomeUpdateView, self).form_valid(form)
abon = self.object
res = abon.sync_with_nas(created=False)
if isinstance(res, Exception):
messages.warning(self.request, res)
messages.success(self.request, _('edit abon success msg'))
return r
def form_invalid(self, form):
messages.warning(self.request, _('fix form errors'))
return super(AbonHomeUpdateView, self).form_invalid(form)
def get(self, request, *args, **kwargs):
r = super(AbonHomeUpdateView, self).get(request, *args, **kwargs)
abon = self.object
if abon.device is None:
messages.warning(request, _('User device was not found'))
return r
def get_initial(self):
abon = self.object
passw = models.AbonRawPassword.objects.get(account=abon).passw_text
frm = forms.AbonForm(instance=abon, initial={'password': passw})
return {
'password': passw
}
except (NasFailedResult, NasNetworkError) as e:
messages.error(request, e)
except models.AbonRawPassword.DoesNotExist:
messages.warning(request, _('User has not have password, and cannot login'))
except mydefs.MultipleException as errs:
for err in errs.err_list:
messages.error(request, err)
def get_context_data(self, **kwargs):
abon = self.object
dev = getattr(abon, 'device')
context = {
'group': self.group,
'device': dev,
'dev_ports': DevPort.objects.filter(device=dev) if dev else None
}
context.update(kwargs)
return super(AbonHomeUpdateView, self).get_context_data(**context)
if request.user.has_perm('abonapp.change_abon'):
return render(request, 'abonapp/editAbon.html', {
'form': frm or forms.AbonForm(instance=abon, initial={'password': passw}),
'abon': abon,
'group': group,
'ip': abon.ip_address,
'is_bad_ip': getattr(abon, 'is_bad_ip', False),
'device': abon.device,
'dev_ports': DevPort.objects.filter(device=abon.device) if abon.device else None
})
else:
return render(request, 'abonapp/viewAbon.html', {
'abon': abon,
'group': group,
'ip': abon.ip_address,
'passw': passw
})
def get_success_url(self):
abon = self.object
return resolve_url('abonapp:abon_home',
gid=getattr(abon.group, 'pk', 0),
uname=abon.username
)
@transaction.atomic
@ -698,7 +715,7 @@ def abon_ping(request):
tm = Transmitter()
ping_result = tm.ping(ip)
if ping_result is None:
if mydefs.ping(ip, 10):
if ping(ip, 10):
status = True
text = '<span class="glyphicon glyphicon-ok"></span> %s' % _('ping ok')
else:
@ -792,9 +809,9 @@ def save_user_dev_port(request, gid, uname):
user_url = resolve_url('abonapp:abon_home', other_abon.group.id, other_abon.username)
messages.error(request, _(
"<a href='%(user_url)s'>%(user_name)s</a> already pinned to this port on this device") % {
'user_url': user_url,
'user_name': other_abon.get_full_name()
})
'user_url': user_url,
'user_name': other_abon.get_full_name()
})
return redirect('abonapp:abon_home', gid, uname)
except models.Abon.DoesNotExist:
pass

3
accounts_app/templates/accounts/create_acc.html

@ -1,4 +1,5 @@
{% extends request.is_ajax|yesno:'bajax.html,base.html' %}
{% load globaltags %}
{% load i18n %}
{% block main %}
@ -62,7 +63,7 @@
<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"
<input id="tel" type="tel" pattern="{% global_var 'TELEPHONE_REGEXP' %}" name="telephone"
placeholder="{% trans '+[7,8,9,3] and 10,11 digits' %}" value="{{ newuser.telephone }}"
class="form-control" required>
</div>

3
accounts_app/templates/accounts/settings/ch_info.html

@ -1,4 +1,5 @@
{% extends request.is_ajax|yesno:'nullcont.htm,accounts/settings/ext.htm' %}
{% load globaltags %}
{% load i18n %}
{% block content %}
@ -38,7 +39,7 @@
<div class="input-group">
<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"
<input id="tel" type="text" value="{{ user.telephone }}" pattern="{% global_var 'TELEPHONE_REGEXP' %}" name="telephone"
placeholder="{% trans '+[7,8,9,3] and 10,11 digits' %}" class="form-control">
</div>
</div>

12
djing/settings.py

@ -172,7 +172,7 @@ DEFAULT_SNMP_PASSWORD = local_settings.DEFAULT_SNMP_PASSWORD
TELEGRAM_BOT_TOKEN = local_settings.TELEGRAM_BOT_TOKEN
TELEPHONE_REGEXP = r'^\+[7,8,9,3]\d{10,11}$'
TELEPHONE_REGEXP = local_settings.TELEPHONE_REGEXP
ASTERISK_MANAGER_AUTH = local_settings.ASTERISK_MANAGER_AUTH
@ -184,3 +184,13 @@ API_AUTH_SUBNET = local_settings.API_AUTH_SUBNET
# Company name
COMPANY_NAME = local_settings.COMPANY_NAME
# bootstrap3 settings
BOOTSTRAP3 = {
# Label class to use in horizontal forms
'horizontal_label_class': 'col-md-3',
# Field class to use in horizontal forms
'horizontal_field_class': 'col-md-9',
}
Loading…
Cancel
Save