Unverified Commit 09fbd3a5 authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #1922 from jumpserver/dev

Dev
parents 0665644f ebecd005
......@@ -74,7 +74,7 @@ class AssetViewSet(IDInFilterMixin, LabelFilter, BulkModelViewSet):
.select_related('admin_user')
self.filter_admin_user_id()
self.filter_node()
return self.queryset
return self.queryset.distinct()
class AssetListUpdateApi(IDInFilterMixin, ListBulkCreateUpdateDestroyAPIView):
......
......@@ -26,7 +26,7 @@ class CommandFilterRuleViewSet(BulkModelViewSet):
fpk = self.kwargs.get('filter_pk')
if not fpk:
return CommandFilterRule.objects.none()
group = get_object_or_404(CommandFilter, pk=fpk)
return group.rules.all().order_by('priority')
cmd_filter = get_object_or_404(CommandFilter, pk=fpk)
return cmd_filter.rules.all()
......@@ -150,7 +150,7 @@ class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm):
'name': '* required',
'username': '* required',
'auto_push': _('Auto push system user to asset'),
'priority': _('High level will be using login asset as default, '
'priority': _('1-100, High level will be using login asset as default, '
'if user was granted more than 2 system user'),
'login_mode': _('If you choose manual login mode, you do not '
'need to fill in the username and password.')
......
......@@ -34,7 +34,8 @@ def default_cluster():
def default_node():
try:
from .node import Node
return Node.root()
root = Node.root()
return root
except:
return None
......
......@@ -44,7 +44,7 @@ class CommandFilterRule(OrgModelMixin):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
filter = models.ForeignKey('CommandFilter', on_delete=models.CASCADE, verbose_name=_("Filter"), related_name='rules')
type = models.CharField(max_length=16, default=TYPE_COMMAND, choices=TYPE_CHOICES, verbose_name=_("Type"))
priority = models.IntegerField(default=50, verbose_name=_("Priority"), help_text=_("1-100, the lower will be match first"),
priority = models.IntegerField(default=50, verbose_name=_("Priority"), help_text=_("1-100, the higher will be match first"),
validators=[MinValueValidator(1), MaxValueValidator(100)])
content = models.TextField(max_length=1024, verbose_name=_("Content"), help_text=_("One line one command"))
action = models.IntegerField(default=ACTION_DENY, choices=ACTION_CHOICES, verbose_name=_("Action"))
......@@ -54,7 +54,7 @@ class CommandFilterRule(OrgModelMixin):
created_by = models.CharField(max_length=128, blank=True, default='', verbose_name=_('Created by'))
class Meta:
ordering = ('priority', 'action')
ordering = ('-priority', 'action')
def __str__(self):
return '{} % {}'.format(self.type, self.content)
......@@ -31,6 +31,8 @@ class Node(OrgModelMixin):
return self.full_value
def __eq__(self, other):
if not other:
return False
return self.key == other.key
def __gt__(self, other):
......@@ -136,7 +138,7 @@ class Node(OrgModelMixin):
args.append(Q(nodes__key__regex=pattern) | Q(nodes=None))
else:
kwargs['nodes__key__regex'] = pattern
assets = Asset.objects.filter(*args, **kwargs)
assets = Asset.objects.filter(*args, **kwargs).distinct()
return assets
def get_all_valid_assets(self):
......@@ -201,13 +203,16 @@ class Node(OrgModelMixin):
# 如果使用current_org 在set_current_org时会死循环
_current_org = get_current_org()
with transaction.atomic():
if _current_org.is_default():
if _current_org.is_root():
key = '0'
elif _current_org.is_default():
key = '1'
else:
set_current_org(Organization.root())
org_nodes_roots = cls.objects.filter(key__regex=r'^[0-9]+$')
org_nodes_roots_keys = org_nodes_roots.values_list('key', flat=True) or [0]
key = str(max([int(k) for k in org_nodes_roots_keys]) + 1)
org_nodes_roots_keys = org_nodes_roots.values_list('key', flat=True) or ['1']
key = max([int(k) for k in org_nodes_roots_keys])
key = str(key + 1) if key != 0 else '2'
set_current_org(_current_org)
root = cls.objects.create(key=key, value=_current_org.name)
return root
......@@ -223,7 +228,7 @@ class Node(OrgModelMixin):
@classmethod
def default_node(cls):
defaults = {'value': 'Default'}
return cls.objects.get_or_create(defaults=defaults, key='0')
return cls.objects.get_or_create(defaults=defaults, key='1')
@classmethod
def get_tree_name_ref(cls):
......
......@@ -7,6 +7,7 @@ import logging
from django.core.cache import cache
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.core.validators import MinValueValidator, MaxValueValidator
from common.utils import get_signer
from ..const import SYSTEM_USER_CONN_CACHE_KEY
......@@ -111,7 +112,8 @@ class SystemUser(AssetUser):
nodes = models.ManyToManyField('assets.Node', blank=True, verbose_name=_("Nodes"))
assets = models.ManyToManyField('assets.Asset', blank=True, verbose_name=_("Assets"))
priority = models.IntegerField(default=10, verbose_name=_("Priority"))
priority = models.IntegerField(default=20, verbose_name=_("Priority"),
validators=[MinValueValidator(1), MaxValueValidator(100)])
protocol = models.CharField(max_length=16, choices=PROTOCOL_CHOICES, default='ssh', verbose_name=_('Protocol'))
auto_push = models.BooleanField(default=True, verbose_name=_('Auto push'))
sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo'))
......@@ -168,7 +170,7 @@ class SystemUser(AssetUser):
from .cmd_filter import CommandFilterRule
rules = CommandFilterRule.objects.filter(
filter__in=self.cmd_filters.all()
).order_by('priority').distinct()
).distinct()
return rules
@classmethod
......
......@@ -69,6 +69,10 @@
<td>{% trans 'Port' %}:</td>
<td><b>{{ asset.port }}</b></td>
</tr>
<tr>
<td>{% trans 'Protocol' %}:</td>
<td><b>{{ asset.protocol }}</b></td>
</tr>
<tr>
<td>{% trans 'Admin user' %}:</td>
<td><b>{{ asset.admin_user }}</b></td>
......
......@@ -5,7 +5,7 @@
<div class="alert alert-info help-message">
{% trans 'System user bound some command filter, each command filter has some rules,'%}
{% trans 'When user login asset with this system user, then run a command,' %}
{% trans 'The command will be filter by rules, higher priority(lower number) rule run first,' %}
{% trans 'The command will be filter by rules, higher priority rule run first,' %}
{% trans 'When a rule matched, if rule action is allow, then allow command execute,' %}
{% trans 'else if action is deny, then command with be deny,' %}
{% trans 'else match next rule, if none matched, allowed' %}
......
......@@ -45,10 +45,7 @@ class AssetListView(AdminUserRequiredMixin, TemplateView):
template_name = 'assets/asset_list.html'
def get_context_data(self, **kwargs):
if current_org.is_default():
Node.default_node()
else:
Node.root()
Node.root()
context = {
'app': _('Assets'),
'action': _('Asset list'),
......
......@@ -18,6 +18,9 @@ class BaseForm(forms.Form):
db_value = getattr(common_settings, name)
django_value = getattr(settings, name) if hasattr(settings, name) else None
if db_value is None and django_value is None:
continue
if db_value is False or db_value:
if isinstance(db_value, dict):
db_value = json.dumps(db_value)
......
......@@ -106,3 +106,8 @@ def to_dict(data):
def sort(data):
print(data)
return sorted(data)
@register.filter
def subtract(value, arg):
return value - arg
This diff is collapsed.
......@@ -4,7 +4,6 @@
from werkzeug.local import Local
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.db.models import Q
from django.shortcuts import redirect
from django.forms import ModelForm
from django.http.response import HttpResponseForbidden
......
......@@ -96,7 +96,7 @@ class UserGrantedNodesApi(ListAPIView):
"""
查询用户授权的所有节点的API, 如果是超级用户或者是 app,切换到root org
"""
permission_classes = (IsOrgAdmin,)
permission_classes = (IsOrgAdminOrAppUser,)
serializer_class = NodeSerializer
def change_org_if_need(self):
......
......@@ -145,7 +145,14 @@ function activeNav() {
var resource = url_array[2];
if (app === ''){
$('#index').addClass('active');
} else {
}
else if (app === 'xpack') {
var item = url_array[3];
$("#" + app).addClass('active');
$('#' + app + ' #' + resource).addClass('active');
$('#' + app + ' #' + resource + ' #' + item + ' a').css('color', '#ffffff');
}
else {
$("#" + app).addClass('active');
$('#' + app + ' #' + resource).addClass('active');
}
......
......@@ -95,7 +95,17 @@
</a>
<ul class="nav nav-second-level">
{% for plugin in XPACK_PLUGINS %}
<li id="{{ plugin.name }}"><a href="{{ plugin.endpoint }}">{% trans plugin.verbose_name %}</a></li>
{% ifequal plugin.name 'cloud'%}
<li id="{{ plugin.name }}">
<a href="#"><span class="nav-label">{% trans plugin.verbose_name %}</span><span class="fa arrow"></span></a>
<ul class="nav nav-third-level">
<li id="account"><a href="{% url 'xpack:cloud:account-list' %}">{% trans 'Account list' %}</a></li>
<li id="sync-instance-task"><a href="{% url 'xpack:cloud:sync-instance-task-list' %}">{% trans 'Sync instance' %}</a></li>
</ul>
</li>
{% else %}
<li id="{{ plugin.name }}"><a href="{{ plugin.endpoint }}">{% trans plugin.verbose_name %}</a></li>
{% endifequal %}
{% endfor %}
</ul>
</li>
......
......@@ -9,8 +9,13 @@
<i class="fa fa-user" style="width: 14px"></i> <span class="nav-label">{% trans 'Profile' %}</span><span class="label label-info pull-right"></span>
</a>
</li>
<li >
<li>
<a href="{% url 'terminal:web-terminal' %}" target="_blank"><i class="fa fa-window-maximize" style="width: 14px"></i>
<span class="nav-label">{% trans 'Web terminal' %}</span>
</a>
</li>
<li>
<a href="{% url 'terminal:web-sftp' %}" target="_blank"><i class="fa fa-file" style="width: 14px"></i>
<span class="nav-label">{% trans 'File manager' %}</span>
</a>
</li>
\ No newline at end of file
......@@ -72,3 +72,5 @@ vine==1.1.4
drf-yasg==1.9.1
Werkzeug==0.14.1
drf-nested-routers==0.90.2
aliyun-python-sdk-core-v3==2.9.1
aliyun-python-sdk-ecs==4.10.1
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment