mirror of https://github.com/jumpserver/jumpserver
commit
692dd6c8c4
|
@ -107,7 +107,7 @@ class CommandExecutionViewSet(ListModelMixin, OrgGenericViewSet):
|
|||
class CommandExecutionHostRelationViewSet(OrgRelationMixin, OrgBulkModelViewSet):
|
||||
serializer_class = CommandExecutionHostsRelationSerializer
|
||||
m2m_field = CommandExecution.hosts.field
|
||||
permission_classes = (IsOrgAdmin,)
|
||||
permission_classes = [IsOrgAdmin | IsOrgAuditor]
|
||||
filter_fields = [
|
||||
'id', 'asset', 'commandexecution'
|
||||
]
|
||||
|
|
|
@ -34,16 +34,6 @@ class LoginConfirmSettingUpdateApi(UpdateAPIView):
|
|||
class TicketStatusApi(mixins.AuthMixin, APIView):
|
||||
permission_classes = ()
|
||||
|
||||
def get_ticket(self):
|
||||
from tickets.models import Ticket
|
||||
ticket_id = self.request.session.get("auth_ticket_id")
|
||||
logger.debug('Login confirm ticket id: {}'.format(ticket_id))
|
||||
if not ticket_id:
|
||||
ticket = None
|
||||
else:
|
||||
ticket = get_object_or_none(Ticket, pk=ticket_id)
|
||||
return ticket
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
try:
|
||||
self.check_user_login_confirm()
|
||||
|
|
|
@ -7,6 +7,7 @@ import time
|
|||
from django.conf import settings
|
||||
from django.contrib.auth import authenticate
|
||||
from django.shortcuts import reverse
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY
|
||||
|
||||
from common.utils import get_object_or_none, get_request_ip, get_logger
|
||||
from users.models import User
|
||||
|
@ -27,8 +28,14 @@ class AuthMixin:
|
|||
def get_user_from_session(self):
|
||||
if self.request.session.is_empty():
|
||||
raise errors.SessionEmptyError()
|
||||
if self.request.user and not self.request.user.is_anonymous:
|
||||
return self.request.user
|
||||
|
||||
if all((self.request.user,
|
||||
not self.request.user.is_anonymous,
|
||||
BACKEND_SESSION_KEY in self.request.session)):
|
||||
user = self.request.user
|
||||
user.backend = self.request.session[BACKEND_SESSION_KEY]
|
||||
return user
|
||||
|
||||
user_id = self.request.session.get('user_id')
|
||||
if not user_id:
|
||||
user = None
|
||||
|
@ -163,7 +170,7 @@ class AuthMixin:
|
|||
if not ticket_id:
|
||||
ticket = None
|
||||
else:
|
||||
ticket = get_object_or_none(Ticket, pk=ticket_id)
|
||||
ticket = Ticket.origin_objects.get(pk=ticket_id)
|
||||
return ticket
|
||||
|
||||
def get_ticket_or_create(self, confirm_setting):
|
||||
|
|
|
@ -34,7 +34,13 @@ def rsa_decrypt(cipher_text, rsa_private_key=None):
|
|||
if rsa_private_key is None:
|
||||
# rsa_private_key 为 None,可以能是API请求认证,不需要解密
|
||||
return cipher_text
|
||||
|
||||
key = RSA.importKey(rsa_private_key)
|
||||
cipher = PKCS1_v1_5.new(key)
|
||||
message = cipher.decrypt(base64.b64decode(cipher_text.encode()), 'error').decode()
|
||||
cipher_decoded = base64.b64decode(cipher_text.encode())
|
||||
# Todo: 弄明白为何要以下这么写,https://xbuba.com/questions/57035263
|
||||
if len(cipher_decoded) == 127:
|
||||
hex_fixed = '00' + cipher_decoded.hex()
|
||||
cipher_decoded = base64.b16decode(hex_fixed.upper())
|
||||
message = cipher.decrypt(cipher_decoded, b'error').decode()
|
||||
return message
|
||||
|
|
|
@ -18,6 +18,7 @@ from django.views.generic.edit import FormView
|
|||
from django.conf import settings
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
from common.const.front_urls import TICKET_DETAIL
|
||||
from common.utils import get_request_ip, get_object_or_none
|
||||
from users.utils import (
|
||||
redirect_user_first_login_or_index
|
||||
|
@ -185,7 +186,7 @@ class UserLoginWaitConfirmView(TemplateView):
|
|||
context = super().get_context_data(**kwargs)
|
||||
if ticket:
|
||||
timestamp_created = datetime.datetime.timestamp(ticket.date_created)
|
||||
ticket_detail_url = reverse('tickets:ticket-detail', kwargs={'pk': ticket_id})
|
||||
ticket_detail_url = TICKET_DETAIL.format(id=ticket_id)
|
||||
msg = _("""Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>
|
||||
Don't close this page""").format(ticket.assignees_display)
|
||||
else:
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
TICKET_DETAIL = '/ui/#/tickets/tickets/{id}'
|
|
@ -182,3 +182,9 @@ class CanUpdateDeleteUser(permissions.BasePermission):
|
|||
if request.method in ['PUT', 'PATCH']:
|
||||
return self.has_update_object_permission(request, view, obj)
|
||||
return True
|
||||
|
||||
|
||||
class IsObjectOwner(IsValidUser):
|
||||
def has_object_permission(self, request, view, obj):
|
||||
return (super().has_object_permission(request, view, obj) and
|
||||
request.user == getattr(obj, 'user', None))
|
||||
|
|
|
@ -247,7 +247,7 @@ class Config(dict):
|
|||
'HTTP_BIND_HOST': '0.0.0.0',
|
||||
'HTTP_LISTEN_PORT': 8080,
|
||||
'WS_LISTEN_PORT': 8070,
|
||||
'LOGIN_LOG_KEEP_DAYS': 90,
|
||||
'LOGIN_LOG_KEEP_DAYS': 9999,
|
||||
'TASK_LOG_KEEP_DAYS': 10,
|
||||
'ASSETS_PERM_CACHE_TIME': 3600 * 24,
|
||||
'SECURITY_MFA_VERIFY_TTL': 3600,
|
||||
|
|
|
@ -52,6 +52,7 @@ def redirect_format_api(request, *args, **kwargs):
|
|||
return JsonResponse({"msg": "Redirect url failed: {}".format(_path)}, status=404)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def redirect_old_apps_view(request, *args, **kwargs):
|
||||
path = request.get_full_path()
|
||||
if path.find('/core') != -1:
|
||||
|
|
Binary file not shown.
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-08-07 18:48+0800\n"
|
||||
"POT-Creation-Date: 2020-08-19 18:10+0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: ibuler <ibuler@qq.com>\n"
|
||||
"Language-Team: JumpServer team<ibuler@qq.com>\n"
|
||||
|
@ -17,7 +17,7 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: applications/const.py:52
|
||||
#: applications/const.py:53
|
||||
msgid "Custom"
|
||||
msgstr "自定义"
|
||||
|
||||
|
@ -27,9 +27,9 @@ msgstr "自定义"
|
|||
#: assets/models/cmd_filter.py:21 assets/models/domain.py:20
|
||||
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
|
||||
#: orgs/models.py:22 perms/models/base.py:48 settings/models.py:27
|
||||
#: terminal/models.py:26 terminal/models.py:342 terminal/models.py:374
|
||||
#: terminal/models.py:411 users/forms/profile.py:20 users/models/group.py:15
|
||||
#: users/models/user.py:489 users/templates/users/_select_user_modal.html:13
|
||||
#: terminal/models.py:27 terminal/models.py:344 terminal/models.py:376
|
||||
#: terminal/models.py:413 users/forms/profile.py:20 users/models/group.py:15
|
||||
#: users/models/user.py:491 users/templates/users/_select_user_modal.html:13
|
||||
#: users/templates/users/user_asset_permission.html:37
|
||||
#: users/templates/users/user_asset_permission.html:154
|
||||
#: users/templates/users/user_database_app_permission.html:36
|
||||
|
@ -47,7 +47,7 @@ msgid "Name"
|
|||
msgstr "名称"
|
||||
|
||||
#: applications/models/database_app.py:22 applications/models/k8s_app.py:14
|
||||
#: assets/models/cmd_filter.py:52 terminal/models.py:376 terminal/models.py:413
|
||||
#: assets/models/cmd_filter.py:52 terminal/models.py:378 terminal/models.py:415
|
||||
#: tickets/models/ticket.py:40
|
||||
#: users/templates/users/user_granted_database_app.html:35
|
||||
msgid "Type"
|
||||
|
@ -77,9 +77,9 @@ msgstr "数据库"
|
|||
#: assets/models/cmd_filter.py:57 assets/models/domain.py:21
|
||||
#: assets/models/domain.py:54 assets/models/group.py:23
|
||||
#: assets/models/label.py:23 ops/models/adhoc.py:37 orgs/models.py:25
|
||||
#: perms/models/base.py:56 settings/models.py:32 terminal/models.py:36
|
||||
#: terminal/models.py:381 terminal/models.py:418 users/models/group.py:16
|
||||
#: users/models/user.py:522 users/templates/users/user_detail.html:115
|
||||
#: perms/models/base.py:56 settings/models.py:32 terminal/models.py:37
|
||||
#: terminal/models.py:383 terminal/models.py:420 users/models/group.py:16
|
||||
#: users/models/user.py:524 users/templates/users/user_detail.html:115
|
||||
#: users/templates/users/user_granted_database_app.html:38
|
||||
#: users/templates/users/user_granted_remote_app.html:37
|
||||
#: users/templates/users/user_group_detail.html:62
|
||||
|
@ -116,11 +116,11 @@ msgstr "Kubernetes应用"
|
|||
#: applications/models/remote_app.py:23 assets/models/asset.py:352
|
||||
#: assets/models/authbook.py:26 assets/models/gathered_user.py:14
|
||||
#: assets/serializers/admin_user.py:32 assets/serializers/asset_user.py:47
|
||||
#: assets/serializers/asset_user.py:84 assets/serializers/system_user.py:44
|
||||
#: assets/serializers/system_user.py:176 audits/models.py:38
|
||||
#: assets/serializers/asset_user.py:84 assets/serializers/system_user.py:46
|
||||
#: assets/serializers/system_user.py:179 audits/models.py:38
|
||||
#: perms/forms/asset_permission.py:89 perms/models/asset_permission.py:90
|
||||
#: templates/index.html:82 terminal/backends/command/models.py:19
|
||||
#: terminal/backends/command/serializers.py:13 terminal/models.py:187
|
||||
#: terminal/backends/command/serializers.py:13 terminal/models.py:188
|
||||
#: users/templates/users/user_asset_permission.html:40
|
||||
#: users/templates/users/user_asset_permission.html:70
|
||||
#: users/templates/users/user_granted_remote_app.html:36
|
||||
|
@ -146,8 +146,8 @@ msgstr "参数"
|
|||
#: assets/models/base.py:240 assets/models/cluster.py:28
|
||||
#: assets/models/cmd_filter.py:26 assets/models/cmd_filter.py:60
|
||||
#: assets/models/group.py:21 common/db/models.py:67 common/mixins/models.py:49
|
||||
#: orgs/models.py:23 orgs/models.py:326 perms/models/base.py:54
|
||||
#: users/models/user.py:530 users/serializers/group.py:35
|
||||
#: orgs/models.py:23 orgs/models.py:389 perms/models/base.py:54
|
||||
#: users/models/user.py:532 users/serializers/group.py:35
|
||||
#: users/templates/users/user_detail.html:97
|
||||
#: xpack/plugins/change_auth_plan/models.py:81 xpack/plugins/cloud/models.py:56
|
||||
#: xpack/plugins/cloud/models.py:146 xpack/plugins/gathered_user/models.py:30
|
||||
|
@ -161,7 +161,7 @@ msgstr "创建者"
|
|||
#: assets/models/domain.py:23 assets/models/gathered_user.py:19
|
||||
#: assets/models/group.py:22 assets/models/label.py:25 common/db/models.py:69
|
||||
#: common/mixins/models.py:50 ops/models/adhoc.py:38 ops/models/command.py:27
|
||||
#: orgs/models.py:24 orgs/models.py:324 perms/models/base.py:55
|
||||
#: orgs/models.py:24 orgs/models.py:387 perms/models/base.py:55
|
||||
#: users/models/group.py:18 users/templates/users/user_group_detail.html:58
|
||||
#: xpack/plugins/cloud/models.py:59 xpack/plugins/cloud/models.py:149
|
||||
msgid "Date created"
|
||||
|
@ -233,7 +233,7 @@ msgid "Hostname"
|
|||
msgstr "主机名"
|
||||
|
||||
#: assets/models/asset.py:190 assets/models/domain.py:52
|
||||
#: assets/models/user.py:116 terminal/serializers/session.py:29
|
||||
#: assets/models/user.py:117 terminal/serializers/session.py:29
|
||||
msgid "Protocol"
|
||||
msgstr "协议"
|
||||
|
||||
|
@ -247,7 +247,7 @@ msgstr "协议组"
|
|||
msgid "Domain"
|
||||
msgstr "网域"
|
||||
|
||||
#: assets/models/asset.py:195 assets/models/user.py:111
|
||||
#: assets/models/asset.py:195 assets/models/user.py:112
|
||||
#: perms/models/asset_permission.py:91
|
||||
#: xpack/plugins/change_auth_plan/models.py:56
|
||||
#: xpack/plugins/gathered_user/models.py:24
|
||||
|
@ -261,7 +261,7 @@ msgid "Is active"
|
|||
msgstr "激活"
|
||||
|
||||
#: assets/models/asset.py:199 assets/models/cluster.py:19
|
||||
#: assets/models/user.py:65 templates/_nav.html:44
|
||||
#: assets/models/user.py:66 templates/_nav.html:44
|
||||
#: xpack/plugins/cloud/models.py:133 xpack/plugins/cloud/serializers.py:83
|
||||
msgid "Admin user"
|
||||
msgstr "管理用户"
|
||||
|
@ -354,7 +354,7 @@ msgstr ""
|
|||
#: audits/models.py:99 authentication/forms.py:11
|
||||
#: authentication/templates/authentication/login.html:21
|
||||
#: authentication/templates/authentication/xpack_login.html:101
|
||||
#: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:487
|
||||
#: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:489
|
||||
#: users/templates/users/_select_user_modal.html:14
|
||||
#: users/templates/users/user_detail.html:53
|
||||
#: users/templates/users/user_list.html:15
|
||||
|
@ -395,7 +395,7 @@ msgstr "SSH公钥"
|
|||
|
||||
#: assets/models/base.py:239 assets/models/gathered_user.py:20
|
||||
#: common/db/models.py:70 common/mixins/models.py:51 ops/models/adhoc.py:39
|
||||
#: orgs/models.py:325
|
||||
#: orgs/models.py:388
|
||||
msgid "Date updated"
|
||||
msgstr "更新日期"
|
||||
|
||||
|
@ -407,7 +407,7 @@ msgstr "带宽"
|
|||
msgid "Contact"
|
||||
msgstr "联系人"
|
||||
|
||||
#: assets/models/cluster.py:22 users/models/user.py:508
|
||||
#: assets/models/cluster.py:22 users/models/user.py:510
|
||||
#: users/templates/users/user_detail.html:62
|
||||
msgid "Phone"
|
||||
msgstr "手机"
|
||||
|
@ -433,7 +433,7 @@ msgid "Default"
|
|||
msgstr "默认"
|
||||
|
||||
#: assets/models/cluster.py:36 assets/models/label.py:14
|
||||
#: users/models/user.py:655
|
||||
#: users/models/user.py:657
|
||||
msgid "System"
|
||||
msgstr "系统"
|
||||
|
||||
|
@ -453,7 +453,7 @@ msgstr "北京电信"
|
|||
msgid "BGP full netcom"
|
||||
msgstr "BGP全网通"
|
||||
|
||||
#: assets/models/cmd_filter.py:33 assets/models/user.py:121
|
||||
#: assets/models/cmd_filter.py:33 assets/models/user.py:122
|
||||
msgid "Command filter"
|
||||
msgstr "命令过滤器"
|
||||
|
||||
|
@ -462,7 +462,7 @@ msgid "Regex"
|
|||
msgstr "正则表达式"
|
||||
|
||||
#: assets/models/cmd_filter.py:41 ops/models/command.py:23
|
||||
#: terminal/backends/command/serializers.py:15 terminal/models.py:196
|
||||
#: terminal/backends/command/serializers.py:15 terminal/models.py:197
|
||||
msgid "Command"
|
||||
msgstr "命令"
|
||||
|
||||
|
@ -478,7 +478,7 @@ msgstr "允许"
|
|||
msgid "Filter"
|
||||
msgstr "过滤器"
|
||||
|
||||
#: assets/models/cmd_filter.py:53 assets/models/user.py:115
|
||||
#: assets/models/cmd_filter.py:53 assets/models/user.py:116
|
||||
msgid "Priority"
|
||||
msgstr "优先级"
|
||||
|
||||
|
@ -547,15 +547,15 @@ msgstr "默认资产组"
|
|||
|
||||
#: assets/models/label.py:15 audits/models.py:36 audits/models.py:56
|
||||
#: audits/models.py:69 audits/serializers.py:77 authentication/models.py:46
|
||||
#: authentication/models.py:90 orgs/models.py:16 orgs/models.py:322
|
||||
#: authentication/models.py:90 orgs/models.py:16 orgs/models.py:385
|
||||
#: perms/forms/asset_permission.py:83 perms/forms/database_app_permission.py:38
|
||||
#: perms/forms/remote_app_permission.py:40 perms/models/base.py:49
|
||||
#: templates/index.html:78 terminal/backends/command/models.py:18
|
||||
#: terminal/backends/command/serializers.py:12 terminal/models.py:185
|
||||
#: terminal/backends/command/serializers.py:12 terminal/models.py:186
|
||||
#: tickets/models/ticket.py:30 tickets/models/ticket.py:137
|
||||
#: tickets/serializers/request_asset_perm.py:65
|
||||
#: tickets/serializers/ticket.py:31 users/forms/group.py:15
|
||||
#: users/models/user.py:157 users/models/user.py:643
|
||||
#: users/models/user.py:158 users/models/user.py:645
|
||||
#: users/serializers/group.py:20
|
||||
#: users/templates/users/user_asset_permission.html:38
|
||||
#: users/templates/users/user_asset_permission.html:64
|
||||
|
@ -597,8 +597,8 @@ msgstr "收藏夹"
|
|||
msgid "Key"
|
||||
msgstr "键"
|
||||
|
||||
#: assets/models/node.py:511 assets/serializers/system_user.py:43
|
||||
#: assets/serializers/system_user.py:175 perms/forms/asset_permission.py:92
|
||||
#: assets/models/node.py:511 assets/serializers/system_user.py:45
|
||||
#: assets/serializers/system_user.py:178 perms/forms/asset_permission.py:92
|
||||
#: perms/forms/asset_permission.py:99
|
||||
#: users/templates/users/user_asset_permission.html:41
|
||||
#: users/templates/users/user_asset_permission.html:73
|
||||
|
@ -607,65 +607,73 @@ msgstr "键"
|
|||
msgid "Node"
|
||||
msgstr "节点"
|
||||
|
||||
#: assets/models/user.py:107
|
||||
#: assets/models/user.py:108
|
||||
msgid "Automatic login"
|
||||
msgstr "自动登录"
|
||||
|
||||
#: assets/models/user.py:108
|
||||
#: assets/models/user.py:109
|
||||
msgid "Manually login"
|
||||
msgstr "手动登录"
|
||||
|
||||
#: assets/models/user.py:110
|
||||
#: assets/models/user.py:111
|
||||
msgid "Username same with user"
|
||||
msgstr "用户名与用户相同"
|
||||
|
||||
#: assets/models/user.py:112 templates/_nav.html:39
|
||||
#: assets/models/user.py:113 templates/_nav.html:39
|
||||
#: xpack/plugins/change_auth_plan/models.py:52
|
||||
msgid "Assets"
|
||||
msgstr "资产管理"
|
||||
|
||||
#: assets/models/user.py:113 templates/_nav.html:17
|
||||
#: assets/models/user.py:114 templates/_nav.html:17
|
||||
#: users/views/profile/password.py:42 users/views/profile/pubkey.py:36
|
||||
msgid "Users"
|
||||
msgstr "用户管理"
|
||||
|
||||
#: assets/models/user.py:114 users/templates/users/user_group_list.html:90
|
||||
#: assets/models/user.py:115 users/templates/users/user_group_list.html:90
|
||||
#: users/templates/users/user_profile.html:124
|
||||
msgid "User groups"
|
||||
msgstr "用户组"
|
||||
|
||||
#: assets/models/user.py:117
|
||||
#: assets/models/user.py:118
|
||||
msgid "Auto push"
|
||||
msgstr "自动推送"
|
||||
|
||||
#: assets/models/user.py:118
|
||||
#: assets/models/user.py:119
|
||||
msgid "Sudo"
|
||||
msgstr "Sudo"
|
||||
|
||||
#: assets/models/user.py:119
|
||||
#: assets/models/user.py:120
|
||||
msgid "Shell"
|
||||
msgstr "Shell"
|
||||
|
||||
#: assets/models/user.py:120
|
||||
#: assets/models/user.py:121
|
||||
msgid "Login mode"
|
||||
msgstr "登录模式"
|
||||
|
||||
#: assets/models/user.py:122
|
||||
#: assets/models/user.py:123
|
||||
msgid "SFTP Root"
|
||||
msgstr "SFTP根路径"
|
||||
|
||||
#: assets/models/user.py:123 authentication/models.py:88
|
||||
#: assets/models/user.py:124 authentication/models.py:88
|
||||
msgid "Token"
|
||||
msgstr ""
|
||||
|
||||
#: assets/models/user.py:198 audits/models.py:39
|
||||
#: assets/models/user.py:125
|
||||
msgid "Home"
|
||||
msgstr "家目录"
|
||||
|
||||
#: assets/models/user.py:126
|
||||
msgid "System groups"
|
||||
msgstr "用户组"
|
||||
|
||||
#: assets/models/user.py:201 audits/models.py:39
|
||||
#: perms/forms/asset_permission.py:95 perms/forms/remote_app_permission.py:49
|
||||
#: perms/models/asset_permission.py:92
|
||||
#: perms/models/database_app_permission.py:22
|
||||
#: perms/models/k8s_app_permission.py:22
|
||||
#: perms/models/remote_app_permission.py:16 templates/_nav.html:45
|
||||
#: terminal/backends/command/models.py:20
|
||||
#: terminal/backends/command/serializers.py:14 terminal/models.py:189
|
||||
#: terminal/backends/command/serializers.py:14 terminal/models.py:190
|
||||
#: tickets/serializers/request_asset_perm.py:27
|
||||
#: users/templates/users/_granted_assets.html:27
|
||||
#: users/templates/users/user_asset_permission.html:42
|
||||
|
@ -725,14 +733,14 @@ msgid "Backend"
|
|||
msgstr "后端"
|
||||
|
||||
#: assets/serializers/asset_user.py:75 users/forms/profile.py:148
|
||||
#: users/models/user.py:519 users/templates/users/user_password_update.html:48
|
||||
#: users/models/user.py:521 users/templates/users/user_password_update.html:48
|
||||
#: users/templates/users/user_profile.html:69
|
||||
#: users/templates/users/user_profile_update.html:46
|
||||
#: users/templates/users/user_pubkey_update.html:46
|
||||
msgid "Public key"
|
||||
msgstr "SSH公钥"
|
||||
|
||||
#: assets/serializers/asset_user.py:79 users/models/user.py:516
|
||||
#: assets/serializers/asset_user.py:79 users/models/user.py:518
|
||||
msgid "Private key"
|
||||
msgstr "ssh私钥"
|
||||
|
||||
|
@ -753,23 +761,23 @@ msgstr "值"
|
|||
msgid "The same level node name cannot be the same"
|
||||
msgstr "同级别节点名字不能重复"
|
||||
|
||||
#: assets/serializers/system_user.py:45 assets/serializers/system_user.py:177
|
||||
#: assets/serializers/system_user.py:47 assets/serializers/system_user.py:180
|
||||
msgid "Login mode display"
|
||||
msgstr "登录模式显示"
|
||||
|
||||
#: assets/serializers/system_user.py:85
|
||||
#: assets/serializers/system_user.py:87
|
||||
msgid "Username same with user with protocol {} only allow 1"
|
||||
msgstr "用户名和用户相同的一种协议只允许存在一个"
|
||||
|
||||
#: assets/serializers/system_user.py:98
|
||||
#: assets/serializers/system_user.py:100
|
||||
msgid "* Automatic login mode must fill in the username."
|
||||
msgstr "自动登录模式,必须填写用户名"
|
||||
|
||||
#: assets/serializers/system_user.py:106
|
||||
#: assets/serializers/system_user.py:108
|
||||
msgid "Path should starts with /"
|
||||
msgstr "路径应该以 / 开头"
|
||||
|
||||
#: assets/serializers/system_user.py:117
|
||||
#: assets/serializers/system_user.py:119
|
||||
msgid "Password or private key required"
|
||||
msgstr "密码或密钥密码需要一个"
|
||||
|
||||
|
@ -821,25 +829,25 @@ msgstr "更新节点资产硬件信息: {}"
|
|||
msgid "Gather assets users"
|
||||
msgstr "收集资产上的用户"
|
||||
|
||||
#: assets/tasks/push_system_user.py:148
|
||||
#: assets/tasks/push_system_user.py:176
|
||||
#: assets/tasks/system_user_connectivity.py:89
|
||||
msgid "System user is dynamic: {}"
|
||||
msgstr "系统用户是动态的: {}"
|
||||
|
||||
#: assets/tasks/push_system_user.py:179
|
||||
#: assets/tasks/push_system_user.py:207
|
||||
msgid "Start push system user for platform: [{}]"
|
||||
msgstr "推送系统用户到平台: [{}]"
|
||||
|
||||
#: assets/tasks/push_system_user.py:180
|
||||
#: assets/tasks/push_system_user.py:208
|
||||
#: assets/tasks/system_user_connectivity.py:81
|
||||
msgid "Hosts count: {}"
|
||||
msgstr "主机数量: {}"
|
||||
|
||||
#: assets/tasks/push_system_user.py:197 assets/tasks/push_system_user.py:213
|
||||
#: assets/tasks/push_system_user.py:225 assets/tasks/push_system_user.py:241
|
||||
msgid "Push system users to assets: {}"
|
||||
msgstr "推送系统用户到入资产: {}"
|
||||
|
||||
#: assets/tasks/push_system_user.py:205
|
||||
#: assets/tasks/push_system_user.py:233
|
||||
msgid "Push system users to asset: {}({}) => {}"
|
||||
msgstr "推送系统用户到入资产: {}({}) => {}"
|
||||
|
||||
|
@ -919,7 +927,7 @@ msgid "Symlink"
|
|||
msgstr "建立软链接"
|
||||
|
||||
#: audits/models.py:37 audits/models.py:60 audits/models.py:71
|
||||
#: terminal/models.py:192
|
||||
#: terminal/models.py:193
|
||||
msgid "Remote addr"
|
||||
msgstr "远端地址"
|
||||
|
||||
|
@ -937,7 +945,7 @@ msgid "Success"
|
|||
msgstr "成功"
|
||||
|
||||
#: audits/models.py:43 ops/models/command.py:28 perms/models/base.py:52
|
||||
#: terminal/models.py:199 tickets/serializers/request_asset_perm.py:29
|
||||
#: terminal/models.py:200 tickets/serializers/request_asset_perm.py:29
|
||||
#: xpack/plugins/change_auth_plan/models.py:177
|
||||
#: xpack/plugins/change_auth_plan/models.py:308
|
||||
#: xpack/plugins/gathered_user/models.py:76
|
||||
|
@ -1017,7 +1025,7 @@ msgstr "Agent"
|
|||
#: audits/models.py:104
|
||||
#: authentication/templates/authentication/_mfa_confirm_modal.html:14
|
||||
#: authentication/templates/authentication/login_otp.html:6
|
||||
#: users/forms/profile.py:52 users/models/user.py:511
|
||||
#: users/forms/profile.py:52 users/models/user.py:513
|
||||
#: users/serializers/user.py:240 users/templates/users/user_detail.html:77
|
||||
#: users/templates/users/user_profile.html:87
|
||||
msgid "MFA"
|
||||
|
@ -1191,7 +1199,7 @@ msgstr "登录复核 {}"
|
|||
msgid "SSO auth closed"
|
||||
msgstr "SSO 认证关闭了"
|
||||
|
||||
#: authentication/errors.py:218 authentication/views/login.py:237
|
||||
#: authentication/errors.py:218 authentication/views/login.py:243
|
||||
msgid "Your password is too simple, please change it for security"
|
||||
msgstr "你的密码过于简单,为了安全,请修改"
|
||||
|
||||
|
@ -1257,7 +1265,7 @@ msgid "Show"
|
|||
msgstr "显示"
|
||||
|
||||
#: authentication/templates/authentication/_access_key_modal.html:66
|
||||
#: users/models/user.py:409 users/serializers/user.py:237
|
||||
#: users/models/user.py:411 users/serializers/user.py:237
|
||||
#: users/templates/users/user_profile.html:94
|
||||
#: users/templates/users/user_profile.html:163
|
||||
#: users/templates/users/user_profile.html:166
|
||||
|
@ -1266,7 +1274,7 @@ msgid "Disable"
|
|||
msgstr "禁用"
|
||||
|
||||
#: authentication/templates/authentication/_access_key_modal.html:67
|
||||
#: users/models/user.py:410 users/serializers/user.py:238
|
||||
#: users/models/user.py:412 users/serializers/user.py:238
|
||||
#: users/templates/users/user_profile.html:92
|
||||
#: users/templates/users/user_profile.html:170
|
||||
msgid "Enable"
|
||||
|
@ -1374,11 +1382,11 @@ msgstr "复制成功"
|
|||
msgid "Welcome back, please enter username and password to login"
|
||||
msgstr "欢迎回来,请输入用户名和密码登录"
|
||||
|
||||
#: authentication/views/login.py:83
|
||||
#: authentication/views/login.py:84
|
||||
msgid "Please enable cookies and try again."
|
||||
msgstr "设置你的浏览器支持cookie"
|
||||
|
||||
#: authentication/views/login.py:183
|
||||
#: authentication/views/login.py:189
|
||||
msgid ""
|
||||
"Wait for <b>{}</b> confirm, You also can copy link to her/him <br/>\n"
|
||||
" Don't close this page"
|
||||
|
@ -1386,19 +1394,19 @@ msgstr ""
|
|||
"等待 <b>{}</b> 确认, 你也可以复制链接发给他/她 <br/>\n"
|
||||
" 不要关闭本页面"
|
||||
|
||||
#: authentication/views/login.py:188
|
||||
#: authentication/views/login.py:194
|
||||
msgid "No ticket found"
|
||||
msgstr "没有发现工单"
|
||||
|
||||
#: authentication/views/login.py:220
|
||||
#: authentication/views/login.py:226
|
||||
msgid "Logout success"
|
||||
msgstr "退出登录成功"
|
||||
|
||||
#: authentication/views/login.py:221
|
||||
#: authentication/views/login.py:227
|
||||
msgid "Logout success, return login page"
|
||||
msgstr "退出登录成功,返回到登录页面"
|
||||
|
||||
#: authentication/views/login.py:236
|
||||
#: authentication/views/login.py:242
|
||||
msgid "Please change your password"
|
||||
msgstr "请修改密码"
|
||||
|
||||
|
@ -1670,14 +1678,14 @@ msgstr "磁盘使用率超过 80%: {} => {}"
|
|||
|
||||
#: orgs/api.py:58
|
||||
msgid "Organization contains undeleted resources"
|
||||
msgstr ""
|
||||
msgstr "组织包含未删除的资源"
|
||||
|
||||
#: orgs/api.py:62
|
||||
msgid "The current organization cannot be deleted"
|
||||
msgstr ""
|
||||
msgstr "当前组织不能被删除"
|
||||
|
||||
#: orgs/mixins/models.py:56 orgs/mixins/serializers.py:25 orgs/models.py:40
|
||||
#: orgs/models.py:321
|
||||
#: orgs/models.py:384
|
||||
msgid "Organization"
|
||||
msgstr "组织"
|
||||
|
||||
|
@ -1689,7 +1697,7 @@ msgstr "组织管理员"
|
|||
msgid "Organization auditor"
|
||||
msgstr "组织审计员"
|
||||
|
||||
#: orgs/models.py:323 users/forms/user.py:27 users/models/user.py:499
|
||||
#: orgs/models.py:386 users/forms/user.py:27 users/models/user.py:501
|
||||
#: users/templates/users/_select_user_modal.html:15
|
||||
#: users/templates/users/user_detail.html:73
|
||||
#: users/templates/users/user_list.html:16
|
||||
|
@ -1714,7 +1722,7 @@ msgstr "提示:RDP 协议不支持单独控制上传或下载文件"
|
|||
#: perms/forms/asset_permission.py:86 perms/forms/database_app_permission.py:41
|
||||
#: perms/forms/remote_app_permission.py:43 perms/models/base.py:50
|
||||
#: templates/_nav.html:21 users/forms/user.py:168 users/models/group.py:31
|
||||
#: users/models/user.py:495 users/serializers/user.py:49
|
||||
#: users/models/user.py:497 users/serializers/user.py:48
|
||||
#: users/templates/users/_select_user_modal.html:16
|
||||
#: users/templates/users/user_asset_permission.html:39
|
||||
#: users/templates/users/user_asset_permission.html:67
|
||||
|
@ -1781,7 +1789,7 @@ msgid "Asset permission"
|
|||
msgstr "资产授权"
|
||||
|
||||
#: perms/models/base.py:53 tickets/serializers/request_asset_perm.py:31
|
||||
#: users/models/user.py:527 users/templates/users/user_detail.html:93
|
||||
#: users/models/user.py:529 users/templates/users/user_detail.html:93
|
||||
#: users/templates/users/user_profile.html:120
|
||||
msgid "Date expired"
|
||||
msgstr "失效日期"
|
||||
|
@ -2469,96 +2477,97 @@ msgstr "风险等级"
|
|||
msgid "Bulk create not support"
|
||||
msgstr "不支持批量创建"
|
||||
|
||||
#: terminal/models.py:27
|
||||
#: terminal/models.py:28
|
||||
msgid "Remote Address"
|
||||
msgstr "远端地址"
|
||||
|
||||
#: terminal/models.py:28
|
||||
#: terminal/models.py:29
|
||||
msgid "SSH Port"
|
||||
msgstr "SSH端口"
|
||||
|
||||
#: terminal/models.py:29
|
||||
#: terminal/models.py:30
|
||||
msgid "HTTP Port"
|
||||
msgstr "HTTP端口"
|
||||
|
||||
#: terminal/models.py:30
|
||||
#: terminal/models.py:31
|
||||
msgid "Command storage"
|
||||
msgstr "命令存储"
|
||||
|
||||
#: terminal/models.py:31
|
||||
#: terminal/models.py:32
|
||||
msgid "Replay storage"
|
||||
msgstr "录像存储"
|
||||
|
||||
#: terminal/models.py:154
|
||||
#: terminal/models.py:155
|
||||
msgid "Session Online"
|
||||
msgstr "在线会话"
|
||||
|
||||
#: terminal/models.py:155
|
||||
#: terminal/models.py:156
|
||||
msgid "CPU Usage"
|
||||
msgstr "CPU使用"
|
||||
|
||||
#: terminal/models.py:156
|
||||
#: terminal/models.py:157
|
||||
msgid "Memory Used"
|
||||
msgstr "内存使用"
|
||||
|
||||
#: terminal/models.py:157
|
||||
#: terminal/models.py:158
|
||||
msgid "Connections"
|
||||
msgstr "连接数"
|
||||
|
||||
#: terminal/models.py:158
|
||||
#: terminal/models.py:159
|
||||
msgid "Threads"
|
||||
msgstr "线程数"
|
||||
|
||||
#: terminal/models.py:159
|
||||
#: terminal/models.py:160
|
||||
msgid "Boot Time"
|
||||
msgstr "运行时间"
|
||||
|
||||
#: terminal/models.py:191
|
||||
#: terminal/models.py:192
|
||||
msgid "Login from"
|
||||
msgstr "登录来源"
|
||||
|
||||
#: terminal/models.py:195
|
||||
#: terminal/models.py:196
|
||||
msgid "Replay"
|
||||
msgstr "回放"
|
||||
|
||||
#: terminal/models.py:200
|
||||
#: terminal/models.py:201
|
||||
msgid "Date end"
|
||||
msgstr "结束日期"
|
||||
|
||||
#: terminal/models.py:343
|
||||
#: terminal/models.py:345
|
||||
msgid "Args"
|
||||
msgstr "参数"
|
||||
|
||||
#: tickets/api/request_asset_perm.py:45
|
||||
#: tickets/api/request_asset_perm.py:46
|
||||
#, python-format
|
||||
msgid "Ticket has %s"
|
||||
msgstr "工单已%s"
|
||||
|
||||
#: tickets/api/request_asset_perm.py:90
|
||||
#: tickets/api/request_asset_perm.py:91
|
||||
msgid "Confirm assets first"
|
||||
msgstr "请先确认资产"
|
||||
|
||||
#: tickets/api/request_asset_perm.py:93
|
||||
#: tickets/api/request_asset_perm.py:94
|
||||
msgid "Confirmed assets changed"
|
||||
msgstr "确认的资产变更了"
|
||||
|
||||
#: tickets/api/request_asset_perm.py:97
|
||||
#: tickets/api/request_asset_perm.py:98
|
||||
msgid "Confirm system-user first"
|
||||
msgstr "请先确认系统用户"
|
||||
|
||||
#: tickets/api/request_asset_perm.py:101
|
||||
#: tickets/api/request_asset_perm.py:102
|
||||
msgid "Confirmed system-user changed"
|
||||
msgstr "确认的系统用户变更了"
|
||||
|
||||
#: tickets/api/request_asset_perm.py:104 xpack/plugins/cloud/models.py:202
|
||||
#: tickets/api/request_asset_perm.py:105 tickets/api/request_asset_perm.py:112
|
||||
#: xpack/plugins/cloud/models.py:202
|
||||
msgid "Succeed"
|
||||
msgstr "成功"
|
||||
|
||||
#: tickets/api/request_asset_perm.py:112
|
||||
#: tickets/api/request_asset_perm.py:120
|
||||
msgid "From request ticket: {} {}"
|
||||
msgstr "来自工单申请: {} {}"
|
||||
|
||||
#: tickets/api/request_asset_perm.py:114
|
||||
#: tickets/api/request_asset_perm.py:122
|
||||
msgid "{} request assets, approved by {}"
|
||||
msgstr "{} 申请资产,通过人 {}"
|
||||
|
||||
|
@ -2576,11 +2585,11 @@ msgstr "不能操作该工单"
|
|||
|
||||
#: tickets/models/ticket.py:18 tickets/models/ticket.py:69
|
||||
msgid "Open"
|
||||
msgstr "开启"
|
||||
msgstr "待处理"
|
||||
|
||||
#: tickets/models/ticket.py:19
|
||||
msgid "Closed"
|
||||
msgstr "关闭"
|
||||
msgstr "已完成"
|
||||
|
||||
#: tickets/models/ticket.py:22
|
||||
msgid "General"
|
||||
|
@ -2741,7 +2750,7 @@ msgstr ""
|
|||
" </div>\n"
|
||||
" "
|
||||
|
||||
#: users/api/user.py:147
|
||||
#: users/api/user.py:158
|
||||
msgid "Could not reset self otp, use profile reset instead"
|
||||
msgstr "不能在该页面重置多因子认证, 请去个人信息页面重置"
|
||||
|
||||
|
@ -2787,7 +2796,7 @@ msgstr "确认密码"
|
|||
msgid "Password does not match"
|
||||
msgstr "密码不一致"
|
||||
|
||||
#: users/forms/profile.py:89 users/models/user.py:491
|
||||
#: users/forms/profile.py:89 users/models/user.py:493
|
||||
#: users/templates/users/user_detail.html:57
|
||||
#: users/templates/users/user_profile.html:59
|
||||
msgid "Email"
|
||||
|
@ -2828,7 +2837,7 @@ msgstr "不能和原来的密钥相同"
|
|||
msgid "Not a valid ssh public key"
|
||||
msgstr "SSH密钥不合法"
|
||||
|
||||
#: users/forms/user.py:31 users/models/user.py:534
|
||||
#: users/forms/user.py:31 users/models/user.py:536
|
||||
#: users/templates/users/user_detail.html:89
|
||||
#: users/templates/users/user_list.html:18
|
||||
#: users/templates/users/user_profile.html:102
|
||||
|
@ -2848,93 +2857,93 @@ msgstr "添加到用户组"
|
|||
msgid "* Your password does not meet the requirements"
|
||||
msgstr "* 您的密码不符合要求"
|
||||
|
||||
#: users/forms/user.py:124 users/serializers/user.py:37
|
||||
#: users/forms/user.py:124 users/serializers/user.py:36
|
||||
msgid "Reset link will be generated and sent to the user"
|
||||
msgstr "生成重置密码链接,通过邮件发送给用户"
|
||||
|
||||
#: users/forms/user.py:125 users/serializers/user.py:38
|
||||
#: users/forms/user.py:125 users/serializers/user.py:37
|
||||
msgid "Set password"
|
||||
msgstr "设置密码"
|
||||
|
||||
#: users/forms/user.py:132 users/serializers/user.py:45
|
||||
#: users/forms/user.py:132 users/serializers/user.py:44
|
||||
#: xpack/plugins/change_auth_plan/models.py:61
|
||||
#: xpack/plugins/change_auth_plan/serializers.py:30
|
||||
msgid "Password strategy"
|
||||
msgstr "密码策略"
|
||||
|
||||
#: users/models/user.py:156
|
||||
msgid "Super administrator"
|
||||
msgstr "超级管理员"
|
||||
|
||||
#: users/models/user.py:158
|
||||
msgid "Super auditor"
|
||||
msgstr "超级审计员"
|
||||
#: users/models/user.py:157
|
||||
msgid "System administrator"
|
||||
msgstr "系统管理员"
|
||||
|
||||
#: users/models/user.py:159
|
||||
msgid "System auditor"
|
||||
msgstr "系统审计员"
|
||||
|
||||
#: users/models/user.py:160
|
||||
msgid "Application"
|
||||
msgstr "应用程序"
|
||||
|
||||
#: users/models/user.py:411 users/templates/users/user_profile.html:90
|
||||
#: users/models/user.py:413 users/templates/users/user_profile.html:90
|
||||
msgid "Force enable"
|
||||
msgstr "强制启用"
|
||||
|
||||
#: users/models/user.py:478
|
||||
#: users/models/user.py:480
|
||||
msgid "Local"
|
||||
msgstr "数据库"
|
||||
|
||||
#: users/models/user.py:502
|
||||
#: users/models/user.py:504
|
||||
msgid "Avatar"
|
||||
msgstr "头像"
|
||||
|
||||
#: users/models/user.py:505 users/templates/users/user_detail.html:68
|
||||
#: users/models/user.py:507 users/templates/users/user_detail.html:68
|
||||
msgid "Wechat"
|
||||
msgstr "微信"
|
||||
|
||||
#: users/models/user.py:538
|
||||
#: users/models/user.py:540
|
||||
msgid "Date password last updated"
|
||||
msgstr "最后更新密码日期"
|
||||
|
||||
#: users/models/user.py:651
|
||||
#: users/models/user.py:653
|
||||
msgid "Administrator"
|
||||
msgstr "管理员"
|
||||
|
||||
#: users/models/user.py:654
|
||||
#: users/models/user.py:656
|
||||
msgid "Administrator is the super user of system"
|
||||
msgstr "Administrator是初始的超级管理员"
|
||||
|
||||
#: users/serializers/user.py:55 users/serializers/user.py:93
|
||||
#: users/serializers/user.py:53 users/serializers/user.py:88
|
||||
msgid "Organization role name"
|
||||
msgstr "组织角色名称"
|
||||
|
||||
#: users/serializers/user.py:59
|
||||
#: users/serializers/user.py:55
|
||||
msgid "Total role name"
|
||||
msgstr "汇总角色名称"
|
||||
|
||||
#: users/serializers/user.py:84 users/serializers/user.py:253
|
||||
#: users/serializers/user.py:79 users/serializers/user.py:253
|
||||
msgid "Is first login"
|
||||
msgstr "首次登录"
|
||||
|
||||
#: users/serializers/user.py:85
|
||||
#: users/serializers/user.py:80
|
||||
msgid "Is valid"
|
||||
msgstr "账户是否有效"
|
||||
|
||||
#: users/serializers/user.py:86
|
||||
#: users/serializers/user.py:81
|
||||
msgid "Is expired"
|
||||
msgstr " 是否过期"
|
||||
|
||||
#: users/serializers/user.py:87
|
||||
#: users/serializers/user.py:82
|
||||
msgid "Avatar url"
|
||||
msgstr "头像路径"
|
||||
|
||||
#: users/serializers/user.py:91
|
||||
#: users/serializers/user.py:86
|
||||
msgid "Groups name"
|
||||
msgstr "用户组名"
|
||||
|
||||
#: users/serializers/user.py:92
|
||||
#: users/serializers/user.py:87
|
||||
msgid "Source name"
|
||||
msgstr "用户来源名"
|
||||
|
||||
#: users/serializers/user.py:94
|
||||
#: users/serializers/user.py:89
|
||||
msgid "Super role name"
|
||||
msgstr "超级角色名称"
|
||||
|
||||
|
@ -4072,6 +4081,12 @@ msgstr "企业版"
|
|||
msgid "Ultimate edition"
|
||||
msgstr "旗舰版"
|
||||
|
||||
#~ msgid "Organization User"
|
||||
#~ msgstr "组织用户"
|
||||
|
||||
#~ msgid "System User"
|
||||
#~ msgstr "系统用户"
|
||||
|
||||
#~ msgid "Auditor"
|
||||
#~ msgstr "审计员"
|
||||
|
||||
|
@ -4489,9 +4504,6 @@ msgstr "旗舰版"
|
|||
#~ msgid "Have existed: "
|
||||
#~ msgstr "已经存在: "
|
||||
|
||||
#~ msgid "Home"
|
||||
#~ msgstr "家目录"
|
||||
|
||||
#~ msgid "Uid"
|
||||
#~ msgstr "Uid"
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.13 on 2020-08-19 12:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('orgs', '0007_auto_20200728_1805'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='organizationmember',
|
||||
name='role',
|
||||
field=models.CharField(choices=[('Admin', 'Organization administrator'), ('Auditor', 'Organization auditor'), ('User', 'User')], default='User', max_length=16, verbose_name='Role'),
|
||||
),
|
||||
]
|
|
@ -13,8 +13,8 @@ from common.db.models import ChoiceSet
|
|||
|
||||
class ROLE(ChoiceSet):
|
||||
ADMIN = choices.ADMIN, _('Organization administrator')
|
||||
USER = choices.USER, _('User')
|
||||
AUDITOR = choices.AUDITOR, _("Organization auditor")
|
||||
USER = choices.USER, _('User')
|
||||
|
||||
|
||||
class Organization(models.Model):
|
||||
|
@ -229,15 +229,44 @@ def _none2list(*args):
|
|||
return ([] if v is None else v for v in args)
|
||||
|
||||
|
||||
class UserRoleMapper(dict):
|
||||
def __init__(self, container=set):
|
||||
super().__init__()
|
||||
self.users = container()
|
||||
self.admins = container()
|
||||
self.auditors = container()
|
||||
|
||||
self[ROLE.USER] = self.users
|
||||
self[ROLE.ADMIN] = self.admins
|
||||
self[ROLE.AUDITOR] = self.auditors
|
||||
|
||||
|
||||
class OrgMemeberManager(models.Manager):
|
||||
|
||||
def remove_users(self, org, users):
|
||||
from users.models import User
|
||||
pk_set = []
|
||||
for user in users:
|
||||
if hasattr(user, 'pk'):
|
||||
pk_set.append(user.pk)
|
||||
else:
|
||||
pk_set.append(user)
|
||||
|
||||
send = partial(signals.m2m_changed.send, sender=self.model, instance=org, reverse=False,
|
||||
model=User, pk_set=pk_set, using=self.db)
|
||||
send(action="pre_remove")
|
||||
self.filter(org_id=org.id, user_id__in=pk_set).delete()
|
||||
send(action="post_remove")
|
||||
|
||||
def remove_users_by_role(self, org, users=None, admins=None, auditors=None):
|
||||
from users.models import User
|
||||
|
||||
if not any((users, admins, auditors)):
|
||||
return
|
||||
users, admins, auditors = _none2list(users, admins, auditors)
|
||||
|
||||
send = partial(signals.m2m_changed.send, sender=self.model, instance=org, reverse=False,
|
||||
model=Organization, pk_set=[*users, *admins, *auditors], using=self.db)
|
||||
model=User, pk_set=[*users, *admins, *auditors], using=self.db)
|
||||
|
||||
send(action="pre_remove")
|
||||
self.filter(org_id=org.id).filter(
|
||||
|
@ -248,6 +277,8 @@ class OrgMemeberManager(models.Manager):
|
|||
send(action="post_remove")
|
||||
|
||||
def add_users_by_role(self, org, users=None, admins=None, auditors=None):
|
||||
from users.models import User
|
||||
|
||||
if not any((users, admins, auditors)):
|
||||
return
|
||||
users, admins, auditors = _none2list(users, admins, auditors)
|
||||
|
@ -266,7 +297,7 @@ class OrgMemeberManager(models.Manager):
|
|||
oms_add.append(self.model(org_id=org.id, user_id=user, role=role))
|
||||
|
||||
send = partial(signals.m2m_changed.send, sender=self.model, instance=org, reverse=False,
|
||||
model=Organization, pk_set=[*users, *admins, *auditors], using=self.db)
|
||||
model=User, pk_set=[*users, *admins, *auditors], using=self.db)
|
||||
|
||||
send(action='pre_add')
|
||||
self.bulk_create(oms_add)
|
||||
|
@ -278,24 +309,56 @@ class OrgMemeberManager(models.Manager):
|
|||
new_users = _convert_to_uuid_set(new_users)
|
||||
return (old_users - new_users), (new_users - old_users)
|
||||
|
||||
def set_user_roles(self, org, user, roles):
|
||||
"""
|
||||
设置某个用户在某个组织里的角色
|
||||
"""
|
||||
old_roles = set(self.filter(org_id=org.id, user=user).values_list('role', flat=True))
|
||||
new_roles = set(roles)
|
||||
|
||||
roles_remove = old_roles - new_roles
|
||||
roles_add = new_roles - old_roles
|
||||
|
||||
to_remove = UserRoleMapper()
|
||||
to_add = UserRoleMapper()
|
||||
|
||||
for role in roles_remove:
|
||||
if role in to_remove:
|
||||
to_remove[role].add(user)
|
||||
for role in roles_add:
|
||||
if role in to_add:
|
||||
to_add[role].add(user)
|
||||
|
||||
self.remove_users_by_role(
|
||||
org,
|
||||
to_remove.users,
|
||||
to_remove.admins,
|
||||
to_remove.auditors
|
||||
)
|
||||
|
||||
self.add_users_by_role(
|
||||
org,
|
||||
to_add.users,
|
||||
to_add.admins,
|
||||
to_add.auditors
|
||||
)
|
||||
|
||||
def set_users_by_role(self, org, users=None, admins=None, auditors=None):
|
||||
"""
|
||||
给组织设置带角色的用户
|
||||
"""
|
||||
|
||||
oms = self.filter(org_id=org.id).values_list('role', 'user_id')
|
||||
|
||||
old_users, old_admins, old_auditors = set(), set(), set()
|
||||
|
||||
mapper = {
|
||||
ROLE.USER: old_users,
|
||||
ROLE.ADMIN: old_admins,
|
||||
ROLE.AUDITOR: old_auditors
|
||||
}
|
||||
old_mapper = UserRoleMapper()
|
||||
|
||||
for role, user_id in oms:
|
||||
if role in mapper:
|
||||
mapper[role].add(user_id)
|
||||
if role in old_mapper:
|
||||
old_mapper[role].add(user_id)
|
||||
|
||||
users_remove, users_add = self._get_remove_add_set(users, old_users)
|
||||
admins_remove, admins_add = self._get_remove_add_set(admins, old_admins)
|
||||
auditors_remove, auditors_add = self._get_remove_add_set(auditors, old_auditors)
|
||||
users_remove, users_add = self._get_remove_add_set(users, old_mapper.users)
|
||||
admins_remove, admins_add = self._get_remove_add_set(admins, old_mapper.admins)
|
||||
auditors_remove, auditors_add = self._get_remove_add_set(auditors, old_mapper.auditors)
|
||||
|
||||
self.remove_users_by_role(
|
||||
org,
|
||||
|
|
|
@ -6,13 +6,13 @@ from users.models.user import User
|
|||
from common.serializers import AdaptedBulkListSerializer
|
||||
from common.drf.serializers import BulkModelSerializer
|
||||
from common.db.models import concated_display as display
|
||||
from .models import Organization, OrganizationMember, ROLE as ORG_ROLE
|
||||
from .models import Organization, OrganizationMember
|
||||
|
||||
|
||||
class OrgSerializer(ModelSerializer):
|
||||
users = serializers.PrimaryKeyRelatedField(many=True, queryset=User.objects.all(), write_only=True)
|
||||
admins = serializers.PrimaryKeyRelatedField(many=True, queryset=User.objects.all(), write_only=True)
|
||||
auditors = serializers.PrimaryKeyRelatedField(many=True, queryset=User.objects.all(), write_only=True)
|
||||
users = serializers.PrimaryKeyRelatedField(many=True, queryset=User.objects.all(), write_only=True, required=False)
|
||||
admins = serializers.PrimaryKeyRelatedField(many=True, queryset=User.objects.all(), write_only=True, required=False)
|
||||
auditors = serializers.PrimaryKeyRelatedField(many=True, queryset=User.objects.all(), write_only=True, required=False)
|
||||
|
||||
class Meta:
|
||||
model = Organization
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import textwrap
|
||||
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework.decorators import action
|
||||
|
@ -8,7 +10,7 @@ from orgs.models import Organization, ROLE as ORG_ROLE
|
|||
from users.models.user import User
|
||||
from common.const.http import POST, GET
|
||||
from common.drf.api import JMSModelViewSet
|
||||
from common.permissions import IsValidUser
|
||||
from common.permissions import IsValidUser, IsObjectOwner
|
||||
from common.utils.django import get_object_or_none
|
||||
from common.utils.timezone import dt_parser
|
||||
from common.drf.serializers import EmptySerializer
|
||||
|
@ -31,6 +33,7 @@ class RequestAssetPermTicketViewSet(JMSModelViewSet):
|
|||
'default': serializers.RequestAssetPermTicketSerializer,
|
||||
'approve': EmptySerializer,
|
||||
'reject': EmptySerializer,
|
||||
'close': EmptySerializer,
|
||||
'assignees': serializers.AssigneeSerializer,
|
||||
}
|
||||
permission_classes = (IsValidUser,)
|
||||
|
@ -61,13 +64,13 @@ class RequestAssetPermTicketViewSet(JMSModelViewSet):
|
|||
ips = ', '.join(meta.get('ips', []))
|
||||
confirmed_assets = ', '.join(meta.get('confirmed_assets', []))
|
||||
|
||||
return f'''
|
||||
return textwrap.dedent(f'''\
|
||||
{_('IP group')}: {ips}
|
||||
{_('Hostname')}: {meta.get('hostname', '')}
|
||||
{_('System user')}: {meta.get('system_user', '')}
|
||||
{_('Confirmed assets')}: {confirmed_assets}
|
||||
{_('Confirmed system user')}: {meta.get('confirmed_system_user', '')}
|
||||
'''
|
||||
''')
|
||||
|
||||
@action(detail=True, methods=[POST], permission_classes=[IsAssignee, IsValidUser])
|
||||
def reject(self, request, *args, **kwargs):
|
||||
|
@ -103,6 +106,13 @@ class RequestAssetPermTicketViewSet(JMSModelViewSet):
|
|||
self._create_asset_permission(instance, assets, system_user)
|
||||
return Response({'detail': _('Succeed')})
|
||||
|
||||
@action(detail=True, methods=[POST], permission_classes=[IsAssignee | IsObjectOwner])
|
||||
def close(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
instance.status = Ticket.STATUS.CLOSED
|
||||
instance.save()
|
||||
return Response({'detail': _('Succeed')})
|
||||
|
||||
def _create_asset_permission(self, instance: Ticket, assets, system_user):
|
||||
meta = instance.meta
|
||||
request = self.request
|
||||
|
|
|
@ -4,6 +4,7 @@ from urllib.parse import urljoin
|
|||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from common.const.front_urls import TICKET_DETAIL
|
||||
from common.utils import get_logger
|
||||
from common.tasks import send_mail_async
|
||||
|
||||
|
@ -20,11 +21,7 @@ def send_new_ticket_mail_to_assignees(ticket: Ticket, assignees):
|
|||
subject = '{}: {}'.format(_("New ticket"), ticket.title)
|
||||
|
||||
# 这里要设置前端地址,因为要直接跳转到页面
|
||||
if ticket.type == ticket.TYPE.REQUEST_ASSET_PERM:
|
||||
detail_url = urljoin(settings.SITE_URL, f'/tickets/tickets/request-asset-perm/{ticket.id}')
|
||||
else:
|
||||
detail_url = urljoin(settings.SITE_URL, f'/tickets/tickets/{ticket.id}')
|
||||
|
||||
detail_url = urljoin(settings.SITE_URL, TICKET_DETAIL.format(id=ticket.id))
|
||||
message = _("""
|
||||
<div>
|
||||
<p>Your has a new ticket</p>
|
||||
|
|
|
@ -56,31 +56,25 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
|||
|
||||
def perform_create(self, serializer):
|
||||
validated_data = serializer.validated_data
|
||||
if isinstance(validated_data, list):
|
||||
org_roles = [item.pop('org_role', None) for item in validated_data]
|
||||
else:
|
||||
org_roles = [validated_data.pop('org_role', None)]
|
||||
|
||||
# `org_roles` 先 `pop`
|
||||
if isinstance(validated_data, list):
|
||||
org_roles = [item.pop('org_roles', []) for item in validated_data]
|
||||
else:
|
||||
org_roles = [validated_data.pop('org_roles', [])]
|
||||
|
||||
# 创建用户
|
||||
users = serializer.save()
|
||||
if isinstance(users, User):
|
||||
users = [users]
|
||||
if current_org and current_org.is_real():
|
||||
mapper = {
|
||||
ORG_ROLE.USER: [],
|
||||
ORG_ROLE.ADMIN: [],
|
||||
ORG_ROLE.AUDITOR: []
|
||||
}
|
||||
|
||||
for user, role in zip(users, org_roles):
|
||||
if role in mapper:
|
||||
mapper[role].append(user)
|
||||
else:
|
||||
mapper[ORG_ROLE.USER].append(user)
|
||||
OrganizationMember.objects.set_users_by_role(
|
||||
current_org, users=mapper[ORG_ROLE.USER],
|
||||
admins=mapper[ORG_ROLE.ADMIN],
|
||||
auditors=mapper[ORG_ROLE.AUDITOR]
|
||||
)
|
||||
# 只有真实存在的组织才真正关联用户
|
||||
if current_org and current_org.is_real():
|
||||
for user, roles in zip(users, org_roles):
|
||||
if not roles:
|
||||
# 当前组织创建的用户,至少是该组织的`User`
|
||||
roles.append(ORG_ROLE.USER)
|
||||
OrganizationMember.objects.set_user_roles(current_org, user, roles)
|
||||
self.send_created_signal(users)
|
||||
|
||||
def get_permissions(self):
|
||||
|
@ -101,6 +95,23 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
|
|||
self.check_object_permissions(self.request, obj)
|
||||
self.perform_destroy(obj)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
validated_data = serializer.validated_data
|
||||
# `org_roles` 先 `pop`
|
||||
if isinstance(validated_data, list):
|
||||
org_roles = [item.pop('org_roles', None) for item in validated_data]
|
||||
else:
|
||||
org_roles = [validated_data.pop('org_roles', None)]
|
||||
|
||||
users = serializer.save()
|
||||
if isinstance(users, User):
|
||||
users = [users]
|
||||
if current_org and current_org.is_real():
|
||||
for user, roles in zip(users, org_roles):
|
||||
if roles is not None:
|
||||
# roles 是 `Node` 表明不需要更新
|
||||
OrganizationMember.objects.set_user_roles(current_org, user, roles)
|
||||
|
||||
def perform_bulk_update(self, serializer):
|
||||
# TODO: 需要测试
|
||||
users_ids = [
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.13 on 2020-08-14 08:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0028_auto_20200728_1805'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='role',
|
||||
field=models.CharField(blank=True, choices=[('Admin', 'System administrator'), ('User', 'User'), ('Auditor', 'System auditor'), ('App', 'Application')], default='User', max_length=10, verbose_name='Role'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.13 on 2020-08-19 12:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0029_auto_20200814_1650'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='role',
|
||||
field=models.CharField(blank=True, choices=[('Admin', 'System administrator'), ('Auditor', 'System auditor'), ('User', 'User'), ('App', 'Application')], default='User', max_length=10, verbose_name='Role'),
|
||||
),
|
||||
]
|
|
@ -18,6 +18,7 @@ from django.shortcuts import reverse
|
|||
|
||||
from common.local import LOCAL_DYNAMIC_SETTINGS
|
||||
from orgs.utils import current_org
|
||||
from orgs.models import OrganizationMember
|
||||
from common.utils import date_expired_default, get_logger, lazyproperty
|
||||
from common import fields
|
||||
from common.const import choices
|
||||
|
@ -153,9 +154,9 @@ class AuthMixin:
|
|||
|
||||
class RoleMixin:
|
||||
class ROLE(ChoiceSet):
|
||||
ADMIN = choices.ADMIN, _('Super administrator')
|
||||
ADMIN = choices.ADMIN, _('System administrator')
|
||||
AUDITOR = choices.AUDITOR, _('System auditor')
|
||||
USER = choices.USER, _('User')
|
||||
AUDITOR = choices.AUDITOR, _('Super auditor')
|
||||
APP = 'App', _('Application')
|
||||
|
||||
role = ROLE.USER
|
||||
|
@ -164,15 +165,15 @@ class RoleMixin:
|
|||
def role_display(self):
|
||||
return self.get_role_display()
|
||||
|
||||
@property
|
||||
def org_role_display(self):
|
||||
@lazyproperty
|
||||
def org_roles(self):
|
||||
from orgs.models import ROLE as ORG_ROLE
|
||||
|
||||
if not current_org.is_real():
|
||||
if self.is_superuser:
|
||||
return ORG_ROLE.ADMIN.label
|
||||
return [ORG_ROLE.ADMIN]
|
||||
else:
|
||||
return ORG_ROLE.USER.label
|
||||
return [ORG_ROLE.USER]
|
||||
|
||||
if hasattr(self, 'gc_m2m_org_members__role'):
|
||||
names = self.gc_m2m_org_members__role
|
||||
|
@ -184,8 +185,24 @@ class RoleMixin:
|
|||
roles = set(self.m2m_org_members.filter(
|
||||
org_id=current_org.id
|
||||
).values_list('role', flat=True))
|
||||
roles = list(roles)
|
||||
roles.sort()
|
||||
return roles
|
||||
|
||||
return ' | '.join([str(ORG_ROLE[role]) for role in roles if role in ORG_ROLE])
|
||||
@lazyproperty
|
||||
def org_roles_label_list(self):
|
||||
from orgs.models import ROLE as ORG_ROLE
|
||||
return [str(ORG_ROLE[role]) for role in self.org_roles if role in ORG_ROLE]
|
||||
|
||||
@lazyproperty
|
||||
def org_role_display(self):
|
||||
return ' | '.join(self.org_roles_label_list)
|
||||
|
||||
@lazyproperty
|
||||
def total_role_display(self):
|
||||
roles = list({self.role_display, *self.org_roles_label_list})
|
||||
roles.sort()
|
||||
return ' | '.join(roles)
|
||||
|
||||
def current_org_roles(self):
|
||||
from orgs.models import OrganizationMember, ROLE as ORG_ROLE
|
||||
|
@ -314,12 +331,7 @@ class RoleMixin:
|
|||
def remove(self):
|
||||
if not current_org.is_real():
|
||||
return
|
||||
if self.can_user_current_org:
|
||||
current_org.users.remove(self)
|
||||
if self.can_admin_current_org:
|
||||
current_org.admins.remove(self)
|
||||
if self.can_audit_current_org:
|
||||
current_org.auditors.remove(self)
|
||||
OrganizationMember.objects.remove_users(current_org, [self])
|
||||
|
||||
|
||||
class TokenMixin:
|
||||
|
|
|
@ -7,7 +7,6 @@ from rest_framework import serializers
|
|||
|
||||
from common.utils import validate_ssh_public_key
|
||||
from common.mixins import CommonBulkSerializerMixin
|
||||
from common.serializers import AdaptedBulkListSerializer
|
||||
from common.permissions import CanUpdateDeleteUser
|
||||
from common.drf.fields import GroupConcatedPrimaryKeyRelatedField
|
||||
from orgs.models import ROLE as ORG_ROLE
|
||||
|
@ -51,17 +50,12 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
|
|||
login_blocked = serializers.SerializerMethodField()
|
||||
can_update = serializers.SerializerMethodField()
|
||||
can_delete = serializers.SerializerMethodField()
|
||||
org_role = serializers.ChoiceField(
|
||||
label=_('Organization role name'), write_only=True,
|
||||
allow_null=True, required=False, allow_blank=True,
|
||||
choices=ORG_ROLE.choices
|
||||
)
|
||||
total_role_display = serializers.SerializerMethodField(label=_('Total role name'))
|
||||
org_roles = serializers.ListField(label=_('Organization role name'), allow_null=True, required=False,
|
||||
child=serializers.ChoiceField(choices=ORG_ROLE.choices))
|
||||
key_prefix_block = "_LOGIN_BLOCK_{}"
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
list_serializer_class = AdaptedBulkListSerializer
|
||||
# mini 是指能识别对象的最小单元
|
||||
fields_mini = ['id', 'name', 'username']
|
||||
# small 指的是 不需要计算的直接能从一张表中获取到的数据
|
||||
|
@ -75,7 +69,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
|
|||
]
|
||||
fields = fields_small + [
|
||||
'groups', 'role', 'groups_display', 'role_display',
|
||||
'can_update', 'can_delete', 'login_blocked', 'org_role'
|
||||
'can_update', 'can_delete', 'login_blocked', 'org_roles'
|
||||
]
|
||||
|
||||
extra_kwargs = {
|
||||
|
@ -92,6 +86,7 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
|
|||
'source_display': {'label': _('Source name')},
|
||||
'org_role_display': {'label': _('Organization role name')},
|
||||
'role_display': {'label': _('Super role name')},
|
||||
'total_role_display': {'label': _('Total role name')}
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -110,9 +105,6 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
|
|||
choices.pop(User.ROLE.AUDITOR, None)
|
||||
role._choices = choices
|
||||
|
||||
def get_total_role_display(self, instance):
|
||||
return ' | '.join({str(instance.role_display), str(instance.org_role_display)})
|
||||
|
||||
def validate_role(self, value):
|
||||
request = self.context.get('request')
|
||||
if not request.user.is_superuser and value != User.ROLE.USER:
|
||||
|
|
Loading…
Reference in New Issue