diff --git a/allianceauth/services/modules/mumble/templates/services/mumble/mumble_connection_history.html b/allianceauth/services/modules/mumble/templates/services/mumble/mumble_connection_history.html new file mode 100644 index 00000000..99ad0be0 --- /dev/null +++ b/allianceauth/services/modules/mumble/templates/services/mumble/mumble_connection_history.html @@ -0,0 +1,185 @@ +{% extends "allianceauth/base-bs5.html" %} +{% load i18n %} +{% load humanize %} + +{% block page_title %} + {% translate "Mumble" %} +{% endblock page_title %} + +{% block header_nav_brand %} + {% trans "Mumble History" %} - {{ mumble_url }} +{% endblock header_nav_brand %} +{% block header_nav_collapse_left %} +{% endblock header_nav_collapse_left %} + +{% block header_nav_collapse_right %} +{% endblock header_nav_collapse_right %} + +{% block content %} +
+
+ {% translate "Server Connection History" %} +
+
+
+
+ + + + + + + + + + + +
{% translate "User" %}{% translate "Display_Name" %}{% translate "Release" %}{% translate "Version" %}{% translate "Last Connection" %}{% translate "Last Disconnection" %}
+
+
+
+
+
+
+
+ {% translate "Server Connection Breakdown" %} +
+
+
+
+ +
+
+
+
+
+
+
+ {% translate "Server Connection Breakdown" %} +
+
+
+
+ + + + + + + +
{% translate "Version" %}{% translate "Number" %}
+
+
+
+
+
+{% endblock content %} +{% block extra_javascript %} + {% include "bundles/datatables-js-bs5.html" %} + {% include "bundles/filterdropdown-js.html" %} + {% include "bundles/chart-js.html" %} + {% include "bundles/moment-js.html" with locale=True %} + +{% endblock extra_javascript %} + +{% block extra_css %} + {% include "bundles/datatables-css-bs5.html" %} +{% endblock extra_css %} +{% block extra_script %} +$(document).ready(function () { + $("#table-mumble-connection-history").DataTable({ + ajax: { + url: "{% url 'mumble:connection_history_data' %}", + dataSrc: "connection_history_data", + }, + columns: [ + { data: "user" }, + { data: "display_name" }, + { data: "release" }, + { data: "version" }, + { data: "last_connect" }, + { data: "last_connect" }, + ], + order: [[4, "desc"]], + processing: true, + stateSave: true, + stateDuration: 0, + filterDropDown: { + columns: [ + { + idx: 2, + }, + { + idx: 3, + }, + ], + bootstrap: true, + bootstrap_version: 5, + }, + }); + + $("#table-mumble-connection-stats").DataTable({ + ajax: { + url: "{% url 'mumble:release_counts_data' %}", + dataSrc: "release_counts_data", + }, + columns: [{ data: "release" }, { data: "user_count" }], + order: [[1, "desc"]], + processing: true, + stateSave: true, + stateDuration: 0, + }); + + // Initialize empty Pie chart + var ctx = document.getElementById("pieChart").getContext("2d"); + var pieChart = new Chart(ctx, { + type: "pie", + data: { + labels: [], // Initially empty + datasets: [ + { + label: "Server Connection Breakdown", + data: [], // Initially empty + backgroundColor: [ + "rgba(255, 99, 132, 0.2)", + "rgba(54, 162, 235, 0.2)", + "rgba(255, 206, 86, 0.2)", + ], + borderColor: [ + "rgba(255, 99, 132, 1)", + "rgba(54, 162, 235, 1)", + "rgba(255, 206, 86, 1)", + ], + borderWidth: 1, + }, + ], + }, + options: { + responsive: true, + plugins: { + legend: { + position: "top", + }, + }, + }, + }); + + // AJAX call to dynamically update the chart + $.ajax({ + url: "{% url 'mumble:release_pie_chart_data' %}", // Your Django view URL that returns chart data + method: "GET", + success: function (data) { + // Replace chart data with the data from the AJAX response + pieChart.data.labels = data.labels; // Set the new labels + pieChart.data.datasets[0].data = data.values; // Set the new values + + // Update the chart to reflect the new data + pieChart.update(); + }, + error: function (xhr, status, error) { + console.error("Error fetching pie chart data:", status, error); + }, + }); +}); + +{% endblock extra_script %} diff --git a/allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html b/allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html index e140ee7c..cf122157 100644 --- a/allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html +++ b/allianceauth/services/modules/mumble/templates/services/mumble/mumble_service_ctrl.html @@ -48,4 +48,9 @@ {% endif %} {% endif %} + {% if request.user.is_superuser %} + + History + +{% endif %} {% endblock %} diff --git a/allianceauth/services/modules/mumble/urls.py b/allianceauth/services/modules/mumble/urls.py index ef7ff699..d3276e0b 100644 --- a/allianceauth/services/modules/mumble/urls.py +++ b/allianceauth/services/modules/mumble/urls.py @@ -10,6 +10,10 @@ module_urls = [ path('deactivate/', views.DeleteMumbleView.as_view(), name='deactivate'), path('reset_password/', views.ResetPasswordMumbleView.as_view(), name='reset_password'), path('set_password/', views.SetPasswordMumbleView.as_view(), name='set_password'), + path('connection_history/', views.connection_history, name="connection_history"), + path('ajax/connection_history_data', views.connection_history_data, name="connection_history_data"), + path('ajax/release_counts_data', views.release_counts_data, name="release_counts_data"), + path('ajax/release_pie_chart_data', views.release_pie_chart_data, name="release_pie_chart_data"), ] urlpatterns = [ diff --git a/allianceauth/services/modules/mumble/views.py b/allianceauth/services/modules/mumble/views.py index ba8904fd..7dd07c82 100644 --- a/allianceauth/services/modules/mumble/views.py +++ b/allianceauth/services/modules/mumble/views.py @@ -3,6 +3,11 @@ import logging from allianceauth.services.forms import ServicePasswordModelForm from allianceauth.services.abstract import BaseCreatePasswordServiceAccountView, BaseDeactivateServiceAccountView, \ BaseResetPasswordServiceAccountView, BaseSetPasswordServiceAccountView +from django.conf import settings +from django.contrib.auth.decorators import login_required, permission_required +from django.db.models import Count +from django.http import HttpResponse, JsonResponse +from django.shortcuts import render from .models import MumbleUser @@ -35,3 +40,51 @@ class ResetPasswordMumbleView(MumbleViewMixin, BaseResetPasswordServiceAccountVi class SetPasswordMumbleView(MumbleViewMixin, BaseSetPasswordServiceAccountView): form_class = MumblePasswordForm + + +@login_required +@permission_required('mumble.view_connection_history') +def connection_history(request) -> HttpResponse: + + context = { + "mumble_url": settings.MUMBLE_URL, + } + + return render(request, 'services/mumble/mumble_connection_history.html', context) + + +@login_required +@permission_required("mumble.view_connection_history") +def connection_history_data(request) -> JsonResponse: + connection_history_data = MumbleUser.objects.all( + ).values( + 'user', + 'display_name', + 'release', + 'version', + 'last_connect', + 'last_disconnect', + ) + + return JsonResponse({"connection_history_data": list(connection_history_data)}) + + +@login_required +@permission_required("mumble.view_connection_history") +def release_counts_data(request) -> JsonResponse: + release_counts_data = MumbleUser.objects.values('release').annotate(user_count=Count('user_id')).order_by('release') + + return JsonResponse({ + "release_counts_data": list(release_counts_data), + }) + + +@login_required +@permission_required("mumble.view_connection_history") +def release_pie_chart_data(request) -> JsonResponse: + release_counts = MumbleUser.objects.values('release').annotate(user_count=Count('user_id')).order_by('release') + + return JsonResponse({ + "labels": list(release_counts.values_list("release", flat=True)), + "values": list(release_counts.values_list("user_count", flat=True)), + })