Skip to content

Commit b189d0d

Browse files
committed
[monitoring/js] Consistent datetime format in RADIUS sessions tab #662
Use Django locale for date formatting in device page RADIUS sessions tab JS, matching Django admin and localization settings. Fixes #662
1 parent a741a47 commit b189d0d

File tree

8 files changed

+91
-23
lines changed

8 files changed

+91
-23
lines changed

openwisp_radius/api/urls.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ def get_api_urls(api_views=None):
8888
api_views.radius_accounting,
8989
name="radius_accounting_list",
9090
),
91+
path(
92+
"radius/monitoring/sessions/",
93+
api_views.monitoring_accounting,
94+
name="monitoring_accounting_list",
95+
),
9196
]
9297
else:
9398
return []

openwisp_radius/api/views.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
SmsAttemptCooldownException,
5454
UserAlreadyVerified,
5555
)
56+
from ..integrations.monitoring.views import MonitoringAccountingView
5657
from ..utils import generate_pdf, get_organization_radius_settings, load_model
5758
from . import freeradius_views
5859
from .freeradius_views import AccountingFilter, AccountingViewPagination
@@ -847,3 +848,5 @@ class RadiusAccountingView(ProtectedAPIMixin, FilterByOrganizationManaged, ListA
847848

848849

849850
radius_accounting = RadiusAccountingView.as_view()
851+
852+
monitoring_accounting = MonitoringAccountingView.as_view()

openwisp_radius/integrations/monitoring/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def get_extra_context(self, pk=None):
2525
ctx.update(
2626
{
2727
"radius_accounting_api_endpoint": reverse(
28-
"radius:radius_accounting_list"
28+
"radius:monitoring_accounting_list"
2929
),
3030
"radius_accounting": reverse(
3131
f"admin:{RadiusAccounting._meta.app_label}"
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from django.utils import formats, timezone
2+
from rest_framework import serializers
3+
from swapper import load_model
4+
5+
RadiusAccounting = load_model("openwisp_radius", "RadiusAccounting")
6+
7+
8+
class MonitoringRadiusAccountingSerializer(serializers.ModelSerializer):
9+
"""
10+
Read-only serializer for RADIUS accounting in monitoring integration
11+
that formats datetime fields server-side using Django's localization
12+
for consistency with Django admin datetime formatting.
13+
"""
14+
15+
start_time = serializers.SerializerMethodField()
16+
stop_time = serializers.SerializerMethodField()
17+
18+
def get_start_time(self, obj):
19+
"""Format start_time using Django's localization settings"""
20+
if not obj.start_time:
21+
return None
22+
local_time = timezone.localtime(obj.start_time)
23+
return formats.date_format(local_time, "DATETIME_FORMAT")
24+
25+
def get_stop_time(self, obj):
26+
"""Format stop_time using Django's localization settings"""
27+
if not obj.stop_time:
28+
return None
29+
local_time = timezone.localtime(obj.stop_time)
30+
return formats.date_format(local_time, "DATETIME_FORMAT")
31+
32+
class Meta:
33+
model = RadiusAccounting
34+
fields = [
35+
"session_id",
36+
"unique_id",
37+
"username",
38+
"input_octets",
39+
"output_octets",
40+
"calling_station_id",
41+
"called_station_id",
42+
"start_time",
43+
"stop_time",
44+
]
45+
read_only_fields = fields

openwisp_radius/integrations/monitoring/static/radius-monitoring/js/device-change.js

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,6 @@
1414
const deviceMac = encodeURIComponent($("#id_mac_address").val()),
1515
apiEndpoint = `${radiusAccountingApiEndpoint}?called_station_id=${deviceMac}`;
1616

17-
function getFormattedDateTimeString(dateTimeString) {
18-
// Strip the timezone from the dateTimeString.
19-
// This is done to show the time in server's timezone
20-
// because RadiusAccounting admin also shows the time in server's timezone.
21-
let strippedDateTime = new Date(dateTimeString.replace(/[-+]\d{2}:\d{2}$/, ""));
22-
const locale = djangoLocale.replace("_", "-");
23-
const options = {
24-
year: "numeric",
25-
month: "short",
26-
day: "numeric",
27-
hour: "2-digit",
28-
minute: "2-digit",
29-
second: "2-digit",
30-
hour12: false,
31-
};
32-
return strippedDateTime.toLocaleString(locale, options);
33-
}
34-
3517
function fetchRadiusSessions() {
3618
if ($("#radius-session-tbody").children().length) {
3719
// Don't fetch if RADIUS sessions are already present
@@ -68,11 +50,8 @@
6850
);
6951

7052
response.forEach((element, index) => {
71-
element.start_time = getFormattedDateTimeString(element.start_time);
7253
if (!element.stop_time) {
7354
element.stop_time = `<strong>${onlineMsg}</strong>`;
74-
} else {
75-
element.stop_time = getFormattedDateTimeString(element.stop_time);
7655
}
7756
$("#radius-session-tbody").append(
7857
`<tr class="form-row has_original dynamic-radiussession_set" id="radiussession_set-${index}">

openwisp_radius/integrations/monitoring/templates/admin/config/radius-monitoring/device/change_form.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ <h2>{% trans "RADIUS Sessions" %}</h2>
3636
<script>
3737
const radiusAccountingApiEndpoint = "{{ radius_accounting_api_endpoint }}";
3838
const radiusAccountingAdminPath = "{{ radius_accounting }}";
39-
const djangoLocale = "{{ LANGUAGE_CODE }}";
4039
</script>
4140
{% endif %}
4241
{% endblock %}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from django_filters.rest_framework import DjangoFilterBackend
2+
from rest_framework.generics import ListAPIView
3+
from swapper import load_model
4+
5+
from openwisp_radius.api.freeradius_views import (
6+
AccountingFilter,
7+
AccountingViewPagination,
8+
)
9+
from openwisp_users.api.mixins import FilterByOrganizationManaged, ProtectedAPIMixin
10+
11+
from .serializers import MonitoringRadiusAccountingSerializer
12+
13+
RadiusAccounting = load_model("openwisp_radius", "RadiusAccounting")
14+
15+
16+
class MonitoringAccountingView(
17+
ProtectedAPIMixin, FilterByOrganizationManaged, ListAPIView
18+
):
19+
"""
20+
API view for RADIUS accounting in monitoring integration.
21+
Uses server-side datetime formatting for consistency with Django admin.
22+
"""
23+
24+
throttle_scope = "radius_accounting_list"
25+
serializer_class = MonitoringRadiusAccountingSerializer
26+
pagination_class = AccountingViewPagination
27+
filter_backends = (DjangoFilterBackend,)
28+
filterset_class = AccountingFilter
29+
queryset = RadiusAccounting.objects.all().order_by("-start_time")

tests/openwisp2/sample_radius/api/views.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
from openwisp_radius.api.views import (
2525
ValidatePhoneTokenView as BaseValidatePhoneTokenView,
2626
)
27+
from openwisp_radius.integrations.monitoring.views import (
28+
MonitoringAccountingView as BaseMonitoringAccountingView,
29+
)
2730

2831

2932
class AuthorizeView(BaseAuthorizeView):
@@ -98,6 +101,10 @@ class RadiusAccountingView(BaseRadiusAccountingView):
98101
pass
99102

100103

104+
class MonitoringAccountingView(BaseMonitoringAccountingView):
105+
pass
106+
107+
101108
authorize = AuthorizeView.as_view()
102109
postauth = PostAuthView.as_view()
103110
accounting = AccountingView.as_view()
@@ -116,3 +123,4 @@ class RadiusAccountingView(BaseRadiusAccountingView):
116123
change_phone_number = ChangePhoneNumberView.as_view()
117124
download_rad_batch_pdf = DownloadRadiusBatchPdfView.as_view()
118125
radius_accounting = RadiusAccountingView.as_view()
126+
monitoring_accounting = MonitoringAccountingView.as_view()

0 commit comments

Comments
 (0)