diff --git a/apps/assets/views/cluster.py b/apps/assets/views/cluster.py index 835229fc1..5df58953c 100644 --- a/apps/assets/views/cluster.py +++ b/apps/assets/views/cluster.py @@ -60,11 +60,6 @@ class ClusterUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView) success_url = reverse_lazy('assets:cluster-list') success_message = update_success_msg - def form_valid(self, form): - cluster = form.save(commit=False) - cluster.save() - return super().form_valid(form) - def get_context_data(self, **kwargs): context = { 'app': _('assets'), diff --git a/apps/common/api.py b/apps/common/api.py index e8680e85e..e75f6147a 100644 --- a/apps/common/api.py +++ b/apps/common/api.py @@ -63,8 +63,6 @@ class LDAPTestingAPI(APIView): 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: @@ -77,9 +75,6 @@ class LDAPTestingAPI(APIView): 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: diff --git a/apps/common/fields.py b/apps/common/fields.py index 36a8bdf9a..f19689830 100644 --- a/apps/common/fields.py +++ b/apps/common/fields.py @@ -18,7 +18,6 @@ class DictField(forms.Field): # 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: diff --git a/apps/common/forms.py b/apps/common/forms.py index 6b83c54cc..3eb8c4989 100644 --- a/apps/common/forms.py +++ b/apps/common/forms.py @@ -4,7 +4,9 @@ import json from django import forms from django.utils.translation import ugettext_lazy as _ +from django.utils.html import escape from django.db import transaction +from django.conf import settings from .models import Setting from .fields import DictField @@ -30,28 +32,32 @@ def to_form_value(value): class BaseForm(forms.Form): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - settings = Setting.objects.all() + db_settings = Setting.objects.all() for name, field in self.fields.items(): - db_value = getattr(settings, name).value - if db_value: + db_value = getattr(db_settings, name).value + django_value = getattr(settings, name) if hasattr(settings, name) else None + if db_value is False or db_value: field.initial = to_form_value(db_value) + elif django_value is False or django_value: + field.initial = django_value - def save(self): + def save(self, category="default"): if not self.is_bound: raise ValueError("Form is not bound") - settings = Setting.objects.all() + db_settings = Setting.objects.all() if self.is_valid(): with transaction.atomic(): for name, value in self.cleaned_data.items(): field = self.fields[name] if isinstance(field.widget, forms.PasswordInput) and not value: continue - if value == to_form_value(getattr(settings, name).value): + if value == to_form_value(getattr(db_settings, name).value): continue defaults = { 'name': name, + 'category': category, 'value': to_model_value(value) } Setting.objects.update_or_create(defaults=defaults, name=name) @@ -126,6 +132,28 @@ class LDAPSettingForm(BaseForm): AUTH_LDAP_START_TLS = forms.BooleanField( label=_("Use SSL"), initial=False, required=False ) - AUTH_LDAP = forms.BooleanField( - label=_("Enable LDAP Auth"), initial=False, required=False + + +class TerminalSettingForm(BaseForm): + SORT_BY_CHOICES = ( + ('hostname', _('Hostname')), + ('ip', _('IP')), + ) + TERMINAL_ASSET_LIST_SORT_BY = forms.ChoiceField( + choices=SORT_BY_CHOICES, initial='hostname', label=_("List sort by") + ) + TERMINAL_HEARTBEAT_INTERVAL = forms.IntegerField( + initial=5, label=_("Heartbeat interval"), help_text=_("Units: seconds") + ) + TERMINAL_PASSWORD_AUTH = forms.BooleanField( + initial=True, required=False, label=_("Password auth") + ) + TERMINAL_PUBLIC_KEY_AUTH = forms.BooleanField( + initial=True, required=False, label=_("Public key auth") + ) + TERMINAL_COMMAND_STORAGE = DictField( + label=_("Command storage"), help_text=_( + "Set terminal storage setting, `default` is the using as default," + "You can set other storage and some terminal using" + ) ) diff --git a/apps/common/models.py b/apps/common/models.py index 091b8b83a..1f634bce2 100644 --- a/apps/common/models.py +++ b/apps/common/models.py @@ -2,6 +2,7 @@ import json import ldap from django.db import models +from django.db.utils import ProgrammingError, OperationalError from django.utils.translation import ugettext_lazy as _ from django.conf import settings from django_auth_ldap.config import LDAPSearch @@ -24,6 +25,7 @@ class SettingManager(models.Manager): class Setting(models.Model): name = models.CharField(max_length=128, unique=True, verbose_name=_("Name")) value = models.TextField(verbose_name=_("Value")) + category = models.CharField(max_length=128, default="default") enabled = models.BooleanField(verbose_name=_("Enabled"), default=True) comment = models.TextField(verbose_name=_("Comment")) @@ -33,17 +35,28 @@ class Setting(models.Model): return self.name @property - def value_(self): + def cleaned_value(self): try: return json.loads(self.value) except json.JSONDecodeError: return None + @cleaned_value.setter + def cleaned_value(self, item): + try: + v = json.dumps(item) + self.value = v + except json.JSONDecodeError as e: + raise ValueError("Json dump error: {}".format(str(e))) + @classmethod def refresh_all_settings(cls): - settings_list = cls.objects.all() - for setting in settings_list: - setting.refresh_setting() + try: + settings_list = cls.objects.all() + for setting in settings_list: + setting.refresh_setting() + except (ProgrammingError, OperationalError): + pass def refresh_setting(self): try: @@ -53,9 +66,9 @@ class Setting(models.Model): setattr(settings, self.name, value) if self.name == "AUTH_LDAP": - if self.value_ and settings.AUTH_LDAP_BACKEND not in settings.AUTHENTICATION_BACKENDS: + if self.cleaned_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: + elif not self.cleaned_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": diff --git a/apps/common/templates/common/_add_terminal_command_storage_modal.html b/apps/common/templates/common/_add_terminal_command_storage_modal.html new file mode 100644 index 000000000..678152981 --- /dev/null +++ b/apps/common/templates/common/_add_terminal_command_storage_modal.html @@ -0,0 +1,21 @@ +{% extends '_modal.html' %} +{% load i18n %} +{% block modal_id %}add_command_storage_model{% endblock %} +{% block modal_title%}{% trans "Add command storage" %}{% endblock %} +{% block modal_body %} +
+ {% csrf_token %} +
+ + {% trans 'Download' %} +
+
+ + + + {% trans 'If set id, will use this id update asset existed' %} + +
+
+{% endblock %} +{% block modal_confirm_id %}btn_asset_import{% endblock %} diff --git a/apps/common/templates/common/basic_setting.html b/apps/common/templates/common/basic_setting.html index fb5039795..496eca977 100644 --- a/apps/common/templates/common/basic_setting.html +++ b/apps/common/templates/common/basic_setting.html @@ -20,6 +20,9 @@
  • {% trans 'LDAP setting' %}
  • +
  • + {% trans 'Terminal setting' %} +
  • diff --git a/apps/common/templates/common/email_setting.html b/apps/common/templates/common/email_setting.html index 7561849bd..1fd772db1 100644 --- a/apps/common/templates/common/email_setting.html +++ b/apps/common/templates/common/email_setting.html @@ -20,6 +20,9 @@
  • {% trans 'LDAP setting' %}
  • +
  • + {% trans 'Terminal setting' %} +
  • diff --git a/apps/common/templates/common/ldap_setting.html b/apps/common/templates/common/ldap_setting.html index 26f021569..f0569f873 100644 --- a/apps/common/templates/common/ldap_setting.html +++ b/apps/common/templates/common/ldap_setting.html @@ -20,6 +20,9 @@
  • {% trans 'LDAP setting' %}
  • +
  • + {% trans 'Terminal setting' %} +
  • diff --git a/apps/common/templates/common/terminal_setting.html b/apps/common/templates/common/terminal_setting.html new file mode 100644 index 000000000..3d0b7eb6f --- /dev/null +++ b/apps/common/templates/common/terminal_setting.html @@ -0,0 +1,130 @@ +{% extends 'base.html' %} +{% load static %} +{% load bootstrap3 %} +{% load i18n %} +{% load common_tags %} + +{% block content %} +
    +
    +
    +
    + +
    +
    +
    +
    + {% if form.non_field_errors %} +
    + {{ form.non_field_errors }} +
    + {% endif %} + {% csrf_token %} +

    {% trans "Basic setting" %}

    + {% for field in form %} + {% if not field.field|is_bool_field %} + {% bootstrap_field field layout="horizontal" %} + {% else %} +
    + +
    +
    + {{ field }} +
    +
    + {{ field.help_text }} +
    +
    +
    + {% endif %} + {% endfor %} + +
    +

    {% trans "Command storage" %}

    + + + + + + + + + {% for name, setting in command_storage.items %} + + + + + {% endfor %} + +
    {% trans 'Name' %}{% trans 'Type' %}
    {{ name }}{{ setting.TYPE }}
    +{# #} +
    +

    {% trans "Replay storage" %}

    + +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + {% include 'common/_add_terminal_command_storage_modal.html' %} +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/common/urls/view_urls.py b/apps/common/urls/view_urls.py index ff8086bde..466f7c49c 100644 --- a/apps/common/urls/view_urls.py +++ b/apps/common/urls/view_urls.py @@ -10,4 +10,5 @@ urlpatterns = [ url(r'^$', views.BasicSettingView.as_view(), name='basic-setting'), url(r'^email/$', views.EmailSettingView.as_view(), name='email-setting'), url(r'^ldap/$', views.LDAPSettingView.as_view(), name='ldap-setting'), + url(r'^terminal/$', views.TerminalSettingView.as_view(), name='terminal-setting'), ] diff --git a/apps/common/views.py b/apps/common/views.py index 43b249cee..dc0d74f92 100644 --- a/apps/common/views.py +++ b/apps/common/views.py @@ -1,9 +1,12 @@ -from django.views.generic import View, TemplateView +from django.views.generic import TemplateView from django.shortcuts import render, redirect from django.contrib import messages from django.utils.translation import ugettext as _ +from django.conf import settings -from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm +from .forms import EmailSettingForm, LDAPSettingForm, BasicSettingForm, \ + TerminalSettingForm +from .models import Setting from .mixins import AdminUserRequiredMixin from .signals import ldap_auth_enable @@ -86,3 +89,31 @@ class LDAPSettingView(AdminUserRequiredMixin, TemplateView): context = self.get_context_data() context.update({"form": form}) return render(request, self.template_name, context) + + +class TerminalSettingView(AdminUserRequiredMixin, TemplateView): + form_class = TerminalSettingForm + template_name = "common/terminal_setting.html" + + def get_context_data(self, **kwargs): + command_storage = settings.TERMINAL_COMMAND_STORAGE + context = { + 'app': _('Settings'), + 'action': _('Terminal setting'), + 'form': self.form_class(), + 'command_storage': command_storage, + } + 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() + msg = _("Update setting successfully, please restart program") + messages.success(request, msg) + return redirect('settings:terminal-setting') + else: + context = self.get_context_data() + context.update({"form": form}) + return render(request, self.template_name, context) diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index 8b0aa2a64..62ea2d657 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -373,7 +373,20 @@ CAPTCHA_FOREGROUND_COLOR = '#001100' CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',) CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE -COMMAND_STORAGE_BACKEND = 'terminal.backends.command.db' +COMMAND_STORAGE = { + 'ENGINE': 'terminal.backends.command.db', +} + +TERMINAL_COMMAND_STORAGE = { + 'default': { + 'TYPE': 'server', + }, + # 'ali-es': { + # 'TYPE': 'elasticsearch', + # 'HOSTS': ['http://elastic:changeme@localhost:9200'], + # }, +} + # Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html BOOTSTRAP3 = { diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 7be8a996a..f64890662 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index ebcc5ac66..ec16cc439 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Jumpserver 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-01-17 17:26+0800\n" +"POT-Creation-Date: 2018-01-22 11:04+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" #: assets/forms.py:23 assets/forms.py:53 assets/forms.py:99 perms/forms.py:37 -#: perms/templates/perms/asset_permission_asset.html:116 users/forms.py:246 +#: perms/templates/perms/asset_permission_asset.html:116 users/forms.py:245 msgid "Select asset groups" msgstr "选择资产组" @@ -44,7 +44,7 @@ msgstr "默认使用管理用户" #: assets/forms.py:76 assets/forms.py:81 assets/forms.py:127 #: assets/templates/assets/asset_group_detail.html:75 perms/forms.py:34 -#: perms/templates/perms/asset_permission_asset.html:88 users/forms.py:243 +#: perms/templates/perms/asset_permission_asset.html:88 users/forms.py:242 msgid "Select assets" msgstr "选择资产" @@ -66,7 +66,7 @@ msgstr "端口" #: assets/templates/assets/system_user_list.html:26 perms/models.py:17 #: perms/templates/perms/asset_permission_create_update.html:40 #: perms/templates/perms/asset_permission_list.html:28 templates/_nav.html:22 -#: terminal/backends/command/models.py:11 terminal/models.py:93 +#: terminal/backends/command/models.py:11 terminal/models.py:124 #: terminal/templates/terminal/command_list.html:40 #: terminal/templates/terminal/command_list.html:73 #: terminal/templates/terminal/session_list.html:41 @@ -77,7 +77,7 @@ msgid "Asset" msgstr "资产" #: assets/forms.py:161 perms/forms.py:40 -#: perms/templates/perms/asset_permission_detail.html:144 users/forms.py:249 +#: perms/templates/perms/asset_permission_detail.html:144 users/forms.py:248 msgid "Select system users" msgstr "选择系统用户" @@ -99,14 +99,15 @@ msgstr "选择的系统用户将会在该集群资产上创建" #: assets/templates/assets/cluster_detail.html:57 #: assets/templates/assets/cluster_list.html:19 #: assets/templates/assets/system_user_detail.html:58 -#: assets/templates/assets/system_user_list.html:24 common/models.py:25 -#: ops/models.py:31 ops/templates/ops/task_detail.html:56 -#: ops/templates/ops/task_list.html:34 perms/models.py:14 +#: assets/templates/assets/system_user_list.html:24 common/models.py:26 +#: common/templates/common/terminal_setting.html:62 ops/models.py:31 +#: ops/templates/ops/task_detail.html:56 ops/templates/ops/task_list.html:34 +#: perms/models.py:14 #: perms/templates/perms/asset_permission_create_update.html:33 #: perms/templates/perms/asset_permission_detail.html:62 #: perms/templates/perms/asset_permission_list.html:25 -#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:14 -#: terminal/models.py:118 terminal/templates/terminal/terminal_detail.html:43 +#: perms/templates/perms/asset_permission_user.html:54 terminal/models.py:23 +#: terminal/models.py:149 terminal/templates/terminal/terminal_detail.html:43 #: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 #: users/models/user.py:35 users/templates/users/_select_user_modal.html:13 #: users/templates/users/user_detail.html:62 @@ -126,10 +127,10 @@ msgstr "集群级别管理用户" #: assets/forms.py:200 msgid "Password or private key password" -msgstr "密码或秘钥不合法" +msgstr "密码或秘钥密码" #: assets/forms.py:201 assets/forms.py:262 assets/models/user.py:30 -#: common/forms.py:107 users/forms.py:16 users/forms.py:24 +#: common/forms.py:113 users/forms.py:16 users/forms.py:24 #: users/templates/users/login.html:56 #: users/templates/users/reset_password.html:52 #: users/templates/users/user_create.html:11 @@ -239,7 +240,7 @@ msgstr "测试环境" #: assets/templates/assets/asset_list.html:31 #: assets/templates/assets/cluster_assets.html:52 #: assets/templates/assets/system_user_asset.html:53 -#: assets/templates/assets/user_asset_list.html:20 +#: assets/templates/assets/user_asset_list.html:20 common/forms.py:140 #: perms/templates/perms/asset_permission_asset.html:55 #: users/templates/users/login_log_list.html:52 #: users/templates/users/user_granted_asset.html:49 @@ -253,7 +254,7 @@ msgstr "IP" #: assets/templates/assets/asset_list.html:30 #: assets/templates/assets/cluster_assets.html:51 #: assets/templates/assets/system_user_asset.html:52 -#: assets/templates/assets/user_asset_list.html:19 +#: assets/templates/assets/user_asset_list.html:19 common/forms.py:139 #: perms/templates/perms/asset_permission_asset.html:54 #: users/templates/users/user_granted_asset.html:48 #: users/templates/users/user_group_granted_asset.html:49 @@ -400,9 +401,9 @@ msgstr "创建日期" #: assets/templates/assets/asset_group_list.html:17 #: assets/templates/assets/cluster_detail.html:97 #: assets/templates/assets/system_user_detail.html:100 -#: assets/templates/assets/system_user_list.html:30 common/models.py:28 +#: assets/templates/assets/system_user_list.html:30 common/models.py:30 #: ops/models.py:37 perms/models.py:24 -#: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:22 +#: perms/templates/perms/asset_permission_detail.html:98 terminal/models.py:33 #: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 #: users/models/user.py:47 users/templates/users/user_detail.html:110 #: users/templates/users/user_group_detail.html:67 @@ -494,7 +495,7 @@ msgstr "Shell" #: assets/models/user.py:269 perms/models.py:19 #: perms/templates/perms/asset_permission_detail.html:136 #: perms/templates/perms/asset_permission_list.html:30 templates/_nav.html:26 -#: terminal/backends/command/models.py:12 terminal/models.py:94 +#: terminal/backends/command/models.py:12 terminal/models.py:125 #: terminal/templates/terminal/command_list.html:48 #: terminal/templates/terminal/command_list.html:74 #: terminal/templates/terminal/session_list.html:49 @@ -576,9 +577,9 @@ msgstr "仅修改你需要更新的字段" #: assets/views/admin_user.py:106 assets/views/asset.py:48 #: assets/views/asset.py:61 assets/views/asset.py:84 assets/views/asset.py:144 #: assets/views/asset.py:161 assets/views/asset.py:185 -#: assets/views/cluster.py:26 assets/views/cluster.py:85 -#: assets/views/cluster.py:102 assets/views/group.py:34 -#: assets/views/group.py:52 assets/views/group.py:69 assets/views/group.py:87 +#: assets/views/cluster.py:26 assets/views/cluster.py:80 +#: assets/views/cluster.py:97 assets/views/group.py:34 assets/views/group.py:52 +#: assets/views/group.py:69 assets/views/group.py:87 #: assets/views/system_user.py:28 assets/views/system_user.py:44 #: assets/views/system_user.py:60 assets/views/system_user.py:75 #: templates/_nav.html:19 @@ -602,20 +603,24 @@ msgid "Import asset" msgstr "导入资产" #: assets/templates/assets/_asset_import_modal.html:9 +#: common/templates/common/_add_terminal_command_storage_modal.html:9 #: users/templates/users/_user_import_modal.html:10 msgid "Template" msgstr "模板" #: assets/templates/assets/_asset_import_modal.html:10 +#: common/templates/common/_add_terminal_command_storage_modal.html:10 #: users/templates/users/_user_import_modal.html:11 msgid "Download" msgstr "下载" #: assets/templates/assets/_asset_import_modal.html:13 +#: common/templates/common/_add_terminal_command_storage_modal.html:13 msgid "Asset csv file" msgstr "资产csv文件" #: assets/templates/assets/_asset_import_modal.html:16 +#: common/templates/common/_add_terminal_command_storage_modal.html:16 msgid "If set id, will use this id update asset existed" msgstr "如果设置了id,则会使用该行信息更新该id的资产" @@ -650,7 +655,7 @@ msgstr "自动生成秘钥" #: assets/templates/assets/asset_update.html:47 #: assets/templates/assets/cluster_create_update.html:46 #: perms/templates/perms/asset_permission_create_update.html:45 -#: terminal/templates/terminal/terminal_update.html:40 +#: terminal/templates/terminal/terminal_update.html:41 msgid "Other" msgstr "其它" @@ -661,11 +666,12 @@ msgstr "其它" #: assets/templates/assets/asset_group_create.html:16 #: assets/templates/assets/asset_update.html:55 #: assets/templates/assets/cluster_create_update.html:54 -#: common/templates/common/basic_setting.html:55 -#: common/templates/common/email_setting.html:56 -#: common/templates/common/ldap_setting.html:56 +#: common/templates/common/basic_setting.html:58 +#: common/templates/common/email_setting.html:59 +#: common/templates/common/ldap_setting.html:59 +#: common/templates/common/terminal_setting.html:82 #: perms/templates/perms/asset_permission_create_update.html:67 -#: terminal/templates/terminal/terminal_update.html:45 +#: terminal/templates/terminal/terminal_update.html:46 #: users/templates/users/_user.html:49 #: users/templates/users/user_bulk_update.html:23 #: users/templates/users/user_password_update.html:58 @@ -684,11 +690,12 @@ msgstr "重置" #: assets/templates/assets/asset_list.html:53 #: assets/templates/assets/asset_update.html:56 #: assets/templates/assets/cluster_create_update.html:55 -#: common/templates/common/basic_setting.html:56 -#: common/templates/common/email_setting.html:57 -#: common/templates/common/ldap_setting.html:57 +#: common/templates/common/basic_setting.html:59 +#: common/templates/common/email_setting.html:60 +#: common/templates/common/ldap_setting.html:60 +#: common/templates/common/terminal_setting.html:83 #: perms/templates/perms/asset_permission_create_update.html:68 -#: terminal/templates/terminal/terminal_update.html:46 +#: terminal/templates/terminal/terminal_update.html:47 #: users/templates/users/_user.html:50 #: users/templates/users/first_login.html:62 #: users/templates/users/forgot_password.html:44 @@ -778,6 +785,7 @@ msgstr "资产列表" #: assets/templates/assets/asset_group_detail.html:53 #: assets/templates/assets/cluster_assets.html:54 #: assets/templates/assets/user_asset_list.html:22 +#: common/templates/common/terminal_setting.html:63 #: users/templates/users/login_log_list.html:50 msgid "Type" msgstr "类型" @@ -878,7 +886,7 @@ msgid "Group" msgstr "组" #: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:186 -#: assets/views/cluster.py:103 +#: assets/views/cluster.py:98 msgid "Asset detail" msgstr "资产详情" @@ -1236,16 +1244,16 @@ msgstr "已经存在" msgid "Cluster list" msgstr "集群列表" -#: assets/views/cluster.py:42 assets/views/cluster.py:70 +#: assets/views/cluster.py:42 assets/views/cluster.py:65 #: assets/views/system_user.py:96 msgid "assets" msgstr "资产管理" -#: assets/views/cluster.py:71 +#: assets/views/cluster.py:66 msgid "Update Cluster" msgstr "更新Cluster" -#: assets/views/cluster.py:86 +#: assets/views/cluster.py:81 msgid "Cluster detail" msgstr "集群详情" @@ -1291,81 +1299,108 @@ msgstr "%(name)s 创建成功" msgid "%(name)s was updated successfully" msgstr "%(name)s 更新成功" -#: common/forms.py:64 +#: common/forms.py:70 msgid "Current SITE URL" msgstr "当前站点URL" -#: common/forms.py:68 +#: common/forms.py:74 msgid "User Guide URL" msgstr "用户向导URL" -#: common/forms.py:69 +#: common/forms.py:75 msgid "User first login update profile done redirect to it" msgstr "用户第一次登录,修改profile后重定向到地址" -#: common/forms.py:72 +#: common/forms.py:78 msgid "Email Subject Prefix" msgstr "Email主题前缀" -#: common/forms.py:79 +#: common/forms.py:85 msgid "SMTP host" msgstr "SMTP主机" -#: common/forms.py:81 +#: common/forms.py:87 msgid "SMTP port" msgstr "SMTP端口" -#: common/forms.py:83 +#: common/forms.py:89 msgid "SMTP user" msgstr "SMTP账号" -#: common/forms.py:86 +#: common/forms.py:92 msgid "SMTP password" msgstr "SMTP密码" -#: common/forms.py:87 +#: common/forms.py:93 msgid "Some provider use token except password" msgstr "一些邮件提供商需要输入的是Token" -#: common/forms.py:90 common/forms.py:127 +#: common/forms.py:96 common/forms.py:133 msgid "Use SSL" msgstr "使用SSL" -#: common/forms.py:91 +#: common/forms.py:97 msgid "If SMTP port is 465, may be select" msgstr "如果SMTP端口是465,通常需要启用SSL" -#: common/forms.py:94 +#: common/forms.py:100 msgid "Use TLS" msgstr "使用TLS" -#: common/forms.py:95 +#: common/forms.py:101 msgid "If SMTP port is 587, may be select" msgstr "如果SMTP端口是587,通常需要启用TLS" -#: common/forms.py:101 +#: common/forms.py:107 msgid "LDAP server" msgstr "LDAP地址" -#: common/forms.py:104 +#: common/forms.py:110 msgid "Bind DN" msgstr "绑定DN" -#: common/forms.py:111 +#: common/forms.py:117 msgid "User OU" msgstr "用户OU" -#: common/forms.py:114 +#: common/forms.py:120 msgid "User search filter" msgstr "用户过滤器" -#: common/forms.py:117 +#: common/forms.py:123 msgid "User attr map" msgstr "LDAP属性映射" -#: common/forms.py:130 -msgid "Enable LDAP Auth" -msgstr "开启LDAP认证" +#: common/forms.py:143 +msgid "List sort by" +msgstr "资产列表排序" + +#: common/forms.py:146 +msgid "Heartbeat interval" +msgstr "心跳间隔" + +#: common/forms.py:146 ops/models.py:32 +msgid "Units: seconds" +msgstr "单位: 秒" + +#: common/forms.py:149 +msgid "Password auth" +msgstr "密码认证" + +#: common/forms.py:152 +msgid "Public key auth" +msgstr "秘钥认证" + +#: common/forms.py:155 common/templates/common/terminal_setting.html:58 +#: terminal/models.py:27 +msgid "Command storage" +msgstr "命令存储" + +#: common/forms.py:156 +msgid "" +"Set terminal storage setting, `default` is the using as default,You can set " +"other storage and some terminal using" +msgstr "设置终端命令存储,default是默认用的存储方式" #: common/mixins.py:29 msgid "is discard" @@ -1375,43 +1410,62 @@ msgstr "" msgid "discard time" msgstr "" -#: common/models.py:26 +#: common/models.py:27 msgid "Value" msgstr "值" -#: common/models.py:27 +#: common/models.py:29 msgid "Enabled" msgstr "启用" +#: common/templates/common/_add_terminal_command_storage_modal.html:4 +msgid "Add command storage" +msgstr "添加命令存储" + #: common/templates/common/basic_setting.html:15 #: common/templates/common/email_setting.html:15 -#: common/templates/common/ldap_setting.html:15 common/views.py:18 +#: common/templates/common/ldap_setting.html:15 +#: common/templates/common/terminal_setting.html:15 +#: common/templates/common/terminal_setting.html:38 common/views.py:21 msgid "Basic setting" msgstr "基本设置" #: common/templates/common/basic_setting.html:18 #: common/templates/common/email_setting.html:18 -#: common/templates/common/ldap_setting.html:18 common/views.py:44 +#: common/templates/common/ldap_setting.html:18 +#: common/templates/common/terminal_setting.html:18 common/views.py:47 msgid "Email setting" msgstr "邮件设置" #: common/templates/common/basic_setting.html:21 #: common/templates/common/email_setting.html:21 -#: common/templates/common/ldap_setting.html:21 common/views.py:70 +#: common/templates/common/ldap_setting.html:21 +#: common/templates/common/terminal_setting.html:21 common/views.py:73 msgid "LDAP setting" msgstr "LDAP设置" -#: common/templates/common/email_setting.html:55 -#: common/templates/common/ldap_setting.html:55 +#: common/templates/common/basic_setting.html:24 +#: common/templates/common/email_setting.html:24 +#: common/templates/common/ldap_setting.html:24 +#: common/templates/common/terminal_setting.html:24 common/views.py:102 +msgid "Terminal setting" +msgstr "终端设置" + +#: common/templates/common/email_setting.html:58 +#: common/templates/common/ldap_setting.html:58 msgid "Test connection" msgstr "测试连接" -#: common/views.py:17 common/views.py:43 common/views.py:69 +#: common/templates/common/terminal_setting.html:77 terminal/models.py:28 +msgid "Replay storage" +msgstr "录像存储" + +#: common/views.py:20 common/views.py:46 common/views.py:72 common/views.py:101 #: templates/_nav.html:69 msgid "Settings" msgstr "系统设置" -#: common/views.py:28 common/views.py:54 common/views.py:82 +#: common/views.py:31 common/views.py:57 common/views.py:85 common/views.py:113 msgid "Update setting successfully, please restart program" msgstr "更新设置成功, 请手动重启程序" @@ -1419,10 +1473,6 @@ msgstr "更新设置成功, 请手动重启程序" msgid "Interval" msgstr "间隔" -#: ops/models.py:32 -msgid "Units: seconds" -msgstr "单位: 秒" - #: ops/models.py:33 msgid "Crontab" msgstr "Crontab" @@ -1566,7 +1616,7 @@ msgstr "执行历史" #: ops/templates/ops/adhoc_history.html:52 #: ops/templates/ops/adhoc_history_detail.html:58 -#: ops/templates/ops/task_history.html:55 terminal/models.py:101 +#: ops/templates/ops/task_history.html:55 terminal/models.py:132 #: terminal/templates/terminal/session_list.html:77 msgid "Date start" msgstr "开始日期" @@ -1683,18 +1733,18 @@ msgid "Task run history" msgstr "执行历史" #: perms/forms.py:16 users/forms.py:147 users/forms.py:152 users/forms.py:164 -#: users/forms.py:195 +#: users/forms.py:194 msgid "Select users" msgstr "选择用户" #: perms/forms.py:18 perms/models.py:15 #: perms/templates/perms/asset_permission_create_update.html:36 #: perms/templates/perms/asset_permission_list.html:26 templates/_nav.html:12 -#: terminal/backends/command/models.py:10 terminal/models.py:92 +#: terminal/backends/command/models.py:10 terminal/models.py:123 #: terminal/templates/terminal/command_list.html:32 #: terminal/templates/terminal/command_list.html:72 #: terminal/templates/terminal/session_list.html:33 -#: terminal/templates/terminal/session_list.html:71 users/forms.py:191 +#: terminal/templates/terminal/session_list.html:71 users/forms.py:190 #: users/models/user.py:30 users/templates/users/user_group_detail.html:78 #: users/views/user.py:337 msgid "User" @@ -1949,7 +1999,7 @@ msgstr "在线会话" msgid "Session offline" msgstr "离线会话" -#: templates/_nav.html:53 terminal/models.py:99 +#: templates/_nav.html:53 terminal/models.py:130 #: terminal/templates/terminal/command_list.html:55 #: terminal/templates/terminal/command_list.html:71 #: terminal/templates/terminal/session_detail.html:48 @@ -1998,56 +2048,56 @@ msgstr "SSH 监听端口" msgid "Coco http/ws listen port" msgstr "Http/Websocket 监听端口" -#: terminal/models.py:15 +#: terminal/models.py:24 msgid "Remote Address" msgstr "远端地址" -#: terminal/models.py:16 +#: terminal/models.py:25 msgid "SSH Port" msgstr "SSH端口" -#: terminal/models.py:17 +#: terminal/models.py:26 msgid "HTTP Port" msgstr "HTTP端口" -#: terminal/models.py:68 +#: terminal/models.py:99 msgid "Session Online" msgstr "在线会话" -#: terminal/models.py:69 +#: terminal/models.py:100 msgid "CPU Usage" msgstr "CPU使用" -#: terminal/models.py:70 +#: terminal/models.py:101 msgid "Memory Used" msgstr "内存使用" -#: terminal/models.py:71 +#: terminal/models.py:102 msgid "Connections" msgstr "连接数" -#: terminal/models.py:72 +#: terminal/models.py:103 msgid "Threads" msgstr "线程数" -#: terminal/models.py:73 +#: terminal/models.py:104 msgid "Boot Time" msgstr "运行时间" -#: terminal/models.py:96 terminal/templates/terminal/session_list.html:74 +#: terminal/models.py:127 terminal/templates/terminal/session_list.html:74 #: terminal/templates/terminal/terminal_detail.html:47 msgid "Remote addr" msgstr "远端地址" -#: terminal/models.py:98 terminal/templates/terminal/session_list.html:100 +#: terminal/models.py:129 terminal/templates/terminal/session_list.html:100 msgid "Replay" msgstr "回放" -#: terminal/models.py:102 +#: terminal/models.py:133 msgid "Date end" msgstr "结束日期" -#: terminal/models.py:119 +#: terminal/models.py:150 msgid "Args" msgstr "参数" @@ -2810,5 +2860,8 @@ msgstr "密码更新" msgid "Public key update" msgstr "秘钥更新" +#~ msgid "Enable LDAP Auth" +#~ msgstr "LDAP认证" + #~ msgid "Connect" #~ msgstr "连接" diff --git a/apps/terminal/api.py b/apps/terminal/api.py index 87311d5b2..279ec0121 100644 --- a/apps/terminal/api.py +++ b/apps/terminal/api.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- # from collections import OrderedDict -import copy import logging import os import uuid @@ -21,7 +20,8 @@ from .serializers import TerminalSerializer, StatusSerializer, \ SessionSerializer, TaskSerializer, ReplaySerializer from .hands import IsSuperUserOrAppUser, IsAppUser, \ IsSuperUserOrAppUserOrUserReadonly -from .backends import get_command_store, SessionCommandSerializer +from .backends import get_command_store, get_multi_command_store, \ + SessionCommandSerializer logger = logging.getLogger(__file__) @@ -197,6 +197,7 @@ class CommandViewSet(viewsets.ViewSet): """ command_store = get_command_store() + multi_command_storage = get_multi_command_store() serializer_class = SessionCommandSerializer permission_classes = (IsSuperUserOrAppUser,) @@ -217,7 +218,7 @@ class CommandViewSet(viewsets.ViewSet): return Response({"msg": msg}, status=401) def list(self, request, *args, **kwargs): - queryset = list(self.command_store.all()) + queryset = self.multi_command_storage.filter() serializer = self.serializer_class(queryset, many=True) return Response(serializer.data) @@ -260,3 +261,13 @@ class SessionReplayViewSet(viewsets.ViewSet): return redirect(url) else: return HttpResponseNotFound() + + +class TerminalConfig(APIView): + permission_classes = (IsAppUser,) + + def get(self, request): + user = request.user + terminal = user.terminal + configs = terminal.config + return Response(configs, status=200) diff --git a/apps/terminal/backends/__init__.py b/apps/terminal/backends/__init__.py index 6baaed3c4..33f63f4de 100644 --- a/apps/terminal/backends/__init__.py +++ b/apps/terminal/backends/__init__.py @@ -2,9 +2,39 @@ from importlib import import_module from django.conf import settings from .command.serializers import SessionCommandSerializer +TYPE_ENGINE_MAPPING = { + 'elasticsearch': 'terminal.backends.command.es', +} + def get_command_store(): - command_engine = import_module(settings.COMMAND_STORAGE_BACKEND) - command_store = command_engine.CommandStore() - return command_store + params = settings.COMMAND_STORAGE + engine_class = import_module(params['ENGINE']) + storage = engine_class.CommandStore(params) + return storage + + +def get_terminal_command_store(): + storage_list = {} + for name, params in settings.TERMINAL_COMMAND_STORAGE.items(): + tp = params['TYPE'] + if tp == 'server': + storage = get_command_store() + else: + if not TYPE_ENGINE_MAPPING.get(tp): + raise AssertionError("Command storage type should in {}".format( + ', '.join(TYPE_ENGINE_MAPPING.keys())) + ) + engine_class = import_module(TYPE_ENGINE_MAPPING[tp]) + storage = engine_class.CommandStore(params) + storage_list[name] = storage + return storage_list + + +def get_multi_command_store(): + from .command.multi import CommandStore + storage_list = get_terminal_command_store().values() + storage = CommandStore(storage_list) + return storage + diff --git a/apps/terminal/backends/command/base.py b/apps/terminal/backends/command/base.py index 0aa689738..585930a5d 100644 --- a/apps/terminal/backends/command/base.py +++ b/apps/terminal/backends/command/base.py @@ -19,3 +19,9 @@ class CommandBase(object): input=None, session=None): pass + @abc.abstractmethod + def count(self, date_from=None, date_to=None, + user=None, asset=None, system_user=None, + input=None, session=None): + pass + diff --git a/apps/terminal/backends/command/db.py b/apps/terminal/backends/command/db.py index 27ee19a14..18652a26f 100644 --- a/apps/terminal/backends/command/db.py +++ b/apps/terminal/backends/command/db.py @@ -8,7 +8,7 @@ from .base import CommandBase class CommandStore(CommandBase): - def __init__(self): + def __init__(self, params): from terminal.models import Command self.model = Command @@ -37,9 +37,11 @@ class CommandStore(CommandBase): )) return self.model.objects.bulk_create(_commands) - def filter(self, date_from=None, date_to=None, - user=None, asset=None, system_user=None, - input=None, session=None): + @staticmethod + def make_filter_kwargs( + date_from=None, date_to=None, + user=None, asset=None, system_user=None, + input=None, session=None): filter_kwargs = {} date_from_default = timezone.now() - datetime.timedelta(days=7) date_to_default = timezone.now() @@ -60,10 +62,28 @@ class CommandStore(CommandBase): if session: filter_kwargs['session'] = session + return filter_kwargs + + def filter(self, date_from=None, date_to=None, + user=None, asset=None, system_user=None, + input=None, session=None): + filter_kwargs = self.make_filter_kwargs( + date_from=date_from, date_to=date_to, user=user, + asset=asset, system_user=system_user, input=input, + session=session, + ) queryset = self.model.objects.filter(**filter_kwargs) - return queryset + return [command.to_dict() for command in queryset] + + def count(self, date_from=None, date_to=None, + user=None, asset=None, system_user=None, + input=None, session=None): + filter_kwargs = self.make_filter_kwargs( + date_from=date_from, date_to=date_to, user=user, + asset=asset, system_user=system_user, input=input, + session=session, + ) + count = self.model.objects.filter(**filter_kwargs).count() + return count - def all(self): - """返回所有数据""" - return self.model.objects.iterator() diff --git a/apps/terminal/backends/command/es.py b/apps/terminal/backends/command/es.py new file mode 100644 index 000000000..2e0995ad9 --- /dev/null +++ b/apps/terminal/backends/command/es.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# + +from jms_es_sdk import ESStore +from .base import CommandBase + + +class CommandStore(CommandBase, ESStore): + def __init__(self, params): + hosts = params.get('HOSTS', ['http://localhost']) + ESStore.__init__(self, hosts=hosts) + + def save(self, command): + return ESStore.save(self, command) + + def bulk_save(self, commands): + return ESStore.bulk_save(self, commands) + + def filter(self, date_from=None, date_to=None, + user=None, asset=None, system_user=None, + input=None, session=None): + + data = ESStore.filter( + self, date_from=date_from, date_to=date_to, + user=user, asset=asset, system_user=system_user, + input=input, session=session + ) + return [item["_source"] for item in data["hits"] if item] + + def count(self, date_from=None, date_to=None, + user=None, asset=None, system_user=None, + input=None, session=None): + amount = ESStore.count( + self, date_from=date_from, date_to=date_to, + user=user, asset=asset, system_user=system_user, + input=input, session=session + ) + return amount diff --git a/apps/terminal/backends/command/models.py b/apps/terminal/backends/command/models.py index 2d1387427..186769b48 100644 --- a/apps/terminal/backends/command/models.py +++ b/apps/terminal/backends/command/models.py @@ -18,5 +18,26 @@ class AbstractSessionCommand(models.Model): class Meta: abstract = True + @classmethod + def from_dict(cls, d): + self = cls() + for k, v in d.items(): + setattr(self, k, v) + return self + + @classmethod + def from_multi_dict(cls, l): + commands = [] + for d in l: + command = cls.from_dict(d) + commands.append(command) + return commands + + def to_dict(self): + d = {} + for field in self._meta.fields: + d[field.name] = getattr(self, field.name) + return d + def __str__(self): return self.input diff --git a/apps/terminal/backends/command/multi.py b/apps/terminal/backends/command/multi.py new file mode 100644 index 000000000..8d51cfd38 --- /dev/null +++ b/apps/terminal/backends/command/multi.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# + +from .base import CommandBase + + +class CommandStore(CommandBase): + def __init__(self, storage_list): + self.storage_list = storage_list + + def filter(self, **kwargs): + queryset = [] + for storage in self.storage_list: + queryset.extend(storage.filter(**kwargs)) + return sorted(queryset, key=lambda command: command["timestamp"]) + + def count(self, **kwargs): + amount = 0 + for storage in self.storage_list: + amount += storage.count(**kwargs) + return amount + + def save(self, command): + pass + + def bulk_save(self, commands): + pass \ No newline at end of file diff --git a/apps/terminal/forms.py b/apps/terminal/forms.py index 5b6278c02..4253da70a 100644 --- a/apps/terminal/forms.py +++ b/apps/terminal/forms.py @@ -10,7 +10,7 @@ from .models import Terminal class TerminalForm(forms.ModelForm): class Meta: model = Terminal - fields = ['name', 'remote_addr', 'ssh_port', 'http_port', 'comment'] + fields = ['name', 'remote_addr', 'ssh_port', 'http_port', 'comment', 'command_storage'] help_texts = { 'ssh_port': _("Coco ssh listen port"), 'http_port': _("Coco http/ws listen port"), diff --git a/apps/terminal/models.py b/apps/terminal/models.py index f545baa5f..617977946 100644 --- a/apps/terminal/models.py +++ b/apps/terminal/models.py @@ -4,17 +4,28 @@ import uuid from django.db import models from django.utils.translation import ugettext_lazy as _ +from django.conf import settings from users.models import User from .backends.command.models import AbstractSessionCommand +def get_all_command_storage(): + # storage_choices = [] + from common.models import Setting + Setting.refresh_all_settings() + for k, v in settings.TERMINAL_COMMAND_STORAGE.items(): + yield (k, k) + + class Terminal(models.Model): id = models.UUIDField(default=uuid.uuid4, primary_key=True) name = models.CharField(max_length=32, verbose_name=_('Name')) remote_addr = models.CharField(max_length=128, verbose_name=_('Remote Address')) ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222) http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000) + command_storage = models.CharField(max_length=128, verbose_name=_("Command storage"), default='default', choices=get_all_command_storage()) + replay_storage = models.CharField(max_length=128, verbose_name=_("Replay storage"), default='default') user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True, on_delete=models.CASCADE) is_accepted = models.BooleanField(default=False, verbose_name='Is Accepted') is_deleted = models.BooleanField(default=False) @@ -33,6 +44,26 @@ class Terminal(models.Model): self.user.is_active = active self.user.save() + def get_common_storage(self): + storage_all = settings.TERMINAL_COMMAND_STORAGE + if self.command_storage in storage_all: + storage = storage_all.get(self.command_storage) + else: + storage = storage_all.get('default') + return {"TERMINAL_COMMAND_STORAGE": storage} + + def get_replay_storage(self): + pass + + @property + def config(self): + configs = {} + for k in dir(settings): + if k.startswith('TERMINAL'): + configs[k] = getattr(settings, k) + configs.update(self.get_common_storage()) + return configs + def create_app_user(self): random = uuid.uuid4().hex[:6] user, access_key = User.create_app_user(name="{}-{}".format(self.name, random), comment=self.comment) diff --git a/apps/terminal/serializers.py b/apps/terminal/serializers.py index 52b4d2b3c..275853411 100644 --- a/apps/terminal/serializers.py +++ b/apps/terminal/serializers.py @@ -5,7 +5,7 @@ from django.utils import timezone from rest_framework import serializers from .models import Terminal, Status, Session, Task -from .backends import get_command_store +from .backends import get_multi_command_store class TerminalSerializer(serializers.ModelSerializer): @@ -43,14 +43,14 @@ class TerminalSerializer(serializers.ModelSerializer): class SessionSerializer(serializers.ModelSerializer): command_amount = serializers.SerializerMethodField() - command_store = get_command_store() + command_store = get_multi_command_store() class Meta: model = Session fields = '__all__' def get_command_amount(self, obj): - return len(self.command_store.filter(session=obj.session)) + return self.command_store.count(session=str(obj.id)) class StatusSerializer(serializers.ModelSerializer): diff --git a/apps/terminal/templates/terminal/terminal_modal_accept.html b/apps/terminal/templates/terminal/terminal_modal_accept.html index b4a18b17c..fe70bb342 100644 --- a/apps/terminal/templates/terminal/terminal_modal_accept.html +++ b/apps/terminal/templates/terminal/terminal_modal_accept.html @@ -12,6 +12,7 @@ {% bootstrap_field form.remote_addr layout="horizontal" %} {% bootstrap_field form.ssh_port layout="horizontal" %} {% bootstrap_field form.http_port layout="horizontal" %} + {% bootstrap_field form.command_storage layout="horizontal" %} {% bootstrap_field form.comment layout="horizontal" %} diff --git a/apps/terminal/templates/terminal/terminal_update.html b/apps/terminal/templates/terminal/terminal_update.html index 9ebd9d2d8..cbf745608 100644 --- a/apps/terminal/templates/terminal/terminal_update.html +++ b/apps/terminal/templates/terminal/terminal_update.html @@ -35,6 +35,7 @@ {% bootstrap_field form.remote_addr layout="horizontal" %} {% bootstrap_field form.ssh_port layout="horizontal" %} {% bootstrap_field form.http_port layout="horizontal" %} + {% bootstrap_field form.command_storage layout="horizontal" %}

    {% trans 'Other' %}

    diff --git a/apps/terminal/templatetags/terminal_tags.py b/apps/terminal/templatetags/terminal_tags.py index 22b517880..cd7120fec 100644 --- a/apps/terminal/templatetags/terminal_tags.py +++ b/apps/terminal/templatetags/terminal_tags.py @@ -1,13 +1,12 @@ # ~*~ coding: utf-8 ~*~ from django import template -from ..backends import get_command_store +from ..backends import get_multi_command_store register = template.Library() -command_store = get_command_store() +command_store = get_multi_command_store() @register.filter def get_session_command_amount(session_id): - return len(command_store.filter(session=str(session_id))) - + return command_store.count(session=session_id) diff --git a/apps/terminal/urls/api_urls.py b/apps/terminal/urls/api_urls.py index 55d77ee00..a3ebc2129 100644 --- a/apps/terminal/urls/api_urls.py +++ b/apps/terminal/urls/api_urls.py @@ -20,7 +20,8 @@ urlpatterns = [ url(r'^v1/sessions/(?P[0-9a-zA-Z\-]{36})/replay/$', api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}), name='session-replay'), - url(r'^v1/terminal/(?P[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(), name='terminal-access-key') + url(r'^v1/terminal/(?P[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(), name='terminal-access-key'), + url(r'^v1/terminal/config', api.TerminalConfig.as_view(), name='terminal-config'), ] urlpatterns += router.urls diff --git a/apps/terminal/views/command.py b/apps/terminal/views/command.py index 8b0479d3e..6fdf905bd 100644 --- a/apps/terminal/views/command.py +++ b/apps/terminal/views/command.py @@ -9,10 +9,10 @@ from django.utils.translation import ugettext as _ from common.mixins import DatetimeSearchMixin from ..models import Command from .. import utils -from ..backends import get_command_store +from ..backends import get_multi_command_store __all__ = ['CommandListView'] -command_store = get_command_store() +common_storage = get_multi_command_store() class CommandListView(DatetimeSearchMixin, ListView): @@ -39,7 +39,7 @@ class CommandListView(DatetimeSearchMixin, ListView): filter_kwargs['system_user'] = self.system_user if self.command: filter_kwargs['input'] = self.command - queryset = command_store.filter(**filter_kwargs) + queryset = common_storage.filter(**filter_kwargs) return queryset def get_context_data(self, **kwargs): diff --git a/apps/terminal/views/session.py b/apps/terminal/views/session.py index 22d04fbaf..0970cade2 100644 --- a/apps/terminal/views/session.py +++ b/apps/terminal/views/session.py @@ -10,7 +10,7 @@ from django.conf import settings from users.utils import AdminUserRequiredMixin from common.mixins import DatetimeSearchMixin from ..models import Session, Command, Terminal -from ..backends import get_command_store +from ..backends import get_multi_command_store from .. import utils @@ -19,7 +19,7 @@ __all__ = [ 'SessionDetailView', ] -command_store = get_command_store() +command_store = get_multi_command_store() class SessionListView(AdminUserRequiredMixin, DatetimeSearchMixin, ListView): diff --git a/apps/users/forms.py b/apps/users/forms.py index 018c39a18..b239f58ee 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -172,7 +172,6 @@ class UserBulkUpdateForm(forms.ModelForm): if self.data.get(field) is not None: changed_fields.append(field) - print(changed_fields) cleaned_data = {k: v for k, v in self.cleaned_data.items() if k in changed_fields} users = cleaned_data.pop('users', '')