mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-08-24 17:09:26 +00:00
perf: user asset account report
This commit is contained in:
parent
ab30bfb2d2
commit
0fb7e84678
@ -6,7 +6,7 @@ def group_stats(queryset, alias, key, label_map=None):
|
|||||||
queryset
|
queryset
|
||||||
.exclude(**{f'{key}__isnull': True})
|
.exclude(**{f'{key}__isnull': True})
|
||||||
.values(**{alias: F(key)})
|
.values(**{alias: F(key)})
|
||||||
.annotate(total=Count('id'))
|
.annotate(total=Count('id', distinct=True))
|
||||||
)
|
)
|
||||||
|
|
||||||
data = [
|
data = [
|
||||||
|
@ -8,7 +8,7 @@ from rest_framework.views import APIView
|
|||||||
|
|
||||||
from audits.models import PasswordChangeLog
|
from audits.models import PasswordChangeLog
|
||||||
from common.permissions import IsValidLicense
|
from common.permissions import IsValidLicense
|
||||||
from common.utils import lazyproperty, get_ip_city, get_logger
|
from common.utils import lazyproperty, get_logger
|
||||||
from rbac.permissions import RBACPermission
|
from rbac.permissions import RBACPermission
|
||||||
from reports.mixins import DateRangeMixin
|
from reports.mixins import DateRangeMixin
|
||||||
|
|
||||||
@ -24,22 +24,6 @@ class UserChangeSecretApi(DateRangeMixin, APIView):
|
|||||||
}
|
}
|
||||||
permission_classes = [RBACPermission, IsValidLicense]
|
permission_classes = [RBACPermission, IsValidLicense]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_change_password_region_distribution(queryset):
|
|
||||||
unique_ips = queryset.values_list('remote_addr', flat=True).distinct()
|
|
||||||
data = defaultdict(int)
|
|
||||||
for ip in unique_ips:
|
|
||||||
try:
|
|
||||||
city = str(get_ip_city(ip))
|
|
||||||
if not city:
|
|
||||||
continue
|
|
||||||
data[city] += 1
|
|
||||||
except Exception:
|
|
||||||
logger.debug(f"Failed to get city for IP {ip}, skipping", exc_info=True)
|
|
||||||
continue
|
|
||||||
|
|
||||||
return [{'name': k, 'value': v} for k, v in data.items()]
|
|
||||||
|
|
||||||
def get_change_password_metrics(self, queryset):
|
def get_change_password_metrics(self, queryset):
|
||||||
filtered_queryset = self.filter_by_date_range(queryset, 'datetime')
|
filtered_queryset = self.filter_by_date_range(queryset, 'datetime')
|
||||||
|
|
||||||
@ -82,5 +66,4 @@ class UserChangeSecretApi(DateRangeMixin, APIView):
|
|||||||
'dates_metrics_total': self.get_change_password_metrics(qs),
|
'dates_metrics_total': self.get_change_password_metrics(qs),
|
||||||
}
|
}
|
||||||
|
|
||||||
data['change_password_region_distribution'] = self.get_change_password_region_distribution(qs)
|
|
||||||
return JsonResponse(data, status=200)
|
return JsonResponse(data, status=200)
|
||||||
|
@ -1,79 +1,56 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<!-- Mainly scripts -->
|
|
||||||
<script src="{% static "js/plugins/metisMenu/jquery.metisMenu.3.0.7.js" %}"></script>
|
|
||||||
|
|
||||||
<!-- Custom and plugin javascript -->
|
|
||||||
<script src="{% static "js/plugins/toastr/toastr.min.js" %}"></script>
|
|
||||||
<script src="{% static "js/inspinia.js" %}"></script>
|
|
||||||
<script src="{% static "js/jumpserver.js" %}?v=10"></script>
|
|
||||||
<script src="{% static 'js/plugins/select2/select2.full.min.js' %}"></script>
|
|
||||||
<script src="{% static 'js/plugins/select2/i18n/zh-CN.js' %}"></script>
|
|
||||||
<script src="{% static 'js/plugins/markdown-it.min.js' %}"></script>
|
|
||||||
|
|
||||||
{% if INTERFACE.footer_content %}
|
{% if INTERFACE.footer_content %}
|
||||||
<style>
|
<style>
|
||||||
.markdown-footer {
|
.markdown-footer{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
display: flex;
|
transform: translateX(-50%);
|
||||||
flex-grow: 0;
|
max-width: 520px;
|
||||||
flex-shrink: 0;
|
width: calc(100% - 40px);
|
||||||
align-items: center;
|
padding: 8px 0;
|
||||||
justify-content: center;
|
text-align: center;
|
||||||
transform: translateX(-50%);
|
line-height: 1.4;
|
||||||
width: 285px;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-footer p {
|
.markdown-footer p{ margin: 0; }
|
||||||
display: flex;
|
.markdown-footer a{ color: #428bca; text-decoration: none; }
|
||||||
flex-direction: column;
|
.markdown-footer a:hover{ text-decoration: underline; }
|
||||||
align-items: center;
|
</style>
|
||||||
justify-content: center;
|
<div id="markdown-output" class="markdown-footer" role="contentinfo" aria-label="{% trans 'Page footer' %}"></div>
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
gap: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-footer a {
|
|
||||||
color: #428bca;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div id="markdown-output" class="markdown-footer"></div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<script src="{% static 'js/plugins/markdown-it.min.js' %}"></script>
|
||||||
|
|
||||||
<script type="text/markdown"> {{ INTERFACE.footer_content }} </script>
|
|
||||||
<script>
|
<script>
|
||||||
activeNav("{{ FORCE_SCRIPT_NAME }}");
|
(function () {
|
||||||
$(document).ready(function () {
|
var container = document.getElementById('markdown-output');
|
||||||
setAjaxCSRFToken();
|
if (!container) return;
|
||||||
$('textarea').attr('rows', 5);
|
|
||||||
if ($('.tooltip')[0]) {
|
|
||||||
$('.tooltip').tooltip();
|
|
||||||
}
|
|
||||||
$.fn.select2.defaults.set('language', getUserLang());
|
|
||||||
const md = window.markdownit({
|
|
||||||
html: true,
|
|
||||||
linkify: true,
|
|
||||||
typographer: true,
|
|
||||||
breaks: false
|
|
||||||
});
|
|
||||||
const markdownContent = `{{ INTERFACE.footer_content|escapejs }}`;
|
|
||||||
const markdownRef = document.getElementById('markdown-output');
|
|
||||||
|
|
||||||
if (markdownRef && markdownContent) {
|
var src = `{{ INTERFACE.footer_content|default:''|escapejs }}`.replace(/\r\n?/g, '\n').trim();
|
||||||
const renderedContent = md.render(markdownContent.trim());
|
if (!src) { container.remove(); return; }
|
||||||
markdownRef.innerHTML = renderedContent;
|
|
||||||
markdownRef.querySelectorAll('a').forEach(link => {
|
var md = window.markdownit({
|
||||||
link.setAttribute('target', '_blank');
|
html: false,
|
||||||
link.setAttribute('rel', 'noopener noreferrer');
|
linkify: true,
|
||||||
});
|
typographer: true,
|
||||||
}
|
breaks: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var html = md.render(src);
|
||||||
|
|
||||||
|
if (window.DOMPurify) {
|
||||||
|
html = window.DOMPurify.sanitize(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
container.innerHTML = html;
|
||||||
|
|
||||||
|
container.querySelectorAll('a').forEach(function (a) {
|
||||||
|
a.setAttribute('target', '_blank');
|
||||||
|
a.setAttribute('rel', 'noopener noreferrer');
|
||||||
|
});
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user