openwisp-controller 1.2.2__tar.gz → 1.3__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.2 → openwisp_controller-1.3}/CHANGES.rst +120 -0
- {openwisp_controller-1.2.2/openwisp_controller.egg-info → openwisp_controller-1.3}/PKG-INFO +15 -14
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/__init__.py +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/admin.py +143 -31
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/api/serializers.py +30 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/api/views.py +17 -19
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/apps.py +128 -78
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/base.py +3 -4
- openwisp_controller-1.3/openwisp_controller/config/base/cache.py +402 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/channels_consumer.py +1 -7
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/config.py +153 -52
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/device.py +77 -9
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/device_group.py +5 -21
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/multitenancy.py +21 -16
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/template.py +4 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/vpn.py +113 -9
- openwisp_controller-1.3/openwisp_controller/config/base/whois.py +210 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/controller/views.py +53 -14
- openwisp_controller-1.3/openwisp_controller/config/converters.py +27 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/handlers.py +64 -15
- openwisp_controller-1.3/openwisp_controller/config/management/commands/clear_last_ip.py +26 -0
- openwisp_controller-1.3/openwisp_controller/config/management/commands/print_cache_dependencies.py +22 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0001_squashed_0002_config_settings_uuid.py +3 -11
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0018_config_context.py +2 -6
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0023_update_context.py +2 -6
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0028_template_default_values.py +2 -6
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0036_device_group.py +1 -5
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0042_multiple_wireguard_tunnels.py +9 -4
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0048_wifi_radio_band_migration.py +13 -6
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0049_devicegroup_context.py +2 -6
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0051_organizationconfigsettings_context.py +2 -6
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0057_populate_vpnclient_template.py +8 -2
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0059_zerotier_templates_ow_zt_to_global.py +10 -5
- openwisp_controller-1.3/openwisp_controller/config/migrations/0061_config_checksum_db.py +330 -0
- openwisp_controller-1.3/openwisp_controller/config/migrations/0062_whoisinfo.py +89 -0
- openwisp_controller-1.3/openwisp_controller/config/migrations/0063_replace_jsonfield_with_django_builtin.py +122 -0
- openwisp_controller-1.3/openwisp_controller/config/migrations/0064_template_notes.py +18 -0
- openwisp_controller-1.3/openwisp_controller/config/migrations/0065_whoisinfo_unreferenced_since.py +19 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/__init__.py +13 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/models.py +11 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/settings.py +20 -5
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/signals.py +8 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/css/admin.css +48 -31
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/css/lib/advanced-mode.css +70 -62
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/css/lib/jsonschema-ui.css +18 -18
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/lib/advanced-mode.js +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/relevant_templates.js +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/tabs.js +5 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/widget.js +3 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/import_export/import-openwisp.css +7 -7
- openwisp_controller-1.3/openwisp_controller/config/static/whois/css/whois.css +110 -0
- openwisp_controller-1.3/openwisp_controller/config/static/whois/images/whois_globe.svg +3 -0
- openwisp_controller-1.3/openwisp_controller/config/static/whois/js/whois.js +62 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tasks.py +32 -22
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tasks_zerotier.py +10 -58
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/change_form.html +8 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/device/change_form.html +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/pytest.py +3 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_admin.py +284 -93
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_api.py +112 -22
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_config.py +619 -2
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_controller.py +500 -316
- openwisp_controller-1.3/openwisp_controller/config/tests/test_converters.py +23 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_device.py +118 -67
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_handlers.py +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_notifications.py +3 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_selenium.py +182 -40
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_views.py +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_vpn.py +206 -29
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/utils.py +43 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/utils.py +84 -21
- openwisp_controller-1.3/openwisp_controller/config/whois/commands.py +68 -0
- openwisp_controller-1.3/openwisp_controller/config/whois/handlers.py +45 -0
- openwisp_controller-1.3/openwisp_controller/config/whois/mixins.py +20 -0
- openwisp_controller-1.3/openwisp_controller/config/whois/serializers.py +17 -0
- openwisp_controller-1.3/openwisp_controller/config/whois/service.py +290 -0
- openwisp_controller-1.3/openwisp_controller/config/whois/tasks.py +138 -0
- openwisp_controller-1.3/openwisp_controller/config/whois/tests/tests.py +1353 -0
- openwisp_controller-1.3/openwisp_controller/config/whois/tests/utils.py +164 -0
- openwisp_controller-1.3/openwisp_controller/config/whois/utils.py +74 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/admin.py +26 -2
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/api/urls.py +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/api/views.py +15 -13
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/apps.py +6 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/base/models.py +85 -35
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/channels/routing.py +3 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/commands.py +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/connectors/openwrt/ssh.py +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/connectors/ssh.py +3 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0001_initial.py +6 -10
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0007_command.py +1 -5
- openwisp_controller-1.3/openwisp_controller/connection/migrations/0010_replace_jsonfield_with_django_builtin.py +47 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/static/connection/css/command-inline.css +24 -10
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/static/connection/js/commands.js +2 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tasks.py +16 -8
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/pytest.py +5 -4
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test_admin.py +37 -17
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test_api.py +4 -4
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test_models.py +154 -19
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test_notifications.py +6 -4
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test_selenium.py +3 -7
- openwisp_controller-1.3/openwisp_controller/connection/tests/test_tasks.py +317 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/utils.py +1 -1
- openwisp_controller-1.3/openwisp_controller/geo/admin.py +249 -0
- openwisp_controller-1.3/openwisp_controller/geo/api/filters.py +58 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/api/serializers.py +74 -6
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/api/views.py +129 -13
- openwisp_controller-1.3/openwisp_controller/geo/apps.py +177 -0
- openwisp_controller-1.3/openwisp_controller/geo/base/models.py +219 -0
- openwisp_controller-1.3/openwisp_controller/geo/channels/consumers.py +42 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/channels/routing.py +11 -3
- openwisp_controller-1.3/openwisp_controller/geo/estimated_location/handlers.py +83 -0
- openwisp_controller-1.3/openwisp_controller/geo/estimated_location/mixins.py +37 -0
- openwisp_controller-1.3/openwisp_controller/geo/estimated_location/service.py +253 -0
- openwisp_controller-1.3/openwisp_controller/geo/estimated_location/tasks.py +47 -0
- openwisp_controller-1.3/openwisp_controller/geo/estimated_location/tests/tests.py +1415 -0
- openwisp_controller-1.3/openwisp_controller/geo/estimated_location/tests/utils.py +43 -0
- openwisp_controller-1.3/openwisp_controller/geo/estimated_location/utils.py +143 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/migrations/0001_initial.py +4 -1
- openwisp_controller-1.3/openwisp_controller/geo/migrations/0004_location_is_estimated.py +22 -0
- openwisp_controller-1.3/openwisp_controller/geo/migrations/0005_organizationgeosettings.py +55 -0
- openwisp_controller-1.3/openwisp_controller/geo/migrations/0006_create_geo_settings_for_existing_orgs.py +40 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/migrations/__init__.py +15 -2
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/models.py +12 -1
- openwisp_controller-1.3/openwisp_controller/geo/settings.py +13 -0
- openwisp_controller-1.3/openwisp_controller/geo/tasks.py +3 -0
- openwisp_controller-1.3/openwisp_controller/geo/templates/admin/geo/device_location_inline.html +11 -0
- openwisp_controller-1.3/openwisp_controller/geo/templates/admin/geo/location/change_form.html +11 -0
- openwisp_controller-1.3/openwisp_controller/geo/tests/pytest.py +201 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/tests/test_admin.py +74 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/tests/test_admin_inline.py +11 -15
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/tests/test_api.py +638 -22
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/tests/test_selenium.py +47 -4
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/tests/utils.py +6 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/utils.py +10 -0
- openwisp_controller-1.3/openwisp_controller/pki/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/api/views.py +5 -9
- openwisp_controller-1.3/openwisp_controller/pki/base/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0001_initial.py +2 -8
- openwisp_controller-1.3/openwisp_controller/pki/migrations/0012_alter_ca_extensions_alter_ca_key_length_and_more.py +70 -0
- openwisp_controller-1.3/openwisp_controller/pki/tests/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/tests/test_api.py +64 -51
- openwisp_controller-1.3/openwisp_controller/settings.py +8 -0
- openwisp_controller-1.3/openwisp_controller/subnet_division/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/admin.py +1 -1
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/base/models.py +1 -1
- openwisp_controller-1.3/openwisp_controller/subnet_division/rule_types/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/rule_types/base.py +64 -24
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/rule_types/vpn.py +7 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/static/subnet-division/css/subnet-division.css +3 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/tasks.py +9 -0
- openwisp_controller-1.3/openwisp_controller/subnet_division/tests/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/tests/test_admin.py +137 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/tests/test_models.py +103 -12
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/tests/mixins.py +5 -0
- openwisp_controller-1.3/openwisp_controller/tests/test_migrationgraph.py +32 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/tests/test_selenium.py +5 -3
- {openwisp_controller-1.2.2 → openwisp_controller-1.3/openwisp_controller.egg-info}/PKG-INFO +15 -14
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller.egg-info/SOURCES.txt +45 -0
- openwisp_controller-1.3/openwisp_controller.egg-info/requires.txt +19 -0
- openwisp_controller-1.3/requirements.txt +19 -0
- openwisp_controller-1.2.2/openwisp_controller/config/migrations/0061_config_checksum_db.py +0 -57
- openwisp_controller-1.2.2/openwisp_controller/connection/tests/test_tasks.py +0 -87
- openwisp_controller-1.2.2/openwisp_controller/geo/admin.py +0 -142
- openwisp_controller-1.2.2/openwisp_controller/geo/api/filters.py +0 -27
- openwisp_controller-1.2.2/openwisp_controller/geo/apps.py +0 -119
- openwisp_controller-1.2.2/openwisp_controller/geo/base/models.py +0 -65
- openwisp_controller-1.2.2/openwisp_controller/geo/channels/consumers.py +0 -19
- openwisp_controller-1.2.2/openwisp_controller/geo/tests/pytest.py +0 -110
- openwisp_controller-1.2.2/openwisp_controller/settings.py +0 -3
- openwisp_controller-1.2.2/openwisp_controller.egg-info/requires.txt +0 -18
- openwisp_controller-1.2.2/requirements.txt +0 -18
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/LICENSE +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/MANIFEST.in +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/README.rst +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/admin.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/base.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/checks.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/api/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/api/download_views.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/api/filters.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/api/urls.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/api/zerotier_service.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/base/tag.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/controller/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/controller/urls.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/crypto.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/exceptions.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/exportable.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/filters.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/fixtures/test_templates.json +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/config/sortedm2m → openwisp_controller-1.3/openwisp_controller/config/management}/__init__.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/connection → openwisp_controller-1.3/openwisp_controller/config/management/commands}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0003_template_tags.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0004_add_device_model.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0005_populate_device.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0006_config_device_not_null.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0007_simplify_config.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0008_update_indexes.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0009_device_system.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0010_auto_20180106_1814.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0011_update_device_mac_address.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0012_auto_20180219_1501.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0013_last_ip_management_ip_and_status_applied.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0014_device_hardware_id.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0015_default_groups_permissions.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0016_default_organization_config_settings.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0017_template_name_organization_unique_together.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0019_organization_mac_add_hardware_id_name_unique_together.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0020_remove_config_organization.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0021_vpn_key.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0022_vpn_format_dh.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0024_update_context_data.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0025_update_device_key.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0026_hardware_id_not_unique.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0027_add_indexes_on_ip_fields.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0029_merge_django_netjsonconfig.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0030_django_taggit_update.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0031_update_vpn_dh_param.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0032_update_legacy_vpn_backend.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0033_name_unique_per_organization.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0034_template_required.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0035_device_name_unique_optional.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0037_alter_taggedtemplate.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0038_vpn_subnet.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0039_wireguard_vxlan_ipam.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0040_vpnclient_ip_setnull.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0041_default_groups_organizationconfigsettings_permission.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0043_devicegroup_templates.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0044_config_error_reason.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0045_alter_vpn_webhook_endpoint.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0046_organizationlimits.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0047_add_organizationlimits.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0050_alter_vpnclient_unique_together.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0052_vpn_node_network_id.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0053_vpnclient_secret.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0054_device__is_deactivated.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0055_alter_config_status.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0056_vpnclient_template.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0058_alter_vpnclient_template.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/migrations/0060_cleanup_api_task_notification_types.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/connection/base → openwisp_controller-1.3/openwisp_controller/config/sortedm2m}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/sortedm2m/fields.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/sortedm2m/forms.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/css/device-delete-confirmation.css +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/css/devicegroup.css +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/css/lib/img/jsoneditor-icons.svg +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/device-delete-confirmation.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/lib/jsonschema-ui.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/lib/tomorrow_night_bright.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/management_ip.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/preview.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/switcher.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/unsaved_changes.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/utils.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/config/js/vpn.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/sortedm2m/patch_sortedm2m.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/static/support.css +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/change_device_group.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/change_list_device.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/clone_template_form.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/device/delete_confirmation.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/device/delete_selected_confirmation.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/device_recover_form.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/jsonschema-widget.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/preview.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/config/system_context.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/device_group/change_form.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/admin/import_export/import.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/templates/reversion/config/revision_form.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_apps.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_device_group.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_tag.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/tests/test_template.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/urls.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/validators.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/views.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/connection/connectors → openwisp_controller-1.3/openwisp_controller/config/whois}/__init__.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/connection/connectors/openwrt → openwisp_controller-1.3/openwisp_controller/config/whois/tests}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/widgets.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/connection/tests → openwisp_controller-1.3/openwisp_controller/connection}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/api/serializers.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/geo → openwisp_controller-1.3/openwisp_controller/connection/base}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/channels/consumers.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/geo/api → openwisp_controller-1.3/openwisp_controller/connection/connectors}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/connectors/airos/snmp.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/connectors/exceptions.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/geo/base → openwisp_controller-1.3/openwisp_controller/connection/connectors/openwrt}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/connectors/openwrt/snmp.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/connectors/snmp.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/exceptions.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0002_credentials_auto_add.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0003_default_group_permissions.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0004_django3_1_upgrade.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0005_device_connection_failure_reason.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0006_name_unique_per_organization.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0008_remove_conflicting_deviceconnections.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/0009_alter_deviceconnection_unique_together.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/migrations/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/models.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/schema.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/settings.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/signals.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/static/connection/css/credentials.css +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/static/connection/js/credentials.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/static/connection/js/lib/reconnecting-websocket.min.js +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/geo/channels → openwisp_controller-1.3/openwisp_controller/connection/tests}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/base.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test-key.ed25519 +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test-key.rsa +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test_command_utilities.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test_snmp.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/tests/test_ssh.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/utils.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/connection/widgets.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/context_processors.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/geo/tests → openwisp_controller-1.3/openwisp_controller/geo}/__init__.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/pki → openwisp_controller-1.3/openwisp_controller/geo/api}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/api/urls.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/pki → openwisp_controller-1.3/openwisp_controller/geo}/base/__init__.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/pki/tests → openwisp_controller-1.3/openwisp_controller/geo/channels}/__init__.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/subnet_division → openwisp_controller-1.3/openwisp_controller/geo/estimated_location}/__init__.py +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/subnet_division/rule_types → openwisp_controller-1.3/openwisp_controller/geo/estimated_location/tests}/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/exportable.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/migrations/0002_default_groups_permissions.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/migrations/0003_alter_devicelocation_floorplan_location.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/templates/admin/widgets/foreign_key_raw_id.html +0 -0
- {openwisp_controller-1.2.2/openwisp_controller/subnet_division → openwisp_controller-1.3/openwisp_controller/geo}/tests/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/tests/test_apps.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/geo/tests/test_models.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/migrations.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/mixins.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/admin.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/api/serializers.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/api/urls.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/apps.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/base/models.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0002_add_organization_name.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0003_fill_organization_name.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0004_auto_20180106_1814.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0005_organizational_unit_name.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0006_add_x509_passphrase_field.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0007_default_groups_permissions.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0008_serial_number_length.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0009_common_name_maxlength_64.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0010_common_name_organization_unique.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/0011_disallowed_blank_key_length_or_digest.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/migrations/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/models.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/static/admin/pki/js/show-org-field.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/templates/admin/pki/change_form.html +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/tests/test_admin.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/tests/test_models.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/tests/utils.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/urls.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/pki/utils.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/routing.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/serializers.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/apps.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/filters.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/migrations/0001_initial.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/migrations/0002_default_group_migration.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/migrations/0003_related_field_allow_blank.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/migrations/0004_index_rule_on_delete.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/migrations/0005_number_of_subnets_and_ips.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/migrations/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/models.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/rule_types/device.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/settings.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/signals.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/static/subnet-division/js/subnet-division.js +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/tests/helpers.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/tests/test_rule.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/subnet_division/utils.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/tests/__init__.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/tests/test_users_integration.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/tests/test_utilities.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/tests/utils.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/urls.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/vpn_backends.py +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller.egg-info/dependency_links.txt +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller.egg-info/not-zip-safe +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller.egg-info/top_level.txt +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/pyproject.toml +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/setup.cfg +0 -0
- {openwisp_controller-1.2.2 → openwisp_controller-1.3}/setup.py +0 -0
|
@@ -1,6 +1,126 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
Version 1.3.0 [2026-09-03]
|
|
5
|
+
--------------------------
|
|
6
|
+
|
|
7
|
+
Features
|
|
8
|
+
~~~~~~~~
|
|
9
|
+
|
|
10
|
+
- Added `WHOIS lookup and geographic location estimation
|
|
11
|
+
<https://github.com/openwisp/openwisp-controller/issues/1034>`_ for
|
|
12
|
+
devices, including WHOIS details in the admin UI, automatic refresh of
|
|
13
|
+
stale WHOIS data, estimated-location notifications and warnings, and
|
|
14
|
+
admin and API filters for estimated locations.
|
|
15
|
+
- Added `WebSocket support for broadcasting all location updates
|
|
16
|
+
<https://github.com/openwisp/openwisp-controller/issues/1157>`_.
|
|
17
|
+
- Added an `API endpoint for retrieving indoor device coordinates
|
|
18
|
+
<https://github.com/openwisp/openwisp-controller/issues/828>`_ for a
|
|
19
|
+
location.
|
|
20
|
+
- Added `location and floorplan filters to the device list API
|
|
21
|
+
<https://github.com/openwisp/openwisp-controller/issues/1158>`_,
|
|
22
|
+
allowing searches by location name and filtering by location or
|
|
23
|
+
floorplan UUID.
|
|
24
|
+
- Added `generic cache invalidation for configuration models
|
|
25
|
+
<https://github.com/openwisp/openwisp-controller/issues/1095>`_. Models
|
|
26
|
+
can declare cache dependencies using ``CacheDependency``, and the new
|
|
27
|
+
``print_cache_dependencies`` management command can be used to inspect
|
|
28
|
+
the dependency graph.
|
|
29
|
+
- Added `notes to configuration templates
|
|
30
|
+
<https://github.com/openwisp/openwisp-controller/issues/1412>`_.
|
|
31
|
+
- Allowed devices to update their name during re-registration.
|
|
32
|
+
|
|
33
|
+
Changes
|
|
34
|
+
~~~~~~~
|
|
35
|
+
|
|
36
|
+
Other changes
|
|
37
|
+
+++++++++++++
|
|
38
|
+
|
|
39
|
+
- Enforced the `deactivated device state across OpenWISP Controller
|
|
40
|
+
<https://github.com/openwisp/openwisp-controller/issues/1338>`_.
|
|
41
|
+
Deactivated devices can no longer register, receive configuration
|
|
42
|
+
updates, run remote commands, or receive automatically assigned
|
|
43
|
+
templates. Cleanup and security operations continue to work normally.
|
|
44
|
+
- Added `VPN subnet and IP address details to the REST API
|
|
45
|
+
<https://github.com/openwisp/openwisp-controller/issues/1003>`_.
|
|
46
|
+
- Allowed deleting organizations containing active devices while
|
|
47
|
+
displaying a warning about the active devices that will be affected.
|
|
48
|
+
- Replaced the third-party ``jsonfield`` implementation with Django's
|
|
49
|
+
built-in ``JSONField`` `#1061
|
|
50
|
+
<https://github.com/openwisp/openwisp-controller/issues/1061>`_,
|
|
51
|
+
including migration handling for databases upgraded from older OpenWISP
|
|
52
|
+
Controller versions.
|
|
53
|
+
- Changed VPN synchronization errors and recovery events to use
|
|
54
|
+
``generic_message`` notifications `#1049
|
|
55
|
+
<https://github.com/openwisp/openwisp-controller/issues/1049>`_.
|
|
56
|
+
- Improved command status visibility in the admin interface by
|
|
57
|
+
highlighting statuses with different colors `#812
|
|
58
|
+
<https://github.com/openwisp/openwisp-controller/issues/812>`_.
|
|
59
|
+
|
|
60
|
+
Dependencies
|
|
61
|
+
++++++++++++
|
|
62
|
+
|
|
63
|
+
- Bumped ``django-reversion`` from ``~=6.0.0`` to `~=6.3.0
|
|
64
|
+
<https://github.com/etianen/django-reversion/blob/v6.3.0/CHANGELOG.rst>`_.
|
|
65
|
+
- Bumped ``netjsonconfig`` from ``~=1.2.0`` to `~=1.3.0
|
|
66
|
+
<https://github.com/openwisp/netjsonconfig/blob/master/CHANGES.rst>`__.
|
|
67
|
+
- Bumped ``django-x509`` from ``~=1.3.0`` to `~=1.4.0
|
|
68
|
+
<https://github.com/openwisp/django-x509/blob/master/CHANGES.rst>`_.
|
|
69
|
+
- Bumped ``django-loci`` from ``~=1.2.0`` to `~=1.3.0
|
|
70
|
+
<https://github.com/openwisp/django-loci/blob/master/CHANGES.rst>`__.
|
|
71
|
+
- Bumped ``django-flat-json-widget`` from ``~=0.4.0`` to `~=0.5.0
|
|
72
|
+
<https://github.com/openwisp/django-flat-json-widget/blob/master/CHANGES.rst>`_.
|
|
73
|
+
- Bumped ``openwisp-users`` from ``~=1.2.0`` to `~=1.3.0
|
|
74
|
+
<https://github.com/openwisp/openwisp-users/blob/master/CHANGES.rst>`__.
|
|
75
|
+
- Bumped ``openwisp-utils[celery,channels]`` from ``~=1.2.0`` to `~=1.3.0
|
|
76
|
+
<https://github.com/openwisp/openwisp-utils/blob/master/CHANGES.rst>`__.
|
|
77
|
+
- Bumped ``openwisp-notifications`` from ``~=1.2.0`` to `~=1.3.0
|
|
78
|
+
<https://github.com/openwisp/openwisp-notifications/blob/master/CHANGES.rst>`__.
|
|
79
|
+
- Bumped ``openwisp-ipam`` from ``~=1.2.0`` to `~=1.3.1
|
|
80
|
+
<https://github.com/openwisp/openwisp-ipam/blob/master/CHANGES.rst>`_.
|
|
81
|
+
- Bumped ``djangorestframework-gis`` from ``~=1.2.0`` to `~=1.3.0
|
|
82
|
+
<https://github.com/openwisp/django-rest-framework-gis/blob/master/CHANGES.rst>`__.
|
|
83
|
+
- Bumped ``paramiko`` from ``~=4.0.0`` to `~=5.0.0
|
|
84
|
+
<https://www.paramiko.org/changelog.html>`_.
|
|
85
|
+
- Bumped ``scp`` from ``~=0.15.0`` to `~=0.16.1
|
|
86
|
+
<https://github.com/jbardin/scp.py/releases/tag/v0.16.1>`_.
|
|
87
|
+
- Bumped ``django-import-export`` from ``~=4.3.10`` to `~=4.4.1
|
|
88
|
+
<https://django-import-export.readthedocs.io/en/latest/changelog.html>`_.
|
|
89
|
+
- Added `geoip2>=5.3.0,<6.0.0
|
|
90
|
+
<https://github.com/maxmind/GeoIP2-python/releases/tag/v5.3.0>`_.
|
|
91
|
+
- Dropped support for Django ``4.2``.
|
|
92
|
+
- Dropped support for Python ``3.9``.
|
|
93
|
+
|
|
94
|
+
Bugfixes
|
|
95
|
+
~~~~~~~~
|
|
96
|
+
|
|
97
|
+
- Fixed `subnet-division rules allocating addresses already in use
|
|
98
|
+
<https://github.com/openwisp/openwisp-controller/issues/1464>`_ by
|
|
99
|
+
respecting existing child prefixes and pre-allocated IP addresses.
|
|
100
|
+
- Fixed background command and connection operations potentially restoring
|
|
101
|
+
objects that had been deleted concurrently or causing foreign key
|
|
102
|
+
errors.
|
|
103
|
+
- Fixed VPN client synchronization when switching VPN templates,
|
|
104
|
+
preventing inconsistent client state during repeated template updates.
|
|
105
|
+
- Fixed SSH connections remaining open when ``update_config()`` failed.
|
|
106
|
+
- Fixed `malformed UUID URLs returning HTTP 500 instead of HTTP 404
|
|
107
|
+
<https://github.com/openwisp/openwisp-controller/issues/682>`_.
|
|
108
|
+
- Fixed the Device admin delete confirmation page when OpenWISP Controller
|
|
109
|
+
is extended by downstream applications.
|
|
110
|
+
- Fixed a typo in the ``update_strategy`` validation error message.
|
|
111
|
+
|
|
112
|
+
Version 1.2.3 [2026-04-09]
|
|
113
|
+
--------------------------
|
|
114
|
+
|
|
115
|
+
Bugfixes
|
|
116
|
+
~~~~~~~~
|
|
117
|
+
|
|
118
|
+
- Corrected initial field value assignment in ``AbstractDevice`` class
|
|
119
|
+
- Fixed duplicate template entries in Device admin
|
|
120
|
+
- Invalidate Config checksum after subnet provisioning
|
|
121
|
+
- Fixed concurrent ``update_config`` detection `#1204
|
|
122
|
+
<https://github.com/openwisp/openwisp-controller/issues/1204>`_
|
|
123
|
+
|
|
4
124
|
Version 1.2.2 [2026-03-06]
|
|
5
125
|
--------------------------
|
|
6
126
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openwisp-controller
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3
|
|
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",
|
|
@@ -548,6 +562,7 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
548
562
|
"created",
|
|
549
563
|
"modified",
|
|
550
564
|
]
|
|
565
|
+
copyable_fields = ["uuid"]
|
|
551
566
|
inlines = [ConfigInline]
|
|
552
567
|
conditional_inlines = []
|
|
553
568
|
actions = [
|
|
@@ -569,12 +584,21 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
569
584
|
fields.insert(0, "hardware_id")
|
|
570
585
|
list_select_related = ("config", "organization")
|
|
571
586
|
|
|
572
|
-
|
|
587
|
+
# overriding media property to allow testing in isolation
|
|
588
|
+
# as class Media is evaluated at import time making the
|
|
589
|
+
# settings not overridable in tests
|
|
590
|
+
@property
|
|
591
|
+
def media(self):
|
|
573
592
|
js = BaseConfigAdmin.Media.js + [
|
|
574
593
|
f"{prefix}js/tabs.js",
|
|
575
594
|
f"{prefix}js/management_ip.js",
|
|
576
595
|
f"{prefix}js/relevant_templates.js",
|
|
577
596
|
]
|
|
597
|
+
css = BaseConfigAdmin.Media.css["all"]
|
|
598
|
+
if app_settings.WHOIS_CONFIGURED:
|
|
599
|
+
js.append(f"{whois_prefix}js/whois.js")
|
|
600
|
+
css += (f"{whois_prefix}css/whois.css",)
|
|
601
|
+
return super().media + forms.Media(js=js, css={"all": css})
|
|
578
602
|
|
|
579
603
|
def has_change_permission(self, request, obj=None):
|
|
580
604
|
perm = super().has_change_permission(request)
|
|
@@ -586,8 +610,70 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
586
610
|
perm = super().has_delete_permission(request)
|
|
587
611
|
if not obj:
|
|
588
612
|
return perm
|
|
613
|
+
if BlockDeleteAllowCascadeMixin.is_admin_cascade_delete_request(self, request):
|
|
614
|
+
self._add_active_device_delete_warning(request, obj)
|
|
615
|
+
return perm
|
|
589
616
|
return perm and obj.is_deactivated()
|
|
590
617
|
|
|
618
|
+
def _add_active_device_delete_warning(self, request, obj):
|
|
619
|
+
if getattr(request, "_active_device_delete_warning_checked", False):
|
|
620
|
+
return
|
|
621
|
+
resolver_match = getattr(request, "resolver_match", None)
|
|
622
|
+
url_name = getattr(resolver_match, "url_name", None)
|
|
623
|
+
opts = Organization._meta
|
|
624
|
+
organization_delete_url_name = f"{opts.app_label}_{opts.model_name}_delete"
|
|
625
|
+
organization_changelist_url_name = (
|
|
626
|
+
f"{opts.app_label}_{opts.model_name}_changelist"
|
|
627
|
+
)
|
|
628
|
+
active_organizations = 0
|
|
629
|
+
if request.method == "GET" and url_name == organization_delete_url_name:
|
|
630
|
+
request._active_device_delete_warning_checked = True
|
|
631
|
+
active_organizations = (
|
|
632
|
+
Device.objects.filter(
|
|
633
|
+
organization_id=obj.organization_id,
|
|
634
|
+
_is_deactivated=False,
|
|
635
|
+
)
|
|
636
|
+
.values("organization_id")
|
|
637
|
+
.distinct()
|
|
638
|
+
.count()
|
|
639
|
+
)
|
|
640
|
+
elif (
|
|
641
|
+
url_name == organization_changelist_url_name
|
|
642
|
+
and request.POST.get("action") == "delete_selected"
|
|
643
|
+
and not request.POST.get("post")
|
|
644
|
+
):
|
|
645
|
+
request._active_device_delete_warning_checked = True
|
|
646
|
+
organizations = self.admin_site.get_model_admin(Organization).get_queryset(
|
|
647
|
+
request
|
|
648
|
+
)
|
|
649
|
+
active_organizations = (
|
|
650
|
+
Device.objects.filter(
|
|
651
|
+
organization_id__in=organizations.filter(
|
|
652
|
+
pk__in=request.POST.getlist(helpers.ACTION_CHECKBOX_NAME)
|
|
653
|
+
),
|
|
654
|
+
_is_deactivated=False,
|
|
655
|
+
)
|
|
656
|
+
.values("organization_id")
|
|
657
|
+
.distinct()
|
|
658
|
+
.count()
|
|
659
|
+
)
|
|
660
|
+
if not active_organizations:
|
|
661
|
+
return
|
|
662
|
+
self.message_user(
|
|
663
|
+
request,
|
|
664
|
+
ngettext_lazy(
|
|
665
|
+
"This organization contains active devices. It is highly "
|
|
666
|
+
"recommended to deactivate them before deleting the organization "
|
|
667
|
+
"to ensure sensitive configuration data is disposed of safely.",
|
|
668
|
+
"%(count)d organizations contain active devices. It is highly "
|
|
669
|
+
"recommended to deactivate them before deleting the organizations "
|
|
670
|
+
"to ensure sensitive configuration data is disposed of safely.",
|
|
671
|
+
active_organizations,
|
|
672
|
+
)
|
|
673
|
+
% {"count": active_organizations},
|
|
674
|
+
messages.WARNING,
|
|
675
|
+
)
|
|
676
|
+
|
|
591
677
|
def save_form(self, request, form, change):
|
|
592
678
|
self._state_adding = form.instance._state.adding
|
|
593
679
|
return super().save_form(request, form, change)
|
|
@@ -656,6 +742,7 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
656
742
|
form = ChangeDeviceGroupForm(data=request.POST, org_id=org_id)
|
|
657
743
|
if form.is_valid():
|
|
658
744
|
group = form.cleaned_data["device_group"]
|
|
745
|
+
queryset = queryset.filter(_is_deactivated=False)
|
|
659
746
|
# Evaluate queryset to store old group id
|
|
660
747
|
old_group_qs = list(queryset)
|
|
661
748
|
queryset.update(group=group or None)
|
|
@@ -683,8 +770,7 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
683
770
|
"action_checkbox_name": helpers.ACTION_CHECKBOX_NAME,
|
|
684
771
|
"opts": self.model._meta,
|
|
685
772
|
"changelist_url": (
|
|
686
|
-
f"{request.resolver_match.app_name}:"
|
|
687
|
-
f"{request.resolver_match.url_name}"
|
|
773
|
+
f"{request.resolver_match.app_name}:{request.resolver_match.url_name}"
|
|
688
774
|
),
|
|
689
775
|
}
|
|
690
776
|
|
|
@@ -928,6 +1014,10 @@ class DeviceAdmin(MultitenantAdminMixin, BaseConfigAdmin, UUIDAdmin):
|
|
|
928
1014
|
),
|
|
929
1015
|
}
|
|
930
1016
|
)
|
|
1017
|
+
# passing the whois details to the context to avoid
|
|
1018
|
+
# the need to make an additional request in the js
|
|
1019
|
+
if data := get_whois_info(pk):
|
|
1020
|
+
ctx["device_whois_details"] = data
|
|
931
1021
|
return ctx
|
|
932
1022
|
|
|
933
1023
|
def add_view(self, request, form_url="", extra_context=None):
|
|
@@ -1046,7 +1136,7 @@ class TemplateAdmin(MultitenantAdminMixin, BaseConfigAdmin, SystemDefinedVariabl
|
|
|
1046
1136
|
"required",
|
|
1047
1137
|
"created",
|
|
1048
1138
|
]
|
|
1049
|
-
search_fields = ["name"]
|
|
1139
|
+
search_fields = ["name", "notes"]
|
|
1050
1140
|
multitenant_shared_relations = ("vpn",)
|
|
1051
1141
|
fields = [
|
|
1052
1142
|
"name",
|
|
@@ -1058,6 +1148,7 @@ class TemplateAdmin(MultitenantAdminMixin, BaseConfigAdmin, SystemDefinedVariabl
|
|
|
1058
1148
|
"tags",
|
|
1059
1149
|
"default",
|
|
1060
1150
|
"required",
|
|
1151
|
+
"notes",
|
|
1061
1152
|
"system_context",
|
|
1062
1153
|
"default_values",
|
|
1063
1154
|
"config",
|
|
@@ -1089,8 +1180,7 @@ class TemplateAdmin(MultitenantAdminMixin, BaseConfigAdmin, SystemDefinedVariabl
|
|
|
1089
1180
|
validated_org = Organization.objects.get(pk=organization)
|
|
1090
1181
|
except (ValidationError, Organization.DoesNotExist) as e:
|
|
1091
1182
|
logger.warning(
|
|
1092
|
-
"Detected tampering in clone template "
|
|
1093
|
-
f"form by user {user}: {e}"
|
|
1183
|
+
f"Detected tampering in clone template form by user {user}: {e}"
|
|
1094
1184
|
)
|
|
1095
1185
|
return
|
|
1096
1186
|
if not user.is_superuser and not user.is_manager(organization):
|
|
@@ -1202,7 +1292,10 @@ class VpnForm(forms.ModelForm):
|
|
|
1202
1292
|
|
|
1203
1293
|
|
|
1204
1294
|
class VpnAdmin(
|
|
1205
|
-
MultitenantAdminMixin,
|
|
1295
|
+
MultitenantAdminMixin,
|
|
1296
|
+
BaseConfigAdmin,
|
|
1297
|
+
CopyableFieldsAdmin,
|
|
1298
|
+
SystemDefinedVariableMixin,
|
|
1206
1299
|
):
|
|
1207
1300
|
form = VpnForm
|
|
1208
1301
|
list_display = [
|
|
@@ -1223,6 +1316,7 @@ class VpnAdmin(
|
|
|
1223
1316
|
]
|
|
1224
1317
|
search_fields = ["id", "name", "host", "key"]
|
|
1225
1318
|
readonly_fields = ["id", "uuid", "system_context"]
|
|
1319
|
+
copyable_fields = ["uuid"]
|
|
1226
1320
|
multitenant_shared_relations = ("ca", "cert", "subnet")
|
|
1227
1321
|
autocomplete_fields = ["ip", "subnet"]
|
|
1228
1322
|
fields = [
|
|
@@ -1293,12 +1387,19 @@ class DeviceGroupAdmin(MultitenantAdminMixin, BaseAdmin):
|
|
|
1293
1387
|
"created",
|
|
1294
1388
|
"modified",
|
|
1295
1389
|
]
|
|
1296
|
-
search_fields = ["name", "description", "
|
|
1390
|
+
search_fields = ["name", "description", "_meta_data_text"]
|
|
1297
1391
|
list_filter = [MultitenantOrgFilter, DeviceGroupFilter]
|
|
1298
1392
|
multitenant_shared_relations = ("templates",)
|
|
1299
1393
|
|
|
1394
|
+
def get_search_results(self, request, queryset, search_term):
|
|
1395
|
+
if search_term:
|
|
1396
|
+
queryset = queryset.annotate(
|
|
1397
|
+
_meta_data_text=Cast("meta_data", output_field=models.TextField()),
|
|
1398
|
+
)
|
|
1399
|
+
return super().get_search_results(request, queryset, search_term)
|
|
1400
|
+
|
|
1300
1401
|
class Media:
|
|
1301
|
-
js = list(
|
|
1402
|
+
js = list(CopyableFieldsAdmin.Media.js) + [
|
|
1302
1403
|
f"{prefix}js/relevant_templates.js",
|
|
1303
1404
|
]
|
|
1304
1405
|
css = {"all": (f"{prefix}css/admin.css",)}
|
|
@@ -1362,18 +1463,29 @@ class OrganizationLimitsInline(admin.StackedInline):
|
|
|
1362
1463
|
|
|
1363
1464
|
|
|
1364
1465
|
limits_inline_position = 0
|
|
1365
|
-
if getattr(app_settings, "REGISTRATION_ENABLED", True):
|
|
1366
1466
|
|
|
1367
|
-
class ConfigSettingsForm(AlwaysHasChangedMixin, forms.ModelForm):
|
|
1368
|
-
class Meta:
|
|
1369
|
-
widgets = {"context": FlatJsonWidget}
|
|
1370
1467
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1468
|
+
class ConfigSettingsForm(AlwaysHasChangedMixin, forms.ModelForm):
|
|
1469
|
+
class Meta:
|
|
1470
|
+
widgets = {"context": FlatJsonWidget}
|
|
1471
|
+
|
|
1472
|
+
|
|
1473
|
+
class ConfigSettingsInline(admin.StackedInline):
|
|
1474
|
+
model = OrganizationConfigSettings
|
|
1475
|
+
form = ConfigSettingsForm
|
|
1476
|
+
|
|
1477
|
+
def get_fields(self, request, obj=None):
|
|
1478
|
+
fields = []
|
|
1479
|
+
if app_settings.REGISTRATION_ENABLED:
|
|
1480
|
+
fields += ["registration_enabled", "shared_secret"]
|
|
1481
|
+
if app_settings.WHOIS_CONFIGURED:
|
|
1482
|
+
fields += ["whois_enabled"]
|
|
1483
|
+
fields += ["context"]
|
|
1484
|
+
return fields
|
|
1485
|
+
|
|
1374
1486
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1487
|
+
OrganizationAdmin.save_on_top = True
|
|
1488
|
+
OrganizationAdmin.inlines.insert(0, ConfigSettingsInline)
|
|
1489
|
+
limits_inline_position = 1
|
|
1378
1490
|
|
|
1379
1491
|
OrganizationAdmin.inlines.insert(limits_inline_position, OrganizationLimitsInline)
|
{openwisp_controller-1.2.2 → openwisp_controller-1.3}/openwisp_controller/config/api/serializers.py
RENAMED
|
@@ -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
|
|