Merge pull request #7866 from jumpserver/dev

v2.20.0 rc4
pull/7919/head
Jiangjie.Bai 2022-03-15 20:54:40 +08:00 committed by GitHub
commit 166745baf6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 167 additions and 109 deletions

View File

@ -8,7 +8,6 @@ WORKDIR /opt/jumpserver
ADD . .
RUN cd utils && bash -ixeu build.sh
# 构建运行时环境
FROM python:3.8-slim
ARG PIP_MIRROR=https://pypi.douban.com/simple
ENV PIP_MIRROR=$PIP_MIRROR
@ -17,38 +16,66 @@ ENV PIP_JMS_MIRROR=$PIP_JMS_MIRROR
WORKDIR /opt/jumpserver
COPY ./requirements/deb_requirements.txt ./requirements/deb_requirements.txt
ARG BUILD_DEPENDENCIES=" \
g++ \
make \
pkg-config"
ARG DEPENDENCIES=" \
default-libmysqlclient-dev \
freetds-dev \
libpq-dev \
libffi-dev \
libldap2-dev \
libsasl2-dev \
libxml2-dev \
libxmlsec1-dev \
libxmlsec1-openssl \
libaio-dev \
sshpass"
ARG TOOLS=" \
curl \
default-mysql-client \
iproute2 \
iputils-ping \
locales \
procps \
redis-tools \
telnet \
vim \
wget"
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \
&& sed -i 's/security.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list \
&& apt update \
&& apt -y install telnet iproute2 redis-tools default-mysql-client vim wget curl locales procps \
&& apt -y install $(cat requirements/deb_requirements.txt) \
&& rm -rf /var/lib/apt/lists/* \
&& apt -y install ${BUILD_DEPENDENCIES} \
&& apt -y install ${DEPENDENCIES} \
&& apt -y install ${TOOLS} \
&& localedef -c -f UTF-8 -i zh_CN zh_CN.UTF-8 \
&& cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& sed -i "s@# alias l@alias l@g" ~/.bashrc \
&& echo "set mouse-=a" > ~/.vimrc
COPY ./requirements/requirements.txt ./requirements/requirements.txt
RUN pip install --upgrade pip==20.2.4 setuptools==49.6.0 wheel==0.34.2 -i ${PIP_MIRROR} \
&& pip install --no-cache-dir $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
&& pip install --no-cache-dir -r requirements/requirements.txt -i ${PIP_MIRROR} \
&& rm -rf ~/.cache/pip
COPY --from=stage-build /opt/jumpserver/release/jumpserver /opt/jumpserver
RUN mkdir -p /root/.ssh/ \
&& mkdir -p /root/.ssh/ \
&& echo "Host *\n\tStrictHostKeyChecking no\n\tUserKnownHostsFile /dev/null" > /root/.ssh/config \
&& sed -i "s@# alias l@alias l@g" ~/.bashrc \
&& echo "set mouse-=a" > ~/.vimrc \
&& rm -rf /var/lib/apt/lists/* \
&& mv /bin/sh /bin/sh.bak \
&& ln -s /bin/bash /bin/sh
RUN mkdir -p /opt/jumpserver/oracle/ \
&& wget https://download.jumpserver.org/public/instantclient-basiclite-linux.x64-21.1.0.0.0.tar > /dev/null \
&& wget https://download.jumpserver.org/public/instantclient-basiclite-linux.x64-21.1.0.0.0.tar \
&& tar xf instantclient-basiclite-linux.x64-21.1.0.0.0.tar -C /opt/jumpserver/oracle/ \
&& echo "/opt/jumpserver/oracle/instantclient_21_1" > /etc/ld.so.conf.d/oracle-instantclient.conf \
&& ldconfig \
&& rm -f instantclient-basiclite-linux.x64-21.1.0.0.0.tar
RUN echo > config.yml
COPY --from=stage-build /opt/jumpserver/release/jumpserver /opt/jumpserver
RUN echo > config.yml \
&& pip install --upgrade pip==20.2.4 setuptools==49.6.0 wheel==0.34.2 -i ${PIP_MIRROR} \
&& pip install --no-cache-dir $(grep -E 'jms|jumpserver' requirements/requirements.txt) -i ${PIP_JMS_MIRROR} \
&& pip install --no-cache-dir -r requirements/requirements.txt -i ${PIP_MIRROR} \
&& rm -rf ~/.cache/pip
VOLUME /opt/jumpserver/data
VOLUME /opt/jumpserver/logs

View File

@ -13,13 +13,17 @@ class AppCategory(models.TextChoices):
def get_label(cls, category):
return dict(cls.choices).get(category, '')
@classmethod
def is_xpack(cls, category):
return category in ['remote_app']
class AppType(models.TextChoices):
# db category
mysql = 'mysql', 'MySQL'
mariadb = 'mariadb', 'MariaDB'
oracle = 'oracle', 'Oracle'
pgsql = 'postgresql', 'PostgreSQL'
mariadb = 'mariadb', 'MariaDB'
sqlserver = 'sqlserver', 'SQLServer'
redis = 'redis', 'Redis'
mongodb = 'mongodb', 'MongoDB'
@ -37,9 +41,13 @@ class AppType(models.TextChoices):
def category_types_mapper(cls):
return {
AppCategory.db: [
cls.mysql, cls.oracle, cls.pgsql, cls.mariadb, cls.sqlserver, cls.redis, cls.mongodb
cls.mysql, cls.oracle, cls.pgsql, cls.mariadb,
cls.sqlserver, cls.redis, cls.mongodb
],
AppCategory.remote_app: [
cls.chrome, cls.mysql_workbench,
cls.vmware_client, cls.custom
],
AppCategory.remote_app: [cls.chrome, cls.mysql_workbench, cls.vmware_client, cls.custom],
AppCategory.cloud: [cls.k8s]
}
@ -66,3 +74,12 @@ class AppType(models.TextChoices):
@classmethod
def cloud_types(cls):
return [tp.value for tp in cls.category_types_mapper()[AppCategory.cloud]]
@classmethod
def is_xpack(cls, tp):
tp_category_mapper = cls.type_category_mapper()
category = tp_category_mapper[tp]
if AppCategory.is_xpack(category):
return True
return tp in ['oracle', 'postgresql', 'sqlserver']

View File

@ -3,6 +3,7 @@ from urllib.parse import urlencode, parse_qsl
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from orgs.mixins.models import OrgModelMixin
from common.mixins import CommonModelMixin
@ -79,6 +80,8 @@ class ApplicationTreeNodeMixin:
nodes = []
categories = const.AppType.category_types_mapper().keys()
for category in categories:
if not settings.XPACK_ENABLED and const.AppCategory.is_xpack(category):
continue
i = cls.create_tree_id(pid, 'category', category.value)
node = cls.create_choice_node(
category, i, pid=pid, tp='category',
@ -97,6 +100,8 @@ class ApplicationTreeNodeMixin:
type_category_mapper = const.AppType.type_category_mapper()
types = const.AppType.type_category_mapper().keys()
for tp in types:
if not settings.XPACK_ENABLED and const.AppType.is_xpack(tp):
continue
category = type_category_mapper.get(tp)
pid = cls.create_tree_id(pid, 'category', category.value)
i = cls.create_tree_id(pid, 'type', tp.value)
@ -155,6 +160,8 @@ class ApplicationTreeNodeMixin:
# 应用的节点
for app in queryset:
if not settings.XPACK_ENABLED and const.AppType.is_xpack(app.type):
continue
node = app.as_tree_node(root_node.id)
tree_nodes.append(node)
return tree_nodes

View File

@ -131,6 +131,9 @@ class CommandExecutionHostRelationViewSet(OrgRelationMixin, OrgBulkModelViewSet)
]
search_fields = ('asset__hostname', )
http_method_names = ['options', 'get']
rbac_perms = {
'GET': 'audits.view_commandexecution'
}
def get_queryset(self):
queryset = super().get_queryset()

View File

@ -44,13 +44,13 @@ class MFASms(BaseMFA):
return settings.SMS_ENABLED
def get_enable_url(self) -> str:
return '/ui/#/users/profile/?activeTab=ProfileUpdate'
return '/ui/#/profile/setting?activeTab=ProfileUpdate'
def can_disable(self) -> bool:
return True
def disable(self):
return '/ui/#/users/profile/?activeTab=ProfileUpdate'
return '/ui/#/profile/setting?activeTab=ProfileUpdate'
@staticmethod
def help_text_of_enable():
@ -61,4 +61,4 @@ class MFASms(BaseMFA):
return _("Clear phone number to disable")
def get_disable_url(self) -> str:
return '/ui/#/users/profile/?activeTab=ProfileUpdate'
return '/ui/#/profile/setting?activeTab=ProfileUpdate'

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:675f93d2cc6b2049fdafc7f6b70edb8f73bbe132de9b91e98f2ec7acb2e89620
size 104134
oid sha256:a8c1155ea28b70a0eb06aa39ab6ae04619cd30d02f59698fadaa6068d91a7900
size 104348

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-03-14 15:58+0800\n"
"POT-Creation-Date: 2022-03-15 19:46+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n"
@ -305,10 +305,14 @@ msgstr "版本"
msgid "Application account"
msgstr "应用账号"
#: applications/models/account.py:26 applications/models/account.py:27
#: applications/models/account.py:26
msgid "Can view application account secret"
msgstr "可以查看应用账号密码"
#: applications/models/account.py:27
msgid "Can change application account secret"
msgstr "可以查看应用账号密码"
#: applications/models/application.py:204
#: applications/serializers/application.py:99 assets/models/label.py:21
#: perms/models/application_permission.py:21
@ -1379,7 +1383,7 @@ msgstr "日志审计"
#: audits/models.py:27 audits/models.py:57
#: authentication/templates/authentication/_access_key_modal.html:65
#: rbac/tree.py:273 users/templates/users/user_asset_permission.html:128
#: rbac/tree.py:158 users/templates/users/user_asset_permission.html:128
#: users/templates/users/user_database_app_permission.html:111
msgid "Delete"
msgstr "删除"
@ -1433,11 +1437,11 @@ msgstr "文件管理"
#: audits/models.py:55
#: authentication/templates/authentication/_access_key_modal.html:22
#: rbac/tree.py:270
#: rbac/tree.py:155
msgid "Create"
msgstr "创建"
#: audits/models.py:56 rbac/tree.py:272 templates/_csv_import_export.html:18
#: audits/models.py:56 rbac/tree.py:157 templates/_csv_import_export.html:18
#: templates/_csv_update_modal.html:6
#: users/templates/users/user_asset_permission.html:127
#: users/templates/users/user_database_app_permission.html:110
@ -2117,7 +2121,7 @@ msgstr "显示"
#: authentication/templates/authentication/_access_key_modal.html:66
#: settings/serializers/security.py:39 users/models/user.py:469
#: users/serializers/profile.py:111 users/templates/users/mfa_setting.html:60
#: users/serializers/profile.py:111 users/templates/users/mfa_setting.html:61
#: users/templates/users/user_verify_mfa.html:36
msgid "Disable"
msgstr "禁用"
@ -2125,7 +2129,7 @@ msgstr "禁用"
#: authentication/templates/authentication/_access_key_modal.html:67
#: users/models/user.py:470 users/serializers/profile.py:112
#: users/templates/users/mfa_setting.html:26
#: users/templates/users/mfa_setting.html:67
#: users/templates/users/mfa_setting.html:68
msgid "Enable"
msgstr "启用"
@ -2679,7 +2683,7 @@ msgstr "站内信"
msgid "Waiting task start"
msgstr "等待任务开始"
#: ops/api/command.py:61
#: ops/api/command.py:56
msgid "Not has host {} permission"
msgstr "没有该主机 {} 权限"
@ -2767,7 +2771,7 @@ msgstr "创建者"
#: ops/models/adhoc.py:243
msgid "AdHoc"
msgstr ""
msgstr "任务各版本"
#: ops/models/adhoc.py:252
msgid "Task display"
@ -2800,7 +2804,7 @@ msgstr "汇总"
#: ops/models/adhoc.py:339
msgid "AdHoc execution"
msgstr "命令执行"
msgstr "任务执行历史"
#: ops/models/command.py:32
msgid "Date finished"
@ -2874,7 +2878,7 @@ msgstr "当前组织 ({}) 不能被删除"
msgid "The organization have resource ({}) cannot be deleted"
msgstr "组织存在资源 ({}) 不能被删除"
#: orgs/apps.py:7 rbac/tree.py:112
#: orgs/apps.py:7 rbac/tree.py:111
msgid "App organizations"
msgstr "组织管理"
@ -2917,11 +2921,15 @@ msgstr "可以查看授权给用户的应用"
msgid "Permed application"
msgstr "授权的应用"
#: perms/models/application_permission.py:117
#: perms/models/application_permission.py:115
msgid "Can view my apps"
msgstr "可以查看我的应用"
#: perms/models/application_permission.py:116
msgid "Can view user apps"
msgstr "可以查看用户授权的应用"
#: perms/models/application_permission.py:118
#: perms/models/application_permission.py:117
msgid "Can view usergroup apps"
msgstr "可以查看用户组授权的应用"
@ -2950,14 +2958,10 @@ msgid "Can view my assets"
msgstr "可以查看我的资产"
#: perms/models/asset_permission.py:188
msgid "Can connect my assets"
msgstr "可以连接我的资产"
#: perms/models/asset_permission.py:189
msgid "Can view user assets"
msgstr "可以查看用户授权的资产"
#: perms/models/asset_permission.py:190
#: perms/models/asset_permission.py:189
msgid "Can view usergroup assets"
msgstr "可以查看用户组授权的资产"
@ -3173,7 +3177,7 @@ msgstr "Web终端"
msgid "Can view file manager"
msgstr "文件管理"
#: rbac/models/permission.py:22
#: rbac/models/permission.py:26
msgid "Permission"
msgstr "授权"
@ -3299,15 +3303,15 @@ msgstr "我的资产"
msgid "My apps"
msgstr "我的应用"
#: rbac/tree.py:113
#: rbac/tree.py:112
msgid "Ticket comment"
msgstr "工单评论"
#: rbac/tree.py:114
#: rbac/tree.py:113
msgid "Common setting"
msgstr "一般设置"
#: rbac/tree.py:271
#: rbac/tree.py:156
msgid "View"
msgstr "查看"
@ -4962,6 +4966,10 @@ msgstr "HTTP端口"
msgid "Terminal"
msgstr "终端"
#: terminal/models/terminal.py:185
msgid "Can view terminal config"
msgstr "可以查看终端配置"
#: terminal/notifications.py:22
msgid "Sessions"
msgstr "会话管理"
@ -6799,11 +6807,11 @@ msgstr "退出页面logo"
msgid "Interface setting"
msgstr "界面设置"
#: xpack/plugins/license/api.py:41
#: xpack/plugins/license/api.py:43
msgid "License import successfully"
msgstr "许可证导入成功"
#: xpack/plugins/license/api.py:42
#: xpack/plugins/license/api.py:44
msgid "License is invalid"
msgstr "无效的许可证"
@ -6827,6 +6835,9 @@ msgstr "旗舰版"
msgid "Community edition"
msgstr "社区版"
#~ msgid "Can connect my assets"
#~ msgstr "可以连接我的资产"
#~ msgid "Can view dashboard"
#~ msgstr "仪表盘"

View File

@ -6,7 +6,6 @@ import os
from django.test import TestCase
from ops.models import Task, AdHoc
from ops.utils import run_adhoc_object
class TestRunAdHoc(TestCase):

View File

@ -22,7 +22,6 @@ from perms import serializers
logger = get_logger(__name__)
__all__ = [
'RefreshAssetPermissionCacheApi',
'UserGrantedAssetSystemUsersForAdminApi',
'ValidateUserAssetPermissionApi',
'GetUserAssetPermissionActionsApi',
@ -97,12 +96,6 @@ class ValidateUserAssetPermissionApi(APIView):
return Response(data, status=status_code)
# TODO 删除
class RefreshAssetPermissionCacheApi(RetrieveAPIView):
def retrieve(self, request, *args, **kwargs):
return Response({'msg': True}, status=200)
class UserGrantedAssetSystemUsersForAdminApi(ListAPIView):
serializer_class = serializers.AssetSystemUserSerializer
only_fields = serializers.AssetSystemUserSerializer.Meta.only_fields

View File

@ -112,7 +112,7 @@ class PermedApplication(Application):
verbose_name = _('Permed application')
default_permissions = []
permissions = [
('view_myapps', 'Can view my apps'),
('view_myapps', _('Can view my apps')),
('view_userapps', _('Can view user apps')),
('view_usergroupapps', _('Can view usergroup apps')),
]

View File

@ -12,7 +12,7 @@ class ActionsField(serializers.MultipleChoiceField):
super().__init__(*args, **kwargs)
def run_validation(self, data=empty):
data = super(ActionsField, self).run_validation()
data = super(ActionsField, self).run_validation(data)
if isinstance(data, list):
data = Action.choices_to_value(value=data)
return data

View File

@ -100,8 +100,6 @@ permission_urlpatterns = [
path('user/validate/', api.ValidateUserAssetPermissionApi.as_view(), name='validate-user-asset-permission'),
path('user/actions/', api.GetUserAssetPermissionActionsApi.as_view(), name='get-user-asset-permission-actions'),
# 刷新缓存
path('cache/refresh/', api.RefreshAssetPermissionCacheApi.as_view(), name='refresh-asset-permission-cache'),
]
asset_permission_urlpatterns = [

View File

@ -55,7 +55,7 @@ exclude_permissions = (
('ops', 'task', 'add,change', 'task'),
('ops', 'commandexecution', 'delete,change', 'commandexecution'),
('orgs', 'organizationmember', '*', '*'),
('settings', 'setting', 'add,delete', 'setting'),
('settings', 'setting', 'add,change,delete', 'setting'),
('audits', 'operatelog', 'add,delete,change', 'operatelog'),
('audits', 'passwordchangelog', 'add,change,delete', 'passwordchangelog'),
('audits', 'userloginlog', 'add,change,delete,change', 'userloginlog'),
@ -71,15 +71,16 @@ exclude_permissions = (
('xpack', 'interface', '*', '*'),
('xpack', 'license', '*', '*'),
('xpack', 'syncinstancedetail', 'add,delete,change', 'syncinstancedetail'),
('xpack', 'syncinstancetaskexecution', 'add,delete,change', 'syncinstancetaskexecution'),
('xpack', 'changeauthplanexecution', 'add,delete,change', 'changeauthplanexecution'),
('xpack', 'syncinstancetaskexecution', 'delete,change', 'syncinstancetaskexecution'),
('xpack', 'changeauthplanexecution', 'delete,change', 'changeauthplanexecution'),
('xpack', 'changeauthplantask', 'add,delete', 'changeauthplantask'),
('common', 'permission', 'add,delete,view,change', 'permission'),
('terminal', 'command', 'delete,change', 'command'),
('terminal', 'status', 'delete,change', 'status'),
('terminal', 'sessionjoinrecord', 'delete', 'sessionjoinrecord'),
('terminal', 'sessionreplay', 'add,change,delete', 'sessionreplay'),
('terminal', 'session', 'delete', 'session'),
('terminal', 'sessionsharing', 'view,add,change,delete', 'sessionsharing'),
('terminal', 'session', 'delete,share', 'session'),
('terminal', 'session', 'delete,change', 'command'),
)

View File

@ -99,7 +99,6 @@ special_pid_mapper = {
"xpack.interface": "view_setting",
"settings.change_terminal": "terminal_node",
"settings.view_setting": "view_setting",
"settings.change_setting": "view_setting",
"rbac.view_console": "view_console",
"rbac.view_audit": "view_audit",
"rbac.view_workspace": "view_workspace",
@ -151,6 +150,21 @@ def sort_nodes(node):
class PermissionTreeUtil:
get_permissions: Callable
action_mapper = {
'add': ugettext('Create'),
'view': ugettext('View'),
'change': ugettext('Update'),
'delete': ugettext('Delete')
}
action_icon = {
'add': 'add',
'view': 'view',
'change': 'change',
'delete': 'delete',
'invite': 'invite',
'match': 'match',
'remove': 'remove'
}
def __init__(self, permissions, scope, check_disabled=False):
self.permissions = self.prefetch_permissions(permissions)
@ -262,38 +276,17 @@ class PermissionTreeUtil:
nodes.append(node)
return nodes
@staticmethod
def _get_permission_name(p, content_types_name_mapper):
p: Permission
code_name = p.codename
action_mapper = {
'add': ugettext('Create'),
'view': ugettext('View'),
'change': ugettext('Update'),
'delete': ugettext('Delete')
}
name = ''
ct = ''
if 'add_' in p.codename:
name = action_mapper['add']
ct = code_name.replace('add_', '')
elif 'view_' in p.codename:
name = action_mapper['view']
ct = code_name.replace('view_', '')
elif 'change_' in p.codename:
name = action_mapper['change']
ct = code_name.replace('change_', '')
elif 'delete' in code_name:
name = action_mapper['delete']
ct = code_name.replace('delete_', '')
app_model = '%s.%s' % (p.content_type.app_label, ct)
if app_model in content_types_name_mapper:
name += content_types_name_mapper[app_model]
def _get_permission_name_icon(self, p: Permission, content_types_name_mapper: dict):
action, resource = p.codename.split('_', 1)
app_model = '%s.%s' % (p.content_type.app_label, resource)
if action in self.action_mapper and app_model in content_types_name_mapper:
action_name = self.action_mapper[action]
name = action_name + content_types_name_mapper[app_model]
else:
name = gettext(p.name)
name = name.replace('Can ', '').replace('可以', '')
return name
icon = self.action_icon.get(action, 'file')
name = name.replace('Can ', '').replace('可以', '')
return name, icon
def _create_perms_nodes(self):
permissions_id = self.permissions.values_list('id', flat=True)
@ -306,7 +299,7 @@ class PermissionTreeUtil:
if not self._check_model_xpack(model_id):
continue
# name 要特殊处理,解决 i18n 问题
name = self._get_permission_name(p, content_types_name_mapper)
name, icon = self._get_permission_name_icon(p, content_types_name_mapper)
if settings.DEBUG:
name += '[{}]'.format(p.app_label_codename)
@ -328,7 +321,7 @@ class PermissionTreeUtil:
'pId': pid,
'isParent': False,
'chkDisabled': self.check_disabled,
'iconSkin': 'file',
'iconSkin': icon,
'checked': p.id in permissions_id,
'open': False,
'meta': {

View File

@ -14,7 +14,7 @@ from .. import serializers
class AlibabaSMSTestingAPI(GenericAPIView):
serializer_class = serializers.AlibabaSMSSettingSerializer
rbac_perms = {
'POST': 'settings.change_setting'
'POST': 'settings.change_sms'
}
def post(self, request):

View File

@ -19,7 +19,7 @@ class MailTestingAPI(APIView):
serializer_class = serializers.MailTestSerializer
success_message = _("Test mail sent to {}, please check")
rbac_perms = {
'POST': 'settings.change_setting'
'POST': 'settings.change_email'
}
def post(self, request):

View File

@ -13,7 +13,7 @@ from .. import serializers
class FeiShuTestingAPI(GenericAPIView):
serializer_class = serializers.FeiShuSettingSerializer
rbac_perms = {
'POST': 'settings.change_setting'
'POST': 'settings.change_auth'
}
def post(self, request):

View File

@ -16,7 +16,7 @@ from .. import serializers
class TencentSMSTestingAPI(GenericAPIView):
serializer_class = serializers.TencentSMSSettingSerializer
rbac_perms = {
'POST': 'settings.change_setting'
'POST': 'settings.change_sms'
}
def post(self, request):

View File

@ -13,7 +13,7 @@ from .. import serializers
class WeComTestingAPI(GenericAPIView):
serializer_class = serializers.WeComSettingSerializer
rbac_perms = {
'POST': 'settings.change_setting'
'POST': 'settings.change_auth'
}
def post(self, request):

View File

@ -121,7 +121,8 @@
url: url,
method: "POST",
body: JSON.stringify(data),
success: onSuccess
success: onSuccess,
flash_message: false
})
}
</script>

View File

@ -131,7 +131,13 @@ class BaseStorageTestConnectiveMixin:
class CommandStorageTestConnectiveApi(BaseStorageTestConnectiveMixin, generics.RetrieveAPIView):
queryset = CommandStorage.objects.all()
rbac_perms = {
'retrieve': 'terminal.view_commandstorage'
}
class ReplayStorageTestConnectiveApi(BaseStorageTestConnectiveMixin, generics.RetrieveAPIView):
queryset = ReplayStorage.objects.all()
rbac_perms = {
'retrieve': 'terminal.view_replaystorage'
}

View File

@ -182,6 +182,6 @@ class Terminal(StorageMixin, TerminalStatusMixin, models.Model):
db_table = "terminal"
verbose_name = _("Terminal")
permissions = (
('view_terminalconfig', 'Can view terminal config'),
('view_terminalconfig', _('Can view terminal config')),
)

View File

@ -15,7 +15,7 @@ __all__ = ['CommentViewSet']
class CommentViewSet(mixins.CreateModelMixin, viewsets.ReadOnlyModelViewSet):
serializer_class = serializers.CommentSerializer
permission_classes = (RBACPermission| IsSwagger | IsAssignee | IsApplicant)
permission_classes = (RBACPermission, IsSwagger | IsAssignee | IsApplicant)
@lazyproperty
def ticket(self):

View File

@ -17,6 +17,7 @@ class TicketSessionRelationViewSet(CreateModelMixin, JMSGenericViewSet):
# Todo: 放到上面的 ViewSet 中
class TicketSessionApi(views.APIView):
perm_model = TicketSession
def get(self, request, *args, **kwargs):
with tmp_to_root_org():

View File

@ -49,8 +49,9 @@
<div style="height: 100%; width: 100%;">
{% for b in mfa_backends %}
<div class="row" style="padding-top: 10px">
<li class="col-sm-6" style="font-size: 14px">{{ b.display_name }}
{{ b.enable }}</li>
<li class="col-sm-6" style="font-size: 14px">
{{ b.display_name }}
</li>
<span class="col-sm-6">
{% if b.is_active %}
<button class="btn btn-warning btn-xs" style="float: right"