diff --git a/apps/assets/api/label.py b/apps/assets/api/label.py
index eb8594e4a..d3537b20c 100644
--- a/apps/assets/api/label.py
+++ b/apps/assets/api/label.py
@@ -13,11 +13,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from rest_framework_bulk import BulkModelViewSet
from rest_framework.pagination import LimitOffsetPagination
from django.db.models import Count
from common.utils import get_logger
+from orgs.mixins import OrgBulkModelViewSet
from ..hands import IsOrgAdmin
from ..models import Label
from .. import serializers
@@ -27,7 +27,7 @@ logger = get_logger(__file__)
__all__ = ['LabelViewSet']
-class LabelViewSet(BulkModelViewSet):
+class LabelViewSet(OrgBulkModelViewSet):
filter_fields = ("name", "value")
search_fields = filter_fields
permission_classes = (IsOrgAdmin,)
diff --git a/apps/assets/migrations/0035_auto_20190711_2018.py b/apps/assets/migrations/0035_auto_20190711_2018.py
new file mode 100644
index 000000000..9dcbad1db
--- /dev/null
+++ b/apps/assets/migrations/0035_auto_20190711_2018.py
@@ -0,0 +1,34 @@
+# Generated by Django 2.1.7 on 2019-07-11 12:18
+
+import common.fields.model
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('assets', '0034_auto_20190705_1348'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='adminuser',
+ name='private_key',
+ field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
+ ),
+ migrations.AlterField(
+ model_name='authbook',
+ name='private_key',
+ field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
+ ),
+ migrations.AlterField(
+ model_name='gateway',
+ name='private_key',
+ field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
+ ),
+ migrations.AlterField(
+ model_name='systemuser',
+ name='private_key',
+ field=common.fields.model.EncryptTextField(blank=True, null=True, verbose_name='SSH private key'),
+ ),
+ ]
diff --git a/apps/assets/models/base.py b/apps/assets/models/base.py
index b372bc9fd..75f81917f 100644
--- a/apps/assets/models/base.py
+++ b/apps/assets/models/base.py
@@ -28,7 +28,7 @@ class AssetUser(OrgModelMixin):
name = models.CharField(max_length=128, verbose_name=_('Name'))
username = models.CharField(max_length=32, blank=True, verbose_name=_('Username'), validators=[alphanumeric])
password = fields.EncryptCharField(max_length=256, blank=True, null=True, verbose_name=_('Password'))
- private_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH private key'), validators=[private_key_validator, ])
+ private_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH private key'))
public_key = fields.EncryptTextField(blank=True, null=True, verbose_name=_('SSH public key'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_("Date created"))
diff --git a/apps/assets/serializers/admin_user.py b/apps/assets/serializers/admin_user.py
index b8295457f..0efc09801 100644
--- a/apps/assets/serializers/admin_user.py
+++ b/apps/assets/serializers/admin_user.py
@@ -21,17 +21,14 @@ class AdminUserSerializer(AuthSerializerMixin, BulkOrgResourceModelSerializer):
model = AdminUser
fields = [
'id', 'name', 'username', 'password', 'private_key', 'public_key',
- 'comment', 'assets_amount',
- 'date_created', 'date_updated', 'created_by',
+ 'comment', 'assets_amount', 'date_created', 'date_updated', 'created_by',
]
+ read_only_fields = ['date_created', 'date_updated', 'created_by', 'assets_amount']
extra_kwargs = {
'password': {"write_only": True},
'private_key': {"write_only": True},
'public_key': {"write_only": True},
- 'date_created': {'read_only': True},
- 'date_updated': {'read_only': True},
- 'created_by': {'read_only': True},
'assets_amount': {'label': _('Asset')},
}
diff --git a/apps/assets/serializers/domain.py b/apps/assets/serializers/domain.py
index 68145e7a9..68feccb41 100644
--- a/apps/assets/serializers/domain.py
+++ b/apps/assets/serializers/domain.py
@@ -15,7 +15,11 @@ class DomainSerializer(BulkOrgResourceModelSerializer):
class Meta:
model = Domain
- fields = '__all__'
+ fields = [
+ 'id', 'name', 'asset_count', 'gateway_count', 'comment', 'assets',
+ 'date_created'
+ ]
+ read_only_fields = ( 'asset_count', 'gateway_count', 'date_created')
list_serializer_class = AdaptedBulkListSerializer
@staticmethod
diff --git a/apps/assets/serializers/label.py b/apps/assets/serializers/label.py
index 526580216..a20c43a11 100644
--- a/apps/assets/serializers/label.py
+++ b/apps/assets/serializers/label.py
@@ -13,7 +13,13 @@ class LabelSerializer(BulkOrgResourceModelSerializer):
class Meta:
model = Label
- fields = '__all__'
+ fields = [
+ 'id', 'name', 'value', 'category', 'is_active', 'comment',
+ 'date_created', 'asset_count', 'assets', 'get_category_display'
+ ]
+ read_only_fields = (
+ 'category', 'date_created', 'asset_count', 'get_category_display'
+ )
list_serializer_class = AdaptedBulkListSerializer
@staticmethod
diff --git a/apps/assets/templates/assets/_asset_user_auth_view_modal.html b/apps/assets/templates/assets/_asset_user_auth_view_modal.html
index 6fbd48fcd..417e1021d 100644
--- a/apps/assets/templates/assets/_asset_user_auth_view_modal.html
+++ b/apps/assets/templates/assets/_asset_user_auth_view_modal.html
@@ -70,7 +70,7 @@ function showAuth() {
var msg = "{% trans 'Get auth info error' %}";
toastr.error(msg)
};
- APIUpdateAttr({
+ requestApi({
url: url,
method: "GET",
success: success,
diff --git a/apps/assets/templates/assets/_asset_user_list.html b/apps/assets/templates/assets/_asset_user_list.html
index 381aec13d..f76754391 100644
--- a/apps/assets/templates/assets/_asset_user_list.html
+++ b/apps/assets/templates/assets/_asset_user_list.html
@@ -141,7 +141,7 @@ $(document).ready(function(){
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
diff --git a/apps/assets/templates/assets/_node_tree.html b/apps/assets/templates/assets/_node_tree.html
index 61737184c..9a4004060 100644
--- a/apps/assets/templates/assets/_node_tree.html
+++ b/apps/assets/templates/assets/_node_tree.html
@@ -235,7 +235,7 @@ function onRename(event, treeId, treeNode, isCancel){
if (isCancel){
return
}
- APIUpdateAttr({
+ requestApi({
url: url,
body: JSON.stringify(data),
method: "PATCH",
@@ -274,7 +274,7 @@ function onDrop(event, treeId, treeNodes, targetNode, moveType) {
var the_url = "{% url 'api-assets:node-add-children' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", targetNode.meta.node.id);
var body = {nodes: treeNodesIds};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: "PUT",
body: JSON.stringify(body)
diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html
index ef78187b5..5cc3e04ba 100644
--- a/apps/assets/templates/assets/_system_user.html
+++ b/apps/assets/templates/assets/_system_user.html
@@ -228,6 +228,7 @@ $(document).ready(function () {
var form = $("form");
var data = form.serializeObject();
+ objectAttrsIsList(data, ['cmd_filters']);
objectAttrsIsBool(data, ["auto_generate_key", "auto_push"]);
data["private_key"] = $("#id_private_key_file").data('file');
diff --git a/apps/assets/templates/assets/admin_user_assets.html b/apps/assets/templates/assets/admin_user_assets.html
index 7c97259ab..9ca433930 100644
--- a/apps/assets/templates/assets/admin_user_assets.html
+++ b/apps/assets/templates/assets/admin_user_assets.html
@@ -88,7 +88,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
diff --git a/apps/assets/templates/assets/admin_user_detail.html b/apps/assets/templates/assets/admin_user_detail.html
index f00e2352a..9e3365509 100644
--- a/apps/assets/templates/assets/admin_user_detail.html
+++ b/apps/assets/templates/assets/admin_user_detail.html
@@ -131,7 +131,7 @@ function replaceNodeAssetsAdminUser(nodes) {
// clear jumpserver.groups_selected
jumpserver.nodes_selected = {};
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
diff --git a/apps/assets/templates/assets/asset_asset_user_list.html b/apps/assets/templates/assets/asset_asset_user_list.html
index 39e4816b9..bf3cba583 100644
--- a/apps/assets/templates/assets/asset_asset_user_list.html
+++ b/apps/assets/templates/assets/asset_asset_user_list.html
@@ -84,7 +84,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
diff --git a/apps/assets/templates/assets/asset_detail.html b/apps/assets/templates/assets/asset_detail.html
index ad635ca5b..760cc7e6d 100644
--- a/apps/assets/templates/assets/asset_detail.html
+++ b/apps/assets/templates/assets/asset_detail.html
@@ -70,7 +70,7 @@
{% trans 'Protocol' %} |
- {{ asset.protocols }} |
+ {{ asset.protocols }} |
{% trans 'Admin user' %}: |
@@ -267,7 +267,7 @@ function updateAssetNodes(nodes) {
// clear jumpserver.groups_selected
jumpserver.nodes_selected = {};
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -282,7 +282,7 @@ function refreshAssetHardware() {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
success: success,
method: 'GET'
@@ -306,7 +306,7 @@ $(document).ready(function () {
};
var success = '{% trans "Update successfully!" %}';
var status = $(".ibox-content > table > tbody > tr:nth-child(13) > td:last >b").text();
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success_message: success
@@ -360,7 +360,7 @@ $(document).ready(function () {
window.open(url, '', 'width=800,height=600')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success
diff --git a/apps/assets/templates/assets/asset_list.html b/apps/assets/templates/assets/asset_list.html
index 8f889feb7..0cdcb176a 100644
--- a/apps/assets/templates/assets/asset_list.html
+++ b/apps/assets/templates/assets/asset_list.html
@@ -360,7 +360,7 @@ $(document).ready(function(){
setTimeout( function () {
window.location.reload();}, 500);
}
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'PATCH',
body: JSON.stringify(data),
@@ -377,7 +377,7 @@ $(document).ready(function(){
setTimeout( function () {
window.location.reload();}, 300);
}
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'PATCH',
body: JSON.stringify(data),
@@ -397,7 +397,7 @@ $(document).ready(function(){
},function () {
function success(data) {
url = setUrlParam(the_url, 'spm', data.spm);
- APIUpdateAttr({
+ requestApi({
url:url,
method:'DELETE',
success:refreshTag,
@@ -410,7 +410,7 @@ $(document).ready(function(){
var msg = "{% trans 'Asset Deleting failed.' %}";
swal("{% trans 'Asset Delete' %}", msg, "error");
}
- APIUpdateAttr({
+ requestApi({
url: "{% url 'api-common:resources-cache' %}",
method:'POST',
body:JSON.stringify(data),
@@ -428,7 +428,7 @@ $(document).ready(function(){
var url = "{% url 'assets:asset-bulk-update' %}";
location.href= setUrlParam(url, 'spm', data.spm);
}
- APIUpdateAttr({
+ requestApi({
url: "{% url 'api-common:resources-cache' %}",
method:'POST',
body:JSON.stringify(data),
@@ -452,7 +452,7 @@ $(document).ready(function(){
asset_table.ajax.reload()
};
- APIUpdateAttr({
+ requestApi({
'url': '/api/assets/v1/nodes/' + current_node_id + '/assets/remove/',
'method': 'PUT',
'body': JSON.stringify(data),
@@ -500,7 +500,7 @@ $(document).ready(function(){
url = "{% url 'api-assets:node-add-assets' pk=DEFAULT_PK %}".replace("{{ DEFAULT_PK }}", current_node_id);
}
- APIUpdateAttr({
+ requestApi({
'url': url,
'method': 'PUT',
'body': JSON.stringify(data),
@@ -524,7 +524,7 @@ $(document).ready(function(){
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600')
}
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: "GET",
success: success,
@@ -539,7 +539,7 @@ $(document).ready(function(){
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600')
}
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: "GET",
success: success,
diff --git a/apps/assets/templates/assets/cmd_filter_detail.html b/apps/assets/templates/assets/cmd_filter_detail.html
index ee68ff2f6..b98828f4e 100644
--- a/apps/assets/templates/assets/cmd_filter_detail.html
+++ b/apps/assets/templates/assets/cmd_filter_detail.html
@@ -136,7 +136,7 @@ function updateCMDFilterSystemUsers(system_users) {
var success = function(data) {
location.reload();
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
method: 'PATCH',
diff --git a/apps/assets/templates/assets/cmd_filter_rule_create_update.html b/apps/assets/templates/assets/cmd_filter_rule_create_update.html
index 9b240bd74..2edaa97dc 100644
--- a/apps/assets/templates/assets/cmd_filter_rule_create_update.html
+++ b/apps/assets/templates/assets/cmd_filter_rule_create_update.html
@@ -70,5 +70,25 @@ $(document).ready(function(){
content_help_ref.html(content_origin_help_text);
}
})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var form = $("form");
+ var data = form.serializeObject();
+ var the_url = '{% url "api-assets:cmd-filter-rule-list" filter_pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", data.filter);
+ var redirect_to = '{% url "assets:cmd-filter-rule-list" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", data.filter);
+ var method = "POST";
+ {% if request_type == "update" %}
+ the_url = '{% url "api-assets:cmd-filter-rule-detail" filter_pk=DEFAULT_PK pk=rule.id %}'.replace('{{ DEFAULT_PK }}', data.filter);
+ method = "PUT";
+ {% endif %}
+ var props = {
+ url: the_url,
+ data: data,
+ method: method,
+ form: form,
+ redirect_to: redirect_to
+ };
+ formSubmit(props);
+})
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/domain_create_update.html b/apps/assets/templates/assets/domain_create_update.html
index 7a31e3e88..399b38011 100644
--- a/apps/assets/templates/assets/domain_create_update.html
+++ b/apps/assets/templates/assets/domain_create_update.html
@@ -48,5 +48,26 @@ $(document).ready(function () {
$("#asset_list_modal").modal('hide');
})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var form = $("form");
+ var data = form.serializeObject();
+ var method = "POST";
+ var the_url = '{% url "api-assets:domain-list" %}';
+ var redirect_to = '{% url "assets:domain-list" %}';
+ {% if type == "update" %}
+ the_url = '{% url 'api-assets:domain-detail' pk=object.id %}';
+ method = "PUT";
+ {% endif %}
+ objectAttrsIsList(data, ['assets']);
+ var props = {
+ url:the_url,
+ data:data,
+ method:method,
+ form:form,
+ redirect_to:redirect_to
+ };
+ formSubmit(props);
+ })
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/domain_gateway_list.html b/apps/assets/templates/assets/domain_gateway_list.html
index d621fb0ec..eb348141e 100644
--- a/apps/assets/templates/assets/domain_gateway_list.html
+++ b/apps/assets/templates/assets/domain_gateway_list.html
@@ -134,7 +134,7 @@ $(document).ready(function(){
var data = $("#test_gateway_form").serializeObject();
var uid = data.gateway_id;
var the_url = '{% url "api-assets:test-gateway-connective" pk=DEFAULT_PK %}'.replace('{{ DEFAULT_PK }}', uid);
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: "POST",
body: JSON.stringify({'port': parseInt(data.port)}),
diff --git a/apps/assets/templates/assets/label_create_update.html b/apps/assets/templates/assets/label_create_update.html
index d55bb8827..a6b9582a5 100644
--- a/apps/assets/templates/assets/label_create_update.html
+++ b/apps/assets/templates/assets/label_create_update.html
@@ -51,5 +51,26 @@ $(document).ready(function () {
$('#id_assets').val(assets).trigger('change');
$("#asset_list_modal").modal('hide');
})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var the_url = '{% url 'api-assets:label-list' %}';
+ var redirect_to = '{% url "assets:label-list" %}';
+ var method = "POST";
+ {% if type == "update" %}
+ the_url = '{% url 'api-assets:label-detail' pk=object.id %}';
+ method = "PUT";
+ {% endif %}
+ var form = $("form");
+ var data = form.serializeObject();
+ objectAttrsIsList(data, ['assets']);
+ var props = {
+ url: the_url,
+ data: data,
+ method: method,
+ form: form,
+ redirect_to: redirect_to
+ };
+ formSubmit(props);
+})
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/templates/assets/system_user_assets.html b/apps/assets/templates/assets/system_user_assets.html
index 546111130..5818e4ce6 100644
--- a/apps/assets/templates/assets/system_user_assets.html
+++ b/apps/assets/templates/assets/system_user_assets.html
@@ -146,7 +146,7 @@ function updateSystemUserNode(nodes) {
// clear jumpserver.nodes_selected
jumpserver.nodes_selected = {};
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -206,7 +206,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
error: error,
method: 'GET',
@@ -226,7 +226,7 @@ $(document).ready(function () {
var error = function (data) {
alert(data)
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
@@ -243,7 +243,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
error: error,
method: 'GET',
diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html
index 55f625d81..d9ff1a641 100644
--- a/apps/assets/templates/assets/system_user_detail.html
+++ b/apps/assets/templates/assets/system_user_detail.html
@@ -212,7 +212,7 @@ function updateCommandFilters(command_filters) {
var success = function(data) {
location.reload();
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -235,7 +235,7 @@ $(document).ready(function () {
var body = {
'auto_push': checked
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body)
});
@@ -254,7 +254,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
@@ -268,7 +268,7 @@ $(document).ready(function () {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
method: 'GET',
success: success,
diff --git a/apps/assets/templates/assets/system_user_list.html b/apps/assets/templates/assets/system_user_list.html
index 6c5ff3339..621e18201 100644
--- a/apps/assets/templates/assets/system_user_list.html
+++ b/apps/assets/templates/assets/system_user_list.html
@@ -182,7 +182,7 @@ $(document).ready(function(){
swal("{% trans 'System Users Delete' %}", msg, "error");
};
var url_delete = the_url + '?id__in=' + JSON.stringify(plain_id_list);
- APIUpdateAttr({url: url_delete, method: 'DELETE', success: success, error: fail});
+ requestApi({url: url_delete, method: 'DELETE', success: success, error: fail});
$data_table.ajax.reload();
jumpserver.checked = false;
});
diff --git a/apps/assets/templates/assets/user_asset_list.html b/apps/assets/templates/assets/user_asset_list.html
index f441baa39..d021df0d7 100644
--- a/apps/assets/templates/assets/user_asset_list.html
+++ b/apps/assets/templates/assets/user_asset_list.html
@@ -11,47 +11,7 @@
{% block content %}
-
-
+ {% include 'users/_granted_assets.html' %}
@@ -62,121 +22,51 @@
{% block custom_foot_js %}
-
{% endblock %}
\ No newline at end of file
diff --git a/apps/assets/utils.py b/apps/assets/utils.py
index a0de3b481..be8a80351 100644
--- a/apps/assets/utils.py
+++ b/apps/assets/utils.py
@@ -1,7 +1,8 @@
# ~*~ coding: utf-8 ~*~
#
import time
-from django.db.models import Prefetch
+from functools import reduce
+from django.db.models import Prefetch, Q
from common.utils import get_object_or_none, get_logger
from common.struct import Stack
@@ -21,24 +22,34 @@ def get_system_user_by_id(id):
return system_user
-class LabelFilter:
- def filter_queryset(self, queryset):
- queryset = super().filter_queryset(queryset)
- query_keys = self.request.query_params.keys()
+class LabelFilterMixin:
+ def get_filter_labels_ids(self):
+ query_params = self.request.query_params
+ query_keys = query_params.keys()
all_label_keys = Label.objects.values_list('name', flat=True)
valid_keys = set(all_label_keys) & set(query_keys)
- labels_query = {}
- for key in valid_keys:
- labels_query[key] = self.request.query_params.get(key)
- conditions = []
- for k, v in labels_query.items():
- query = {'labels__name': k, 'labels__value': v}
- conditions.append(query)
+ if not valid_keys:
+ return []
- if conditions:
- for kwargs in conditions:
- queryset = queryset.filter(**kwargs)
+ labels_query = [
+ {"name": key, "value": query_params[key]}
+ for key in valid_keys
+ ]
+ args = [Q(**kwargs) for kwargs in labels_query]
+ args = reduce(lambda x, y: x | y, args)
+ labels_id = Label.objects.filter(args).values_list('id', flat=True)
+ return labels_id
+
+
+class LabelFilter(LabelFilterMixin):
+ def filter_queryset(self, queryset):
+ queryset = super().filter_queryset(queryset)
+ labels_ids = self.get_filter_labels_ids()
+ if not labels_ids:
+ return queryset
+ for labels_id in labels_ids:
+ queryset = queryset.filter(labels=labels_id)
return queryset
diff --git a/apps/assets/views/asset.py b/apps/assets/views/asset.py
index ce701b129..40601d27f 100644
--- a/apps/assets/views/asset.py
+++ b/apps/assets/views/asset.py
@@ -69,7 +69,7 @@ class UserAssetListView(PermissionsMixin, TemplateView):
context = {
'action': _('My assets'),
'labels': Label.objects.all().order_by('name'),
- 'system_users': SystemUser.objects.all(),
+ 'show_actions': True
}
kwargs.update(context)
return super().get_context_data(**kwargs)
diff --git a/apps/assets/views/cmd_filter.py b/apps/assets/views/cmd_filter.py
index 7eef5980a..530f4193b 100644
--- a/apps/assets/views/cmd_filter.py
+++ b/apps/assets/views/cmd_filter.py
@@ -138,6 +138,7 @@ class CommandFilterRuleCreateView(PermissionsMixin, CreateView):
'app': _('Assets'),
'action': _('Create command filter rule'),
'object': self.cmd_filter,
+ 'request_type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -172,6 +173,8 @@ class CommandFilterRuleUpdateView(PermissionsMixin, UpdateView):
'app': _('Assets'),
'action': _('Update command filter rule'),
'object': self.cmd_filter,
+ 'rule': self.get_object(),
+ 'request_type': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
\ No newline at end of file
diff --git a/apps/assets/views/domain.py b/apps/assets/views/domain.py
index 6bbf09e25..7b4dcfcce 100644
--- a/apps/assets/views/domain.py
+++ b/apps/assets/views/domain.py
@@ -46,6 +46,7 @@ class DomainCreateView(PermissionsMixin, CreateView):
context = {
'app': _('Assets'),
'action': _('Create domain'),
+ 'type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -63,6 +64,7 @@ class DomainUpdateView(PermissionsMixin, UpdateView):
context = {
'app': _('Assets'),
'action': _('Update domain'),
+ 'type': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
diff --git a/apps/assets/views/label.py b/apps/assets/views/label.py
index b53a5d040..522962ce3 100644
--- a/apps/assets/views/label.py
+++ b/apps/assets/views/label.py
@@ -44,6 +44,7 @@ class LabelCreateView(PermissionsMixin, CreateView):
context = {
'app': _('Assets'),
'action': _('Create label'),
+ 'type': 'create'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
@@ -71,6 +72,7 @@ class LabelUpdateView(PermissionsMixin, UpdateView):
context = {
'app': _('Assets'),
'action': _('Update label'),
+ 'type': 'update'
}
kwargs.update(context)
return super().get_context_data(**kwargs)
diff --git a/apps/authentication/templates/authentication/_mfa_confirm_modal.html b/apps/authentication/templates/authentication/_mfa_confirm_modal.html
index 0d7b794bb..60512d7de 100644
--- a/apps/authentication/templates/authentication/_mfa_confirm_modal.html
+++ b/apps/authentication/templates/authentication/_mfa_confirm_modal.html
@@ -38,7 +38,7 @@ $(document).ready(function () {
var error = function () {
$("#mfa_error").addClass("text-danger").html(codeError);
};
- APIUpdateAttr({
+ requestApi({
url: url,
method: "POST",
body: JSON.stringify(data),
diff --git a/apps/common/permissions.py b/apps/common/permissions.py
index edb5ee4d0..bdc25fe21 100644
--- a/apps/common/permissions.py
+++ b/apps/common/permissions.py
@@ -145,13 +145,13 @@ class NeedMFAVerify(permissions.BasePermission):
return False
-class CanUpdateSuperUser(permissions.BasePermission):
+class CanUpdateDeleteSuperUser(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in ['GET', 'OPTIONS']:
return True
- if str(request.user.id) == str(obj.id):
+ elif request.method == 'DELETE' and str(request.user.id) == str(obj.id):
return False
- if request.user.is_superuser:
+ elif request.user.is_superuser:
return True
if hasattr(obj, 'is_superuser') and obj.is_superuser:
return False
diff --git a/apps/ops/templates/ops/command_execution_create.html b/apps/ops/templates/ops/command_execution_create.html
index 3e4436e41..17d2c044a 100644
--- a/apps/ops/templates/ops/command_execution_create.html
+++ b/apps/ops/templates/ops/command_execution_create.html
@@ -255,7 +255,7 @@ function execute() {
}
}
- APIUpdateAttr({
+ requestApi({
url: url,
body: JSON.stringify(data),
method: 'POST',
diff --git a/apps/ops/templates/ops/task_list.html b/apps/ops/templates/ops/task_list.html
index 0426e059d..ae8c45043 100644
--- a/apps/ops/templates/ops/task_list.html
+++ b/apps/ops/templates/ops/task_list.html
@@ -109,7 +109,7 @@ $(document).ready(function() {
var url = '{% url "ops:celery-task-log" pk=DEFAULT_PK %}'.replace("{{ DEFAULT_PK }}", task_id);
window.open(url, '', 'width=800,height=600,left=400,top=400')
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
error: error,
method: 'GET',
diff --git a/apps/perms/api/asset_permission.py b/apps/perms/api/asset_permission.py
index 38e44abd0..d4f6e7c85 100644
--- a/apps/perms/api/asset_permission.py
+++ b/apps/perms/api/asset_permission.py
@@ -4,7 +4,8 @@
from django.utils import timezone
from django.db.models import Q
from rest_framework.views import Response
-from rest_framework.generics import RetrieveUpdateAPIView
+from django.shortcuts import get_object_or_404
+from rest_framework.generics import RetrieveUpdateAPIView, ListAPIView
from rest_framework import viewsets
from rest_framework.pagination import LimitOffsetPagination
@@ -20,7 +21,7 @@ from .. import serializers
__all__ = [
'AssetPermissionViewSet', 'AssetPermissionRemoveUserApi',
'AssetPermissionAddUserApi', 'AssetPermissionRemoveAssetApi',
- 'AssetPermissionAddAssetApi',
+ 'AssetPermissionAddAssetApi', 'AssetPermissionAssetsApi',
]
@@ -232,3 +233,22 @@ class AssetPermissionAddAssetApi(RetrieveUpdateAPIView):
return Response({"msg": "ok"})
else:
return Response({"error": serializer.errors})
+
+
+class AssetPermissionAssetsApi(ListAPIView):
+ permission_classes = (IsOrgAdmin,)
+ pagination_class = LimitOffsetPagination
+ serializer_class = serializers.AssetPermissionAssetsSerializer
+ filter_fields = ("hostname", "ip")
+ search_fields = filter_fields
+
+ def get_object(self):
+ pk = self.kwargs.get('pk')
+ return get_object_or_404(AssetPermission, pk=pk)
+
+ def get_queryset(self):
+ perm = self.get_object()
+ assets = perm.get_all_assets().only(
+ *self.serializer_class.Meta.only_fields
+ )
+ return assets
diff --git a/apps/perms/api/mixin.py b/apps/perms/api/mixin.py
new file mode 100644
index 000000000..24bd9abd2
--- /dev/null
+++ b/apps/perms/api/mixin.py
@@ -0,0 +1,225 @@
+# -*- coding: utf-8 -*-
+#
+from functools import reduce
+from hashlib import md5
+from django.core.cache import cache
+from django.db.models import Q
+from django.conf import settings
+from rest_framework.views import Response
+
+from django.utils.translation import ugettext as _
+from common.utils import get_logger
+from assets.utils import LabelFilterMixin
+from ..utils import (
+ AssetPermissionUtil
+)
+from .. import const
+from ..hands import Asset, Node, SystemUser, Label
+from .. import serializers
+
+logger = get_logger(__name__)
+
+__all__ = ['UserPermissionCacheMixin', 'GrantAssetsMixin', 'NodesWithUngroupMixin']
+
+
+class UserPermissionCacheMixin:
+ cache_policy = '0'
+ RESP_CACHE_KEY = '_PERMISSION_RESPONSE_CACHE_V2_{}'
+ CACHE_TIME = settings.ASSETS_PERM_CACHE_TIME
+ _object = None
+
+ def get_object(self):
+ return None
+
+ # 内部使用可控制缓存
+ def _get_object(self):
+ if not self._object:
+ self._object = self.get_object()
+ return self._object
+
+ def get_object_id(self):
+ obj = self._get_object()
+ if obj:
+ return str(obj.id)
+ return None
+
+ def get_request_md5(self):
+ path = self.request.path
+ query = {k: v for k, v in self.request.GET.items()}
+ query.pop("_", None)
+ query = "&".join(["{}={}".format(k, v) for k, v in query.items()])
+ full_path = "{}?{}".format(path, query)
+ return md5(full_path.encode()).hexdigest()
+
+ def get_meta_cache_id(self):
+ obj = self._get_object()
+ util = AssetPermissionUtil(obj, cache_policy=self.cache_policy)
+ meta_cache_id = util.cache_meta.get('id')
+ return meta_cache_id
+
+ def get_response_cache_id(self):
+ obj_id = self.get_object_id()
+ request_md5 = self.get_request_md5()
+ meta_cache_id = self.get_meta_cache_id()
+ resp_cache_id = '{}_{}_{}'.format(obj_id, request_md5, meta_cache_id)
+ return resp_cache_id
+
+ def get_response_from_cache(self):
+ # 没有数据缓冲
+ meta_cache_id = self.get_meta_cache_id()
+ if not meta_cache_id:
+ logger.debug("Not get meta id: {}".format(meta_cache_id))
+ return None
+ # 从响应缓冲里获取响应
+ key = self.get_response_key()
+ data = cache.get(key)
+ if not data:
+ logger.debug("Not get response from cache: {}".format(key))
+ return None
+ logger.debug("Get user permission from cache: {}".format(self.get_object()))
+ response = Response(data)
+ return response
+
+ def expire_response_cache(self):
+ obj_id = self.get_object_id()
+ expire_cache_id = '{}_{}'.format(obj_id, '*')
+ key = self.RESP_CACHE_KEY.format(expire_cache_id)
+ cache.delete_pattern(key)
+
+ def get_response_key(self):
+ resp_cache_id = self.get_response_cache_id()
+ key = self.RESP_CACHE_KEY.format(resp_cache_id)
+ return key
+
+ def set_response_to_cache(self, response):
+ key = self.get_response_key()
+ cache.set(key, response.data, self.CACHE_TIME)
+ logger.debug("Set response to cache: {}".format(key))
+
+ def get(self, request, *args, **kwargs):
+ self.cache_policy = request.GET.get('cache_policy', '0')
+
+ obj = self._get_object()
+ if obj is None:
+ logger.debug("Not get response from cache: obj is none")
+ return super().get(request, *args, **kwargs)
+
+ if AssetPermissionUtil.is_not_using_cache(self.cache_policy):
+ logger.debug("Not get resp from cache: {}".format(self.cache_policy))
+ return super().get(request, *args, **kwargs)
+ elif AssetPermissionUtil.is_refresh_cache(self.cache_policy):
+ logger.debug("Not get resp from cache: {}".format(self.cache_policy))
+ self.expire_response_cache()
+
+ logger.debug("Try get response from cache")
+ resp = self.get_response_from_cache()
+ if not resp:
+ resp = super().get(request, *args, **kwargs)
+ self.set_response_to_cache(resp)
+ return resp
+
+
+class NodesWithUngroupMixin:
+ util = None
+
+ @staticmethod
+ def get_ungrouped_node(ungroup_key):
+ return Node(key=ungroup_key, id=const.UNGROUPED_NODE_ID,
+ value=_("ungrouped"))
+
+ @staticmethod
+ def get_empty_node():
+ return Node(key=const.EMPTY_NODE_KEY, id=const.EMPTY_NODE_ID,
+ value=_("empty"))
+
+ def add_ungrouped_nodes(self, node_map, node_keys):
+ ungroup_key = '1:-1'
+ for key in node_keys:
+ if key.endswith('-1'):
+ ungroup_key = key
+ break
+ ungroup_node = self.get_ungrouped_node(ungroup_key)
+ empty_node = self.get_empty_node()
+ node_map[ungroup_key] = ungroup_node
+ node_map[const.EMPTY_NODE_KEY] = empty_node
+
+
+class GrantAssetsMixin(LabelFilterMixin):
+ serializer_class = serializers.AssetGrantedSerializer
+
+ def get_serializer_queryset(self, queryset):
+ assets_ids = []
+ system_users_ids = set()
+ for asset in queryset:
+ assets_ids.append(asset["id"])
+ system_users_ids.update(set(asset["system_users"]))
+ assets = Asset.objects.filter(id__in=assets_ids).only(
+ *self.serializer_class.Meta.only_fields
+ )
+ assets_map = {asset.id: asset for asset in assets}
+ system_users = SystemUser.objects.filter(id__in=system_users_ids).only(
+ *self.serializer_class.system_users_only_fields
+ )
+ system_users_map = {s.id: s for s in system_users}
+ data = []
+ for item in queryset:
+ i = item["id"]
+ asset = assets_map.get(i)
+ if not asset:
+ continue
+
+ _system_users = item["system_users"]
+ system_users_granted = []
+ for sid, action in _system_users.items():
+ system_user = system_users_map.get(sid)
+ if not system_user:
+ continue
+ system_user.actions = action
+ system_users_granted.append(system_user)
+ asset.system_users_granted = system_users_granted
+ data.append(asset)
+ return data
+
+ def get_serializer(self, queryset_list, many=True):
+ data = self.get_serializer_queryset(queryset_list)
+ return super().get_serializer(data, many=True)
+
+ def search_queryset(self, assets_items):
+ search = self.request.query_params.get("search")
+ if not search:
+ return assets_items
+ assets_map = {asset['id']: asset for asset in assets_items}
+ assets_ids = set(assets_map.keys())
+ assets_ids_search = Asset.objects.filter(id__in=assets_ids).filter(
+ Q(hostname__icontains=search) | Q(ip__icontains=search)
+ ).values_list('id', flat=True)
+ return [assets_map.get(asset_id) for asset_id in assets_ids_search]
+
+ def filter_queryset_by_label(self, assets_items):
+ labels_id = self.get_filter_labels_ids()
+ if not labels_id:
+ return assets_items
+
+ assets_map = {asset['id']: asset for asset in assets_items}
+ assets_matched = Asset.objects.filter(id__in=assets_map.keys())
+ for label_id in labels_id:
+ assets_matched = assets_matched.filter(labels=label_id)
+ assets_ids_matched = assets_matched.values_list('id', flat=True)
+ return [assets_map.get(asset_id) for asset_id in assets_ids_matched]
+
+ def sort_queryset(self, assets_items):
+ order_by = self.request.query_params.get('order', 'hostname')
+
+ if order_by not in ['hostname', '-hostname', 'ip', '-ip']:
+ order_by = 'hostname'
+ assets_map = {asset['id']: asset for asset in assets_items}
+ assets_ids_search = Asset.objects.filter(id__in=assets_map.keys())\
+ .order_by(order_by)\
+ .values_list('id', flat=True)
+ return [assets_map.get(asset_id) for asset_id in assets_ids_search]
+
+ def filter_queryset(self, assets_items):
+ assets_items = self.search_queryset(assets_items)
+ assets_items = self.filter_queryset_by_label(assets_items)
+ assets_items = self.sort_queryset(assets_items)
+ return assets_items
\ No newline at end of file
diff --git a/apps/perms/api/user_group_permission.py b/apps/perms/api/user_group_permission.py
index 9e32055d4..f83330c58 100644
--- a/apps/perms/api/user_group_permission.py
+++ b/apps/perms/api/user_group_permission.py
@@ -2,23 +2,21 @@
#
from django.shortcuts import get_object_or_404
-from rest_framework.generics import (
- ListAPIView, get_object_or_404,
-)
from common.permissions import IsOrgAdmin, IsOrgAdminOrAppUser
from ..hands import UserGroup
-from .. import serializers, const
+from .. import serializers
from .user_permission import (
UserGrantedAssetsApi, UserGrantedNodesApi, UserGrantedNodesWithAssetsApi,
UserGrantedNodesWithAssetsAsTreeApi, UserGrantedNodeAssetsApi,
+ UserGrantedNodesAsTreeApi,
)
__all__ = [
'UserGroupGrantedAssetsApi', 'UserGroupGrantedNodesApi',
'UserGroupGrantedNodesWithAssetsApi', 'UserGroupGrantedNodeAssetsApi',
- 'UserGroupGrantedNodesWithAssetsAsTreeApi',
+ 'UserGroupGrantedNodesWithAssetsAsTreeApi', 'UserGroupGrantedNodesAsTreeApi',
]
@@ -36,6 +34,13 @@ class UserGroupGrantedNodesApi(UserGrantedNodesApi):
return user_group
+class UserGroupGrantedNodesAsTreeApi(UserGrantedNodesAsTreeApi):
+ def get_object(self):
+ user_group_id = self.kwargs.get('pk', '')
+ user_group = get_object_or_404(UserGroup, id=user_group_id)
+ return user_group
+
+
class UserGroupGrantedNodesWithAssetsApi(UserGrantedNodesWithAssetsApi):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.NodeGrantedSerializer
diff --git a/apps/perms/api/user_permission.py b/apps/perms/api/user_permission.py
index 8d55ee49c..0e67e2747 100644
--- a/apps/perms/api/user_permission.py
+++ b/apps/perms/api/user_permission.py
@@ -2,25 +2,23 @@
#
import time
import traceback
+from functools import reduce
import uuid
-from hashlib import md5
-from django.core.cache import cache
-from django.conf import settings
from django.db.models import Q
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView, Response
from rest_framework.generics import (
ListAPIView, get_object_or_404, RetrieveAPIView
)
-from django.utils.translation import ugettext as _
from rest_framework.pagination import LimitOffsetPagination
from common.permissions import IsValidUser, IsOrgAdminOrAppUser
from common.tree import TreeNodeSerializer
-from common.utils import get_logger, get_object_or_none
+from common.utils import get_logger
from ..utils import (
AssetPermissionUtil, ParserNode,
)
+from .mixin import UserPermissionCacheMixin, GrantAssetsMixin, NodesWithUngroupMixin
from .. import const
from ..hands import User, Asset, Node, SystemUser, NodeSerializer
from .. import serializers
@@ -37,153 +35,6 @@ __all__ = [
]
-class UserPermissionCacheMixin:
- cache_policy = '0'
- RESP_CACHE_KEY = '_PERMISSION_RESPONSE_CACHE_V2_{}'
- CACHE_TIME = settings.ASSETS_PERM_CACHE_TIME
- _object = None
-
- def get_object(self):
- return None
-
- # 内部使用可控制缓存
- def _get_object(self):
- if not self._object:
- self._object = self.get_object()
- return self._object
-
- def get_object_id(self):
- obj = self._get_object()
- if obj:
- return str(obj.id)
- return None
-
- def get_request_md5(self):
- path = self.request.path
- query = {k: v for k, v in self.request.GET.items()}
- query.pop("_", None)
- query = "&".join(["{}={}".format(k, v) for k, v in query.items()])
- full_path = "{}?{}".format(path, query)
- return md5(full_path.encode()).hexdigest()
-
- def get_meta_cache_id(self):
- obj = self._get_object()
- util = AssetPermissionUtil(obj, cache_policy=self.cache_policy)
- meta_cache_id = util.cache_meta.get('id')
- return meta_cache_id
-
- def get_response_cache_id(self):
- obj_id = self.get_object_id()
- request_md5 = self.get_request_md5()
- meta_cache_id = self.get_meta_cache_id()
- resp_cache_id = '{}_{}_{}'.format(obj_id, request_md5, meta_cache_id)
- return resp_cache_id
-
- def get_response_from_cache(self):
- # 没有数据缓冲
- meta_cache_id = self.get_meta_cache_id()
- if not meta_cache_id:
- logger.debug("Not get meta id: {}".format(meta_cache_id))
- return None
- # 从响应缓冲里获取响应
- key = self.get_response_key()
- data = cache.get(key)
- if not data:
- logger.debug("Not get response from cache: {}".format(key))
- return None
- logger.debug("Get user permission from cache: {}".format(self.get_object()))
- response = Response(data)
- return response
-
- def expire_response_cache(self):
- obj_id = self.get_object_id()
- expire_cache_id = '{}_{}'.format(obj_id, '*')
- key = self.RESP_CACHE_KEY.format(expire_cache_id)
- cache.delete_pattern(key)
-
- def get_response_key(self):
- resp_cache_id = self.get_response_cache_id()
- key = self.RESP_CACHE_KEY.format(resp_cache_id)
- return key
-
- def set_response_to_cache(self, response):
- key = self.get_response_key()
- cache.set(key, response.data, self.CACHE_TIME)
- logger.debug("Set response to cache: {}".format(key))
-
- def get(self, request, *args, **kwargs):
- self.cache_policy = request.GET.get('cache_policy', '0')
-
- obj = self._get_object()
- if obj is None:
- logger.debug("Not get response from cache: obj is none")
- return super().get(request, *args, **kwargs)
-
- if AssetPermissionUtil.is_not_using_cache(self.cache_policy):
- logger.debug("Not get resp from cache: {}".format(self.cache_policy))
- return super().get(request, *args, **kwargs)
- elif AssetPermissionUtil.is_refresh_cache(self.cache_policy):
- logger.debug("Not get resp from cache: {}".format(self.cache_policy))
- self.expire_response_cache()
-
- logger.debug("Try get response from cache")
- resp = self.get_response_from_cache()
- if not resp:
- resp = super().get(request, *args, **kwargs)
- self.set_response_to_cache(resp)
- return resp
-
-
-class GrantAssetsMixin:
- serializer_class = serializers.AssetGrantedSerializer
-
- def get_serializer(self, queryset, many=True):
- assets_ids = []
- system_users_ids = set()
- for asset in queryset:
- assets_ids.append(asset["id"])
- system_users_ids.update(set(asset["system_users"]))
- assets = Asset.objects.filter(id__in=assets_ids).only(
- *self.serializer_class.Meta.only_fields
- )
- assets_map = {asset.id: asset for asset in assets}
- system_users = SystemUser.objects.filter(id__in=system_users_ids).only(
- *self.serializer_class.system_users_only_fields
- )
- system_users_map = {s.id: s for s in system_users}
- data = []
- for item in queryset:
- i = item["id"]
- asset = assets_map.get(i)
- if not asset:
- continue
-
- _system_users = item["system_users"]
- system_users_granted = []
- for sid, action in _system_users.items():
- system_user = system_users_map.get(sid)
- if not system_user:
- continue
- system_user.actions = action
- system_users_granted.append(system_user)
- asset.system_users_granted = system_users_granted
- data.append(asset)
- return super().get_serializer(data, many=True)
-
- def search_queryset(self, assets):
- search = self.request.query_params.get("search")
- if not search:
- return assets
-
- assets_map = {asset['id']: asset for asset in assets}
- assets_ids = set(assets_map.keys())
- assets_ids_search = Asset.objects.filter(id__in=assets_ids).filter(
- Q(hostname__icontains=search) | Q(ip__icontains=search)
- ).values_list('id', flat=True)
- assets_ids &= set(assets_ids_search)
- return [assets_map.get(asset_id) for asset_id in assets_ids]
-
-
class UserGrantedAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIView):
"""
用户授权的所有资产
@@ -203,7 +54,6 @@ class UserGrantedAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIVi
user = self.get_object()
util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
queryset = util.get_assets()
- queryset = self.search_queryset(queryset)
return queryset
def get_permissions(self):
@@ -212,29 +62,52 @@ class UserGrantedAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIVi
return super().get_permissions()
-class NodesWithUngroupMixin:
- util = None
+class UserGrantedNodeAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIView):
+ """
+ 查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产
+ """
+ permission_classes = (IsOrgAdminOrAppUser,)
+ pagination_class = LimitOffsetPagination
- @staticmethod
- def get_ungrouped_node(ungroup_key):
- return Node(key=ungroup_key, id=const.UNGROUPED_NODE_ID,
- value=_("ungrouped"))
+ def get_object(self):
+ user_id = self.kwargs.get('pk', '')
- @staticmethod
- def get_empty_node():
- return Node(key=const.EMPTY_NODE_KEY, id=const.EMPTY_NODE_ID,
- value=_("empty"))
+ if user_id:
+ user = get_object_or_404(User, id=user_id)
+ else:
+ user = self.request.user
+ return user
- def add_ungrouped_nodes(self, node_map, node_keys):
- ungroup_key = '1:-1'
- for key in node_keys:
- if key.endswith('-1'):
- ungroup_key = key
+ def get_node_key(self):
+ node_id = self.kwargs.get('node_id')
+ if str(node_id) == const.UNGROUPED_NODE_ID:
+ key = self.util.tree.ungrouped_key
+ elif str(node_id) == const.EMPTY_NODE_ID:
+ key = const.EMPTY_NODE_KEY
+ else:
+ node = get_object_or_404(Node, id=node_id)
+ key = node.key
+ return key
+
+ def get_queryset(self):
+ user = self.get_object()
+ self.util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
+ key = self.get_node_key()
+ nodes_items = self.util.get_nodes_with_assets()
+ assets_system_users = {}
+ for item in nodes_items:
+ if item["key"] == key:
+ assets_system_users = item["assets"]
break
- ungroup_node = self.get_ungrouped_node(ungroup_key)
- empty_node = self.get_empty_node()
- node_map[ungroup_key] = ungroup_node
- node_map[const.EMPTY_NODE_KEY] = empty_node
+ assets = []
+ for asset_id, system_users in assets_system_users.items():
+ assets.append({"id": asset_id, "system_users": system_users})
+ return assets
+
+ def get_permissions(self):
+ if self.kwargs.get('pk') is None:
+ self.permission_classes = (IsValidUser,)
+ return super().get_permissions()
class UserGrantedNodesApi(UserPermissionCacheMixin, NodesWithUngroupMixin, ListAPIView):
@@ -435,55 +308,6 @@ class UserGrantedNodesWithAssetsAsTreeApi(UserGrantedNodesWithAssetsApi):
return self.serializer_class(queryset, many=True)
-class UserGrantedNodeAssetsApi(UserPermissionCacheMixin, GrantAssetsMixin, ListAPIView):
- """
- 查询用户授权的节点下的资产的api, 与上面api不同的是,只返回某个节点下的资产
- """
- permission_classes = (IsOrgAdminOrAppUser,)
- pagination_class = LimitOffsetPagination
-
- def get_object(self):
- user_id = self.kwargs.get('pk', '')
-
- if user_id:
- user = get_object_or_404(User, id=user_id)
- else:
- user = self.request.user
- return user
-
- def get_node_key(self):
- node_id = self.kwargs.get('node_id')
- if str(node_id) == const.UNGROUPED_NODE_ID:
- key = self.util.tree.ungrouped_key
- elif str(node_id) == const.EMPTY_NODE_ID:
- key = const.EMPTY_NODE_KEY
- else:
- node = get_object_or_404(Node, id=node_id)
- key = node.key
- return key
-
- def get_queryset(self):
- user = self.get_object()
- self.util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
- key = self.get_node_key()
- nodes_items = self.util.get_nodes_with_assets()
- assets_system_users = {}
- for item in nodes_items:
- if item["key"] == key:
- assets_system_users = item["assets"]
- break
- assets = []
- for asset_id, system_users in assets_system_users.items():
- assets.append({"id": asset_id, "system_users": system_users})
- assets = self.search_queryset(assets)
- return assets
-
- def get_permissions(self):
- if self.kwargs.get('pk') is None:
- self.permission_classes = (IsValidUser,)
- return super().get_permissions()
-
-
class ValidateUserAssetPermissionApi(UserPermissionCacheMixin, APIView):
permission_classes = (IsOrgAdminOrAppUser,)
@@ -522,16 +346,12 @@ class GetUserAssetPermissionActionsApi(UserPermissionCacheMixin, RetrieveAPIView
system_id = self.request.query_params.get('system_user_id', '')
user = get_object_or_404(User, id=user_id)
- asset = get_object_or_404(Asset, id=asset_id)
- su = get_object_or_404(SystemUser, id=system_id)
util = AssetPermissionUtil(user, cache_policy=self.cache_policy)
- granted_assets = util.get_assets()
- granted_system_users = granted_assets.get(asset, {})
-
- _object = {}
- if su not in granted_system_users:
- _object['actions'] = 0
- else:
- _object['actions'] = granted_system_users[su]
- return _object
+ assets = util.get_assets()
+ actions = 0
+ for asset in assets:
+ if asset_id == asset["id"]:
+ actions = asset["system_users"].get(system_id, 0)
+ break
+ return {"actions": actions}
diff --git a/apps/perms/hands.py b/apps/perms/hands.py
index bbdc01e1e..aef0f4875 100644
--- a/apps/perms/hands.py
+++ b/apps/perms/hands.py
@@ -2,7 +2,7 @@
#
from users.models import User, UserGroup
-from assets.models import Asset, SystemUser, Node
+from assets.models import Asset, SystemUser, Node, Label
from assets.serializers import NodeSerializer
from applications.serializers import RemoteAppSerializer
from applications.models import RemoteApp
diff --git a/apps/perms/models/asset_permission.py b/apps/perms/models/asset_permission.py
index cb3e37768..b10d33d6b 100644
--- a/apps/perms/models/asset_permission.py
+++ b/apps/perms/models/asset_permission.py
@@ -2,6 +2,7 @@ import uuid
from functools import reduce
from django.db import models
+from django.db.models import Q
from django.utils.translation import ugettext_lazy as _
from common.utils import date_expired_default, set_or_append_attr_bulk
@@ -93,11 +94,16 @@ class AssetPermission(BasePermission):
)
def get_all_assets(self):
- assets = set(self.assets.all())
- for node in self.nodes.all():
- _assets = node.get_all_assets()
- set_or_append_attr_bulk(_assets, 'inherit', node.value)
- assets.update(set(_assets))
+ args = [Q(granted_by_permissions=self)]
+ pattern = set()
+ nodes_keys = self.nodes.all().values_list('key', flat=True)
+ for key in nodes_keys:
+ pattern.add(r'^{0}$|^{0}:'.format(key))
+ pattern = '|'.join(list(pattern))
+ if pattern:
+ args.append(Q(nodes__key__regex=pattern))
+ args = reduce(lambda x, y: x | y, args)
+ assets = Asset.objects.filter(args)
return assets
diff --git a/apps/perms/serializers/asset_permission.py b/apps/perms/serializers/asset_permission.py
index ecbed669b..7bc145d9f 100644
--- a/apps/perms/serializers/asset_permission.py
+++ b/apps/perms/serializers/asset_permission.py
@@ -6,11 +6,12 @@ from rest_framework import serializers
from common.fields import StringManyToManyField
from orgs.mixins import BulkOrgResourceModelSerializer
from perms.models import AssetPermission, Action
+from assets.models import Asset
__all__ = [
'AssetPermissionCreateUpdateSerializer', 'AssetPermissionListSerializer',
'AssetPermissionUpdateUserSerializer', 'AssetPermissionUpdateAssetSerializer',
- 'ActionsField',
+ 'ActionsField', 'AssetPermissionAssetsSerializer',
]
@@ -70,3 +71,11 @@ class AssetPermissionUpdateAssetSerializer(serializers.ModelSerializer):
class Meta:
model = AssetPermission
fields = ['id', 'assets']
+
+
+class AssetPermissionAssetsSerializer(serializers.ModelSerializer):
+
+ class Meta:
+ model = Asset
+ only_fields = ['id', 'hostname', 'ip']
+ fields = tuple(only_fields)
diff --git a/apps/perms/templates/perms/asset_permission_asset.html b/apps/perms/templates/perms/asset_permission_asset.html
index e774692f3..d8cd8ee96 100644
--- a/apps/perms/templates/perms/asset_permission_asset.html
+++ b/apps/perms/templates/perms/asset_permission_asset.html
@@ -48,29 +48,19 @@
-
+
-
- {% include '_pagination.html' %}
-
@@ -86,9 +76,6 @@
|
@@ -146,6 +133,7 @@
+{% include 'assets/_asset_list_modal.html' %}
{% endblock %}
{% block custom_foot_js %}
diff --git a/apps/users/templates/users/user_create.html b/apps/users/templates/users/user_create.html
index 13bb26cbc..5e15b5469 100644
--- a/apps/users/templates/users/user_create.html
+++ b/apps/users/templates/users/user_create.html
@@ -4,9 +4,7 @@
{% block user_template_title %}{% trans "Create user" %}{% endblock %}
{% block password %}
{% bootstrap_field form.password_strategy layout="horizontal" %}
-
- {% bootstrap_field form.password layout="horizontal" %}
-
+ {% bootstrap_field form.password layout="horizontal" %}
{# 密码popover #}
@@ -29,7 +27,7 @@ function passwordCheck() {
progress = $('#id_progress'),
password_check_rules = {{ password_check_rules|safe }},
minLength = 6,
- top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) - 10 + 34,
+ top = idPassword.offset().top - $('.navbar').outerHeight(true) - $('.page-heading').outerHeight(true) -77 + 34,
left = 377,
i18n_fallback = {
"veryWeak": "{% trans 'Very weak' %}",
@@ -67,9 +65,9 @@ var password_strategy_radio_input = 'input[type=radio][name=password_strategy]';
function passwordStrategyFieldsDisplay(){
var val = $('input:radio[name="password_strategy"]:checked').val();
if(val === '0'){
- $('#custom_password').addClass('hidden')
+ $('#id_password').parents('.form-group').addClass('hidden')
}else {
- $('#custom_password').removeClass('hidden')
+ $('#id_password').parents('.form-group').removeClass('hidden')
}
}
$(document).ready(function () {
@@ -78,7 +76,25 @@ $(document).ready(function () {
}).on('change', password_strategy_radio_input, function(){
passwordStrategyFieldsDisplay()
- })
+})
+.on("submit", "form", function (evt) {
+ evt.preventDefault();
+ var the_url = '{% url 'api-users:user-list' %}';
+ var redirect_to = '{% url "users:user-list" %}';
+ var method = "POST";
+ var form = $("form");
+ var data = form.serializeObject();
+ objectAttrsIsList(data, ['groups']);
+ objectAttrsIsDatetime(data,['date_expired']);
+ var props = {
+ url: the_url,
+ data: data,
+ method: method,
+ form: form,
+ redirect_to: redirect_to
+ };
+ formSubmit(props);
+})
{% endblock %}
diff --git a/apps/users/templates/users/user_detail.html b/apps/users/templates/users/user_detail.html
index 351823a9e..929d7def4 100644
--- a/apps/users/templates/users/user_detail.html
+++ b/apps/users/templates/users/user_detail.html
@@ -280,7 +280,7 @@ function updateUserGroups(groups) {
// clear jumpserver.groups_selected
jumpserver.nodes_selected = {};
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -305,7 +305,7 @@ $(document).ready(function() {
'is_active': checked
};
var success = '{% trans "Update successfully!" %}';
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success_message: success
@@ -332,7 +332,7 @@ $(document).ready(function() {
'otp_secret_key': otp_secret_key
};
var success = '{% trans "Update successfully!" %}';
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success_message: success
@@ -372,7 +372,7 @@ $(document).ready(function() {
var msg = "{% trans "An e-mail has been sent to the user`s mailbox." %}";
swal("{% trans 'Reset password' %}", msg, "success");
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -398,7 +398,7 @@ $(document).ready(function() {
var msg = "{% trans 'The reset-ssh-public-key E-mail has been sent successfully. Please inform the user to update his new ssh public key.' %}";
swal("{% trans 'Reset SSH public key' %}", msg, "success");
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: body,
success: success
@@ -441,7 +441,7 @@ $(document).ready(function() {
}
);
};
- APIUpdateAttr({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
+ requestApi({ url: the_url, body: JSON.stringify(body), success: success, error: fail});
}).on('click', '.btn-delete-user', function () {
var $this = $(this);
var name = "{{ user_object.name }}";
@@ -466,7 +466,7 @@ $(document).ready(function() {
}
);
};
- APIUpdateAttr({
+ requestApi({
url: the_url,
body: JSON.stringify(body),
success: success
@@ -485,7 +485,7 @@ $(document).ready(function() {
doReset();
});
}).on('click', '#btn-reset-mfa', function () {
- APIUpdateAttr({
+ requestApi({
url: "{% url 'api-users:user-reset-otp' pk=user_object.id %}",
method: "GET",
success_message: "{% trans 'Reset user MFA success' %}"
diff --git a/apps/users/templates/users/user_granted_asset.html b/apps/users/templates/users/user_granted_asset.html
index 225005ffd..fc5197a77 100644
--- a/apps/users/templates/users/user_granted_asset.html
+++ b/apps/users/templates/users/user_granted_asset.html
@@ -23,33 +23,7 @@
-
-
-
-
+ {% include 'users/_granted_assets.html' %}
@@ -58,81 +32,10 @@
{% endblock %}
{% block custom_foot_js %}
{% endblock %}