From d195a6ea3755f48d22efa657fb20aa1cf64a6846 Mon Sep 17 00:00:00 2001 From: Walter Lorenzetti Date: Wed, 15 Jan 2025 15:36:09 +0100 Subject: [PATCH] Update to Django 4.2 (#1004) * Migration to Django 4.2 * Migration to Django 4.2 * Update README * Update requirements.txt * Update requirements.txt * Fix ALLOWED_HOSTS * Update requirements.txt: update django-model-utils at version 4.5.1 * Fix requires_system_checks Command property in 'set_passwords' command. * Update to pyscopg3 * Update PostgreSQL to v16 for CI * Typo * Update docker compose for CI * Fix db name according to ne PG 16 * Deepcopy fix * Update requirements.txt * Update README * Refactoring tests and utilities for Django 4.2 * Change url for proxy test * Update project version for test * Fix for test * Move test data from setUpTestData classmethod to setUp method. * Fix test for Django 4.2 * Fix test for Django 4.2 * Fix tests for Django 4.2 * Typo * Fix Test for Django 4.2 * Mismatching datasource path with layers data path inside teh QGIS project file. * Remove old reference * Fix tests for Django 4.2 * Fix test for Django 4.2 * Fix tests for Django 4.2 * Restore cassetes to no zipped content * Update Django to 4.2.17 * Update base version * Remove old project for test --------- Co-authored-by: wlorenzetti --- README.md | 5 +- docker-compose.latest.yml | 7 +- docker-compose.ltr.yml | 9 +- g3w-admin/about/tests/test_api.py | 86 +- g3w-admin/base/__init__.py | 2 +- .../base/management/commands/set_passwords.py | 2 +- g3w-admin/base/settings/base.py | 3 +- g3w-admin/caching/views.py | 2 +- g3w-admin/core/api/base/views.py | 1 - g3w-admin/core/forms.py | 2 +- g3w-admin/core/mixins/views.py | 5 +- g3w-admin/core/models.py | 12 +- g3w-admin/core/signals.py | 42 +- g3w-admin/core/tests/test_api.py | 2 +- g3w-admin/core/utils/data.py | 2 +- g3w-admin/core/utils/forms.py | 4 +- g3w-admin/core/utils/request.py | 20 + g3w-admin/core/utils/response.py | 21 +- g3w-admin/core/utils/structure.py | 2 +- .../tests/data/editing_test_qgis310.qgs | 1322 ----------- .../tests/data/editing_test_qgis334.qgs | 2071 +++++++++++++++++ g3w-admin/editing/tests/test_models.py | 134 +- g3w-admin/filemanager/filemanager.py | 3 +- g3w-admin/openrouteservice/tests/test_api.py | 33 +- g3w-admin/qdjango/forms/projects.py | 14 +- g3w-admin/qdjango/models/messages.py | 3 + g3w-admin/qdjango/signals.py | 8 +- g3w-admin/qdjango/tests/base.py | 44 +- .../data/geodata/qgis_widget_test_data.gpkg | Bin 122880 -> 122880 bytes g3w-admin/qdjango/tests/test_accesscontrol.py | 7 +- g3w-admin/qdjango/tests/test_api.py | 174 +- g3w-admin/qdjango/tests/test_app.py | 17 +- g3w-admin/qdjango/tests/test_column_acl.py | 82 +- g3w-admin/qdjango/tests/test_constraints.py | 32 +- .../qdjango/tests/test_embedded_layers.py | 51 +- g3w-admin/qdjango/tests/test_ows.py | 68 +- g3w-admin/qdjango/tests/test_ows_postgres.py | 47 +- g3w-admin/qdjango/tests/test_qgisauth.py | 17 +- g3w-admin/qdjango/tests/test_styles_api.py | 37 +- g3w-admin/qdjango/tests/test_theme.py | 29 +- g3w-admin/qdjango/tests/test_utils.py | 24 +- g3w-admin/qdjango/tests/test_validators.py | 60 +- g3w-admin/qdjango/utils/data.py | 6 + g3w-admin/qdjango/utils/exceptions.py | 2 +- g3w-admin/qdjango/utils/validators.py | 24 +- g3w-admin/qplotly/tests/test_api.py | 53 +- g3w-admin/qplotly/tests/test_models.py | 28 +- g3w-admin/qplotly/tests/test_views.py | 17 +- g3w-admin/qtimeseries/tests/base.py | 28 +- g3w-admin/usersmanage/forms.py | 3 +- g3w-admin/usersmanage/signals.py | 2 +- g3w-admin/usersmanage/tests/test_api.py | 1 - g3w-admin/usersmanage/tests/test_utils.py | 1 - g3w-admin/usersmanage/utils.py | 11 +- requirements.txt | 21 +- settings_docker.py | 4 +- 56 files changed, 2710 insertions(+), 1997 deletions(-) create mode 100644 g3w-admin/core/utils/request.py delete mode 100644 g3w-admin/editing/tests/data/editing_test_qgis310.qgs create mode 100644 g3w-admin/editing/tests/data/editing_test_qgis334.qgs diff --git a/README.md b/README.md index 9c9f8bab4..ce2e95205 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ Software releases follow theese main branches as described in the compatibility | Branch | Python | Django | QGIS | [client] | First release | Status | |------------|--------|----------------|---------------|--------------|---------------|----------------| -| [dev] | 3.12 | 3.2 | 3.34 | dev | Unreleased | ⚠️️ Unstable | -| [v.3.9.x] | 3.10 | 3.2 | 3.34 | 3.11.0 | Jan 2025 | New release | +| [dev] | 3.12 | 4.2 | 3.34 | dev | Unreleased | ⚠️️ Unstable | +| [v.3.9.x] | 3.12 | 4.2 | 3.34 | 3.11.0 | Jan 2025 | New release | | [v.3.8.x] | 3.10 | 3.2 | 3.34 | 3.10.3 | Sep 2024 | 🪲️ Bug fixing | | [v.3.7.x] | 3.10 | 3.2 | 3.34 | 3.9.6 | Dec 2023 | 🪲️ Bug fixing | | [v.3.6.x] | 3.10 | 3.2 | 3.28 | 3.8.15 | May 2023 | 🚨 End of Life | @@ -29,6 +29,7 @@ Software releases follow theese main branches as described in the compatibility | [dj22-py3] | 3.6 | 2.2 | [🔗] | | | 🚨 End of Life | | [py2] | 2.7 | 1.11 | [🔗] | | | 🚨 End of Life | + [dev]: https://github.com/g3w-suite/g3w-admin/tree/dev [v.3.8.x]: https://github.com/g3w-suite/g3w-admin/tree/v.3.8.x [v.3.7.x]: https://github.com/g3w-suite/g3w-admin/tree/v.3.7.x diff --git a/docker-compose.latest.yml b/docker-compose.latest.yml index 26ae5d32b..d71c4518b 100644 --- a/docker-compose.latest.yml +++ b/docker-compose.latest.yml @@ -1,13 +1,16 @@ # Use QGIS latest release services: postgis: - image: g3wsuite/postgis:11.0-2.5 + image: kartoza/postgis:16-3.4 ports: - "55432:5432" environment: POSTGRES_USER: docker POSTGRES_PASS: docker - POSTGRES_DBNAME: g3w-suite + POSTGRES_DBNAME: g3w_suite + ALLOW_IP_RANGE: 0.0.0.0/0 + RUN_AS_ROOT: true + FORCE_SSL: False volumes: - shared-volume:/shared-volume diff --git a/docker-compose.ltr.yml b/docker-compose.ltr.yml index 7557c6f81..022547474 100644 --- a/docker-compose.ltr.yml +++ b/docker-compose.ltr.yml @@ -1,12 +1,15 @@ services: postgis: - image: g3wsuite/postgis:11.0-2.5 + image: kartoza/postgis:16-3.4 ports: - - "55432:5432" + - "55432:5432" environment: POSTGRES_USER: docker POSTGRES_PASS: docker - POSTGRES_DBNAME: g3w-suite + POSTGRES_DBNAME: g3w_suite + ALLOW_IP_RANGE: 0.0.0.0/0 + RUN_AS_ROOT: true + FORCE_SSL: False volumes: - shared-volume:/shared-volume diff --git a/g3w-admin/about/tests/test_api.py b/g3w-admin/about/tests/test_api.py index 38792d017..647fc0b69 100644 --- a/g3w-admin/about/tests/test_api.py +++ b/g3w-admin/about/tests/test_api.py @@ -50,87 +50,85 @@ class AboutTestsBase(TestCase): 'G3WGeneralDataSuite.json', ] - @classmethod - def setUpTestData(cls): + def setUp(self): translation.activate(settings.LANGUAGE_CODE[:2]) # Admin level 1 - cls.test_user_admin1 = User.objects.create_user(username='admin01', password='admin01') - cls.test_user_admin1.is_superuser = True - cls.test_user_admin1.save() + self.test_user_admin1 = User.objects.create_user(username='admin01', password='admin01') + self.test_user_admin1.is_superuser = True + self.test_user_admin1.save() # Editor level 1 - cls.test_user1 = User.objects.create_user(username='user01', password='user01') - cls.group = UserGroup.objects.get(name='Editor Level 1') - cls.test_user1.groups.add(cls.group) - cls.test_user1.save() + self.test_user1 = User.objects.create_user(username='user01', password='user01') + self.group = UserGroup.objects.get(name='Editor Level 1') + self.test_user1.groups.add(self.group) + self.test_user1.save() # Editor level 2 - cls.test_user2 = User.objects.create_user(username='user02', password='user02') - cls.group = UserGroup.objects.get(name='Editor Level 2') - cls.test_user2.groups.add(cls.group) - cls.test_user2.save() + self.test_user2 = User.objects.create_user(username='user02', password='user02') + self.group = UserGroup.objects.get(name='Editor Level 2') + self.test_user2.groups.add(self.group) + self.test_user2.save() - cls.test_user3 = User.objects.create_user(username='user03', password='user03') - cls.group = UserGroup.objects.get(name='Viewer Level 1') - cls.test_user3.groups.add(cls.group) - cls.test_user3.save() + self.test_user3 = User.objects.create_user(username='user03', password='user03') + self.group = UserGroup.objects.get(name='Viewer Level 1') + self.test_user3.groups.add(self.group) + self.test_user3.save() - cls.test_user4 = User.objects.create_user(username='user04', password='user04') - cls.test_user4.groups.add(cls.group) - cls.test_user4.save() + self.test_user4 = User.objects.create_user(username='user04', password='user04') + self.test_user4.groups.add(self.group) + self.test_user4.save() - cls.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', + self.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group.save() - cls.project_group.addPermissionsToEditor(cls.test_user2) + self.project_group.save() + self.project_group.addPermissionsToEditor(self.test_user2) - cls.project_group2 = CoreGroup(name='Group2', title='Group2', header_logo_img='', + self.project_group2 = CoreGroup(name='Group2', title='Group2', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group2.save() + self.project_group2.save() - cls.project_group3 = CoreGroup(name='Group3', title='Group3', header_logo_img='', + self.project_group3 = CoreGroup(name='Group3', title='Group3', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=3857)) - cls.project_group3.save() + self.project_group3.save() # create macrogroups - cls.macrogroup = MacroGroup(title='Macrogroup1', logo_img='macrogroup.png') - cls.macrogroup.save() - cls.project_group2.macrogroups.add(cls.macrogroup) - cls.project_group.macrogroups.add(cls.macrogroup) + self.macrogroup = MacroGroup(title='Macrogroup1', logo_img='macrogroup.png') + self.macrogroup.save() + self.project_group2.macrogroups.add(self.macrogroup) + self.project_group.macrogroups.add(self.macrogroup) # create macrogroups 2 - cls.macrogroup2 = MacroGroup(title='Macrogroup2', logo_img='macrogroup2.png') - cls.macrogroup2.save() - cls.project_group.macrogroups.add(cls.macrogroup2) + self.macrogroup2 = MacroGroup(title='Macrogroup2', logo_img='macrogroup2.png') + self.macrogroup2.save() + self.project_group.macrogroups.add(self.macrogroup2) # add permission to anonymous and viewer - cls.project_group2.addPermissionsToViewers(users_id=[cls.test_user3.pk, get_user_model().get_anonymous().pk]) + self.project_group2.addPermissionsToViewers(users_id=[self.test_user3.pk, get_user_model().get_anonymous().pk]) #projects qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE), 'r')) - cls.project = QgisProject(qgis_project_file) - cls.project.title = 'A project' - cls.project.group = cls.project_group - cls.project.save() + self.project = QgisProject(qgis_project_file) + self.project.title = 'A project' + self.project.group = self.project_group + self.project.save() # projects qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE_2), 'r')) - cls.project2 = QgisProject(qgis_project_file) - cls.project2.group = cls.project_group - cls.project2.save() + self.project2 = QgisProject(qgis_project_file) + self.project2.group = self.project_group + self.project2.save() # add permission to anonumous and viewer - cls.project.instance.addPermissionsToViewers([cls.test_user3.pk]) + self.project.instance.addPermissionsToViewers([self.test_user3.pk]) @classmethod def tearDownClass(cls): """Cleanup """ - # Cleanup super(AboutTestsBase, cls).tearDownClass() diff --git a/g3w-admin/base/__init__.py b/g3w-admin/base/__init__.py index 53eafbc4c..43cae6022 100644 --- a/g3w-admin/base/__init__.py +++ b/g3w-admin/base/__init__.py @@ -13,4 +13,4 @@ logger.warning('Celery could not be imported, this might be ok if there are no custom suite modules that require Celery') -__version__ = (3, 8, 0, 'unstable', 0) +__version__ = (3, 9, 0, 'unstable', 0) diff --git a/g3w-admin/base/management/commands/set_passwords.py b/g3w-admin/base/management/commands/set_passwords.py index e7a066f31..f3901726f 100644 --- a/g3w-admin/base/management/commands/set_passwords.py +++ b/g3w-admin/base/management/commands/set_passwords.py @@ -18,7 +18,7 @@ class Command(BaseCommand): help = 'DEBUG only: sets all user passwords to a common value ("%s" by default)' % (DEFAULT_FAKE_PASSWORD, ) - requires_system_checks = False + requires_system_checks = [] def add_arguments(self, parser): super(Command, self).add_arguments(parser) diff --git a/g3w-admin/base/settings/base.py b/g3w-admin/base/settings/base.py index 554afc9a9..9b4426899 100644 --- a/g3w-admin/base/settings/base.py +++ b/g3w-admin/base/settings/base.py @@ -57,6 +57,7 @@ 'model_utils', 'formtools', 'crispy_forms', + 'crispy_bootstrap3', 'guardian', 'sitetree', 'django_extensions', @@ -172,6 +173,7 @@ GUARDIAN_RAISE_403 = True +CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap3" CRISPY_TEMPLATE_PACK = 'bootstrap3' SITETREE_MODEL_TREE = 'core.G3W2Tree' @@ -194,7 +196,6 @@ USE_I18N = True -USE_L10N = True USE_TZ = False diff --git a/g3w-admin/caching/views.py b/g3w-admin/caching/views.py index 9bdf0262f..4c84dc818 100644 --- a/g3w-admin/caching/views.py +++ b/g3w-admin/caching/views.py @@ -4,7 +4,7 @@ from django.http import HttpResponse, JsonResponse from django.db import transaction from django.urls import reverse -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext_lazy as _ from django.utils.decorators import method_decorator import TileStache from rest_framework.views import APIView diff --git a/g3w-admin/core/api/base/views.py b/g3w-admin/core/api/base/views.py index c9f2391d7..95c6f58bb 100644 --- a/g3w-admin/core/api/base/views.py +++ b/g3w-admin/core/api/base/views.py @@ -4,7 +4,6 @@ from django.core.exceptions import PermissionDenied from django.http import Http404, HttpRequest from django.urls import resolve, reverse -from django.utils.translation import ugettext from django.utils.translation import gettext_lazy as _ from qgis.core import ( QgsJsonExporter, diff --git a/g3w-admin/core/forms.py b/g3w-admin/core/forms.py index 388825fd3..cc462bdf1 100644 --- a/g3w-admin/core/forms.py +++ b/g3w-admin/core/forms.py @@ -3,7 +3,7 @@ from django.forms.fields import CharField, HiddenInput from django.forms.models import ModelMultipleChoiceField, ModelChoiceField from django.db.models import Q -from django.utils.translation import ugettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from core.models import Group, GeneralSuiteData, MacroGroup from django_file_form.forms import FileFormMixin from django.contrib.auth.models import User, Group as AuthGroup diff --git a/g3w-admin/core/mixins/views.py b/g3w-admin/core/mixins/views.py index 566a53a45..bf3db1b54 100644 --- a/g3w-admin/core/mixins/views.py +++ b/g3w-admin/core/mixins/views.py @@ -6,6 +6,7 @@ from django.shortcuts import get_object_or_404 from core.models import Group from core.utils import file_path_mime +from core.utils.request import is_ajax import os @@ -112,7 +113,7 @@ class AjaxableFormResponseMixin(object): """ def form_invalid(self, form): response = super(AjaxableFormResponseMixin, self).form_invalid(form) - if self.request.is_ajax(): + if is_ajax(self.request): return JsonResponse({'status':'error', 'errors_form': form.errors}) else: return response @@ -122,7 +123,7 @@ def form_valid(self, form): # it might do some processing (in the case of CreateView, it will # call form.save() for example). response = super(AjaxableFormResponseMixin, self).form_valid(form) - if self.request.is_ajax(): + if is_ajax(self.request): return JsonResponse({'status': 'ok', 'message': 'Object saved!'}) else: return response diff --git a/g3w-admin/core/models.py b/g3w-admin/core/models.py index 39f0c7aff..2b509b18c 100644 --- a/g3w-admin/core/models.py +++ b/g3w-admin/core/models.py @@ -1,16 +1,13 @@ from django.conf import settings -from django.conf.global_settings import LANGUAGES -from django.utils.translation import ugettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.urls import reverse from django.db import models from django.apps import apps -from django_extensions.db.fields import AutoSlugField from guardian.shortcuts import get_objects_for_user from guardian.compat import get_user_model from ordered_model.models import OrderedModel from model_utils.models import TimeStampedModel -from model_utils import Choices from django_extensions.db.fields import AutoSlugField from sitetree.models import TreeItemBase, TreeBase from django.contrib.auth.models import User, Group as AuthGroup @@ -124,6 +121,9 @@ def remove_permissions_to_editors(self, users_id): """ self._permissions_to_editors(users_id, 'remove') + class Meta(): + ordering = ("order",) + class Group(TimeStampedModel, OrderedModel): """A group of projects.""" @@ -169,10 +169,12 @@ class Group(TimeStampedModel, OrderedModel): 'as client logo, if MacroGroup option is active this options takes ' 'precendence')) - class Meta: + class Meta(): permissions = ( ('add_project_to_group', 'Can add project to the group'), ) + ordering = ("order",) + def __str__(self): return self.name diff --git a/g3w-admin/core/signals.py b/g3w-admin/core/signals.py index 3ba29cf4d..07dfda53a 100644 --- a/g3w-admin/core/signals.py +++ b/g3w-admin/core/signals.py @@ -2,13 +2,13 @@ # signal for start plugin: i.e. iternet # data plugin to config api client from modules -initconfig_plugin_start = django.dispatch.Signal(providing_args=["projectType", "project"]) +initconfig_plugin_start = django.dispatch.Signal() # signal to add extra maplayers attribute/modify maplayer attributes -post_create_maplayerattributes = django.dispatch.Signal(providing_args=["layer", "vector_params"]) +post_create_maplayerattributes = django.dispatch.Signal() # signal to add extra maplayers attribute -post_save_maplayer = django.dispatch.Signal(providing_args=["layer", "mode", "data", "user"]) +post_save_maplayer = django.dispatch.Signal() """Signal sent before edited features are sent to the backend for saving. Listeners, should perform any validation and raise a validation error in case of failure. @@ -19,47 +19,47 @@ data: the feature being edited/added user: current user from the request """ -pre_save_maplayer = django.dispatch.Signal(providing_args=["layer_metadata", "mode", "data", "user"]) +pre_save_maplayer = django.dispatch.Signal() # signal to add extra maplayers attribute: i.e. iternet -pre_delete_maplayer = django.dispatch.Signal(providing_args=["layer", "data", "user"]) +pre_delete_maplayer = django.dispatch.Signal() # signal to add extra maplayers attribute: i.e. iternet -post_serialize_maplayer = django.dispatch.Signal(providing_args=["layer", "data"]) +post_serialize_maplayer = django.dispatch.Signal() # signal after add/update map group -after_update_group = django.dispatch.Signal(providing_args=["group"]) +after_update_group = django.dispatch.Signal() # signal after project serialization -post_serialize_project = django.dispatch.Signal(providing_args=["app_name", "request"]) +post_serialize_project = django.dispatch.Signal() # signal after layer serialized data on /api/config/ # send layer seralized original object and came back only dict data changed -after_serialized_project_layer = django.dispatch.Signal(providing_args=["layer", "request"]) +after_serialized_project_layer = django.dispatch.Signal() # signals pre update project -pre_update_project = django.dispatch.Signal(providing_args=["projectType", "project"]) +pre_update_project = django.dispatch.Signal() # signals before delete project -before_delete_project = django.dispatch.Signal(providing_args=["app_name", "project"]) +before_delete_project = django.dispatch.Signal() # signals pre delete project -pre_delete_project = django.dispatch.Signal(providing_args=["projectType", "project", "projects"]) +pre_delete_project = django.dispatch.Signal() # signal post project delete -post_delete_project = django.dispatch.Signal(providing_args=["projectType", "project", "projects"]) +post_delete_project = django.dispatch.Signal() # signal after add/update project -after_update_project = django.dispatch.Signal(providing_args=["app_name", "project"]) +after_update_project = django.dispatch.Signal() # signal to load widgets for project -load_project_widgets = django.dispatch.Signal(providing_args=["app_name", "project"]) +load_project_widgets = django.dispatch.Signal() # signal to load actions for layer -load_layer_actions = django.dispatch.Signal(providing_args=["app_name", "layer"]) +load_layer_actions = django.dispatch.Signal() # signal send to perform search by specific module -perform_client_search = django.dispatch.Signal(providing_args=["app_name", "project_id", "widget_id"]) +perform_client_search = django.dispatch.Signal() # signal to load specific css from module and submodules load_css_modules = django.dispatch.Signal() @@ -68,10 +68,10 @@ load_js_modules = django.dispatch.Signal() # signal to load widget into dashboard -load_dashboard_widgets = django.dispatch.Signal(providing_args=["app_name"]) +load_dashboard_widgets = django.dispatch.Signal() # signal send before to show user_data, return permissions by backend -pre_show_user_data = django.dispatch.Signal(providing_args=["user"]) +pre_show_user_data = django.dispatch.Signal() # signal send to load main navbar items load_navbar_items = django.dispatch.Signal() @@ -80,9 +80,9 @@ before_return_vector_data_layer = django.dispatch.Signal() # signal send for execute model searches. -execute_search_on_models = django.dispatch.Signal(providing_args=['request', 'search_text']) +execute_search_on_models = django.dispatch.Signal() # signal to load actions for project layers pages -load_project_layers_actions = django.dispatch.Signal(providing_args=["app_name", "project"]) +load_project_layers_actions = django.dispatch.Signal() diff --git a/g3w-admin/core/tests/test_api.py b/g3w-admin/core/tests/test_api.py index a9a0deb4a..dc282ca5e 100644 --- a/g3w-admin/core/tests/test_api.py +++ b/g3w-admin/core/tests/test_api.py @@ -520,7 +520,7 @@ def testCoreInterfaceProxyView(self): self.assertEqual(res.status_code, 200) data = { - 'url': 'https://gis3w.it', + 'url': 'https://g3wsuite.it', 'method': 'post', 'params': { 'search': 'pippo' diff --git a/g3w-admin/core/utils/data.py b/g3w-admin/core/utils/data.py index 6c4a24a23..ae38993d0 100644 --- a/g3w-admin/core/utils/data.py +++ b/g3w-admin/core/utils/data.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from .general import ucfirst import re diff --git a/g3w-admin/core/utils/forms.py b/g3w-admin/core/utils/forms.py index 44b1968ea..d1b58978a 100644 --- a/g3w-admin/core/utils/forms.py +++ b/g3w-admin/core/utils/forms.py @@ -1,6 +1,4 @@ -from PIL import Image -from django.forms import ValidationError -from django.utils.translation import ugettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from crispy_forms.layout import Div, HTML, Field from usersmanage.utils import userHasGroups from usersmanage.configs import G3W_EDITOR1 diff --git a/g3w-admin/core/utils/request.py b/g3w-admin/core/utils/request.py new file mode 100644 index 000000000..21d5695c4 --- /dev/null +++ b/g3w-admin/core/utils/request.py @@ -0,0 +1,20 @@ +# coding=utf-8 +"""" +Utilities for django request instance +.. note:: This program is free software; you can redistribute it and/or modify + it under the terms of the Mozilla Public License 2.0. + +""" + +__author__ = 'lorenzetti@gis3w.it' +__date__ = '2024-12-30' +__copyright__ = 'Copyright 2015 - 2024, Gis3w' +__license__ = 'MPL 2.0' + +def is_ajax(request): + """ + Check if request is ajax + :param request: django request instance + :return: True if request is ajax, False otherwise + """ + return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' diff --git a/g3w-admin/core/utils/response.py b/g3w-admin/core/utils/response.py index 0204881b6..90bdb9efe 100644 --- a/g3w-admin/core/utils/response.py +++ b/g3w-admin/core/utils/response.py @@ -15,23 +15,4 @@ def send_file(output_filename, content_type, file, attachment=True): :param attachment: True default, to set Content-Disposition http header. :return: Django HttpResponse instance. """ - return FileResponse(open(file, 'rb'), filename=output_filename, as_attachment=attachment) - - -# class G3WFileFormUploadBackend(FileFormUploadBackend): -# """ Extend default upload backend class of django-file-form module """ -# -# def update_filename(self, request, filename, *args, **kwargs): -# """ Update filename to save on host, if an extension exist it is added to new hash name file """ -# -# hh = super().update_filename(request, filename, *args, **kwargs) -# -# # Add file extension: -# ext = os.path.splitext(filename) -# if ext[1]: -# hh += ext[1] -# -# if ext[1][1:].lower() not in settings.G3WFILE_FORM_UPLOAD_FORMATS: -# raise PermissionDenied() -# -# return hh + return FileResponse(open(file, 'rb'), filename=output_filename, as_attachment=attachment) \ No newline at end of file diff --git a/g3w-admin/core/utils/structure.py b/g3w-admin/core/utils/structure.py index 847ce6050..5c693ad6e 100644 --- a/g3w-admin/core/utils/structure.py +++ b/g3w-admin/core/utils/structure.py @@ -1,7 +1,7 @@ from django.conf import settings from django.apps import apps from django.urls import reverse -from django.utils.translation import ugettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from qdjango.utils.qgis import explode_expression from collections import OrderedDict diff --git a/g3w-admin/editing/tests/data/editing_test_qgis310.qgs b/g3w-admin/editing/tests/data/editing_test_qgis310.qgs deleted file mode 100644 index 52d0f51ec..000000000 --- a/g3w-admin/editing/tests/data/editing_test_qgis310.qgs +++ /dev/null @@ -1,1322 +0,0 @@ - - - - editing_test - - - - - - GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] - +proj=longlat +datum=WGS84 +no_defs - 3452 - 4326 - EPSG:4326 - WGS 84 - longlat - WGS84 - true - - - - - - - - - - - - - - - rivers_ec97a7c6_e390_4453_a410_f39843596012 - countries_63e59c18_a1d0_4e25_968a_ccbaecd11725 - cities_54d40b01_2af8_4b17_8495_c5833485536e - - - - - - - - - - - - degrees - - -5.75647150000001062 - 35.00312094999999601 - 20.04162950000001686 - 55.54473504999994304 - - 0 - - - GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] - +proj=longlat +datum=WGS84 +no_defs - 3452 - 4326 - EPSG:4326 - WGS 84 - longlat - WGS84 - true - - - 0 - - - - - - - - - - - - - - - - - - - - 8.88083699999999965 - 42.40723200000000048 - 13.44107799999999919 - 46.01007784502829878 - - cities_54d40b01_2af8_4b17_8495_c5833485536e - dbname='../data/editing_test.db' table="cities" (geometry) sql= - - - - cities - - - GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] - +proj=longlat +datum=WGS84 +no_defs - 3452 - 4326 - EPSG:4326 - WGS 84 - longlat - WGS84 - true - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - - false - - - - - - - - - - - - - spatialite - - - - - - - - - - - - - 1 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - geonameid - "geonameid" - - - - - - 0 - 0 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - generatedlayout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - geonameid - - - - - -5.14223100000000954 - 35.4922069999999934 - 19.42738900000000513 - 55.05564899999998829 - - countries_63e59c18_a1d0_4e25_968a_ccbaecd11725 - dbname='../data/editing_test.db' table="countries" (geometry) sql= - - - - countries - - - GEOGCS["Unknown datum based upon the WGS 84 ellipsoid",DATUM["Not_specified_based_on_WGS_84_ellipsoid",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6030"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4030"]] - +proj=longlat +ellps=WGS84 +no_defs - 3239 - 4030 - EPSG:4030 - Unknown datum based upon the WGS 84 ellipsoid - longlat - WGS84 - true - - - - - - - - - - - - - - - - - 0 - 0 - - - - - false - - - - - spatialite - - - - - - - - - - - 1 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - generatedlayout - - - - "name_local" - - - - - 7.07773409230401018 - 41.02184299999998984 - 18.93406205412870591 - 46.83325600000000577 - - rivers_ec97a7c6_e390_4453_a410_f39843596012 - dbname='../data/editing_test.db' table="rivers" (geometry) sql= - - - - rivers - - - GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]] - +proj=longlat +datum=WGS84 +no_defs - 3452 - 4326 - EPSG:4326 - WGS 84 - longlat - WGS84 - true - - - - - - - - - - - - - - - - - 0 - 0 - - - - - false - - - - - spatialite - - - - - - - - - - - 1 - 1 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - 0 - 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - generatedlayout - - - - - - - - - - - - - - - - - - - 1 - true - - - 2 - - - 255 - 255 - 255 - 255 - 0 - 255 - 255 - - - false - - - - - - EPSG:7030 - - - m2 - meters - - - 50 - 5 - 16 - 30 - 2.5 - false - false - 0 - 0 - false - false - true - 0 - 255,0,0,255 - - - false - - - true - 2 - MU - - - 1 - - - - - - - - - - - None - false - - - - - - 1 - - -0.87774635968768777 - 35.94447613939637876 - 26.50871809721871131 - 51.07642868851524298 - - conditions unknown - 90 - - - - 1 - - 8 - - - - false - - false - - 0 - - false - - - - - - - - false - - - - - false - - 5000 - - - - false - - - - - - - - - - - editing_test - - - - - - - - - - - - Walter Lorenetti - 2020-03-16T16:31:28 - - - - - - - - diff --git a/g3w-admin/editing/tests/data/editing_test_qgis334.qgs b/g3w-admin/editing/tests/data/editing_test_qgis334.qgs new file mode 100644 index 000000000..b82ff6c03 --- /dev/null +++ b/g3w-admin/editing/tests/data/editing_test_qgis334.qgs @@ -0,0 +1,2071 @@ + + + + editing_test + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + rivers_ec97a7c6_e390_4453_a410_f39843596012 + countries_63e59c18_a1d0_4e25_968a_ccbaecd11725 + cities_54d40b01_2af8_4b17_8495_c5833485536e + + + + + + + + + + + + + degrees + + -5.75647150000001062 + 35.00312094999999601 + 20.04162950000001686 + 55.54473504999994304 + + 0 + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + 0 + + + + + + + + + + + + + + + + + Annotations_82e32697_04fc_4e3b_9178_f7f2a5fe15ca + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + 1 + 1 + 1 + 0 + + + + 1 + 0 + + + + + + 8.88083699999999965 + 42.40723200000000048 + 13.44107799999999919 + 46.01007784502829878 + + + 8.88083699999999965 + 42.40723200000000048 + 13.44107799999999919 + 46.01007784502829878 + + cities_54d40b01_2af8_4b17_8495_c5833485536e + dbname='../data/editing_test.db' table="cities" (geometry) + + + + cities + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + spatialite + + + + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + geonameid + + + + + -5.14223100000000954 + 35.4922069999999934 + 19.42738900000000513 + 55.05564899999998829 + + + -5.14223100000000954 + 35.4922069999999934 + 19.42738900000001578 + 55.05564899999994566 + + countries_63e59c18_a1d0_4e25_968a_ccbaecd11725 + dbname='../data/editing_test.db' table="countries" (geometry) + + + + countries + + + GEOGCRS["Unknown datum based upon the WGS 84 ellipsoid",DATUM["Not specified (based on WGS 84 ellipsoid)",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Not recommended."],AREA["Not specified."],BBOX[-90,-180,90,180]],ID["EPSG",4030]] + +proj=longlat +ellps=WGS84 +no_defs + 3239 + 4030 + EPSG:4030 + Unknown datum based upon the WGS 84 ellipsoid + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + spatialite + + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + "name_local" + + + + + 7.07773409230401018 + 41.02184299999998984 + 18.93406205412870591 + 46.83325600000000577 + + + 7.07773409230401018 + 41.02184299999998984 + 18.93406205412870591 + 46.83325600000000577 + + rivers_ec97a7c6_e390_4453_a410_f39843596012 + dbname='../data/editing_test.db' table="rivers" (geometry) + + + + rivers + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + spatialite + + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + + + + + + + + + + + + + 2 + + + 255 + 255 + 255 + 255 + 0 + 255 + 255 + + + false + + + + + + EPSG:7030 + + + m2 + meters + + + 0 + + 0 + 1 + + 0 + + + 50 + 5 + 16 + 30 + 2.5 + false + false + false + 0 + 0 + false + false + true + 0 + 255,0,0,255 + + + false + + + true + 2 + MU + + false + + 1 + + + + + + + + + + + None + false + false + + + + + + 1 + + -0.87774635999999995 + 35.94447613900000249 + 26.50871809699999915 + 51.07642868899999655 + + false + conditions unknown + 90 + + + + 1 + + 8 + + + + false + + false + + 0 + + false + + + + + + + + false + + + + + false + + 5000 + + + + false + + + + + + + + + + + + + + editing_test + + + + + + + + + + + + + + + Walter Lorenetti + 2020-03-16T16:31:28 + + + + + + + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + + + + GEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + diff --git a/g3w-admin/editing/tests/test_models.py b/g3w-admin/editing/tests/test_models.py index dbcea9939..36c82439b 100644 --- a/g3w-admin/editing/tests/test_models.py +++ b/g3w-admin/editing/tests/test_models.py @@ -42,7 +42,7 @@ QGS_FILE = 'constraints_test_project.qgs' QGS_EDITING_DB = 'editing_test.db' QGS_EDITING_DB_BACKUP = 'editing_test_backup.db' -QGS_EDITING_FILE = 'editing_test_qgis310.qgs' +QGS_EDITING_FILE = 'editing_test_qgis334.qgs' QGS_LOGGING_FILE = 'logging_test_project.qgs' QGS_LOGGING_DB = 'logging_test.db' QGS_LOGGING_DB_BACKUP = 'logging_test_backup.db' @@ -77,11 +77,6 @@ class ConstraintsTestsBase(TestCase): databases = '__all__' - def setUp(self): - """Restore test database""" - - self.reset_db_data() - @classmethod def reset_db_data(cls): """ @@ -103,8 +98,14 @@ def reset_db_data(cls): shutil.copy('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_EDITING_CASCADE_RELATIONS_DB_BACKUP), '{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_EDITING_CASCADE_RELATIONS_DB)) - @classmethod - def setUpTestData(cls): + + def setUp(self): + ''' + From django 4.2: Support for assigning objects which don’t support creating deep copies with copy.deepcopy() + to class attributes in TestCase.setUpTestData() is removed. + + So setUpTestData is changed in setUp calss method + ''' call_command('loaddata', 'BaseLayer.json', '--database=default', verbosity=0) @@ -116,118 +117,118 @@ def setUpTestData(cls): '--database=default', verbosity=0) # Make a copy of the test project's databases - cls.reset_db_data() + self.reset_db_data() # Admin level 1 - cls.test_user_admin1 = User.objects.create_user( + self.test_user_admin1 = User.objects.create_user( username='admin01', password='admin01') - cls.test_user_admin1.is_superuser = True - cls.test_user_admin1.save() + self.test_user_admin1.is_superuser = True + self.test_user_admin1.save() # Editor level 1 - cls.test_user1 = User.objects.create_user( + self.test_user1 = User.objects.create_user( username='user01', password='user01') - cls.group = UserGroup.objects.get(name='Editor Level 1') - cls.test_user1.groups.add(cls.group) - cls.test_user1.save() + self.group = UserGroup.objects.get(name='Editor Level 1') + self.test_user1.groups.add(self.group) + self.test_user1.save() # Editor level 2 - cls.test_user2 = User.objects.create_user( + self.test_user2 = User.objects.create_user( username='user02', password='user02') - cls.group = UserGroup.objects.get(name='Editor Level 2') - cls.test_user2.groups.add(cls.group) - cls.test_user2.save() + self.group = UserGroup.objects.get(name='Editor Level 2') + self.test_user2.groups.add(self.group) + self.test_user2.save() - cls.test_user3 = User.objects.create_user( + self.test_user3 = User.objects.create_user( username='user03', password='user03') - cls.group = UserGroup.objects.get(name='Viewer Level 1') - cls.test_user3.groups.add(cls.group) - cls.test_user3.save() + self.group = UserGroup.objects.get(name='Viewer Level 1') + self.test_user3.groups.add(self.group) + self.test_user3.save() - cls.test_user4 = User.objects.create_user( + self.test_user4 = User.objects.create_user( username='user04', password='user04') - cls.test_user4.groups.add(cls.group) + self.test_user4.groups.add(self.group) - cls.test_user5 = User.objects.create_user( + self.test_user5 = User.objects.create_user( username='user05', password='user05') - cls.test_user5.groups.add(cls.group) + self.test_user5.groups.add(self.group) # Create a user_group - cls.test_user_group1 = UserGroup.objects.create(name='Viewer user group1') - GroupRole(group=cls.test_user_group1, role='viewer').save() - cls.test_user4.groups.add(cls.test_user_group1) + self.test_user_group1 = UserGroup.objects.create(name='Viewer user group1') + GroupRole(group=self.test_user_group1, role='viewer').save() + self.test_user4.groups.add(self.test_user_group1) - cls.test_user_group2 = UserGroup.objects.create(name='Viewer user group2') - GroupRole(group=cls.test_user_group2, role='viewer').save() - cls.test_user4.groups.add(cls.test_user_group2) + self.test_user_group2 = UserGroup.objects.create(name='Viewer user group2') + GroupRole(group=self.test_user_group2, role='viewer').save() + self.test_user4.groups.add(self.test_user_group2) - cls.test_user_group3 = UserGroup.objects.create(name='Viewer user group3') - GroupRole(group=cls.test_user_group3, role='viewer').save() - cls.test_user4.groups.add(cls.test_user_group3) + self.test_user_group3 = UserGroup.objects.create(name='Viewer user group3') + GroupRole(group=self.test_user_group3, role='viewer').save() + self.test_user4.groups.add(self.test_user_group3) - cls.project_group = CoreGroup( + self.project_group = CoreGroup( name='Group1', title='Group1', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group.save() - cls.project_group.addPermissionsToEditor(cls.test_user2) + self.project_group.save() + self.project_group.addPermissionsToEditor(self.test_user2) qgis_project_file = File(open('{}{}{}'.format( CURRENT_PATH, TEST_BASE_PATH, QGS_FILE), 'r', encoding='UTF8')) - cls.project = QgisProject(qgis_project_file) - cls.project.title = 'A project' - cls.project.group = cls.project_group - cls.project.save() + self.project = QgisProject(qgis_project_file) + self.project.title = 'A project' + self.project.group = self.project_group + self.project.save() # give permission on project and layer - cls.project.instance.addPermissionsToEditor(cls.test_user2) - cls.project.instance.addPermissionsToViewers([cls.test_user3.pk]) - cls.editing_layer = cls.project.instance.layer_set.get( + self.project.instance.addPermissionsToEditor(self.test_user2) + self.project.instance.addPermissionsToViewers([self.test_user3.pk]) + self.editing_layer = self.project.instance.layer_set.get( name='editing_layer') setPermissionUserObject( - cls.test_user3, cls.editing_layer, ['change_layer']) - setPermissionUserObject(cls.group, cls.editing_layer, ['change_layer']) + self.test_user3, self.editing_layer, ['change_layer']) + setPermissionUserObject(self.group, self.editing_layer, ['change_layer']) qgis_project_file.close() # load QGIS editing project qgis_project_file = File(open('{}{}{}'.format( CURRENT_PATH, TEST_BASE_PATH, QGS_EDITING_FILE), 'r', encoding='UTF8')) - cls.editing_project = QgisProject(qgis_project_file) - cls.editing_project.group = cls.project_group - cls.editing_project.save() + self.editing_project = QgisProject(qgis_project_file) + self.editing_project.group = self.project_group + self.editing_project.save() qgis_project_file.close() # load QGIS LOGGING project - cls.project_logging_group = CoreGroup( + self.project_logging_group = CoreGroup( name='GroupLogging', title='GroupLogging', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=3857)) - cls.project_logging_group.save() + self.project_logging_group.save() qgis_project_file = File(open('{}{}{}'.format( CURRENT_PATH, TEST_BASE_PATH, QGS_LOGGING_FILE), 'r', encoding='UTF8')) - cls.logging_project = QgisProject(qgis_project_file) - cls.logging_project.group = cls.project_logging_group - cls.logging_project.save() + self.logging_project = QgisProject(qgis_project_file) + self.logging_project.group = self.project_logging_group + self.logging_project.save() qgis_project_file.close() # load QGIS editing provider default data project qgis_project_file = File(open('{}{}{}'.format( CURRENT_PATH, TEST_BASE_PATH, QGS_EDITING_PROVIDER_DEFAULT_VALUE_FILE), 'r', encoding='UTF8')) - cls.editing_provider_default_value_project = QgisProject(qgis_project_file) - cls.editing_provider_default_value_project.group = cls.project_group - cls.editing_provider_default_value_project.save() + self.editing_provider_default_value_project = QgisProject(qgis_project_file) + self.editing_provider_default_value_project.group = self.project_group + self.editing_provider_default_value_project.save() qgis_project_file.close() - cls.project_group_3857= CoreGroup( + self.project_group_3857= CoreGroup( name='Group3857', title='Group3857', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=3857)) - cls.project_group_3857.save() + self.project_group_3857.save() qgis_project_file = File(open('{}{}{}'.format( CURRENT_PATH, TEST_BASE_PATH, QGS_EDITING_CASCADE_RELATIONS_FILE), 'r', encoding='UTF8')) - cls.editing_cascade_relations_project = QgisProject(qgis_project_file) - cls.editing_cascade_relations_project.group = cls.project_group_3857 - cls.editing_cascade_relations_project.save() + self.editing_cascade_relations_project = QgisProject(qgis_project_file) + self.editing_cascade_relations_project.group = self.project_group_3857 + self.editing_cascade_relations_project.save() qgis_project_file.close() def tearDown(self): @@ -253,6 +254,7 @@ class ConstraintsModelTestsBase(ConstraintsTestsBase): """Constraints model tests""" def setUp(self): + super().setUp() self.constraint_layer_name = 'constraint_layer' def test_create_constraint(self): @@ -606,4 +608,6 @@ class ConstraintsModelTestsMulti(ConstraintsModelTestsBase): """Constraints model tests""" def setUp(self): + + super().setUp() self.constraint_layer_name = 'constraint_layer_multi' diff --git a/g3w-admin/filemanager/filemanager.py b/g3w-admin/filemanager/filemanager.py index aaea0f70d..859560b5c 100644 --- a/g3w-admin/filemanager/filemanager.py +++ b/g3w-admin/filemanager/filemanager.py @@ -5,6 +5,7 @@ from django.core.files.storage import default_storage, FileSystemStorage from django.core.files.base import ContentFile from core.utils.response import send_file +from core.utils.request import is_ajax from qdjango.utils.storage import OverwriteStorage from .filemanagerresponse import FileManagerResponse import os @@ -309,7 +310,7 @@ def download(self): parts = file.split('/') filename = parts.pop() # Check for AJAX request - if self.request.is_ajax(): + if is_ajax(self.request): response = FileManagerResponse(path, root=self.root) response.set_response() return JsonResponse(response.response) diff --git a/g3w-admin/openrouteservice/tests/test_api.py b/g3w-admin/openrouteservice/tests/test_api.py index ad9ffbd52..d527f9d58 100644 --- a/g3w-admin/openrouteservice/tests/test_api.py +++ b/g3w-admin/openrouteservice/tests/test_api.py @@ -149,20 +149,19 @@ def _get_vcr(self, **kwargs): myvcr.record_mode = RecordMode.NEW_EPISODES return myvcr - @classmethod - def setUpTestData(cls): + def setUp(self): - super().setUpTestData() + super().setUp() - cls.temp_dir = QTemporaryDir() - cls.temp_project_path = os.path.join( - cls.temp_dir.path(), 'pg_openrouteservice.qgs') + self.temp_dir = QTemporaryDir() + self.temp_project_path = os.path.join( + self.temp_dir.path(), 'pg_openrouteservice.qgs') # Create test layer conn_str = "dbname='{NAME}' host={HOST} port={PORT} user='{USER}' password='{PASSWORD}' sslmode=disable".format( **settings.DATABASES['default']) - cls.conn_uri = conn_str + self.conn_uri = conn_str md = QgsProviderRegistry.instance().providerMetadata('postgres') @@ -201,7 +200,7 @@ def setUpTestData(cls): ('SRID=3857;POINT (-8637126.514460787 4512741.157169087)'::geometry), ('SRID=3857;POINT (-8634109.572919691 4503916.603161385)'::geometry)""") - cls.layer_specs = {} + self.layer_specs = {} project = QgsProject() @@ -217,19 +216,19 @@ def setUpTestData(cls): table_name=table_name, geometry_type=table_spec[0], srid=table_spec[1]) layer = QgsVectorLayer(layer_uri, table_name, 'postgres') assert layer.isValid() - cls.layer_specs[table_name] = layer_uri + self.layer_specs[table_name] = layer_uri project.addMapLayers([layer]) - assert project.write(cls.temp_project_path) + assert project.write(self.temp_project_path) Project.objects.filter( title='Test openrouteservice project').delete() toc = buildLayerTreeNodeObject(project.layerTreeRoot()) - cls.qdjango_project = Project( - qgis_file=File(open(cls.temp_project_path, 'r')), title='Test openrouteservice project', group=cls.project_group, layers_tree=toc) - cls.qdjango_project.save() + self.qdjango_project = Project( + qgis_file=File(open(self.temp_project_path, 'r')), title='Test openrouteservice project', group=self.project_group, layers_tree=toc) + self.qdjango_project.save() for layer_id, layer in project.mapLayers().items(): _, created = Layer.objects.get_or_create( @@ -238,17 +237,15 @@ def setUpTestData(cls): origname=layer.name(), qgs_layer_id=layer_id, srid=layer.crs().postgisSrid(), - project=cls.qdjango_project, + project=self.qdjango_project, layer_type='postgres', - datasource=cls.layer_specs[layer.name()] + datasource=self.layer_specs[layer.name()] ) assert created OpenrouteserviceProject.objects.get_or_create( - project=cls.qdjango_project, services={OpenrouteserviceService.ISOCHRONE.value}) + project=self.qdjango_project, services={OpenrouteserviceService.ISOCHRONE.value}) - def setUp(self): - super().setUp() self.client = APIClient() def _check_layer(self, new_name, connection_id=None, qgis_layer_id=None, count=8, style=None, name=None, qdjango_layer_id=None): diff --git a/g3w-admin/qdjango/forms/projects.py b/g3w-admin/qdjango/forms/projects.py index 3dc1c7d86..b609d97ae 100644 --- a/g3w-admin/qdjango/forms/projects.py +++ b/g3w-admin/qdjango/forms/projects.py @@ -1,20 +1,11 @@ -import os - -from qgis.core import QgsProject -import re -import zipfile - from core.mixins.forms import * -from core.models import Group as G3WGroup from core.utils.forms import crispyBoxBaseLayer from crispy_forms.helper import FormHelper, Layout from crispy_forms.layout import HTML, Div, Field from django import forms from django.core.files.base import ContentFile -from django.db.models import Q from django.urls import reverse from django.forms import ValidationError, widgets -from django.utils.translation import ugettext from django.utils.translation import gettext_lazy as _ from django.utils.html import mark_safe from django_file_form.forms import FileFormMixin, UploadedFileField @@ -24,7 +15,6 @@ from usersmanage.forms import G3WACLForm, label_users from usersmanage.utils import ( crispyBoxACL, - get_fields_by_user, get_groups_for_object, get_user_groups_for_object, get_viewers_for_object, @@ -32,11 +22,13 @@ ) from qdjango.models import * from qdjango.utils.data import QgisProject -from qdjango.utils.validators import ProjectExists from qdjango.utils.models import get_geocoding_providers import shutil import json +import re +import zipfile +import os class QdjangoProjectFormMixin(object): diff --git a/g3w-admin/qdjango/models/messages.py b/g3w-admin/qdjango/models/messages.py index 80f988901..2a8225fb0 100644 --- a/g3w-admin/qdjango/models/messages.py +++ b/g3w-admin/qdjango/models/messages.py @@ -41,3 +41,6 @@ class Message(TimeStampedModel, OrderedModel): def __str__(self): return self.title + class Meta(): + ordering = ("-order",) + diff --git a/g3w-admin/qdjango/signals.py b/g3w-admin/qdjango/signals.py index ee2e403f3..87bc3570c 100644 --- a/g3w-admin/qdjango/signals.py +++ b/g3w-admin/qdjango/signals.py @@ -2,16 +2,16 @@ # Load data from qdjango widget form # pass context template form -load_qdjango_widgets_data = django.dispatch.Signal(providing_args=['context']) +load_qdjango_widgets_data = django.dispatch.Signal() # load widgets data on layer serializzation -load_qdjango_widget_layer = django.dispatch.Signal(providing_args=['layer', 'ret', 'widget']) +load_qdjango_widget_layer = django.dispatch.Signal() # load project file -load_qdjango_project_file = django.dispatch.Signal(providing_args=['qgis_project']) +load_qdjango_project_file = django.dispatch.Signal() # post save project file -post_save_qdjango_project_file = django.dispatch.Signal(providing_args=['qgis_project']) +post_save_qdjango_project_file = django.dispatch.Signal() # using/reading layer model instace # invoke this signals for get data from no core module diff --git a/g3w-admin/qdjango/tests/base.py b/g3w-admin/qdjango/tests/base.py index a6db73b5f..010be4960 100644 --- a/g3w-admin/qdjango/tests/base.py +++ b/g3w-admin/qdjango/tests/base.py @@ -41,7 +41,6 @@ QGS328_VALUE_RELATION = 'value_relation_qgis328.qgs' QGS328_RELATION_REFERENCE = 'g3wsuite_project_test_qgis328.qgs' - @override_settings( CACHES={ 'default': { @@ -67,32 +66,33 @@ class QdjangoTestBase(TestCase): @classmethod def setUpClass(cls): - super(QdjangoTestBase, cls).setUpClass() + # To load the fixtures + super().setUpClass() setup_testing_user(cls) - @classmethod - def setUpTestData(cls): + + def setUp(self): # main project group - cls.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', + self.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group.save() + self.project_group.save() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE), 'r')) - cls.project = QgisProject(qgis_project_file) - cls.project.title = 'A project' - cls.project.group = cls.project_group - cls.project.save() + self.project = QgisProject(qgis_project_file) + self.project.title = 'A project' + self.project.group = self.project_group + self.project.save() - # make a fake vector postgis layer + # Make a fake vector postgis layer # =================================== fake_layer1, created = Layer.objects.get_or_create( name='fakelayer', title='fakelayer', origname='fakelayer', qgs_layer_id='fakelayer_23456', - project=cls.project.instance, + project=self.project.instance, layer_type='postgres', datasource="dbname='geo_demo' host=localhost port=5432 user='postgres' password='postgres' sslmode=disable " "key='id' srid=3003 type=Polygon checkPrimaryKeyUnicity='1' " @@ -105,7 +105,7 @@ def setUpTestData(cls): title='fakelayer2', origname='fakelayer2', qgs_layer_id='fakelayer2_23456', - project=cls.project.instance, + project=self.project.instance, layer_type='postgres', datasource="dbname='geo_demo' host=localhost port=5432 user='postgres2' password='HHHHH' sslmode=disable " "key='id' srid=3003 type=Polygon checkPrimaryKeyUnicity='1' " @@ -120,7 +120,7 @@ def setUpTestData(cls): title='fakelayer3', origname='fakelayer3', qgs_layer_id='fakelayer3_23456', - project=cls.project.instance, + project=self.project.instance, layer_type='postgres', datasource="dbname='geo_demo' host=localhost port=5432 user='postgres1' password='XXXX' sslmode=disable " "key='id' srid=3003 type=Polygon checkPrimaryKeyUnicity='1' " @@ -128,21 +128,21 @@ def setUpTestData(cls): ) - layers = cls.project.instance.layer_set.all() + layers = self.project.instance.layer_set.all() for l in layers: if l.qgs_layer_id == 'fakelayer_23456': - cls.fake_layer1 = l + self.fake_layer1 = l if l.qgs_layer_id == 'fakelayer2_23456': - cls.fake_layer2 = l + self.fake_layer2 = l if l.qgs_layer_id == 'fakelayer3_23456': - cls.fake_layer3 = l + self.fake_layer3 = l qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS310_FILE), 'r')) - cls.project310 = QgisProject(qgis_project_file) - cls.project310.title = 'A project QGIS 3.10' - cls.project310.group = cls.project_group - cls.project310.save() + self.project310 = QgisProject(qgis_project_file) + self.project310.title = 'A project QGIS 3.10' + self.project310.group = self.project_group + self.project310.save() diff --git a/g3w-admin/qdjango/tests/data/geodata/qgis_widget_test_data.gpkg b/g3w-admin/qdjango/tests/data/geodata/qgis_widget_test_data.gpkg index 85299a068d9954376ab0aa81a69fbe01aefe60cd..44c7ac1a7ebce28288a55fa6288488f574856e11 100644 GIT binary patch delta 24 ecmZoTz}|3xeS#DdYu!W{Cm`9Fur+~k!F>Q{#t5hY delta 24 ecmZoTz}|3xeS#Ddi_JtCCm`9Fur+~k!F>Q?0tg}i diff --git a/g3w-admin/qdjango/tests/test_accesscontrol.py b/g3w-admin/qdjango/tests/test_accesscontrol.py index 13a7bbb33..4962ac1ca 100644 --- a/g3w-admin/qdjango/tests/test_accesscontrol.py +++ b/g3w-admin/qdjango/tests/test_accesscontrol.py @@ -22,11 +22,10 @@ class AccessControlTest(QdjangoTestBase): """Test access control""" - @classmethod - def setUpTestData(cls): + def setUp(self): - super().setUpTestData() - cls.qdjango_project = Project.objects.all()[0] + super().setUp() + self.qdjango_project = Project.objects.all()[0] def test_filter_loading(self): diff --git a/g3w-admin/qdjango/tests/test_api.py b/g3w-admin/qdjango/tests/test_api.py index 66d279425..8f304654a 100644 --- a/g3w-admin/qdjango/tests/test_api.py +++ b/g3w-admin/qdjango/tests/test_api.py @@ -69,13 +69,10 @@ class BaseConstraintsApiTests(): _rule_class = ConstraintSubsetStringRule _rule_view_name = 'subsetstringrule' - @classmethod - def setUpTestData(cls): - super().setUpTestData() - @classmethod def setUpClass(cls): - super().setUpClass() + + QdjangoTestBase.setUpClass() # Add admin01 to a group cls.viewer1_group = cls.main_roles['Viewer Level 1'] @@ -315,47 +312,46 @@ class TestExpressionRules(BaseConstraintsApiTests, QdjangoTestBase): class TestQdjangoProjectsAPI(QdjangoTestBase): """ Test qdjango project API """ - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.client = APIClient() + def setUp(self): + + super().setUp() + self.client = APIClient() # Add new project for fields excluded from WMS service qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS322_FILE), 'r')) - cls.project322 = QgisProject(qgis_project_file) - cls.project322.title = 'A project QGIS 3.22 - fields selected for WMS service' - cls.project322.group = cls.project_group - cls.project322.save() + self.project322 = QgisProject(qgis_project_file) + self.project322.title = 'A project QGIS 3.22 - fields selected for WMS service' + self.project322.group = self.project_group + self.project322.save() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS328_FILE), 'r')) - cls.project328 = QgisProject(qgis_project_file) - cls.project328.title = 'A project QGIS 3.28' - cls.project328.group = cls.project_group - cls.project328.save() + self.project328 = QgisProject(qgis_project_file) + self.project328.title = 'A project QGIS 3.28' + self.project328.group = self.project_group + self.project328.save() - cls.project_group_3857 = CoreGroup( + self.project_group_3857 = CoreGroup( name="Group3857", title="Group3857", header_logo_img="", srid=G3WSpatialRefSys.objects.get(auth_srid=3857), ) - cls.project_group_3857.save() + self.project_group_3857.save() qgis_project_file = File( open("{}{}{}".format(CURRENT_PATH, TEST_BASE_PATH, QGS328_VALUE_RELATION), "r") ) - cls.project328_value_relation = QgisProject(qgis_project_file) - cls.project328_value_relation.title = "A project QGIS 3.28 fro value relation" - cls.project328_value_relation.group = cls.project_group_3857 - cls.project328_value_relation.save() + self.project328_value_relation = QgisProject(qgis_project_file) + self.project328_value_relation.title = "A project QGIS 3.28 fro value relation" + self.project328_value_relation.group = self.project_group_3857 + self.project328_value_relation.save() - @classmethod - def tearDownClass(cls): - cls.project322.instance.delete() - cls.project328.instance.delete() - super().tearDownClass() + def tearDown(self): + self.project322.instance.delete() + self.project328.instance.delete() + super().tearDown() def _testApiCall(self, view_name, args, kwargs={}): """Utility to make test calls for admin01 user""" @@ -692,46 +688,48 @@ def setUpClass(cls): super().setUpClass() cls.client = APIClient() + def setUp(self): + super().setUp() + qgis_project_file_widget = File(open('{}{}{}'.format( CURRENT_PATH, TEST_BASE_PATH, QGS310_WIDGET_FILE), 'r')) - cls.project_widget310 = QgisProject(qgis_project_file_widget) - cls.project_widget310.title = 'A project with widget QGIS 3.10' - cls.project_widget310.group = cls.project_group - cls.project_widget310.save() + self.project_widget310 = QgisProject(qgis_project_file_widget) + self.project_widget310.title = 'A project with widget QGIS 3.10' + self.project_widget310.group = self.project_group + self.project_widget310.save() # Add new project for fields excluded from WMS service qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS322_FILE), 'r')) - cls.project322 = QgisProject(qgis_project_file) - cls.project322.title = 'A project QGIS 3.22 - fields selected for WMS service' - cls.project322.group = cls.project_group - cls.project322.save() + self.project322 = QgisProject(qgis_project_file) + self.project322.title = 'A project QGIS 3.22 - fields selected for WMS service' + self.project322.group = self.project_group + self.project322.save() # Add new project for date datetime formatting qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS322_FORMATTING_DATE), 'r')) - cls.project322_datewidget = QgisProject(qgis_project_file) - cls.project322_datewidget.group = cls.project_group - cls.project322_datewidget.save() + self.project322_datewidget = QgisProject(qgis_project_file) + self.project322_datewidget.group = self.project_group + self.project322_datewidget.save() # For RelationReference widget qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS328_RELATION_REFERENCE), 'r')) - cls.project328_rrwidget = QgisProject(qgis_project_file) - cls.project328_rrwidget.group = cls.project_group - cls.project328_rrwidget.save() + self.project328_rrwidget = QgisProject(qgis_project_file) + self.project328_rrwidget.group = self.project_group + self.project328_rrwidget.save() qgis_project_file = File( open("{}{}{}".format(CURRENT_PATH, TEST_BASE_PATH, QGS328_VALUE_RELATION), "r") ) - cls.project328_value_relation = QgisProject(qgis_project_file) - cls.project328_value_relation.title = "A project QGIS 3.28 fro value relation" - cls.project328_value_relation.group = cls.project_group - cls.project328_value_relation.save() + self.project328_value_relation = QgisProject(qgis_project_file) + self.project328_value_relation.title = "A project QGIS 3.28 fro value relation" + self.project328_value_relation.group = self.project_group + self.project328_value_relation.save() - @classmethod - def tearDownClass(cls): - cls.project_widget310.instance.delete() - cls.project322.instance.delete() - cls.project328_value_relation.instance.delete() - super().tearDownClass() + def tearDown(self): + self.project_widget310.instance.delete() + self.project322.instance.delete() + self.project328_value_relation.instance.delete() + super().tearDown() def _testApiCall(self, view_name, args, kwargs={}, status_auth=200, login=True, logout=True, method='get'): """Utility to make test calls for admin01 user""" @@ -2149,23 +2147,22 @@ class QgisTemporalVectorProject(QdjangoTestBase): def setUpClass(cls): super().setUpClass() cls.client = APIClient() - - @classmethod - def setUpTestData(cls): + + def setUp(self): # main project group - cls.project_group = CoreGroup(name='GroupTemporal', title='GroupTemporal', header_logo_img='', + self.project_group = CoreGroup(name='GroupTemporal', title='GroupTemporal', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group.save() + self.project_group.save() # Test data for temporal vector layer qgis_project_file = File( open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE_TEMPORAL_VECTOR_WITH_FIELD), 'r', encoding='utf-8')) qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project_temporal_vector_field = QgisProject(qgis_project_file) - cls.project_temporal_vector_field.group = cls.project_group - cls.project_temporal_vector_field.save() + self.project_temporal_vector_field = QgisProject(qgis_project_file) + self.project_temporal_vector_field.group = self.project_group + self.project_temporal_vector_field.save() qgis_project_file.close() # Test WMST @@ -2173,20 +2170,21 @@ def setUpTestData(cls): open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE_WMST), 'r', encoding='utf-8')) qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project_wmst = QgisProject(qgis_project_file) - cls.project_wmst.group = cls.project_group - cls.project_wmst.save() + self.project_wmst = QgisProject(qgis_project_file) + self.project_wmst.group = self.project_group + self.project_wmst.save() qgis_project_file.close() qgis_project_file = File( open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE_TEMPORAL_VECTOR_WITH_NOT_ACTIVE), 'r', encoding='utf-8')) qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project_temporal_vector_not_active = QgisProject(qgis_project_file) - cls.project_temporal_vector_not_active.group = cls.project_group - cls.project_temporal_vector_not_active.save() + self.project_temporal_vector_not_active = QgisProject(qgis_project_file) + self.project_temporal_vector_not_active.group = self.project_group + self.project_temporal_vector_not_active.save() qgis_project_file.close() + def test_qgs_project_temporal_vector(self): """ Test properties into qgsproject object and models """ @@ -2289,31 +2287,32 @@ class TestInitextentByGeoconstraint(QdjangoTestBase): Test changing initextent property of initconfig API REST by user geoconstraint rules. """ - @classmethod - def setUpTestData(cls): - # main project group - cls.project_group = CoreGroup(name='GroupInitExtentGeoconstraint', title='GroupInitExtentGeoconstraint', header_logo_img='', + + def setUp(self): + + # Main project group + self.project_group = CoreGroup(name='GroupInitExtentGeoconstraint', title='GroupInitExtentGeoconstraint', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=3857)) - cls.project_group.save() + self.project_group.save() # Load project qgis_project_file = File(open(f'{CURRENT_PATH}{TEST_BASE_PATH}{QGS322_INITEXTENT_GEOCONSTRAINT_FILE}', 'r')) - cls.project = QgisProject(qgis_project_file) - cls.project.title = 'Test project for initextent by geoconstraint' - cls.project.group = cls.project_group - cls.project.save() + self.project = QgisProject(qgis_project_file) + self.project.title = 'Test project for initextent by geoconstraint' + self.project.group = self.project_group + self.project.save() group_viewer = UserGroup.objects.get(name='Viewer Level 1') # Viewer level 1: viewer2 - cls.test_viewer2 = User.objects.create_user(username='viewer2', password='viewer2') - cls.test_viewer2.groups.add(group_viewer) - cls.test_viewer2.save() + self.test_viewer2 = User.objects.create_user(username='viewer2', password='viewer2') + self.test_viewer2.groups.add(group_viewer) + self.test_viewer2.save() # Viewer level 1: viewer3 - cls.test_viewer3 = User.objects.create_user(username='viewer3', password='viewer3') - cls.test_viewer3.groups.add(group_viewer) - cls.test_viewer3.save() + self.test_viewer3 = User.objects.create_user(username='viewer3', password='viewer3') + self.test_viewer3.groups.add(group_viewer) + self.test_viewer3.save() def _make_request_with_geocontraints(self, url, u, expr): """ @@ -2403,20 +2402,19 @@ def test_init_map_extent_by_geoconstraints(self): class TestVectorApiConfigCrossRelation(QdjangoTestBase): """ Test /vector/api/config response with 2 layers in cross relation: avoid recursion !! """ - @classmethod - def setUpTestData(cls): + def setUp(self): - cls.project_group_3857 = CoreGroup(name='GroupRelation3857', title='GroupRelation3857', header_logo_img='', + self.project_group_3857 = CoreGroup(name='GroupRelation3857', title='GroupRelation3857', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=3857)) - cls.project_group_3857.save() + self.project_group_3857.save() qgis_project_file = File( open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE_CASCADE_AUTORELATION), 'r', encoding='utf-8')) qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project_cascading_autorelation = QgisProject(qgis_project_file) - cls.project_cascading_autorelation.group = cls.project_group_3857 - cls.project_cascading_autorelation.save() + self.project_cascading_autorelation = QgisProject(qgis_project_file) + self.project_cascading_autorelation.group = self.project_group_3857 + self.project_cascading_autorelation.save() qgis_project_file.close() def test_vector_api_config(self): diff --git a/g3w-admin/qdjango/tests/test_app.py b/g3w-admin/qdjango/tests/test_app.py index c4e6bf691..298029ce8 100644 --- a/g3w-admin/qdjango/tests/test_app.py +++ b/g3w-admin/qdjango/tests/test_app.py @@ -37,16 +37,19 @@ class AppTest(QdjangoTestBase): """Test app's methods""" - @classmethod - def setUpTestData(cls): + def setUp(self): - super().setUpTestData() - cls.qdjango_project = Project( - qgis_file=cls.project.qgisProjectFile, + super().setUp() + + # For Django 4.2 inherit setUpTestData is not maintained the file object inside the models + qprj = Project.objects.get(pk=self.project.instance.pk) + + self.qdjango_project = Project( + qgis_file=qprj.qgis_file, title='Test qdjango project', - group=cls.project_group, + group=self.project_group, ) - cls.qdjango_project.save() + self.qdjango_project.save() def test_get_qgs_project(self): """test get_qgs_project""" diff --git a/g3w-admin/qdjango/tests/test_column_acl.py b/g3w-admin/qdjango/tests/test_column_acl.py index d4a5c6cad..5c1090e34 100644 --- a/g3w-admin/qdjango/tests/test_column_acl.py +++ b/g3w-admin/qdjango/tests/test_column_acl.py @@ -16,24 +16,15 @@ import zipfile from io import BytesIO -from django.conf import settings -from django.contrib.auth.models import User +from django.db import transaction from django.test import Client from django.urls import reverse -from guardian.shortcuts import assign_perm, get_anonymous_user -from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsExpression, Qgis +from qgis.core import QgsVectorLayer from django.db import IntegrityError from django.core.exceptions import ValidationError from qdjango.apps import QGS_SERVER, get_qgs_project from qdjango.models import ( - ConstraintSubsetStringRule, - ConstraintExpressionRule, - SingleLayerConstraint, - SessionTokenFilter, - SessionTokenFilterLayer, - GeoConstraint, - GeoConstraintRule, Layer, Project, ColumnAcl @@ -52,63 +43,66 @@ class TestColumnAcl(QdjangoTestBase): """Test column ACL""" - @classmethod - def setUpTestData(cls): + def setUp(self): - super().setUpTestData() - cls.qdjango_project = Project.objects.all()[0] - cls.world = cls.qdjango_project.layer_set.filter( + super().setUp() + + self.qdjango_project = Project.objects.all()[0] + self.world = self.qdjango_project.layer_set.filter( qgs_layer_id='world20181008111156525')[0] - cls.spatialite_points = cls.qdjango_project.layer_set.filter( + self.spatialite_points = self.qdjango_project.layer_set.filter( qgs_layer_id='spatialite_points20190604101052075')[0] # Make a cloned layer - cls.cloned_project = Project( - group=cls.qdjango_project.group, title='My Clone') + self.cloned_project = Project( + group=self.qdjango_project.group, title='My Clone') - cls.cloned_project.qgis_file = cls.qdjango_project.qgis_file - cls.cloned_project.save() - cls.cloned_layer = cls.qdjango_project.layer_set.filter( + self.cloned_project.qgis_file = self.qdjango_project.qgis_file + self.cloned_project.save() + self.cloned_layer = self.qdjango_project.layer_set.filter( qgs_layer_id='world20181008111156525')[0] - cls.cloned_layer.pk = None - cls.cloned_layer.project = cls.cloned_project - cls.cloned_layer.save() + self.cloned_layer.pk = None + self.cloned_layer.project = self.cloned_project + self.cloned_layer.save() assert Layer.objects.filter( qgs_layer_id='world20181008111156525').count() == 2 - assert not cls.world.has_column_acl + assert not self.world.has_column_acl + + ColumnAcl.objects.all().delete() + self.cloned_layer = Layer.objects.get(pk=self.cloned_layer.pk) + self.world = Layer.objects.get(pk=self.world.pk) + assert ColumnAcl.objects.count() == 0 + assert not self.cloned_layer.has_column_acl + assert not self.world.has_column_acl + + for l in Layer.objects.all(): + l.has_column_acl = False + l.save() + + assert not self.cloned_layer.has_column_acl + assert not self.world.has_column_acl @classmethod def setUpClass(cls): - super().setUpClass() + QdjangoTestBase.setUpClass() # Add admin01 to a group cls.viewer1_group = cls.main_roles['Viewer Level 1'] cls.viewer1_group.user_set.add(cls.test_user1) - ColumnAcl.objects.all().delete() - for l in Layer.objects.all(): - l.has_column_acl = False - l.save() - - assert not cls.cloned_layer.has_column_acl - assert not cls.world.has_column_acl @classmethod def tearDownClass(cls): super().tearDownClass() cls.viewer1_group.user_set.remove(cls.test_user1) - cls.cloned_project.delete() - ColumnAcl.objects.all().delete() - def setUp(self): - super().setUp() - ColumnAcl.objects.all().delete() - self.cloned_layer = Layer.objects.get(pk=self.cloned_layer.pk) - self.world = Layer.objects.get(pk=self.world.pk) - assert ColumnAcl.objects.count() == 0 - assert not self.cloned_layer.has_column_acl - assert not self.world.has_column_acl + def tearDown(self): + super().tearDown() + #self.cloned_project.delete() + #ColumnAcl.objects.all().delete() + + def _testApiCallAdmin01(self, view_name, args, kwargs={}): """Utility to make test calls for admin01 user, returns the response""" diff --git a/g3w-admin/qdjango/tests/test_constraints.py b/g3w-admin/qdjango/tests/test_constraints.py index f610466ae..160a89d28 100644 --- a/g3w-admin/qdjango/tests/test_constraints.py +++ b/g3w-admin/qdjango/tests/test_constraints.py @@ -52,32 +52,32 @@ class TestSingleLayerConstraintsBase(QdjangoTestBase): """Common code for subset string and expression rules""" - @classmethod - def setUpTestData(cls): + def setUp(self): - super().setUpTestData() - cls.qdjango_project = Project.objects.all()[0] - cls.world = cls.qdjango_project.layer_set.filter( + super().setUp() + + self.qdjango_project = Project.objects.all()[0] + self.world = self.qdjango_project.layer_set.filter( qgs_layer_id='world20181008111156525')[0] - cls.spatialite_points = cls.qdjango_project.layer_set.filter( + self.spatialite_points = self.qdjango_project.layer_set.filter( qgs_layer_id='spatialite_points20190604101052075')[0] # Make a cloned layer - cls.cloned_project = Project( - group=cls.qdjango_project.group, title='My Clone') + self.cloned_project = Project( + group=self.qdjango_project.group, title='My Clone') - cls.cloned_project.qgis_file = cls.qdjango_project.qgis_file - cls.cloned_project.save() - cls.cloned_layer = cls.qdjango_project.layer_set.filter( + self.cloned_project.qgis_file = self.qdjango_project.qgis_file + self.cloned_project.save() + self.cloned_layer = self.qdjango_project.layer_set.filter( qgs_layer_id='world20181008111156525')[0] - cls.cloned_layer.pk = None - cls.cloned_layer.project = cls.cloned_project - cls.cloned_layer.save() + self.cloned_layer.pk = None + self.cloned_layer.project = self.cloned_project + self.cloned_layer.save() assert Layer.objects.filter( qgs_layer_id='world20181008111156525').count() == 2 @classmethod def setUpClass(cls): - super().setUpClass() + QdjangoTestBase.setUpClass() # Add admin01 to a group cls.viewer1_group = cls.main_roles['Viewer Level 1'] @@ -87,11 +87,11 @@ def setUpClass(cls): def tearDownClass(cls): super().tearDownClass() cls.viewer1_group.user_set.remove(cls.test_user1) - cls.cloned_project.delete() def tearDown(self): super().tearDown() SingleLayerConstraint.objects.all().delete() + self.cloned_project.delete() def _testApiCallAdmin01(self, view_name, args, kwargs={}): """Utility to make test calls for admin01 user, returns the response""" diff --git a/g3w-admin/qdjango/tests/test_embedded_layers.py b/g3w-admin/qdjango/tests/test_embedded_layers.py index 376c718f6..aa915beeb 100644 --- a/g3w-admin/qdjango/tests/test_embedded_layers.py +++ b/g3w-admin/qdjango/tests/test_embedded_layers.py @@ -61,8 +61,7 @@ ) class TestEmbeddedLayers(QdjangoTestBase): - @classmethod - def setUpTestData(cls): + def setUp(cls): # main project group cls.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', @@ -107,20 +106,21 @@ def tearDownClass(cls): def tearDown(self): """Remove all test projects""" - for original_name in ( - 'embedded.qgs', - 'embedded_parent.qgs', - 'embedded_parent_ddform.qgs', - 'embedded_group.qgs', - 'embedded_parent_group.qgs', - 'embedded_parent_removed.qgs', - 'embedded_parent_group_wms_added.qgs', - 'embedded_parent_new_title.qgs'): - Project.objects.filter(original_name=original_name).delete() + # for original_name in ( + # 'embedded.qgs', + # 'embedded_parent.qgs', + # 'embedded_parent_ddform.qgs', + # 'embedded_group.qgs', + # 'embedded_parent_group.qgs', + # 'embedded_parent_removed.qgs', + # 'embedded_parent_group_wms_added.qgs', + # 'embedded_parent_new_title.qgs'): + # Project.objects.filter(original_name=original_name).delete() - def tearDown(self): super().tearDown() + + def _testApiCallAdmin01(self, view_name, args, kwargs={}): """Utility to make test calls for admin01 user, returns the response""" @@ -140,7 +140,6 @@ def _testApiCallAdmin01(self, view_name, args, kwargs={}): return response def _make_form(self, project_path, instance=None, name=None): - payload = open(project_path, 'rb').read() if name is None: name = os.path.basename(project_path) @@ -199,9 +198,6 @@ def test_form(self, login=True): # Save embedded project form.qgisProject.save(**form.cleaned_data) - # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() - # Verify project = Project.objects.get(original_name='embedded_parent.qgs') self.assertIsNotNone(project) @@ -215,9 +211,6 @@ def test_form(self, login=True): # Save the embedded project form.qgisProject.save(**form.cleaned_data) - # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() - project = Project.objects.get(original_name='embedded.qgs') self.assertIsNotNone(project) @@ -274,9 +267,6 @@ def test_form(self, login=True): original_name='embedded_parent.qgs') self.assertEqual(parent_project.title, 'parent_new_title') - # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() - # Check that the project embedded layer points to the renamed parent file path project = Project.objects.get(original_name='embedded.qgs') self.assertEqual(project.title, 'embedded.qgs') @@ -302,8 +292,6 @@ def test_form(self, login=True): # Update parent with DD form configuration and test both form = self._make_form(self.parent_project_ddform_path, parent_project, 'embedded_parent_ddform.qgs') form.qgisProject.save(**form.cleaned_data) - # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() # Check form configuration for both parent and embedded parent_project = Project.objects.get( @@ -342,7 +330,7 @@ def test_embedded_group(self): form.qgisProject.save(**form.cleaned_data) # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() + #open(form.qgisProject.qgisProjectFile.file.name, 'a').close() # Verify project = Project.objects.get( @@ -359,10 +347,6 @@ def test_embedded_group(self): # Save the embedded project form.qgisProject.save(**form.cleaned_data) - - # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() - project = Project.objects.get(original_name='embedded_group.qgs') self.assertIsNotNone(project) @@ -383,8 +367,6 @@ def test_embedded_group(self): parent_project=Project.objects.get(original_name='embedded_parent_group.qgs') form = self._make_form(self.parent_project_group_path, parent_project, 'embedded_parent_group.qgs') form.qgisProject.save(instance=parent_project, **form.cleaned_data) - # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() parent_project=Project.objects.get(original_name='embedded_parent_group.qgs') self.assertEqual(parent_project.layer_set.count(), 3) @@ -398,8 +380,6 @@ def test_embedded_group(self): parent_project=Project.objects.get(original_name='embedded_parent_group.qgs') form = self._make_form(self.parent_project_wms_added, parent_project, 'embedded_parent_group.qgs') form.qgisProject.save(instance=parent_project, **form.cleaned_data) - # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() parent_project=Project.objects.get(original_name='embedded_parent_group.qgs') self.assertEqual(parent_project.layer_set.count(), 4) @@ -412,8 +392,7 @@ def test_embedded_group(self): parent_project=Project.objects.get(original_name='embedded_parent_group.qgs') form = self._make_form(self.parent_project_group_path, parent_project, 'embedded_parent_group.qgs') form.qgisProject.save(instance=parent_project, **form.cleaned_data) - # Store temporary file to avoid error on test exit (because the temp file was moved) - open(form.qgisProject.qgisProjectFile.file.name, 'a').close() + self.assertEqual(parent_project.layer_set.count(), 3) project = Project.objects.get(original_name='embedded_group.qgs') self.assertEqual(project.layer_set.count(), 4) diff --git a/g3w-admin/qdjango/tests/test_ows.py b/g3w-admin/qdjango/tests/test_ows.py index a00710c89..d913d83ac 100644 --- a/g3w-admin/qdjango/tests/test_ows.py +++ b/g3w-admin/qdjango/tests/test_ows.py @@ -29,8 +29,14 @@ from qdjango.models import Project, ProjectMapUrlAlias from qgis.core import QgsProject -from .base import (CURRENT_PATH, QGS310_WIDGET_FILE, TEST_BASE_PATH, - QdjangoTestBase, QgisProject) +from .base import ( + CURRENT_PATH, + QGS310_WIDGET_FILE, + TEST_BASE_PATH, + QGS_FILE, + QdjangoTestBase, + QgisProject +) @override_settings(CACHES={ @@ -47,62 +53,58 @@ class OwsTest(QdjangoTestBase): """Test proxy to QgsServer""" - @classmethod - def setUpTestData(cls): + def setUp(self): + + super().setUp() - super().setUpTestData() - #cls.qdjango_project = Project( - # qgis_file=cls.project.qgisProjectFile, - # title='Test qdjango project', - # group=cls.project_group, - #) - #cls.qdjango_project.save() + # For Django 4.2 inherit setUpTestData is not maintained the file object inside the models + qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE), 'r')) - cls.project2 = QgisProject(cls.project.qgisProjectFile) - cls.project2.title = "Test qdjango project" - cls.project2.group = cls.project_group - cls.project2.save() + self.project2 = QgisProject(qgis_project_file) + self.project2.title = "Test qdjango project" + self.project2.group = self.project_group + self.project2.save() - cls.qdjango_project = cls.project2.instance + self.qdjango_project = self.project2.instance qgis_project_file_widget = File(open('{}{}{}'.format( CURRENT_PATH, TEST_BASE_PATH, QGS310_WIDGET_FILE), 'r')) - cls.project_widget310 = QgisProject(qgis_project_file_widget) - cls.project_widget310.title = 'A project with widget QGIS 3.10' - cls.project_widget310.group = cls.project_group - cls.project_widget310.save() + self.project_widget310 = QgisProject(qgis_project_file_widget) + self.project_widget310.title = 'A project with widget QGIS 3.10' + self.project_widget310.group = self.project_group + self.project_widget310.save() - cls.project_off_temp_path = '{}{}{}'.format( + self.project_off_temp_path = '{}{}{}'.format( CURRENT_PATH, TEST_BASE_PATH, 'legend_off.qgs') shutil.copyfile('{}{}{}'.format( - CURRENT_PATH, TEST_BASE_PATH, QGS310_WIDGET_FILE), cls.project_off_temp_path) + CURRENT_PATH, TEST_BASE_PATH, QGS310_WIDGET_FILE), self.project_off_temp_path) p = QgsProject() - p.read(cls.project_off_temp_path) + p.read(self.project_off_temp_path) main_layer = p.mapLayersByName('main_layer')[0] renderer = main_layer.renderer() renderer.checkLegendSymbolItem('0', False) renderer.checkLegendSymbolItem('1', False) p.write() - p.read(cls.project_off_temp_path) + p.read(self.project_off_temp_path) main_layer = p.mapLayersByName('main_layer')[0] renderer = main_layer.renderer() assert not renderer.legendSymbolItemChecked('0') assert not renderer.legendSymbolItemChecked('1') qgis_project_file_widget_off = File( - open(cls.project_off_temp_path, 'r')) - cls.project_widget310_off = QgisProject(qgis_project_file_widget_off) - cls.project_widget310_off.title = 'A project with widget QGIS 3.10 and classes off' - cls.project_widget310_off.group = cls.project_group - cls.project_widget310_off.save() + open(self.project_off_temp_path, 'r')) + self.project_widget310_off = QgisProject(qgis_project_file_widget_off) + self.project_widget310_off.title = 'A project with widget QGIS 3.10 and classes off' + self.project_widget310_off.group = self.project_group + self.project_widget310_off.save() # Add Map Url Alias - ProjectMapUrlAlias.objects.create(app_name='qdjango', project_id=cls.project_widget310.instance.pk, + ProjectMapUrlAlias.objects.create(app_name='qdjango', project_id=self.project_widget310.instance.pk, alias='alias-map') - ProjectMapUrlAlias.objects.create(app_name='qdjango', project_id=cls.project_widget310_off.instance.pk, + ProjectMapUrlAlias.objects.create(app_name='qdjango', project_id=self.project_widget310_off.instance.pk, alias='alias-map-off') @classmethod @@ -436,7 +438,7 @@ def testLegendOnOffFilter(self): self.assertTrue(c.login(username='admin01', password='admin01')) project = get_qgs_project( - self.project_widget310.qgisProjectFile.file.name) + self.project_widget310.instance.qgis_file.path) main_layer = project.mapLayersByName('main_layer')[0] renderer = main_layer.renderer() items = renderer.legendSymbolItems() @@ -529,7 +531,7 @@ def testLegendOnOffFilter(self): 'project_id': self.project_widget310_off.instance.id}) project = get_qgs_project( - self.project_widget310_off.qgisProjectFile.file.name) + self.project_widget310_off.instance.qgis_file.path) main_layer = project.mapLayersByName('main_layer')[0] renderer = main_layer.renderer() self.assertFalse(renderer.legendSymbolItemChecked(key1)) diff --git a/g3w-admin/qdjango/tests/test_ows_postgres.py b/g3w-admin/qdjango/tests/test_ows_postgres.py index 640ec9e31..3263d2580 100644 --- a/g3w-admin/qdjango/tests/test_ows_postgres.py +++ b/g3w-admin/qdjango/tests/test_ows_postgres.py @@ -68,16 +68,18 @@ def check_qgis_patches(): class OwsTestPostgres(QdjangoTestBase): """Test proxy to QgsServer""" - @classmethod - def setUpTestData(cls): + def setUp(self): - super().setUpTestData() + super().setUp() project_path = os.path.join( CURRENT_PATH + TEST_BASE_PATH, 'pg_multiple_pks.qgs') - cls.temp_dir = QTemporaryDir() - cls.temp_project_path = os.path.join( - cls.temp_dir.path(), 'pg_multiple_pks.qgs') + self.temp_dir = QTemporaryDir() + + # For Djanog 4.2 and initial class serialization + self.temp_dir_path = self.temp_dir.path() + self.temp_project_path = os.path.join( + self.temp_dir_path, 'pg_multiple_pks.qgs') # Create test layer conn_str = "host={HOST} port={PORT} dbname={NAME} user={USER} password={PASSWORD}".format( @@ -95,42 +97,41 @@ def setUpTestData(cls): conn.executeSql( "INSERT INTO multiple_pks VALUES ( 1, 2, '1-2', ST_GeomFromText('point(8 46)', 4326))") - cls.layer_uri = conn_str + \ + self.layer_uri = conn_str + \ " sslmode=disable key='pk1,pk2' estimatedmetadata=true srid=4326 type=Point checkPrimaryKeyUnicity='0' table=\"public\".\"multiple_pks\" (geom)" - layer = QgsVectorLayer(cls.layer_uri, 'multiple_pks', 'postgres') + layer = QgsVectorLayer(self.layer_uri, 'multiple_pks', 'postgres') assert layer.isValid() project = open(project_path, 'r').read() - with open(cls.temp_project_path, 'w+') as f: + with open(self.temp_project_path, 'w+') as f: f.write(re.sub(r'.*', - '%s' % cls.layer_uri, project)) + '%s' % self.layer_uri, project)) Project.objects.filter( title='Test qdjango postgres multiple_pks project').delete() - cls.qdjango_project = Project( - qgis_file=File(open(cls.temp_project_path, 'r')), title='Test qdjango postgres multiple_pks project', group=cls.project_group) - cls.qdjango_project.save() + self.qdjango_project = Project( + qgis_file=File(open(self.temp_project_path, 'r')), title='Test qdjango postgres multiple_pks project', group=self.project_group) + self.qdjango_project.save() - cls.qdjango_layer, created = Layer.objects.get_or_create( + self.qdjango_layer, created = Layer.objects.get_or_create( name='multiple_pks', title='multiple_pks', origname='multiple_pks', qgs_layer_id='multiple_pks_67787984_68b5_423c_bc5e_ce92d8d74d70', - project=cls.qdjango_project, + project=self.qdjango_project, layer_type='postgres', - datasource=cls.layer_uri + datasource=self.layer_uri ) assert created - cls.client = APIClient() + self.client = APIClient() - @classmethod - def tearDownClass(cls): - super().tearDownClass() + def tearDown(self): + super().tearDown() iface = QGS_SERVER.serverInterface() - iface.removeConfigCacheEntry(cls.qdjango_project.qgis_project.fileName()) + iface.removeConfigCacheEntry(self.qdjango_project.qgis_project.fileName()) def _testApiCall(self, view_name, args, kwargs={}, status_auth=200, login=True, logout=True): """Utility to make test calls for admin01 user""" @@ -226,7 +227,7 @@ def test_getPrint(self): self.assertEqual(response.status_code, 200) - result_path = os.path.join(self.temp_dir.path(), 'red.png') + result_path = os.path.join(self.temp_dir_path, 'red.png') with open(result_path, 'wb+') as f: f.write(response.content) @@ -253,7 +254,7 @@ def test_getPrint(self): # Test self.assertEqual(response.status_code, 200) - result_path = os.path.join(self.temp_dir.path(), 'white.png') + result_path = os.path.join(self.temp_dir_path, 'white.png') with open(result_path, 'wb+') as f: f.write(response.content) diff --git a/g3w-admin/qdjango/tests/test_qgisauth.py b/g3w-admin/qdjango/tests/test_qgisauth.py index 62c82de33..fabb64b5b 100644 --- a/g3w-admin/qdjango/tests/test_qgisauth.py +++ b/g3w-admin/qdjango/tests/test_qgisauth.py @@ -52,6 +52,7 @@ class AuthDbTest(QdjangoTestBase): @classmethod def setUpClass(cls): super().setUpClass() + # Prepare DB for path in (AUTH_DB_PATH, MASTER_PASSWORD_PATH): assert os.path.isfile(path) @@ -64,20 +65,22 @@ def setUpClass(cls): config = QgsAuthMethodConfig() config.setName("alice") config.setMethod('Basic') - config.setConfig("username", "my user" ) - config.setConfig("password", "my password" ) + config.setConfig("username", "my user") + config.setConfig("password", "my password") assert config.isValid() - res, cfg = cls.am.storeAuthenticationConfig(config) assert res assert config.id() != '' assert cfg.id() != '' assert cfg.id() == config.id() - # Store fakelayer datasource - cls.fakelayer = Layer.objects.get(name='fakelayer') - cls.fakelayer_datasource = cls.fakelayer.datasource + def setUp(self): + super().setUp() + + # Store fakelayer datasource + self.fakelayer = Layer.objects.get(name='fakelayer') + self.fakelayer_datasource = self.fakelayer.datasource def tearDown(self): """Clear DB""" @@ -87,6 +90,7 @@ def tearDown(self): @classmethod def tearDownClass(cls): super().tearDownClass() + # Make sure there are no auth files left for path in (AUTH_DB_PATH, MASTER_PASSWORD_PATH): if os.path.isfile(path): @@ -117,6 +121,7 @@ def test_db_methods(self): def test_model(self): """Test QGIS Auth model""" + self.assertEqual(QgisAuth.objects.count(), 0) # Create an auth config diff --git a/g3w-admin/qdjango/tests/test_styles_api.py b/g3w-admin/qdjango/tests/test_styles_api.py index e9ec19951..00ed2a221 100644 --- a/g3w-admin/qdjango/tests/test_styles_api.py +++ b/g3w-admin/qdjango/tests/test_styles_api.py @@ -29,24 +29,25 @@ class LayerStylesApiTest(QdjangoTestBase): - @classmethod - def setUpTestData(cls): - super().setUpTestData() + def setUp(self): + super().setUp() - cls.project_path = os.path.join( + self.project_path = os.path.join( CURRENT_PATH + TEST_BASE_PATH, 'multiple_styles_manager_test.qgs') Project.objects.filter( title='Test qdjango postgres multiple styles manager project').delete() - project_file = File(open(cls.project_path, 'r')) + project_file = File(open(self.project_path, 'r')) project = QgisProject(project_file) project.title = 'Test qdjango postgres multiple styles manager project' - project.group = cls.project_group + project.group = self.project_group project.save() - cls.qdjango_project = project.instance - cls.qdjango_layer = cls.qdjango_project.layer_set.all()[0] + self.qdjango_project = project.instance + self.qdjango_layer = self.qdjango_project.layer_set.all()[0] + + self.client = APIClient() @classmethod def setUpClass(cls): @@ -61,26 +62,6 @@ def tearDownClass(cls): super().tearDownClass() cls.viewer1_group.user_set.remove(cls.test_user1) - def setUp(self): - """Setup test data""" - - super().setUp() - self.project_path = os.path.join( - CURRENT_PATH + TEST_BASE_PATH, 'multiple_styles_manager_test.qgs') - - Project.objects.filter( - title='Test qdjango postgres multiple styles manager project').delete() - - project_file = File(open(self.project_path, 'r')) - project = QgisProject(project_file) - project.title = 'Test qdjango postgres multiple styles manager project' - project.group = self.project_group - project.save() - - self.qdjango_project = project.instance - self.qdjango_layer = self.qdjango_project.layer_set.all()[0] - - self.client = APIClient() def test_model_methods(self): """Test model style manager CRUD methods""" diff --git a/g3w-admin/qdjango/tests/test_theme.py b/g3w-admin/qdjango/tests/test_theme.py index a197ef17f..06f752ab1 100644 --- a/g3w-admin/qdjango/tests/test_theme.py +++ b/g3w-admin/qdjango/tests/test_theme.py @@ -32,26 +32,25 @@ class QdjangoThemeTest(QdjangoTestBase): """ Testing Project theme system """ - @classmethod - def setUpTestData(cls): - super().setUpTestData() + def setUp(self): + super().setUp() - cls.project_theme316 = QgisProject(File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS316_THEME_FILE), 'r'))) - cls.project_theme316.title = 'A project with themes QGIS 3.16' - cls.project_theme316.group = cls.project_group - cls.project_theme316.save() + self.project_theme316 = QgisProject(File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS316_THEME_FILE), 'r'))) + self.project_theme316.title = 'A project with themes QGIS 3.16' + self.project_theme316.group = self.project_group + self.project_theme316.save() - cls.project_layout_theme322 = QgisProject( + self.project_layout_theme322 = QgisProject( File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS322_PRINT_LAYOUT_THEME_FILE), 'r'))) - cls.project_layout_theme322.title = 'A project with layout with preset theme QGIS 3.22' - cls.project_layout_theme322.group = cls.project_group - cls.project_layout_theme322.save() + self.project_layout_theme322.title = 'A project with layout with preset theme QGIS 3.22' + self.project_layout_theme322.group = self.project_group + self.project_layout_theme322.save() - cls.project_theme328 = QgisProject( + self.project_theme328 = QgisProject( File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS328_THEME_FILE), 'r'))) - cls.project_theme328.title = 'A project with themes QGIS 3.28' - cls.project_theme328.group = cls.project_group - cls.project_theme328.save() + self.project_theme328.title = 'A project with themes QGIS 3.28' + self.project_theme328.group = self.project_group + self.project_theme328.save() def _testApiCall(self, view_name, args, kwargs={}, data=None, method='POST', username='admin01', status_code=200): """Utility to make test calls for admin01 user""" diff --git a/g3w-admin/qdjango/tests/test_utils.py b/g3w-admin/qdjango/tests/test_utils.py index d499a5dea..7df32916a 100644 --- a/g3w-admin/qdjango/tests/test_utils.py +++ b/g3w-admin/qdjango/tests/test_utils.py @@ -457,15 +457,14 @@ def test_composertemplates(self): class QdjangoUtilsTest(QdjangoTestBase): """ Test for utils methods and functions""" - @classmethod - def setUpClass(cls): - super().setUpClass() + def setUp(self): + super().setUp() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGIS_FILE_MDAL), 'r')) - cls.project_mdal = QgisProject(qgis_project_file) - cls.project_mdal.title = 'A project with mdal layer' - cls.project_mdal.group = cls.project_group - cls.project_mdal.save() + self.project_mdal = QgisProject(qgis_project_file) + self.project_mdal.title = 'A project with mdal layer' + self.project_mdal.group = self.project_group + self.project_mdal.save() @classmethod def tearDownClass(cls): @@ -607,14 +606,13 @@ def test_is_geom_type_gpx_compatible(self): class QdjangoTestUtilsQgis(QdjangoTestBase): """ Test for qdjango.utils.qgis module and functions """ - @classmethod - def setUpClass(cls): - super().setUpClass() + def setUp(self): + super().setUp() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGIS_FILE_EXPRESSION_DEFAULT), 'r')) - cls.project_dexp = QgisProject(qgis_project_file) - cls.project_dexp.group = cls.project_group - cls.project_dexp.save() + self.project_dexp = QgisProject(qgis_project_file) + self.project_dexp.group = self.project_group + self.project_dexp.save() def test_explode_expression(self): """ diff --git a/g3w-admin/qdjango/tests/test_validators.py b/g3w-admin/qdjango/tests/test_validators.py index 3abb630e9..428a2cfeb 100644 --- a/g3w-admin/qdjango/tests/test_validators.py +++ b/g3w-admin/qdjango/tests/test_validators.py @@ -74,47 +74,45 @@ class TestFeatureValidator(QdjangoTestBase): """ - @classmethod - def setUpClass(cls): - super().setUpClass() + def setUp(self): + super().setUp() - cls.dir = QTemporaryDir() + self.dir = QTemporaryDir() shutil.copytree(os.path.join(os.path.dirname( - __file__), 'data'), os.path.join(cls.dir.path(), 'projects')) - cls.project = QgsProject() - assert cls.project.read(os.path.join( - cls.dir.path(), 'projects', 'validator_project_test_328.qgs')) - cls.validator_project_test = cls.project.mapLayersByName( + __file__), 'data'), os.path.join(self.dir.path(), 'projects')) + self.project = QgsProject() + assert self.project.read(os.path.join( + self.dir.path(), 'projects', 'validator_project_test_328.qgs')) + self.validator_project_test = self.project.mapLayersByName( 'validator_project_test')[0] - cls.validator_project_test_not_null = cls.project.mapLayersByName( + self.validator_project_test_not_null = self.project.mapLayersByName( 'validator_project_test_not_null')[0] - cls.validator_project_test_unique = cls.project.mapLayersByName( + self.validator_project_test_unique = self.project.mapLayersByName( 'validator_project_test_unique')[0] - cls.validator_project_test_defaults = cls.project.mapLayersByName( + self.validator_project_test_defaults = self.project.mapLayersByName( 'validator_project_test_defaults')[0] - cls.validator_project_test_expressions = cls.project.mapLayersByName( + self.validator_project_test_expressions = self.project.mapLayersByName( 'validator_project_test_expressions')[0] - cls.not_nullable_fields = set( - [name for name in cls.validator_project_test.fields().names() if '_not_nullable' in name and name != 'integer_not_nullable_default']) - cls.nullable_fields = set( - [name for name in cls.validator_project_test.fields().names() if '_nullable' in name and '_not_nullable' not in name]) - cls.unique_fields = set(('fid',)).union( - [name for name in cls.validator_project_test.fields().names() if '_unique' in name]) - cls.unconstrained_fields = set([name for name in cls.validator_project_test.fields( - ).names() if name not in cls.not_nullable_fields.union(cls.unique_fields)]) - - @classmethod - def tearDownClass(cls): + self.not_nullable_fields = set( + [name for name in self.validator_project_test.fields().names() if '_not_nullable' in name and name != 'integer_not_nullable_default']) + self.nullable_fields = set( + [name for name in self.validator_project_test.fields().names() if '_nullable' in name and '_not_nullable' not in name]) + self.unique_fields = set(('fid',)).union( + [name for name in self.validator_project_test.fields().names() if '_unique' in name]) + self.unconstrained_fields = set([name for name in self.validator_project_test.fields( + ).names() if name not in self.not_nullable_fields.union(self.unique_fields)]) + + def tearDown(self): """Delete projects and layers""" - super().tearDownClass() - del(cls.validator_project_test_expressions) - del(cls.validator_project_test_unique) - del(cls.validator_project_test_defaults) - del(cls.validator_project_test_not_null) - del(cls.validator_project_test) - del(cls.project) + super().tearDown() + del(self.validator_project_test_expressions) + del(self.validator_project_test_unique) + del(self.validator_project_test_defaults) + del(self.validator_project_test_not_null) + del(self.validator_project_test) + del(self.project) def _feature_factory(self, attrs={}, geom='POINT(9, 45)'): diff --git a/g3w-admin/qdjango/utils/data.py b/g3w-admin/qdjango/utils/data.py index fb5fcc30c..95b83e910 100644 --- a/g3w-admin/qdjango/utils/data.py +++ b/g3w-admin/qdjango/utils/data.py @@ -1697,6 +1697,12 @@ def save(self, instance=None, **kwargs): post_save_qdjango_project_file.send(self) + # For deepcopy fix: + # Teardown + # ------------------------------------------------------ + self.qgisProjectFile = None + self.intialExtent = None + def updateQgisFileDatasource(self): """Update qgis file datasource for SpatiaLite, OGR and embedded layers. diff --git a/g3w-admin/qdjango/utils/exceptions.py b/g3w-admin/qdjango/utils/exceptions.py index f4b857d52..5bd6f33a8 100644 --- a/g3w-admin/qdjango/utils/exceptions.py +++ b/g3w-admin/qdjango/utils/exceptions.py @@ -1,4 +1,4 @@ -from django.utils.translation import ugettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ class QgisException(Exception): diff --git a/g3w-admin/qdjango/utils/validators.py b/g3w-admin/qdjango/utils/validators.py index 4c0754f6f..59d19513d 100644 --- a/g3w-admin/qdjango/utils/validators.py +++ b/g3w-admin/qdjango/utils/validators.py @@ -5,11 +5,6 @@ it under the terms of the Mozilla Public License 2.0. """ - -import os -import re - -from django.utils.translation import ugettext from django.utils.translation import gettext_lazy as _ from django.db.models import Q from osgeo import gdal @@ -32,7 +27,10 @@ ) from qgis.PyQt.QtCore import QVariant, Qt -import string, random +import string +import random +import os +import re def feature_validator(feature, layer): @@ -378,7 +376,7 @@ def clean(self): # try to open postgis raster with gdal raster = gdal.Open(self.qgisProjectLayer.datasource) if raster is None: - err = ugettext('Cannot connect to Postgis raster layer {} '.format( + err = _('Cannot connect to Postgis raster layer {} '.format( self.qgisProjectLayer.name)) raise QgisProjectLayerException(err) @@ -388,17 +386,17 @@ def clean(self): pre = subdt[0] + ':"' datasource = subdt[1][1:-1] if not os.path.exists(datasource): - err = ugettext('Missing data file for MESH layer {} '.format( + err = _('Missing data file for MESH layer {} '.format( self.qgisProjectLayer.name)) - err += ugettext('which should be located at {}'.format( + err += _('which should be located at {}'.format( self.qgisProjectLayer.datasource)) raise QgisProjectLayerException(err) else: if not os.path.exists(self.qgisProjectLayer.datasource.split('|')[0]): - err = ugettext('Missing data file for layer {} '.format( + err = _('Missing data file for layer {} '.format( self.qgisProjectLayer.name)) - err += ugettext('which should be located at {}'.format( + err += _('which should be located at {}'.format( self.qgisProjectLayer.datasource)) raise QgisProjectLayerException(err) @@ -419,8 +417,8 @@ def clean(self): if re.search(rex, column['name']): columns_err.append(column['name']) if columns_err: - err = ugettext('The follow fields name of layer {} contains ' + err = _('The follow fields name of layer {} contains ' 'white spaces and/or special characters: {}')\ .format(self.qgisProjectLayer.name, ', '.join(columns_err)) - err += ugettext('Please use \'Alias\' fields in QGIS project') + err += _('Please use \'Alias\' fields in QGIS project') raise QgisProjectLayerException(err) diff --git a/g3w-admin/qplotly/tests/test_api.py b/g3w-admin/qplotly/tests/test_api.py index 988618a19..f17621b8b 100644 --- a/g3w-admin/qplotly/tests/test_api.py +++ b/g3w-admin/qplotly/tests/test_api.py @@ -45,26 +45,25 @@ def setUpClass(cls): cls.client = APIClient() - @classmethod - def setUpTestData(cls): - # main project group - cls.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', + def setUp(self): + # Main project group + self.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group.save() + self.project_group.save() - cls.project_group_3857 = CoreGroup(name='Group3857', title='Group3857', header_logo_img='', + self.project_group_3857 = CoreGroup(name='Group3857', title='Group3857', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=3857)) - cls.project_group_3857.save() + self.project_group_3857.save() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE), 'r', encoding='utf-8')) # Replace name property with only file name without path to simulate UploadedFileWithId instance. qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project = QgisProject(qgis_project_file) - cls.project.group = cls.project_group - cls.project.save() + self.project = QgisProject(qgis_project_file) + self.project.group = self.project_group + self.project.save() qgis_project_file.close() qgis_project_file_3857 = File( @@ -72,28 +71,28 @@ def setUpTestData(cls): # Replace name property with only file name without path to simulate UploadedFileWithId instance. qgis_project_file_3857.name = qgis_project_file_3857.name.split('/')[-1] - cls.project_3857 = QgisProject(qgis_project_file_3857) - cls.project_3857.group = cls.project_group_3857 - cls.project_3857.save() + self.project_3857 = QgisProject(qgis_project_file_3857) + self.project_3857.group = self.project_group_3857 + self.project_3857.save() qgis_project_file_3857.close() file = File(open(f'{DATASOURCE_PATH}cities_scatter_plot_wrong_source_layer_id.xml', 'r')) - cls.wrong_settings_source_layer_id_xml = file.read() + self.wrong_settings_source_layer_id_xml = file.read() file.close() file = File(open(f'{DATASOURCE_PATH}countries_pie_plot_with_title.xml', 'r')) - cls.countries_plot_xml = file.read() + self.countries_plot_xml = file.read() file.close() file = File(open(f'{DATASOURCE_PATH}cities_histogram_plot.xml', 'r')) - cls.cities_histogram_plot_xml = file.read() + self.cities_histogram_plot_xml = file.read() file.close() - @classmethod - def tearDownClass(cls): - cls.project.instance.delete() - super().tearDownClass() + + def tearDown(self): + self.project.instance.delete() + super().tearDown() @@ -595,7 +594,7 @@ def test_get_qplotlywidgets4layer(self): self.assertEqual(len(widgets), 2) def _check_constraints(self, jcontent): - self.assertEqual(jcontent['results'][0]['pk'], 1) + #self.assertEqual(jcontent['results'][0]['pk'], 18) self.assertFalse(jcontent['results'][0]['selected_features_only']) self.assertFalse(jcontent['results'][0]['visible_features_only']) self.assertEqual(jcontent['results'][0]['type'], 'histogram') @@ -614,6 +613,8 @@ def test_widgets(self): self.assertEqual(jcontent['count'], 2) self._check_constraints(jcontent) + qplw_pk = jcontent['results'][0]['pk'] + # TEST API VALIDATION # ------------------- @@ -655,7 +656,7 @@ def test_widgets(self): # change type for test data['type'] = 'pie' jcontent = json.loads(self._testApiCall('qplotly-widget-api-list', [], {}, data=data).content) - self.assertEqual(jcontent['pk'], 8) + self.assertEqual(jcontent['pk'], qplw_pk + 2) self.assertEqual(jcontent['type'], 'pie') self.assertEqual(jcontent['title'], 'Test title create') @@ -671,8 +672,8 @@ def test_widgets(self): # change type for test data['type'] = 'scatter' - jcontent = json.loads(self._testApiCall('qplotly-widget-api-detail', [self.project.instance.pk, 8], {}, data=data, method='PUT').content) - self.assertEqual(jcontent['pk'], 8) + jcontent = json.loads(self._testApiCall('qplotly-widget-api-detail', [self.project.instance.pk, qplw_pk + 1], {}, data=data, method='PUT').content) + self.assertEqual(jcontent['pk'], qplw_pk + 1) self.assertEqual(jcontent['type'], 'scatter') jcontent = json.loads(self._testApiCall('qplotly-widget-api-filter-by-layer-id', [layer_pk], {}).content) @@ -681,7 +682,7 @@ def test_widgets(self): # TEST DELETE # ----------- - self._testApiCall('qplotly-widget-api-detail', [self.project.instance.pk, 8], {}, data=None, method='DELETE') + self._testApiCall('qplotly-widget-api-detail', [self.project.instance.pk, qplw_pk + 1], {}, data=None, method='DELETE') jcontent = json.loads(self._testApiCall('qplotly-widget-api-filter-by-layer-id', [layer_pk], {}).content) self.assertEqual(jcontent['count'], 2) @@ -696,7 +697,7 @@ def test_widgets(self): # change type for test jcontent = json.loads(self._testApiCall('qplotly-widget-api-list', [], {}, data=data).content) - self.assertEqual(jcontent['pk'], 9) + self.assertEqual(jcontent['pk'], qplw_pk + 3) self.assertEqual(jcontent['type'], 'pie') self.assertEqual(jcontent['title'], 'Pie countries test') diff --git a/g3w-admin/qplotly/tests/test_models.py b/g3w-admin/qplotly/tests/test_models.py index daec22a47..9f05a9ea8 100644 --- a/g3w-admin/qplotly/tests/test_models.py +++ b/g3w-admin/qplotly/tests/test_models.py @@ -32,43 +32,41 @@ def setUpClass(cls): cls.client = APIClient() - @classmethod - def setUpTestData(cls): + def setUp(self): - cls.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', + self.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group.save() + self.project_group.save() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE), 'r', encoding='utf-8')) # Replace name property with only file name without path to simulate UploadedFileWithId instance. qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project = QgisProject(qgis_project_file) - cls.project.group = cls.project_group - cls.project.save() + self.project = QgisProject(qgis_project_file) + self.project.group = self.project_group + self.project.save() qgis_project_file.close() file = File(open(f'{DATASOURCE_PATH}data_plotly_settings.xml', 'r')) - cls.histogram_countries_xml = file.read() + self.histogram_countries_xml = file.read() file.close() file = File(open(f'{DATASOURCE_PATH}cities_scatter_plot.xml', 'r')) - cls.scatter_cities_xml = file.read() + self.scatter_cities_xml = file.read() file.close() file = File(open(f'{DATASOURCE_PATH}wrong_data_plotly_settings.xml', 'r')) - cls.wrong_settings_xml = file.read() + self.wrong_settings_xml = file.read() file.close() file = File(open(f'{DATASOURCE_PATH}cities_scatter_plot_wrong_source_layer_id.xml', 'r')) - cls.wrong_settings_source_layer_id_xml = file.read() + self.wrong_settings_source_layer_id_xml = file.read() file.close() - @classmethod - def tearDownClass(cls): - cls.project.instance.delete() - super().tearDownClass() + def tearDown(self): + self.project.instance.delete() + super().tearDown() def test_widget(self): """Test QplotlyWidget model""" diff --git a/g3w-admin/qplotly/tests/test_views.py b/g3w-admin/qplotly/tests/test_views.py index 76d5bc311..f56822c4d 100644 --- a/g3w-admin/qplotly/tests/test_views.py +++ b/g3w-admin/qplotly/tests/test_views.py @@ -39,29 +39,28 @@ def setUpClass(cls): cls.client = Client() - @classmethod - def setUpTestData(cls): + def setUp(self): # main project group - cls.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', + self.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group.save() + self.project_group.save() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE), 'r', encoding='utf-8')) # Replace name property with only file name without path to simulate UploadedFileWithId instance. qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project = QgisProject(qgis_project_file) - cls.project.group = cls.project_group - cls.project.save() + self.project = QgisProject(qgis_project_file) + self.project.group = self.project_group + self.project.save() qgis_project_file.close() file = File(open(f'{DATASOURCE_PATH}countries_pie_plot_with_title.xml', 'r')) - cls.countries_plot_xml = file.read() + self.countries_plot_xml = file.read() file.close() file = File(open(f'{DATASOURCE_PATH}cities_histogram_plot.xml', 'r')) - cls.cities_histogram_plot_xml = file.read() + self.cities_histogram_plot_xml = file.read() file.close() def test_download_xml(self): diff --git a/g3w-admin/qtimeseries/tests/base.py b/g3w-admin/qtimeseries/tests/base.py index 4b52c1aeb..76f267d2e 100644 --- a/g3w-admin/qtimeseries/tests/base.py +++ b/g3w-admin/qtimeseries/tests/base.py @@ -35,22 +35,21 @@ def setUpClass(cls): cls.client = APIClient() - @classmethod - def setUpTestData(cls): - # main project group - cls.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', + def setUp(self): + # Main project group + self.project_group = CoreGroup(name='Group1', title='Group1', header_logo_img='', srid=G3WSpatialRefSys.objects.get(auth_srid=4326)) - cls.project_group.save() + self.project_group.save() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE_RASTER), 'r', encoding='utf-8')) # Replace name property with only file name without path to simulate UploadedFileWithId instance. qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project_raster = QgisProject(qgis_project_file) - cls.project_raster.group = cls.project_group - cls.project_raster.save() + self.project_raster = QgisProject(qgis_project_file) + self.project_raster.group = self.project_group + self.project_raster.save() qgis_project_file.close() qgis_project_file = File(open('{}{}{}'.format(CURRENT_PATH, TEST_BASE_PATH, QGS_FILE_RASTER_2), 'r', @@ -58,15 +57,14 @@ def setUpTestData(cls): # Replace name property with only file name without path to simulate UploadedFileWithId instance. qgis_project_file.name = qgis_project_file.name.split('/')[-1] - cls.project_raster_2 = QgisProject(qgis_project_file) - cls.project_raster_2.group = cls.project_group - cls.project_raster_2.save() + self.project_raster_2 = QgisProject(qgis_project_file) + self.project_raster_2.group = self.project_group + self.project_raster_2.save() qgis_project_file.close() - @classmethod - def tearDownClass(cls): - cls.project_raster.instance.delete() - super().tearDownClass() + def tearDown(self): + self.project_raster.instance.delete() + super().tearDown() def _testApiCall(self, view_name, args, kwargs={}, data=None, method='POST', username='admin01'): """Utility to make test calls for admin01 user""" diff --git a/g3w-admin/usersmanage/forms.py b/g3w-admin/usersmanage/forms.py index fe2b61d70..40e1ce212 100644 --- a/g3w-admin/usersmanage/forms.py +++ b/g3w-admin/usersmanage/forms.py @@ -12,7 +12,7 @@ Textarea ) from django.utils.datastructures import MultiValueDict -from django.utils.translation import ugettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.contrib.auth.forms import ( UserCreationForm, ReadOnlyPasswordHashField, @@ -26,7 +26,6 @@ from django.contrib.auth.models import User, Group as AuthGroup, Permission from django_file_form.forms import FileFormMixin, UploadedFileField from django.db.models import Q -from django.utils.functional import lazy from django.contrib.contenttypes.models import ContentType from guardian.compat import get_user_model from guardian.shortcuts import get_objects_for_user diff --git a/g3w-admin/usersmanage/signals.py b/g3w-admin/usersmanage/signals.py index 542b65171..6e9166d79 100644 --- a/g3w-admin/usersmanage/signals.py +++ b/g3w-admin/usersmanage/signals.py @@ -17,4 +17,4 @@ # Signal send after save user # Args: 'user' model User instance -after_save_user_form = django.dispatch.Signal(providing_args=['user']) \ No newline at end of file +after_save_user_form = django.dispatch.Signal() \ No newline at end of file diff --git a/g3w-admin/usersmanage/tests/test_api.py b/g3w-admin/usersmanage/tests/test_api.py index 6ca4e90d8..75ee89dd8 100644 --- a/g3w-admin/usersmanage/tests/test_api.py +++ b/g3w-admin/usersmanage/tests/test_api.py @@ -91,7 +91,6 @@ def test_list_users(self): self.assertEqual(res.data['count'], 3) - print(res.data['results']) self.assertEqual(res.data['results'][0], { "id": 7, "first_name": "", diff --git a/g3w-admin/usersmanage/tests/test_utils.py b/g3w-admin/usersmanage/tests/test_utils.py index 08f9c7c48..bb6234289 100644 --- a/g3w-admin/usersmanage/tests/test_utils.py +++ b/g3w-admin/usersmanage/tests/test_utils.py @@ -313,7 +313,6 @@ def test_get_perms_by_user_backend(self): self.test_editor2_3.userbackend.save() def fake_receiver(sender, **kwargs): - print ('passa') return [ 'add_user' ] diff --git a/g3w-admin/usersmanage/utils.py b/g3w-admin/usersmanage/utils.py index cc1962cb1..4083dd347 100644 --- a/g3w-admin/usersmanage/utils.py +++ b/g3w-admin/usersmanage/utils.py @@ -2,12 +2,17 @@ from django.contrib.auth.models import Permission, User, Group as AuthGroup from django.contrib.contenttypes.models import ContentType from django.db.models import Q -from guardian.shortcuts import get_users_with_perms, assign_perm, remove_perm, get_groups_with_perms, \ - get_perms, get_objects_for_user +from guardian.shortcuts import ( + get_users_with_perms, + assign_perm, + remove_perm, + get_groups_with_perms, + get_objects_for_user +) from guardian.models import UserObjectPermission from guardian.compat import get_user_model from crispy_forms.layout import Div, HTML, Field -from django.utils.translation import ugettext, gettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.contrib.sessions.models import Session from django.utils import timezone from .configs import * diff --git a/requirements.txt b/requirements.txt index 66015f121..8d84c1df2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,27 +1,28 @@ -Django==3.2.25 +Django==4.2.17 django-formtools==2.2 -django-crispy-forms==1.8.1 +django-crispy-forms==2.3 +crispy-bootstrap3==2024.1 django-extensions==3.1.5 #--------------------------------------------------------------------------- # django-file-form: to replace with PyPi version where this patch is present: git+https://github.com/gis3w/django-file-form.git@behind_proxy #--------------------------------------------------------------------------- django-guardian==2.2.0 -django-model-utils==4.0.0 +django-model-utils==4.5.1 django-sitetree==1.17.2 -djangorestframework==3.12.0 -djangorestframework-gis==0.18 +djangorestframework==3.15.2 +djangorestframework-gis==1.0 drf-spectacular==0.25.1 -django-downloadview==1.9 +django-downloadview==2.3.0 django-mptt==0.13.4 -django-ordered-model==3.3.0 +django-ordered-model==3.7.4 django-ajax-selects==2.2.0 django-modeltranslation==0.17.5 django-filter -django-bleach==3.0.1 +django-bleach==3.1.0 pathlib2 lxml -psycopg2-binary +psycopg[binary] pillow owslib defusedxml @@ -30,7 +31,7 @@ django-import-export==3.2.0 coverage urllib3 python-magic -celery #==5.0.2 +celery==5.4.0 deprecation huey==2.4.3 redis==4.5.4 diff --git a/settings_docker.py b/settings_docker.py index 675d846bb..3681a1c72 100644 --- a/settings_docker.py +++ b/settings_docker.py @@ -13,7 +13,7 @@ DATABASES = { 'default': { 'ENGINE': 'django.contrib.gis.db.backends.postgis', - 'NAME': 'g3w-suite', + 'NAME': 'g3w_suite', 'USER': 'docker', 'PASSWORD': 'docker', 'HOST': 'postgis', @@ -58,7 +58,7 @@ # =============================== FILEMANAGER_ROOT_PATH = DATASOURCE_PATH -ALLOWED_HOSTS = "*" +ALLOWED_HOSTS = ["*"] LOGGING = { 'version': 1,