mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-08-23 16:39:30 +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
|
||||
.exclude(**{f'{key}__isnull': True})
|
||||
.values(**{alias: F(key)})
|
||||
.annotate(total=Count('id'))
|
||||
.annotate(total=Count('id', distinct=True))
|
||||
)
|
||||
|
||||
data = [
|
||||
|
@ -8,7 +8,7 @@ from rest_framework.views import APIView
|
||||
|
||||
from audits.models import PasswordChangeLog
|
||||
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 reports.mixins import DateRangeMixin
|
||||
|
||||
@ -24,22 +24,6 @@ class UserChangeSecretApi(DateRangeMixin, APIView):
|
||||
}
|
||||
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):
|
||||
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),
|
||||
}
|
||||
|
||||
data['change_password_region_distribution'] = self.get_change_password_region_distribution(qs)
|
||||
return JsonResponse(data, status=200)
|
||||
|
@ -1,79 +1,56 @@
|
||||
{% load i18n %}
|
||||
{% 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 %}
|
||||
<style>
|
||||
.markdown-footer {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: translateX(-50%);
|
||||
width: 285px;
|
||||
}
|
||||
|
||||
.markdown-footer p {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
gap: 3px;
|
||||
}
|
||||
<style>
|
||||
.markdown-footer{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
transform: translateX(-50%);
|
||||
max-width: 520px;
|
||||
width: calc(100% - 40px);
|
||||
padding: 8px 0;
|
||||
text-align: center;
|
||||
line-height: 1.4;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.markdown-footer a {
|
||||
color: #428bca;
|
||||
}
|
||||
</style>
|
||||
<div id="markdown-output" class="markdown-footer"></div>
|
||||
.markdown-footer p{ margin: 0; }
|
||||
.markdown-footer a{ color: #428bca; text-decoration: none; }
|
||||
.markdown-footer a:hover{ text-decoration: underline; }
|
||||
</style>
|
||||
<div id="markdown-output" class="markdown-footer" role="contentinfo" aria-label="{% trans 'Page footer' %}"></div>
|
||||
{% endif %}
|
||||
|
||||
<script src="{% static 'js/plugins/markdown-it.min.js' %}"></script>
|
||||
|
||||
<script type="text/markdown"> {{ INTERFACE.footer_content }} </script>
|
||||
<script>
|
||||
activeNav("{{ FORCE_SCRIPT_NAME }}");
|
||||
$(document).ready(function () {
|
||||
setAjaxCSRFToken();
|
||||
$('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');
|
||||
(function () {
|
||||
var container = document.getElementById('markdown-output');
|
||||
if (!container) return;
|
||||
|
||||
if (markdownRef && markdownContent) {
|
||||
const renderedContent = md.render(markdownContent.trim());
|
||||
markdownRef.innerHTML = renderedContent;
|
||||
markdownRef.querySelectorAll('a').forEach(link => {
|
||||
link.setAttribute('target', '_blank');
|
||||
link.setAttribute('rel', 'noopener noreferrer');
|
||||
});
|
||||
}
|
||||
var src = `{{ INTERFACE.footer_content|default:''|escapejs }}`.replace(/\r\n?/g, '\n').trim();
|
||||
if (!src) { container.remove(); return; }
|
||||
|
||||
var md = window.markdownit({
|
||||
html: false,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
breaks: true
|
||||
});
|
||||
</script>
|
||||
|
||||
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>
|
Loading…
Reference in New Issue
Block a user