diff --git a/apps/assets/api/node.py b/apps/assets/api/node.py index 4ffdbfe1a..f964b7704 100644 --- a/apps/assets/api/node.py +++ b/apps/assets/api/node.py @@ -127,9 +127,13 @@ class NodeChildrenApi(generics.ListCreateAPIView): def get_object(self): pk = self.kwargs.get('pk') or self.request.query_params.get('id') key = self.request.query_params.get("key") + if not pk and not key: - node = Node.org_root() self.is_initial = True + if current_org.is_root(): + node = None + else: + node = Node.org_root() return node if pk: node = get_object_or_404(Node, pk=pk) @@ -137,16 +141,26 @@ class NodeChildrenApi(generics.ListCreateAPIView): node = get_object_or_404(Node, key=key) return node + def get_org_root_queryset(self, query_all): + if query_all: + return Node.objects.all() + else: + return Node.org_root_nodes() + def get_queryset(self): query_all = self.request.query_params.get("all", "0") == "all" - if not self.instance: - return Node.objects.none() + + if self.is_initial and current_org.is_root(): + return self.get_org_root_queryset(query_all) if self.is_initial: with_self = True else: with_self = False + if not self.instance: + return Node.objects.none() + if query_all: queryset = self.instance.get_all_children(with_self=with_self) else: @@ -178,7 +192,7 @@ class NodeChildrenAsTreeApi(SerializeToTreeNodeMixin, NodeChildrenApi): def get_assets(self): include_assets = self.request.query_params.get('assets', '0') == '1' - if not include_assets: + if not self.instance or not include_assets: return [] assets = self.instance.get_assets().only( "id", "hostname", "ip", "os", "platform_id", @@ -240,7 +254,10 @@ class NodeRemoveAssetsApi(generics.UpdateAPIView): node.assets.remove(*assets) # 把孤儿资产添加到 root 节点 - orphan_assets = Asset.objects.filter(id__in=[a.id for a in assets], nodes__isnull=True).distinct() + orphan_assets = Asset.objects.filter( + id__in=[a.id for a in assets], + nodes__isnull=True + ).distinct() Node.org_root().assets.add(*orphan_assets) diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index eb326859b..27a2a7df6 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -40,7 +40,7 @@ def compute_parent_key(key): class NodeQuerySet(models.QuerySet): def delete(self): raise NotImplementedError - +# class FamilyMixin: __parents = None @@ -446,8 +446,9 @@ class SomeNodesMixin: @classmethod def default_node(cls): - with tmp_to_org(Organization.default()): - defaults = {'value': cls.default_value} + default_org = Organization.default() + with tmp_to_org(default_org): + defaults = {'value': default_org.name} try: obj, created = cls.objects.get_or_create( defaults=defaults, key=cls.default_key, @@ -482,25 +483,34 @@ class SomeNodesMixin: @classmethod def create_org_root_node(cls): - # 如果使用current_org 在set_current_org时会死循环 ori_org = get_current_org() with transaction.atomic(): - if not ori_org.is_real(): - return cls.default_node() key = cls.get_next_org_root_node_key() root = cls.objects.create(key=key, value=ori_org.name) return root @classmethod - def org_root(cls): - root = cls.objects.filter(parent_key='')\ - .filter(key__regex=r'^[0-9]+$')\ - .exclude(key__startswith='-')\ + def org_root_nodes(cls): + nodes = cls.objects.filter(parent_key='') \ + .filter(key__regex=r'^[0-9]+$') \ + .exclude(key__startswith='-') \ .order_by('key') - if root: - return root[0] + return nodes + + @classmethod + def org_root(cls): + org_roots = cls.org_root_nodes() + if org_roots: + return org_roots[0] + ori_org = get_current_org() + # 如果使用current_org 在set_current_org时会死循环 + if ori_org.is_root(): + root = cls.default_node() + elif ori_org.is_default(): + root = cls.default_node() else: - return cls.create_org_root_node() + root = cls.create_org_root_node() + return root @classmethod def initial_some_nodes(cls): @@ -519,9 +529,6 @@ class SomeNodesMixin: if not node_key1: logger.info("Not found node that `key` = 1") return - if not node_key1.org.is_real(): - logger.info("Org is not real for node that `key` = 1") - return with transaction.atomic(): with tmp_to_org(node_key1.org): diff --git a/apps/assets/tasks/nodes_amount.py b/apps/assets/tasks/nodes_amount.py index a7cb46a45..2f8f0592d 100644 --- a/apps/assets/tasks/nodes_amount.py +++ b/apps/assets/tasks/nodes_amount.py @@ -13,18 +13,20 @@ logger = get_logger(__file__) @shared_task -def check_node_assets_amount_task(orgid=None): - if orgid is None: - orgs = [*Organization.objects.all(), Organization.default()] +def check_node_assets_amount_task(org_id=None): + if org_id is None: + orgs = Organization.objects.all() else: - orgs = [Organization.get_instance(orgid)] + orgs = [Organization.get_instance(org_id)] for org in orgs: try: with tmp_to_org(org): check_node_assets_amount() except AcquireFailed: - logger.error(_('The task of self-checking is already running and cannot be started repeatedly')) + error = _('The task of self-checking is already running ' + 'and cannot be started repeatedly') + logger.error(error) @register_as_period_task(crontab='0 2 * * *') diff --git a/apps/common/permissions.py b/apps/common/permissions.py index 43779204c..7098cdb84 100644 --- a/apps/common/permissions.py +++ b/apps/common/permissions.py @@ -110,12 +110,17 @@ class PermissionsMixin(UserPassesTestMixin): return True -class UserCanUpdatePassword: +class UserCanUseCurrentOrg(permissions.BasePermission): + def has_permission(self, request, view): + return current_org.can_use_by(request.user) + + +class UserCanUpdatePassword(permissions.BasePermission): def has_permission(self, request, view): return request.user.can_update_password() -class UserCanUpdateSSHKey: +class UserCanUpdateSSHKey(permissions.BasePermission): def has_permission(self, request, view): return request.user.can_update_ssh_key() diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index ea2503cb9..f5ee34c63 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 6cd533e47..c8368dce6 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: JumpServer 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-01-26 17:25+0800\n" +"POT-Creation-Date: 2021-02-20 15:17+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -32,8 +32,8 @@ msgstr "远程应用" msgid "Custom" msgstr "自定义" -#: applications/models/application.py:10 assets/models/asset.py:149 -#: assets/models/base.py:234 assets/models/cluster.py:18 +#: applications/models/application.py:10 assets/models/asset.py:142 +#: assets/models/base.py:235 assets/models/cluster.py:18 #: assets/models/cmd_filter.py:21 assets/models/domain.py:21 #: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24 #: orgs/models.py:23 perms/models/base.py:48 settings/models.py:29 @@ -78,7 +78,7 @@ msgstr "类别" msgid "Type" msgstr "类型" -#: applications/models/application.py:19 assets/models/asset.py:198 +#: applications/models/application.py:19 assets/models/asset.py:191 #: assets/models/domain.py:27 assets/models/domain.py:55 msgid "Domain" msgstr "网域" @@ -89,8 +89,8 @@ msgstr "" # msgid "Date created" # msgstr "创建日期" -#: applications/models/application.py:23 assets/models/asset.py:154 -#: assets/models/asset.py:230 assets/models/base.py:239 +#: applications/models/application.py:23 assets/models/asset.py:147 +#: assets/models/asset.py:223 assets/models/base.py:240 #: assets/models/cluster.py:29 assets/models/cmd_filter.py:23 #: assets/models/cmd_filter.py:57 assets/models/domain.py:22 #: assets/models/domain.py:56 assets/models/group.py:23 @@ -125,16 +125,16 @@ msgstr "主机" #: applications/serializers/attrs/application_type/mysql_workbench.py:22 #: applications/serializers/attrs/application_type/oracle.py:11 #: applications/serializers/attrs/application_type/pgsql.py:11 -#: assets/models/asset.py:195 assets/models/domain.py:53 +#: assets/models/asset.py:188 assets/models/domain.py:53 msgid "Port" msgstr "端口" #: applications/serializers/attrs/application_category/remote_app.py:33 -#: assets/models/asset.py:363 assets/models/authbook.py:26 +#: assets/models/asset.py:355 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:191 audits/models.py:38 -#: perms/models/asset_permission.py:96 templates/index.html:82 +#: perms/models/asset_permission.py:99 templates/index.html:82 #: terminal/backends/command/models.py:19 #: terminal/backends/command/serializers.py:13 terminal/models/session.py:39 #: users/templates/users/user_asset_permission.html:40 @@ -161,7 +161,7 @@ msgstr "目标URL" #: applications/serializers/attrs/application_type/custom.py:21 #: applications/serializers/attrs/application_type/mysql_workbench.py:30 #: applications/serializers/attrs/application_type/vmware_client.py:26 -#: assets/models/base.py:235 assets/models/gathered_user.py:15 +#: assets/models/base.py:236 assets/models/gathered_user.py:15 #: audits/models.py:99 authentication/forms.py:11 #: authentication/templates/authentication/login.html:101 #: ops/models/adhoc.py:148 users/forms/profile.py:19 users/models/user.py:515 @@ -178,7 +178,7 @@ msgstr "用户名" #: applications/serializers/attrs/application_type/custom.py:25 #: applications/serializers/attrs/application_type/mysql_workbench.py:34 #: applications/serializers/attrs/application_type/vmware_client.py:30 -#: assets/models/base.py:236 assets/serializers/asset_user.py:71 +#: assets/models/base.py:237 assets/serializers/asset_user.py:71 #: audits/signals_handler.py:42 authentication/forms.py:13 #: authentication/templates/authentication/login.html:109 #: settings/serializers/settings.py:84 users/forms/user.py:22 @@ -204,7 +204,7 @@ msgid "Target url" msgstr "目标URL" #: applications/serializers/attrs/application_type/mysql_workbench.py:18 -#: assets/models/asset.py:190 assets/models/domain.py:52 +#: assets/models/asset.py:183 assets/models/domain.py:52 #: assets/serializers/asset_user.py:46 settings/serializers/settings.py:103 #: users/templates/users/_granted_assets.html:26 #: users/templates/users/user_asset_permission.html:156 @@ -219,15 +219,15 @@ msgstr "删除失败,存在关联资产" msgid "Number required" msgstr "需要为数字" -#: assets/api/node.py:67 +#: assets/api/node.py:60 msgid "You can't update the root node name" msgstr "不能修改根节点名称" -#: assets/api/node.py:74 +#: assets/api/node.py:67 msgid "You can't delete the root node ({})" msgstr "不能删除根节点 ({})" -#: assets/api/node.py:77 +#: assets/api/node.py:70 msgid "Deletion failed and the node contains children or assets" msgstr "删除失败,节点包含子节点或资产" @@ -239,137 +239,137 @@ msgstr "不能移除资产的管理用户账号" msgid "Latest version could not be delete" msgstr "最新版本的不能被删除" -#: assets/models/asset.py:150 xpack/plugins/cloud/providers/base.py:17 +#: assets/models/asset.py:143 xpack/plugins/cloud/providers/base.py:17 msgid "Base" msgstr "基础" -#: assets/models/asset.py:151 +#: assets/models/asset.py:144 msgid "Charset" msgstr "编码" -#: assets/models/asset.py:152 tickets/models/ticket.py:40 +#: assets/models/asset.py:145 tickets/models/ticket.py:40 msgid "Meta" msgstr "元数据" -#: assets/models/asset.py:153 +#: assets/models/asset.py:146 msgid "Internal" msgstr "内部的" -#: assets/models/asset.py:173 assets/models/asset.py:197 +#: assets/models/asset.py:166 assets/models/asset.py:190 #: assets/serializers/asset.py:66 msgid "Platform" msgstr "系统平台" -#: assets/models/asset.py:191 assets/serializers/asset_user.py:45 +#: assets/models/asset.py:184 assets/serializers/asset_user.py:45 #: assets/serializers/gathered_user.py:20 settings/serializers/settings.py:102 #: users/templates/users/_granted_assets.html:25 #: users/templates/users/user_asset_permission.html:157 msgid "Hostname" msgstr "主机名" -#: assets/models/asset.py:194 assets/models/domain.py:54 +#: assets/models/asset.py:187 assets/models/domain.py:54 #: assets/models/user.py:120 terminal/serializers/session.py:29 #: terminal/serializers/storage.py:69 msgid "Protocol" msgstr "协议" -#: assets/models/asset.py:196 assets/serializers/asset.py:68 +#: assets/models/asset.py:189 assets/serializers/asset.py:68 #: perms/serializers/asset/user_permission.py:41 msgid "Protocols" msgstr "协议组" -#: assets/models/asset.py:199 assets/models/user.py:115 -#: perms/models/asset_permission.py:97 +#: assets/models/asset.py:192 assets/models/user.py:115 +#: perms/models/asset_permission.py:100 #: xpack/plugins/change_auth_plan/models.py:56 #: xpack/plugins/gathered_user/models.py:24 msgid "Nodes" msgstr "节点" -#: assets/models/asset.py:200 assets/models/cmd_filter.py:22 +#: assets/models/asset.py:193 assets/models/cmd_filter.py:22 #: assets/models/domain.py:57 assets/models/label.py:22 #: authentication/models.py:46 msgid "Is active" msgstr "激活" -#: assets/models/asset.py:203 assets/models/cluster.py:19 +#: assets/models/asset.py:196 assets/models/cluster.py:19 #: assets/models/user.py:66 templates/_nav.html:44 #: xpack/plugins/cloud/models.py:143 xpack/plugins/cloud/serializers.py:137 msgid "Admin user" msgstr "管理用户" -#: assets/models/asset.py:206 +#: assets/models/asset.py:199 msgid "Public IP" msgstr "公网IP" -#: assets/models/asset.py:207 +#: assets/models/asset.py:200 msgid "Asset number" msgstr "资产编号" -#: assets/models/asset.py:210 +#: assets/models/asset.py:203 msgid "Vendor" msgstr "制造商" -#: assets/models/asset.py:211 +#: assets/models/asset.py:204 msgid "Model" msgstr "型号" -#: assets/models/asset.py:212 +#: assets/models/asset.py:205 msgid "Serial number" msgstr "序列号" -#: assets/models/asset.py:214 +#: assets/models/asset.py:207 msgid "CPU model" msgstr "CPU型号" -#: assets/models/asset.py:215 +#: assets/models/asset.py:208 msgid "CPU count" msgstr "CPU数量" -#: assets/models/asset.py:216 +#: assets/models/asset.py:209 msgid "CPU cores" msgstr "CPU核数" -#: assets/models/asset.py:217 +#: assets/models/asset.py:210 msgid "CPU vcpus" msgstr "CPU总数" -#: assets/models/asset.py:218 +#: assets/models/asset.py:211 msgid "Memory" msgstr "内存" -#: assets/models/asset.py:219 +#: assets/models/asset.py:212 msgid "Disk total" msgstr "硬盘大小" -#: assets/models/asset.py:220 +#: assets/models/asset.py:213 msgid "Disk info" msgstr "硬盘信息" -#: assets/models/asset.py:222 +#: assets/models/asset.py:215 msgid "OS" msgstr "操作系统" -#: assets/models/asset.py:223 +#: assets/models/asset.py:216 msgid "OS version" msgstr "系统版本" -#: assets/models/asset.py:224 +#: assets/models/asset.py:217 msgid "OS arch" msgstr "系统架构" -#: assets/models/asset.py:225 +#: assets/models/asset.py:218 msgid "Hostname raw" msgstr "主机名原始" -#: assets/models/asset.py:227 templates/_nav.html:46 +#: assets/models/asset.py:220 templates/_nav.html:46 msgid "Labels" msgstr "标签管理" -#: assets/models/asset.py:228 assets/models/base.py:242 +#: assets/models/asset.py:221 assets/models/base.py:243 #: 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:24 -#: orgs/models.py:427 perms/models/base.py:54 users/models/user.py:558 +#: orgs/models.py:412 perms/models/base.py:54 users/models/user.py:558 #: 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:58 #: xpack/plugins/cloud/models.py:156 xpack/plugins/gathered_user/models.py:30 @@ -378,12 +378,12 @@ msgstr "创建者" # msgid "Created by" # msgstr "创建者" -#: assets/models/asset.py:229 assets/models/base.py:240 +#: assets/models/asset.py:222 assets/models/base.py:241 #: assets/models/cluster.py:26 assets/models/domain.py:24 #: 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:29 orgs/models.py:25 -#: orgs/models.py:425 perms/models/base.py:55 users/models/group.py:18 +#: orgs/models.py:410 perms/models/base.py:55 users/models/group.py:18 #: users/templates/users/user_group_detail.html:58 #: xpack/plugins/cloud/models.py:61 xpack/plugins/cloud/models.py:159 msgid "Date created" @@ -405,21 +405,21 @@ msgstr "版本" msgid "AuthBook" msgstr "" -#: assets/models/base.py:237 xpack/plugins/change_auth_plan/models.py:72 +#: assets/models/base.py:238 xpack/plugins/change_auth_plan/models.py:72 #: xpack/plugins/change_auth_plan/models.py:197 #: xpack/plugins/change_auth_plan/models.py:292 msgid "SSH private key" msgstr "SSH密钥" -#: assets/models/base.py:238 xpack/plugins/change_auth_plan/models.py:75 +#: assets/models/base.py:239 xpack/plugins/change_auth_plan/models.py:75 #: xpack/plugins/change_auth_plan/models.py:193 #: xpack/plugins/change_auth_plan/models.py:288 msgid "SSH public key" msgstr "SSH公钥" -#: assets/models/base.py:241 assets/models/gathered_user.py:20 +#: assets/models/base.py:242 assets/models/gathered_user.py:20 #: common/db/models.py:70 common/mixins/models.py:51 ops/models/adhoc.py:39 -#: orgs/models.py:426 +#: orgs/models.py:411 msgid "Date updated" msgstr "更新日期" @@ -556,9 +556,9 @@ msgstr "默认资产组" #: assets/models/label.py:15 audits/models.py:36 audits/models.py:56 #: audits/models.py:69 audits/serializers.py:81 authentication/models.py:44 -#: authentication/models.py:95 orgs/models.py:18 orgs/models.py:423 -#: perms/models/asset_permission.py:173 perms/models/base.py:49 -#: templates/index.html:78 terminal/backends/command/models.py:18 +#: authentication/models.py:95 orgs/models.py:18 orgs/models.py:408 +#: perms/models/base.py:49 templates/index.html:78 +#: terminal/backends/command/models.py:18 #: terminal/backends/command/serializers.py:12 terminal/models/session.py:37 #: tickets/models/comment.py:17 users/forms/group.py:15 #: users/models/user.py:158 users/models/user.py:665 @@ -575,31 +575,31 @@ msgstr "默认资产组" msgid "User" msgstr "用户" -#: assets/models/label.py:19 assets/models/node.py:413 settings/models.py:30 +#: assets/models/label.py:19 assets/models/node.py:545 settings/models.py:30 msgid "Value" msgstr "值" -#: assets/models/node.py:143 +#: assets/models/node.py:152 msgid "New node" msgstr "新节点" -#: assets/models/node.py:316 users/templates/users/_granted_assets.html:130 +#: assets/models/node.py:450 users/templates/users/_granted_assets.html:130 msgid "empty" msgstr "空" -#: assets/models/node.py:412 perms/models/asset_permission.py:148 +#: assets/models/node.py:544 perms/models/asset_permission.py:156 msgid "Key" msgstr "键" -#: assets/models/node.py:414 +#: assets/models/node.py:546 msgid "Full value" msgstr "全称" -#: assets/models/node.py:417 perms/models/asset_permission.py:152 +#: assets/models/node.py:549 perms/models/asset_permission.py:157 msgid "Parent key" msgstr "ssh私钥" -#: assets/models/node.py:426 assets/serializers/system_user.py:190 +#: assets/models/node.py:557 assets/serializers/system_user.py:190 #: users/templates/users/user_asset_permission.html:41 #: users/templates/users/user_asset_permission.html:73 #: users/templates/users/user_asset_permission.html:158 @@ -668,7 +668,7 @@ msgstr "用户组" #: assets/models/user.py:221 audits/models.py:39 #: perms/models/application_permission.py:31 -#: perms/models/asset_permission.py:98 templates/_nav.html:45 +#: perms/models/asset_permission.py:101 templates/_nav.html:45 #: terminal/backends/command/models.py:20 #: terminal/backends/command/serializers.py:14 terminal/models/session.py:41 #: users/templates/users/_granted_assets.html:27 @@ -727,7 +727,7 @@ msgstr "硬件信息" msgid "Org name" msgstr "组织名称" -#: assets/serializers/asset.py:162 assets/serializers/asset.py:201 +#: assets/serializers/asset.py:162 assets/serializers/asset.py:194 msgid "Connectivity" msgstr "连接" @@ -873,11 +873,6 @@ msgstr "更新节点资产硬件信息: {}" msgid "Gather assets users" msgstr "收集资产上的用户" -#: assets/tasks/nodes_amount.py:21 -msgid "" -"The task of self-checking is already running and cannot be started repeatedly" -msgstr "自检程序已经在运行,不能重复启动" - #: assets/tasks/push_system_user.py:184 #: assets/tasks/system_user_connectivity.py:89 msgid "System user is dynamic: {}" @@ -1081,7 +1076,7 @@ msgstr "用户代理" #: authentication/templates/authentication/_mfa_confirm_modal.html:14 #: authentication/templates/authentication/login_otp.html:6 #: users/forms/profile.py:52 users/models/user.py:539 -#: users/serializers/user.py:232 users/templates/users/user_detail.html:77 +#: users/serializers/profile.py:102 users/templates/users/user_detail.html:77 #: users/templates/users/user_profile.html:87 msgid "MFA" msgstr "多因子认证" @@ -1355,7 +1350,7 @@ msgid "Show" msgstr "显示" #: authentication/templates/authentication/_access_key_modal.html:66 -#: users/models/user.py:443 users/serializers/user.py:229 +#: users/models/user.py:443 users/serializers/profile.py:99 #: users/templates/users/user_profile.html:94 #: users/templates/users/user_profile.html:163 #: users/templates/users/user_profile.html:166 @@ -1364,7 +1359,7 @@ msgid "Disable" msgstr "禁用" #: authentication/templates/authentication/_access_key_modal.html:67 -#: users/models/user.py:444 users/serializers/user.py:230 +#: users/models/user.py:444 users/serializers/profile.py:100 #: users/templates/users/user_profile.html:92 #: users/templates/users/user_profile.html:170 msgid "Enable" @@ -1605,7 +1600,7 @@ msgstr "不能包含特殊字符" msgid "

Flow service unavailable, check it

" msgstr "" -#: jumpserver/views/other.py:26 +#: jumpserver/views/other.py:27 msgid "" "
Luna is a separately deployed program, you need to deploy Luna, koko, " "configure nginx for url distribution,
If you see this page, " @@ -1614,11 +1609,11 @@ msgstr "" "
Luna是单独部署的一个程序,你需要部署luna,koko,
如果你看到了" "这个页面,证明你访问的不是nginx监听的端口,祝你好运
" -#: jumpserver/views/other.py:77 +#: jumpserver/views/other.py:78 msgid "Websocket server run on port: {}, you should proxy it on nginx" msgstr "Websocket 服务运行在端口: {}, 请检查nginx是否代理是否设置" -#: jumpserver/views/other.py:91 +#: jumpserver/views/other.py:92 msgid "" "
Koko is a separately deployed program, you need to deploy Koko, " "configure nginx for url distribution,
If you see this page, " @@ -1795,8 +1790,8 @@ msgstr "组织包含未删除的资源" msgid "The current organization cannot be deleted" msgstr "当前组织不能被删除" -#: orgs/mixins/models.py:56 orgs/mixins/serializers.py:25 orgs/models.py:41 -#: orgs/models.py:422 orgs/serializers.py:100 +#: orgs/mixins/models.py:53 orgs/mixins/serializers.py:25 orgs/models.py:39 +#: orgs/models.py:407 orgs/serializers.py:100 #: tickets/serializers/ticket/ticket.py:81 msgid "Organization" msgstr "组织" @@ -1809,7 +1804,11 @@ msgstr "组织管理员" msgid "Organization auditor" msgstr "组织审计员" -#: orgs/models.py:424 users/forms/user.py:27 users/models/user.py:527 +#: orgs/models.py:33 +msgid "GLOBAL" +msgstr "全局组织" + +#: orgs/models.py:409 users/forms/user.py:27 users/models/user.py:527 #: users/templates/users/_select_user_modal.html:15 #: users/templates/users/user_detail.html:73 #: users/templates/users/user_list.html:16 @@ -1817,7 +1816,7 @@ msgstr "组织审计员" msgid "Role" msgstr "角色" -#: perms/const.py:7 perms/utils/asset/user_permission.py:28 +#: perms/const.py:7 perms/models/asset_permission.py:189 msgid "Ungrouped" msgstr "未分组" @@ -1841,47 +1840,52 @@ msgstr "应用程序" msgid "Application permission" msgstr "应用管理" -#: perms/models/asset_permission.py:34 settings/serializers/settings.py:107 +#: perms/models/asset_permission.py:37 settings/serializers/settings.py:107 msgid "All" msgstr "全部" -#: perms/models/asset_permission.py:35 +#: perms/models/asset_permission.py:38 msgid "Connect" msgstr "连接" -#: perms/models/asset_permission.py:36 +#: perms/models/asset_permission.py:39 msgid "Upload file" msgstr "上传文件" -#: perms/models/asset_permission.py:37 +#: perms/models/asset_permission.py:40 msgid "Download file" msgstr "下载文件" -#: perms/models/asset_permission.py:38 +#: perms/models/asset_permission.py:41 msgid "Upload download" msgstr "上传下载" -#: perms/models/asset_permission.py:39 +#: perms/models/asset_permission.py:42 msgid "Clipboard copy" msgstr "剪贴板复制" -#: perms/models/asset_permission.py:40 +#: perms/models/asset_permission.py:43 msgid "Clipboard paste" msgstr "剪贴板粘贴" -#: perms/models/asset_permission.py:41 +#: perms/models/asset_permission.py:44 msgid "Clipboard copy paste" msgstr "剪贴板复制粘贴" -#: perms/models/asset_permission.py:99 perms/serializers/asset/permission.py:60 +#: perms/models/asset_permission.py:102 +#: perms/serializers/asset/permission.py:60 msgid "Actions" msgstr "动作" -#: perms/models/asset_permission.py:103 templates/_nav.html:78 +#: perms/models/asset_permission.py:106 templates/_nav.html:78 #: users/templates/users/_user_detail_nav_header.html:31 msgid "Asset permission" msgstr "资产授权" +#: perms/models/asset_permission.py:191 +msgid "Favorite" +msgstr "收藏夹" + #: perms/models/base.py:50 templates/_nav.html:21 users/forms/user.py:168 #: users/models/group.py:31 users/models/user.py:523 #: users/templates/users/_select_user_modal.html:16 @@ -1912,11 +1916,11 @@ msgid "" "permission type. ({})" msgstr "应用列表中包含与授权类型不同的应用。({})" -#: perms/serializers/asset/permission.py:58 users/serializers/user.py:80 +#: perms/serializers/asset/permission.py:58 users/serializers/user.py:65 msgid "Is expired" msgstr "是否过期" -#: perms/serializers/asset/permission.py:59 users/serializers/user.py:79 +#: perms/serializers/asset/permission.py:59 users/serializers/user.py:64 msgid "Is valid" msgstr "账户是否有效" @@ -1932,14 +1936,6 @@ msgstr "用户组数量" msgid "System users amount" msgstr "系统用户数量" -#: perms/utils/asset/user_permission.py:30 -msgid "Favorite" -msgstr "收藏夹" - -#: perms/utils/asset/user_permission.py:522 -msgid "Please wait while your data is being initialized" -msgstr "数据正在初始化,请稍等" - #: settings/api/common.py:24 msgid "Test mail sent to {}, please check" msgstr "邮件已经发送{}, 请检查" @@ -3054,7 +3050,7 @@ msgstr "索引" msgid "Doc type" msgstr "文档类型" -#: terminal/serializers/terminal.py:44 terminal/serializers/terminal.py:52 +#: terminal/serializers/terminal.py:47 terminal/serializers/terminal.py:55 msgid "Not found" msgstr "没有发现" @@ -3530,8 +3526,8 @@ msgid "Public key should not be the same as your old one." msgstr "不能和原来的密钥相同" #: users/forms/profile.py:137 users/forms/user.py:90 -#: users/serializers/user.py:192 users/serializers/user.py:277 -#: users/serializers/user.py:335 +#: users/serializers/profile.py:74 users/serializers/profile.py:147 +#: users/serializers/profile.py:160 msgid "Not a valid ssh public key" msgstr "SSH密钥不合法" @@ -3555,15 +3551,15 @@ msgstr "添加到用户组" msgid "* Your password does not meet the requirements" msgstr "* 您的密码不符合要求" -#: users/forms/user.py:124 users/serializers/user.py:35 +#: users/forms/user.py:124 users/serializers/user.py:20 msgid "Reset link will be generated and sent to the user" msgstr "生成重置密码链接,通过邮件发送给用户" -#: users/forms/user.py:125 users/serializers/user.py:36 +#: users/forms/user.py:125 users/serializers/user.py:21 msgid "Set password" msgstr "设置密码" -#: users/forms/user.py:132 users/serializers/user.py:43 +#: users/forms/user.py:132 users/serializers/user.py:28 #: xpack/plugins/change_auth_plan/models.py:61 #: xpack/plugins/change_auth_plan/serializers.py:30 msgid "Password strategy" @@ -3605,75 +3601,75 @@ msgstr "管理员" msgid "Administrator is the super user of system" msgstr "Administrator是初始的超级管理员" -#: users/serializers/user.py:45 -msgid "MFA level for display" -msgstr "多因子认证等级(显示名称)" - -#: users/serializers/user.py:46 -msgid "Login blocked" -msgstr "登录被阻塞" - -#: users/serializers/user.py:47 -msgid "Can update" -msgstr "是否可更新" - -#: users/serializers/user.py:48 -msgid "Can delete" -msgstr "是否可删除" - -#: users/serializers/user.py:49 users/serializers/user.py:85 -msgid "Organization role name" -msgstr "组织角色名称" - -#: users/serializers/user.py:78 users/serializers/user.py:248 -msgid "Is first login" -msgstr "首次登录" - -#: users/serializers/user.py:81 -msgid "Avatar url" -msgstr "头像路径" - -#: users/serializers/user.py:83 -msgid "Groups name" -msgstr "用户组名" - -#: users/serializers/user.py:84 -msgid "Source name" -msgstr "用户来源名" - -#: users/serializers/user.py:86 -msgid "Super role name" -msgstr "超级角色名称" - -#: users/serializers/user.py:87 -msgid "Total role name" -msgstr "汇总角色名称" - -#: users/serializers/user.py:88 -msgid "MFA enabled" -msgstr "是否开启多因子认证" - -#: users/serializers/user.py:89 -msgid "MFA force enabled" -msgstr "强制启用多因子认证" - -#: users/serializers/user.py:112 -msgid "Role limit to {}" -msgstr "角色只能为 {}" - -#: users/serializers/user.py:124 users/serializers/user.py:301 -msgid "Password does not match security rules" -msgstr "密码不满足安全规则" - -#: users/serializers/user.py:293 +#: users/serializers/profile.py:32 msgid "The old password is incorrect" msgstr "旧密码错误" -#: users/serializers/user.py:307 +#: users/serializers/profile.py:40 users/serializers/user.py:109 +msgid "Password does not match security rules" +msgstr "密码不满足安全规则" + +#: users/serializers/profile.py:46 msgid "The newly set password is inconsistent" msgstr "两次密码不一致" -#: users/serializers_v2/user.py:36 +#: users/serializers/profile.py:118 users/serializers/user.py:63 +msgid "Is first login" +msgstr "首次登录" + +#: users/serializers/user.py:30 +msgid "MFA level for display" +msgstr "多因子认证等级(显示名称)" + +#: users/serializers/user.py:31 +msgid "Login blocked" +msgstr "登录被阻塞" + +#: users/serializers/user.py:32 +msgid "Can update" +msgstr "是否可更新" + +#: users/serializers/user.py:33 +msgid "Can delete" +msgstr "是否可删除" + +#: users/serializers/user.py:34 users/serializers/user.py:70 +msgid "Organization role name" +msgstr "组织角色名称" + +#: users/serializers/user.py:66 +msgid "Avatar url" +msgstr "头像路径" + +#: users/serializers/user.py:68 +msgid "Groups name" +msgstr "用户组名" + +#: users/serializers/user.py:69 +msgid "Source name" +msgstr "用户来源名" + +#: users/serializers/user.py:71 +msgid "Super role name" +msgstr "超级角色名称" + +#: users/serializers/user.py:72 +msgid "Total role name" +msgstr "汇总角色名称" + +#: users/serializers/user.py:73 +msgid "MFA enabled" +msgstr "是否开启多因子认证" + +#: users/serializers/user.py:74 +msgid "MFA force enabled" +msgstr "强制启用多因子认证" + +#: users/serializers/user.py:97 +msgid "Role limit to {}" +msgstr "角色只能为 {}" + +#: users/serializers/user.py:210 msgid "name not unique" msgstr "名称重复" @@ -4891,3 +4887,11 @@ msgstr "旗舰版" #: xpack/plugins/license/models.py:77 msgid "Community edition" msgstr "社区版" + +#~ msgid "" +#~ "The task of self-checking is already running and cannot be started " +#~ "repeatedly" +#~ msgstr "自检程序已经在运行,不能重复启动" + +#~ msgid "Please wait while your data is being initialized" +#~ msgstr "数据正在初始化,请稍等" diff --git a/apps/orgs/api.py b/apps/orgs/api.py index 1a6545f0b..618ebe9ed 100644 --- a/apps/orgs/api.py +++ b/apps/orgs/api.py @@ -5,14 +5,17 @@ from django.utils.translation import ugettext as _ from rest_framework import status from rest_framework.views import Response from rest_framework_bulk import BulkModelViewSet +from rest_framework.generics import RetrieveAPIView +from rest_framework.exceptions import PermissionDenied -from common.permissions import IsSuperUserOrAppUser +from common.permissions import IsSuperUserOrAppUser, IsValidUser, UserCanUseCurrentOrg from common.drf.api import JMSBulkRelationModelViewSet from .models import Organization, ROLE from .serializers import ( OrgSerializer, OrgReadSerializer, OrgRetrieveSerializer, OrgMemberSerializer, - OrgMemberAdminSerializer, OrgMemberUserSerializer + OrgMemberAdminSerializer, OrgMemberUserSerializer, + CurrentOrgSerializer ) from users.models import User, UserGroup from assets.models import Asset, Domain, AdminUser, SystemUser, Label @@ -129,3 +132,11 @@ class OrgMemberUserRelationBulkViewSet(JMSBulkRelationModelViewSet): objs = list(queryset.all().prefetch_related('user', 'org')) queryset.delete() self.send_m2m_changed_signal(objs, action='post_remove') + + +class CurrentOrgDetailApi(RetrieveAPIView): + serializer_class = CurrentOrgSerializer + permission_classes = (IsValidUser, UserCanUseCurrentOrg) + + def get_object(self): + return current_org diff --git a/apps/orgs/caches.py b/apps/orgs/caches.py index 462b13594..b7e086d6a 100644 --- a/apps/orgs/caches.py +++ b/apps/orgs/caches.py @@ -33,12 +33,12 @@ class OrgResourceStatisticsCache(OrgRelatedCache): return self.org def compute_users_amount(self): - if self.org.is_real(): + if self.org.is_root(): + users_amount = User.objects.all().count() + else: users_amount = OrganizationMember.objects.values( 'user_id' ).filter(org_id=self.org.id).distinct().count() - else: - users_amount = User.objects.all().distinct().count() return users_amount def compute_assets_amount(self): diff --git a/apps/orgs/migrations/0010_auto_20210219_1241.py b/apps/orgs/migrations/0010_auto_20210219_1241.py new file mode 100644 index 000000000..70a4463f1 --- /dev/null +++ b/apps/orgs/migrations/0010_auto_20210219_1241.py @@ -0,0 +1,56 @@ +# Generated by Django 3.1 on 2021-02-19 04:41 + +import time +from django.db import migrations + + +default_id = '00000000-0000-0000-0000-000000000001' + + +def add_default_org(apps, schema_editor): + org_cls = apps.get_model('orgs', 'Organization') + defaults = {'name': 'DEFAULT', 'id': default_id} + org_cls.objects.get_or_create(defaults=defaults, id=default_id) + + +def migrate_default_org_id(apps, schema_editor): + org_app_models = [ + ('applications', ['Application']), + ('assets', [ + 'AdminUser', 'Asset', 'AuthBook', 'CommandFilter', + 'CommandFilterRule', 'Domain', 'Gateway', 'GatheredUser', + 'Label', 'Node', 'SystemUser' + ]), + ('audits', ['FTPLog', 'OperateLog']), + ('ops', ['AdHoc', 'AdHocExecution', 'CommandExecution', 'Task']), + ('perms', ['ApplicationPermission', 'AssetPermission', 'UserAssetGrantedTreeNodeRelation']), + ('terminal', ['Session', 'Command']), + ('tickets', ['Ticket']), + ('users', ['UserGroup']), + ('xpack', [ + 'Account', 'SyncInstanceDetail', 'SyncInstanceTask', 'SyncInstanceTaskExecution', + 'ChangeAuthPlan', 'ChangeAuthPlanExecution', 'ChangeAuthPlanTask', + 'GatherUserTask', 'GatherUserTaskExecution', + ]), + ] + print("") + for app, models_name in org_app_models: + for model_name in models_name: + t_start = time.time() + print("Migrate model org id: {}".format(model_name), end='') + model_cls = apps.get_model(app, model_name) + model_cls.objects.filter(org_id='').update(org_id=default_id) + interval = round((time.time() - t_start) * 1000, 2) + print(" done, use {} ms".format(interval)) + + +class Migration(migrations.Migration): + + dependencies = [ + ('orgs', '0009_auto_20201023_1628'), + ] + + operations = [ + migrations.RunPython(add_default_org), + migrations.RunPython(migrate_default_org_id) + ] diff --git a/apps/orgs/mixins/models.py b/apps/orgs/mixins/models.py index c0823bb74..dd967757f 100644 --- a/apps/orgs/mixins/models.py +++ b/apps/orgs/mixins/models.py @@ -23,14 +23,11 @@ class OrgManager(models.Manager): def all_group_by_org(self): from ..models import Organization orgs = list(Organization.objects.all()) - orgs.append(Organization.default()) querysets = {} for org in orgs: - if org.is_real(): - org_id = org.id - else: - org_id = '' - querysets[org] = super(OrgManager, self).get_queryset().filter(org_id=org_id) + org_id = org.id + queryset = super(OrgManager, self).get_queryset().filter(org_id=org_id) + querysets[org] = queryset return querysets def get_queryset(self): @@ -53,12 +50,11 @@ class OrgModelMixin(models.Model): def save(self, *args, **kwargs): org = get_current_org() - if org is None: - return super().save(*args, **kwargs) - if org.is_real() or org.is_system(): + if org.is_root(): + if not self.org_id: + raise ValidationError('Please save in a organization') + else: self.org_id = org.id - elif org.is_default(): - self.org_id = '' return super().save(*args, **kwargs) @property @@ -78,10 +74,7 @@ class OrgModelMixin(models.Model): name = self.name elif hasattr(self, 'hostname'): name = self.hostname - if self.org.is_real(): - return name + self.sep + self.org_name - else: - return name + return name + self.sep + self.org_name def validate_unique(self, exclude=None): """ @@ -89,7 +82,7 @@ class OrgModelMixin(models.Model): failed. Form 提交时会使用这个检验 """ - self.org_id = current_org.id if current_org.is_real() else '' + self.org_id = current_org.id if exclude and 'org_id' in exclude: exclude.remove('org_id') unique_checks, date_checks = self._get_unique_checks(exclude=exclude) diff --git a/apps/orgs/models.py b/apps/orgs/models.py index 4d3850181..2c9e85591 100644 --- a/apps/orgs/models.py +++ b/apps/orgs/models.py @@ -30,11 +30,9 @@ class Organization(models.Model): orgs = None CACHE_PREFIX = 'JMS_ORG_{}' ROOT_ID = '00000000-0000-0000-0000-000000000000' - ROOT_NAME = 'ROOT' - DEFAULT_ID = 'DEFAULT' + ROOT_NAME = _('GLOBAL') + DEFAULT_ID = '00000000-0000-0000-0000-000000000001' DEFAULT_NAME = 'DEFAULT' - SYSTEM_ID = '00000000-0000-0000-0000-000000000002' - SYSTEM_NAME = 'SYSTEM' _user_admin_orgs = None class Meta: @@ -69,8 +67,6 @@ class Organization(models.Model): return cls.default() elif id_or_name in [cls.ROOT_ID, cls.ROOT_NAME]: return cls.root() - elif id_or_name in [cls.SYSTEM_ID, cls.SYSTEM_NAME]: - return cls.system() try: if is_uuid(id_or_name): @@ -87,7 +83,7 @@ class Organization(models.Model): def get_org_members_by_role(self, role): from users.models import User - if self.is_real(): + if not self.is_root(): return self.members.filter(m2m_org_members__role=role) users = User.objects.filter(role=role) return users @@ -105,20 +101,14 @@ class Organization(models.Model): return self.get_org_members_by_role(ROLE.AUDITOR) def org_id(self): - if self.is_real(): - return self.id - elif self.is_root(): - return self.ROOT_ID - else: - return '' + return self.id def get_members(self, exclude=()): from users.models import User - if self.is_real(): - members = self.members.exclude(m2m_org_members__role__in=exclude) - else: + if self.is_root(): members = User.objects.exclude(role__in=exclude) - + else: + members = self.members.exclude(m2m_org_members__role__in=exclude) return members.exclude(role=User.ROLE.APP).distinct() def can_admin_by(self, user): @@ -129,20 +119,19 @@ class Organization(models.Model): return False def can_audit_by(self, user): - if user.is_super_auditor: + if user.is_superuser or user.is_super_auditor: return True if self.auditors.filter(id=user.id).exists(): return True return False - def can_user_by(self, user): + def can_use_by(self, user): + if user.is_superuser or user.is_super_auditor: + return True if self.users.filter(id=user.id).exists(): return True return False - def is_real(self): - return self.id not in (self.DEFAULT_NAME, self.ROOT_ID, self.SYSTEM_ID) - @classmethod def get_user_orgs_by_role(cls, user, role): if not isinstance(role, (tuple, list)): @@ -165,7 +154,7 @@ class Organization(models.Model): if user.is_anonymous: return cls.objects.none() if user.is_superuser: - return [*cls.objects.all(), cls.default()] + return [cls.root(), *cls.objects.all()] return cls.get_user_orgs_by_role(user, ROLE.ADMIN) @classmethod @@ -182,7 +171,7 @@ class Organization(models.Model): if user.is_anonymous: return cls.objects.none() if user.is_super_auditor: - return [*cls.objects.all(), cls.default()] + return [cls.root(), *cls.objects.all()] return cls.get_user_orgs_by_role(user, ROLE.AUDITOR) @classmethod @@ -190,29 +179,24 @@ class Organization(models.Model): if user.is_anonymous: return cls.objects.none() if user.is_superuser or user.is_super_auditor: - return [*cls.objects.all(), cls.default()] + return [cls.root(), *cls.objects.all()] return cls.get_user_orgs_by_role(user, (ROLE.AUDITOR, ROLE.ADMIN)) @classmethod def default(cls): - return cls(id=cls.DEFAULT_ID, name=cls.DEFAULT_NAME) + defaults = dict(name=cls.DEFAULT_NAME, id=cls.DEFAULT_ID) + obj, created = cls.objects.get_or_create(defaults=defaults, id=cls.DEFAULT_ID) + return obj @classmethod def root(cls): return cls(id=cls.ROOT_ID, name=cls.ROOT_NAME) - @classmethod - def system(cls): - return cls(id=cls.SYSTEM_ID, name=cls.SYSTEM_NAME) - def is_root(self): - return self.id is self.ROOT_ID + return self.id == self.ROOT_ID def is_default(self): - return self.id is self.DEFAULT_ID - - def is_system(self): - return self.id is self.SYSTEM_ID + return str(self.id) == self.DEFAULT_ID def change_to(self): from .utils import set_current_org @@ -282,7 +266,7 @@ class UserRoleMapper(dict): self[ROLE.AUDITOR] = self.auditors -class OrgMemeberManager(models.Manager): +class OrgMemberManager(models.Manager): def remove_users(self, org, users): from users.models import User @@ -337,8 +321,11 @@ class OrgMemeberManager(models.Manager): _user = _user.id 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=User, pk_set=_users2pks_if_need(users, admins, auditors), using=self.db) + pk_set = _users2pks_if_need(users, admins, auditors) + 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_add') self.bulk_create(oms_add, ignore_conflicts=True) @@ -429,7 +416,7 @@ class OrganizationMember(models.Model): date_updated = models.DateTimeField(auto_now=True, verbose_name=_("Date updated")) created_by = models.CharField(max_length=128, null=True, verbose_name=_('Created by')) - objects = OrgMemeberManager() + objects = OrgMemberManager() class Meta: unique_together = [('org', 'user', 'role')] diff --git a/apps/orgs/serializers.py b/apps/orgs/serializers.py index e167aa525..482c622e1 100644 --- a/apps/orgs/serializers.py +++ b/apps/orgs/serializers.py @@ -38,7 +38,8 @@ class OrgSerializer(ModelSerializer): list_serializer_class = AdaptedBulkListSerializer fields_mini = ['id', 'name'] fields_small = fields_mini + [ - 'created_by', 'date_created', 'comment', 'resource_statistics' + 'is_default', 'is_root', 'comment', + 'created_by', 'date_created', 'resource_statistics' ] fields_m2m = ['users', 'admins', 'auditors'] @@ -127,3 +128,9 @@ class OrgRetrieveSerializer(OrgReadSerializer): class Meta(OrgReadSerializer.Meta): pass + + +class CurrentOrgSerializer(ModelSerializer): + class Meta: + model = Organization + fields = ['id', 'name', 'is_default', 'is_root', 'comment'] diff --git a/apps/orgs/urls/api_urls.py b/apps/orgs/urls/api_urls.py index d8533bb87..61fad175e 100644 --- a/apps/orgs/urls/api_urls.py +++ b/apps/orgs/urls/api_urls.py @@ -1,28 +1,26 @@ # -*- coding: utf-8 -*- # -from django.urls import re_path -from rest_framework.routers import DefaultRouter +from django.urls import path from rest_framework_bulk.routes import BulkRouter -from common import api as capi from .. import api app_name = 'orgs' -router = DefaultRouter() -bulk_router = BulkRouter() +router = BulkRouter() router.register(r'orgs', api.OrgViewSet, 'org') -bulk_router.register(r'org-member-relation', api.OrgMemberRelationBulkViewSet, 'org-member-relation') +router.register(r'org-member-relation', api.OrgMemberRelationBulkViewSet, 'org-member-relation') router.register(r'orgs/(?P[0-9a-zA-Z\-]{36})/membership/admins', api.OrgMemberAdminRelationBulkViewSet, 'membership-admins') router.register(r'orgs/(?P[0-9a-zA-Z\-]{36})/membership/users', api.OrgMemberUserRelationBulkViewSet, 'membership-users'), -old_version_urlpatterns = [ - re_path('(?Porg)/.*', capi.redirect_plural_name_api) + +urlpatterns = [ + path('orgs/current/', api.CurrentOrgDetailApi.as_view(), name='current-org-detail'), ] -urlpatterns = router.urls + bulk_router.urls + old_version_urlpatterns +urlpatterns += router.urls diff --git a/apps/orgs/utils.py b/apps/orgs/utils.py index de9e2982c..56f22ac86 100644 --- a/apps/orgs/utils.py +++ b/apps/orgs/utils.py @@ -68,12 +68,8 @@ def get_current_org_id(): def construct_org_mapper(): orgs = Organization.objects.all() org_mapper = {str(org.id): org for org in orgs} - default_org = Organization.default() org_mapper.update({ - '': default_org, - Organization.DEFAULT_ID: default_org, Organization.ROOT_ID: Organization.root(), - Organization.SYSTEM_ID: Organization.system() }) return org_mapper @@ -137,11 +133,9 @@ def get_org_filters(): _current_org = get_current_org() if _current_org is None: return kwargs - - if _current_org.is_real(): - kwargs['org_id'] = _current_org.id - elif _current_org.is_default(): - kwargs["org_id"] = '' + if _current_org.is_root(): + return kwargs + kwargs['org_id'] = _current_org.id return kwargs diff --git a/apps/terminal/models/session.py b/apps/terminal/models/session.py index b35a618bc..b440d2f1e 100644 --- a/apps/terminal/models/session.py +++ b/apps/terminal/models/session.py @@ -168,7 +168,7 @@ class Session(OrgModelMixin): from common.utils.random import random_datetime, random_ip org = get_current_org() - if not org or not org.is_real(): + if not org or org.is_root(): Organization.default().change_to() i = 0 users = User.objects.all()[:100] diff --git a/apps/users/api/mixins.py b/apps/users/api/mixins.py index 0e81bd8d2..23425aa0e 100644 --- a/apps/users/api/mixins.py +++ b/apps/users/api/mixins.py @@ -8,7 +8,7 @@ from orgs.utils import current_org class UserQuerysetMixin: def get_queryset(self): - if self.request.query_params.get('all') or not current_org.is_real(): + if self.request.query_params.get('all') or current_org.is_root(): queryset = User.objects.exclude(role=User.ROLE.APP) else: queryset = utils.get_current_org_members() diff --git a/apps/users/api/profile.py b/apps/users/api/profile.py index 473ad3819..a9123047a 100644 --- a/apps/users/api/profile.py +++ b/apps/users/api/profile.py @@ -2,6 +2,7 @@ import uuid from rest_framework import generics +from common.permissions import IsOrgAdmin from rest_framework.permissions import IsAuthenticated from django.conf import settings @@ -23,7 +24,7 @@ __all__ = [ class UserResetPasswordApi(UserQuerysetMixin, generics.UpdateAPIView): queryset = User.objects.all() serializer_class = serializers.UserSerializer - permission_classes = (IsAuthenticated,) + permission_classes = (IsOrgAdmin,) def perform_update(self, serializer): # Note: we are not updating the user object here. @@ -37,7 +38,7 @@ class UserResetPasswordApi(UserQuerysetMixin, generics.UpdateAPIView): class UserResetPKApi(UserQuerysetMixin, generics.UpdateAPIView): serializer_class = serializers.UserSerializer - permission_classes = (IsAuthenticated,) + permission_classes = (IsOrgAdmin,) def perform_update(self, serializer): from ..utils import send_reset_ssh_key_mail diff --git a/apps/users/api/user.py b/apps/users/api/user.py index 7e4d60646..488c699c3 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -48,7 +48,7 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): queryset = super().get_queryset().prefetch_related( 'groups' ) - if current_org.is_real(): + if not current_org.is_root(): # 为在列表中计算用户在真实组织里的角色 queryset = queryset.prefetch_related( Prefetch( @@ -67,7 +67,7 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): @staticmethod def set_users_to_org(users, org_roles, update=False): # 只有真实存在的组织才真正关联用户 - if not current_org or not current_org.is_real(): + if not current_org or current_org.is_root(): return for user, roles in zip(users, org_roles): if update and roles is None: @@ -94,7 +94,7 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): return super().get_permissions() def perform_destroy(self, instance): - if current_org.is_real(): + if not current_org.is_root(): instance.remove() else: return super().perform_destroy(instance) @@ -150,7 +150,7 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet): data = request.data if not isinstance(data, list): data = [request.data] - if not current_org or not current_org.is_real(): + if not current_org or current_org.is_root(): error = {"error": "Not a valid org"} return Response(error, status=400) diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 50099253d..bbacd998b 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -169,20 +169,21 @@ class RoleMixin: def org_roles(self): from orgs.models import ROLE as ORG_ROLE - if not current_org.is_real(): - # 不是真实的组织,取 User 本身的角色 + if current_org.is_root(): + # root 组织, 取 User 本身的角色 if self.is_superuser: - return [ORG_ROLE.ADMIN] + roles = [ORG_ROLE.ADMIN] + elif self.is_super_auditor: + roles = [ORG_ROLE.AUDITOR] else: - return [ORG_ROLE.USER] - - # 是真实组织,取 OrganizationMember 中的角色 - roles = [ - org_member.role - for org_member in self.m2m_org_members.all() - if org_member.org_id == current_org.id - ] - roles.sort() + roles = [ORG_ROLE.USER] + else: + # 是真实组织, 取 OrganizationMember 中的角色 + roles = [ + org_member.role for org_member in self.m2m_org_members.all() + if org_member.org_id == current_org.id + ] + roles.sort() return roles @lazyproperty @@ -202,7 +203,7 @@ class RoleMixin: def current_org_roles(self): from orgs.models import OrganizationMember, ROLE as ORG_ROLE - if not current_org.is_real(): + if current_org.is_root(): if self.is_superuser: return [ORG_ROLE.ADMIN] else: @@ -297,7 +298,7 @@ class RoleMixin: @lazyproperty def can_user_current_org(self): - return current_org.can_user_by(self) + return current_org.can_use_by(self) @lazyproperty def can_admin_or_audit_current_org(self): @@ -325,7 +326,7 @@ class RoleMixin: return app, access_key def remove(self): - if not current_org.is_real(): + if current_org.is_root(): return org = Organization.get_instance(current_org.id) OrganizationMember.objects.remove_users(org, [self])