diff --git a/apps/assets/api/asset_user.py b/apps/assets/api/asset_user.py index ce5930a26..c0d834737 100644 --- a/apps/assets/api/asset_user.py +++ b/apps/assets/api/asset_user.py @@ -105,7 +105,7 @@ class AssetUserViewSet(CommonApiMixin, BulkModelViewSet): class AssetUserAuthInfoViewSet(AssetUserViewSet): serializer_classes = {"default": serializers.AssetUserAuthInfoSerializer} - http_method_names = ['get'] + http_method_names = ['get', 'post'] permission_classes = [IsOrgAdminOrAppUser] def get_permissions(self): diff --git a/apps/assets/api/system_user_relation.py b/apps/assets/api/system_user_relation.py index 02dd887a1..69605b74a 100644 --- a/apps/assets/api/system_user_relation.py +++ b/apps/assets/api/system_user_relation.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # +from collections import defaultdict from django.db.models import F, Value +from django.db.models.signals import m2m_changed from django.db.models.functions import Concat from common.permissions import IsOrgAdmin @@ -26,6 +28,34 @@ class RelationMixin: )) return queryset + def send_post_add_signal(self, instance): + if not isinstance(instance, list): + instance = [instance] + + system_users_objects_map = defaultdict(list) + model, object_field = self.get_objects_attr() + + for i in instance: + _id = getattr(i, object_field).id + system_users_objects_map[i.systemuser].append(_id) + + sender = self.get_sender() + for system_user, objects in system_users_objects_map.items(): + m2m_changed.send( + sender=sender, instance=system_user, action='post_add', + reverse=False, model=model, pk_set=objects + ) + + def get_sender(self): + return self.model + + def get_objects_attr(self): + return models.Asset, 'asset' + + def perform_create(self, serializer): + instance = serializer.save() + self.send_post_add_signal(instance) + class BaseRelationViewSet(RelationMixin, OrgBulkModelViewSet): pass @@ -43,6 +73,9 @@ class SystemUserAssetRelationViewSet(BaseRelationViewSet): "systemuser__name", "systemuser__username" ] + def get_objects_attr(self): + return models.Asset, 'asset' + def get_queryset(self): queryset = super().get_queryset() queryset = queryset.annotate( @@ -65,6 +98,9 @@ class SystemUserNodeRelationViewSet(BaseRelationViewSet): "node__value", "systemuser__name", "systemuser_username" ] + def get_objects_attr(self): + return models.Node, 'node' + def get_queryset(self): queryset = super().get_queryset() queryset = queryset \ @@ -84,6 +120,10 @@ class SystemUserUserRelationViewSet(BaseRelationViewSet): "systemuser__name", "systemuser__username", ] + def get_objects_attr(self): + from users.models import User + return User, 'user' + def get_queryset(self): queryset = super().get_queryset() queryset = queryset.annotate( diff --git a/apps/assets/backends/db.py b/apps/assets/backends/db.py index 7cdba2754..35be8b9fd 100644 --- a/apps/assets/backends/db.py +++ b/apps/assets/backends/db.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # +from django.utils.translation import ugettext as _ from functools import reduce from django.db.models import F, CharField, Value, IntegerField, Q, Count from django.db.models.functions import Concat @@ -240,7 +241,7 @@ class AdminUserBackend(DBBackend): ) def _perform_delete_by_union_id(self, union_id_cleaned): - raise PermissionError("Could remove asset admin user") + raise PermissionError(_("Could not remove asset admin user")) def all(self): qs = self.model.objects.all().annotate( @@ -301,7 +302,7 @@ class AuthbookBackend(DBBackend): authbook_id, asset_id = union_id_cleaned authbook = get_object_or_none(AuthBook, pk=authbook_id) if authbook.is_latest: - raise PermissionError("Latest version could be delete") + raise PermissionError(_("Latest version could not be delete")) AuthBook.objects.filter(id=authbook_id).delete() def all(self): diff --git a/apps/assets/signals_handler.py b/apps/assets/signals_handler.py index 696732fc8..3bf185bc4 100644 --- a/apps/assets/signals_handler.py +++ b/apps/assets/signals_handler.py @@ -16,6 +16,8 @@ from .tasks import ( update_assets_hardware_info_util, test_asset_connectivity_util, push_system_user_to_assets, + push_system_user_to_assets_manual, + push_system_user_to_assets, add_nodes_assets_to_system_users ) @@ -95,6 +97,25 @@ def on_system_user_assets_change(sender, instance=None, action='', model=None, p push_system_user_to_assets.delay(system_user, assets) +@receiver(m2m_changed, sender=SystemUser.users.through) +def on_system_user_users_change(sender, instance=None, action='', model=None, pk_set=None, **kwargs): + """ + 当系统用户和用户关系发生变化时,应该重新推送系统用户资产中 + """ + if action != "post_add": + return + if not instance.username_same_with_user: + return + logger.debug("System user users change signal recv: {}".format(instance)) + queryset = model.objects.filter(pk__in=pk_set) + if model == SystemUser: + system_users = queryset + else: + system_users = [instance] + for s in system_users: + push_system_user_to_assets_manual.delay(s) + + @receiver(m2m_changed, sender=SystemUser.nodes.through) def on_system_user_nodes_change(sender, instance=None, action=None, model=None, pk_set=None, **kwargs): """ diff --git a/apps/assets/tasks/push_system_user.py b/apps/assets/tasks/push_system_user.py index 961f24a01..eb3978178 100644 --- a/apps/assets/tasks/push_system_user.py +++ b/apps/assets/tasks/push_system_user.py @@ -121,7 +121,6 @@ def get_push_windows_system_user_tasks(system_user, username=None): ''.format(username, username, password), } } - print(task) tasks.append(task) return tasks @@ -193,10 +192,10 @@ def push_system_user_util(system_user, assets, task_name, username=None): @shared_task(queue="ansible") -def push_system_user_to_assets_manual(system_user): +def push_system_user_to_assets_manual(system_user, username=None): assets = system_user.get_related_assets() task_name = _("Push system users to assets: {}").format(system_user.name) - return push_system_user_util(system_user, assets, task_name=task_name) + return push_system_user_util(system_user, assets, task_name=task_name, username=username) @shared_task(queue="ansible") @@ -210,9 +209,9 @@ def push_system_user_a_asset_manual(system_user, asset, username=None): @shared_task(queue="ansible") -def push_system_user_to_assets(system_user, assets): +def push_system_user_to_assets(system_user, assets, username=None): task_name = _("Push system users to assets: {}").format(system_user.name) - return push_system_user_util(system_user, assets, task_name) + return push_system_user_util(system_user, assets, task_name, username=username) diff --git a/apps/assets/templates/assets/admin_user_detail.html b/apps/assets/templates/assets/admin_user_detail.html index e3f618d93..198b1e765 100644 --- a/apps/assets/templates/assets/admin_user_detail.html +++ b/apps/assets/templates/assets/admin_user_detail.html @@ -61,7 +61,7 @@ {% trans 'Created by' %}: - {{ asset_group.created_by }} + {{ admin_user.created_by }} {% trans 'Comment' %}: diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html index f7588043a..24a789404 100644 --- a/apps/assets/templates/assets/asset_list.html +++ b/apps/assets/templates/assets/asset_list.html @@ -258,6 +258,10 @@ $(document).ready(function(){ confirmButtonText: "{% trans 'Confirm' %}", closeOnConfirm: false },function () { + function fail() { + var msg = "{% trans 'Asset Deleting failed.' %}"; + swal("{% trans 'Asset Delete' %}", msg, "error"); + } function success(data) { url = setUrlParam(the_url, 'spm', data.spm); requestApi({ @@ -268,13 +272,10 @@ $(document).ready(function(){ swal("{% trans 'Asset Delete' %}", msg, "success"); reloadTable(); }, + error: fail, flash_message: false, }); } - function fail() { - var msg = "{% trans 'Asset Deleting failed.' %}"; - swal("{% trans 'Asset Delete' %}", msg, "error"); - } requestApi({ url: "{% url 'api-common:resources-cache' %}", method: 'POST', diff --git a/apps/assets/templates/assets/domain_detail.html b/apps/assets/templates/assets/domain_detail.html index 5b01c30fe..119b58080 100644 --- a/apps/assets/templates/assets/domain_detail.html +++ b/apps/assets/templates/assets/domain_detail.html @@ -63,10 +63,6 @@ {% trans 'Date created' %}: {{ object.date_created }} - - {% trans 'Created by' %}: - {{ object.created_by }} - {% trans 'Comment' %}: {{ object.comment }} diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html index b26cfbf11..01e71fc1c 100644 --- a/apps/assets/templates/assets/system_user_detail.html +++ b/apps/assets/templates/assets/system_user_detail.html @@ -106,7 +106,7 @@ {% trans 'Created by' %}: - {{ asset_group.created_by }} + {{ system_user.created_by }} {% trans 'Comment' %}: diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index f9e23c281..b952d9ab4 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 7356b96e3..27dc9addd 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: 2020-03-12 17:27+0800\n" +"POT-Creation-Date: 2020-03-17 13:50+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: JumpServer team\n" @@ -535,7 +535,7 @@ msgstr "详情" #: xpack/plugins/cloud/templates/cloud/account_detail.html:20 #: xpack/plugins/cloud/templates/cloud/account_list.html:40 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:26 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:57 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:60 #: xpack/plugins/gathered_user/templates/gathered_user/task_list.html:46 #: xpack/plugins/orgs/templates/orgs/org_detail.html:20 #: xpack/plugins/orgs/templates/orgs/org_list.html:93 @@ -587,7 +587,7 @@ msgstr "更新" #: xpack/plugins/cloud/templates/cloud/account_detail.html:24 #: xpack/plugins/cloud/templates/cloud/account_list.html:42 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:30 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:58 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:61 #: xpack/plugins/gathered_user/templates/gathered_user/task_list.html:47 #: xpack/plugins/orgs/templates/orgs/org_detail.html:24 #: xpack/plugins/orgs/templates/orgs/org_list.html:95 @@ -727,6 +727,14 @@ msgstr "不能修改根节点名称" msgid "Deletion failed and the node contains children or assets" msgstr "删除失败,节点包含子节点或资产" +#: assets/backends/db.py:244 +msgid "Could not remove asset admin user" +msgstr "不能移除资产的管理用户账号" + +#: assets/backends/db.py:305 +msgid "Latest version could not be delete" +msgstr "最新版本的不能被删除" + #: assets/forms/asset.py:83 assets/models/asset.py:196 #: assets/models/user.py:109 assets/templates/assets/asset_detail.html:186 #: assets/templates/assets/asset_detail.html:194 @@ -3169,23 +3177,23 @@ msgstr "{} 任务结束" msgid "Result" msgstr "结果" -#: ops/models/command.py:59 +#: ops/models/command.py:64 msgid "Task start" msgstr "任务开始" -#: ops/models/command.py:81 +#: ops/models/command.py:86 msgid "Command `{}` is forbidden ........" msgstr "命令 `{}` 不允许被执行 ......." -#: ops/models/command.py:88 +#: ops/models/command.py:93 msgid "Task end" msgstr "任务结束" -#: ops/tasks.py:63 +#: ops/tasks.py:65 msgid "Clean task history period" msgstr "定期清除任务历史" -#: ops/tasks.py:76 +#: ops/tasks.py:78 msgid "Clean celery log period" msgstr "定期清除Celery日志" @@ -3349,6 +3357,7 @@ msgstr "结束" #: ops/templates/ops/task_adhoc.html:17 ops/templates/ops/task_detail.html:18 #: ops/templates/ops/task_history.html:17 ops/views/adhoc.py:50 +#: ops/views/adhoc.py:92 msgid "Task detail" msgstr "任务详情" @@ -3383,7 +3392,7 @@ msgstr "内容" #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_detail.html:135 #: xpack/plugins/change_auth_plan/templates/change_auth_plan/plan_list.html:54 #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:138 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:55 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:58 #: xpack/plugins/gathered_user/templates/gathered_user/task_list.html:44 msgid "Run" msgstr "执行" @@ -4261,7 +4270,9 @@ msgid "Please enter Password: {}" msgstr "请输入密码: {}" #: settings/utils/ldap.py:420 -msgid "Please enter correct Bind DN and Password: {}" +#, fuzzy +#| msgid "Please enter correct Bind DN and Password: {}" +msgid "Please enter Correct Bind DN and Password: {}" msgstr "请输入正确的绑定DN和密码: {}" #: settings/utils/ldap.py:438 @@ -4970,7 +4981,6 @@ msgid "Session detail" msgstr "会话详情" #: terminal/templates/terminal/session_commands.html:29 -#: terminal/templates/terminal/session_detail.html:29 #: terminal/views/command.py:22 msgid "Command list" msgstr "命令记录列表" @@ -6575,7 +6585,7 @@ msgid "Run task manually" msgstr "手动执行任务" #: xpack/plugins/cloud/templates/cloud/sync_instance_task_detail.html:178 -#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:99 +#: xpack/plugins/cloud/templates/cloud/sync_instance_task_list.html:102 msgid "Sync success" msgstr "同步成功" diff --git a/apps/ops/inventory.py b/apps/ops/inventory.py index 59179b5c7..b0fe5f8ef 100644 --- a/apps/ops/inventory.py +++ b/apps/ops/inventory.py @@ -92,7 +92,7 @@ class JMSInventory(JMSBaseInventory): for asset in assets: host = self.convert_to_ansible(asset, run_as_admin=run_as_admin) - if run_as: + if run_as is not None: run_user_info = self.get_run_user_info(host) host.update(run_user_info) if become_info and asset.is_unixlike(): @@ -104,7 +104,7 @@ class JMSInventory(JMSBaseInventory): def get_run_user_info(self, host): from assets.backends import AssetUserManager - if not self.run_as: + if self.run_as is None: return {} try: diff --git a/apps/ops/models/adhoc.py b/apps/ops/models/adhoc.py index 01d1e1adb..faa3ac01f 100644 --- a/apps/ops/models/adhoc.py +++ b/apps/ops/models/adhoc.py @@ -206,7 +206,7 @@ class AdHoc(OrgModelMixin): def __str__(self): return "{} of {}".format(self.task.name, self.short_id) - def __eq__(self, other): + def same_with(self, other): if not isinstance(other, self.__class__): return False fields_check = [] diff --git a/apps/ops/models/command.py b/apps/ops/models/command.py index 53aeff2b9..662131bc5 100644 --- a/apps/ops/models/command.py +++ b/apps/ops/models/command.py @@ -33,7 +33,12 @@ class CommandExecution(OrgModelMixin): @property def inventory(self): - return JMSInventory(self.hosts.all(), run_as=self.run_as.username) + if self.run_as.username_same_with_user: + username = self.user.username + else: + username = self.run_as.username + inv = JMSInventory(self.hosts.all(), run_as=username) + return inv @property def result(self): diff --git a/apps/ops/tasks.py b/apps/ops/tasks.py index 33d7cb850..0967ac482 100644 --- a/apps/ops/tasks.py +++ b/apps/ops/tasks.py @@ -10,6 +10,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from common.utils import get_logger, get_object_or_none, get_disk_usage +from orgs.utils import tmp_to_root_org from .celery.decorator import ( register_as_period_task, after_app_shutdown_clean_periodic, after_app_ready_start @@ -44,7 +45,8 @@ def run_ansible_task(tid, callback=None, **kwargs): @shared_task(soft_time_limit=60, queue="ansible") def run_command_execution(cid, **kwargs): - execution = get_object_or_none(CommandExecution, id=cid) + with tmp_to_root_org(): + execution = get_object_or_none(CommandExecution, id=cid) if execution: try: os.environ.update({ diff --git a/apps/ops/urls/view_urls.py b/apps/ops/urls/view_urls.py index 592ae9d93..f17fb8662 100644 --- a/apps/ops/urls/view_urls.py +++ b/apps/ops/urls/view_urls.py @@ -15,7 +15,7 @@ urlpatterns = [ path('task//adhoc/', views.TaskAdhocView.as_view(), name='task-adhoc'), path('task//executions/', views.TaskExecutionView.as_view(), name='task-execution'), path('adhoc//', views.AdHocDetailView.as_view(), name='adhoc-detail'), - path('adhoc//executions/', views.AdHocExecutionView.as_view(), name='adhoc-history'), + path('adhoc//executions/', views.AdHocExecutionView.as_view(), name='adhoc-execution'), path('adhoc/executions//', views.AdHocExecutionDetailView.as_view(), name='adhoc-execution-detail'), path('celery/task//log/', views.CeleryTaskLogView.as_view(), name='celery-task-log'), diff --git a/apps/ops/utils.py b/apps/ops/utils.py index 16ba8e648..81b5a1afd 100644 --- a/apps/ops/utils.py +++ b/apps/ops/utils.py @@ -56,7 +56,7 @@ def update_or_create_ansible_task( new_hosts = set([str(asset.id) for asset in hosts]) hosts_same = old_hosts == new_hosts - if not adhoc or adhoc != new_adhoc or not hosts_same: + if not adhoc or not adhoc.same_with(new_adhoc) or not hosts_same: logger.debug(_("Update task content: {}").format(task_name)) new_adhoc.save() new_adhoc.hosts.set(hosts) diff --git a/apps/ops/views/adhoc.py b/apps/ops/views/adhoc.py index b8d90f092..e21c7b575 100644 --- a/apps/ops/views/adhoc.py +++ b/apps/ops/views/adhoc.py @@ -89,7 +89,7 @@ class AdHocDetailView(PermissionsMixin, DetailView): def get_context_data(self, **kwargs): context = { 'app': _('Ops'), - 'action': 'Task version detail', + 'action': _('Task detail'), } kwargs.update(context) return super().get_context_data(**kwargs) diff --git a/apps/perms/signals_handler.py b/apps/perms/signals_handler.py index 1be6ce9f4..7a40bcb66 100644 --- a/apps/perms/signals_handler.py +++ b/apps/perms/signals_handler.py @@ -62,6 +62,34 @@ def on_asset_permission_system_users_changed(sender, instance=None, action='', system_user.users.add(*tuple(users)) +@receiver(m2m_changed, sender=AssetPermission.users.through) +def on_asset_permission_users_changed(sender, instance=None, action='', + reverse=False, **kwargs): + if action != 'post_add' and reverse: + return + logger.debug("Asset permission users change signal received") + users = kwargs['model'].objects.filter(pk__in=kwargs['pk_set']) + system_users = instance.system_users.all() + + for system_user in system_users: + if system_user.username_same_with_user: + system_user.users.add(*tuple(users)) + + +@receiver(m2m_changed, sender=AssetPermission.user_groups.through) +def on_asset_permission_user_groups_changed(sender, instance=None, action='', + reverse=False, **kwargs): + if action != 'post_add' and reverse: + return + logger.debug("Asset permission user groups change signal received") + groups = kwargs['model'].objects.filter(pk__in=kwargs['pk_set']) + system_users = instance.system_users.all() + + for system_user in system_users: + if system_user.username_same_with_user: + system_user.groups.add(*tuple(groups)) + + @receiver(m2m_changed, sender=RemoteAppPermission.system_users.through) def on_remote_app_permission_system_users_changed(sender, instance=None, action='', reverse=False, **kwargs): @@ -77,3 +105,17 @@ def on_remote_app_permission_system_users_changed(sender, instance=None, if system_user.username_same_with_user: system_user.groups.add(*tuple(groups)) system_user.users.add(*tuple(users)) + + +@receiver(m2m_changed, sender=RemoteAppPermission.users.through) +def on_remoteapps_permission_users_changed(sender, instance=None, action='', + reverse=False, **kwargs): + on_asset_permission_users_changed(sender, instance=instance, action=action, + reverse=reverse, **kwargs) + + +@receiver(m2m_changed, sender=RemoteAppPermission.user_groups.through) +def on_remoteapps_permission_user_groups_changed(sender, instance=None, action='', + reverse=False, **kwargs): + on_asset_permission_user_groups_changed(sender, instance=instance, + action=action, reverse=reverse, **kwargs) diff --git a/apps/static/img/login_image.png b/apps/static/img/login_image.png index 11a19957e..60c851e78 100644 Binary files a/apps/static/img/login_image.png and b/apps/static/img/login_image.png differ diff --git a/apps/terminal/forms/storage.py b/apps/terminal/forms/storage.py index a94375e81..3b586560c 100644 --- a/apps/terminal/forms/storage.py +++ b/apps/terminal/forms/storage.py @@ -117,13 +117,6 @@ class ReplayStorageCephForm(BaseReplayStorageForm): ) ceph_endpoint = forms.CharField( max_length=128, label=_('Endpoint'), required=False, - help_text=_( - """ - S3: http://s3.{REGION_NAME}.amazonaws.com
- S3(China): http://s3.{REGION_NAME}.amazonaws.com.cn
- Example: http://s3.cn-north-1.amazonaws.com.cn - """ - ) ) diff --git a/apps/terminal/templates/terminal/session_detail.html b/apps/terminal/templates/terminal/session_detail.html index 26ec1c785..1863ad75f 100644 --- a/apps/terminal/templates/terminal/session_detail.html +++ b/apps/terminal/templates/terminal/session_detail.html @@ -26,7 +26,7 @@
- {% trans 'Command list' %} + {{ object.id }}