Skip to content

Commit a0d7e52

Browse files
committed
Merge remote-tracking branch 'upstream/master' into issues/600-replace-jsonfield-clean
2 parents fe56cd9 + 82b99f8 commit a0d7e52

44 files changed

Lines changed: 1599 additions & 392 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/FUNDING.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# These are supported funding model platforms
22

3-
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
3+
github: [openwisp]
44
patreon: # Replace with a single Patreon username
55
open_collective: # Replace with a single Open Collective username
66
ko_fi: # Replace with a single Ko-fi username

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
django-version: django~=4.2.0
3939

4040
steps:
41-
- uses: actions/checkout@v4
41+
- uses: actions/checkout@v5
4242
with:
4343
ref: ${{ github.event.pull_request.head.sha }}
4444

@@ -56,7 +56,7 @@ jobs:
5656
sudo dpkg-reconfigure man-db
5757
5858
- name: Set up Python ${{ matrix.python-version }}
59-
uses: actions/setup-python@v5
59+
uses: actions/setup-python@v6
6060
with:
6161
python-version: ${{ matrix.python-version }}
6262
cache: "pip"

.github/workflows/pypi.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ jobs:
1717
permissions:
1818
id-token: write
1919
steps:
20-
- uses: actions/checkout@v4
20+
- uses: actions/checkout@v5
2121
- name: Set up Python
22-
uses: actions/setup-python@v5
22+
uses: actions/setup-python@v6
2323
with:
2424
python-version: "3.10"
2525
- name: Install dependencies
@@ -29,4 +29,4 @@ jobs:
2929
- name: Build package
3030
run: python -m build
3131
- name: Publish package distributions to PyPI
32-
uses: pypa/gh-action-pypi-publish@v1.12.4
32+
uses: pypa/gh-action-pypi-publish@v1.13.0

docs/deploy/freeradius.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ for the available configuration values.
140140
uri = "${..connect_uri}/api/v1/freeradius/authorize/"
141141
method = 'post'
142142
body = 'json'
143-
data = '{"username": "%{User-Name}", "password": "%{User-Password}"}'
143+
data = '{"username": "%{User-Name}", "password": "%{User-Password}", "called_station_id": "%{Called-Station-ID}", "calling_station_id": "%{Calling-Station-ID}"}'
144144
tls = ${..tls}
145145
}
146146

docs/developer/installation.rst

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,19 @@ Install the system dependencies:
2020
.. code-block:: shell
2121
2222
sudo apt update
23-
sudo apt install -y sqlite3 libsqlite3-dev libpq-dev
24-
sudo apt install -y xmlsec1
23+
sudo apt install xmlsec1 gettext \
24+
sqlite3 \
25+
# the dependencies below are needed
26+
# to test the integration with
27+
# OpenWISP Monitoring
28+
fping \
29+
gdal-bin \
30+
libproj-dev \
31+
libgeos-dev \
32+
libspatialite-dev \
33+
spatialite-bin \
34+
libsqlite3-mod-spatialite
35+
# for selenium tests
2536
sudo apt install -y chromium-browser
2637
2738
Fork and clone the forked repository:
@@ -36,11 +47,12 @@ Navigate into the cloned repository:
3647
3748
cd openwisp-radius/
3849
39-
Launch Redis:
50+
Launch Redis (and InfluxDB for the :doc:`integration with OpenWISP
51+
Monitoring </radius/user/radius_monitoring>`):
4052

4153
.. code-block:: shell
4254
43-
docker compose up -d redis
55+
docker compose up -d redis influxdb
4456
4557
Setup and activate a virtual-environment (we'll be using `virtualenv
4658
<https://pypi.org/project/virtualenv/>`_):
@@ -95,7 +107,7 @@ Run tests with:
95107

96108
.. code-block:: shell
97109
98-
./runtests.py --parallel
110+
./runtests
99111
100112
Run quality assurance tests with:
101113

@@ -136,7 +148,7 @@ Migrating an existing freeradius database
136148
-----------------------------------------
137149

138150
If you already have a freeradius 3 database with the default schema, you
139-
should be able to use it with openwisp-radius (and extended apps) easily:
151+
should be able to use it with OpenWISP RADIUS (and extended apps) easily:
140152

141153
1. first of all, back up your existing database;
142154
2. configure django to connect to your existing database;

docs/user/settings.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ The default encryption format for storing radius check values.
111111
A list of disabled encryption formats, by default all formats are enabled
112112
in order to keep backward compatibility with legacy systems.
113113

114+
``OPENWISP_RADIUS_BATCH_ASYNC_THRESHOLD``
115+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116+
117+
**Default**: ``15``
118+
119+
When the number of users to be generated in batch user creation is greater
120+
than or equal to this value, the operation will be executed as a
121+
background task (asynchronously) using Celery. This prevents timeouts and
122+
keeps the user interface responsive when creating a large number of users.
123+
For batches smaller than the threshold, users will be created immediately
124+
(synchronously).
125+
114126
``OPENWISP_RADIUS_BATCH_DEFAULT_PASSWORD_LENGTH``
115127
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116128

docs/user/simultaneous_use.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Limiting concurrent sessions (``Simultaneous-Use``)
2-
===================================================
1+
Limiting concurrent sessions
2+
============================
33

44
``Simultaneous-Use`` is a FreeRADIUS feature that restricts how many
55
sessions a user can keep active at the same time. When the maximum limit

openwisp_radius/admin.py

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from django.contrib.admin.utils import model_ngettext
88
from django.contrib.auth import get_user_model
99
from django.core.exceptions import PermissionDenied
10+
from django.http import HttpResponseRedirect
1011
from django.templatetags.static import static
1112
from django.urls import reverse
1213
from django.utils.safestring import mark_safe
@@ -338,13 +339,15 @@ class RadiusBatchAdmin(MultitenantAdminMixin, TimeStampedEditableAdmin):
338339
"name",
339340
"organization",
340341
"strategy",
342+
"status",
341343
"expiration_date",
342344
"created",
343345
"modified",
344346
]
345347
fields = [
346348
"strategy",
347349
"organization",
350+
"status",
348351
"name",
349352
"csvfile",
350353
"prefix",
@@ -393,25 +396,21 @@ def number_of_users(self, obj):
393396
number_of_users.short_description = _("number of users")
394397

395398
def get_fields(self, request, obj=None):
396-
fields = super().get_fields(request, obj)[:]
399+
fields = super().get_fields(request, obj)
397400
if not obj:
401+
fields = fields[:]
398402
fields.remove("users")
403+
fields.remove("status")
399404
return fields
400405

401406
def save_model(self, request, obj, form, change):
402-
data = form.cleaned_data
403-
strategy = data.get("strategy")
404-
if not change:
405-
if strategy == "csv":
406-
if data.get("csvfile", False):
407-
csvfile = data.get("csvfile")
408-
obj.csvfile_upload(csvfile)
409-
elif strategy == "prefix":
410-
prefix = data.get("prefix")
411-
n = data.get("number_of_users")
412-
obj.prefix_add(prefix, n)
413-
else:
414-
obj.save()
407+
if change:
408+
super().save_model(request, obj, form, change)
409+
return
410+
# Save the object initially to get a PK
411+
super().save_model(request, obj, form, change)
412+
num_users = form.cleaned_data.get("number_of_users", 0)
413+
obj.schedule_processing(number_of_users=num_users)
415414

416415
def delete_model(self, request, obj):
417416
obj.users.all().delete()
@@ -466,16 +465,46 @@ def get_readonly_fields(self, request, obj=None):
466465
readonly_fields = super(RadiusBatchAdmin, self).get_readonly_fields(
467466
request, obj
468467
)
469-
if obj:
468+
if obj and obj.status != "pending":
470469
return (
471470
"strategy",
472471
"prefix",
473472
"csvfile",
474473
"number_of_users",
475474
"users",
476475
"expiration_date",
476+
"name",
477+
"organization",
478+
"status",
477479
) + readonly_fields
478-
return readonly_fields
480+
elif obj:
481+
return ("status",) + readonly_fields
482+
return ("status",) + readonly_fields
483+
484+
def has_delete_permission(self, request, obj=None):
485+
if obj and obj.status == "processing":
486+
return False
487+
return super().has_delete_permission(request, obj)
488+
489+
def response_add(self, request, obj, post_url_continue=None):
490+
if obj.status != "pending":
491+
return super().response_add(request, obj, post_url_continue)
492+
opts = self.model._meta
493+
msg = _(
494+
'The batch user creation "{obj}" was added successfully '
495+
"and is now being processed in the background."
496+
).format(obj=obj)
497+
if "_continue" in request.POST:
498+
self.message_user(request, msg, messages.SUCCESS)
499+
post_url_continue = reverse(
500+
f"admin:{opts.app_label}_{opts.model_name}_change",
501+
args=(obj.pk,),
502+
current_app=self.admin_site.name,
503+
)
504+
return HttpResponseRedirect(post_url_continue)
505+
else:
506+
self.message_user(request, msg, messages.SUCCESS)
507+
return self.response_post_save_add(request, obj)
479508

480509

481510
# Inlines for UserAdmin & OrganizationAdmin

0 commit comments

Comments
 (0)