diff --git a/apps/applications/__init__.py b/apps/applications/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/applications/admin.py b/apps/applications/admin.py new file mode 100644 index 000000000..8c38f3f3d --- /dev/null +++ b/apps/applications/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/apps/applications/api/__init__.py b/apps/applications/api/__init__.py new file mode 100644 index 000000000..e6bc7adb4 --- /dev/null +++ b/apps/applications/api/__init__.py @@ -0,0 +1 @@ +from .remote_app import * diff --git a/apps/applications/api/remote_app.py b/apps/applications/api/remote_app.py new file mode 100644 index 000000000..c41c5d100 --- /dev/null +++ b/apps/applications/api/remote_app.py @@ -0,0 +1,31 @@ +# coding: utf-8 +# + + +from rest_framework import generics +from rest_framework.pagination import LimitOffsetPagination +from rest_framework_bulk import BulkModelViewSet + +from ..hands import IsOrgAdmin, IsAppUser +from ..models import RemoteApp +from ..serializers import RemoteAppSerializer, RemoteAppConnectionInfoSerializer + + +__all__ = [ + 'RemoteAppViewSet', 'RemoteAppConnectionInfoApi', +] + + +class RemoteAppViewSet(BulkModelViewSet): + filter_fields = ('name',) + search_fields = filter_fields + permission_classes = (IsOrgAdmin,) + queryset = RemoteApp.objects.all() + serializer_class = RemoteAppSerializer + pagination_class = LimitOffsetPagination + + +class RemoteAppConnectionInfoApi(generics.RetrieveAPIView): + queryset = RemoteApp.objects.all() + permission_classes = (IsAppUser, ) + serializer_class = RemoteAppConnectionInfoSerializer diff --git a/apps/applications/apps.py b/apps/applications/apps.py new file mode 100644 index 000000000..3c22ddedc --- /dev/null +++ b/apps/applications/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class ApplicationsConfig(AppConfig): + name = 'applications' diff --git a/apps/applications/const.py b/apps/applications/const.py new file mode 100644 index 000000000..b64b1a14b --- /dev/null +++ b/apps/applications/const.py @@ -0,0 +1,68 @@ +# coding: utf-8 +# + +from django.utils.translation import ugettext_lazy as _ + + +# RemoteApp +REMOTE_APP_BOOT_PROGRAM_NAME = '||jmservisor' + +REMOTE_APP_TYPE_CHROME = 'chrome' +REMOTE_APP_TYPE_MYSQL_WORKBENCH = 'mysql_workbench' +REMOTE_APP_TYPE_VMWARE_CLIENT = 'vmware_client' +REMOTE_APP_TYPE_CUSTOM = 'custom' + +REMOTE_APP_TYPE_CHOICES = ( + ( + _('Browser'), + ( + (REMOTE_APP_TYPE_CHROME, 'Chrome'), + ) + ), + ( + _('Database tools'), + ( + (REMOTE_APP_TYPE_MYSQL_WORKBENCH, 'MySQL Workbench'), + ) + ), + ( + _('Virtualization tools'), + ( + (REMOTE_APP_TYPE_VMWARE_CLIENT, 'VMware Client'), + ) + ), + (REMOTE_APP_TYPE_CUSTOM, _('Custom')), + +) + +# Fields attribute write_only default => False + +REMOTE_APP_TYPE_CHROME_FIELDS = [ + {'name': 'chrome_target'}, + {'name': 'chrome_username'}, + {'name': 'chrome_password', 'write_only': True} +] +REMOTE_APP_TYPE_MYSQL_WORKBENCH_FIELDS = [ + {'name': 'mysql_workbench_ip'}, + {'name': 'mysql_workbench_name'}, + {'name': 'mysql_workbench_username'}, + {'name': 'mysql_workbench_password', 'write_only': True} +] +REMOTE_APP_TYPE_VMWARE_CLIENT_FIELDS = [ + {'name': 'vmware_target'}, + {'name': 'vmware_username'}, + {'name': 'vmware_password', 'write_only': True} +] +REMOTE_APP_TYPE_CUSTOM_FIELDS = [ + {'name': 'custom_cmdline'}, + {'name': 'custom_target'}, + {'name': 'custom_username'}, + {'name': 'custom_password', 'write_only': True} +] + +REMOTE_APP_TYPE_MAP_FIELDS = { + REMOTE_APP_TYPE_CHROME: REMOTE_APP_TYPE_CHROME_FIELDS, + REMOTE_APP_TYPE_MYSQL_WORKBENCH: REMOTE_APP_TYPE_MYSQL_WORKBENCH_FIELDS, + REMOTE_APP_TYPE_VMWARE_CLIENT: REMOTE_APP_TYPE_VMWARE_CLIENT_FIELDS, + REMOTE_APP_TYPE_CUSTOM: REMOTE_APP_TYPE_CUSTOM_FIELDS +} diff --git a/apps/applications/forms/__init__.py b/apps/applications/forms/__init__.py new file mode 100644 index 000000000..e6bc7adb4 --- /dev/null +++ b/apps/applications/forms/__init__.py @@ -0,0 +1 @@ +from .remote_app import * diff --git a/apps/applications/forms/remote_app.py b/apps/applications/forms/remote_app.py new file mode 100644 index 000000000..88f1912e0 --- /dev/null +++ b/apps/applications/forms/remote_app.py @@ -0,0 +1,111 @@ +# coding: utf-8 +# + +from django.utils.translation import ugettext as _ +from django import forms + +from orgs.mixins import OrgModelForm +from assets.models import Asset, SystemUser + +from ..models import RemoteApp + + +__all__ = [ + 'RemoteAppCreateUpdateForm', +] + + +class RemoteAppTypeChromeForm(forms.ModelForm): + chrome_target = forms.CharField( + max_length=128, label=_('Target URL'), required=False + ) + chrome_username = forms.CharField( + max_length=128, label=_('Login username'), required=False + ) + chrome_password = forms.CharField( + widget=forms.PasswordInput, strip=True, + max_length=128, label=_('Login password'), required=False + ) + + +class RemoteAppTypeMySQLWorkbenchForm(forms.ModelForm): + mysql_workbench_ip = forms.CharField( + max_length=128, label=_('Database IP'), required=False + ) + mysql_workbench_name = forms.CharField( + max_length=128, label=_('Database name'), required=False + ) + mysql_workbench_username = forms.CharField( + max_length=128, label=_('Database username'), required=False + ) + mysql_workbench_password = forms.CharField( + widget=forms.PasswordInput, strip=True, + max_length=128, label=_('Database password'), required=False + ) + + +class RemoteAppTypeVMwareForm(forms.ModelForm): + vmware_target = forms.CharField( + max_length=128, label=_('Target address'), required=False + ) + vmware_username = forms.CharField( + max_length=128, label=_('Login username'), required=False + ) + vmware_password = forms.CharField( + widget=forms.PasswordInput, strip=True, + max_length=128, label=_('Login password'), required=False + ) + + +class RemoteAppTypeCustomForm(forms.ModelForm): + custom_cmdline = forms.CharField( + max_length=128, label=_('Operating parameter'), required=False + ) + custom_target = forms.CharField( + max_length=128, label=_('Target address'), required=False + ) + custom_username = forms.CharField( + max_length=128, label=_('Login username'), required=False + ) + custom_password = forms.CharField( + widget=forms.PasswordInput, strip=True, + max_length=128, label=_('Login password'), required=False + ) + + +class RemoteAppTypeForms( + RemoteAppTypeChromeForm, + RemoteAppTypeMySQLWorkbenchForm, + RemoteAppTypeVMwareForm, + RemoteAppTypeCustomForm +): + pass + + +class RemoteAppCreateUpdateForm(RemoteAppTypeForms, OrgModelForm): + def __init__(self, *args, **kwargs): + # 过滤RDP资产和系统用户 + super().__init__(*args, **kwargs) + field_asset = self.fields['asset'] + field_asset.queryset = field_asset.queryset.filter( + protocol=Asset.PROTOCOL_RDP + ) + field_system_user = self.fields['system_user'] + field_system_user.queryset = field_system_user.queryset.filter( + protocol=SystemUser.PROTOCOL_RDP + ) + + class Meta: + model = RemoteApp + fields = [ + 'name', 'asset', 'system_user', 'type', 'path', 'comment' + ] + widgets = { + 'asset': forms.Select(attrs={ + 'class': 'select2', 'data-placeholder': _('Asset') + }), + 'system_user': forms.Select(attrs={ + 'class': 'select2', 'data-placeholder': _('System user') + }) + } + diff --git a/apps/applications/hands.py b/apps/applications/hands.py new file mode 100644 index 000000000..ffe1e35c5 --- /dev/null +++ b/apps/applications/hands.py @@ -0,0 +1,16 @@ +""" + jumpserver.__app__.hands.py + ~~~~~~~~~~~~~~~~~ + + This app depends other apps api, function .. should be import or write mack here. + + Other module of this app shouldn't connect with other app. + + :copyright: (c) 2014-2018 by Jumpserver Team. + :license: GPL v2, see LICENSE for more details. +""" + + +from common.permissions import AdminUserRequiredMixin +from common.permissions import IsAppUser, IsOrgAdmin, IsValidUser, IsOrgAdminOrAppUser +from users.models import User, UserGroup diff --git a/apps/applications/migrations/0001_initial.py b/apps/applications/migrations/0001_initial.py new file mode 100644 index 000000000..35d6dc103 --- /dev/null +++ b/apps/applications/migrations/0001_initial.py @@ -0,0 +1,42 @@ +# Generated by Django 2.1.7 on 2019-05-20 11:04 + +import common.fields.model +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('assets', '0026_auto_20190325_2035'), + ] + + operations = [ + migrations.CreateModel( + name='RemoteApp', + fields=[ + ('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), + ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=128, verbose_name='Name')), + ('type', models.CharField(choices=[('Browser', (('chrome', 'Chrome'),)), ('Database tools', (('mysql_workbench', 'MySQL Workbench'),)), ('Virtualization tools', (('vmware_client', 'VMware Client'),)), ('custom', 'Custom')], default='chrome', max_length=128, verbose_name='App type')), + ('path', models.CharField(max_length=128, verbose_name='App path')), + ('params', common.fields.model.EncryptJsonDictTextField(blank=True, default={}, max_length=4096, null=True, verbose_name='Parameters')), + ('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')), + ('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')), + ('comment', models.TextField(blank=True, default='', max_length=128, verbose_name='Comment')), + ('asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.Asset', verbose_name='Asset')), + ('system_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='assets.SystemUser', verbose_name='System user')), + ], + options={ + 'verbose_name': 'RemoteApp', + 'ordering': ('name',), + }, + ), + migrations.AlterUniqueTogether( + name='remoteapp', + unique_together={('org_id', 'name')}, + ), + ] diff --git a/apps/applications/migrations/__init__.py b/apps/applications/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/applications/models/__init__.py b/apps/applications/models/__init__.py new file mode 100644 index 000000000..e6bc7adb4 --- /dev/null +++ b/apps/applications/models/__init__.py @@ -0,0 +1 @@ +from .remote_app import * diff --git a/apps/applications/models/remote_app.py b/apps/applications/models/remote_app.py new file mode 100644 index 000000000..772d39834 --- /dev/null +++ b/apps/applications/models/remote_app.py @@ -0,0 +1,89 @@ +# coding: utf-8 +# + +import uuid +from django.db import models +from django.utils.translation import ugettext_lazy as _ + +from orgs.mixins import OrgModelMixin +from common.fields.model import EncryptJsonDictTextField + +from .. import const + + +__all__ = [ + 'RemoteApp', +] + + +class RemoteApp(OrgModelMixin): + id = models.UUIDField(default=uuid.uuid4, primary_key=True) + name = models.CharField(max_length=128, verbose_name=_('Name')) + asset = models.ForeignKey( + 'assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset') + ) + system_user = models.ForeignKey( + 'assets.SystemUser', on_delete=models.CASCADE, + verbose_name=_('System user') + ) + type = models.CharField( + default=const.REMOTE_APP_TYPE_CHROME, + choices=const.REMOTE_APP_TYPE_CHOICES, + max_length=128, verbose_name=_('App type') + ) + path = models.CharField( + max_length=128, blank=False, null=False, + verbose_name=_('App path') + ) + params = EncryptJsonDictTextField( + max_length=4096, default={}, blank=True, null=True, + verbose_name=_('Parameters') + ) + created_by = models.CharField( + max_length=32, null=True, blank=True, verbose_name=_('Created by') + ) + date_created = models.DateTimeField( + auto_now_add=True, null=True, blank=True, verbose_name=_('Date created') + ) + comment = models.TextField( + max_length=128, default='', blank=True, verbose_name=_('Comment') + ) + + class Meta: + verbose_name = _("RemoteApp") + unique_together = [('org_id', 'name')] + ordering = ('name', ) + + def __str__(self): + return self.name + + @property + def parameters(self): + """ + 返回Guacamole需要的RemoteApp配置参数信息中的parameters参数 + """ + _parameters = list() + _parameters.append(self.type) + path = '\"%s\"' % self.path + _parameters.append(path) + for field in const.REMOTE_APP_TYPE_MAP_FIELDS[self.type]: + value = self.params.get(field['name']) + if value is None: + continue + _parameters.append(value) + _parameters = ' '.join(_parameters) + return _parameters + + @property + def asset_info(self): + return { + 'id': self.asset.id, + 'hostname': self.asset.hostname + } + + @property + def system_user_info(self): + return { + 'id': self.system_user.id, + 'name': self.system_user.name + } diff --git a/apps/applications/serializers/__init__.py b/apps/applications/serializers/__init__.py new file mode 100644 index 000000000..e6bc7adb4 --- /dev/null +++ b/apps/applications/serializers/__init__.py @@ -0,0 +1 @@ +from .remote_app import * diff --git a/apps/applications/serializers/remote_app.py b/apps/applications/serializers/remote_app.py new file mode 100644 index 000000000..6957d11d5 --- /dev/null +++ b/apps/applications/serializers/remote_app.py @@ -0,0 +1,103 @@ +# coding: utf-8 +# + + +from rest_framework import serializers + +from common.mixins import BulkSerializerMixin +from common.serializers import AdaptedBulkListSerializer + +from .. import const +from ..models import RemoteApp + + +__all__ = [ + 'RemoteAppSerializer', 'RemoteAppConnectionInfoSerializer', +] + + +class RemoteAppParamsDictField(serializers.DictField): + """ + RemoteApp field => params + """ + @staticmethod + def filter_attribute(attribute, instance): + """ + 过滤掉params字段值中write_only特性的key-value值 + For example, the chrome_password field is not returned when serializing + { + 'chrome_target': 'http://www.jumpserver.org/', + 'chrome_username': 'admin', + 'chrome_password': 'admin', + } + """ + for field in const.REMOTE_APP_TYPE_MAP_FIELDS[instance.type]: + if field.get('write_only', False): + attribute.pop(field['name'], None) + return attribute + + def get_attribute(self, instance): + """ + 序列化时调用 + """ + attribute = super().get_attribute(instance) + attribute = self.filter_attribute(attribute, instance) + return attribute + + @staticmethod + def filter_value(dictionary, value): + """ + 过滤掉不属于当前app_type所包含的key-value值 + """ + app_type = dictionary.get('type', const.REMOTE_APP_TYPE_CHROME) + fields = const.REMOTE_APP_TYPE_MAP_FIELDS[app_type] + fields_names = [field['name'] for field in fields] + no_need_keys = [k for k in value.keys() if k not in fields_names] + for k in no_need_keys: + value.pop(k) + return value + + def get_value(self, dictionary): + """ + 反序列化时调用 + """ + value = super().get_value(dictionary) + value = self.filter_value(dictionary, value) + return value + + +class RemoteAppSerializer(BulkSerializerMixin, serializers.ModelSerializer): + params = RemoteAppParamsDictField() + + class Meta: + model = RemoteApp + list_serializer_class = AdaptedBulkListSerializer + fields = [ + 'id', 'name', 'asset', 'system_user', 'type', 'path', 'params', + 'comment', 'created_by', 'date_created', 'asset_info', + 'system_user_info', 'get_type_display', + ] + read_only_fields = [ + 'created_by', 'date_created', 'asset_info', + 'system_user_info', 'get_type_display' + ] + + +class RemoteAppConnectionInfoSerializer(serializers.ModelSerializer): + parameter_remote_app = serializers.SerializerMethodField() + + class Meta: + model = RemoteApp + fields = [ + 'id', 'name', 'asset', 'system_user', 'parameter_remote_app', + ] + read_only_fields = ['parameter_remote_app'] + + @staticmethod + def get_parameter_remote_app(obj): + parameter = { + 'program': const.REMOTE_APP_BOOT_PROGRAM_NAME, + 'working_directory': '', + 'parameters': obj.parameters, + } + return parameter diff --git a/apps/applications/templates/applications/remote_app_create_update.html b/apps/applications/templates/applications/remote_app_create_update.html new file mode 100644 index 000000000..e64b8994c --- /dev/null +++ b/apps/applications/templates/applications/remote_app_create_update.html @@ -0,0 +1,91 @@ +{% extends '_base_create_update.html' %} +{% load static %} +{% load bootstrap3 %} +{% load i18n %} + +{% block form %} +
+ {% if form.non_field_errors %} +
+ {{ form.non_field_errors }} +
+ {% endif %} + {% csrf_token %} + {% bootstrap_field form.name layout="horizontal" %} + {% bootstrap_field form.asset layout="horizontal" %} + {% bootstrap_field form.system_user layout="horizontal" %} + {% bootstrap_field form.type layout="horizontal" %} + {% bootstrap_field form.path layout="horizontal" %} + +
+ + {# chrome #} +
+ {% bootstrap_field form.chrome_target layout="horizontal" %} + {% bootstrap_field form.chrome_username layout="horizontal" %} + {% bootstrap_field form.chrome_password layout="horizontal" %} +
+ + {# mysql workbench #} +
+ {% bootstrap_field form.mysql_workbench_ip layout="horizontal" %} + {% bootstrap_field form.mysql_workbench_name layout="horizontal" %} + {% bootstrap_field form.mysql_workbench_username layout="horizontal" %} + {% bootstrap_field form.mysql_workbench_password layout="horizontal" %} +
+ + {# vmware #} +
+ {% bootstrap_field form.vmware_target layout="horizontal" %} + {% bootstrap_field form.vmware_username layout="horizontal" %} + {% bootstrap_field form.vmware_password layout="horizontal" %} +
+ + {# custom #} +
+ {% bootstrap_field form.custom_cmdline layout="horizontal" %} + {% bootstrap_field form.custom_target layout="horizontal" %} + {% bootstrap_field form.custom_username layout="horizontal" %} + {% bootstrap_field form.custom_password layout="horizontal" %} +
+ + {% bootstrap_field form.comment layout="horizontal" %} +
+
+
+ + + +
+
+ +
+{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/applications/templates/applications/remote_app_detail.html b/apps/applications/templates/applications/remote_app_detail.html new file mode 100644 index 000000000..d006bb51a --- /dev/null +++ b/apps/applications/templates/applications/remote_app_detail.html @@ -0,0 +1,109 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ remote_app.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Name' %}:{{ remote_app.name }}
{% trans 'Asset' %}:{{ remote_app.asset.hostname }}
{% trans 'System user' %}:{{ remote_app.system_user.name }}
{% trans 'App type' %}:{{ remote_app.get_type_display }}
{% trans 'App path' %}:{{ remote_app.path }}
{% trans 'Date created' %}:{{ remote_app.date_created }}
{% trans 'Created by' %}:{{ remote_app.created_by }}
{% trans 'Comment' %}:{{ remote_app.comment }}
+
+
+
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/applications/templates/applications/remote_app_list.html b/apps/applications/templates/applications/remote_app_list.html new file mode 100644 index 000000000..c2f64235e --- /dev/null +++ b/apps/applications/templates/applications/remote_app_list.html @@ -0,0 +1,90 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block help_message %} +
+ {% trans 'Before using this feature, make sure that the application loader has been uploaded to the application server and successfully published as a RemoteApp application' %} + {% trans 'Download application loader' %} +
+{% endblock %} +{% block table_search %}{% endblock %} +{% block table_container %} +
+ {% trans "Create RemoteApp" %} +
+ + + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'App type' %}{% trans 'Asset' %}{% trans 'System user' %}{% trans 'Comment' %}{% trans 'Action' %}
+{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/applications/templates/applications/user_remote_app_list.html b/apps/applications/templates/applications/user_remote_app_list.html new file mode 100644 index 000000000..4199e805f --- /dev/null +++ b/apps/applications/templates/applications/user_remote_app_list.html @@ -0,0 +1,79 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block custom_head_css_js %} + +{% endblock %} + +{% block content %} +
+ + + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'App type' %}{% trans 'Asset' %}{% trans 'System user' %}{% trans 'Comment' %}{% trans 'Action' %}
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/applications/tests.py b/apps/applications/tests.py new file mode 100644 index 000000000..7ce503c2d --- /dev/null +++ b/apps/applications/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/apps/applications/urls/__init__.py b/apps/applications/urls/__init__.py new file mode 100644 index 000000000..3aab4972f --- /dev/null +++ b/apps/applications/urls/__init__.py @@ -0,0 +1,7 @@ +# coding: utf-8 +# + + +__all__ = [ + +] diff --git a/apps/applications/urls/api_urls.py b/apps/applications/urls/api_urls.py new file mode 100644 index 000000000..97487b5a1 --- /dev/null +++ b/apps/applications/urls/api_urls.py @@ -0,0 +1,20 @@ +# coding:utf-8 +# + +from django.urls import path +from rest_framework_bulk.routes import BulkRouter + +from .. import api + +app_name = 'applications' + +router = BulkRouter() +router.register(r'remote-app', api.RemoteAppViewSet, 'remote-app') + +urlpatterns = [ + path('remote-apps//connection-info/', + api.RemoteAppConnectionInfoApi.as_view(), + name='remote-app-connection-info') +] + +urlpatterns += router.urls diff --git a/apps/applications/urls/views_urls.py b/apps/applications/urls/views_urls.py new file mode 100644 index 000000000..3ffcffc5c --- /dev/null +++ b/apps/applications/urls/views_urls.py @@ -0,0 +1,16 @@ +# coding:utf-8 +from django.urls import path +from .. import views + +app_name = 'applications' + +urlpatterns = [ + # RemoteApp + path('remote-app/', views.RemoteAppListView.as_view(), name='remote-app-list'), + path('remote-app/create/', views.RemoteAppCreateView.as_view(), name='remote-app-create'), + path('remote-app//update/', views.RemoteAppUpdateView.as_view(), name='remote-app-update'), + path('remote-app//', views.RemoteAppDetailView.as_view(), name='remote-app-detail'), + # User RemoteApp view + path('user-remote-app/', views.UserRemoteAppListView.as_view(), name='user-remote-app-list') + +] diff --git a/apps/applications/views/__init__.py b/apps/applications/views/__init__.py new file mode 100644 index 000000000..e6bc7adb4 --- /dev/null +++ b/apps/applications/views/__init__.py @@ -0,0 +1 @@ +from .remote_app import * diff --git a/apps/applications/views/remote_app.py b/apps/applications/views/remote_app.py new file mode 100644 index 000000000..e21db3ad8 --- /dev/null +++ b/apps/applications/views/remote_app.py @@ -0,0 +1,99 @@ +# coding: utf-8 +# + +from django.utils.translation import ugettext as _ +from django.views.generic import TemplateView +from django.views.generic.edit import CreateView, UpdateView +from django.views.generic.detail import DetailView +from django.contrib.messages.views import SuccessMessageMixin +from django.contrib.auth.mixins import LoginRequiredMixin +from django.urls import reverse_lazy + + +from common.permissions import AdminUserRequiredMixin +from common.const import create_success_msg, update_success_msg + +from ..models import RemoteApp +from .. import forms + + +__all__ = [ + 'RemoteAppListView', 'RemoteAppCreateView', 'RemoteAppUpdateView', + 'RemoteAppDetailView', 'UserRemoteAppListView', +] + + +class RemoteAppListView(AdminUserRequiredMixin, TemplateView): + template_name = 'applications/remote_app_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('RemoteApp list'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class RemoteAppCreateView(AdminUserRequiredMixin, SuccessMessageMixin, CreateView): + template_name = 'applications/remote_app_create_update.html' + model = RemoteApp + form_class = forms.RemoteAppCreateUpdateForm + success_url = reverse_lazy('applications:remote-app-list') + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Create RemoteApp'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + def get_success_message(self, cleaned_data): + return create_success_msg % ({'name': cleaned_data['name']}) + + +class RemoteAppUpdateView(AdminUserRequiredMixin, SuccessMessageMixin, UpdateView): + template_name = 'applications/remote_app_create_update.html' + model = RemoteApp + form_class = forms.RemoteAppCreateUpdateForm + success_url = reverse_lazy('applications:remote-app-list') + + def get_initial(self): + return {k: v for k, v in self.object.params.items()} + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Update RemoteApp'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + def get_success_message(self, cleaned_data): + return update_success_msg % ({'name': cleaned_data['name']}) + + +class RemoteAppDetailView(AdminUserRequiredMixin, DetailView): + template_name = 'applications/remote_app_detail.html' + model = RemoteApp + context_object_name = 'remote_app' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('RemoteApp detail'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class UserRemoteAppListView(LoginRequiredMixin, TemplateView): + template_name = 'applications/user_remote_app_list.html' + + def get_context_data(self, **kwargs): + context = { + 'action': _('My RemoteApp'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) diff --git a/apps/assets/const.py b/apps/assets/const.py index a110683d0..0cd74ba0d 100644 --- a/apps/assets/const.py +++ b/apps/assets/const.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- # +from django.utils.translation import ugettext_lazy as _ + + UPDATE_ASSETS_HARDWARE_TASKS = [ { 'name': "setup", @@ -51,3 +54,4 @@ TASK_OPTIONS = { CACHE_KEY_ASSET_BULK_UPDATE_ID_PREFIX = '_KEY_ASSET_BULK_UPDATE_ID_{}' + diff --git a/apps/assets/models/__init__.py b/apps/assets/models/__init__.py index b87a18796..c82c66a69 100644 --- a/apps/assets/models/__init__.py +++ b/apps/assets/models/__init__.py @@ -8,3 +8,4 @@ from .asset import * from .cmd_filter import * from .utils import * from .authbook import * +from applications.models.remote_app import * diff --git a/apps/common/fields/model.py b/apps/common/fields/model.py index b844d3517..c2bb1e0be 100644 --- a/apps/common/fields/model.py +++ b/apps/common/fields/model.py @@ -11,7 +11,7 @@ __all__ = [ 'JsonMixin', 'JsonDictMixin', 'JsonListMixin', 'JsonTypeMixin', 'JsonCharField', 'JsonTextField', 'JsonListCharField', 'JsonListTextField', 'JsonDictCharField', 'JsonDictTextField', 'EncryptCharField', - 'EncryptTextField', 'EncryptMixin', + 'EncryptTextField', 'EncryptMixin', 'EncryptJsonDictTextField', ] signer = get_signer() @@ -129,4 +129,7 @@ class EncryptCharField(EncryptMixin, models.CharField): super().__init__(*args, **kwargs) +class EncryptJsonDictTextField(EncryptMixin, JsonDictTextField): + pass + diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index d97acb361..a6ec9c92a 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -67,6 +67,7 @@ INSTALLED_APPS = [ 'terminal.apps.TerminalConfig', 'audits.apps.AuditsConfig', 'authentication.apps.AuthenticationConfig', # authentication + 'applications.apps.ApplicationsConfig', 'rest_framework', 'rest_framework_swagger', 'drf_yasg', diff --git a/apps/jumpserver/urls.py b/apps/jumpserver/urls.py index 5ef225828..a2538b6c0 100644 --- a/apps/jumpserver/urls.py +++ b/apps/jumpserver/urls.py @@ -20,6 +20,7 @@ api_v1 = [ path('orgs/v1/', include('orgs.urls.api_urls', namespace='api-orgs')), path('settings/v1/', include('settings.urls.api_urls', namespace='api-settings')), path('authentication/v1/', include('authentication.urls.api_urls', namespace='api-auth')), + path('applications/v1/', include('applications.urls.api_urls', namespace='api-applications')), ] api_v2 = [ @@ -37,6 +38,7 @@ app_view_patterns = [ path('audits/', include('audits.urls.view_urls', namespace='audits')), path('orgs/', include('orgs.urls.views_urls', namespace='orgs')), path('auth/', include('authentication.urls.view_urls'), name='auth'), + path('applications/', include('applications.urls.views_urls', namespace='applications')), ] diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 4d188c93e..0d17f388b 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 1f39462f8..9eda46fc6 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: 2019-05-20 11:19+0800\n" +"POT-Creation-Date: 2019-05-20 19:37+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -17,6 +17,573 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +#: applications/const.py:17 +msgid "Browser" +msgstr "浏览器" + +#: applications/const.py:23 +msgid "Database tools" +msgstr "数据库工具" + +#: applications/const.py:29 +msgid "Virtualization tools" +msgstr "虚拟化工具" + +#: applications/const.py:34 +msgid "Custom" +msgstr "自定义" + +#: applications/forms/remote_app.py:20 +msgid "Target URL" +msgstr "目标URL" + +#: applications/forms/remote_app.py:23 applications/forms/remote_app.py:52 +#: applications/forms/remote_app.py:68 +msgid "Login username" +msgstr "登录账号" + +#: applications/forms/remote_app.py:27 applications/forms/remote_app.py:56 +#: applications/forms/remote_app.py:72 +msgid "Login password" +msgstr "登录密码" + +#: applications/forms/remote_app.py:33 +msgid "Database IP" +msgstr "数据库IP" + +#: applications/forms/remote_app.py:36 +msgid "Database name" +msgstr "数据库名" + +#: applications/forms/remote_app.py:39 +msgid "Database username" +msgstr "数据库账号" + +#: applications/forms/remote_app.py:43 +msgid "Database password" +msgstr "数据库密码" + +#: applications/forms/remote_app.py:49 applications/forms/remote_app.py:65 +msgid "Target address" +msgstr "目标地址" + +#: applications/forms/remote_app.py:62 +msgid "Operating parameter" +msgstr "运行参数" + +#: applications/forms/remote_app.py:105 applications/models/remote_app.py:23 +#: applications/templates/applications/remote_app_detail.html:57 +#: applications/templates/applications/remote_app_list.html:22 +#: applications/templates/applications/user_remote_app_list.html:18 +#: assets/forms/domain.py:15 assets/forms/label.py:13 +#: assets/models/asset.py:279 assets/models/authbook.py:27 +#: assets/templates/assets/admin_user_list.html:28 +#: assets/templates/assets/domain_detail.html:60 +#: assets/templates/assets/domain_list.html:26 +#: assets/templates/assets/label_list.html:16 +#: assets/templates/assets/system_user_list.html:33 audits/models.py:19 +#: audits/templates/audits/ftp_log_list.html:41 +#: audits/templates/audits/ftp_log_list.html:71 +#: perms/forms/asset_permission.py:46 perms/models/asset_permission.py:55 +#: perms/templates/perms/asset_permission_create_update.html:45 +#: perms/templates/perms/asset_permission_list.html:56 +#: perms/templates/perms/asset_permission_list.html:125 +#: terminal/backends/command/models.py:13 terminal/models.py:155 +#: terminal/templates/terminal/command_list.html:40 +#: terminal/templates/terminal/command_list.html:73 +#: terminal/templates/terminal/session_list.html:41 +#: terminal/templates/terminal/session_list.html:72 +#: xpack/plugins/change_auth_plan/forms.py:114 +#: xpack/plugins/change_auth_plan/models.py:409 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:13 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:14 +#: xpack/plugins/cloud/models.py:187 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:63 +#: xpack/plugins/orgs/templates/orgs/org_list.html:16 +msgid "Asset" +msgstr "资产" + +#: applications/forms/remote_app.py:108 applications/models/remote_app.py:27 +#: applications/templates/applications/remote_app_detail.html:61 +#: applications/templates/applications/remote_app_list.html:23 +#: applications/templates/applications/user_remote_app_list.html:19 +#: assets/models/user.py:247 assets/templates/assets/user_asset_list.html:168 +#: audits/models.py:20 audits/templates/audits/ftp_log_list.html:49 +#: audits/templates/audits/ftp_log_list.html:72 +#: perms/forms/asset_permission.py:52 perms/models/asset_permission.py:57 +#: perms/models/asset_permission.py:112 +#: perms/templates/perms/asset_permission_detail.html:140 +#: perms/templates/perms/asset_permission_list.html:58 +#: perms/templates/perms/asset_permission_list.html:79 +#: perms/templates/perms/asset_permission_list.html:131 templates/_nav.html:25 +#: terminal/backends/command/models.py:14 terminal/models.py:156 +#: terminal/templates/terminal/command_list.html:48 +#: terminal/templates/terminal/command_list.html:74 +#: terminal/templates/terminal/session_list.html:49 +#: terminal/templates/terminal/session_list.html:73 +#: xpack/plugins/orgs/templates/orgs/org_list.html:19 +msgid "System user" +msgstr "系统用户" + +#: applications/models/remote_app.py:21 +#: applications/templates/applications/remote_app_detail.html:53 +#: applications/templates/applications/remote_app_list.html:20 +#: applications/templates/applications/user_remote_app_list.html:16 +#: assets/forms/domain.py:73 assets/forms/user.py:84 assets/forms/user.py:146 +#: assets/models/base.py:26 assets/models/cluster.py:18 +#: assets/models/cmd_filter.py:20 assets/models/domain.py:20 +#: assets/models/group.py:20 assets/models/label.py:18 +#: assets/templates/assets/admin_user_detail.html:56 +#: assets/templates/assets/admin_user_list.html:26 +#: assets/templates/assets/cmd_filter_detail.html:61 +#: assets/templates/assets/cmd_filter_list.html:24 +#: assets/templates/assets/domain_detail.html:56 +#: assets/templates/assets/domain_gateway_list.html:67 +#: assets/templates/assets/domain_list.html:25 +#: assets/templates/assets/label_list.html:14 +#: assets/templates/assets/system_user_detail.html:58 +#: assets/templates/assets/system_user_list.html:29 ops/models/adhoc.py:37 +#: ops/templates/ops/task_detail.html:60 ops/templates/ops/task_list.html:27 +#: orgs/models.py:12 perms/models/asset_permission.py:22 +#: perms/models/asset_permission.py:52 perms/models/remote_app_permission.py:33 +#: perms/templates/perms/asset_permission_detail.html:62 +#: perms/templates/perms/asset_permission_list.html:53 +#: perms/templates/perms/asset_permission_list.html:72 +#: perms/templates/perms/asset_permission_user.html:54 +#: perms/templates/perms/remote_app_permission_detail.html:62 +#: perms/templates/perms/remote_app_permission_list.html:14 +#: perms/templates/perms/remote_app_permission_remote_app.html:53 +#: perms/templates/perms/remote_app_permission_user.html:53 +#: settings/models.py:29 +#: settings/templates/settings/_ldap_list_users_modal.html:38 +#: settings/templates/settings/command_storage_create.html:41 +#: settings/templates/settings/replay_storage_create.html:44 +#: settings/templates/settings/terminal_setting.html:80 +#: settings/templates/settings/terminal_setting.html:102 terminal/models.py:22 +#: terminal/models.py:241 terminal/templates/terminal/terminal_detail.html:43 +#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 +#: users/models/user.py:61 users/templates/users/_select_user_modal.html:13 +#: users/templates/users/user_detail.html:63 +#: users/templates/users/user_group_detail.html:55 +#: users/templates/users/user_group_list.html:12 +#: users/templates/users/user_list.html:23 +#: users/templates/users/user_profile.html:51 +#: users/templates/users/user_pubkey_update.html:53 +#: xpack/plugins/change_auth_plan/forms.py:97 +#: xpack/plugins/change_auth_plan/models.py:58 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12 +#: xpack/plugins/cloud/models.py:49 xpack/plugins/cloud/models.py:119 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:50 +#: xpack/plugins/cloud/templates/cloud/account_list.html:12 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:53 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:12 +#: xpack/plugins/orgs/templates/orgs/org_detail.html:52 +#: xpack/plugins/orgs/templates/orgs/org_list.html:12 +msgid "Name" +msgstr "名称" + +#: applications/models/remote_app.py:32 +#: applications/templates/applications/remote_app_detail.html:65 +#: applications/templates/applications/remote_app_list.html:21 +#: applications/templates/applications/user_remote_app_list.html:17 +msgid "App type" +msgstr "应用类型" + +#: applications/models/remote_app.py:36 +#: applications/templates/applications/remote_app_detail.html:69 +msgid "App path" +msgstr "应用路径" + +#: applications/models/remote_app.py:40 +msgid "Parameters" +msgstr "参数" + +#: applications/models/remote_app.py:43 +#: applications/templates/applications/remote_app_detail.html:77 +#: assets/models/asset.py:109 assets/models/base.py:34 +#: assets/models/cluster.py:28 assets/models/cmd_filter.py:25 +#: assets/models/cmd_filter.py:58 assets/models/group.py:21 +#: assets/templates/assets/admin_user_detail.html:68 +#: assets/templates/assets/asset_detail.html:128 +#: assets/templates/assets/cmd_filter_detail.html:77 +#: assets/templates/assets/domain_detail.html:72 +#: assets/templates/assets/system_user_detail.html:100 +#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 +#: perms/models/asset_permission.py:62 perms/models/asset_permission.py:115 +#: perms/models/remote_app_permission.py:40 +#: perms/templates/perms/asset_permission_detail.html:98 +#: perms/templates/perms/remote_app_permission_detail.html:90 +#: users/models/user.py:102 users/templates/users/user_detail.html:111 +#: xpack/plugins/change_auth_plan/models.py:103 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 +#: xpack/plugins/cloud/models.py:55 xpack/plugins/cloud/models.py:127 +msgid "Created by" +msgstr "创建者" + +#: applications/models/remote_app.py:46 +#: applications/templates/applications/remote_app_detail.html:73 +#: assets/models/asset.py:110 assets/models/cluster.py:26 +#: assets/models/domain.py:23 assets/models/group.py:22 +#: assets/models/label.py:25 assets/templates/assets/admin_user_detail.html:64 +#: assets/templates/assets/cmd_filter_detail.html:69 +#: assets/templates/assets/domain_detail.html:68 +#: assets/templates/assets/system_user_detail.html:96 +#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:64 +#: orgs/models.py:16 perms/models/asset_permission.py:63 +#: perms/models/asset_permission.py:116 +#: perms/models/remote_app_permission.py:41 +#: perms/templates/perms/asset_permission_detail.html:94 +#: perms/templates/perms/remote_app_permission_detail.html:86 +#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17 +#: users/templates/users/user_group_detail.html:63 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:105 +#: xpack/plugins/cloud/models.py:56 xpack/plugins/cloud/models.py:128 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:66 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:77 +#: xpack/plugins/orgs/templates/orgs/org_detail.html:60 +msgid "Date created" +msgstr "创建日期" + +#: applications/models/remote_app.py:49 +#: applications/templates/applications/remote_app_detail.html:81 +#: applications/templates/applications/remote_app_list.html:24 +#: applications/templates/applications/user_remote_app_list.html:20 +#: assets/models/asset.py:111 assets/models/base.py:31 +#: assets/models/cluster.py:29 assets/models/cmd_filter.py:22 +#: assets/models/cmd_filter.py:55 assets/models/domain.py:21 +#: assets/models/domain.py:53 assets/models/group.py:23 +#: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:72 +#: assets/templates/assets/admin_user_list.html:32 +#: assets/templates/assets/asset_detail.html:136 +#: assets/templates/assets/cmd_filter_detail.html:65 +#: assets/templates/assets/cmd_filter_list.html:27 +#: assets/templates/assets/cmd_filter_rule_list.html:62 +#: assets/templates/assets/domain_detail.html:76 +#: assets/templates/assets/domain_gateway_list.html:72 +#: assets/templates/assets/domain_list.html:28 +#: assets/templates/assets/system_user_detail.html:104 +#: assets/templates/assets/system_user_list.html:37 +#: assets/templates/assets/user_asset_list.html:171 ops/models/adhoc.py:43 +#: orgs/models.py:17 perms/models/asset_permission.py:64 +#: perms/models/asset_permission.py:117 +#: perms/models/remote_app_permission.py:42 +#: perms/templates/perms/asset_permission_detail.html:102 +#: perms/templates/perms/remote_app_permission_detail.html:94 +#: settings/models.py:34 terminal/models.py:32 +#: terminal/templates/terminal/terminal_detail.html:63 users/models/group.py:15 +#: users/models/user.py:94 users/templates/users/user_detail.html:127 +#: users/templates/users/user_group_detail.html:67 +#: users/templates/users/user_group_list.html:14 +#: users/templates/users/user_profile.html:134 +#: xpack/plugins/change_auth_plan/models.py:99 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19 +#: xpack/plugins/cloud/models.py:54 xpack/plugins/cloud/models.py:125 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:70 +#: xpack/plugins/cloud/templates/cloud/account_list.html:15 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:69 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:16 +#: xpack/plugins/orgs/templates/orgs/org_detail.html:64 +#: xpack/plugins/orgs/templates/orgs/org_list.html:22 +msgid "Comment" +msgstr "备注" + +#: applications/models/remote_app.py:53 perms/forms/remote_app_permission.py:37 +#: perms/models/remote_app_permission.py:36 +#: perms/templates/perms/remote_app_permission_create_update.html:48 +#: perms/templates/perms/remote_app_permission_detail.html:27 +#: perms/templates/perms/remote_app_permission_list.html:17 +#: perms/templates/perms/remote_app_permission_remote_app.html:26 +#: perms/templates/perms/remote_app_permission_user.html:26 +#: templates/_nav.html:35 templates/_nav_user.html:14 +msgid "RemoteApp" +msgstr "远程应用" + +#: applications/templates/applications/remote_app_create_update.html:56 +#: assets/templates/assets/_system_user.html:75 +#: assets/templates/assets/admin_user_create_update.html:45 +#: assets/templates/assets/asset_bulk_update.html:23 +#: assets/templates/assets/asset_create.html:67 +#: assets/templates/assets/asset_update.html:71 +#: assets/templates/assets/cmd_filter_create_update.html:15 +#: assets/templates/assets/cmd_filter_rule_create_update.html:40 +#: assets/templates/assets/domain_create_update.html:16 +#: assets/templates/assets/gateway_create_update.html:58 +#: assets/templates/assets/label_create_update.html:18 +#: perms/templates/perms/asset_permission_create_update.html:83 +#: perms/templates/perms/remote_app_permission_create_update.html:83 +#: settings/templates/settings/basic_setting.html:61 +#: settings/templates/settings/command_storage_create.html:79 +#: settings/templates/settings/email_setting.html:62 +#: settings/templates/settings/ldap_setting.html:61 +#: settings/templates/settings/replay_storage_create.html:152 +#: settings/templates/settings/security_setting.html:70 +#: settings/templates/settings/terminal_setting.html:68 +#: terminal/templates/terminal/terminal_update.html:45 +#: users/templates/users/_user.html:50 +#: users/templates/users/user_bulk_update.html:23 +#: users/templates/users/user_detail.html:176 +#: users/templates/users/user_password_update.html:71 +#: users/templates/users/user_profile.html:204 +#: users/templates/users/user_profile_update.html:63 +#: users/templates/users/user_pubkey_update.html:70 +#: users/templates/users/user_pubkey_update.html:76 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:71 +#: xpack/plugins/cloud/templates/cloud/account_create_update.html:33 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:35 +#: xpack/plugins/interface/templates/interface/interface.html:72 +msgid "Reset" +msgstr "重置" + +#: applications/templates/applications/remote_app_create_update.html:58 +#: assets/templates/assets/_system_user.html:76 +#: assets/templates/assets/admin_user_create_update.html:46 +#: assets/templates/assets/asset_bulk_update.html:24 +#: assets/templates/assets/asset_create.html:68 +#: assets/templates/assets/asset_list.html:113 +#: assets/templates/assets/asset_update.html:72 +#: assets/templates/assets/cmd_filter_create_update.html:16 +#: assets/templates/assets/cmd_filter_rule_create_update.html:41 +#: assets/templates/assets/domain_create_update.html:17 +#: assets/templates/assets/gateway_create_update.html:59 +#: assets/templates/assets/label_create_update.html:19 +#: audits/templates/audits/login_log_list.html:89 +#: perms/templates/perms/asset_permission_create_update.html:84 +#: perms/templates/perms/remote_app_permission_create_update.html:84 +#: settings/templates/settings/basic_setting.html:62 +#: settings/templates/settings/command_storage_create.html:80 +#: settings/templates/settings/email_setting.html:63 +#: settings/templates/settings/ldap_setting.html:64 +#: settings/templates/settings/replay_storage_create.html:153 +#: settings/templates/settings/security_setting.html:71 +#: settings/templates/settings/terminal_setting.html:70 +#: terminal/templates/terminal/command_list.html:103 +#: terminal/templates/terminal/session_list.html:126 +#: terminal/templates/terminal/terminal_update.html:46 +#: users/templates/users/_user.html:51 +#: users/templates/users/forgot_password.html:42 +#: users/templates/users/user_bulk_update.html:24 +#: users/templates/users/user_list.html:45 +#: users/templates/users/user_password_update.html:72 +#: users/templates/users/user_profile_update.html:64 +#: users/templates/users/user_pubkey_update.html:77 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:72 +#: xpack/plugins/interface/templates/interface/interface.html:74 +msgid "Submit" +msgstr "提交" + +#: applications/templates/applications/remote_app_detail.html:18 +#: assets/templates/assets/admin_user_assets.html:18 +#: assets/templates/assets/admin_user_detail.html:18 +#: assets/templates/assets/cmd_filter_detail.html:19 +#: assets/templates/assets/cmd_filter_rule_list.html:19 +#: assets/templates/assets/domain_detail.html:18 +#: assets/templates/assets/domain_gateway_list.html:20 +#: assets/templates/assets/system_user_asset.html:18 +#: assets/templates/assets/system_user_detail.html:18 +#: ops/templates/ops/adhoc_history.html:130 +#: ops/templates/ops/task_adhoc.html:116 +#: ops/templates/ops/task_history.html:136 +#: perms/templates/perms/asset_permission_asset.html:18 +#: perms/templates/perms/asset_permission_detail.html:18 +#: perms/templates/perms/asset_permission_user.html:18 +#: perms/templates/perms/remote_app_permission_detail.html:18 +#: perms/templates/perms/remote_app_permission_remote_app.html:17 +#: perms/templates/perms/remote_app_permission_user.html:17 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:17 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:20 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:17 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:106 +#: xpack/plugins/change_auth_plan/views.py:83 +msgid "Detail" +msgstr "详情" + +#: applications/templates/applications/remote_app_detail.html:21 +#: applications/templates/applications/remote_app_list.html:56 +#: assets/templates/assets/admin_user_detail.html:24 +#: assets/templates/assets/admin_user_list.html:88 +#: assets/templates/assets/asset_detail.html:27 +#: assets/templates/assets/asset_list.html:178 +#: assets/templates/assets/cmd_filter_detail.html:29 +#: assets/templates/assets/cmd_filter_list.html:58 +#: assets/templates/assets/cmd_filter_rule_list.html:86 +#: assets/templates/assets/domain_detail.html:24 +#: assets/templates/assets/domain_detail.html:103 +#: assets/templates/assets/domain_gateway_list.html:97 +#: assets/templates/assets/domain_list.html:54 +#: assets/templates/assets/label_list.html:39 +#: assets/templates/assets/system_user_detail.html:26 +#: assets/templates/assets/system_user_list.html:93 audits/models.py:33 +#: perms/templates/perms/asset_permission_detail.html:30 +#: perms/templates/perms/asset_permission_list.html:181 +#: perms/templates/perms/remote_app_permission_detail.html:30 +#: perms/templates/perms/remote_app_permission_list.html:59 +#: terminal/templates/terminal/terminal_detail.html:16 +#: terminal/templates/terminal/terminal_list.html:72 +#: users/templates/users/user_detail.html:25 +#: users/templates/users/user_group_detail.html:28 +#: users/templates/users/user_group_list.html:45 +#: users/templates/users/user_list.html:83 +#: users/templates/users/user_list.html:86 +#: users/templates/users/user_profile.html:177 +#: users/templates/users/user_profile.html:187 +#: users/templates/users/user_profile.html:196 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:29 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:55 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:23 +#: xpack/plugins/cloud/templates/cloud/account_list.html:39 +#: xpack/plugins/orgs/templates/orgs/org_detail.html:25 +#: xpack/plugins/orgs/templates/orgs/org_list.html:87 +msgid "Update" +msgstr "更新" + +#: applications/templates/applications/remote_app_detail.html:25 +#: applications/templates/applications/remote_app_list.html:57 +#: assets/templates/assets/admin_user_detail.html:28 +#: assets/templates/assets/admin_user_list.html:89 +#: assets/templates/assets/asset_detail.html:31 +#: assets/templates/assets/asset_list.html:179 +#: assets/templates/assets/cmd_filter_detail.html:33 +#: assets/templates/assets/cmd_filter_list.html:59 +#: assets/templates/assets/cmd_filter_rule_list.html:87 +#: assets/templates/assets/domain_detail.html:28 +#: assets/templates/assets/domain_detail.html:104 +#: assets/templates/assets/domain_gateway_list.html:98 +#: assets/templates/assets/domain_list.html:55 +#: assets/templates/assets/label_list.html:40 +#: assets/templates/assets/system_user_detail.html:30 +#: assets/templates/assets/system_user_list.html:94 audits/models.py:34 +#: ops/templates/ops/task_list.html:64 +#: perms/templates/perms/asset_permission_detail.html:34 +#: perms/templates/perms/asset_permission_list.html:182 +#: perms/templates/perms/remote_app_permission_detail.html:34 +#: perms/templates/perms/remote_app_permission_list.html:60 +#: settings/templates/settings/terminal_setting.html:90 +#: settings/templates/settings/terminal_setting.html:112 +#: terminal/templates/terminal/terminal_list.html:74 +#: users/templates/users/user_detail.html:30 +#: users/templates/users/user_group_detail.html:32 +#: users/templates/users/user_group_list.html:47 +#: users/templates/users/user_list.html:91 +#: users/templates/users/user_list.html:95 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:33 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:57 +#: xpack/plugins/cloud/templates/cloud/account_detail.html:27 +#: xpack/plugins/cloud/templates/cloud/account_list.html:41 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:30 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:55 +#: xpack/plugins/orgs/templates/orgs/org_detail.html:29 +#: xpack/plugins/orgs/templates/orgs/org_list.html:89 +msgid "Delete" +msgstr "删除" + +#: applications/templates/applications/remote_app_list.html:5 +msgid "" +"Before using this feature, make sure that the application loader has been " +"uploaded to the application server and successfully published as a RemoteApp " +"application" +msgstr "" +"使用此功能前,请确保已将应用加载器上传到应用服务器并成功发布为一个RemoteApp应" +"用" + +#: applications/templates/applications/remote_app_list.html:6 +msgid "Download application loader" +msgstr "下载应用加载器" + +#: applications/templates/applications/remote_app_list.html:12 +#: applications/views/remote_app.py:47 +msgid "Create RemoteApp" +msgstr "创建远程应用" + +#: applications/templates/applications/remote_app_list.html:25 +#: applications/templates/applications/user_remote_app_list.html:21 +#: assets/models/cmd_filter.py:54 +#: assets/templates/assets/admin_user_assets.html:52 +#: assets/templates/assets/admin_user_list.html:33 +#: assets/templates/assets/asset_asset_user_list.html:48 +#: assets/templates/assets/asset_list.html:96 +#: assets/templates/assets/cmd_filter_list.html:28 +#: assets/templates/assets/cmd_filter_rule_list.html:63 +#: assets/templates/assets/domain_gateway_list.html:73 +#: assets/templates/assets/domain_list.html:29 +#: assets/templates/assets/label_list.html:17 +#: assets/templates/assets/system_user_asset.html:54 +#: assets/templates/assets/system_user_list.html:38 +#: assets/templates/assets/user_asset_list.html:48 audits/models.py:38 +#: audits/templates/audits/operate_log_list.html:41 +#: audits/templates/audits/operate_log_list.html:67 +#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64 +#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:34 +#: perms/forms/asset_permission.py:55 perms/models/asset_permission.py:26 +#: perms/models/asset_permission.py:58 +#: perms/templates/perms/asset_permission_create_update.html:50 +#: perms/templates/perms/asset_permission_list.html:60 +#: perms/templates/perms/asset_permission_list.html:134 +#: perms/templates/perms/remote_app_permission_list.html:19 +#: settings/templates/settings/terminal_setting.html:82 +#: settings/templates/settings/terminal_setting.html:104 +#: terminal/templates/terminal/session_list.html:81 +#: terminal/templates/terminal/terminal_list.html:36 +#: users/templates/users/user_group_list.html:15 +#: users/templates/users/user_list.html:29 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:60 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:18 +#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:20 +#: xpack/plugins/cloud/templates/cloud/account_list.html:16 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:18 +#: xpack/plugins/orgs/templates/orgs/org_list.html:23 +msgid "Action" +msgstr "动作" + +#: applications/templates/applications/user_remote_app_list.html:57 +#: assets/templates/assets/user_asset_list.html:100 perms/const.py:19 +msgid "Connect" +msgstr "连接" + +#: applications/views/remote_app.py:31 applications/views/remote_app.py:46 +#: applications/views/remote_app.py:67 applications/views/remote_app.py:84 +#: assets/models/user.py:134 +#: assets/templates/assets/_asset_group_bulk_update_modal.html:11 +#: assets/templates/assets/system_user_asset.html:22 +#: assets/templates/assets/system_user_detail.html:22 +#: assets/views/admin_user.py:29 assets/views/admin_user.py:47 +#: assets/views/admin_user.py:63 assets/views/admin_user.py:78 +#: assets/views/admin_user.py:102 assets/views/asset.py:51 +#: assets/views/asset.py:67 assets/views/asset.py:104 assets/views/asset.py:145 +#: assets/views/asset.py:162 assets/views/asset.py:186 +#: assets/views/cmd_filter.py:30 assets/views/cmd_filter.py:46 +#: assets/views/cmd_filter.py:62 assets/views/cmd_filter.py:78 +#: assets/views/cmd_filter.py:97 assets/views/cmd_filter.py:130 +#: assets/views/cmd_filter.py:163 assets/views/domain.py:29 +#: assets/views/domain.py:45 assets/views/domain.py:61 +#: assets/views/domain.py:74 assets/views/domain.py:98 +#: assets/views/domain.py:126 assets/views/domain.py:145 +#: assets/views/label.py:26 assets/views/label.py:43 assets/views/label.py:69 +#: assets/views/system_user.py:28 assets/views/system_user.py:44 +#: assets/views/system_user.py:60 assets/views/system_user.py:74 +#: templates/_nav.html:19 xpack/plugins/change_auth_plan/models.py:65 +msgid "Assets" +msgstr "资产管理" + +#: applications/views/remote_app.py:32 +msgid "RemoteApp list" +msgstr "远程应用列表" + +#: applications/views/remote_app.py:68 +msgid "Update RemoteApp" +msgstr "更新远程应用" + +#: applications/views/remote_app.py:85 +msgid "RemoteApp detail" +msgstr "远程应用详情" + +#: applications/views/remote_app.py:96 +msgid "My RemoteApp" +msgstr "我的远程应用" + #: assets/api/asset.py:112 msgid "Please select assets that need to be updated" msgstr "请选择需要更新的资产" @@ -36,7 +603,8 @@ msgstr "测试节点下资产是否可连接: {}" #: assets/forms/asset.py:27 assets/models/asset.py:80 assets/models/user.py:133 #: assets/templates/assets/asset_detail.html:194 #: assets/templates/assets/asset_detail.html:202 -#: assets/templates/assets/system_user_asset.html:95 perms/models.py:51 +#: assets/templates/assets/system_user_asset.html:95 +#: perms/models/asset_permission.py:56 #: xpack/plugins/change_auth_plan/models.py:69 msgid "Nodes" msgstr "节点管理" @@ -72,8 +640,9 @@ msgstr "网域" #: assets/forms/asset.py:41 assets/forms/asset.py:63 assets/forms/asset.py:77 #: assets/forms/asset.py:112 assets/models/node.py:31 #: assets/templates/assets/asset_create.html:30 -#: assets/templates/assets/asset_update.html:35 perms/forms.py:45 -#: perms/forms.py:55 perms/models.py:105 +#: assets/templates/assets/asset_update.html:35 +#: perms/forms/asset_permission.py:49 perms/forms/asset_permission.py:59 +#: perms/models/asset_permission.py:110 #: perms/templates/perms/asset_permission_list.html:57 #: perms/templates/perms/asset_permission_list.html:78 #: perms/templates/perms/asset_permission_list.html:128 @@ -111,36 +680,6 @@ msgstr "如果有多个的互相隔离的网络,设置资产属于的网域, msgid "Select assets" msgstr "选择资产" -#: assets/forms/domain.py:15 assets/forms/label.py:13 -#: assets/models/asset.py:279 assets/models/authbook.py:27 -#: assets/templates/assets/admin_user_list.html:28 -#: assets/templates/assets/domain_detail.html:60 -#: assets/templates/assets/domain_list.html:26 -#: assets/templates/assets/label_list.html:16 -#: assets/templates/assets/system_user_list.html:33 audits/models.py:19 -#: audits/templates/audits/ftp_log_list.html:41 -#: audits/templates/audits/ftp_log_list.html:71 perms/forms.py:42 -#: perms/models.py:50 -#: perms/templates/perms/asset_permission_create_update.html:45 -#: perms/templates/perms/asset_permission_list.html:56 -#: perms/templates/perms/asset_permission_list.html:125 -#: terminal/backends/command/models.py:13 terminal/models.py:155 -#: terminal/templates/terminal/command_list.html:40 -#: terminal/templates/terminal/command_list.html:73 -#: terminal/templates/terminal/session_list.html:41 -#: terminal/templates/terminal/session_list.html:72 -#: xpack/plugins/change_auth_plan/forms.py:114 -#: xpack/plugins/change_auth_plan/models.py:409 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:46 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:54 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:13 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:14 -#: xpack/plugins/cloud/models.py:187 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_instance.html:63 -#: xpack/plugins/orgs/templates/orgs/org_list.html:16 -msgid "Asset" -msgstr "资产" - #: assets/forms/domain.py:51 msgid "Password should not contain special characters" msgstr "不能包含特殊字符" @@ -149,54 +688,6 @@ msgstr "不能包含特殊字符" msgid "SSH gateway support proxy SSH,RDP,VNC" msgstr "SSH网关,支持代理SSH,RDP和VNC" -#: assets/forms/domain.py:73 assets/forms/user.py:84 assets/forms/user.py:146 -#: assets/models/base.py:26 assets/models/cluster.py:18 -#: assets/models/cmd_filter.py:20 assets/models/domain.py:20 -#: assets/models/group.py:20 assets/models/label.py:18 -#: assets/templates/assets/admin_user_detail.html:56 -#: assets/templates/assets/admin_user_list.html:26 -#: assets/templates/assets/cmd_filter_detail.html:61 -#: assets/templates/assets/cmd_filter_list.html:24 -#: assets/templates/assets/domain_detail.html:56 -#: assets/templates/assets/domain_gateway_list.html:67 -#: assets/templates/assets/domain_list.html:25 -#: assets/templates/assets/label_list.html:14 -#: assets/templates/assets/system_user_detail.html:58 -#: assets/templates/assets/system_user_list.html:29 ops/models/adhoc.py:37 -#: ops/templates/ops/task_detail.html:60 ops/templates/ops/task_list.html:27 -#: orgs/models.py:12 perms/models.py:17 perms/models.py:47 -#: perms/templates/perms/asset_permission_detail.html:62 -#: perms/templates/perms/asset_permission_list.html:53 -#: perms/templates/perms/asset_permission_list.html:72 -#: perms/templates/perms/asset_permission_user.html:54 settings/models.py:29 -#: settings/templates/settings/_ldap_list_users_modal.html:38 -#: settings/templates/settings/command_storage_create.html:41 -#: settings/templates/settings/replay_storage_create.html:44 -#: settings/templates/settings/terminal_setting.html:80 -#: settings/templates/settings/terminal_setting.html:102 terminal/models.py:22 -#: terminal/models.py:241 terminal/templates/terminal/terminal_detail.html:43 -#: terminal/templates/terminal/terminal_list.html:29 users/models/group.py:14 -#: users/models/user.py:61 users/templates/users/_select_user_modal.html:13 -#: users/templates/users/user_detail.html:63 -#: users/templates/users/user_group_detail.html:55 -#: users/templates/users/user_group_list.html:12 -#: users/templates/users/user_list.html:23 -#: users/templates/users/user_profile.html:51 -#: users/templates/users/user_pubkey_update.html:53 -#: xpack/plugins/change_auth_plan/forms.py:97 -#: xpack/plugins/change_auth_plan/models.py:58 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:61 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:12 -#: xpack/plugins/cloud/models.py:49 xpack/plugins/cloud/models.py:119 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:50 -#: xpack/plugins/cloud/templates/cloud/account_list.html:12 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:53 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:12 -#: xpack/plugins/orgs/templates/orgs/org_detail.html:52 -#: xpack/plugins/orgs/templates/orgs/org_list.html:12 -msgid "Name" -msgstr "名称" - #: assets/forms/domain.py:74 assets/forms/user.py:85 assets/forms/user.py:147 #: assets/models/base.py:27 #: assets/templates/assets/_asset_user_auth_modal.html:15 @@ -212,6 +703,7 @@ msgstr "名称" #: authentication/templates/authentication/new_login.html:90 #: ops/models/adhoc.py:164 perms/templates/perms/asset_permission_list.html:74 #: perms/templates/perms/asset_permission_user.html:55 +#: perms/templates/perms/remote_app_permission_user.html:54 #: settings/templates/settings/_ldap_list_users_modal.html:37 users/forms.py:13 #: users/models/user.py:59 users/templates/users/_select_user_modal.html:14 #: users/templates/users/user_detail.html:67 @@ -434,79 +926,6 @@ msgstr "主机名原始" msgid "Labels" msgstr "标签管理" -#: assets/models/asset.py:109 assets/models/base.py:34 -#: assets/models/cluster.py:28 assets/models/cmd_filter.py:25 -#: assets/models/cmd_filter.py:58 assets/models/group.py:21 -#: assets/templates/assets/admin_user_detail.html:68 -#: assets/templates/assets/asset_detail.html:128 -#: assets/templates/assets/cmd_filter_detail.html:77 -#: assets/templates/assets/domain_detail.html:72 -#: assets/templates/assets/system_user_detail.html:100 -#: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 perms/models.py:57 -#: perms/models.py:110 perms/templates/perms/asset_permission_detail.html:98 -#: users/models/user.py:102 users/templates/users/user_detail.html:111 -#: xpack/plugins/change_auth_plan/models.py:103 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:113 -#: xpack/plugins/cloud/models.py:55 xpack/plugins/cloud/models.py:127 -msgid "Created by" -msgstr "创建者" - -#: assets/models/asset.py:110 assets/models/cluster.py:26 -#: assets/models/domain.py:23 assets/models/group.py:22 -#: assets/models/label.py:25 assets/templates/assets/admin_user_detail.html:64 -#: assets/templates/assets/cmd_filter_detail.html:69 -#: assets/templates/assets/domain_detail.html:68 -#: assets/templates/assets/system_user_detail.html:96 -#: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:64 -#: orgs/models.py:16 perms/models.py:58 perms/models.py:111 -#: perms/templates/perms/asset_permission_detail.html:94 -#: terminal/templates/terminal/terminal_detail.html:59 users/models/group.py:17 -#: users/templates/users/user_group_detail.html:63 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:105 -#: xpack/plugins/cloud/models.py:56 xpack/plugins/cloud/models.py:128 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:66 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:77 -#: xpack/plugins/orgs/templates/orgs/org_detail.html:60 -msgid "Date created" -msgstr "创建日期" - -#: assets/models/asset.py:111 assets/models/base.py:31 -#: assets/models/cluster.py:29 assets/models/cmd_filter.py:22 -#: assets/models/cmd_filter.py:55 assets/models/domain.py:21 -#: assets/models/domain.py:53 assets/models/group.py:23 -#: assets/models/label.py:23 assets/templates/assets/admin_user_detail.html:72 -#: assets/templates/assets/admin_user_list.html:32 -#: assets/templates/assets/asset_detail.html:136 -#: assets/templates/assets/cmd_filter_detail.html:65 -#: assets/templates/assets/cmd_filter_list.html:27 -#: assets/templates/assets/cmd_filter_rule_list.html:62 -#: assets/templates/assets/domain_detail.html:76 -#: assets/templates/assets/domain_gateway_list.html:72 -#: assets/templates/assets/domain_list.html:28 -#: assets/templates/assets/system_user_detail.html:104 -#: assets/templates/assets/system_user_list.html:37 -#: assets/templates/assets/user_asset_list.html:171 ops/models/adhoc.py:43 -#: orgs/models.py:17 perms/models.py:59 perms/models.py:112 -#: perms/templates/perms/asset_permission_detail.html:102 settings/models.py:34 -#: terminal/models.py:32 terminal/templates/terminal/terminal_detail.html:63 -#: users/models/group.py:15 users/models/user.py:94 -#: users/templates/users/user_detail.html:127 -#: users/templates/users/user_group_detail.html:67 -#: users/templates/users/user_group_list.html:14 -#: users/templates/users/user_profile.html:134 -#: xpack/plugins/change_auth_plan/models.py:99 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:117 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:19 -#: xpack/plugins/cloud/models.py:54 xpack/plugins/cloud/models.py:125 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:70 -#: xpack/plugins/cloud/templates/cloud/account_list.html:15 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:69 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:16 -#: xpack/plugins/orgs/templates/orgs/org_detail.html:64 -#: xpack/plugins/orgs/templates/orgs/org_list.html:22 -msgid "Comment" -msgstr "备注" - #: assets/models/asset.py:117 assets/models/base.py:38 #: assets/templates/assets/admin_user_list.html:30 #: assets/templates/assets/system_user_list.html:35 @@ -639,6 +1058,7 @@ msgstr "过滤器" #: assets/models/cmd_filter.py:50 #: assets/templates/assets/cmd_filter_rule_list.html:58 #: audits/templates/audits/login_log_list.html:52 +#: perms/templates/perms/remote_app_permission_remote_app.html:54 #: settings/templates/settings/command_storage_create.html:31 #: settings/templates/settings/replay_storage_create.html:31 #: settings/templates/settings/terminal_setting.html:81 @@ -665,42 +1085,6 @@ msgstr "内容" msgid "One line one command" msgstr "每行一个命令" -#: assets/models/cmd_filter.py:54 -#: assets/templates/assets/admin_user_assets.html:52 -#: assets/templates/assets/admin_user_list.html:33 -#: assets/templates/assets/asset_asset_user_list.html:48 -#: assets/templates/assets/asset_list.html:96 -#: assets/templates/assets/cmd_filter_list.html:28 -#: assets/templates/assets/cmd_filter_rule_list.html:63 -#: assets/templates/assets/domain_gateway_list.html:73 -#: assets/templates/assets/domain_list.html:29 -#: assets/templates/assets/label_list.html:17 -#: assets/templates/assets/system_user_asset.html:54 -#: assets/templates/assets/system_user_list.html:38 -#: assets/templates/assets/user_asset_list.html:48 audits/models.py:38 -#: audits/templates/audits/operate_log_list.html:41 -#: audits/templates/audits/operate_log_list.html:67 -#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64 -#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:34 -#: perms/forms.py:51 perms/models.py:21 perms/models.py:53 -#: perms/templates/perms/asset_permission_create_update.html:50 -#: perms/templates/perms/asset_permission_list.html:60 -#: perms/templates/perms/asset_permission_list.html:134 -#: settings/templates/settings/terminal_setting.html:82 -#: settings/templates/settings/terminal_setting.html:104 -#: terminal/templates/terminal/session_list.html:81 -#: terminal/templates/terminal/terminal_list.html:36 -#: users/templates/users/user_group_list.html:15 -#: users/templates/users/user_list.html:29 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:60 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_subtask_list.html:18 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:20 -#: xpack/plugins/cloud/templates/cloud/account_list.html:16 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:18 -#: xpack/plugins/orgs/templates/orgs/org_list.html:23 -msgid "Action" -msgstr "动作" - #: assets/models/cmd_filter.py:64 msgid "Command filter rule" msgstr "命令过滤规则" @@ -728,13 +1112,16 @@ msgstr "默认资产组" #: audits/templates/audits/password_change_log_list.html:33 #: audits/templates/audits/password_change_log_list.html:50 #: ops/templates/ops/command_execution_list.html:35 -#: ops/templates/ops/command_execution_list.html:60 perms/forms.py:36 -#: perms/models.py:48 +#: ops/templates/ops/command_execution_list.html:60 +#: perms/forms/asset_permission.py:40 perms/forms/remote_app_permission.py:31 +#: perms/models/asset_permission.py:53 perms/models/remote_app_permission.py:34 #: perms/templates/perms/asset_permission_create_update.html:41 #: perms/templates/perms/asset_permission_list.html:54 -#: perms/templates/perms/asset_permission_list.html:119 templates/index.html:87 -#: terminal/backends/command/models.py:12 terminal/models.py:154 -#: terminal/templates/terminal/command_list.html:32 +#: perms/templates/perms/asset_permission_list.html:119 +#: perms/templates/perms/remote_app_permission_create_update.html:43 +#: perms/templates/perms/remote_app_permission_list.html:15 +#: templates/index.html:87 terminal/backends/command/models.py:12 +#: terminal/models.py:154 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:283 @@ -772,29 +1159,6 @@ msgstr "自动登录" msgid "Manually login" msgstr "手动登录" -#: assets/models/user.py:134 -#: assets/templates/assets/_asset_group_bulk_update_modal.html:11 -#: assets/templates/assets/system_user_asset.html:22 -#: assets/templates/assets/system_user_detail.html:22 -#: assets/views/admin_user.py:29 assets/views/admin_user.py:47 -#: assets/views/admin_user.py:63 assets/views/admin_user.py:78 -#: assets/views/admin_user.py:102 assets/views/asset.py:51 -#: assets/views/asset.py:67 assets/views/asset.py:104 assets/views/asset.py:145 -#: assets/views/asset.py:162 assets/views/asset.py:186 -#: assets/views/cmd_filter.py:30 assets/views/cmd_filter.py:46 -#: assets/views/cmd_filter.py:62 assets/views/cmd_filter.py:78 -#: assets/views/cmd_filter.py:97 assets/views/cmd_filter.py:130 -#: assets/views/cmd_filter.py:163 assets/views/domain.py:29 -#: assets/views/domain.py:45 assets/views/domain.py:61 -#: assets/views/domain.py:74 assets/views/domain.py:98 -#: assets/views/domain.py:126 assets/views/domain.py:145 -#: assets/views/label.py:26 assets/views/label.py:43 assets/views/label.py:69 -#: assets/views/system_user.py:28 assets/views/system_user.py:44 -#: assets/views/system_user.py:60 assets/views/system_user.py:74 -#: templates/_nav.html:19 xpack/plugins/change_auth_plan/models.py:65 -msgid "Assets" -msgstr "资产管理" - #: assets/models/user.py:137 assets/templates/assets/_system_user.html:59 #: assets/templates/assets/system_user_detail.html:122 #: assets/templates/assets/system_user_update.html:10 @@ -814,23 +1178,6 @@ msgstr "Shell" msgid "Login mode" msgstr "登录模式" -#: assets/models/user.py:247 assets/templates/assets/user_asset_list.html:168 -#: audits/models.py:20 audits/templates/audits/ftp_log_list.html:49 -#: audits/templates/audits/ftp_log_list.html:72 perms/forms.py:48 -#: perms/models.py:52 perms/models.py:107 -#: perms/templates/perms/asset_permission_detail.html:140 -#: perms/templates/perms/asset_permission_list.html:58 -#: perms/templates/perms/asset_permission_list.html:79 -#: perms/templates/perms/asset_permission_list.html:131 templates/_nav.html:25 -#: terminal/backends/command/models.py:14 terminal/models.py:156 -#: terminal/templates/terminal/command_list.html:48 -#: terminal/templates/terminal/command_list.html:74 -#: terminal/templates/terminal/session_list.html:49 -#: terminal/templates/terminal/session_list.html:73 -#: xpack/plugins/orgs/templates/orgs/org_list.html:19 -msgid "System user" -msgstr "系统用户" - #: assets/models/utils.py:29 #, python-format msgid "%(value)s is not an even number" @@ -983,9 +1330,9 @@ msgid "Asset user auth" msgstr "资产用户信息" #: assets/templates/assets/_asset_user_view_auth_modal.html:14 -#: assets/templates/assets/_otp_verify_modal.html:8 audits/models.py:99 -#: audits/templates/audits/login_log_list.html:56 users/forms.py:142 -#: users/models/user.py:83 users/templates/users/first_login.html:45 +#: audits/models.py:99 audits/templates/audits/login_log_list.html:56 +#: users/forms.py:142 users/models/user.py:83 +#: users/templates/users/first_login.html:45 msgid "MFA" msgstr "MFA" @@ -1045,15 +1392,12 @@ msgstr "SSH端口" msgid "If use nat, set the ssh real port" msgstr "如果使用了nat端口映射,请设置为ssh真实监听的端口" -#: assets/templates/assets/_otp_verify_modal.html:4 -msgid "MFA Confirm" -msgstr "确认" - #: assets/templates/assets/_system_user.html:37 #: assets/templates/assets/asset_create.html:16 #: assets/templates/assets/asset_update.html:21 #: assets/templates/assets/gateway_create_update.html:37 #: perms/templates/perms/asset_permission_create_update.html:38 +#: perms/templates/perms/remote_app_permission_create_update.html:39 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:43 msgid "Basic" msgstr "基本" @@ -1075,108 +1419,18 @@ msgstr "自动生成密钥" #: assets/templates/assets/asset_update.html:64 #: assets/templates/assets/gateway_create_update.html:53 #: perms/templates/perms/asset_permission_create_update.html:53 +#: perms/templates/perms/remote_app_permission_create_update.html:52 #: terminal/templates/terminal/terminal_update.html:40 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:67 msgid "Other" msgstr "其它" -#: assets/templates/assets/_system_user.html:75 -#: assets/templates/assets/admin_user_create_update.html:45 -#: assets/templates/assets/asset_bulk_update.html:23 -#: assets/templates/assets/asset_create.html:67 -#: assets/templates/assets/asset_update.html:71 -#: assets/templates/assets/cmd_filter_create_update.html:15 -#: assets/templates/assets/cmd_filter_rule_create_update.html:40 -#: assets/templates/assets/domain_create_update.html:16 -#: assets/templates/assets/gateway_create_update.html:58 -#: assets/templates/assets/label_create_update.html:18 -#: perms/templates/perms/asset_permission_create_update.html:83 -#: settings/templates/settings/basic_setting.html:61 -#: settings/templates/settings/command_storage_create.html:79 -#: settings/templates/settings/email_setting.html:62 -#: settings/templates/settings/ldap_setting.html:61 -#: settings/templates/settings/replay_storage_create.html:152 -#: settings/templates/settings/security_setting.html:70 -#: settings/templates/settings/terminal_setting.html:68 -#: terminal/templates/terminal/terminal_update.html:45 -#: users/templates/users/_user.html:50 -#: users/templates/users/user_bulk_update.html:23 -#: users/templates/users/user_detail.html:176 -#: users/templates/users/user_password_update.html:71 -#: users/templates/users/user_profile.html:204 -#: users/templates/users/user_profile_update.html:63 -#: users/templates/users/user_pubkey_update.html:70 -#: users/templates/users/user_pubkey_update.html:76 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:71 -#: xpack/plugins/cloud/templates/cloud/account_create_update.html:33 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_create.html:35 -#: xpack/plugins/interface/templates/interface/interface.html:72 -msgid "Reset" -msgstr "重置" - -#: assets/templates/assets/_system_user.html:76 -#: assets/templates/assets/admin_user_create_update.html:46 -#: assets/templates/assets/asset_bulk_update.html:24 -#: assets/templates/assets/asset_create.html:68 -#: assets/templates/assets/asset_list.html:113 -#: assets/templates/assets/asset_update.html:72 -#: assets/templates/assets/cmd_filter_create_update.html:16 -#: assets/templates/assets/cmd_filter_rule_create_update.html:41 -#: assets/templates/assets/domain_create_update.html:17 -#: assets/templates/assets/gateway_create_update.html:59 -#: assets/templates/assets/label_create_update.html:19 -#: audits/templates/audits/login_log_list.html:89 -#: perms/templates/perms/asset_permission_create_update.html:84 -#: settings/templates/settings/basic_setting.html:62 -#: settings/templates/settings/command_storage_create.html:80 -#: settings/templates/settings/email_setting.html:63 -#: settings/templates/settings/ldap_setting.html:64 -#: settings/templates/settings/replay_storage_create.html:153 -#: settings/templates/settings/security_setting.html:71 -#: settings/templates/settings/terminal_setting.html:70 -#: terminal/templates/terminal/command_list.html:103 -#: terminal/templates/terminal/session_list.html:126 -#: terminal/templates/terminal/terminal_update.html:46 -#: users/templates/users/_user.html:51 -#: users/templates/users/forgot_password.html:42 -#: users/templates/users/user_bulk_update.html:24 -#: users/templates/users/user_list.html:45 -#: users/templates/users/user_password_update.html:72 -#: users/templates/users/user_profile_update.html:64 -#: users/templates/users/user_pubkey_update.html:77 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_create_update.html:72 -#: xpack/plugins/interface/templates/interface/interface.html:74 -msgid "Submit" -msgstr "提交" - #: assets/templates/assets/_user_asset_detail_modal.html:11 #: assets/templates/assets/asset_asset_user_list.html:13 #: assets/templates/assets/asset_detail.html:20 assets/views/asset.py:187 msgid "Asset detail" msgstr "资产详情" -#: assets/templates/assets/admin_user_assets.html:18 -#: assets/templates/assets/admin_user_detail.html:18 -#: assets/templates/assets/cmd_filter_detail.html:19 -#: assets/templates/assets/cmd_filter_rule_list.html:19 -#: assets/templates/assets/domain_detail.html:18 -#: assets/templates/assets/domain_gateway_list.html:20 -#: assets/templates/assets/system_user_asset.html:18 -#: assets/templates/assets/system_user_detail.html:18 -#: ops/templates/ops/adhoc_history.html:130 -#: ops/templates/ops/task_adhoc.html:116 -#: ops/templates/ops/task_history.html:136 -#: perms/templates/perms/asset_permission_asset.html:18 -#: perms/templates/perms/asset_permission_detail.html:18 -#: perms/templates/perms/asset_permission_user.html:18 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_asset_list.html:17 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:20 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:17 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:106 -#: xpack/plugins/change_auth_plan/views.py:83 -msgid "Detail" -msgstr "详情" - #: assets/templates/assets/admin_user_assets.html:21 #: assets/templates/assets/admin_user_detail.html:21 msgid "Assets list" @@ -1192,6 +1446,7 @@ msgstr "资产列表" #: assets/templates/assets/system_user_asset.html:66 #: assets/templates/assets/system_user_detail.html:116 #: perms/templates/perms/asset_permission_detail.html:114 +#: perms/templates/perms/remote_app_permission_detail.html:106 msgid "Quick update" msgstr "快速更新" @@ -1240,77 +1495,6 @@ msgstr "更新成功" msgid "Update failed!" msgstr "更新失败" -#: assets/templates/assets/admin_user_detail.html:24 -#: assets/templates/assets/admin_user_list.html:88 -#: assets/templates/assets/asset_detail.html:27 -#: assets/templates/assets/asset_list.html:178 -#: assets/templates/assets/cmd_filter_detail.html:29 -#: assets/templates/assets/cmd_filter_list.html:58 -#: assets/templates/assets/cmd_filter_rule_list.html:86 -#: assets/templates/assets/domain_detail.html:24 -#: assets/templates/assets/domain_detail.html:103 -#: assets/templates/assets/domain_gateway_list.html:97 -#: assets/templates/assets/domain_list.html:54 -#: assets/templates/assets/label_list.html:39 -#: assets/templates/assets/system_user_detail.html:26 -#: assets/templates/assets/system_user_list.html:93 audits/models.py:33 -#: perms/templates/perms/asset_permission_detail.html:30 -#: perms/templates/perms/asset_permission_list.html:181 -#: terminal/templates/terminal/terminal_detail.html:16 -#: terminal/templates/terminal/terminal_list.html:72 -#: users/templates/users/user_detail.html:25 -#: users/templates/users/user_group_detail.html:28 -#: users/templates/users/user_group_list.html:45 -#: users/templates/users/user_list.html:83 -#: users/templates/users/user_list.html:86 -#: users/templates/users/user_profile.html:177 -#: users/templates/users/user_profile.html:187 -#: users/templates/users/user_profile.html:196 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:29 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:55 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:23 -#: xpack/plugins/cloud/templates/cloud/account_list.html:39 -#: xpack/plugins/orgs/templates/orgs/org_detail.html:25 -#: xpack/plugins/orgs/templates/orgs/org_list.html:87 -msgid "Update" -msgstr "更新" - -#: assets/templates/assets/admin_user_detail.html:28 -#: assets/templates/assets/admin_user_list.html:89 -#: assets/templates/assets/asset_detail.html:31 -#: assets/templates/assets/asset_list.html:179 -#: assets/templates/assets/cmd_filter_detail.html:33 -#: assets/templates/assets/cmd_filter_list.html:59 -#: assets/templates/assets/cmd_filter_rule_list.html:87 -#: assets/templates/assets/domain_detail.html:28 -#: assets/templates/assets/domain_detail.html:104 -#: assets/templates/assets/domain_gateway_list.html:98 -#: assets/templates/assets/domain_list.html:55 -#: assets/templates/assets/label_list.html:40 -#: assets/templates/assets/system_user_detail.html:30 -#: assets/templates/assets/system_user_list.html:94 audits/models.py:34 -#: ops/templates/ops/task_list.html:64 -#: perms/templates/perms/asset_permission_detail.html:34 -#: perms/templates/perms/asset_permission_list.html:182 -#: settings/templates/settings/terminal_setting.html:90 -#: settings/templates/settings/terminal_setting.html:112 -#: terminal/templates/terminal/terminal_list.html:74 -#: users/templates/users/user_detail.html:30 -#: users/templates/users/user_group_detail.html:32 -#: users/templates/users/user_group_list.html:47 -#: users/templates/users/user_list.html:91 -#: users/templates/users/user_list.html:95 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:33 -#: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:57 -#: xpack/plugins/cloud/templates/cloud/account_detail.html:27 -#: xpack/plugins/cloud/templates/cloud/account_list.html:41 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:30 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:55 -#: xpack/plugins/orgs/templates/orgs/org_detail.html:29 -#: xpack/plugins/orgs/templates/orgs/org_list.html:89 -msgid "Delete" -msgstr "删除" - #: assets/templates/assets/admin_user_detail.html:83 msgid "Replace node assets admin user with this" msgstr "替换资产的管理员" @@ -1405,10 +1589,13 @@ msgid "Date joined" msgstr "创建日期" #: assets/templates/assets/asset_detail.html:154 -#: assets/templates/assets/user_asset_list.html:46 perms/models.py:54 -#: perms/models.py:108 +#: assets/templates/assets/user_asset_list.html:46 +#: perms/models/asset_permission.py:59 perms/models/asset_permission.py:113 +#: perms/models/remote_app_permission.py:37 #: perms/templates/perms/asset_permission_create_update.html:55 #: perms/templates/perms/asset_permission_detail.html:120 +#: perms/templates/perms/remote_app_permission_create_update.html:54 +#: perms/templates/perms/remote_app_permission_detail.html:112 #: terminal/templates/terminal/terminal_list.html:34 #: users/templates/users/_select_user_modal.html:18 #: users/templates/users/user_detail.html:144 @@ -1783,10 +1970,6 @@ msgstr "删除系统用户" msgid "System Users Deleting failed." msgstr "系统用户删除失败" -#: assets/templates/assets/user_asset_list.html:100 perms/const.py:19 -msgid "Connect" -msgstr "连接" - #: assets/views/admin_user.py:30 msgid "Admin user list" msgstr "管理用户列表" @@ -2009,9 +2192,11 @@ msgstr "登录日期" #: ops/templates/ops/adhoc_history.html:52 #: ops/templates/ops/adhoc_history_detail.html:61 #: ops/templates/ops/command_execution_list.html:66 -#: ops/templates/ops/task_history.html:58 perms/models.py:55 -#: perms/templates/perms/asset_permission_detail.html:86 terminal/models.py:165 -#: terminal/templates/terminal/session_list.html:78 +#: ops/templates/ops/task_history.html:58 perms/models/asset_permission.py:60 +#: perms/models/remote_app_permission.py:38 +#: perms/templates/perms/asset_permission_detail.html:86 +#: perms/templates/perms/remote_app_permission_detail.html:78 +#: terminal/models.py:165 terminal/templates/terminal/session_list.html:78 #: xpack/plugins/change_auth_plan/models.py:246 #: xpack/plugins/change_auth_plan/models.py:416 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_execution_list.html:59 @@ -2021,6 +2206,7 @@ msgstr "开始日期" #: audits/templates/audits/login_log_list.html:28 #: perms/templates/perms/asset_permission_user.html:88 +#: perms/templates/perms/remote_app_permission_user.html:87 msgid "Select user" msgstr "选择用户" @@ -2071,23 +2257,23 @@ msgid "Datetime" msgstr "日期" #: audits/views.py:85 audits/views.py:129 audits/views.py:165 -#: audits/views.py:209 audits/views.py:241 templates/_nav.html:72 +#: audits/views.py:209 audits/views.py:241 templates/_nav.html:83 msgid "Audits" msgstr "日志审计" -#: audits/views.py:86 templates/_nav.html:76 +#: audits/views.py:86 templates/_nav.html:87 msgid "FTP log" msgstr "FTP日志" -#: audits/views.py:130 templates/_nav.html:77 +#: audits/views.py:130 templates/_nav.html:88 msgid "Operate log" msgstr "操作日志" -#: audits/views.py:166 templates/_nav.html:78 +#: audits/views.py:166 templates/_nav.html:89 msgid "Password change log" msgstr "改密日志" -#: audits/views.py:210 templates/_nav.html:75 +#: audits/views.py:210 templates/_nav.html:86 msgid "Login log" msgstr "登录日志" @@ -2712,7 +2898,7 @@ msgstr "更新任务内容: {}" msgid "Ops" msgstr "作业中心" -#: ops/views/adhoc.py:45 templates/_nav.html:66 +#: ops/views/adhoc.py:45 templates/_nav.html:77 msgid "Task list" msgstr "任务列表" @@ -2724,7 +2910,7 @@ msgstr "执行历史" msgid "Command execution list" msgstr "命令执行列表" -#: ops/views/command.py:69 templates/_nav_user.html:9 +#: ops/views/command.py:69 templates/_nav_user.html:21 msgid "Command execution" msgstr "命令执行" @@ -2744,46 +2930,59 @@ msgstr "上传文件" msgid "Download file" msgstr "下载文件" -#: perms/forms.py:39 perms/models.py:49 perms/models.py:106 +#: perms/forms/asset_permission.py:43 perms/forms/remote_app_permission.py:34 +#: perms/models/asset_permission.py:54 perms/models/asset_permission.py:111 +#: perms/models/remote_app_permission.py:35 #: perms/templates/perms/asset_permission_list.html:55 #: perms/templates/perms/asset_permission_list.html:75 -#: perms/templates/perms/asset_permission_list.html:122 templates/_nav.html:14 -#: users/forms.py:253 users/models/group.py:26 users/models/user.py:67 -#: users/templates/users/_select_user_modal.html:16 +#: perms/templates/perms/asset_permission_list.html:122 +#: perms/templates/perms/remote_app_permission_list.html:16 +#: templates/_nav.html:14 users/forms.py:253 users/models/group.py:26 +#: users/models/user.py:67 users/templates/users/_select_user_modal.html:16 #: users/templates/users/user_detail.html:213 #: users/templates/users/user_list.html:26 #: xpack/plugins/orgs/templates/orgs/org_list.html:15 msgid "User group" msgstr "用户组" -#: perms/forms.py:58 +#: perms/forms/asset_permission.py:62 msgid "" "Tips: The RDP protocol does not support separate controls for uploading or " "downloading files" msgstr "提示:RDP 协议不支持单独控制上传或下载文件" -#: perms/forms.py:68 +#: perms/forms/asset_permission.py:72 perms/forms/remote_app_permission.py:47 msgid "User or group at least one required" msgstr "用户和用户组至少选一个" -#: perms/forms.py:77 +#: perms/forms/asset_permission.py:81 msgid "Asset or group at least one required" msgstr "资产和节点至少选一个" -#: perms/models.py:56 perms/models.py:109 +#: perms/models/asset_permission.py:61 perms/models/asset_permission.py:114 +#: perms/models/remote_app_permission.py:39 #: perms/templates/perms/asset_permission_detail.html:90 +#: perms/templates/perms/remote_app_permission_detail.html:82 #: users/models/user.py:99 users/templates/users/user_detail.html:107 #: users/templates/users/user_profile.html:116 msgid "Date expired" msgstr "失效日期" -#: perms/models.py:65 perms/models.py:118 templates/_nav.html:34 +#: perms/models/asset_permission.py:70 perms/models/asset_permission.py:123 +#: templates/_nav.html:42 msgid "Asset permission" msgstr "资产授权" +#: perms/models/remote_app_permission.py:48 templates/_nav.html:45 +msgid "RemoteApp permission" +msgstr "远程应用授权" + #: perms/templates/perms/asset_permission_asset.html:22 #: perms/templates/perms/asset_permission_detail.html:22 #: perms/templates/perms/asset_permission_user.html:22 +#: perms/templates/perms/remote_app_permission_detail.html:22 +#: perms/templates/perms/remote_app_permission_remote_app.html:21 +#: perms/templates/perms/remote_app_permission_user.html:21 msgid "Users and user groups" msgstr "用户或用户组" @@ -2804,6 +3003,9 @@ msgstr "添加资产" #: perms/templates/perms/asset_permission_detail.html:157 #: perms/templates/perms/asset_permission_user.html:97 #: perms/templates/perms/asset_permission_user.html:125 +#: perms/templates/perms/remote_app_permission_remote_app.html:96 +#: perms/templates/perms/remote_app_permission_user.html:96 +#: perms/templates/perms/remote_app_permission_user.html:124 #: settings/templates/settings/terminal_setting.html:95 #: settings/templates/settings/terminal_setting.html:117 #: users/templates/users/user_group_detail.html:95 @@ -2824,17 +3026,20 @@ msgid "Join" msgstr "加入" #: perms/templates/perms/asset_permission_create_update.html:61 +#: perms/templates/perms/remote_app_permission_create_update.html:60 msgid "Validity period" msgstr "有效期" #: perms/templates/perms/asset_permission_detail.html:66 +#: perms/templates/perms/remote_app_permission_detail.html:66 #: xpack/plugins/license/templates/license/license_detail.html:76 msgid "User count" msgstr "用户数量" #: perms/templates/perms/asset_permission_detail.html:70 +#: perms/templates/perms/remote_app_permission_detail.html:70 msgid "User group count" -msgstr "用户组列表" +msgstr "用户组数量" #: perms/templates/perms/asset_permission_detail.html:74 #: xpack/plugins/license/templates/license/license_detail.html:72 @@ -2854,11 +3059,13 @@ msgid "Select system users" msgstr "选择系统用户" #: perms/templates/perms/asset_permission_list.html:46 +#: perms/templates/perms/remote_app_permission_list.html:6 msgid "Create permission" msgstr "创建授权规则" #: perms/templates/perms/asset_permission_list.html:59 #: perms/templates/perms/asset_permission_list.html:73 +#: perms/templates/perms/remote_app_permission_list.html:18 #: users/templates/users/user_list.html:28 xpack/plugins/cloud/models.py:53 #: xpack/plugins/cloud/templates/cloud/account_detail.html:58 #: xpack/plugins/cloud/templates/cloud/account_list.html:14 @@ -2866,6 +3073,7 @@ msgid "Validity" msgstr "有效" #: perms/templates/perms/asset_permission_user.html:35 +#: perms/templates/perms/remote_app_permission_user.html:34 msgid "User list of " msgstr "用户列表" @@ -2878,35 +3086,95 @@ msgid "Add user group to asset permission" msgstr "添加用户组" #: perms/templates/perms/asset_permission_user.html:116 +#: perms/templates/perms/remote_app_permission_user.html:115 msgid "Select user groups" msgstr "选择用户组" -#: perms/views.py:24 perms/views.py:56 perms/views.py:71 perms/views.py:86 -#: perms/views.py:121 perms/views.py:153 templates/_nav.html:31 +#: perms/templates/perms/remote_app_permission_detail.html:74 +msgid "RemoteApp count" +msgstr "远程应用数量" + +#: perms/templates/perms/remote_app_permission_remote_app.html:34 +msgid "RemoteApp list of " +msgstr "远程应用列表" + +#: perms/templates/perms/remote_app_permission_remote_app.html:79 +msgid "Add RemoteApp to this permission" +msgstr "添加远程应用" + +#: perms/templates/perms/remote_app_permission_remote_app.html:87 +msgid "Select RemoteApp" +msgstr "选择远程应用" + +#: perms/templates/perms/remote_app_permission_user.html:79 +msgid "Add user to this permission" +msgstr "添加用户" + +#: perms/templates/perms/remote_app_permission_user.html:107 +msgid "Add user group to this permission" +msgstr "添加用户组" + +#: perms/views/asset_permission.py:33 perms/views/asset_permission.py:65 +#: perms/views/asset_permission.py:80 perms/views/asset_permission.py:95 +#: perms/views/asset_permission.py:130 perms/views/asset_permission.py:162 +#: perms/views/remote_app_permission.py:33 +#: perms/views/remote_app_permission.py:48 +#: perms/views/remote_app_permission.py:63 +#: perms/views/remote_app_permission.py:76 +#: perms/views/remote_app_permission.py:102 +#: perms/views/remote_app_permission.py:138 templates/_nav.html:39 #: xpack/plugins/orgs/templates/orgs/org_list.html:21 msgid "Perms" msgstr "权限管理" -#: perms/views.py:25 +#: perms/views/asset_permission.py:34 msgid "Asset permission list" msgstr "资产授权列表" -#: perms/views.py:57 +#: perms/views/asset_permission.py:66 msgid "Create asset permission" msgstr "创建权限规则" -#: perms/views.py:72 perms/views.py:87 +#: perms/views/asset_permission.py:81 msgid "Update asset permission" msgstr "更新资产授权" -#: perms/views.py:122 +#: perms/views/asset_permission.py:96 +msgid "Asset permission detail" +msgstr "资产授权详情" + +#: perms/views/asset_permission.py:131 msgid "Asset permission user list" msgstr "资产授权用户列表" -#: perms/views.py:154 +#: perms/views/asset_permission.py:163 msgid "Asset permission asset list" msgstr "资产授权资产列表" +#: perms/views/remote_app_permission.py:34 +msgid "RemoteApp permission list" +msgstr "远程应用授权列表" + +#: perms/views/remote_app_permission.py:49 +msgid "Create RemoteApp permission" +msgstr "创建远程应用授权规则" + +#: perms/views/remote_app_permission.py:64 +msgid "Update RemoteApp permission" +msgstr "更新远程应用授权规则" + +#: perms/views/remote_app_permission.py:77 +msgid "RemoteApp permission detail" +msgstr "远程应用授权详情" + +#: perms/views/remote_app_permission.py:103 +msgid "RemoteApp permission user list" +msgstr "远程应用授权用户列表" + +#: perms/views/remote_app_permission.py:139 +msgid "RemoteApp permission RemoteApp list" +msgstr "远程应用授权远程应用列表" + #: settings/api.py:26 msgid "Test mail sent to {}, please check" msgstr "邮件已经发送{}, 请检查" @@ -3376,7 +3644,7 @@ msgstr "在ou:{}中没有匹配条目" #: settings/views.py:18 settings/views.py:44 settings/views.py:70 #: settings/views.py:99 settings/views.py:126 settings/views.py:138 -#: settings/views.py:151 templates/_nav.html:107 +#: settings/views.py:151 templates/_nav.html:118 msgid "Settings" msgstr "系统设置" @@ -3405,7 +3673,7 @@ msgstr "文档" msgid "Commercial support" msgstr "商业支持" -#: templates/_header_bar.html:89 templates/_nav_user.html:14 users/forms.py:121 +#: templates/_header_bar.html:89 templates/_nav_user.html:26 users/forms.py:121 #: users/templates/users/_user.html:43 #: users/templates/users/first_login.html:39 #: users/templates/users/user_password_update.html:40 @@ -3508,57 +3776,65 @@ msgstr "用户列表" msgid "Command filters" msgstr "命令过滤" -#: templates/_nav.html:40 +#: templates/_nav.html:32 +msgid "Applications" +msgstr "应用管理" + +#: templates/_nav.html:51 msgid "Sessions" msgstr "会话管理" -#: templates/_nav.html:43 +#: templates/_nav.html:54 msgid "Session online" msgstr "在线会话" -#: templates/_nav.html:44 +#: templates/_nav.html:55 msgid "Session offline" msgstr "历史会话" -#: templates/_nav.html:45 +#: templates/_nav.html:56 msgid "Commands" msgstr "命令记录" -#: templates/_nav.html:48 templates/_nav_user.html:19 +#: templates/_nav.html:59 templates/_nav_user.html:31 msgid "Web terminal" msgstr "Web终端" -#: templates/_nav.html:53 templates/_nav_user.html:24 +#: templates/_nav.html:64 templates/_nav_user.html:36 msgid "File manager" msgstr "文件管理" -#: templates/_nav.html:57 terminal/views/command.py:50 +#: templates/_nav.html:68 terminal/views/command.py:50 #: terminal/views/session.py:75 terminal/views/session.py:93 #: terminal/views/session.py:115 terminal/views/terminal.py:31 #: terminal/views/terminal.py:46 terminal/views/terminal.py:58 msgid "Terminal" msgstr "终端管理" -#: templates/_nav.html:63 +#: templates/_nav.html:74 msgid "Job Center" msgstr "作业中心" -#: templates/_nav.html:67 templates/_nav.html:79 +#: templates/_nav.html:78 templates/_nav.html:90 msgid "Batch command" msgstr "批量命令" -#: templates/_nav.html:85 +#: templates/_nav.html:96 msgid "XPack" msgstr "" -#: templates/_nav.html:93 xpack/plugins/cloud/views.py:26 +#: templates/_nav.html:104 xpack/plugins/cloud/views.py:26 msgid "Account list" msgstr "账户列表" -#: templates/_nav.html:94 +#: templates/_nav.html:105 msgid "Sync instance" msgstr "同步实例" +#: templates/_nav_user.html:9 +msgid "My Applications" +msgstr "我的应用" + #: templates/_pagination.html:59 msgid "" "Displays the results of items _START_ to _END_; A total of _TOTAL_ entries" @@ -5452,6 +5728,9 @@ msgstr "创建组织" msgid "Update org" msgstr "更新组织" +#~ msgid "MFA Confirm" +#~ msgstr "确认" + #~ msgid "Monitor" #~ msgstr "监控" @@ -5501,24 +5780,6 @@ msgstr "更新组织" #~ msgid "Invalid private key" #~ msgstr "ssh密钥不合法" -#, fuzzy -#~| msgid "CPU count" -#~ msgid "Cpu count" -#~ msgstr "CPU数量" - -#~ msgid "Login Jumpserver" -#~ msgstr "登录 Jumpserver" - -#, fuzzy -#~| msgid "Delete succeed" -#~ msgid "Delete success!" -#~ msgstr "删除成功" - -#, fuzzy -#~| msgid "Username does not exist" -#~ msgid "This license does not exist!" -#~ msgstr "用户名不存在" - #~ msgid "Valid" #~ msgstr "账户状态" @@ -5540,11 +5801,6 @@ msgstr "更新组织" #~ msgid "Date finished" #~ msgstr "结束日期" -#, fuzzy -#~| msgid "Audits" -#~ msgid "Audit" -#~ msgstr "日志审计" - #~ msgid "User id" #~ msgstr "用户" @@ -5554,11 +5810,6 @@ msgstr "更新组织" #~ msgid "Start" #~ msgstr "开始" -#, fuzzy -#~| msgid "Update setting successfully" -#~ msgid "Update setting successfully, please restart program" -#~ msgstr "更新设置成功" - #~ msgid "User login settings" #~ msgstr "用户登录设置" diff --git a/apps/perms/api/__init__.py b/apps/perms/api/__init__.py index e90e0262c..aebfb2d33 100644 --- a/apps/perms/api/__init__.py +++ b/apps/perms/api/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # -from .permission import * +from .asset_permission import * from .user_permission import * from .user_group_permission import * +from .remote_app_permission import * diff --git a/apps/perms/api/permission.py b/apps/perms/api/asset_permission.py similarity index 100% rename from apps/perms/api/permission.py rename to apps/perms/api/asset_permission.py diff --git a/apps/perms/api/remote_app_permission.py b/apps/perms/api/remote_app_permission.py new file mode 100644 index 000000000..d75e80b8f --- /dev/null +++ b/apps/perms/api/remote_app_permission.py @@ -0,0 +1,101 @@ +# coding: utf-8 +# + + +from rest_framework import viewsets, generics +from rest_framework.pagination import LimitOffsetPagination +from rest_framework.views import Response + +from common.permissions import IsOrgAdmin + +from ..models import RemoteAppPermission +from ..serializers import ( + RemoteAppPermissionSerializer, + RemoteAppPermissionUpdateUserSerializer, + RemoteAppPermissionUpdateRemoteAppSerializer, +) + + +__all__ = [ + 'RemoteAppPermissionViewSet', + 'RemoteAppPermissionAddUserApi', 'RemoteAppPermissionAddRemoteAppApi', + 'RemoteAppPermissionRemoveUserApi', 'RemoteAppPermissionRemoveRemoteAppApi', +] + + +class RemoteAppPermissionViewSet(viewsets.ModelViewSet): + filter_fields = ('name', ) + search_fields = filter_fields + queryset = RemoteAppPermission.objects.all() + serializer_class = RemoteAppPermissionSerializer + pagination_class = LimitOffsetPagination + permission_classes = (IsOrgAdmin,) + + +class RemoteAppPermissionAddUserApi(generics.RetrieveUpdateAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = RemoteAppPermissionUpdateUserSerializer + queryset = RemoteAppPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + users = serializer.validated_data.get('users') + if users: + perm.users.add(*tuple(users)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class RemoteAppPermissionRemoveUserApi(generics.RetrieveUpdateAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = RemoteAppPermissionUpdateUserSerializer + queryset = RemoteAppPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + users = serializer.validated_data.get('users') + if users: + perm.users.remove(*tuple(users)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class RemoteAppPermissionAddRemoteAppApi(generics.RetrieveUpdateAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = RemoteAppPermissionUpdateRemoteAppSerializer + queryset = RemoteAppPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + remote_apps = serializer.validated_data.get('remote_apps') + if remote_apps: + perm.remote_apps.add(*tuple(remote_apps)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + + +class RemoteAppPermissionRemoveRemoteAppApi(generics.RetrieveUpdateAPIView): + permission_classes = (IsOrgAdmin,) + serializer_class = RemoteAppPermissionUpdateRemoteAppSerializer + queryset = RemoteAppPermission.objects.all() + + def update(self, request, *args, **kwargs): + perm = self.get_object() + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + remote_apps = serializer.validated_data.get('remote_apps') + if remote_apps: + perm.remote_apps.remove(*tuple(remote_apps)) + return Response({"msg": "ok"}) + else: + return Response({"error": serializer.errors}) + diff --git a/apps/perms/api/user_group_permission.py b/apps/perms/api/user_group_permission.py index 82b71bb63..4e5c8acd9 100644 --- a/apps/perms/api/user_group_permission.py +++ b/apps/perms/api/user_group_permission.py @@ -10,10 +10,12 @@ from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser from common.tree import TreeNodeSerializer from orgs.utils import set_to_root_org from ..utils import ( - AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node + AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node, + RemoteAppPermissionUtil, ) from ..hands import ( - AssetGrantedSerializer, UserGroup, Node, NodeSerializer + AssetGrantedSerializer, UserGroup, Node, NodeSerializer, + RemoteAppSerializer, ) from .. import serializers @@ -22,6 +24,7 @@ __all__ = [ 'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi', 'UserGroupGrantedNodesWithAssetsApi', 'UserGroupGrantedNodeAssetsApi', 'UserGroupGrantedNodesWithAssetsAsTreeApi', + 'UserGroupGrantedRemoteAppsApi', ] @@ -138,3 +141,20 @@ class UserGroupGrantedNodeAssetsApi(ListAPIView): for asset, system_users in assets.items(): asset.system_users_granted = system_users return assets + + +# RemoteApp permission + +class UserGroupGrantedRemoteAppsApi(ListAPIView): + permission_classes = (IsOrgAdmin, ) + serializer_class = RemoteAppSerializer + + def get_queryset(self): + queryset = [] + user_group_id = self.kwargs.get('pk') + if not user_group_id: + return queryset + user_group = get_object_or_404(UserGroup, id=user_group_id) + util = RemoteAppPermissionUtil(user_group) + queryset = util.get_remote_apps() + return queryset diff --git a/apps/perms/api/user_permission.py b/apps/perms/api/user_permission.py index 8d1a42c26..7c934340e 100644 --- a/apps/perms/api/user_permission.py +++ b/apps/perms/api/user_permission.py @@ -17,14 +17,15 @@ from common.utils import get_logger from orgs.utils import set_to_root_org from ..utils import ( AssetPermissionUtil, parse_asset_to_tree_node, parse_node_to_tree_node, - check_system_user_action + check_system_user_action, RemoteAppPermissionUtil, + construct_remote_apps_tree_root, parse_remote_app_to_tree_node, ) from ..hands import ( - AssetGrantedSerializer, User, Asset, Node, - SystemUser, NodeSerializer + User, Asset, Node, SystemUser, RemoteApp, AssetGrantedSerializer, + NodeSerializer, RemoteAppSerializer, ) from .. import serializers -from ..mixins import AssetsFilterMixin +from ..mixins import AssetsFilterMixin, RemoteAppFilterMixin from ..models import Action logger = get_logger(__name__) @@ -34,6 +35,8 @@ __all__ = [ 'UserGrantedNodesWithAssetsApi', 'UserGrantedNodeAssetsApi', 'ValidateUserAssetPermissionApi', 'UserGrantedNodeChildrenApi', 'UserGrantedNodesWithAssetsAsTreeApi', 'GetUserAssetPermissionActionsApi', + 'UserGrantedRemoteAppsApi', 'ValidateUserRemoteAppPermissionApi', + 'UserGrantedRemoteAppsAsTreeApi', ] @@ -447,3 +450,78 @@ class GetUserAssetPermissionActionsApi(UserPermissionCacheMixin, APIView): actions = [action.name for action in getattr(_su, 'actions', [])] return Response({'actions': actions}, status=200) + + +# RemoteApp permission + +class UserGrantedRemoteAppsApi(RemoteAppFilterMixin, ListAPIView): + permission_classes = (IsOrgAdminOrAppUser,) + serializer_class = RemoteAppSerializer + pagination_class = LimitOffsetPagination + + def get_object(self): + user_id = self.kwargs.get('pk', '') + if user_id: + user = get_object_or_404(User, id=user_id) + else: + user = self.request.user + return user + + def get_queryset(self): + util = RemoteAppPermissionUtil(self.get_object()) + queryset = util.get_remote_apps() + queryset = list(queryset) + return queryset + + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() + + +class UserGrantedRemoteAppsAsTreeApi(ListAPIView): + serializer_class = TreeNodeSerializer + permission_classes = (IsOrgAdminOrAppUser,) + + def get_object(self): + user_id = self.kwargs.get('pk', '') + if not user_id: + user = self.request.user + else: + user = get_object_or_404(User, id=user_id) + return user + + def get_queryset(self): + queryset = [] + tree_root = construct_remote_apps_tree_root() + queryset.append(tree_root) + + util = RemoteAppPermissionUtil(self.get_object()) + remote_apps = util.get_remote_apps() + for remote_app in remote_apps: + node = parse_remote_app_to_tree_node(tree_root, remote_app) + queryset.append(node) + + queryset = sorted(queryset) + return queryset + + def get_permissions(self): + if self.kwargs.get('pk') is None: + self.permission_classes = (IsValidUser,) + return super().get_permissions() + + +class ValidateUserRemoteAppPermissionApi(APIView): + + def get(self, request, *args, **kwargs): + user_id = request.query_params.get('user_id', '') + remote_app_id = request.query_params.get('remote_app_id', '') + user = get_object_or_404(User, id=user_id) + remote_app = get_object_or_404(RemoteApp, id=remote_app_id) + + util = RemoteAppPermissionUtil(user) + remote_apps = util.get_remote_apps() + if remote_app not in remote_apps: + return Response({'msg': False}, status=403) + + return Response({'msg': True}, status=200) diff --git a/apps/perms/forms/__init__.py b/apps/perms/forms/__init__.py new file mode 100644 index 000000000..129901afc --- /dev/null +++ b/apps/perms/forms/__init__.py @@ -0,0 +1,5 @@ +# coding: utf-8 +# + +from .asset_permission import * +from .remote_app_permission import * diff --git a/apps/perms/forms.py b/apps/perms/forms/asset_permission.py similarity index 97% rename from apps/perms/forms.py rename to apps/perms/forms/asset_permission.py index 35d8a2528..81845fb77 100644 --- a/apps/perms/forms.py +++ b/apps/perms/forms/asset_permission.py @@ -6,9 +6,13 @@ from django.utils.translation import ugettext_lazy as _ from orgs.mixins import OrgModelForm from orgs.utils import current_org -from .models import AssetPermission +from perms.models import AssetPermission from assets.models import Asset +__all__ = [ + 'AssetPermissionForm', +] + class AssetPermissionForm(OrgModelForm): def __init__(self, *args, **kwargs): diff --git a/apps/perms/forms/remote_app_permission.py b/apps/perms/forms/remote_app_permission.py new file mode 100644 index 000000000..2e0cc1b66 --- /dev/null +++ b/apps/perms/forms/remote_app_permission.py @@ -0,0 +1,49 @@ +# coding: utf-8 +# + +from django.utils.translation import ugettext as _ +from django import forms +from orgs.mixins import OrgModelForm +from orgs.utils import current_org + +from ..models import RemoteAppPermission + + +__all__ = [ + 'RemoteAppPermissionCreateUpdateForm', +] + + +class RemoteAppPermissionCreateUpdateForm(OrgModelForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + users_field = self.fields.get('users') + if hasattr(users_field, 'queryset'): + users_field.queryset = current_org.get_org_users() + + class Meta: + model = RemoteAppPermission + exclude = ( + 'id', 'date_created', 'created_by', 'org_id' + ) + widgets = { + 'users': forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('User')} + ), + 'user_groups': forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('User group')} + ), + 'remote_apps': forms.SelectMultiple( + attrs={'class': 'select2', 'data-placeholder': _('RemoteApp')} + ) + } + + def clean_user_groups(self): + users = self.cleaned_data.get('users') + user_groups = self.cleaned_data.get('user_groups') + + if not users and not user_groups: + raise forms.ValidationError( + _("User or group at least one required") + ) + return self.cleaned_data['user_groups'] diff --git a/apps/perms/hands.py b/apps/perms/hands.py index 56a60cba7..2a208fefa 100644 --- a/apps/perms/hands.py +++ b/apps/perms/hands.py @@ -3,8 +3,11 @@ from common.permissions import AdminUserRequiredMixin from users.models import User, UserGroup -from assets.models import Asset, SystemUser, Node -from assets.serializers import AssetGrantedSerializer, NodeSerializer +from assets.models import Asset, SystemUser, Node, RemoteApp +from assets.serializers import ( + AssetGrantedSerializer, NodeSerializer +) +from applications.serializers import RemoteAppSerializer diff --git a/apps/perms/migrations/0005_auto_20190520_1904.py b/apps/perms/migrations/0005_auto_20190520_1904.py new file mode 100644 index 000000000..48c579201 --- /dev/null +++ b/apps/perms/migrations/0005_auto_20190520_1904.py @@ -0,0 +1,45 @@ +# Generated by Django 2.1.7 on 2019-05-20 11:04 + +import common.utils.django +from django.conf import settings +from django.db import migrations, models +import django.utils.timezone +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('applications', '0001_initial'), + ('users', '0019_auto_20190304_1459'), + ('perms', '0004_assetpermission_actions'), + ] + + operations = [ + migrations.CreateModel( + name='RemoteAppPermission', + fields=[ + ('org_id', models.CharField(blank=True, db_index=True, default='', max_length=36, verbose_name='Organization')), + ('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=128, verbose_name='Name')), + ('is_active', models.BooleanField(default=True, verbose_name='Active')), + ('date_start', models.DateTimeField(db_index=True, default=django.utils.timezone.now, verbose_name='Date start')), + ('date_expired', models.DateTimeField(db_index=True, default=common.utils.django.date_expired_default, verbose_name='Date expired')), + ('created_by', models.CharField(blank=True, max_length=128, verbose_name='Created by')), + ('date_created', models.DateTimeField(auto_now_add=True, verbose_name='Date created')), + ('comment', models.TextField(blank=True, verbose_name='Comment')), + ('remote_apps', models.ManyToManyField(blank=True, related_name='remote_app_permissions', to='applications.RemoteApp', verbose_name='RemoteApp')), + ('user_groups', models.ManyToManyField(blank=True, related_name='remote_app_permissions', to='users.UserGroup', verbose_name='User group')), + ('users', models.ManyToManyField(blank=True, related_name='remote_app_permissions', to=settings.AUTH_USER_MODEL, verbose_name='User')), + ], + options={ + 'verbose_name': 'RemoteApp permission', + 'ordering': ('name',), + }, + ), + migrations.AlterUniqueTogether( + name='remoteapppermission', + unique_together={('org_id', 'name')}, + ), + ] diff --git a/apps/perms/mixins.py b/apps/perms/mixins.py index e41c0529b..3adaa6e5b 100644 --- a/apps/perms/mixins.py +++ b/apps/perms/mixins.py @@ -2,6 +2,11 @@ # +__all__ = [ + 'AssetsFilterMixin', 'RemoteAppFilterMixin', +] + + class AssetsFilterMixin(object): """ 对资产进行过滤(查询,排序) @@ -34,3 +39,38 @@ class AssetsFilterMixin(object): queryset = sort_assets(queryset, order_by=order_by, reverse=reverse) return queryset + + +class RemoteAppFilterMixin(object): + """ + 对RemoteApp进行过滤(查询,排序) + """ + + def filter_queryset(self, queryset): + queryset = self.search_remote_apps(queryset) + queryset = self.sort_remote_apps(queryset) + return queryset + + def search_remote_apps(self, queryset): + value = self.request.query_params.get('search') + if not value: + return queryset + queryset = [ + remote_app for remote_app in queryset if value in remote_app.name + ] + return queryset + + def sort_remote_apps(self, queryset): + order_by = self.request.query_params.get('order') + if not order_by: + order_by = 'name' + if order_by.startswith('-'): + order_by = order_by.lstrip('-') + reverse = True + else: + reverse = False + + queryset = sorted( + queryset, key=lambda x: getattr(x, order_by), reverse=reverse + ) + return queryset diff --git a/apps/perms/models/__init__.py b/apps/perms/models/__init__.py new file mode 100644 index 000000000..129901afc --- /dev/null +++ b/apps/perms/models/__init__.py @@ -0,0 +1,5 @@ +# coding: utf-8 +# + +from .asset_permission import * +from .remote_app_permission import * diff --git a/apps/perms/models.py b/apps/perms/models/asset_permission.py similarity index 97% rename from apps/perms/models.py rename to apps/perms/models/asset_permission.py index c524c4f58..ca917d69d 100644 --- a/apps/perms/models.py +++ b/apps/perms/models/asset_permission.py @@ -7,7 +7,12 @@ from django.utils import timezone from common.utils import date_expired_default, set_or_append_attr_bulk from orgs.mixins import OrgModelMixin, OrgManager -from .const import PERMS_ACTION_NAME_CHOICES, PERMS_ACTION_NAME_ALL +from perms.const import PERMS_ACTION_NAME_CHOICES, PERMS_ACTION_NAME_ALL + + +__all__ = [ + 'Action', 'AssetPermission', 'NodePermission', +] class Action(models.Model): diff --git a/apps/perms/models/remote_app_permission.py b/apps/perms/models/remote_app_permission.py new file mode 100644 index 000000000..7b29c8d20 --- /dev/null +++ b/apps/perms/models/remote_app_permission.py @@ -0,0 +1,75 @@ +# coding: utf-8 +# + +import uuid +from django.db import models +from django.utils import timezone +from django.utils.translation import ugettext_lazy as _ + +from orgs.mixins import OrgModelMixin, OrgManager +from common.utils import date_expired_default, set_or_append_attr_bulk + +__all__ = [ + 'RemoteAppPermission', +] + + +class RemoteAppPermissionQuerySet(models.QuerySet): + def active(self): + return self.filter(is_active=True) + + def valid(self): + return self.active().filter(date_start__lt=timezone.now())\ + .filter(date_expired__gt=timezone.now()) + + +class RemoteAppPermissionManager(OrgManager): + def valid(self): + return self.get_queryset().valid() + + +class RemoteAppPermission(OrgModelMixin): + id = models.UUIDField(default=uuid.uuid4, primary_key=True) + name = models.CharField(max_length=128, verbose_name=_('Name')) + users = models.ManyToManyField('users.User', related_name='remote_app_permissions', blank=True, verbose_name=_("User")) + user_groups = models.ManyToManyField('users.UserGroup', related_name='remote_app_permissions', blank=True, verbose_name=_("User group")) + remote_apps = models.ManyToManyField('applications.RemoteApp', related_name='remote_app_permissions', blank=True, verbose_name=_("RemoteApp")) + is_active = models.BooleanField(default=True, verbose_name=_('Active')) + date_start = models.DateTimeField(default=timezone.now, db_index=True, verbose_name=_("Date start")) + date_expired = models.DateTimeField(default=date_expired_default, db_index=True, verbose_name=_('Date expired')) + created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by')) + date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created')) + comment = models.TextField(verbose_name=_('Comment'), blank=True) + + objects = RemoteAppPermissionManager.from_queryset(RemoteAppPermissionQuerySet)() + + class Meta: + unique_together = [('org_id', 'name')] + verbose_name = _('RemoteApp permission') + ordering = ('name',) + + def __str__(self): + return self.name + + @property + def is_expired(self): + if self.date_expired > timezone.now() > self.date_start: + return False + return True + + @property + def is_valid(self): + if not self.is_expired and self.is_active: + return True + return False + + def get_all_users(self): + users = set(self.users.all()) + for group in self.user_groups.all(): + _users = group.users.all() + set_or_append_attr_bulk(_users, 'inherit', group.name) + users.update(set(_users)) + return users + + def get_all_remote_apps(self): + return set(self.remote_apps.all()) diff --git a/apps/perms/serializers/__init__.py b/apps/perms/serializers/__init__.py new file mode 100644 index 000000000..129901afc --- /dev/null +++ b/apps/perms/serializers/__init__.py @@ -0,0 +1,5 @@ +# coding: utf-8 +# + +from .asset_permission import * +from .remote_app_permission import * diff --git a/apps/perms/serializers.py b/apps/perms/serializers/asset_permission.py similarity index 97% rename from apps/perms/serializers.py rename to apps/perms/serializers/asset_permission.py index 01c5a077a..a1eec6710 100644 --- a/apps/perms/serializers.py +++ b/apps/perms/serializers/asset_permission.py @@ -4,7 +4,7 @@ from rest_framework import serializers from common.fields import StringManyToManyField -from .models import AssetPermission, Action +from perms.models import AssetPermission, Action from assets.models import Node, Asset, SystemUser from assets.serializers import AssetGrantedSerializer @@ -13,7 +13,7 @@ __all__ = [ 'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer', 'AssetPermissionNodeSerializer', 'GrantedNodeSerializer', 'GrantedAssetSerializer', 'GrantedSystemUserSerializer', - 'ActionSerializer', + 'ActionSerializer', 'NodeGrantedSerializer', ] diff --git a/apps/perms/serializers/remote_app_permission.py b/apps/perms/serializers/remote_app_permission.py new file mode 100644 index 000000000..bb95d910c --- /dev/null +++ b/apps/perms/serializers/remote_app_permission.py @@ -0,0 +1,36 @@ +# coding: utf-8 +# + +from rest_framework import serializers + +from ..models import RemoteAppPermission + + +__all__ = [ + 'RemoteAppPermissionSerializer', + 'RemoteAppPermissionUpdateUserSerializer', + 'RemoteAppPermissionUpdateRemoteAppSerializer', +] + + +class RemoteAppPermissionSerializer(serializers.ModelSerializer): + class Meta: + model = RemoteAppPermission + fields = [ + 'id', 'name', 'users', 'user_groups', 'remote_apps', 'comment', + 'is_active', 'date_start', 'date_expired', 'is_valid', + 'created_by', 'date_created', 'org_id' + ] + read_only_fields = ['created_by', 'date_created'] + + +class RemoteAppPermissionUpdateUserSerializer(serializers.ModelSerializer): + class Meta: + model = RemoteAppPermission + fields = ['id', 'users'] + + +class RemoteAppPermissionUpdateRemoteAppSerializer(serializers.ModelSerializer): + class Meta: + model = RemoteAppPermission + fields = ['id', 'remote_apps'] diff --git a/apps/perms/templates/perms/remote_app_permission_create_update.html b/apps/perms/templates/perms/remote_app_permission_create_update.html new file mode 100644 index 000000000..3d6154991 --- /dev/null +++ b/apps/perms/templates/perms/remote_app_permission_create_update.html @@ -0,0 +1,120 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap3 %} +{% block custom_head_css_js %} + + + +{% endblock %} + +{% block content %} +
+
+
+
+
+
{{ action }}
+ +
+
+
+ {% if form.non_field_errors %} +
+ {{ form.non_field_errors }} +
+ {% endif %} + {% csrf_token %} + +

{% trans 'Basic' %}

+ {% bootstrap_field form.name layout="horizontal" %} +
+ +

{% trans 'User' %}

+ {% bootstrap_field form.users layout="horizontal" %} + {% bootstrap_field form.user_groups layout="horizontal" %} +
+ +

{% trans 'RemoteApp' %}

+ {% bootstrap_field form.remote_apps layout="horizontal" %} +
+ +

{% trans 'Other' %}

+
+ +
+ {{ form.is_active }} +
+
+
+ +
+
+ + {% if form.errors %} + + to + + {% else %} + + to + + {% endif %} +
+ {{ form.date_expired.errors }} + {{ form.date_start.errors }} +
+
+ + {% bootstrap_field form.comment layout="horizontal" %} + +
+
+ + +
+
+ +
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + + + + + + +{% endblock %} \ No newline at end of file diff --git a/apps/perms/templates/perms/remote_app_permission_detail.html b/apps/perms/templates/perms/remote_app_permission_detail.html new file mode 100644 index 000000000..98bc6633e --- /dev/null +++ b/apps/perms/templates/perms/remote_app_permission_detail.html @@ -0,0 +1,169 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ object.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Name' %}:{{ object.name }}
{% trans 'User count' %}:{{ object.users.count }}
{% trans 'User group count' %}:{{ object.user_groups.count }}
{% trans 'RemoteApp count' %}:{{ object.remote_apps.count }}
{% trans 'Date start' %}:{{ object.date_start }}
{% trans 'Date expired' %}:{{ object.date_expired }}
{% trans 'Date created' %}:{{ object.date_created }}
{% trans 'Created by' %}:{{ object.created_by }}
{% trans 'Comment' %}:{{ object.comment }}
+
+
+
+ +
+
+
+ {% trans 'Quick update' %} +
+
+ + + + + + + +
{% trans 'Active' %} : +
+
+ + +
+
+
+
+
+ +
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/perms/templates/perms/remote_app_permission_list.html b/apps/perms/templates/perms/remote_app_permission_list.html new file mode 100644 index 000000000..8f1681781 --- /dev/null +++ b/apps/perms/templates/perms/remote_app_permission_list.html @@ -0,0 +1,93 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block table_search %}{% endblock %} +{% block table_container %} + + + + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'User' %}{% trans 'User group' %}{% trans 'RemoteApp' %}{% trans 'Validity' %}{% trans 'Action' %}
+{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/perms/templates/perms/remote_app_permission_remote_app.html b/apps/perms/templates/perms/remote_app_permission_remote_app.html new file mode 100644 index 000000000..63d395941 --- /dev/null +++ b/apps/perms/templates/perms/remote_app_permission_remote_app.html @@ -0,0 +1,164 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {% trans 'RemoteApp list of ' %} {{ remote_app_permission.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + {% for remote_app in object_list %} + + + + + + {% endfor %} + +
{% trans 'Name' %}{% trans 'Type' %}
{{ remote_app.name }}{{ remote_app.get_type_display }} + +
+
+ {% include '_pagination.html' %} +
+
+
+
+
+
+
+ {% trans 'Add RemoteApp to this permission' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+
+
+
+
+ +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/perms/templates/perms/remote_app_permission_user.html b/apps/perms/templates/perms/remote_app_permission_user.html new file mode 100644 index 000000000..7433327c5 --- /dev/null +++ b/apps/perms/templates/perms/remote_app_permission_user.html @@ -0,0 +1,256 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} +{% block content %} +
+
+
+
+ +
+
+
+
+ {% trans 'User list of ' %} {{ remote_app_permission.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + {% for user in object_list %} + + + + + + {% endfor %} + +
{% trans 'Name' %}{% trans 'Username' %}
{{ user.name }}{{ user.username }} + +
+
+ {% include '_pagination.html' %} +
+
+
+
+
+
+
+ {% trans 'Add user to this permission' %} +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+ {% trans 'Add user group to this permission' %} +
+
+ + + + + + + + + + + + {% for user_group in remote_app_permission.user_groups.all %} + + + + + {% endfor %} + +
+ +
+ +
{{ user_group }} + +
+
+
+
+
+
+
+
+
+ +{% endblock %} +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/perms/urls/api_urls.py b/apps/perms/urls/api_urls.py index 5894d3835..48f2ace61 100644 --- a/apps/perms/urls/api_urls.py +++ b/apps/perms/urls/api_urls.py @@ -9,8 +9,9 @@ app_name = 'perms' router = routers.DefaultRouter() router.register('actions', api.ActionViewSet, 'action') router.register('asset-permissions', api.AssetPermissionViewSet, 'asset-permission') +router.register('remote-app-permissions', api.RemoteAppPermissionViewSet, 'remote-app-permission') -urlpatterns = [ +asset_permission_urlpatterns = [ # 查询某个用户授权的资产和资产组 path('user//assets/', api.UserGrantedAssetsApi.as_view(), name='user-assets'), @@ -35,7 +36,6 @@ urlpatterns = [ path('user/nodes-assets/tree/', api.UserGrantedNodesWithAssetsAsTreeApi.as_view(), name='my-nodes-assets-as-tree'), - # 查询某个用户组授权的资产和资产组 path('user-group//assets/', api.UserGroupGrantedAssetsApi.as_view(), name='user-group-assets'), @@ -72,5 +72,48 @@ urlpatterns = [ name='get-user-asset-permission-actions'), ] + +remote_app_permission_urlpatterns = [ + # 查询用户授权的RemoteApp + path('user//remote-apps/', + api.UserGrantedRemoteAppsApi.as_view(), name='user-remote-apps'), + path('user/remote-apps/', + api.UserGrantedRemoteAppsApi.as_view(), name='my-remote-apps'), + + # 获取用户授权的RemoteApp树 + path('user//remote-apps/tree/', + api.UserGrantedRemoteAppsAsTreeApi.as_view(), + name='user-remote-apps-as-tree'), + path('user/remote-apps/tree/', + api.UserGrantedRemoteAppsAsTreeApi.as_view(), + name='my-remote-apps-as-tree'), + + # 查询用户组授权的RemoteApp + path('user-group//remote-apps/', + api.UserGroupGrantedRemoteAppsApi.as_view(), + name='user-group-remote-apps'), + + # 校验用户对RemoteApp的权限 + path('remote-app-permission/user/validate/', + api.ValidateUserRemoteAppPermissionApi.as_view(), + name='validate-user-remote-app-permission'), + + # 用户和RemoteApp变更 + path('remote-app-permissions//user/add/', + api.RemoteAppPermissionAddUserApi.as_view(), + name='remote-app-permission-add-user'), + path('remote-app-permissions//user/remove/', + api.RemoteAppPermissionRemoveUserApi.as_view(), + name='remote-app-permission-remove-user'), + path('remote-app-permissions//remote-app/remove/', + api.RemoteAppPermissionRemoveRemoteAppApi.as_view(), + name='remote-app-permission-remove-remote-app'), + path('remote-app-permissions//remote-app/add/', + api.RemoteAppPermissionAddRemoteAppApi.as_view(), + name='remote-app-permission-add-remote-app'), +] + +urlpatterns = asset_permission_urlpatterns + remote_app_permission_urlpatterns + urlpatterns += router.urls diff --git a/apps/perms/urls/views_urls.py b/apps/perms/urls/views_urls.py index 8b8348d28..964025db3 100644 --- a/apps/perms/urls/views_urls.py +++ b/apps/perms/urls/views_urls.py @@ -7,6 +7,7 @@ from .. import views app_name = 'perms' urlpatterns = [ + # asset-permission path('asset-permission/', views.AssetPermissionListView.as_view(), name='asset-permission-list'), path('asset-permission/create/', views.AssetPermissionCreateView.as_view(), name='asset-permission-create'), path('asset-permission//update/', views.AssetPermissionUpdateView.as_view(), name='asset-permission-update'), @@ -14,4 +15,12 @@ urlpatterns = [ path('asset-permission//delete/', views.AssetPermissionDeleteView.as_view(), name='asset-permission-delete'), path('asset-permission//user/', views.AssetPermissionUserView.as_view(), name='asset-permission-user-list'), path('asset-permission//asset/', views.AssetPermissionAssetView.as_view(), name='asset-permission-asset-list'), + + # remote-app-permission + path('remote-app-permission/', views.RemoteAppPermissionListView.as_view(), name='remote-app-permission-list'), + path('remote-app-permission/create/', views.RemoteAppPermissionCreateView.as_view(), name='remote-app-permission-create'), + path('remote-app-permission//update/', views.RemoteAppPermissionUpdateView.as_view(), name='remote-app-permission-update'), + path('remote-app-permission//', views.RemoteAppPermissionDetailView.as_view(), name='remote-app-permission-detail'), + path('remote-app-permission//user/', views.RemoteAppPermissionUserView.as_view(), name='remote-app-permission-user-list'), + path('remote-app-permission//remote-app/', views.RemoteAppPermissionRemoteAppView.as_view(), name='remote-app-permission-remote-app-list'), ] diff --git a/apps/perms/utils/__init__.py b/apps/perms/utils/__init__.py new file mode 100644 index 000000000..129901afc --- /dev/null +++ b/apps/perms/utils/__init__.py @@ -0,0 +1,5 @@ +# coding: utf-8 +# + +from .asset_permission import * +from .remote_app_permission import * diff --git a/apps/perms/utils.py b/apps/perms/utils/asset_permission.py similarity index 98% rename from apps/perms/utils.py rename to apps/perms/utils/asset_permission.py index bd5094def..cacad1718 100644 --- a/apps/perms/utils.py +++ b/apps/perms/utils/asset_permission.py @@ -12,12 +12,19 @@ from django.conf import settings from common.utils import get_logger from common.tree import TreeNode -from .models import AssetPermission, Action -from .hands import Node +from perms.models import AssetPermission, Action +from perms.hands import Node logger = get_logger(__file__) +__all__ = [ + 'AssetPermissionUtil', 'is_obj_attr_has', 'sort_assets', + 'parse_asset_to_tree_node', 'parse_node_to_tree_node', + 'check_system_user_action', +] + + class GenerateTree: def __init__(self): """ @@ -378,7 +385,7 @@ def sort_assets(assets, order_by='hostname', reverse=False): def parse_node_to_tree_node(node): - from . import serializers + from .. import serializers name = '{} ({})'.format(node.value, node.assets_amount) node_serializer = serializers.GrantedNodeSerializer(node) data = { @@ -444,11 +451,6 @@ def parse_asset_to_tree_node(node, asset, system_users): return tree_node -# -# actions -# - - def check_system_user_action(system_user, action): """ :param system_user: SystemUser object (包含动态属性: actions) diff --git a/apps/perms/utils/remote_app_permission.py b/apps/perms/utils/remote_app_permission.py new file mode 100644 index 000000000..0f67e32dc --- /dev/null +++ b/apps/perms/utils/remote_app_permission.py @@ -0,0 +1,81 @@ +# coding: utf-8 +# + +from django.db.models import Q + +from common.tree import TreeNode + +from ..models import RemoteAppPermission + + +__all__ = [ + 'RemoteAppPermissionUtil', + 'construct_remote_apps_tree_root', + 'parse_remote_app_to_tree_node', +] + + +def get_user_remote_app_permissions(user, include_group=True): + if include_group: + groups = user.groups.all() + arg = Q(users=user) | Q(user_groups__in=groups) + else: + arg = Q(users=user) + return RemoteAppPermission.objects.all().valid().filter(arg) + + +def get_user_group_remote_app_permissions(user_group): + return RemoteAppPermission.objects.all().valid().filter( + user_groups=user_group + ) + + +class RemoteAppPermissionUtil: + get_permissions_map = { + "User": get_user_remote_app_permissions, + "UserGroup": get_user_group_remote_app_permissions, + } + + def __init__(self, obj): + self.object = obj + + @property + def permissions(self): + obj_class = self.object.__class__.__name__ + func = self.get_permissions_map[obj_class] + _permissions = func(self.object) + return _permissions + + def get_remote_apps(self): + remote_apps = set() + for perm in self.permissions: + remote_apps.update(list(perm.remote_apps.all())) + return remote_apps + + +def construct_remote_apps_tree_root(): + tree_root = { + 'id': 'ID_REMOTE_APP_ROOT', + 'name': 'RemoteApp', + 'title': 'RemoteApp', + 'pId': '', + 'open': False, + 'isParent': True, + 'iconSkin': '', + 'meta': {'type': 'remote_app'} + } + return TreeNode(**tree_root) + + +def parse_remote_app_to_tree_node(parent, remote_app): + tree_node = { + 'id': remote_app.id, + 'name': remote_app.name, + 'title': remote_app.name, + 'pId': parent.id, + 'open': False, + 'isParent': False, + 'iconSkin': 'file', + 'meta': {'type': 'remote_app'} + } + return TreeNode(**tree_node) diff --git a/apps/perms/views/__init__.py b/apps/perms/views/__init__.py new file mode 100644 index 000000000..129901afc --- /dev/null +++ b/apps/perms/views/__init__.py @@ -0,0 +1,5 @@ +# coding: utf-8 +# + +from .asset_permission import * +from .remote_app_permission import * diff --git a/apps/perms/views.py b/apps/perms/views/asset_permission.py similarity index 90% rename from apps/perms/views.py rename to apps/perms/views/asset_permission.py index 0e02b38a7..fc16b70a9 100644 --- a/apps/perms/views.py +++ b/apps/perms/views/asset_permission.py @@ -10,10 +10,19 @@ from django.conf import settings from common.permissions import AdminUserRequiredMixin from orgs.utils import current_org -from .hands import Node, Asset, SystemUser, User, UserGroup -from .models import AssetPermission, Action -from .forms import AssetPermissionForm -from .const import PERMS_ACTION_NAME_ALL +from perms.hands import Node, Asset, SystemUser, User, UserGroup +from perms.models import AssetPermission, Action +from perms.forms import AssetPermissionForm +from perms.const import PERMS_ACTION_NAME_ALL + + +__all__ = [ + 'AssetPermissionListView', 'AssetPermissionCreateView', + 'AssetPermissionUpdateView', 'AssetPermissionDetailView', + 'AssetPermissionDeleteView', 'AssetPermissionUserView', + 'AssetPermissionAssetView', + +] class AssetPermissionListView(AdminUserRequiredMixin, TemplateView): @@ -84,7 +93,7 @@ class AssetPermissionDetailView(AdminUserRequiredMixin, DetailView): def get_context_data(self, **kwargs): context = { 'app': _('Perms'), - 'action': _('Update asset permission'), + 'action': _('Asset permission detail'), 'system_users_remain': SystemUser.objects.exclude( granted_by_permissions=self.object ), diff --git a/apps/perms/views/remote_app_permission.py b/apps/perms/views/remote_app_permission.py new file mode 100644 index 000000000..f4da75ffe --- /dev/null +++ b/apps/perms/views/remote_app_permission.py @@ -0,0 +1,144 @@ +# coding: utf-8 +# + +from django.utils.translation import ugettext as _ +from django.urls import reverse_lazy +from django.views.generic import ( + TemplateView, CreateView, UpdateView, DetailView, ListView +) +from django.views.generic.edit import SingleObjectMixin +from django.conf import settings + +from common.permissions import AdminUserRequiredMixin +from orgs.utils import current_org +from users.models import UserGroup +from assets.models import RemoteApp + +from ..models import RemoteAppPermission +from ..forms import RemoteAppPermissionCreateUpdateForm + + +__all__ = [ + 'RemoteAppPermissionListView', 'RemoteAppPermissionCreateView', + 'RemoteAppPermissionUpdateView', 'RemoteAppPermissionDetailView', + 'RemoteAppPermissionUserView', 'RemoteAppPermissionRemoteAppView' +] + + +class RemoteAppPermissionListView(AdminUserRequiredMixin, TemplateView): + template_name = 'perms/remote_app_permission_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('RemoteApp permission list'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class RemoteAppPermissionCreateView(AdminUserRequiredMixin, CreateView): + template_name = 'perms/remote_app_permission_create_update.html' + model = RemoteAppPermission + form_class = RemoteAppPermissionCreateUpdateForm + success_url = reverse_lazy('perms:remote-app-permission-list') + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('Create RemoteApp permission'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class RemoteAppPermissionUpdateView(AdminUserRequiredMixin, UpdateView): + template_name = 'perms/remote_app_permission_create_update.html' + model = RemoteAppPermission + form_class = RemoteAppPermissionCreateUpdateForm + success_url = reverse_lazy('perms:remote-app-permission-list') + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('Update RemoteApp permission') + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class RemoteAppPermissionDetailView(AdminUserRequiredMixin, DetailView): + template_name = 'perms/remote_app_permission_detail.html' + model = RemoteAppPermission + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('RemoteApp permission detail'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class RemoteAppPermissionUserView(AdminUserRequiredMixin, + SingleObjectMixin, + ListView): + template_name = 'perms/remote_app_permission_user.html' + context_object_name = 'remote_app_permission' + paginate_by = settings.DISPLAY_PER_PAGE + object = None + + def get(self, request, *args, **kwargs): + self.object = self.get_object( + queryset=RemoteAppPermission.objects.all()) + return super().get(request, *args, **kwargs) + + def get_queryset(self): + queryset = list(self.object.get_all_users()) + return queryset + + def get_context_data(self, **kwargs): + context = { + 'app': _('Perms'), + 'action': _('RemoteApp permission user list'), + 'users_remain': current_org.get_org_users().exclude( + remote_app_permissions=self.object + ), + 'user_groups_remain': UserGroup.objects.exclude( + remote_app_permissions=self.object + ) + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class RemoteAppPermissionRemoteAppView(AdminUserRequiredMixin, + SingleObjectMixin, + ListView): + template_name = 'perms/remote_app_permission_remote_app.html' + context_object_name = 'remote_app_permission' + paginate_by = settings.DISPLAY_PER_PAGE + object = None + + def get(self, request, *args, **kwargs): + self.object = self.get_object( + queryset=RemoteAppPermission.objects.all() + ) + return super().get(request, *args, **kwargs) + + def get_queryset(self): + queryset = list(self.object.get_all_remote_apps()) + return queryset + + def get_context_data(self, **kwargs): + remote_app_granted = self.get_queryset() + remote_app_remain = RemoteApp.objects.exclude( + id__in=[a.id for a in remote_app_granted]) + context = { + 'app': _('Perms'), + 'action': _('RemoteApp permission RemoteApp list'), + 'remote_app_remain': remote_app_remain + } + kwargs.update(context) + return super().get_context_data(**kwargs) + diff --git a/apps/templates/_nav.html b/apps/templates/_nav.html index 5c3124f8e..c24a7acb4 100644 --- a/apps/templates/_nav.html +++ b/apps/templates/_nav.html @@ -27,12 +27,23 @@
  • {% trans 'Command filters' %}
  • +
  • + + {% trans 'Applications' %} + + +
  • {% trans 'Perms' %}
  • diff --git a/apps/templates/_nav_user.html b/apps/templates/_nav_user.html index 151ed124e..5412dc37d 100644 --- a/apps/templates/_nav_user.html +++ b/apps/templates/_nav_user.html @@ -4,6 +4,18 @@ {% trans 'My assets' %}
  • +
  • + + {% trans 'My Applications' %} + + +
  • {% trans 'Command execution' %}