openwisp-controller 1.2.3__tar.gz → 1.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/CHANGES.rst +163 -0
- {openwisp_controller-1.2.3/openwisp_controller.egg-info → openwisp_controller-1.3.1}/PKG-INFO +15 -14
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/__init__.py +1 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/admin.py +145 -31
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/api/serializers.py +30 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/api/views.py +17 -19
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/apps.py +128 -78
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/base.py +3 -4
- openwisp_controller-1.3.1/openwisp_controller/config/base/cache.py +402 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/channels_consumer.py +1 -7
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/config.py +153 -52
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/device.py +74 -6
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/device_group.py +5 -21
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/multitenancy.py +21 -16
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/template.py +4 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/vpn.py +113 -9
- openwisp_controller-1.3.1/openwisp_controller/config/base/whois.py +210 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/controller/views.py +53 -14
- openwisp_controller-1.3.1/openwisp_controller/config/converters.py +27 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/handlers.py +64 -15
- openwisp_controller-1.3.1/openwisp_controller/config/management/commands/clear_last_ip.py +26 -0
- openwisp_controller-1.3.1/openwisp_controller/config/management/commands/print_cache_dependencies.py +22 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0001_squashed_0002_config_settings_uuid.py +3 -11
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0018_config_context.py +2 -6
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0023_update_context.py +2 -6
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0028_template_default_values.py +2 -6
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0036_device_group.py +1 -5
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0042_multiple_wireguard_tunnels.py +9 -4
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0048_wifi_radio_band_migration.py +13 -6
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0049_devicegroup_context.py +2 -6
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0051_organizationconfigsettings_context.py +2 -6
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0057_populate_vpnclient_template.py +8 -2
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0059_zerotier_templates_ow_zt_to_global.py +10 -5
- openwisp_controller-1.3.1/openwisp_controller/config/migrations/0061_config_checksum_db.py +330 -0
- openwisp_controller-1.3.1/openwisp_controller/config/migrations/0062_whoisinfo.py +89 -0
- openwisp_controller-1.3.1/openwisp_controller/config/migrations/0063_replace_jsonfield_with_django_builtin.py +122 -0
- openwisp_controller-1.3.1/openwisp_controller/config/migrations/0064_template_notes.py +18 -0
- openwisp_controller-1.3.1/openwisp_controller/config/migrations/0065_whoisinfo_unreferenced_since.py +19 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/__init__.py +13 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/models.py +11 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/settings.py +20 -5
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/signals.py +8 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/css/admin.css +48 -31
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/css/lib/advanced-mode.css +70 -62
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/css/lib/jsonschema-ui.css +18 -18
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/lib/advanced-mode.js +1 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/management_ip.js +9 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/relevant_templates.js +19 -4
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/tabs.js +5 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/widget.js +3 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/import_export/import-openwisp.css +7 -7
- openwisp_controller-1.3.1/openwisp_controller/config/static/whois/css/whois.css +110 -0
- openwisp_controller-1.3.1/openwisp_controller/config/static/whois/images/whois_globe.svg +3 -0
- openwisp_controller-1.3.1/openwisp_controller/config/static/whois/js/whois.js +62 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tasks.py +32 -22
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tasks_zerotier.py +10 -58
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/change_form.html +8 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/device/change_form.html +1 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/pytest.py +3 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_admin.py +297 -94
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_api.py +112 -22
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_config.py +619 -2
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_controller.py +500 -316
- openwisp_controller-1.3.1/openwisp_controller/config/tests/test_converters.py +23 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_device.py +104 -67
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_handlers.py +1 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_notifications.py +3 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_selenium.py +113 -40
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_views.py +1 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_vpn.py +206 -29
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/utils.py +43 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/utils.py +84 -21
- openwisp_controller-1.3.1/openwisp_controller/config/whois/commands.py +68 -0
- openwisp_controller-1.3.1/openwisp_controller/config/whois/handlers.py +45 -0
- openwisp_controller-1.3.1/openwisp_controller/config/whois/mixins.py +20 -0
- openwisp_controller-1.3.1/openwisp_controller/config/whois/serializers.py +17 -0
- openwisp_controller-1.3.1/openwisp_controller/config/whois/service.py +290 -0
- openwisp_controller-1.3.1/openwisp_controller/config/whois/tasks.py +138 -0
- openwisp_controller-1.3.1/openwisp_controller/config/whois/tests/tests.py +1353 -0
- openwisp_controller-1.3.1/openwisp_controller/config/whois/tests/utils.py +164 -0
- openwisp_controller-1.3.1/openwisp_controller/config/whois/utils.py +74 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/admin.py +26 -2
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/api/urls.py +1 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/api/views.py +15 -13
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/apps.py +6 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/base/models.py +85 -35
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/channels/routing.py +3 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/commands.py +1 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/connectors/openwrt/ssh.py +1 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/connectors/ssh.py +3 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0001_initial.py +6 -10
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0007_command.py +1 -5
- openwisp_controller-1.3.1/openwisp_controller/connection/migrations/0010_replace_jsonfield_with_django_builtin.py +47 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/static/connection/css/command-inline.css +24 -10
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/static/connection/js/commands.js +27 -16
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tasks.py +6 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/pytest.py +5 -4
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test_admin.py +37 -17
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test_api.py +4 -4
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test_models.py +98 -7
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test_notifications.py +6 -4
- openwisp_controller-1.3.1/openwisp_controller/connection/tests/test_selenium.py +126 -0
- openwisp_controller-1.3.1/openwisp_controller/connection/tests/test_tasks.py +317 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/utils.py +1 -1
- openwisp_controller-1.3.1/openwisp_controller/geo/admin.py +249 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/api/filters.py +58 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/api/serializers.py +159 -44
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/api/views.py +142 -17
- openwisp_controller-1.3.1/openwisp_controller/geo/apps.py +177 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/base/models.py +219 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/channels/consumers.py +42 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/channels/routing.py +11 -3
- openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location/handlers.py +83 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location/mixins.py +37 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location/service.py +253 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location/tasks.py +47 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location/tests/tests.py +1415 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location/tests/utils.py +43 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location/utils.py +143 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/migrations/0001_initial.py +4 -1
- openwisp_controller-1.3.1/openwisp_controller/geo/migrations/0004_location_is_estimated.py +22 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/migrations/0005_organizationgeosettings.py +55 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/migrations/0006_create_geo_settings_for_existing_orgs.py +40 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/migrations/__init__.py +15 -2
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/models.py +12 -1
- openwisp_controller-1.3.1/openwisp_controller/geo/settings.py +13 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/tasks.py +3 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/templates/admin/geo/device_location_inline.html +11 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/templates/admin/geo/location/change_form.html +11 -0
- openwisp_controller-1.3.1/openwisp_controller/geo/tests/pytest.py +201 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/tests/test_admin.py +68 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/tests/test_admin_inline.py +11 -15
- openwisp_controller-1.3.1/openwisp_controller/geo/tests/test_api.py +2067 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/tests/test_selenium.py +42 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/tests/utils.py +6 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/utils.py +10 -0
- openwisp_controller-1.3.1/openwisp_controller/pki/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/api/views.py +5 -9
- openwisp_controller-1.3.1/openwisp_controller/pki/base/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0001_initial.py +2 -8
- openwisp_controller-1.3.1/openwisp_controller/pki/migrations/0012_alter_ca_extensions_alter_ca_key_length_and_more.py +70 -0
- openwisp_controller-1.3.1/openwisp_controller/pki/tests/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/tests/test_api.py +64 -51
- openwisp_controller-1.3.1/openwisp_controller/settings.py +8 -0
- openwisp_controller-1.3.1/openwisp_controller/subnet_division/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/admin.py +12 -8
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/base/models.py +1 -1
- openwisp_controller-1.3.1/openwisp_controller/subnet_division/rule_types/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/rule_types/base.py +36 -16
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/rule_types/vpn.py +5 -2
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/static/subnet-division/css/subnet-division.css +3 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/tasks.py +9 -0
- openwisp_controller-1.3.1/openwisp_controller/subnet_division/tests/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/tests/test_admin.py +11 -1
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/tests/test_models.py +103 -12
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/tests/mixins.py +5 -0
- openwisp_controller-1.3.1/openwisp_controller/tests/test_migrationgraph.py +32 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/tests/test_selenium.py +5 -3
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1/openwisp_controller.egg-info}/PKG-INFO +15 -14
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller.egg-info/SOURCES.txt +45 -0
- openwisp_controller-1.3.1/openwisp_controller.egg-info/requires.txt +19 -0
- openwisp_controller-1.3.1/requirements.txt +19 -0
- openwisp_controller-1.2.3/openwisp_controller/config/migrations/0061_config_checksum_db.py +0 -57
- openwisp_controller-1.2.3/openwisp_controller/connection/tests/test_selenium.py +0 -69
- openwisp_controller-1.2.3/openwisp_controller/connection/tests/test_tasks.py +0 -137
- openwisp_controller-1.2.3/openwisp_controller/geo/admin.py +0 -142
- openwisp_controller-1.2.3/openwisp_controller/geo/api/filters.py +0 -27
- openwisp_controller-1.2.3/openwisp_controller/geo/apps.py +0 -119
- openwisp_controller-1.2.3/openwisp_controller/geo/base/models.py +0 -65
- openwisp_controller-1.2.3/openwisp_controller/geo/channels/consumers.py +0 -19
- openwisp_controller-1.2.3/openwisp_controller/geo/tests/pytest.py +0 -110
- openwisp_controller-1.2.3/openwisp_controller/geo/tests/test_api.py +0 -1056
- openwisp_controller-1.2.3/openwisp_controller/settings.py +0 -3
- openwisp_controller-1.2.3/openwisp_controller.egg-info/requires.txt +0 -18
- openwisp_controller-1.2.3/requirements.txt +0 -18
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/LICENSE +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/MANIFEST.in +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/README.rst +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/admin.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/base.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/checks.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/api/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/api/download_views.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/api/filters.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/api/urls.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/api/zerotier_service.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/base/tag.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/controller/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/controller/urls.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/crypto.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/exceptions.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/exportable.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/filters.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/fixtures/test_templates.json +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/config/sortedm2m → openwisp_controller-1.3.1/openwisp_controller/config/management}/__init__.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/connection → openwisp_controller-1.3.1/openwisp_controller/config/management/commands}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0003_template_tags.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0004_add_device_model.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0005_populate_device.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0006_config_device_not_null.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0007_simplify_config.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0008_update_indexes.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0009_device_system.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0010_auto_20180106_1814.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0011_update_device_mac_address.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0012_auto_20180219_1501.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0013_last_ip_management_ip_and_status_applied.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0014_device_hardware_id.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0015_default_groups_permissions.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0016_default_organization_config_settings.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0017_template_name_organization_unique_together.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0019_organization_mac_add_hardware_id_name_unique_together.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0020_remove_config_organization.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0021_vpn_key.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0022_vpn_format_dh.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0024_update_context_data.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0025_update_device_key.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0026_hardware_id_not_unique.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0027_add_indexes_on_ip_fields.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0029_merge_django_netjsonconfig.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0030_django_taggit_update.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0031_update_vpn_dh_param.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0032_update_legacy_vpn_backend.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0033_name_unique_per_organization.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0034_template_required.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0035_device_name_unique_optional.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0037_alter_taggedtemplate.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0038_vpn_subnet.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0039_wireguard_vxlan_ipam.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0040_vpnclient_ip_setnull.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0041_default_groups_organizationconfigsettings_permission.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0043_devicegroup_templates.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0044_config_error_reason.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0045_alter_vpn_webhook_endpoint.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0046_organizationlimits.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0047_add_organizationlimits.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0050_alter_vpnclient_unique_together.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0052_vpn_node_network_id.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0053_vpnclient_secret.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0054_device__is_deactivated.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0055_alter_config_status.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0056_vpnclient_template.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0058_alter_vpnclient_template.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/migrations/0060_cleanup_api_task_notification_types.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/connection/base → openwisp_controller-1.3.1/openwisp_controller/config/sortedm2m}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/sortedm2m/fields.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/sortedm2m/forms.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/css/device-delete-confirmation.css +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/css/devicegroup.css +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/css/lib/img/jsoneditor-icons.svg +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/device-delete-confirmation.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/lib/jsonschema-ui.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/lib/tomorrow_night_bright.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/preview.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/switcher.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/unsaved_changes.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/utils.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/config/js/vpn.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/sortedm2m/patch_sortedm2m.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/static/support.css +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/change_device_group.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/change_list_device.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/clone_template_form.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/device/delete_confirmation.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/device/delete_selected_confirmation.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/device_recover_form.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/jsonschema-widget.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/preview.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/config/system_context.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/device_group/change_form.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/admin/import_export/import.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/templates/reversion/config/revision_form.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_apps.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_device_group.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_tag.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/tests/test_template.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/urls.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/validators.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/views.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/connection/connectors → openwisp_controller-1.3.1/openwisp_controller/config/whois}/__init__.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/connection/connectors/openwrt → openwisp_controller-1.3.1/openwisp_controller/config/whois/tests}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/config/widgets.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/connection/tests → openwisp_controller-1.3.1/openwisp_controller/connection}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/api/serializers.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/geo → openwisp_controller-1.3.1/openwisp_controller/connection/base}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/channels/consumers.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/geo/api → openwisp_controller-1.3.1/openwisp_controller/connection/connectors}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/connectors/airos/snmp.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/connectors/exceptions.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/geo/base → openwisp_controller-1.3.1/openwisp_controller/connection/connectors/openwrt}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/connectors/openwrt/snmp.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/connectors/snmp.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/exceptions.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0002_credentials_auto_add.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0003_default_group_permissions.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0004_django3_1_upgrade.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0005_device_connection_failure_reason.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0006_name_unique_per_organization.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0008_remove_conflicting_deviceconnections.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/0009_alter_deviceconnection_unique_together.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/migrations/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/models.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/schema.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/settings.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/signals.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/static/connection/css/credentials.css +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/static/connection/js/credentials.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/static/connection/js/lib/reconnecting-websocket.min.js +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/geo/channels → openwisp_controller-1.3.1/openwisp_controller/connection/tests}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/base.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test-key.ed25519 +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test-key.rsa +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test_command_utilities.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test_snmp.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/tests/test_ssh.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/utils.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/connection/widgets.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/context_processors.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/geo/tests → openwisp_controller-1.3.1/openwisp_controller/geo}/__init__.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/pki → openwisp_controller-1.3.1/openwisp_controller/geo/api}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/api/urls.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/pki → openwisp_controller-1.3.1/openwisp_controller/geo}/base/__init__.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/pki/tests → openwisp_controller-1.3.1/openwisp_controller/geo/channels}/__init__.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/subnet_division → openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location}/__init__.py +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/subnet_division/rule_types → openwisp_controller-1.3.1/openwisp_controller/geo/estimated_location/tests}/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/exportable.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/migrations/0002_default_groups_permissions.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/migrations/0003_alter_devicelocation_floorplan_location.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/templates/admin/widgets/foreign_key_raw_id.html +0 -0
- {openwisp_controller-1.2.3/openwisp_controller/subnet_division → openwisp_controller-1.3.1/openwisp_controller/geo}/tests/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/tests/test_apps.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/geo/tests/test_models.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/migrations.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/mixins.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/admin.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/api/serializers.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/api/urls.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/apps.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/base/models.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0002_add_organization_name.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0003_fill_organization_name.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0004_auto_20180106_1814.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0005_organizational_unit_name.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0006_add_x509_passphrase_field.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0007_default_groups_permissions.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0008_serial_number_length.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0009_common_name_maxlength_64.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0010_common_name_organization_unique.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/0011_disallowed_blank_key_length_or_digest.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/migrations/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/models.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/static/admin/pki/js/show-org-field.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/templates/admin/pki/change_form.html +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/tests/test_admin.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/tests/test_models.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/tests/utils.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/urls.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/pki/utils.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/routing.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/serializers.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/apps.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/filters.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/migrations/0001_initial.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/migrations/0002_default_group_migration.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/migrations/0003_related_field_allow_blank.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/migrations/0004_index_rule_on_delete.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/migrations/0005_number_of_subnets_and_ips.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/migrations/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/models.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/rule_types/device.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/settings.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/signals.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/static/subnet-division/js/subnet-division.js +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/tests/helpers.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/tests/test_rule.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/subnet_division/utils.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/tests/__init__.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/tests/test_users_integration.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/tests/test_utilities.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/tests/utils.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/urls.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller/vpn_backends.py +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller.egg-info/dependency_links.txt +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller.egg-info/not-zip-safe +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/openwisp_controller.egg-info/top_level.txt +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/pyproject.toml +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/setup.cfg +0 -0
- {openwisp_controller-1.2.3 → openwisp_controller-1.3.1}/setup.py +0 -0
|
@@ -1,6 +1,169 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
Version 1.3.1 [2026-10-15]
|
|
5
|
+
--------------------------
|
|
6
|
+
|
|
7
|
+
Security
|
|
8
|
+
~~~~~~~~
|
|
9
|
+
|
|
10
|
+
- Fixed insecure multi-tenancy boundary in location REST API
|
|
11
|
+
|
|
12
|
+
Fixed a **security issue** that allowed organization managers to link
|
|
13
|
+
locations and floorplans belonging to other organizations to their
|
|
14
|
+
devices by submitting known object IDs.
|
|
15
|
+
|
|
16
|
+
The API now resolves related objects only from organizations managed by
|
|
17
|
+
the requesting user and validates the organization of all
|
|
18
|
+
device-location relationships. Device lists for a location are scoped to
|
|
19
|
+
managed organizations and no longer expose device keys.
|
|
20
|
+
|
|
21
|
+
Nested location and floorplan writes are validated before being saved
|
|
22
|
+
and run in a database transaction, preventing rejected requests from
|
|
23
|
+
leaving related database objects or files behind.
|
|
24
|
+
|
|
25
|
+
Advisory: **GHSA-39c4-xj33-j8j3**.
|
|
26
|
+
|
|
27
|
+
- Fixed XSS vulnerabilities in device and command admin UI
|
|
28
|
+
|
|
29
|
+
Fixed cross-site scripting (XSS) vulnerabilities caused by improper
|
|
30
|
+
escaping of user-controlled data in the following admin pages:
|
|
31
|
+
|
|
32
|
+
- Device and device group forms (template names).
|
|
33
|
+
- Device pages (command inputs, outputs, and management IP).
|
|
34
|
+
- Subnet administration (device names and links).
|
|
35
|
+
|
|
36
|
+
These vulnerabilities could allow attackers to execute malicious
|
|
37
|
+
JavaScript in an administrator's browser.
|
|
38
|
+
|
|
39
|
+
Advisory: **GHSA-4f2x-pxjx-h8m3**.
|
|
40
|
+
|
|
41
|
+
Bugfixes
|
|
42
|
+
~~~~~~~~
|
|
43
|
+
|
|
44
|
+
- Fixed loss of data in PATCH requests to device location endpoint `#1510
|
|
45
|
+
<https://github.com/openwisp/openwisp-controller/issues/1510>`_
|
|
46
|
+
|
|
47
|
+
Sending `PATCH` requests to the device location endpoint
|
|
48
|
+
(`/api/v1/controller/device/{id}/location/`) now doesn't set `location`
|
|
49
|
+
and `floorplan` to `NULL` when they are not included in the request
|
|
50
|
+
body.
|
|
51
|
+
|
|
52
|
+
Changes
|
|
53
|
+
~~~~~~~
|
|
54
|
+
|
|
55
|
+
- Added IP address search to DeviceAdmin
|
|
56
|
+
|
|
57
|
+
Enabled searches by last and management IP addresses.
|
|
58
|
+
|
|
59
|
+
Version 1.3.0 [2026-09-03]
|
|
60
|
+
--------------------------
|
|
61
|
+
|
|
62
|
+
Features
|
|
63
|
+
~~~~~~~~
|
|
64
|
+
|
|
65
|
+
- Added `WHOIS lookup and geographic location estimation
|
|
66
|
+
<https://github.com/openwisp/openwisp-controller/issues/1034>`_ for
|
|
67
|
+
devices, including WHOIS details in the admin UI, automatic refresh of
|
|
68
|
+
stale WHOIS data, estimated-location notifications and warnings, and
|
|
69
|
+
admin and API filters for estimated locations.
|
|
70
|
+
- Added `WebSocket support for broadcasting all location updates
|
|
71
|
+
<https://github.com/openwisp/openwisp-controller/issues/1157>`_.
|
|
72
|
+
- Added an `API endpoint for retrieving indoor device coordinates
|
|
73
|
+
<https://github.com/openwisp/openwisp-controller/issues/828>`_ for a
|
|
74
|
+
location.
|
|
75
|
+
- Added `location and floorplan filters to the device list API
|
|
76
|
+
<https://github.com/openwisp/openwisp-controller/issues/1158>`_,
|
|
77
|
+
allowing searches by location name and filtering by location or
|
|
78
|
+
floorplan UUID.
|
|
79
|
+
- Added `generic cache invalidation for configuration models
|
|
80
|
+
<https://github.com/openwisp/openwisp-controller/issues/1095>`_. Models
|
|
81
|
+
can declare cache dependencies using ``CacheDependency``, and the new
|
|
82
|
+
``print_cache_dependencies`` management command can be used to inspect
|
|
83
|
+
the dependency graph.
|
|
84
|
+
- Added `notes to configuration templates
|
|
85
|
+
<https://github.com/openwisp/openwisp-controller/issues/1412>`_.
|
|
86
|
+
- Allowed devices to update their name during re-registration.
|
|
87
|
+
|
|
88
|
+
Changes
|
|
89
|
+
~~~~~~~
|
|
90
|
+
|
|
91
|
+
Other changes
|
|
92
|
+
+++++++++++++
|
|
93
|
+
|
|
94
|
+
- Enforced the `deactivated device state across OpenWISP Controller
|
|
95
|
+
<https://github.com/openwisp/openwisp-controller/issues/1338>`_.
|
|
96
|
+
Deactivated devices can no longer register, receive configuration
|
|
97
|
+
updates, run remote commands, or receive automatically assigned
|
|
98
|
+
templates. Cleanup and security operations continue to work normally.
|
|
99
|
+
- Added `VPN subnet and IP address details to the REST API
|
|
100
|
+
<https://github.com/openwisp/openwisp-controller/issues/1003>`_.
|
|
101
|
+
- Allowed deleting organizations containing active devices while
|
|
102
|
+
displaying a warning about the active devices that will be affected.
|
|
103
|
+
- Replaced the third-party ``jsonfield`` implementation with Django's
|
|
104
|
+
built-in ``JSONField`` `#1061
|
|
105
|
+
<https://github.com/openwisp/openwisp-controller/issues/1061>`_,
|
|
106
|
+
including migration handling for databases upgraded from older OpenWISP
|
|
107
|
+
Controller versions.
|
|
108
|
+
- Changed VPN synchronization errors and recovery events to use
|
|
109
|
+
``generic_message`` notifications `#1049
|
|
110
|
+
<https://github.com/openwisp/openwisp-controller/issues/1049>`_.
|
|
111
|
+
- Improved command status visibility in the admin interface by
|
|
112
|
+
highlighting statuses with different colors `#812
|
|
113
|
+
<https://github.com/openwisp/openwisp-controller/issues/812>`_.
|
|
114
|
+
|
|
115
|
+
Dependencies
|
|
116
|
+
++++++++++++
|
|
117
|
+
|
|
118
|
+
- Bumped ``django-reversion`` from ``~=6.0.0`` to `~=6.3.0
|
|
119
|
+
<https://github.com/etianen/django-reversion/blob/v6.3.0/CHANGELOG.rst>`_.
|
|
120
|
+
- Bumped ``netjsonconfig`` from ``~=1.2.0`` to `~=1.3.0
|
|
121
|
+
<https://github.com/openwisp/netjsonconfig/blob/master/CHANGES.rst>`__.
|
|
122
|
+
- Bumped ``django-x509`` from ``~=1.3.0`` to `~=1.4.0
|
|
123
|
+
<https://github.com/openwisp/django-x509/blob/master/CHANGES.rst>`_.
|
|
124
|
+
- Bumped ``django-loci`` from ``~=1.2.0`` to `~=1.3.0
|
|
125
|
+
<https://github.com/openwisp/django-loci/blob/master/CHANGES.rst>`__.
|
|
126
|
+
- Bumped ``django-flat-json-widget`` from ``~=0.4.0`` to `~=0.5.0
|
|
127
|
+
<https://github.com/openwisp/django-flat-json-widget/blob/master/CHANGES.rst>`_.
|
|
128
|
+
- Bumped ``openwisp-users`` from ``~=1.2.0`` to `~=1.3.0
|
|
129
|
+
<https://github.com/openwisp/openwisp-users/blob/master/CHANGES.rst>`__.
|
|
130
|
+
- Bumped ``openwisp-utils[celery,channels]`` from ``~=1.2.0`` to `~=1.3.0
|
|
131
|
+
<https://github.com/openwisp/openwisp-utils/blob/master/CHANGES.rst>`__.
|
|
132
|
+
- Bumped ``openwisp-notifications`` from ``~=1.2.0`` to `~=1.3.0
|
|
133
|
+
<https://github.com/openwisp/openwisp-notifications/blob/master/CHANGES.rst>`__.
|
|
134
|
+
- Bumped ``openwisp-ipam`` from ``~=1.2.0`` to `~=1.3.1
|
|
135
|
+
<https://github.com/openwisp/openwisp-ipam/blob/master/CHANGES.rst>`_.
|
|
136
|
+
- Bumped ``djangorestframework-gis`` from ``~=1.2.0`` to `~=1.3.0
|
|
137
|
+
<https://github.com/openwisp/django-rest-framework-gis/blob/master/CHANGES.rst>`__.
|
|
138
|
+
- Bumped ``paramiko`` from ``~=4.0.0`` to `~=5.0.0
|
|
139
|
+
<https://www.paramiko.org/changelog.html>`_.
|
|
140
|
+
- Bumped ``scp`` from ``~=0.15.0`` to `~=0.16.1
|
|
141
|
+
<https://github.com/jbardin/scp.py/releases/tag/v0.16.1>`_.
|
|
142
|
+
- Bumped ``django-import-export`` from ``~=4.3.10`` to `~=4.4.1
|
|
143
|
+
<https://django-import-export.readthedocs.io/en/latest/changelog.html>`_.
|
|
144
|
+
- Added `geoip2>=5.3.0,<6.0.0
|
|
145
|
+
<https://github.com/maxmind/GeoIP2-python/releases/tag/v5.3.0>`_.
|
|
146
|
+
- Dropped support for Django ``4.2``.
|
|
147
|
+
- Dropped support for Python ``3.9``.
|
|
148
|
+
|
|
149
|
+
Bugfixes
|
|
150
|
+
~~~~~~~~
|
|
151
|
+
|
|
152
|
+
- Fixed `subnet-division rules allocating addresses already in use
|
|
153
|
+
<https://github.com/openwisp/openwisp-controller/issues/1464>`_ by
|
|
154
|
+
respecting existing child prefixes and pre-allocated IP addresses.
|
|
155
|
+
- Fixed background command and connection operations potentially restoring
|
|
156
|
+
objects that had been deleted concurrently or causing foreign key
|
|
157
|
+
errors.
|
|
158
|
+
- Fixed VPN client synchronization when switching VPN templates,
|
|
159
|
+
preventing inconsistent client state during repeated template updates.
|
|
160
|
+
- Fixed SSH connections remaining open when ``update_config()`` failed.
|
|
161
|
+
- Fixed `malformed UUID URLs returning HTTP 500 instead of HTTP 404
|
|
162
|
+
<https://github.com/openwisp/openwisp-controller/issues/682>`_.
|
|
163
|
+
- Fixed the Device admin delete confirmation page when OpenWISP Controller
|
|
164
|
+
is extended by downstream applications.
|
|
165
|
+
- Fixed a typo in the ``update_strategy`` validation error message.
|
|
166
|
+
|
|
4
167
|
Version 1.2.3 [2026-04-09]
|
|
5
168
|
--------------------------
|
|
6
169
|
|
{openwisp_controller-1.2.3/openwisp_controller.egg-info → openwisp_controller-1.3.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openwisp-controller
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.1
|
|
4
4
|
Summary: OpenWISP Controller
|
|
5
5
|
Home-page: http://openwisp.org
|
|
6
6
|
Download-URL: https://github.com/openwisp/openwisp-controller/releases
|
|
@@ -20,23 +20,24 @@ Classifier: Framework :: Django
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: django-sortedm2m~=4.0.0
|
|
23
|
-
Requires-Dist: django-reversion~=6.
|
|
23
|
+
Requires-Dist: django-reversion~=6.3.0
|
|
24
24
|
Requires-Dist: django-taggit~=6.1.0
|
|
25
|
-
Requires-Dist: netjsonconfig~=1.
|
|
26
|
-
Requires-Dist: django-x509~=1.
|
|
27
|
-
Requires-Dist: django-loci~=1.
|
|
28
|
-
Requires-Dist: django-flat-json-widget~=0.
|
|
29
|
-
Requires-Dist: openwisp-users~=1.
|
|
30
|
-
Requires-Dist: openwisp-utils[celery,channels]~=1.
|
|
31
|
-
Requires-Dist: openwisp-notifications~=1.
|
|
32
|
-
Requires-Dist: openwisp-ipam~=1.
|
|
33
|
-
Requires-Dist: djangorestframework-gis~=1.
|
|
34
|
-
Requires-Dist: paramiko~=
|
|
35
|
-
Requires-Dist: scp~=0.
|
|
25
|
+
Requires-Dist: netjsonconfig~=1.3.0
|
|
26
|
+
Requires-Dist: django-x509~=1.4.0
|
|
27
|
+
Requires-Dist: django-loci~=1.3.0
|
|
28
|
+
Requires-Dist: django-flat-json-widget~=0.5.0
|
|
29
|
+
Requires-Dist: openwisp-users~=1.3.0
|
|
30
|
+
Requires-Dist: openwisp-utils[celery,channels]~=1.3.0
|
|
31
|
+
Requires-Dist: openwisp-notifications~=1.3.0
|
|
32
|
+
Requires-Dist: openwisp-ipam~=1.3.1
|
|
33
|
+
Requires-Dist: djangorestframework-gis~=1.3.0
|
|
34
|
+
Requires-Dist: paramiko~=5.0.0
|
|
35
|
+
Requires-Dist: scp~=0.16.1
|
|
36
36
|
Requires-Dist: django-cache-memoize~=0.2.1
|
|
37
37
|
Requires-Dist: shortuuid~=1.0.13
|
|
38
38
|
Requires-Dist: netaddr~=1.3.0
|
|
39
|
-
Requires-Dist: django-import-export~=4.
|
|
39
|
+
Requires-Dist: django-import-export~=4.4.1
|
|
40
|
+
Requires-Dist: geoip2<6.0.0,>=5.3.0
|
|
40
41
|
Dynamic: author
|
|
41
42
|
Dynamic: author-email
|
|
42
43
|
Dynamic: classifier
|
|
@@ -15,12 +15,14 @@ from django.core.exceptions import (
|
|
|
15
15
|
ObjectDoesNotExist,
|
|
16
16
|
ValidationError,
|
|
17
17
|
)
|
|
18
|
+
from django.db import models
|
|
19
|
+
from django.db.models.functions import Cast
|
|
18
20
|
from django.http import Http404, HttpResponse, HttpResponseRedirect, JsonResponse
|
|
19
21
|
from django.http.response import HttpResponseForbidden
|
|
20
22
|
from django.shortcuts import get_object_or_404
|
|
21
23
|
from django.template.loader import get_template
|
|
22
24
|
from django.template.response import TemplateResponse
|
|
23
|
-
from django.urls import
|
|
25
|
+
from django.urls import NoReverseMatch, path, reverse
|
|
24
26
|
from django.utils.html import format_html, mark_safe
|
|
25
27
|
from django.utils.translation import gettext_lazy as _
|
|
26
28
|
from django.utils.translation import ngettext_lazy
|
|
@@ -31,12 +33,14 @@ from openwisp_ipam.filters import SubnetFilter
|
|
|
31
33
|
from swapper import load_model
|
|
32
34
|
|
|
33
35
|
from openwisp_controller.config.views import get_default_values, get_relevant_templates
|
|
36
|
+
from openwisp_controller.config.whois.utils import get_whois_info
|
|
34
37
|
from openwisp_users.admin import OrganizationAdmin
|
|
35
38
|
from openwisp_users.multitenancy import MultitenantOrgFilter
|
|
36
39
|
from openwisp_utils.admin import (
|
|
37
40
|
AlwaysHasChangedMixin,
|
|
41
|
+
BlockDeleteAllowCascadeMixin,
|
|
42
|
+
CopyableFieldsAdmin,
|
|
38
43
|
TimeReadonlyAdminMixin,
|
|
39
|
-
UUIDAdmin,
|
|
40
44
|
)
|
|
41
45
|
|
|
42
46
|
from ..admin import MultitenantAdminMixin
|
|
@@ -49,6 +53,7 @@ from .widgets import DeviceGroupJsonSchemaWidget, JsonSchemaWidget
|
|
|
49
53
|
|
|
50
54
|
logger = logging.getLogger(__name__)
|
|
51
55
|
prefix = "config/"
|
|
56
|
+
whois_prefix = "whois/"
|
|
52
57
|
Config = load_model("config", "Config")
|
|
53
58
|
Device = load_model("config", "Device")
|
|
54
59
|
DeviceGroup = load_model("config", "DeviceGroup")
|
|
@@ -111,7 +116,7 @@ class BaseConfigAdmin(BaseAdmin):
|
|
|
111
116
|
|
|
112
117
|
class Media:
|
|
113
118
|
css = {"all": (f"{prefix}css/admin.css",)}
|
|
114
|
-
js = list(
|
|
119
|
+
js = list(CopyableFieldsAdmin.Media.js) + [
|
|
115
120
|
f"{prefix}js/{file_}"
|
|
116
121
|
for file_ in ("preview.js", "unsaved_changes.js", "switcher.js")
|
|
117
122
|
]
|
|
@@ -137,16 +142,15 @@ class BaseConfigAdmin(BaseAdmin):
|
|
|
137
142
|
if not issubclass(self.model, AbstractVpn):
|
|
138
143
|
ctx["CONFIG_BACKEND_FIELD_SHOWN"] = app_settings.CONFIG_BACKEND_FIELD_SHOWN
|
|
139
144
|
if pk:
|
|
140
|
-
ctx["download_url"] = reverse("{0}_download".format(prefix), args=[pk])
|
|
141
145
|
try:
|
|
146
|
+
download_url = reverse("{0}_download".format(prefix), args=[pk])
|
|
142
147
|
has_config = True
|
|
143
148
|
if self.model.__name__ == "Device":
|
|
144
149
|
has_config = self.model.objects.get(pk=pk)._has_config()
|
|
145
|
-
except (ObjectDoesNotExist, ValidationError):
|
|
150
|
+
except (ObjectDoesNotExist, ValidationError, NoReverseMatch):
|
|
146
151
|
raise Http404()
|
|
147
152
|
else:
|
|
148
|
-
if
|
|
149
|
-
ctx["download_url"] = None
|
|
153
|
+
ctx["download_url"] = download_url if has_config else None
|
|
150
154
|
return ctx
|
|
151
155
|
|
|
152
156
|
def add_view(self, request, form_url="", extra_context=None):
|
|
@@ -167,8 +171,8 @@ class BaseConfigAdmin(BaseAdmin):
|
|
|
167
171
|
options = getattr(self.model, "_meta")
|
|
168
172
|
url_prefix = "{0}_{1}".format(options.app_label, options.model_name)
|
|
169
173
|
return [
|
|
170
|
-
|
|
171
|
-
|
|
174
|
+
path(
|
|
175
|
+
"download/<uuid_any:pk>/",
|
|
172
176
|
self.admin_site.admin_view(self.download_view),
|
|
173
177
|
name="{0}_download".format(url_prefix),
|
|
174
178
|
),
|
|
@@ -177,8 +181,8 @@ class BaseConfigAdmin(BaseAdmin):
|
|
|
177
181
|
self.admin_site.admin_view(self.preview_view),
|
|
178
182
|
name="{0}_preview".format(url_prefix),
|
|
179
183
|
),
|
|
180
|
-
|
|
181
|
-
|
|
184
|
+
path(
|
|
185
|
+
"<uuid_any:pk>/context.json",
|
|
182
186
|
self.admin_site.admin_view(self.context_view),
|
|
183
187
|
name="{0}_context".format(url_prefix),
|
|
184
188
|
),
|
|
@@ -215,6 +219,15 @@ class BaseConfigAdmin(BaseAdmin):
|
|
|
215
219
|
key = "{relation}_id".format(relation=key)
|
|
216
220
|
# pass non-empty string or None
|
|
217
221
|
kwargs[key] = value or None
|
|
222
|
+
# parse JSON strings for JSONField fields
|
|
223
|
+
elif isinstance(field, models.JSONField) and isinstance(value, str):
|
|
224
|
+
if not value:
|
|
225
|
+
kwargs[key] = None
|
|
226
|
+
else:
|
|
227
|
+
try:
|
|
228
|
+
kwargs[key] = json.loads(value)
|
|
229
|
+
except json.JSONDecodeError:
|
|
230
|
+
kwargs[key] = value
|
|
218
231
|
# put regular field values in kwargs dict
|
|
219
232
|
else:
|
|
220
233
|
kwargs[key] = value
|
|
@@ -498,11 +511,12 @@ class ChangeDeviceGroupForm(forms.Form):
|
|
|
498
511
|
)
|
|
499
512
|
|
|
500
513
|
|
|
501
|
-
class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin,
|
|
514
|
+
class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, CopyableFieldsAdmin):
|
|
502
515
|
change_form_template = "admin/config/device/change_form.html"
|
|
503
516
|
delete_selected_confirmation_template = (
|
|
504
517
|
"admin/config/device/delete_selected_confirmation.html"
|
|
505
518
|
)
|
|
519
|
+
delete_confirmation_template = "admin/config/device/delete_confirmation.html"
|
|
506
520
|
list_display = [
|
|
507
521
|
"name",
|
|
508
522
|
"backend",
|
|
@@ -528,6 +542,8 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
528
542
|
"model",
|
|
529
543
|
"os",
|
|
530
544
|
"system",
|
|
545
|
+
"last_ip",
|
|
546
|
+
"management_ip",
|
|
531
547
|
"devicelocation__location__address",
|
|
532
548
|
]
|
|
533
549
|
readonly_fields = ["last_ip", "uuid"]
|
|
@@ -548,6 +564,7 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
548
564
|
"created",
|
|
549
565
|
"modified",
|
|
550
566
|
]
|
|
567
|
+
copyable_fields = ["uuid"]
|
|
551
568
|
inlines = [ConfigInline]
|
|
552
569
|
conditional_inlines = []
|
|
553
570
|
actions = [
|
|
@@ -569,12 +586,21 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
569
586
|
fields.insert(0, "hardware_id")
|
|
570
587
|
list_select_related = ("config", "organization")
|
|
571
588
|
|
|
572
|
-
|
|
589
|
+
# overriding media property to allow testing in isolation
|
|
590
|
+
# as class Media is evaluated at import time making the
|
|
591
|
+
# settings not overridable in tests
|
|
592
|
+
@property
|
|
593
|
+
def media(self):
|
|
573
594
|
js = BaseConfigAdmin.Media.js + [
|
|
574
595
|
f"{prefix}js/tabs.js",
|
|
575
596
|
f"{prefix}js/management_ip.js",
|
|
576
597
|
f"{prefix}js/relevant_templates.js",
|
|
577
598
|
]
|
|
599
|
+
css = BaseConfigAdmin.Media.css["all"]
|
|
600
|
+
if app_settings.WHOIS_CONFIGURED:
|
|
601
|
+
js.append(f"{whois_prefix}js/whois.js")
|
|
602
|
+
css += (f"{whois_prefix}css/whois.css",)
|
|
603
|
+
return super().media + forms.Media(js=js, css={"all": css})
|
|
578
604
|
|
|
579
605
|
def has_change_permission(self, request, obj=None):
|
|
580
606
|
perm = super().has_change_permission(request)
|
|
@@ -586,8 +612,70 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
586
612
|
perm = super().has_delete_permission(request)
|
|
587
613
|
if not obj:
|
|
588
614
|
return perm
|
|
615
|
+
if BlockDeleteAllowCascadeMixin.is_admin_cascade_delete_request(self, request):
|
|
616
|
+
self._add_active_device_delete_warning(request, obj)
|
|
617
|
+
return perm
|
|
589
618
|
return perm and obj.is_deactivated()
|
|
590
619
|
|
|
620
|
+
def _add_active_device_delete_warning(self, request, obj):
|
|
621
|
+
if getattr(request, "_active_device_delete_warning_checked", False):
|
|
622
|
+
return
|
|
623
|
+
resolver_match = getattr(request, "resolver_match", None)
|
|
624
|
+
url_name = getattr(resolver_match, "url_name", None)
|
|
625
|
+
opts = Organization._meta
|
|
626
|
+
organization_delete_url_name = f"{opts.app_label}_{opts.model_name}_delete"
|
|
627
|
+
organization_changelist_url_name = (
|
|
628
|
+
f"{opts.app_label}_{opts.model_name}_changelist"
|
|
629
|
+
)
|
|
630
|
+
active_organizations = 0
|
|
631
|
+
if request.method == "GET" and url_name == organization_delete_url_name:
|
|
632
|
+
request._active_device_delete_warning_checked = True
|
|
633
|
+
active_organizations = (
|
|
634
|
+
Device.objects.filter(
|
|
635
|
+
organization_id=obj.organization_id,
|
|
636
|
+
_is_deactivated=False,
|
|
637
|
+
)
|
|
638
|
+
.values("organization_id")
|
|
639
|
+
.distinct()
|
|
640
|
+
.count()
|
|
641
|
+
)
|
|
642
|
+
elif (
|
|
643
|
+
url_name == organization_changelist_url_name
|
|
644
|
+
and request.POST.get("action") == "delete_selected"
|
|
645
|
+
and not request.POST.get("post")
|
|
646
|
+
):
|
|
647
|
+
request._active_device_delete_warning_checked = True
|
|
648
|
+
organizations = self.admin_site.get_model_admin(Organization).get_queryset(
|
|
649
|
+
request
|
|
650
|
+
)
|
|
651
|
+
active_organizations = (
|
|
652
|
+
Device.objects.filter(
|
|
653
|
+
organization_id__in=organizations.filter(
|
|
654
|
+
pk__in=request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
|
|
655
|
+
),
|
|
656
|
+
_is_deactivated=False,
|
|
657
|
+
)
|
|
658
|
+
.values("organization_id")
|
|
659
|
+
.distinct()
|
|
660
|
+
.count()
|
|
661
|
+
)
|
|
662
|
+
if not active_organizations:
|
|
663
|
+
return
|
|
664
|
+
self.message_user(
|
|
665
|
+
request,
|
|
666
|
+
ngettext_lazy(
|
|
667
|
+
"This organization contains active devices. It is highly "
|
|
668
|
+
"recommended to deactivate them before deleting the organization "
|
|
669
|
+
"to ensure sensitive configuration data is disposed of safely.",
|
|
670
|
+
"%(count)d organizations contain active devices. It is highly "
|
|
671
|
+
"recommended to deactivate them before deleting the organizations "
|
|
672
|
+
"to ensure sensitive configuration data is disposed of safely.",
|
|
673
|
+
active_organizations,
|
|
674
|
+
)
|
|
675
|
+
% {"count": active_organizations},
|
|
676
|
+
messages.WARNING,
|
|
677
|
+
)
|
|
678
|
+
|
|
591
679
|
def save_form(self, request, form, change):
|
|
592
680
|
self._state_adding = form.instance._state.adding
|
|
593
681
|
return super().save_form(request, form, change)
|
|
@@ -656,6 +744,7 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
656
744
|
form = ChangeDeviceGroupForm(data=request.POST, org_id=org_id)
|
|
657
745
|
if form.is_valid():
|
|
658
746
|
group = form.cleaned_data["device_group"]
|
|
747
|
+
queryset = queryset.filter(_is_deactivated=False)
|
|
659
748
|
# Evaluate queryset to store old group id
|
|
660
749
|
old_group_qs = list(queryset)
|
|
661
750
|
queryset.update(group=group or None)
|
|
@@ -683,8 +772,7 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
683
772
|
"action_checkbox_name": helpers.ACTION_CHECKBOX_NAME,
|
|
684
773
|
"opts": self.model._meta,
|
|
685
774
|
"changelist_url": (
|
|
686
|
-
f"{request.resolver_match.app_name}:"
|
|
687
|
-
f"{request.resolver_match.url_name}"
|
|
775
|
+
f"{request.resolver_match.app_name}:{request.resolver_match.url_name}"
|
|
688
776
|
),
|
|
689
777
|
}
|
|
690
778
|
|
|
@@ -928,6 +1016,10 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
928
1016
|
),
|
|
929
1017
|
}
|
|
930
1018
|
)
|
|
1019
|
+
# passing the whois details to the context to avoid
|
|
1020
|
+
# the need to make an additional request in the js
|
|
1021
|
+
if data := get_whois_info(pk):
|
|
1022
|
+
ctx["device_whois_details"] = data
|
|
931
1023
|
return ctx
|
|
932
1024
|
|
|
933
1025
|
def add_view(self, request, form_url="", extra_context=None):
|
|
@@ -1046,7 +1138,7 @@ class TemplateAdmin(MultitenantAdminMixin, BaseConfigAdmin, SystemDefinedVariabl
|
|
|
1046
1138
|
"required",
|
|
1047
1139
|
"created",
|
|
1048
1140
|
]
|
|
1049
|
-
search_fields = ["name"]
|
|
1141
|
+
search_fields = ["name", "notes"]
|
|
1050
1142
|
multitenant_shared_relations = ("vpn",)
|
|
1051
1143
|
fields = [
|
|
1052
1144
|
"name",
|
|
@@ -1058,6 +1150,7 @@ class TemplateAdmin(MultitenantAdminMixin, BaseConfigAdmin, SystemDefinedVariabl
|
|
|
1058
1150
|
"tags",
|
|
1059
1151
|
"default",
|
|
1060
1152
|
"required",
|
|
1153
|
+
"notes",
|
|
1061
1154
|
"system_context",
|
|
1062
1155
|
"default_values",
|
|
1063
1156
|
"config",
|
|
@@ -1089,8 +1182,7 @@ class TemplateAdmin(MultitenantAdminMixin, BaseConfigAdmin, SystemDefinedVariabl
|
|
|
1089
1182
|
validated_org = Organization.objects.get(pk=organization)
|
|
1090
1183
|
except (ValidationError, Organization.DoesNotExist) as e:
|
|
1091
1184
|
logger.warning(
|
|
1092
|
-
"Detected tampering in clone template "
|
|
1093
|
-
f"form by user {user}: {e}"
|
|
1185
|
+
f"Detected tampering in clone template form by user {user}: {e}"
|
|
1094
1186
|
)
|
|
1095
1187
|
return
|
|
1096
1188
|
if not user.is_superuser and not user.is_manager(organization):
|
|
@@ -1202,7 +1294,10 @@ class VpnForm(forms.ModelForm):
|
|
|
1202
1294
|
|
|
1203
1295
|
|
|
1204
1296
|
class VpnAdmin(
|
|
1205
|
-
MultitenantAdminMixin,
|
|
1297
|
+
MultitenantAdminMixin,
|
|
1298
|
+
BaseConfigAdmin,
|
|
1299
|
+
CopyableFieldsAdmin,
|
|
1300
|
+
SystemDefinedVariableMixin,
|
|
1206
1301
|
):
|
|
1207
1302
|
form = VpnForm
|
|
1208
1303
|
list_display = [
|
|
@@ -1223,6 +1318,7 @@ class VpnAdmin(
|
|
|
1223
1318
|
]
|
|
1224
1319
|
search_fields = ["id", "name", "host", "key"]
|
|
1225
1320
|
readonly_fields = ["id", "uuid", "system_context"]
|
|
1321
|
+
copyable_fields = ["uuid"]
|
|
1226
1322
|
multitenant_shared_relations = ("ca", "cert", "subnet")
|
|
1227
1323
|
autocomplete_fields = ["ip", "subnet"]
|
|
1228
1324
|
fields = [
|
|
@@ -1293,12 +1389,19 @@ class DeviceGroupAdmin(MultitenantAdminMixin, BaseAdmin):
|
|
|
1293
1389
|
"created",
|
|
1294
1390
|
"modified",
|
|
1295
1391
|
]
|
|
1296
|
-
search_fields = ["name", "description", "
|
|
1392
|
+
search_fields = ["name", "description", "_meta_data_text"]
|
|
1297
1393
|
list_filter = [MultitenantOrgFilter, DeviceGroupFilter]
|
|
1298
1394
|
multitenant_shared_relations = ("templates",)
|
|
1299
1395
|
|
|
1396
|
+
def get_search_results(self, request, queryset, search_term):
|
|
1397
|
+
if search_term:
|
|
1398
|
+
queryset = queryset.annotate(
|
|
1399
|
+
_meta_data_text=Cast("meta_data", output_field=models.TextField()),
|
|
1400
|
+
)
|
|
1401
|
+
return super().get_search_results(request, queryset, search_term)
|
|
1402
|
+
|
|
1300
1403
|
class Media:
|
|
1301
|
-
js = list(
|
|
1404
|
+
js = list(CopyableFieldsAdmin.Media.js) + [
|
|
1302
1405
|
f"{prefix}js/relevant_templates.js",
|
|
1303
1406
|
]
|
|
1304
1407
|
css = {"all": (f"{prefix}css/admin.css",)}
|
|
@@ -1362,18 +1465,29 @@ class OrganizationLimitsInline(admin.StackedInline):
|
|
|
1362
1465
|
|
|
1363
1466
|
|
|
1364
1467
|
limits_inline_position = 0
|
|
1365
|
-
if getattr(app_settings, "REGISTRATION_ENABLED", True):
|
|
1366
1468
|
|
|
1367
|
-
class ConfigSettingsForm(AlwaysHasChangedMixin, forms.ModelForm):
|
|
1368
|
-
class Meta:
|
|
1369
|
-
widgets = {"context": FlatJsonWidget}
|
|
1370
1469
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1470
|
+
class ConfigSettingsForm(AlwaysHasChangedMixin, forms.ModelForm):
|
|
1471
|
+
class Meta:
|
|
1472
|
+
widgets = {"context": FlatJsonWidget}
|
|
1473
|
+
|
|
1474
|
+
|
|
1475
|
+
class ConfigSettingsInline(admin.StackedInline):
|
|
1476
|
+
model = OrganizationConfigSettings
|
|
1477
|
+
form = ConfigSettingsForm
|
|
1478
|
+
|
|
1479
|
+
def get_fields(self, request, obj=None):
|
|
1480
|
+
fields = []
|
|
1481
|
+
if app_settings.REGISTRATION_ENABLED:
|
|
1482
|
+
fields += ["registration_enabled", "shared_secret"]
|
|
1483
|
+
if app_settings.WHOIS_CONFIGURED:
|
|
1484
|
+
fields += ["whois_enabled"]
|
|
1485
|
+
fields += ["context"]
|
|
1486
|
+
return fields
|
|
1487
|
+
|
|
1374
1488
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1489
|
+
OrganizationAdmin.save_on_top = True
|
|
1490
|
+
OrganizationAdmin.inlines.insert(0, ConfigSettingsInline)
|
|
1491
|
+
limits_inline_position = 1
|
|
1378
1492
|
|
|
1379
1493
|
OrganizationAdmin.inlines.insert(limits_inline_position, OrganizationLimitsInline)
|
|
@@ -9,6 +9,7 @@ from openwisp_utils.api.serializers import ValidatedModelSerializer
|
|
|
9
9
|
|
|
10
10
|
from ...serializers import BaseSerializer
|
|
11
11
|
from .. import settings as app_settings
|
|
12
|
+
from ..whois.mixins import WHOISMixin
|
|
12
13
|
|
|
13
14
|
Template = load_model("config", "Template")
|
|
14
15
|
Vpn = load_model("config", "Vpn")
|
|
@@ -40,6 +41,7 @@ class TemplateSerializer(BaseSerializer):
|
|
|
40
41
|
"tags",
|
|
41
42
|
"default",
|
|
42
43
|
"required",
|
|
44
|
+
"notes",
|
|
43
45
|
"default_values",
|
|
44
46
|
"config",
|
|
45
47
|
"created",
|
|
@@ -70,6 +72,7 @@ class TemplateSerializer(BaseSerializer):
|
|
|
70
72
|
|
|
71
73
|
class VpnSerializer(BaseSerializer):
|
|
72
74
|
config = serializers.JSONField(initial={})
|
|
75
|
+
ip = serializers.PrimaryKeyRelatedField(read_only=True)
|
|
73
76
|
include_shared = True
|
|
74
77
|
|
|
75
78
|
class Meta(BaseMeta):
|
|
@@ -83,6 +86,10 @@ class VpnSerializer(BaseSerializer):
|
|
|
83
86
|
"ca",
|
|
84
87
|
"cert",
|
|
85
88
|
"backend",
|
|
89
|
+
"subnet",
|
|
90
|
+
"ip",
|
|
91
|
+
"webhook_endpoint",
|
|
92
|
+
"auth_token",
|
|
86
93
|
"notes",
|
|
87
94
|
"dh",
|
|
88
95
|
"config",
|
|
@@ -90,6 +97,28 @@ class VpnSerializer(BaseSerializer):
|
|
|
90
97
|
"modified",
|
|
91
98
|
]
|
|
92
99
|
|
|
100
|
+
def validate(self, data):
|
|
101
|
+
"""Validates the VPN and clears the certificate if CA is changed.
|
|
102
|
+
|
|
103
|
+
When the CA is updated on an existing VPN, the current certificate
|
|
104
|
+
(which was issued by the old CA) becomes invalid. This method clears
|
|
105
|
+
the certificate so the model's ``save()`` method can auto-create a
|
|
106
|
+
new one for the new CA.
|
|
107
|
+
"""
|
|
108
|
+
if self.instance and "ca" in data and self.instance.cert:
|
|
109
|
+
# if the CA is changed and new cert not supplied,
|
|
110
|
+
# allow creating a new certificate automatically
|
|
111
|
+
if data["ca"] and self.instance.cert.ca != data["ca"]:
|
|
112
|
+
data["cert"] = None
|
|
113
|
+
return super().validate(data)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class VpnListSerializer(VpnSerializer):
|
|
117
|
+
class Meta(VpnSerializer.Meta):
|
|
118
|
+
fields = VpnSerializer.Meta.fields[:]
|
|
119
|
+
fields.remove("webhook_endpoint")
|
|
120
|
+
fields.remove("auth_token")
|
|
121
|
+
|
|
93
122
|
|
|
94
123
|
class FilterTemplatesByOrganization(serializers.PrimaryKeyRelatedField):
|
|
95
124
|
def get_queryset(self):
|
|
@@ -274,7 +303,7 @@ class DeviceDetailConfigSerializer(BaseConfigSerializer):
|
|
|
274
303
|
templates = FilterTemplatesByOrganization(many=True)
|
|
275
304
|
|
|
276
305
|
|
|
277
|
-
class DeviceDetailSerializer(DeviceConfigSerializer):
|
|
306
|
+
class DeviceDetailSerializer(WHOISMixin, DeviceConfigSerializer):
|
|
278
307
|
config = DeviceDetailConfigSerializer(allow_null=True)
|
|
279
308
|
is_deactivated = serializers.BooleanField(read_only=True)
|
|
280
309
|
|