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 %}
+
+{% 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 %}
+
+
+{% 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 %}
+
+{% 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 %}
+
+{% 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 %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% 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 %}
+
+
+{% 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 }}
+
+
+
+
+
+
+ {% trans 'Name' %}
+ {% trans 'Type' %}
+
+
+
+
+ {% for remote_app in object_list %}
+
+ {{ remote_app.name }}
+ {{ remote_app.get_type_display }}
+
+
+
+
+ {% endfor %}
+
+
+
+ {% 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 }}
+
+
+
+
+
+
+ {% trans 'Name' %}
+ {% trans 'Username' %}
+
+
+
+
+ {% for user in object_list %}
+
+ {{ user.name }}
+ {{ user.username }}
+
+
+
+
+ {% endfor %}
+
+
+
+ {% 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 %}
+
+ {{ user_group }}
+
+
+
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+
+
+
+{% 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' %}