mirror of https://github.com/jumpserver/jumpserver
[Feature] 添加basic settings
parent
121f56f44b
commit
abb1a40a4f
|
@ -85,7 +85,7 @@ class AdminUserDetailView(AdminUserRequiredMixin, DetailView):
|
||||||
|
|
||||||
|
|
||||||
class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
class AdminUserAssetsView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
template_name = 'assets/admin_user_assets.html'
|
template_name = 'assets/admin_user_assets.html'
|
||||||
context_object_name = 'admin_user'
|
context_object_name = 'admin_user'
|
||||||
object = None
|
object = None
|
||||||
|
|
|
@ -92,7 +92,7 @@ class AssetCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
|
|
||||||
|
|
||||||
class AssetModalListView(AdminUserRequiredMixin, ListView):
|
class AssetModalListView(AdminUserRequiredMixin, ListView):
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
model = Asset
|
model = Asset
|
||||||
context_object_name = 'asset_modal_list'
|
context_object_name = 'asset_modal_list'
|
||||||
template_name = 'assets/asset_modal_list.html'
|
template_name = 'assets/asset_modal_list.html'
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
import json
|
||||||
|
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.views import Response
|
from rest_framework.views import Response
|
||||||
|
from ldap3 import Server, Connection
|
||||||
from django.core.mail import get_connection, send_mail
|
from django.core.mail import get_connection, send_mail
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from .permissions import IsSuperUser
|
from .permissions import IsSuperUser
|
||||||
from .serializers import MailTestSerializer
|
from .serializers import MailTestSerializer, LDAPTestSerializer
|
||||||
|
|
||||||
|
|
||||||
class MailTestingAPI(APIView):
|
class MailTestingAPI(APIView):
|
||||||
|
@ -27,7 +31,6 @@ class MailTestingAPI(APIView):
|
||||||
"use_tls": serializer.validated_data["EMAIL_USE_TLS"]
|
"use_tls": serializer.validated_data["EMAIL_USE_TLS"]
|
||||||
}
|
}
|
||||||
connection = get_connection(timeout=5, **kwargs)
|
connection = get_connection(timeout=5, **kwargs)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connection.open()
|
connection.open()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -40,3 +43,68 @@ class MailTestingAPI(APIView):
|
||||||
return Response({"error": str(e)}, status=401)
|
return Response({"error": str(e)}, status=401)
|
||||||
|
|
||||||
return Response({"msg": self.success_message.format(email_host_user)})
|
return Response({"msg": self.success_message.format(email_host_user)})
|
||||||
|
else:
|
||||||
|
return Response({"error": str(serializer.errors)}, status=401)
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPTestingAPI(APIView):
|
||||||
|
permission_classes = (IsSuperUser,)
|
||||||
|
serializer_class = LDAPTestSerializer
|
||||||
|
success_message = _("Test ldap success")
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
serializer = self.serializer_class(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
host = serializer.validated_data["AUTH_LDAP_SERVER_URI"]
|
||||||
|
bind_dn = serializer.validated_data["AUTH_LDAP_BIND_DN"]
|
||||||
|
password = serializer.validated_data["AUTH_LDAP_BIND_PASSWORD"]
|
||||||
|
use_ssl = serializer.validated_data.get("AUTH_LDAP_START_TLS", False)
|
||||||
|
search_ou = serializer.validated_data["AUTH_LDAP_SEARCH_OU"]
|
||||||
|
search_filter = serializer.validated_data["AUTH_LDAP_SEARCH_FILTER"]
|
||||||
|
attr_map = serializer.validated_data["AUTH_LDAP_USER_ATTR_MAP"]
|
||||||
|
|
||||||
|
print(serializer.validated_data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
attr_map = json.loads(attr_map)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return Response({"error": "AUTH_LDAP_USER_ATTR_MAP not valid"}, status=401)
|
||||||
|
|
||||||
|
server = Server(host, use_ssl=use_ssl)
|
||||||
|
conn = Connection(server, bind_dn, password)
|
||||||
|
try:
|
||||||
|
conn.bind()
|
||||||
|
except Exception as e:
|
||||||
|
return Response({"error": str(e)}, status=401)
|
||||||
|
|
||||||
|
print(search_ou)
|
||||||
|
print(search_filter % ({"user": "*"}))
|
||||||
|
print(attr_map.values())
|
||||||
|
ok = conn.search(search_ou, search_filter % ({"user": "*"}),
|
||||||
|
attributes=list(attr_map.values()))
|
||||||
|
if not ok:
|
||||||
|
return Response({"error": "Search no entry matched"}, status=401)
|
||||||
|
|
||||||
|
users = []
|
||||||
|
for entry in conn.entries:
|
||||||
|
user = {}
|
||||||
|
for attr, mapping in attr_map.items():
|
||||||
|
if hasattr(entry, mapping):
|
||||||
|
user[attr] = getattr(entry, mapping)
|
||||||
|
users.append(user)
|
||||||
|
if len(users) > 0:
|
||||||
|
return Response({"msg": "Match {} s users".format(len(users))})
|
||||||
|
else:
|
||||||
|
return Response({"error": "Have user but attr mapping error"}, status=401)
|
||||||
|
else:
|
||||||
|
return Response({"error": str(serializer.errors)}, status=401)
|
||||||
|
|
||||||
|
|
||||||
|
class DjangoSettingsAPI(APIView):
|
||||||
|
def get(self, request):
|
||||||
|
configs = {}
|
||||||
|
for i in dir(settings):
|
||||||
|
if i.isupper():
|
||||||
|
configs[i] = str(getattr(settings, i))
|
||||||
|
return Response(configs)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
from django.utils import six
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
class DictField(forms.Field):
|
||||||
|
widget = forms.Textarea
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
"""Returns a Python boolean object."""
|
||||||
|
# Explicitly check for the string 'False', which is what a hidden field
|
||||||
|
# will submit for False. Also check for '0', since this is what
|
||||||
|
# RadioSelect will provide. Because bool("True") == bool('1') == True,
|
||||||
|
# we don't need to handle that explicitly.
|
||||||
|
if isinstance(value, six.string_types):
|
||||||
|
try:
|
||||||
|
print(value)
|
||||||
|
value = json.loads(value)
|
||||||
|
return value
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
pass
|
||||||
|
value = {}
|
||||||
|
return value
|
||||||
|
|
||||||
|
def validate(self, value):
|
||||||
|
print(value)
|
||||||
|
if not value and self.required:
|
||||||
|
raise ValidationError(self.error_messages['required'], code='required')
|
||||||
|
|
||||||
|
def has_changed(self, initial, data):
|
||||||
|
# Sometimes data or initial may be a string equivalent of a boolean
|
||||||
|
# so we should run it through to_python first to get a boolean value
|
||||||
|
return self.to_python(initial) != self.to_python(data)
|
|
@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from .models import Setting
|
from .models import Setting
|
||||||
|
from .fields import DictField
|
||||||
|
|
||||||
|
|
||||||
def to_model_value(value):
|
def to_model_value(value):
|
||||||
|
@ -18,7 +19,10 @@ def to_model_value(value):
|
||||||
|
|
||||||
def to_form_value(value):
|
def to_form_value(value):
|
||||||
try:
|
try:
|
||||||
return json.loads(value)
|
data = json.loads(value)
|
||||||
|
if isinstance(data, dict):
|
||||||
|
data = value
|
||||||
|
return data
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
@ -26,23 +30,26 @@ def to_form_value(value):
|
||||||
class BaseForm(forms.Form):
|
class BaseForm(forms.Form):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if not self.is_bound:
|
settings = Setting.objects.all()
|
||||||
settings = Setting.objects.all()
|
for name, field in self.fields.items():
|
||||||
for name, field in self.fields.items():
|
db_value = getattr(settings, name).value
|
||||||
db_value = getattr(settings, name).value
|
if db_value:
|
||||||
if db_value:
|
field.initial = to_form_value(db_value)
|
||||||
field.initial = to_form_value(db_value)
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
if not self.is_bound:
|
if not self.is_bound:
|
||||||
raise ValueError("Form is not bound")
|
raise ValueError("Form is not bound")
|
||||||
|
|
||||||
|
settings = Setting.objects.all()
|
||||||
if self.is_valid():
|
if self.is_valid():
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
for name, value in self.cleaned_data.items():
|
for name, value in self.cleaned_data.items():
|
||||||
field = self.fields[name]
|
field = self.fields[name]
|
||||||
if isinstance(field.widget, forms.PasswordInput) and not value:
|
if isinstance(field.widget, forms.PasswordInput) and not value:
|
||||||
continue
|
continue
|
||||||
|
if value == to_form_value(getattr(settings, name).value):
|
||||||
|
continue
|
||||||
|
|
||||||
defaults = {
|
defaults = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'value': to_model_value(value)
|
'value': to_model_value(value)
|
||||||
|
@ -52,6 +59,24 @@ class BaseForm(forms.Form):
|
||||||
raise ValueError(self.errors)
|
raise ValueError(self.errors)
|
||||||
|
|
||||||
|
|
||||||
|
class BasicSettingForm(BaseForm):
|
||||||
|
SITE_URL = forms.URLField(
|
||||||
|
label=_("Current SITE URL"),
|
||||||
|
help_text="http://jumpserver.abc.com:8080"
|
||||||
|
)
|
||||||
|
USER_GUIDE_URL = forms.URLField(
|
||||||
|
label=_("User Guide URL"),
|
||||||
|
help_text=_("User first login update profile done redirect to it")
|
||||||
|
)
|
||||||
|
EMAIL_SUBJECT_PREFIX = forms.CharField(
|
||||||
|
max_length=1024, label=_("Email Subject Prefix"),
|
||||||
|
initial="[Jumpserver] "
|
||||||
|
)
|
||||||
|
AUTH_LDAP = forms.BooleanField(
|
||||||
|
label=_("Enable LDAP Auth"), initial=False, required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EmailSettingForm(BaseForm):
|
class EmailSettingForm(BaseForm):
|
||||||
EMAIL_HOST = forms.CharField(
|
EMAIL_HOST = forms.CharField(
|
||||||
max_length=1024, label=_("SMTP host"), initial='smtp.jumpserver.org'
|
max_length=1024, label=_("SMTP host"), initial='smtp.jumpserver.org'
|
||||||
|
@ -72,3 +97,35 @@ class EmailSettingForm(BaseForm):
|
||||||
label=_("Use TLS"), initial=False, required=False,
|
label=_("Use TLS"), initial=False, required=False,
|
||||||
help_text=_("If SMTP port is 587, may be select")
|
help_text=_("If SMTP port is 587, may be select")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPSettingForm(BaseForm):
|
||||||
|
AUTH_LDAP_SERVER_URI = forms.CharField(
|
||||||
|
label=_("LDAP server"), initial='ldap://localhost:389'
|
||||||
|
)
|
||||||
|
AUTH_LDAP_BIND_DN = forms.CharField(
|
||||||
|
label=_("Bind DN"), initial='cn=admin,dc=jumpserver,dc=org'
|
||||||
|
)
|
||||||
|
AUTH_LDAP_BIND_PASSWORD = forms.CharField(
|
||||||
|
label=_("Password"), initial='',
|
||||||
|
widget=forms.PasswordInput, required=False
|
||||||
|
)
|
||||||
|
AUTH_LDAP_SEARCH_OU = forms.CharField(
|
||||||
|
label=_("User OU"), initial='ou=tech,dc=jumpserver,dc=org'
|
||||||
|
)
|
||||||
|
AUTH_LDAP_SEARCH_FILTER = forms.CharField(
|
||||||
|
label=_("User search filter"), initial='(cn=%(user)s)'
|
||||||
|
)
|
||||||
|
AUTH_LDAP_USER_ATTR_MAP = DictField(
|
||||||
|
label=_("User attr map"),
|
||||||
|
initial=json.dumps({
|
||||||
|
"username": "cn",
|
||||||
|
"name": "sn",
|
||||||
|
"email": "mail"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
# AUTH_LDAP_GROUP_SEARCH_OU = CONFIG.AUTH_LDAP_GROUP_SEARCH_OU
|
||||||
|
# AUTH_LDAP_GROUP_SEARCH_FILTER = CONFIG.AUTH_LDAP_GROUP_SEARCH_FILTER
|
||||||
|
AUTH_LDAP_START_TLS = forms.BooleanField(
|
||||||
|
label=_("Use SSL"), initial=False, required=False
|
||||||
|
)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
import ldap
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django_auth_ldap.config import LDAPSearch
|
||||||
|
|
||||||
|
|
||||||
class SettingQuerySet(models.QuerySet):
|
class SettingQuerySet(models.QuerySet):
|
||||||
|
@ -30,6 +32,13 @@ class Setting(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value_(self):
|
||||||
|
try:
|
||||||
|
return json.loads(self.value)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def refresh_all_settings(cls):
|
def refresh_all_settings(cls):
|
||||||
settings_list = cls.objects.all()
|
settings_list = cls.objects.all()
|
||||||
|
@ -43,5 +52,17 @@ class Setting(models.Model):
|
||||||
return
|
return
|
||||||
setattr(settings, self.name, value)
|
setattr(settings, self.name, value)
|
||||||
|
|
||||||
|
if self.name == "AUTH_LDAP":
|
||||||
|
if self.value_ and settings.AUTH_LDAP_BACKEND not in settings.AUTHENTICATION_BACKENDS:
|
||||||
|
settings.AUTHENTICATION_BACKENDS.insert(0, settings.AUTH_LDAP_BACKEND)
|
||||||
|
elif not self.value_ and settings.AUTH_LDAP_BACKEND in settings.AUTHENTICATION_BACKENDS:
|
||||||
|
settings.AUTHENTICATION_BACKENDS.remove(settings.AUTH_LDAP_BACKEND)
|
||||||
|
|
||||||
|
if self.name == "AUTH_LDAP_SEARCH_FILTER":
|
||||||
|
settings.AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||||
|
settings.AUTH_LDAP_SEARCH_OU, ldap.SCOPE_SUBTREE,
|
||||||
|
settings.AUTH_LDAP_SEARCH_FILTER,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "settings"
|
db_table = "settings"
|
||||||
|
|
|
@ -8,3 +8,14 @@ class MailTestSerializer(serializers.Serializer):
|
||||||
EMAIL_HOST_PASSWORD = serializers.CharField()
|
EMAIL_HOST_PASSWORD = serializers.CharField()
|
||||||
EMAIL_USE_SSL = serializers.BooleanField(default=False)
|
EMAIL_USE_SSL = serializers.BooleanField(default=False)
|
||||||
EMAIL_USE_TLS = serializers.BooleanField(default=False)
|
EMAIL_USE_TLS = serializers.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPTestSerializer(serializers.Serializer):
|
||||||
|
AUTH_LDAP_SERVER_URI = serializers.CharField(max_length=1024)
|
||||||
|
AUTH_LDAP_BIND_DN = serializers.CharField(max_length=1024)
|
||||||
|
AUTH_LDAP_BIND_PASSWORD = serializers.CharField()
|
||||||
|
AUTH_LDAP_SEARCH_OU = serializers.CharField()
|
||||||
|
AUTH_LDAP_SEARCH_FILTER = serializers.CharField()
|
||||||
|
AUTH_LDAP_USER_ATTR_MAP = serializers.CharField()
|
||||||
|
AUTH_LDAP_START_TLS = serializers.BooleanField(required=False)
|
||||||
|
|
||||||
|
|
|
@ -4,3 +4,4 @@
|
||||||
from django.dispatch import Signal
|
from django.dispatch import Signal
|
||||||
|
|
||||||
django_ready = Signal()
|
django_ready = Signal()
|
||||||
|
ldap_auth_enable = Signal(providing_args=["enabled"])
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
import ldap
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
|
from django.conf import settings
|
||||||
|
from django_auth_ldap.config import LDAPSearch
|
||||||
|
|
||||||
from .models import Setting
|
from .models import Setting
|
||||||
from .utils import get_logger
|
from .utils import get_logger
|
||||||
from .signals import django_ready
|
from .signals import django_ready, ldap_auth_enable
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
@ -25,3 +26,17 @@ def refresh_all_settings_on_django_ready(sender, **kwargs):
|
||||||
logger.debug("Receive django ready signal")
|
logger.debug("Receive django ready signal")
|
||||||
logger.debug(" - fresh all settings")
|
logger.debug(" - fresh all settings")
|
||||||
Setting.refresh_all_settings()
|
Setting.refresh_all_settings()
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(ldap_auth_enable, dispatch_uid="my_unique_identifier")
|
||||||
|
def ldap_auth_on_changed(sender, enabled=True, **kwargs):
|
||||||
|
if enabled:
|
||||||
|
logger.debug("Enable LDAP auth")
|
||||||
|
if settings.AUTH_LDAP_BACKEND not in settings.AUTH_LDAP_BACKEND:
|
||||||
|
settings.AUTHENTICATION_BACKENDS.insert(0, settings.AUTH_LDAP_BACKEND)
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.debug("Disable LDAP auth")
|
||||||
|
if settings.AUTH_LDAP_BACKEND in settings.AUTHENTICATION_BACKENDS:
|
||||||
|
settings.AUTHENTICATION_BACKENDS.remove(settings.AUTH_LDAP_BACKEND)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load common_tags %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="ibox float-e-margins">
|
||||||
|
<div class="panel-options">
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li class="active">
|
||||||
|
<a href="" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Basic setting' %}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'settings:email-setting' %}" class="text-center"><i class="fa fa-envelope"></i> {% trans 'Email setting' %} </a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="col-sm-12" style="padding-left:0">
|
||||||
|
<div class="ibox-content" style="border-width: 0;padding-top: 40px;">
|
||||||
|
<form action="" method="post" class="form-horizontal">
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% csrf_token %}
|
||||||
|
{% for field in form %}
|
||||||
|
{% if not field.field|is_bool_field %}
|
||||||
|
{% bootstrap_field field layout="horizontal" %}
|
||||||
|
{% else %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{ field.label }}</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="col-sm-1">
|
||||||
|
{{ field }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<span class="help-block" >{{ field.help_text }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
|
<button class="btn btn-default btn-test" type="button"> {% trans 'Test connection' %}</button>
|
||||||
|
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
|
||||||
|
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block custom_foot_js %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
})
|
||||||
|
.on("click", ".btn-test", function () {
|
||||||
|
var data = {};
|
||||||
|
var form = $("form").serializeArray();
|
||||||
|
$.each(form, function (i, field) {
|
||||||
|
data[field.name] = field.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
var the_url = "{% url 'api-common:mail-testing' %}";
|
||||||
|
|
||||||
|
function error(message) {
|
||||||
|
toastr.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
function success(message) {
|
||||||
|
toastr.success(message.msg)
|
||||||
|
}
|
||||||
|
APIUpdateAttr({
|
||||||
|
url: the_url,
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
method: "POST",
|
||||||
|
flash_message: false,
|
||||||
|
success: success,
|
||||||
|
error: error
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
|
@ -4,10 +4,6 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load common_tags %}
|
{% load common_tags %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
|
||||||
<link href="{% static 'css/plugins/select2/select2.min.css' %}" rel="stylesheet">
|
|
||||||
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
|
||||||
{% endblock %}
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -16,10 +12,13 @@
|
||||||
<div class="panel-options">
|
<div class="panel-options">
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li>
|
<li>
|
||||||
<a href="" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Basic setting' %}</a>
|
<a href="{% url 'settings:basic-setting' %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Basic setting' %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a class="text-center"><i class="fa fa-envelope"></i> {% trans 'Email setting' %} </a>
|
<a href="{% url 'settings:email-setting' %}" class="text-center"><i class="fa fa-envelope"></i> {% trans 'Email setting' %} </a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,6 +52,7 @@
|
||||||
<div class="hr-line-dashed"></div>
|
<div class="hr-line-dashed"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-4 col-sm-offset-2">
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
|
<button class="btn btn-default btn-test" type="button"> {% trans 'Test connection' %}</button>
|
||||||
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
|
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
|
||||||
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -69,5 +69,33 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
<script>
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
})
|
||||||
|
.on("click", ".btn-test", function () {
|
||||||
|
var data = {};
|
||||||
|
var form = $("form").serializeArray();
|
||||||
|
$.each(form, function (i, field) {
|
||||||
|
data[field.name] = field.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
var the_url = "{% url 'api-common:mail-testing' %}";
|
||||||
|
|
||||||
|
function error(message) {
|
||||||
|
toastr.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
function success(message) {
|
||||||
|
toastr.success(message.msg)
|
||||||
|
}
|
||||||
|
APIUpdateAttr({
|
||||||
|
url: the_url,
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
method: "POST",
|
||||||
|
flash_message: false,
|
||||||
|
success: success,
|
||||||
|
error: error
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load common_tags %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="ibox float-e-margins">
|
||||||
|
<div class="panel-options">
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'settings:basic-setting' %}" class="text-center"><i class="fa fa-cubes"></i> {% trans 'Basic setting' %}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'settings:email-setting' %}" class="text-center"><i class="fa fa-envelope"></i> {% trans 'Email setting' %} </a>
|
||||||
|
</li>
|
||||||
|
<li class="active">
|
||||||
|
<a href="{% url 'settings:ldap-setting' %}" class="text-center"><i class="fa fa-archive"></i> {% trans 'LDAP setting' %} </a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="col-sm-12" style="padding-left:0">
|
||||||
|
<div class="ibox-content" style="border-width: 0;padding-top: 40px;">
|
||||||
|
<form action="" method="post" class="form-horizontal">
|
||||||
|
{% if form.non_field_errors %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% csrf_token %}
|
||||||
|
{% for field in form %}
|
||||||
|
{% if not field.field|is_bool_field %}
|
||||||
|
{% bootstrap_field field layout="horizontal" %}
|
||||||
|
{% else %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{ field.label }}</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div class="col-sm-1">
|
||||||
|
{{ field }}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<span class="help-block" >{{ field.help_text }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<div class="hr-line-dashed"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-4 col-sm-offset-2">
|
||||||
|
<button class="btn btn-default btn-test" type="button"> {% trans 'Test connection' %}</button>
|
||||||
|
<button class="btn btn-default" type="reset"> {% trans 'Reset' %}</button>
|
||||||
|
<button id="submit_button" class="btn btn-primary" type="submit">{% trans 'Submit' %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block custom_foot_js %}
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
})
|
||||||
|
.on("click", ".btn-test", function () {
|
||||||
|
var data = {};
|
||||||
|
var form = $("form").serializeArray();
|
||||||
|
$.each(form, function (i, field) {
|
||||||
|
data[field.name] = field.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
var the_url = "{% url 'api-common:ldap-testing' %}";
|
||||||
|
|
||||||
|
function error(message) {
|
||||||
|
toastr.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
function success(message) {
|
||||||
|
toastr.success(message.msg)
|
||||||
|
}
|
||||||
|
APIUpdateAttr({
|
||||||
|
url: the_url,
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
method: "POST",
|
||||||
|
flash_message: false,
|
||||||
|
success: success,
|
||||||
|
error: error
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
|
@ -8,4 +8,6 @@ app_name = 'common'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^v1/mail/testing/$', api.MailTestingAPI.as_view(), name='mail-testing'),
|
url(r'^v1/mail/testing/$', api.MailTestingAPI.as_view(), name='mail-testing'),
|
||||||
|
url(r'^v1/ldap/testing/$', api.LDAPTestingAPI.as_view(), name='ldap-testing'),
|
||||||
|
url(r'^v1/django-settings/$', api.DjangoSettingsAPI.as_view(), name='django-settings'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -7,5 +7,7 @@ from .. import views
|
||||||
app_name = 'common'
|
app_name = 'common'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
url(r'^$', views.BasicSettingView.as_view(), name='basic-setting'),
|
||||||
url(r'^email/$', views.EmailSettingView.as_view(), name='email-setting'),
|
url(r'^email/$', views.EmailSettingView.as_view(), name='email-setting'),
|
||||||
|
url(r'^ldap/$', views.LDAPSettingView.as_view(), name='ldap-setting'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -91,7 +91,7 @@ class Signer(metaclass=Singleton):
|
||||||
|
|
||||||
def date_expired_default():
|
def date_expired_default():
|
||||||
try:
|
try:
|
||||||
years = int(settings.CONFIG.DEFAULT_EXPIRED_YEARS)
|
years = int(settings.DEFAULT_EXPIRED_YEARS)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
years = 70
|
years = 70
|
||||||
return timezone.now() + timezone.timedelta(days=365*years)
|
return timezone.now() + timezone.timedelta(days=365*years)
|
||||||
|
|
|
@ -1,33 +1,85 @@
|
||||||
from django.views.generic import View
|
from django.views.generic import View, TemplateView
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render, redirect
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from .forms import EmailSettingForm
|
from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm
|
||||||
from .mixins import AdminUserRequiredMixin
|
from .mixins import AdminUserRequiredMixin
|
||||||
|
from .signals import ldap_auth_enable
|
||||||
|
|
||||||
|
|
||||||
class EmailSettingView(AdminUserRequiredMixin, View):
|
class BasicSettingView(AdminUserRequiredMixin, TemplateView):
|
||||||
|
form_class = BasicSettingForm
|
||||||
|
template_name = "common/basic_setting.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = {
|
||||||
|
'app': _('Settings'),
|
||||||
|
'action': _('Basic setting'),
|
||||||
|
'form': self.form_class(),
|
||||||
|
}
|
||||||
|
kwargs.update(context)
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
form = self.form_class(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
if "AUTH_LDAP" in form.cleaned_data:
|
||||||
|
ldap_auth_enable.send(form.cleaned_data["AUTH_LDAP"])
|
||||||
|
messages.success(request, _("Update basic setting successfully"))
|
||||||
|
return redirect('settings:basic-setting')
|
||||||
|
else:
|
||||||
|
context = self.get_context_data()
|
||||||
|
context.update({"form": form})
|
||||||
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
class EmailSettingView(AdminUserRequiredMixin, TemplateView):
|
||||||
form_class = EmailSettingForm
|
form_class = EmailSettingForm
|
||||||
template_name = "common/email_setting.html"
|
template_name = "common/email_setting.html"
|
||||||
|
|
||||||
def get(self, request):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': 'settings',
|
'app': _('Settings'),
|
||||||
'action': 'Email setting',
|
'action': _('Email setting'),
|
||||||
"form": EmailSettingForm(),
|
'form': self.form_class(),
|
||||||
}
|
}
|
||||||
return render(request, self.template_name, context)
|
kwargs.update(context)
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
form = self.form_class(request.POST)
|
form = self.form_class(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
messages.success(request, _("Update email setting successfully"))
|
messages.success(request, _("Update email setting successfully"))
|
||||||
|
return redirect('settings:email-setting')
|
||||||
|
else:
|
||||||
|
context = self.get_context_data()
|
||||||
|
context.update({"form": form})
|
||||||
|
return render(request, self.template_name, context)
|
||||||
|
|
||||||
|
|
||||||
|
class LDAPSettingView(AdminUserRequiredMixin, TemplateView):
|
||||||
|
form_class = LDAPSettingForm
|
||||||
|
template_name = "common/ldap_setting.html"
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': 'settings',
|
'app': _('Settings'),
|
||||||
'action': 'Email setting',
|
'action': _('LDAP setting'),
|
||||||
"form": EmailSettingForm(),
|
'form': self.form_class(),
|
||||||
}
|
}
|
||||||
return render(request, self.template_name, context)
|
kwargs.update(context)
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
form = self.form_class(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.success(request, _("Update ldap setting successfully"))
|
||||||
|
return redirect('settings:ldap-setting')
|
||||||
|
else:
|
||||||
|
context = self.get_context_data()
|
||||||
|
context.update({"form": form})
|
||||||
|
return render(request, self.template_name, context)
|
||||||
|
|
|
@ -15,7 +15,6 @@ import sys
|
||||||
|
|
||||||
import ldap
|
import ldap
|
||||||
from django_auth_ldap.config import LDAPSearch
|
from django_auth_ldap.config import LDAPSearch
|
||||||
|
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
|
||||||
|
|
||||||
|
@ -303,18 +302,28 @@ AUTH_USER_MODEL = 'users.User'
|
||||||
|
|
||||||
|
|
||||||
# Auth LDAP settings
|
# Auth LDAP settings
|
||||||
if CONFIG.AUTH_LDAP:
|
AUTH_LDAP = CONFIG.AUTH_LDAP
|
||||||
AUTHENTICATION_BACKENDS.insert(0, 'django_auth_ldap.backend.LDAPBackend')
|
AUTH_LDAP_SERVER_URI = CONFIG.AUTH_LDAP_SERVER_URI
|
||||||
AUTH_LDAP_SERVER_URI = CONFIG.AUTH_LDAP_SERVER_URI
|
AUTH_LDAP_BIND_DN = CONFIG.AUTH_LDAP_BIND_DN
|
||||||
AUTH_LDAP_BIND_DN = CONFIG.AUTH_LDAP_BIND_DN
|
AUTH_LDAP_BIND_PASSWORD = CONFIG.AUTH_LDAP_BIND_PASSWORD
|
||||||
AUTH_LDAP_BIND_PASSWORD = CONFIG.AUTH_LDAP_BIND_PASSWORD
|
AUTH_LDAP_SEARCH_OU = CONFIG.AUTH_LDAP_SEARCH_OU
|
||||||
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
AUTH_LDAP_SEARCH_FILTER = CONFIG.AUTH_LDAP_SEARCH_FILTER
|
||||||
CONFIG.AUTH_LDAP_SEARCH_OU,
|
AUTH_LDAP_START_TLS = CONFIG.AUTH_LDAP_START_TLS
|
||||||
ldap.SCOPE_SUBTREE,
|
AUTH_LDAP_USER_ATTR_MAP = CONFIG.AUTH_LDAP_USER_ATTR_MAP
|
||||||
CONFIG.AUTH_LDAP_SEARCH_FILTER
|
AUTH_LDAP_USER_SEARCH = LDAPSearch(
|
||||||
)
|
AUTH_LDAP_SEARCH_OU, ldap.SCOPE_SUBTREE, AUTH_LDAP_SEARCH_FILTER,
|
||||||
AUTH_LDAP_START_TLS = CONFIG.AUTH_LDAP_START_TLS
|
)
|
||||||
AUTH_LDAP_USER_ATTR_MAP = CONFIG.AUTH_LDAP_USER_ATTR_MAP
|
AUTH_LDAP_GROUP_SEARCH_OU = CONFIG.AUTH_LDAP_GROUP_SEARCH_OU
|
||||||
|
AUTH_LDAP_GROUP_SEARCH_FILTER = CONFIG.AUTH_LDAP_GROUP_SEARCH_FILTER
|
||||||
|
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
|
||||||
|
AUTH_LDAP_GROUP_SEARCH_OU, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_SEARCH_FILTER
|
||||||
|
)
|
||||||
|
AUTH_LDAP_ALWAYS_UPDATE_USER = True
|
||||||
|
AUTH_LDAP_BACKEND = 'django_auth_ldap.backend.LDAPBackend'
|
||||||
|
|
||||||
|
if AUTH_LDAP:
|
||||||
|
AUTHENTICATION_BACKENDS.insert(0, AUTH_LDAP_BACKEND)
|
||||||
|
|
||||||
|
|
||||||
# Celery using redis as broker
|
# Celery using redis as broker
|
||||||
CELERY_BROKER_URL = 'redis://:%(password)s@%(host)s:%(port)s/3' % {
|
CELERY_BROKER_URL = 'redis://:%(password)s@%(host)s:%(port)s/3' % {
|
||||||
|
@ -367,3 +376,7 @@ BOOTSTRAP3 = {
|
||||||
'set_placeholder': True,
|
'set_placeholder': True,
|
||||||
'success_css_class': '',
|
'success_css_class': '',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TOKEN_EXPIRATION = CONFIG.TOKEN_EXPIRATION or 3600
|
||||||
|
DISPLAY_PER_PAGE = CONFIG.DISPLAY_PER_PAGE
|
||||||
|
DEFAULT_EXPIRED_YEARS = 70
|
||||||
|
|
|
@ -10,7 +10,7 @@ from .hands import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
class TaskListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
|
class TaskListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
model = Task
|
model = Task
|
||||||
ordering = ('-date_created',)
|
ordering = ('-date_created',)
|
||||||
context_object_name = 'task_list'
|
context_object_name = 'task_list'
|
||||||
|
|
|
@ -93,7 +93,7 @@ class AssetPermissionUserView(AdminUserRequiredMixin,
|
||||||
ListView):
|
ListView):
|
||||||
template_name = 'perms/asset_permission_user.html'
|
template_name = 'perms/asset_permission_user.html'
|
||||||
context_object_name = 'asset_permission'
|
context_object_name = 'asset_permission'
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
object = None
|
object = None
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
@ -123,7 +123,7 @@ class AssetPermissionAssetView(AdminUserRequiredMixin,
|
||||||
ListView):
|
ListView):
|
||||||
template_name = 'perms/asset_permission_asset.html'
|
template_name = 'perms/asset_permission_asset.html'
|
||||||
context_object_name = 'asset_permission'
|
context_object_name = 'asset_permission'
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
object = None
|
object = None
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
|
@ -157,6 +157,11 @@ function APIUpdateAttr(props) {
|
||||||
props = props || {};
|
props = props || {};
|
||||||
var success_message = props.success_message || '更新成功!';
|
var success_message = props.success_message || '更新成功!';
|
||||||
var fail_message = props.fail_message || '更新时发生未知错误.';
|
var fail_message = props.fail_message || '更新时发生未知错误.';
|
||||||
|
var flash_message = true;
|
||||||
|
if (props.flash_message === false){
|
||||||
|
flash_message = false;
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: props.url,
|
url: props.url,
|
||||||
type: props.method || "PATCH",
|
type: props.method || "PATCH",
|
||||||
|
@ -164,12 +169,16 @@ function APIUpdateAttr(props) {
|
||||||
contentType: props.content_type || "application/json; charset=utf-8",
|
contentType: props.content_type || "application/json; charset=utf-8",
|
||||||
dataType: props.data_type || "json"
|
dataType: props.data_type || "json"
|
||||||
}).done(function(data, textStatue, jqXHR) {
|
}).done(function(data, textStatue, jqXHR) {
|
||||||
toastr.success(success_message);
|
if (flash_message) {
|
||||||
|
toastr.success(success_message);
|
||||||
|
}
|
||||||
if (typeof props.success === 'function') {
|
if (typeof props.success === 'function') {
|
||||||
return props.success(data);
|
return props.success(data);
|
||||||
}
|
}
|
||||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||||
toastr.error(fail_message);
|
if (flash_message) {
|
||||||
|
toastr.error(fail_message);
|
||||||
|
}
|
||||||
if (typeof props.error === 'function') {
|
if (typeof props.error === 'function') {
|
||||||
return props.error(jqXHR.responseText);
|
return props.error(jqXHR.responseText);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,8 @@
|
||||||
{# <li id="download"><a href="">{% trans 'File download' %}</a></li>#}
|
{# <li id="download"><a href="">{% trans 'File download' %}</a></li>#}
|
||||||
{# </ul>#}
|
{# </ul>#}
|
||||||
{#</li>#}
|
{#</li>#}
|
||||||
{#<li id="">#}
|
<li id="settings">
|
||||||
{# <a href="">#}
|
<a href="{% url 'settings:email-setting' %}">
|
||||||
{# <i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>#}
|
<i class="fa fa-gears"></i> <span class="nav-label">{% trans 'Settings' %}</span><span class="label label-info pull-right"></span>
|
||||||
{# </a>#}
|
</a>
|
||||||
{#</li>#}
|
</li>
|
|
@ -19,7 +19,7 @@ class CommandListView(DatetimeSearchMixin, ListView):
|
||||||
model = Command
|
model = Command
|
||||||
template_name = "terminal/command_list.html"
|
template_name = "terminal/command_list.html"
|
||||||
context_object_name = 'command_list'
|
context_object_name = 'command_list'
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
command = user = asset = system_user = ""
|
command = user = asset = system_user = ""
|
||||||
date_from = date_to = None
|
date_from = date_to = None
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class SessionListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView):
|
||||||
model = Session
|
model = Session
|
||||||
template_name = 'terminal/session_list.html'
|
template_name = 'terminal/session_list.html'
|
||||||
context_object_name = 'session_list'
|
context_object_name = 'session_list'
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
user = asset = system_user = ''
|
user = asset = system_user = ''
|
||||||
date_from = date_to = None
|
date_from = date_to = None
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ class AccessKeyAuthentication(authentication.BaseAuthentication):
|
||||||
class AccessTokenAuthentication(authentication.BaseAuthentication):
|
class AccessTokenAuthentication(authentication.BaseAuthentication):
|
||||||
keyword = 'Bearer'
|
keyword = 'Bearer'
|
||||||
model = User
|
model = User
|
||||||
expiration = settings.CONFIG.TOKEN_EXPIRATION or 3600
|
expiration = settings.TOKEN_EXPIRATION or 3600
|
||||||
|
|
||||||
def authenticate(self, request):
|
def authenticate(self, request):
|
||||||
auth = authentication.get_authorization_header(request).split()
|
auth = authentication.get_authorization_header(request).split()
|
||||||
|
|
|
@ -148,12 +148,7 @@ class User(AbstractUser):
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
if not self.name:
|
if not self.name:
|
||||||
self.name = self.username
|
self.name = self.username
|
||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
# Add the current user to the default group.
|
|
||||||
if not self.groups.count():
|
|
||||||
group = UserGroup.initial()
|
|
||||||
self.groups.add(group)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def private_token(self):
|
def private_token(self):
|
||||||
|
@ -253,6 +248,7 @@ class User(AbstractUser):
|
||||||
#: Use this method initial user
|
#: Use this method initial user
|
||||||
@classmethod
|
@classmethod
|
||||||
def initial(cls):
|
def initial(cls):
|
||||||
|
from .group import UserGroup
|
||||||
user = cls(username='admin',
|
user = cls(username='admin',
|
||||||
email='admin@jumpserver.org',
|
email='admin@jumpserver.org',
|
||||||
name=_('Administrator'),
|
name=_('Administrator'),
|
||||||
|
@ -268,6 +264,7 @@ class User(AbstractUser):
|
||||||
from random import seed, choice
|
from random import seed, choice
|
||||||
import forgery_py
|
import forgery_py
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
|
from .group import UserGroup
|
||||||
|
|
||||||
seed()
|
seed()
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
|
|
|
@ -2,16 +2,19 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.dispatch import Signal, receiver
|
from django.dispatch import Signal, receiver
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
|
from .models import User
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
on_user_created = Signal(providing_args=['user', 'request'])
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(on_user_created)
|
@receiver(post_save, sender=User)
|
||||||
def send_user_add_mail_to_user(sender, user=None, **kwargs):
|
def on_user_created(sender, instance=None, created=False, **kwargs):
|
||||||
from .utils import send_user_created_mail
|
if created:
|
||||||
logger.debug("Receive asset create signal, update asset hardware info")
|
logger.debug("Receive user `{}` create signal".format(instance.name))
|
||||||
send_user_created_mail(user)
|
from .utils import send_user_created_mail
|
||||||
|
logger.info(" - Sending welcome mail ...".format(instance.name))
|
||||||
|
send_user_created_mail(instance)
|
||||||
|
|
||||||
|
|
|
@ -151,12 +151,12 @@ def check_user_valid(**kwargs):
|
||||||
return None, _('Password or SSH public key invalid')
|
return None, _('Password or SSH public key invalid')
|
||||||
|
|
||||||
|
|
||||||
def refresh_token(token, user, expiration=settings.CONFIG.TOKEN_EXPIRATION or 3600):
|
def refresh_token(token, user, expiration=settings.TOKEN_EXPIRATION or 3600):
|
||||||
cache.set(token, user.id, expiration)
|
cache.set(token, user.id, expiration)
|
||||||
|
|
||||||
|
|
||||||
def generate_token(request, user):
|
def generate_token(request, user):
|
||||||
expiration = settings.CONFIG.TOKEN_EXPIRATION or 3600
|
expiration = settings.TOKEN_EXPIRATION or 3600
|
||||||
remote_addr = request.META.get('REMOTE_ADDR', '')
|
remote_addr = request.META.get('REMOTE_ADDR', '')
|
||||||
if not isinstance(remote_addr, bytes):
|
if not isinstance(remote_addr, bytes):
|
||||||
remote_addr = remote_addr.encode("utf-8")
|
remote_addr = remote_addr.encode("utf-8")
|
||||||
|
|
|
@ -185,7 +185,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
|
||||||
user.is_public_key_valid = True
|
user.is_public_key_valid = True
|
||||||
user.save()
|
user.save()
|
||||||
context = {
|
context = {
|
||||||
'user_guide_url': settings.CONFIG.USER_GUIDE_URL
|
'user_guide_url': settings.USER_GUIDE_URL
|
||||||
}
|
}
|
||||||
return render(self.request, 'users/first_login_done.html', context)
|
return render(self.request, 'users/first_login_done.html', context)
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ class UserFirstLoginView(LoginRequiredMixin, SessionWizardView):
|
||||||
class LoginLogListView(DatetimeSearchMixin, ListView):
|
class LoginLogListView(DatetimeSearchMixin, ListView):
|
||||||
template_name = 'users/login_log_list.html'
|
template_name = 'users/login_log_list.html'
|
||||||
model = LoginLog
|
model = LoginLog
|
||||||
paginate_by = settings.CONFIG.DISPLAY_PER_PAGE
|
paginate_by = settings.DISPLAY_PER_PAGE
|
||||||
user = keyword = ""
|
user = keyword = ""
|
||||||
date_to = date_from = None
|
date_to = date_from = None
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,6 @@ class UserCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView):
|
||||||
user = form.save(commit=False)
|
user = form.save(commit=False)
|
||||||
user.created_by = self.request.user.username or 'System'
|
user.created_by = self.request.user.username or 'System'
|
||||||
user.save()
|
user.save()
|
||||||
on_user_created.send(self.__class__, user=user)
|
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue