Commit bdcf9ba1 authored by BaiJiangJie's avatar BaiJiangJie Committed by 老广

Dev remoteapp (#3205)

* [Update] 修改RemoteApp关联的系统用户:从RemoteApp中转移到RemoteAppPermission中(未提交迁移文件)

* [Update] 修改RemoteApp关联的系统用户:提交迁移文件

* [Update] 修改RemoteApp关联的系统用户:修改迁移文件

* [Update] 修改迁移文件1

* [Update] 修改迁移文件2

* [Update] 修改迁移文件3

* [Update] 修改RemoteAppPermsUtil获取系统用户的逻辑
parent 3a8fad7c
...@@ -89,23 +89,16 @@ class RemoteAppCreateUpdateForm(RemoteAppTypeForms, OrgModelForm): ...@@ -89,23 +89,16 @@ class RemoteAppCreateUpdateForm(RemoteAppTypeForms, OrgModelForm):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
field_asset = self.fields['asset'] field_asset = self.fields['asset']
field_asset.queryset = field_asset.queryset.has_protocol('rdp') field_asset.queryset = field_asset.queryset.has_protocol('rdp')
field_system_user = self.fields['system_user']
field_system_user.queryset = field_system_user.queryset.filter(
protocol=SystemUser.PROTOCOL_RDP
)
class Meta: class Meta:
model = RemoteApp model = RemoteApp
fields = [ fields = [
'name', 'asset', 'system_user', 'type', 'path', 'comment' 'name', 'asset', 'type', 'path', 'comment'
] ]
widgets = { widgets = {
'asset': forms.Select(attrs={ 'asset': forms.Select(attrs={
'class': 'select2', 'data-placeholder': _('Asset') 'class': 'select2', 'data-placeholder': _('Asset')
}), }),
'system_user': forms.Select(attrs={
'class': 'select2', 'data-placeholder': _('System user')
})
} }
def _clean_params(self): def _clean_params(self):
......
# Generated by Django 2.1.7 on 2019-09-09 09:57
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('applications', '0001_initial'),
('perms', '0008_remoteapppermission_system_users'),
]
operations = [
migrations.RemoveField(
model_name='remoteapp',
name='system_user',
),
]
...@@ -22,10 +22,6 @@ class RemoteApp(OrgModelMixin): ...@@ -22,10 +22,6 @@ class RemoteApp(OrgModelMixin):
asset = models.ForeignKey( asset = models.ForeignKey(
'assets.Asset', on_delete=models.CASCADE, verbose_name=_('Asset') '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( type = models.CharField(
default=const.REMOTE_APP_TYPE_CHROME, default=const.REMOTE_APP_TYPE_CHROME,
choices=const.REMOTE_APP_TYPE_CHOICES, choices=const.REMOTE_APP_TYPE_CHOICES,
...@@ -80,10 +76,3 @@ class RemoteApp(OrgModelMixin): ...@@ -80,10 +76,3 @@ class RemoteApp(OrgModelMixin):
'id': self.asset.id, 'id': self.asset.id,
'hostname': self.asset.hostname 'hostname': self.asset.hostname
} }
@property
def system_user_info(self):
return {
'id': self.system_user.id,
'name': self.system_user.name
}
...@@ -73,13 +73,13 @@ class RemoteAppSerializer(BulkOrgResourceModelSerializer): ...@@ -73,13 +73,13 @@ class RemoteAppSerializer(BulkOrgResourceModelSerializer):
model = RemoteApp model = RemoteApp
list_serializer_class = AdaptedBulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = [ fields = [
'id', 'name', 'asset', 'system_user', 'type', 'path', 'params', 'id', 'name', 'asset', 'type', 'path', 'params',
'comment', 'created_by', 'date_created', 'asset_info', 'comment', 'created_by', 'date_created', 'asset_info',
'system_user_info', 'get_type_display', 'get_type_display',
] ]
read_only_fields = [ read_only_fields = [
'created_by', 'date_created', 'asset_info', 'created_by', 'date_created', 'asset_info',
'system_user_info', 'get_type_display' 'get_type_display'
] ]
...@@ -89,7 +89,7 @@ class RemoteAppConnectionInfoSerializer(serializers.ModelSerializer): ...@@ -89,7 +89,7 @@ class RemoteAppConnectionInfoSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = RemoteApp model = RemoteApp
fields = [ fields = [
'id', 'name', 'asset', 'system_user', 'parameter_remote_app', 'id', 'name', 'asset', 'parameter_remote_app',
] ]
read_only_fields = ['parameter_remote_app'] read_only_fields = ['parameter_remote_app']
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
{% csrf_token %} {% csrf_token %}
{% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.asset layout="horizontal" %} {% bootstrap_field form.asset layout="horizontal" %}
{% bootstrap_field form.system_user layout="horizontal" %}
{% bootstrap_field form.type layout="horizontal" %} {% bootstrap_field form.type layout="horizontal" %}
{% bootstrap_field form.path layout="horizontal" %} {% bootstrap_field form.path layout="horizontal" %}
......
...@@ -57,10 +57,6 @@ ...@@ -57,10 +57,6 @@
<td>{% trans 'Asset' %}:</td> <td>{% trans 'Asset' %}:</td>
<td><b><a href="{% url 'assets:asset-detail' pk=remote_app.asset.id %}">{{ remote_app.asset.hostname }}</a></b></td> <td><b><a href="{% url 'assets:asset-detail' pk=remote_app.asset.id %}">{{ remote_app.asset.hostname }}</a></b></td>
</tr> </tr>
<tr>
<td>{% trans 'System user' %}:</td>
<td><b><a href="{% url 'assets:system-user-detail' pk=remote_app.system_user.id %}">{{ remote_app.system_user.name }}</a></b></td>
</tr>
<tr> <tr>
<td>{% trans 'App type' %}:</td> <td>{% trans 'App type' %}:</td>
<td><b>{{ remote_app.get_type_display }}</b></td> <td><b>{{ remote_app.get_type_display }}</b></td>
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
<th class="text-center">{% trans 'Name' %}</th> <th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'App type' %}</th> <th class="text-center">{% trans 'App type' %}</th>
<th class="text-center">{% trans 'Asset' %}</th> <th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center">{% trans 'Comment' %}</th> <th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center">{% trans 'Action' %}</th> <th class="text-center">{% trans 'Action' %}</th>
</tr> </tr>
...@@ -47,12 +46,11 @@ function initTable() { ...@@ -47,12 +46,11 @@ function initTable() {
var detail_btn = '<a href="{% url 'assets:asset-detail' pk=DEFAULT_PK %}">' + hostname + '</a>'; var detail_btn = '<a href="{% url 'assets:asset-detail' pk=DEFAULT_PK %}">' + hostname + '</a>';
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', cellData.id)); $(td).html(detail_btn.replace('{{ DEFAULT_PK }}', cellData.id));
}}, }},
{targets: 4, createdCell: function (td, cellData, rowData) { {targets: 3, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(cellData.name); var comment = htmlEscape(cellData);
var detail_btn = '<a href="{% url 'assets:system-user-detail' pk=DEFAULT_PK %}">' + name + '</a>'; $(td).html(comment)
$(td).html(detail_btn.replace('{{ DEFAULT_PK }}', cellData.id));
}}, }},
{targets: 6, createdCell: function (td, cellData, rowData) { {targets: 5, createdCell: function (td, cellData, rowData) {
var update_btn = '<a href="{% url "applications:remote-app-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace("{{ DEFAULT_PK }}", cellData); var update_btn = '<a href="{% url "applications:remote-app-update" pk=DEFAULT_PK %}" class="btn btn-xs btn-info">{% trans "Update" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-rid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData); var del_btn = '<a class="btn btn-xs btn-danger m-l-xs btn-delete" data-rid="{{ DEFAULT_PK }}">{% trans "Delete" %}</a>'.replace('{{ DEFAULT_PK }}', cellData);
$(td).html(update_btn + del_btn) $(td).html(update_btn + del_btn)
...@@ -64,7 +62,6 @@ function initTable() { ...@@ -64,7 +62,6 @@ function initTable() {
{data: "name" }, {data: "name" },
{data: "get_type_display", orderable: false}, {data: "get_type_display", orderable: false},
{data: "asset_info", orderable: false}, {data: "asset_info", orderable: false},
{data: "system_user_info", orderable: false},
{data: "comment"}, {data: "comment"},
{data: "id", orderable: false} {data: "id", orderable: false}
], ],
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
<th class="text-center">{% trans 'Name' %}</th> <th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'App type' %}</th> <th class="text-center">{% trans 'App type' %}</th>
<th class="text-center">{% trans 'Asset' %}</th> <th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'System user' %}</th>
<th class="text-center">{% trans 'Comment' %}</th> <th class="text-center">{% trans 'Comment' %}</th>
<th class="text-center">{% trans 'Action' %}</th> <th class="text-center">{% trans 'Action' %}</th>
</tr> </tr>
...@@ -49,11 +48,7 @@ function initTable() { ...@@ -49,11 +48,7 @@ function initTable() {
var hostname = htmlEscape(cellData.hostname); var hostname = htmlEscape(cellData.hostname);
$(td).html(hostname); $(td).html(hostname);
}}, }},
{targets: 4, createdCell: function (td, cellData, rowData) { {targets: 5, createdCell: function (td, cellData, rowData) {
var name = htmlEscape(cellData.name);
$(td).html(name);
}},
{targets: 6, createdCell: function (td, cellData, rowData) {
var conn_btn = '<a href="{% url "luna-view" %}?login_to=' + cellData +'" class="btn btn-xs btn-primary">{% trans "Connect" %}</a>'.replace("{{ DEFAULT_PK }}", cellData); var conn_btn = '<a href="{% url "luna-view" %}?login_to=' + cellData +'" class="btn btn-xs btn-primary">{% trans "Connect" %}</a>'.replace("{{ DEFAULT_PK }}", cellData);
$(td).html(conn_btn) $(td).html(conn_btn)
}} }}
...@@ -64,7 +59,6 @@ function initTable() { ...@@ -64,7 +59,6 @@ function initTable() {
{data: "name"}, {data: "name"},
{data: "get_type_display", orderable: false}, {data: "get_type_display", orderable: false},
{data: "asset_info", orderable: false}, {data: "asset_info", orderable: false},
{data: "system_user_info", orderable: false},
{data: "comment", orderable: false}, {data: "comment", orderable: false},
{data: "id", orderable: false} {data: "id", orderable: false}
] ]
......
...@@ -13,9 +13,7 @@ router = BulkRouter() ...@@ -13,9 +13,7 @@ router = BulkRouter()
router.register(r'remote-apps', api.RemoteAppViewSet, 'remote-app') router.register(r'remote-apps', api.RemoteAppViewSet, 'remote-app')
urlpatterns = [ urlpatterns = [
path('remote-apps/<uuid:pk>/connection-info/', path('remote-apps/<uuid:pk>/connection-info/', api.RemoteAppConnectionInfoApi.as_view(), name='remote-app-connection-info'),
api.RemoteAppConnectionInfoApi.as_view(),
name='remote-app-connection-info')
] ]
old_version_urlpatterns = [ old_version_urlpatterns = [
re_path('(?P<resource>remote-app)/.*', capi.redirect_plural_name_api) re_path('(?P<resource>remote-app)/.*', capi.redirect_plural_name_api)
......
...@@ -9,16 +9,49 @@ from rest_framework.views import Response ...@@ -9,16 +9,49 @@ from rest_framework.views import Response
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.http import condition from django.views.decorators.http import condition
from rest_framework.generics import get_object_or_404
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from common.utils import get_logger
from assets.utils import LabelFilterMixin from assets.utils import LabelFilterMixin
from .. import const from common.permissions import IsValidUser, IsOrgAdminOrAppUser, IsOrgAdmin
from ..hands import Asset, Node, SystemUser from common.utils import get_logger
from orgs.utils import set_to_root_org
from ..hands import User, Asset, Node, SystemUser
from .. import serializers from .. import serializers
from .. import const
logger = get_logger(__name__) logger = get_logger(__name__)
__all__ = ['UserPermissionCacheMixin', 'GrantAssetsMixin', 'NodesWithUngroupMixin'] __all__ = [
'UserPermissionCacheMixin', 'GrantAssetsMixin', 'NodesWithUngroupMixin',
'UserPermissionMixin',
]
class UserPermissionMixin:
permission_classes = (IsOrgAdminOrAppUser,)
obj = None
def initial(self, *args, **kwargs):
super().initial(*args, *kwargs)
self.obj = self.get_obj()
def get(self, request, *args, **kwargs):
set_to_root_org()
return super().get(request, *args, **kwargs)
def get_obj(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_permissions(self):
if self.kwargs.get('pk') is None:
self.permission_classes = (IsValidUser,)
return super().get_permissions()
# def get_etag(request, *args, **kwargs): # def get_etag(request, *args, **kwargs):
......
...@@ -8,16 +8,16 @@ from rest_framework.generics import ( ...@@ -8,16 +8,16 @@ from rest_framework.generics import (
ListAPIView, get_object_or_404, RetrieveAPIView ListAPIView, get_object_or_404, RetrieveAPIView
) )
from common.permissions import IsValidUser, IsOrgAdminOrAppUser, IsOrgAdmin from common.permissions import IsOrgAdminOrAppUser, IsOrgAdmin
from common.tree import TreeNodeSerializer from common.tree import TreeNodeSerializer
from common.utils import get_logger from common.utils import get_logger
from orgs.utils import set_to_root_org
from ..utils import ( from ..utils import (
ParserNode, AssetPermissionUtilV2 ParserNode, AssetPermissionUtilV2
) )
from ..hands import User, Asset, Node, SystemUser, NodeSerializer from ..hands import User, Asset, Node, SystemUser, NodeSerializer
from .. import serializers from .. import serializers
from ..models import Action from ..models import Action
from .mixin import UserPermissionMixin
logger = get_logger(__name__) logger = get_logger(__name__)
...@@ -39,32 +39,6 @@ __all__ = [ ...@@ -39,32 +39,6 @@ __all__ = [
] ]
class UserPermissionMixin:
permission_classes = (IsOrgAdminOrAppUser,)
obj = None
def initial(self, *args, **kwargs):
super().initial(*args, *kwargs)
self.obj = self.get_obj()
def get(self, request, *args, **kwargs):
set_to_root_org()
return super().get(request, *args, **kwargs)
def get_obj(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_permissions(self):
if self.kwargs.get('pk') is None:
self.permission_classes = (IsValidUser,)
return super().get_permissions()
class UserAssetPermissionMixin(UserPermissionMixin): class UserAssetPermissionMixin(UserPermissionMixin):
util = None util = None
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import uuid
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from rest_framework.views import APIView, Response from rest_framework.views import APIView, Response
from rest_framework.generics import ( from rest_framework.generics import (
...@@ -12,13 +13,16 @@ from ..utils import ( ...@@ -12,13 +13,16 @@ from ..utils import (
RemoteAppPermissionUtil, construct_remote_apps_tree_root, RemoteAppPermissionUtil, construct_remote_apps_tree_root,
parse_remote_app_to_tree_node, parse_remote_app_to_tree_node,
) )
from ..hands import User, RemoteAppSerializer, UserGroup from ..hands import User, RemoteApp, RemoteAppSerializer, UserGroup, SystemUser
from ..mixins import RemoteAppFilterMixin from ..mixins import RemoteAppFilterMixin
from .mixin import UserPermissionMixin
from .. import serializers
__all__ = [ __all__ = [
'UserGrantedRemoteAppsApi', 'ValidateUserRemoteAppPermissionApi', 'UserGrantedRemoteAppsApi', 'ValidateUserRemoteAppPermissionApi',
'UserGrantedRemoteAppsAsTreeApi', 'UserGroupGrantedRemoteAppsApi', 'UserGrantedRemoteAppsAsTreeApi', 'UserGroupGrantedRemoteAppsApi',
'UserGrantedRemoteAppSystemUsersApi',
] ]
...@@ -65,18 +69,43 @@ class UserGrantedRemoteAppsAsTreeApi(UserGrantedRemoteAppsApi): ...@@ -65,18 +69,43 @@ class UserGrantedRemoteAppsAsTreeApi(UserGrantedRemoteAppsApi):
return super().get_serializer(data, many=True) return super().get_serializer(data, many=True)
class UserGrantedRemoteAppSystemUsersApi(UserPermissionMixin, ListAPIView):
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = serializers.RemoteAppSystemUserSerializer
only_fields = serializers.RemoteAppSystemUserSerializer.Meta.only_fields
def get_queryset(self):
util = RemoteAppPermissionUtil(self.obj)
remote_app_id = self.kwargs.get('remote_app_id')
remote_app = get_object_or_404(RemoteApp, id=remote_app_id)
system_users = util.get_remote_app_system_users(remote_app)
return system_users
class ValidateUserRemoteAppPermissionApi(APIView): class ValidateUserRemoteAppPermissionApi(APIView):
permission_classes = (IsOrgAdminOrAppUser,) permission_classes = (IsOrgAdminOrAppUser,)
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
user_id = request.query_params.get('user_id', '') user_id = request.query_params.get('user_id', '')
remote_app_id = request.query_params.get('remote_app_id', '') remote_app_id = request.query_params.get('remote_app_id', '')
system_id = request.query_params.get('system_user_id', '')
try:
user_id = uuid.UUID(user_id)
remote_app_id = uuid.UUID(remote_app_id)
system_id = uuid.UUID(system_id)
except ValueError:
return Response({'msg': False}, status=403)
user = get_object_or_404(User, id=user_id) user = get_object_or_404(User, id=user_id)
remote_app = get_object_or_404(RemoteApp, id=remote_app_id)
system_user = get_object_or_404(SystemUser, id=system_id)
util = RemoteAppPermissionUtil(user) util = RemoteAppPermissionUtil(user)
remote_app = util.get_remote_apps().filter(id=remote_app_id).exists() system_users = util.get_remote_app_system_users(remote_app)
if remote_app: if system_user in system_users:
return Response({'msg': True}, status=200) return Response({'msg': True}, status=200)
return Response({'msg': False}, status=403) return Response({'msg': False}, status=403)
......
...@@ -35,6 +35,9 @@ class RemoteAppPermissionCreateUpdateForm(OrgModelForm): ...@@ -35,6 +35,9 @@ class RemoteAppPermissionCreateUpdateForm(OrgModelForm):
), ),
'remote_apps': forms.SelectMultiple( 'remote_apps': forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('RemoteApp')} attrs={'class': 'select2', 'data-placeholder': _('RemoteApp')}
),
'system_users': forms.SelectMultiple(
attrs={'class': 'select2', 'data-placeholder': _('System user')}
) )
} }
......
# Generated by Django 2.1.7 on 2019-09-09 09:09
from django.db import migrations, models
from assets.models import SystemUser
def migrate_system_user_from_remote_app_to_remote_app_perms(apps, schema_editor):
remote_app_perms_model = apps.get_model("perms", "RemoteAppPermission")
db_alias = schema_editor.connection.alias
perms = remote_app_perms_model.objects.using(db_alias).all()
for perm in perms:
system_users_ids = perm.remote_apps.values_list('system_user', flat=True)
perm.system_users.set(system_users_ids)
class Migration(migrations.Migration):
dependencies = [
('assets', '0037_auto_20190724_2002'),
('perms', '0007_remove_assetpermission_actions'),
]
operations = [
migrations.AddField(
model_name='remoteapppermission',
name='system_users',
field=models.ManyToManyField(related_name='granted_by_remote_app_permissions', to='assets.SystemUser', verbose_name='System user'),
),
migrations.RunPython(
code=migrate_system_user_from_remote_app_to_remote_app_perms,
),
]
...@@ -13,6 +13,7 @@ __all__ = [ ...@@ -13,6 +13,7 @@ __all__ = [
class RemoteAppPermission(BasePermission): class RemoteAppPermission(BasePermission):
remote_apps = models.ManyToManyField('applications.RemoteApp', related_name='granted_by_permissions', blank=True, verbose_name=_("RemoteApp")) remote_apps = models.ManyToManyField('applications.RemoteApp', related_name='granted_by_permissions', blank=True, verbose_name=_("RemoteApp"))
system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_remote_app_permissions', verbose_name=_("System user"))
class Meta: class Meta:
unique_together = [('org_id', 'name')] unique_together = [('org_id', 'name')]
......
...@@ -20,8 +20,8 @@ class RemoteAppPermissionSerializer(BulkOrgResourceModelSerializer): ...@@ -20,8 +20,8 @@ class RemoteAppPermissionSerializer(BulkOrgResourceModelSerializer):
model = RemoteAppPermission model = RemoteAppPermission
list_serializer_class = AdaptedBulkListSerializer list_serializer_class = AdaptedBulkListSerializer
fields = [ fields = [
'id', 'name', 'users', 'user_groups', 'remote_apps', 'comment', 'id', 'name', 'users', 'user_groups', 'remote_apps', 'system_users',
'is_active', 'date_start', 'date_expired', 'is_valid', 'comment', 'is_active', 'date_start', 'date_expired', 'is_valid',
'created_by', 'date_created', 'created_by', 'date_created',
] ]
read_only_fields = ['created_by', 'date_created'] read_only_fields = ['created_by', 'date_created']
......
...@@ -12,6 +12,7 @@ __all__ = [ ...@@ -12,6 +12,7 @@ __all__ = [
'NodeGrantedSerializer', 'NodeGrantedSerializer',
'AssetGrantedSerializer', 'AssetGrantedSerializer',
'ActionsSerializer', 'AssetSystemUserSerializer', 'ActionsSerializer', 'AssetSystemUserSerializer',
'RemoteAppSystemUserSerializer',
] ]
...@@ -24,13 +25,22 @@ class AssetSystemUserSerializer(serializers.ModelSerializer): ...@@ -24,13 +25,22 @@ class AssetSystemUserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = SystemUser model = SystemUser
only_fields = ( only_fields = (
'id', 'name', 'username', 'priority', 'id', 'name', 'username', 'priority', 'protocol', 'login_mode',
'protocol', 'login_mode',
) )
fields = list(only_fields) + ["actions"] fields = list(only_fields) + ["actions"]
read_only_fields = fields read_only_fields = fields
class RemoteAppSystemUserSerializer(serializers.ModelSerializer):
class Meta:
model = SystemUser
only_fields = (
'id', 'name', 'username', 'priority', 'protocol', 'login_mode',
)
fields = list(only_fields)
read_only_fields = fields
class AssetGrantedSerializer(serializers.ModelSerializer): class AssetGrantedSerializer(serializers.ModelSerializer):
""" """
被授权资产的数据结构 被授权资产的数据结构
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
<h3>{% trans 'RemoteApp' %}</h3> <h3>{% trans 'RemoteApp' %}</h3>
{% bootstrap_field form.remote_apps layout="horizontal" %} {% bootstrap_field form.remote_apps layout="horizontal" %}
{% bootstrap_field form.system_users layout="horizontal" %}
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<h3>{% trans 'Other' %}</h3> <h3>{% trans 'Other' %}</h3>
...@@ -127,7 +128,7 @@ $(document).ready(function () { ...@@ -127,7 +128,7 @@ $(document).ready(function () {
the_url = '{% url "api-perms:remote-app-permission-detail" pk=object.id %}'; the_url = '{% url "api-perms:remote-app-permission-detail" pk=object.id %}';
method = "PUT"; method = "PUT";
{% endif %} {% endif %}
objectAttrsIsList(data, ['users', 'user_groups', 'remote_apps']); objectAttrsIsList(data, ['users', 'user_groups', 'remote_apps', 'system_users']);
objectAttrsIsDatetime(data, ['date_expired', 'date_start']); objectAttrsIsDatetime(data, ['date_expired', 'date_start']);
objectAttrsIsBool(data, ['is_active']); objectAttrsIsBool(data, ['is_active']);
var props = { var props = {
......
...@@ -126,7 +126,42 @@ ...@@ -126,7 +126,42 @@
</table> </table>
</div> </div>
</div> </div>
<div class="panel panel-info">
<div class="panel-heading">
<i class="fa fa-info-circle"></i> {% trans 'System user' %}
</div>
<div class="panel-body">
<table class="table" id="system-user-table">
<tbody>
<form>
<tr class="no-borders-tr">
<td colspan="2">
<select data-placeholder="{% trans 'Select system users' %}" class="select2" style="width: 100%" multiple="" tabindex="4">
{% for system_user in system_users_remain %}
<option value="{{ system_user.id }}" id="opt_{{ system_user.id }}">{{ system_user }}</option>
{% endfor %}
</select>
</td>
</tr>
<tr class="no-borders-tr">
<td colspan="2">
<button type="button" class="btn btn-info btn-small" id="btn-add-system-user">{% trans 'Add' %}</button>
</td>
</tr>
</form>
{% for system_user in object.system_users.all %}
<tr {% if forloop.counter == 1 %} class="no-borders-tr" {% endif %} >
<td ><b class="bdg-system-user" data-uid={{ system_user.id }}>{{ system_user }}</b></td>
<td>
<button class="btn btn-danger btn-xs btn-remove-user" data-uid="{{ system_user.id }}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -136,6 +171,20 @@ ...@@ -136,6 +171,20 @@
{% endblock %} {% endblock %}
{% block custom_foot_js %} {% block custom_foot_js %}
<script> <script>
jumpserver.system_users_selected = {};
function updateSystemUser(system_users) {
var the_url = "{% url 'api-perms:remote-app-permission-detail' pk=object.id %}";
var body = {
system_users: Object.assign([], system_users)
};
requestApi({
url: the_url,
body: JSON.stringify(body),
success: function () {window.location.reload()}
});
}
$(document).ready(function () { $(document).ready(function () {
$('.select2').select2() $('.select2').select2()
.on('select2:select', function(evt) { .on('select2:select', function(evt) {
...@@ -147,7 +196,36 @@ $(document).ready(function () { ...@@ -147,7 +196,36 @@ $(document).ready(function () {
delete jumpserver.system_users_selected[data.id] delete jumpserver.system_users_selected[data.id]
}) })
}) })
.on('click', '.btn-delete', function () { .on('click', '#btn-add-system-user', function () {
if (Object.keys(jumpserver.system_users_selected).length === 0) {
return false;
}
var system_users = $('.bdg-system-user').map(function() {
return $(this).data('uid');
}).get();
$.map(jumpserver.system_users_selected, function(name, index) {
system_users.push(index);
$('#opt_' + index).remove();
$('.group_edit tbody').append(
'<tr>' +
'<td><b class="bdg-system-user" data-gid="' + index + '">' + name + '</b></td>' +
'<td><button class="btn btn-danger btn-xs pull-right btn-remove-user" type="button"><i class="fa fa-minus"></i></button></td>' +
'</tr>'
)
});
updateSystemUser(system_users);
}).on('click', '.btn-remove-user', function () {
var $this = $(this);
var $tr = $this.closest('tr');
var system_users = $('.bdg-system-user').map(function() {
if ($(this).data('uid') !== $this.data('uid')){
return $(this).data('uid');
}
}).get();
updateSystemUser(system_users);
$tr.remove()
}).on('click', '.btn-delete', function () {
var $this = $(this); var $this = $(this);
var name = "{{ object.name }}"; var name = "{{ object.name }}";
var rid = "{{ object.id }}"; var rid = "{{ object.id }}";
......
...@@ -91,6 +91,10 @@ remote_app_permission_urlpatterns = [ ...@@ -91,6 +91,10 @@ remote_app_permission_urlpatterns = [
# 查询用户组授权的RemoteApp # 查询用户组授权的RemoteApp
path('user-groups/<uuid:pk>/remote-apps/', api.UserGroupGrantedRemoteAppsApi.as_view(), name='user-group-remote-apps'), path('user-groups/<uuid:pk>/remote-apps/', api.UserGroupGrantedRemoteAppsApi.as_view(), name='user-group-remote-apps'),
# RemoteApp System users
path('users/<uuid:pk>/remote-apps/<uuid:remote_app_id>/system-users/', api.UserGrantedRemoteAppSystemUsersApi.as_view(), name='user-remote-app-system-users'),
path('users/remote-apps/<uuid:remote_app_id>/system-users/', api.UserGrantedRemoteAppSystemUsersApi.as_view(), name='my-remote-app-system-users'),
# 校验用户对RemoteApp的权限 # 校验用户对RemoteApp的权限
path('remote-app-permissions/user/validate/', api.ValidateUserRemoteAppPermissionApi.as_view(), name='validate-user-remote-app-permission'), path('remote-app-permissions/user/validate/', api.ValidateUserRemoteAppPermissionApi.as_view(), name='validate-user-remote-app-permission'),
......
...@@ -7,7 +7,7 @@ from common.tree import TreeNode ...@@ -7,7 +7,7 @@ from common.tree import TreeNode
from orgs.utils import set_to_root_org from orgs.utils import set_to_root_org
from ..models import RemoteAppPermission from ..models import RemoteAppPermission
from ..hands import RemoteApp from ..hands import RemoteApp, SystemUser
__all__ = [ __all__ = [
...@@ -59,6 +59,16 @@ class RemoteAppPermissionUtil: ...@@ -59,6 +59,16 @@ class RemoteAppPermissionUtil:
) )
return remote_apps return remote_apps
def get_remote_app_system_users(self, remote_app):
queryset = self.permissions
kwargs = {"remote_apps": remote_app}
queryset = queryset.filter(**kwargs)
system_users_ids = queryset.values_list('system_users', flat=True)
system_users_ids = system_users_ids.distinct()
system_users = SystemUser.objects.filter(id__in=system_users_ids)
system_users = system_users.order_by('-priority')
return system_users
def construct_remote_apps_tree_root(): def construct_remote_apps_tree_root():
tree_root = { tree_root = {
......
...@@ -12,7 +12,7 @@ from django.conf import settings ...@@ -12,7 +12,7 @@ from django.conf import settings
from common.permissions import PermissionsMixin, IsOrgAdmin from common.permissions import PermissionsMixin, IsOrgAdmin
from orgs.utils import current_org from orgs.utils import current_org
from ..hands import RemoteApp, UserGroup from ..hands import RemoteApp, UserGroup, SystemUser
from ..models import RemoteAppPermission from ..models import RemoteAppPermission
from ..forms import RemoteAppPermissionCreateUpdateForm from ..forms import RemoteAppPermissionCreateUpdateForm
...@@ -80,6 +80,9 @@ class RemoteAppPermissionDetailView(PermissionsMixin, DetailView): ...@@ -80,6 +80,9 @@ class RemoteAppPermissionDetailView(PermissionsMixin, DetailView):
context = { context = {
'app': _('Perms'), 'app': _('Perms'),
'action': _('RemoteApp permission detail'), 'action': _('RemoteApp permission detail'),
'system_users_remain': SystemUser.objects.exclude(
granted_by_remote_app_permissions=self.object
),
} }
kwargs.update(context) kwargs.update(context)
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment