Merge pull request #3783 from jumpserver/bugfix

Bugfix
pull/3789/head
BaiJiangJie 2020-03-18 11:05:51 +08:00 committed by GitHub
commit ffce909ee3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 156 additions and 46 deletions

View File

@ -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):

View File

@ -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(

View File

@ -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):

View File

@ -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):
"""

View File

@ -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)

View File

@ -61,7 +61,7 @@
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ asset_group.created_by }}</b></td>
<td><b>{{ admin_user.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>

View File

@ -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',

View File

@ -63,10 +63,6 @@
<td>{% trans 'Date created' %}:</td>
<td><b>{{ object.date_created }}</b></td>
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ object.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>
<td><b>{{ object.comment }}</b></td>

View File

@ -106,7 +106,7 @@
</tr>
<tr>
<td>{% trans 'Created by' %}:</td>
<td><b>{{ asset_group.created_by }}</b></td>
<td><b>{{ system_user.created_by }}</b></td>
</tr>
<tr>
<td>{% trans 'Comment' %}:</td>

Binary file not shown.

View File

@ -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 <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\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 "同步成功"

View File

@ -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:

View File

@ -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 = []

View File

@ -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):

View File

@ -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({

View File

@ -15,7 +15,7 @@ urlpatterns = [
path('task/<uuid:pk>/adhoc/', views.TaskAdhocView.as_view(), name='task-adhoc'),
path('task/<uuid:pk>/executions/', views.TaskExecutionView.as_view(), name='task-execution'),
path('adhoc/<uuid:pk>/', views.AdHocDetailView.as_view(), name='adhoc-detail'),
path('adhoc/<uuid:pk>/executions/', views.AdHocExecutionView.as_view(), name='adhoc-history'),
path('adhoc/<uuid:pk>/executions/', views.AdHocExecutionView.as_view(), name='adhoc-execution'),
path('adhoc/executions/<uuid:pk>/', views.AdHocExecutionDetailView.as_view(), name='adhoc-execution-detail'),
path('celery/task/<uuid:pk>/log/', views.CeleryTaskLogView.as_view(), name='celery-task-log'),

View File

@ -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)

View File

@ -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)

View File

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 263 KiB

View File

@ -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 <br>
S3(China): http://s3.{REGION_NAME}.amazonaws.com.cn <br>
Example: http://s3.cn-north-1.amazonaws.com.cn
"""
)
)

View File

@ -26,7 +26,7 @@
<div class="col-sm-8" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Command list' %} <b></b></span>
<span style="float: left"> <b>{{ object.id }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>