From 265159991035f5ac63b7510bec6cfb6ad7ef5ac9 Mon Sep 17 00:00:00 2001 From: prabinoid <38830224+prabinoid@users.noreply.github.com> Date: Fri, 19 Jun 2026 14:52:46 +0545 Subject: [PATCH] test: remove legacy Flask unittest suite (tests/backend) --- Makefile | 2 +- docs/developers/development-setup.md | 2 +- docs/developers/submit-pr.md | 4 +- .../services/test_project_search_service.py | 2 +- .../unit/services/users/test_osm_service.py | 2 +- tests/backend/__init__.py | 0 tests/backend/base.py | 107 - tests/backend/helpers/__init__.py | 0 .../helpers/test_files/2d_multi_polygon.json | 37 - .../test_files/CHAI-Escuintla-West2.json | 1 - .../test_files/canned_draft_project.json | 85 - .../test_files/canned_kml_project.json | 56 - .../test_files/canned_project_detail.json | 180 - .../clipped_feature_collection.json | 1145 ------ .../test_files/feature_collection.json | 1145 ------ .../feature_collection_one_multipolygon.json | 1563 ------- .../helpers/test_files/multi_polygon.json | 77 - .../test_files/multi_polygon_dissolved.json | 77 - .../test_files/non_square_project_aoi.json | 0 .../test_files/non_square_split_results.json | 214 - .../helpers/test_files/non_square_task.json | 38 - .../backend/helpers/test_files/osm_sample.xml | 25 - .../helpers/test_files/osm_user_details.json | 47 - .../osm_user_details_changed_name.xml | 21 - .../test_files/osm_user_details_simple.xml | 13 - .../test_files/search_bbox_feature.json | 2917 -------------- .../test_files/search_bbox_result.json | 2930 -------------- .../test_files/self_intersecting_aoi.json | 121 - .../helpers/test_files/split_task.json | 154 - .../helpers/test_files/splittable_task.json | 38 - .../test_files/tasks_from_aoi_features.json | 42 - .../backend/helpers/test_files/test_aoi.json | 26 - .../helpers/test_files/test_arbitrary.json | 36 - .../backend/helpers/test_files/test_grid.json | 3576 ----------------- tests/backend/helpers/test_helpers.py | 391 -- tests/backend/integration/__init__.py | 0 tests/backend/integration/api/__init__.py | 0 .../integration/api/campaigns/__init__.py | 0 .../api/campaigns/test_resources.py | 325 -- .../integration/api/comments/__init__.py | 0 .../api/comments/test_resources.py | 318 -- .../integration/api/countries/__init__.py | 0 .../api/countries/test_resources.py | 28 - .../integration/api/interests/__init__.py | 0 .../api/interests/test_resources.py | 335 -- .../integration/api/issues/__init__.py | 0 .../integration/api/issues/test_resources.py | 216 - .../integration/api/licenses/__init__.py | 0 .../integration/api/licenses/test_actions.py | 55 - .../api/licenses/test_resources.py | 240 -- .../integration/api/notifications/__init__.py | 0 .../api/notifications/test_actions.py | 52 - .../api/notifications/test_resources.py | 477 --- .../integration/api/organisations/__init__.py | 0 .../api/organisations/test_campaigns.py | 162 - .../api/organisations/test_resources.py | 392 -- .../integration/api/projects/__init__.py | 0 .../integration/api/projects/test_actions.py | 435 -- .../api/projects/test_activities.py | 107 - .../integration/api/projects/test_campaign.py | 211 - .../api/projects/test_contributions.py | 176 - .../api/projects/test_favourites.py | 130 - .../api/projects/test_resources.py | 2321 ----------- .../api/projects/test_statistics.py | 99 - .../integration/api/system/__init__.py | 0 .../api/system/test_authentication.py | 288 -- .../integration/api/system/test_banner.py | 64 - .../integration/api/system/test_general.py | 68 - .../api/system/test_image_upload.py | 92 - .../integration/api/system/test_statistics.py | 30 - .../backend/integration/api/tasks/__init__.py | 0 .../integration/api/tasks/test_actions.py | 1724 -------- .../integration/api/tasks/test_resources.py | 628 --- .../integration/api/tasks/test_statistics.py | 264 -- .../backend/integration/api/teams/__init__.py | 0 .../integration/api/teams/test_actions.py | 480 --- .../integration/api/teams/test_resources.py | 275 -- .../backend/integration/api/users/__init__.py | 0 .../integration/api/users/test_actions.py | 309 -- .../api/users/test_openstreetmap.py | 60 - .../integration/api/users/test_resources.py | 692 ---- .../integration/api/users/test_statistics.py | 157 - .../integration/api/users/test_tasks.py | 193 - tests/backend/integration/models/__init__.py | 0 .../integration/models/postgis/__init__.py | 0 .../models/postgis/test_project.py | 130 - .../integration/models/postgis/test_user.py | 32 - .../backend/integration/services/__init__.py | 0 .../integration/services/grid/__init__.py | 0 .../services/grid/test_split_service.py | 117 - .../services/messaging/__init__.py | 0 .../services/messaging/test_chat_service.py | 149 - .../messaging/test_messaging_service.py | 241 -- .../services/messaging/test_smtp_service.py | 208 - .../services/test_favorite_service.py | 44 - .../test_featured_projects_services.py | 26 - .../services/test_interests_service.py | 91 - .../services/test_license_service.py | 42 - .../services/test_mapping_service.py | 167 - .../services/test_organisation_service.py | 205 - .../services/test_project_admin_service.py | 484 --- .../services/test_project_search_service.py | 113 - .../services/test_project_service.py | 92 - .../services/test_recommendation_service.py | 207 - .../services/test_stats_service.py | 19 - .../integration/services/test_team_service.py | 144 - .../services/test_validation_service.py | 138 - .../integration/services/users/__init__.py | 0 .../users/test_authentication_service.py | 172 - .../services/users/test_osm_service.py | 31 - .../services/users/test_user_service.py | 164 - tests/backend/unit/__init__.py | 0 tests/backend/unit/models/__init__.py | 0 tests/backend/unit/models/dtos/__init__.py | 0 .../unit/models/dtos/test_mapping_dto.py | 28 - .../unit/models/dtos/test_project_dto.py | 14 - tests/backend/unit/models/postgis/__init__.py | 0 .../unit/models/postgis/test_banner.py | 85 - .../unit/models/postgis/test_custom_editor.py | 93 - .../unit/models/postgis/test_message.py | 127 - .../unit/models/postgis/test_organisation.py | 49 - .../unit/models/postgis/test_project.py | 69 - .../unit/models/postgis/test_project_info.py | 12 - .../backend/unit/models/postgis/test_task.py | 197 - .../backend/unit/models/postgis/test_user.py | 35 - tests/backend/unit/services/__init__.py | 0 tests/backend/unit/services/grid/__init__.py | 0 .../unit/services/grid/test_grid_service.py | 159 - .../unit/services/messaging/__init__.py | 0 .../messaging/test_messaging_service.py | 97 - .../messaging/test_template_service.py | 57 - .../unit/services/test_mapping_service.py | 238 -- .../services/test_organisation_service.py | 64 - .../services/test_project_admin_service.py | 137 - .../services/test_project_search_service.py | 39 - .../unit/services/test_project_service.py | 279 -- .../services/test_recommendation_service.py | 173 - .../unit/services/test_stats_service.py | 203 - .../unit/services/test_team_service.py | 79 - .../unit/services/test_validator_service.py | 218 - tests/backend/unit/services/users/__init__.py | 0 .../users/test_authentication_service.py | 67 - .../unit/services/users/test_osm_service.py | 21 - .../unit/services/users/test_user_service.py | 84 - 144 files changed, 6 insertions(+), 32111 deletions(-) delete mode 100644 tests/backend/__init__.py delete mode 100644 tests/backend/base.py delete mode 100644 tests/backend/helpers/__init__.py delete mode 100644 tests/backend/helpers/test_files/2d_multi_polygon.json delete mode 100644 tests/backend/helpers/test_files/CHAI-Escuintla-West2.json delete mode 100644 tests/backend/helpers/test_files/canned_draft_project.json delete mode 100644 tests/backend/helpers/test_files/canned_kml_project.json delete mode 100644 tests/backend/helpers/test_files/canned_project_detail.json delete mode 100644 tests/backend/helpers/test_files/clipped_feature_collection.json delete mode 100644 tests/backend/helpers/test_files/feature_collection.json delete mode 100644 tests/backend/helpers/test_files/feature_collection_one_multipolygon.json delete mode 100644 tests/backend/helpers/test_files/multi_polygon.json delete mode 100644 tests/backend/helpers/test_files/multi_polygon_dissolved.json delete mode 100644 tests/backend/helpers/test_files/non_square_project_aoi.json delete mode 100644 tests/backend/helpers/test_files/non_square_split_results.json delete mode 100644 tests/backend/helpers/test_files/non_square_task.json delete mode 100644 tests/backend/helpers/test_files/osm_sample.xml delete mode 100644 tests/backend/helpers/test_files/osm_user_details.json delete mode 100644 tests/backend/helpers/test_files/osm_user_details_changed_name.xml delete mode 100644 tests/backend/helpers/test_files/osm_user_details_simple.xml delete mode 100644 tests/backend/helpers/test_files/search_bbox_feature.json delete mode 100644 tests/backend/helpers/test_files/search_bbox_result.json delete mode 100644 tests/backend/helpers/test_files/self_intersecting_aoi.json delete mode 100644 tests/backend/helpers/test_files/split_task.json delete mode 100644 tests/backend/helpers/test_files/splittable_task.json delete mode 100644 tests/backend/helpers/test_files/tasks_from_aoi_features.json delete mode 100644 tests/backend/helpers/test_files/test_aoi.json delete mode 100644 tests/backend/helpers/test_files/test_arbitrary.json delete mode 100644 tests/backend/helpers/test_files/test_grid.json delete mode 100644 tests/backend/helpers/test_helpers.py delete mode 100644 tests/backend/integration/__init__.py delete mode 100644 tests/backend/integration/api/__init__.py delete mode 100644 tests/backend/integration/api/campaigns/__init__.py delete mode 100644 tests/backend/integration/api/campaigns/test_resources.py delete mode 100644 tests/backend/integration/api/comments/__init__.py delete mode 100644 tests/backend/integration/api/comments/test_resources.py delete mode 100644 tests/backend/integration/api/countries/__init__.py delete mode 100644 tests/backend/integration/api/countries/test_resources.py delete mode 100644 tests/backend/integration/api/interests/__init__.py delete mode 100644 tests/backend/integration/api/interests/test_resources.py delete mode 100644 tests/backend/integration/api/issues/__init__.py delete mode 100644 tests/backend/integration/api/issues/test_resources.py delete mode 100644 tests/backend/integration/api/licenses/__init__.py delete mode 100644 tests/backend/integration/api/licenses/test_actions.py delete mode 100644 tests/backend/integration/api/licenses/test_resources.py delete mode 100644 tests/backend/integration/api/notifications/__init__.py delete mode 100644 tests/backend/integration/api/notifications/test_actions.py delete mode 100644 tests/backend/integration/api/notifications/test_resources.py delete mode 100644 tests/backend/integration/api/organisations/__init__.py delete mode 100644 tests/backend/integration/api/organisations/test_campaigns.py delete mode 100644 tests/backend/integration/api/organisations/test_resources.py delete mode 100644 tests/backend/integration/api/projects/__init__.py delete mode 100644 tests/backend/integration/api/projects/test_actions.py delete mode 100644 tests/backend/integration/api/projects/test_activities.py delete mode 100644 tests/backend/integration/api/projects/test_campaign.py delete mode 100644 tests/backend/integration/api/projects/test_contributions.py delete mode 100644 tests/backend/integration/api/projects/test_favourites.py delete mode 100644 tests/backend/integration/api/projects/test_resources.py delete mode 100644 tests/backend/integration/api/projects/test_statistics.py delete mode 100644 tests/backend/integration/api/system/__init__.py delete mode 100644 tests/backend/integration/api/system/test_authentication.py delete mode 100644 tests/backend/integration/api/system/test_banner.py delete mode 100644 tests/backend/integration/api/system/test_general.py delete mode 100644 tests/backend/integration/api/system/test_image_upload.py delete mode 100644 tests/backend/integration/api/system/test_statistics.py delete mode 100644 tests/backend/integration/api/tasks/__init__.py delete mode 100644 tests/backend/integration/api/tasks/test_actions.py delete mode 100644 tests/backend/integration/api/tasks/test_resources.py delete mode 100644 tests/backend/integration/api/tasks/test_statistics.py delete mode 100644 tests/backend/integration/api/teams/__init__.py delete mode 100644 tests/backend/integration/api/teams/test_actions.py delete mode 100644 tests/backend/integration/api/teams/test_resources.py delete mode 100644 tests/backend/integration/api/users/__init__.py delete mode 100644 tests/backend/integration/api/users/test_actions.py delete mode 100644 tests/backend/integration/api/users/test_openstreetmap.py delete mode 100644 tests/backend/integration/api/users/test_resources.py delete mode 100644 tests/backend/integration/api/users/test_statistics.py delete mode 100644 tests/backend/integration/api/users/test_tasks.py delete mode 100644 tests/backend/integration/models/__init__.py delete mode 100644 tests/backend/integration/models/postgis/__init__.py delete mode 100644 tests/backend/integration/models/postgis/test_project.py delete mode 100644 tests/backend/integration/models/postgis/test_user.py delete mode 100644 tests/backend/integration/services/__init__.py delete mode 100644 tests/backend/integration/services/grid/__init__.py delete mode 100644 tests/backend/integration/services/grid/test_split_service.py delete mode 100644 tests/backend/integration/services/messaging/__init__.py delete mode 100644 tests/backend/integration/services/messaging/test_chat_service.py delete mode 100644 tests/backend/integration/services/messaging/test_messaging_service.py delete mode 100644 tests/backend/integration/services/messaging/test_smtp_service.py delete mode 100644 tests/backend/integration/services/test_favorite_service.py delete mode 100644 tests/backend/integration/services/test_featured_projects_services.py delete mode 100644 tests/backend/integration/services/test_interests_service.py delete mode 100644 tests/backend/integration/services/test_license_service.py delete mode 100644 tests/backend/integration/services/test_mapping_service.py delete mode 100644 tests/backend/integration/services/test_organisation_service.py delete mode 100644 tests/backend/integration/services/test_project_admin_service.py delete mode 100644 tests/backend/integration/services/test_project_search_service.py delete mode 100644 tests/backend/integration/services/test_project_service.py delete mode 100644 tests/backend/integration/services/test_recommendation_service.py delete mode 100644 tests/backend/integration/services/test_stats_service.py delete mode 100644 tests/backend/integration/services/test_team_service.py delete mode 100644 tests/backend/integration/services/test_validation_service.py delete mode 100644 tests/backend/integration/services/users/__init__.py delete mode 100644 tests/backend/integration/services/users/test_authentication_service.py delete mode 100644 tests/backend/integration/services/users/test_osm_service.py delete mode 100644 tests/backend/integration/services/users/test_user_service.py delete mode 100644 tests/backend/unit/__init__.py delete mode 100644 tests/backend/unit/models/__init__.py delete mode 100644 tests/backend/unit/models/dtos/__init__.py delete mode 100644 tests/backend/unit/models/dtos/test_mapping_dto.py delete mode 100644 tests/backend/unit/models/dtos/test_project_dto.py delete mode 100644 tests/backend/unit/models/postgis/__init__.py delete mode 100644 tests/backend/unit/models/postgis/test_banner.py delete mode 100644 tests/backend/unit/models/postgis/test_custom_editor.py delete mode 100644 tests/backend/unit/models/postgis/test_message.py delete mode 100644 tests/backend/unit/models/postgis/test_organisation.py delete mode 100644 tests/backend/unit/models/postgis/test_project.py delete mode 100644 tests/backend/unit/models/postgis/test_project_info.py delete mode 100644 tests/backend/unit/models/postgis/test_task.py delete mode 100644 tests/backend/unit/models/postgis/test_user.py delete mode 100644 tests/backend/unit/services/__init__.py delete mode 100644 tests/backend/unit/services/grid/__init__.py delete mode 100644 tests/backend/unit/services/grid/test_grid_service.py delete mode 100644 tests/backend/unit/services/messaging/__init__.py delete mode 100644 tests/backend/unit/services/messaging/test_messaging_service.py delete mode 100644 tests/backend/unit/services/messaging/test_template_service.py delete mode 100644 tests/backend/unit/services/test_mapping_service.py delete mode 100644 tests/backend/unit/services/test_organisation_service.py delete mode 100644 tests/backend/unit/services/test_project_admin_service.py delete mode 100644 tests/backend/unit/services/test_project_search_service.py delete mode 100644 tests/backend/unit/services/test_project_service.py delete mode 100644 tests/backend/unit/services/test_recommendation_service.py delete mode 100644 tests/backend/unit/services/test_stats_service.py delete mode 100644 tests/backend/unit/services/test_team_service.py delete mode 100644 tests/backend/unit/services/test_validator_service.py delete mode 100644 tests/backend/unit/services/users/__init__.py delete mode 100644 tests/backend/unit/services/users/test_authentication_service.py delete mode 100644 tests/backend/unit/services/users/test_osm_service.py delete mode 100644 tests/backend/unit/services/users/test_user_service.py diff --git a/Makefile b/Makefile index 6c49dc9f9a..8ea3f06464 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ test-frontend: docker-compose exec frontend sh -c "cd /usr/src/app/frontend && CI=true npm test" test-backend: - docker-compose exec backend sh -c "python -m unittest discover tests/backend" + docker-compose exec tm-backend sh -c "pytest tests/api -p no:warnings" fetch: ifndef PRNUMBER diff --git a/docs/developers/development-setup.md b/docs/developers/development-setup.md index 2a360598a4..27c2913ff5 100644 --- a/docs/developers/development-setup.md +++ b/docs/developers/development-setup.md @@ -281,7 +281,7 @@ The project includes a suite of Unit and Integration tests that you should run after any changes. ``` -python3 -m unittest discover tests/backend +pytest tests/api ``` or ``` diff --git a/docs/developers/submit-pr.md b/docs/developers/submit-pr.md index 15a4fb265f..d882482721 100644 --- a/docs/developers/submit-pr.md +++ b/docs/developers/submit-pr.md @@ -17,11 +17,11 @@ mode for more than a short time runs the risk of being ignored. The backend has unit tests which can be run manually. These are the same tests the CI support runs. To run all the tests, do this: - python3 -m unittest discover ./tests + pytest tests/api To run a specific test case, you can do it like this: - python -m unittest tests/backend/integration/services/test_license_service.py + pytest tests/api/integration/services/test_license_service.py Whenever you add a new endpoint in the backend, you should add a test case for it. diff --git a/tests/api/integration/services/test_project_search_service.py b/tests/api/integration/services/test_project_search_service.py index 4ed9bbb4a5..a90148b2c1 100644 --- a/tests/api/integration/services/test_project_search_service.py +++ b/tests/api/integration/services/test_project_search_service.py @@ -5,7 +5,7 @@ from backend.models.postgis.project import ProjectInfo, Project from backend.models.dtos.project_dto import ProjectSearchBBoxDTO from backend.models.postgis.user import User -from tests.backend.helpers.test_helpers import get_canned_json +from tests.api.helpers.test_helpers import get_canned_json from unittest.mock import patch, MagicMock, AsyncMock from shapely.geometry import Polygon, box import shapely.wkt diff --git a/tests/api/unit/services/users/test_osm_service.py b/tests/api/unit/services/users/test_osm_service.py index 4753817fe8..27adefd3f0 100644 --- a/tests/api/unit/services/users/test_osm_service.py +++ b/tests/api/unit/services/users/test_osm_service.py @@ -1,6 +1,6 @@ import pytest from backend.services.users.osm_service import OSMService, OSMServiceError -from tests.backend.helpers.test_helpers import get_canned_osm_user_json_details +from tests.api.helpers.test_helpers import get_canned_osm_user_json_details class TestOsmService: diff --git a/tests/backend/__init__.py b/tests/backend/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/base.py b/tests/backend/base.py deleted file mode 100644 index a322aabe80..0000000000 --- a/tests/backend/base.py +++ /dev/null @@ -1,107 +0,0 @@ -import os -import unittest -from typing import Optional - -import geojson -from flask import Flask -from flask_sqlalchemy import SQLAlchemy -from shapely.geometry import shape - -from backend import create_app, db - - -def clean_db(db): - for table in reversed(db.metadata.sorted_tables): - db.session.execute(table.delete()) - - -class BaseTestCase(unittest.TestCase): - DEFAULT_PRECISION: Optional[int] - app: Optional[Flask] - db: Optional[SQLAlchemy] - - @classmethod - def setUpClass(cls): - super(BaseTestCase, cls).setUpClass() - cls.DEFAULT_PRECISION = geojson.geometry.DEFAULT_PRECISION - # OSM uses 7, which means the worst error of longitude is ±5.56595 mm - # at the equator. The worst error for 6 decimal places of longitude is - # ±5.56595 cm at the equator. This is the default, and realistically - # is probably more than enough for the TM. - geojson.geometry.DEFAULT_PRECISION = 7 - - # Set the "TM_ENVIRONMENT" environment variable to "test" to use the test configuration - os.environ["TM_ENVIRONMENT"] = "test" - cls.app = create_app("backend.config.TestEnvironmentConfig") - cls.app.config.update({"TESTING": True}) - cls.db = db - cls.db.app = cls.app - with cls.app.app_context(): - cls.db.create_all() - - @classmethod - def tearDownClass(cls): - geojson.geometry.DEFAULT_PRECISION = cls.DEFAULT_PRECISION - with cls.app.app_context(): - db.session.remove() - cls.db.drop_all() - if cls.app in cls.db.engines: - cls.db.engines[cls.app].dispose() - if None in cls.db.engines: - cls.db.engines[None].dispose() - super(BaseTestCase, cls).tearDownClass() - - def setUp(self): - super(BaseTestCase, self).setUp() - self.client = self.app.test_client() - self.app_context = self.app.app_context() - self.app_context.push() - clean_db(self.db) - - def tearDown(self): - super(BaseTestCase, self).tearDown() - self.db.session.rollback() - self.db.session.close() - self.app_context.pop() - - # Code modified from https://github.com/larsbutler/oq-engine/blob/master/tests/utils/helpers.py - # Note: Was originally in test_resources.py (author Aadesh-Baral) - def assertDeepAlmostEqual(self, expected, actual, *args, **kwargs): - """ - Assert that two complex structures have almost equal contents. - - Compares lists, dicts and tuples recursively. Checks numeric values - using test_case's :py:meth:`unittest.TestCase.assertAlmostEqual` and - checks all other values with :py:meth:`unittest.TestCase.assertEqual`. - Accepts additional positional and keyword arguments and pass those - intact to assertAlmostEqual() (that's how you specify comparison - precision). - - :type test_case: :py:class:`unittest.TestCase` object - """ - kwargs.pop("__trace", "ROOT") - if ( - hasattr(expected, "__geo_interface__") - and hasattr(actual, "__geo_interface__") - and expected.__geo_interface__["type"] == actual.__geo_interface__["type"] - and expected.__geo_interface__["type"] - not in ["Feature", "FeatureCollection"] - ): - shape_expected = shape(expected) - shape_actual = shape(actual) - assert shape_expected.equals(shape_actual) - elif isinstance(expected, (int, float, complex)): - self.assertAlmostEqual(expected, actual, *args, **kwargs) - elif isinstance(expected, (list, tuple)): - self.assertEqual(len(expected), len(actual)) - for index in range(len(expected)): - v1, v2 = expected[index], actual[index] - self.assertDeepAlmostEqual(v1, v2, __trace=repr(index), *args, **kwargs) - elif isinstance(expected, dict): - self.assertEqual(set(expected), set(actual)) - for key in expected: - self.assertDeepAlmostEqual( - expected[key], actual[key], __trace=repr(key), *args, **kwargs - ) - else: - self.assertEqual(expected, actual) diff --git a/tests/backend/helpers/__init__.py b/tests/backend/helpers/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/helpers/test_files/2d_multi_polygon.json b/tests/backend/helpers/test_files/2d_multi_polygon.json deleted file mode 100644 index 164125cc5f..0000000000 --- a/tests/backend/helpers/test_files/2d_multi_polygon.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "coordinates": [ - [ - [ - [ - -4.65996216497632, - 55.95041925350509 - ], - [ - -4.95173413390339, - 56.2627945145455 - ], - [ - -4.67367146099783, - 56.2434516969104 - ], - [ - -4.66709656284914, - 56.2435936767028 - ], - [ - -4.0046243330544, - 56.03981437664169 - ], - [ - -4.35742797997559, - 55.48727395069889 - ], - [ - -4.65996216497632, - 55.95041925350509 - ] - ] - ] - ], - "type": "MultiPolygon" -} diff --git a/tests/backend/helpers/test_files/CHAI-Escuintla-West2.json b/tests/backend/helpers/test_files/CHAI-Escuintla-West2.json deleted file mode 100644 index eec661d63c..0000000000 --- a/tests/backend/helpers/test_files/CHAI-Escuintla-West2.json +++ /dev/null @@ -1 +0,0 @@ -{"areaOfInterest":{"type":"FeatureCollection","features":[{"type":"Feature","id":"way/-203564","geometry":{"type":"LineString","coordinates":[[-10127048.178416166,1617084.2643527186],[-10127124.615444696,1564294.9416937805],[-10134672.771987133,1564333.1602070213],[-10139899.153796503,1564562.4712926599],[-10145603.267032227,1565135.7490041214],[-10150953.859012537,1565699.4720884543],[-10154116.441057198,1566205.8674002888],[-10162018.118856166,1567973.4736797952],[-10164273.011190526,1568575.4152773896],[-10171639.629792018,1571585.1232656306],[-10178710.054908102,1574566.1673690565],[-10183783.562660413,1576926.1606175983],[-10189716.986981722,1579343.4816372513],[-10189134.154640723,1580021.8602626226],[-10189640.549953194,1581149.3064306113],[-10189248.810182959,1582228.9794543462],[-10189363.465725195,1583595.29133491],[-10187490.758532364,1585200.4689291308],[-10186497.07716483,1586604.99932385],[-10186076.673509594,1588028.6389762075],[-10184366.395001413,1589519.1610274045],[-10183888.663575057,1592051.13758973],[-10181691.099011812,1594200.9290093365],[-10180936.28335746,1595271.047406339],[-10180668.753758166,1596197.8463731967],[-10179980.820503633,1596885.7796285297],[-10179933.047361221,1597545.0489974308],[-10180525.434329813,1598080.108195309],[-10179684.627019336,1598538.73036506],[-10179598.635362104,1599006.907163535],[-10180143.249188283,1600086.580187673],[-10180019.03901734,1602064.3882947403],[-10180334.341759047,1602838.3132062345],[-10180171.9130744,1603354.263147198],[-10179942.601989927,1603545.3557177363],[-10180620.980615752,1604997.6592547125],[-10181442.678669931,1605045.4323972866],[-10181328.023126582,1605666.4832528231],[-10180592.316729637,1606402.1896499498],[-10180754.745415399,1607797.1654164798],[-10181165.594441932,1608523.3171851905],[-10180955.392613756,1609536.1078099879],[-10179980.820503633,1610204.9318074128],[-10179512.64370487,1610997.9659759416],[-10178442.525308808,1611303.7140886895],[-10174018.73229732,1612870.6731685624],[-10173273.47127167,1612813.3453974952],[-10173111.042587021,1613176.4212819359],[-10172919.950016256,1614141.4387640653],[-10172776.630587902,1615240.2210453018],[-10171916.714020018,1615536.414529353],[-10171649.184420723,1617246.6930375884],[-10170598.175282072,1617514.222636646],[-10170177.77162572,1617944.1809211902],[-10168821.014374068,1617982.3994346226],[-10166518.348897293,1619950.6529135099],[-10166059.726727236,1619998.4260565552],[-10166069.28135594,1619750.0057145548],[-10167330.492322769,1617686.2059509377],[-10166986.525694946,1617437.785608549],[-10167273.16455165,1616960.0541812328],[-10167340.046951473,1616224.3477844433],[-10167999.316319888,1614647.8340763669],[-10167550.248778535,1613243.3036815731],[-10168534.37551736,1611676.3446018011],[-10168123.526490832,1610625.3354631204],[-10167043.853466062,1611246.386317547],[-10161425.731887572,1609660.3179806576],[-10161263.30320181,1611208.1678030351],[-10160776.017146748,1611896.1010576806],[-10159858.772807743,1612134.9667713104],[-10159858.772807743,1612861.118539615],[-10158635.780354623,1612746.4629975522],[-10158588.00721221,1612498.0426552794],[-10159381.041380275,1610816.428033054],[-10159228.16732433,1610071.1670079106],[-10159533.915437331,1609106.1495251525],[-10147571.520510998,1606937.248847834],[-10147151.116854647,1607233.4423329392],[-10146587.393771054,1606660.1646199096],[-10146358.082686583,1607099.6775324112],[-10146252.98177305,1608074.2496439232],[-10146482.292857524,1608446.8801567464],[-10146243.427144347,1609306.7967242857],[-10145889.905888932,1610281.368835586],[-10145373.955947755,1611074.4030037387],[-10144619.1402934,1611064.848375511],[-10144399.383836519,1612058.529743294],[-10144284.728294283,1612268.731571024],[-10144466.266236342,1613558.6064233307],[-10144236.95515187,1615230.6664169363],[-10144733.795835637,1615756.1709864808],[-10144819.78749287,1616673.4153254433],[-10145373.955947755,1617198.9198945775],[-10143549.021897338,1618995.1900599198],[-10143185.946013218,1619979.3167994628],[-10141943.844302688,1621307.4101653951],[-10141246.356420564,1621603.6036501292],[-10140749.515735684,1621412.5110790848],[-10140567.977793625,1620896.5611379454],[-10140099.800995972,1620781.9055963007],[-10139536.077912383,1620285.0649124421],[-10138943.690942677,1620829.678738686],[-10137902.236432731,1622119.553590554],[-10136669.689352019,1622367.9739328555],[-10135895.764440253,1623428.5377007416],[-10133717.309134422,1623132.3442154143],[-10133354.23324919,1621985.7887918265],[-10133698.199877013,1620848.7879962025],[-10132035.694511242,1621536.7212505806],[-10131768.164913062,1622625.948903151],[-10131156.668685947,1622836.1507315093],[-10131022.903887413,1623973.1515267442],[-10129933.67623394,1624670.6394095276],[-10129675.701263351,1624326.672782828],[-10128691.574524524,1623447.6469578946],[-10128825.339324169,1622482.6294750923],[-10128051.414412405,1622367.9739328555],[-10127344.371900463,1621125.8722229986],[-10127554.573728638,1619683.1233138966],[-10127048.178416166,1617084.2643527186]]},"properties":null}]},"clipToAoi":true,"grid":{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1562984.3540953137],[-10189973.112928126,1565430.3390000015],[-10187527.128023438,1565430.3390000015],[-10187527.128023438,1562984.3540953137],[-10189973.112928126,1562984.3540953137]]]]},"properties":{"x":4026,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1565430.3390000015],[-10189973.112928126,1567876.3239046894],[-10187527.128023438,1567876.3239046894],[-10187527.128023438,1565430.3390000015],[-10189973.112928126,1565430.3390000015]]]]},"properties":{"x":4026,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1567876.3239046894],[-10189973.112928126,1570322.3088093735],[-10187527.128023438,1570322.3088093735],[-10187527.128023438,1567876.3239046894],[-10189973.112928126,1567876.3239046894]]]]},"properties":{"x":4026,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1570322.3088093735],[-10189973.112928126,1572768.2937140614],[-10187527.128023438,1572768.2937140614],[-10187527.128023438,1570322.3088093735],[-10189973.112928126,1570322.3088093735]]]]},"properties":{"x":4026,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1572768.2937140614],[-10189973.112928126,1575214.2786187492],[-10187527.128023438,1575214.2786187492],[-10187527.128023438,1572768.2937140614],[-10189973.112928126,1572768.2937140614]]]]},"properties":{"x":4026,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1575214.2786187492],[-10189973.112928126,1577660.263523437],[-10187527.128023438,1577660.263523437],[-10187527.128023438,1575214.2786187492],[-10189973.112928126,1575214.2786187492]]]]},"properties":{"x":4026,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1577660.263523437],[-10189973.112928126,1580106.248428125],[-10187527.128023438,1580106.248428125],[-10187527.128023438,1577660.263523437],[-10189973.112928126,1577660.263523437]]]]},"properties":{"x":4026,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1580106.248428125],[-10189973.112928126,1582552.2333328128],[-10187527.128023438,1582552.2333328128],[-10187527.128023438,1580106.248428125],[-10189973.112928126,1580106.248428125]]]]},"properties":{"x":4026,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1582552.2333328128],[-10189973.112928126,1584998.2182375006],[-10187527.128023438,1584998.2182375006],[-10187527.128023438,1582552.2333328128],[-10189973.112928126,1582552.2333328128]]]]},"properties":{"x":4026,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1584998.2182375006],[-10189973.112928126,1587444.2031421885],[-10187527.128023438,1587444.2031421885],[-10187527.128023438,1584998.2182375006],[-10189973.112928126,1584998.2182375006]]]]},"properties":{"x":4026,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1587444.2031421885],[-10189973.112928126,1589890.1880468763],[-10187527.128023438,1589890.1880468763],[-10187527.128023438,1587444.2031421885],[-10189973.112928126,1587444.2031421885]]]]},"properties":{"x":4026,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1589890.1880468763],[-10189973.112928126,1592336.1729515642],[-10187527.128023438,1592336.1729515642],[-10187527.128023438,1589890.1880468763],[-10189973.112928126,1589890.1880468763]]]]},"properties":{"x":4026,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1592336.1729515642],[-10189973.112928126,1594782.1578562483],[-10187527.128023438,1594782.1578562483],[-10187527.128023438,1592336.1729515642],[-10189973.112928126,1592336.1729515642]]]]},"properties":{"x":4026,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1594782.1578562483],[-10189973.112928126,1597228.1427609362],[-10187527.128023438,1597228.1427609362],[-10187527.128023438,1594782.1578562483],[-10189973.112928126,1594782.1578562483]]]]},"properties":{"x":4026,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1597228.1427609362],[-10189973.112928126,1599674.127665624],[-10187527.128023438,1599674.127665624],[-10187527.128023438,1597228.1427609362],[-10189973.112928126,1597228.1427609362]]]]},"properties":{"x":4026,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1599674.127665624],[-10189973.112928126,1602120.1125703119],[-10187527.128023438,1602120.1125703119],[-10187527.128023438,1599674.127665624],[-10189973.112928126,1599674.127665624]]]]},"properties":{"x":4026,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1602120.1125703119],[-10189973.112928126,1604566.0974749997],[-10187527.128023438,1604566.0974749997],[-10187527.128023438,1602120.1125703119],[-10189973.112928126,1602120.1125703119]]]]},"properties":{"x":4026,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1604566.0974749997],[-10189973.112928126,1607012.0823796876],[-10187527.128023438,1607012.0823796876],[-10187527.128023438,1604566.0974749997],[-10189973.112928126,1604566.0974749997]]]]},"properties":{"x":4026,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1607012.0823796876],[-10189973.112928126,1609458.0672843754],[-10187527.128023438,1609458.0672843754],[-10187527.128023438,1607012.0823796876],[-10189973.112928126,1607012.0823796876]]]]},"properties":{"x":4026,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1609458.0672843754],[-10189973.112928126,1611904.0521890633],[-10187527.128023438,1611904.0521890633],[-10187527.128023438,1609458.0672843754],[-10189973.112928126,1609458.0672843754]]]]},"properties":{"x":4026,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1611904.0521890633],[-10189973.112928126,1614350.0370937511],[-10187527.128023438,1614350.0370937511],[-10187527.128023438,1611904.0521890633],[-10189973.112928126,1611904.0521890633]]]]},"properties":{"x":4026,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1614350.0370937511],[-10189973.112928126,1616796.021998439],[-10187527.128023438,1616796.021998439],[-10187527.128023438,1614350.0370937511],[-10189973.112928126,1614350.0370937511]]]]},"properties":{"x":4026,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1616796.021998439],[-10189973.112928126,1619242.0069031268],[-10187527.128023438,1619242.0069031268],[-10187527.128023438,1616796.021998439],[-10189973.112928126,1616796.021998439]]]]},"properties":{"x":4026,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1619242.0069031268],[-10189973.112928126,1621687.991807811],[-10187527.128023438,1621687.991807811],[-10187527.128023438,1619242.0069031268],[-10189973.112928126,1619242.0069031268]]]]},"properties":{"x":4026,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1621687.991807811],[-10189973.112928126,1624133.9767124988],[-10187527.128023438,1624133.9767124988],[-10187527.128023438,1621687.991807811],[-10189973.112928126,1621687.991807811]]]]},"properties":{"x":4026,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10189973.112928126,1624133.9767124988],[-10189973.112928126,1626579.9616171867],[-10187527.128023438,1626579.9616171867],[-10187527.128023438,1624133.9767124988],[-10189973.112928126,1624133.9767124988]]]]},"properties":{"x":4026,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1562984.3540953137],[-10187527.128023438,1565430.3390000015],[-10185081.14311875,1565430.3390000015],[-10185081.14311875,1562984.3540953137],[-10187527.128023438,1562984.3540953137]]]]},"properties":{"x":4027,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1565430.3390000015],[-10187527.128023438,1567876.3239046894],[-10185081.14311875,1567876.3239046894],[-10185081.14311875,1565430.3390000015],[-10187527.128023438,1565430.3390000015]]]]},"properties":{"x":4027,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1567876.3239046894],[-10187527.128023438,1570322.3088093735],[-10185081.14311875,1570322.3088093735],[-10185081.14311875,1567876.3239046894],[-10187527.128023438,1567876.3239046894]]]]},"properties":{"x":4027,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1570322.3088093735],[-10187527.128023438,1572768.2937140614],[-10185081.14311875,1572768.2937140614],[-10185081.14311875,1570322.3088093735],[-10187527.128023438,1570322.3088093735]]]]},"properties":{"x":4027,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1572768.2937140614],[-10187527.128023438,1575214.2786187492],[-10185081.14311875,1575214.2786187492],[-10185081.14311875,1572768.2937140614],[-10187527.128023438,1572768.2937140614]]]]},"properties":{"x":4027,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1575214.2786187492],[-10187527.128023438,1577660.263523437],[-10185081.14311875,1577660.263523437],[-10185081.14311875,1575214.2786187492],[-10187527.128023438,1575214.2786187492]]]]},"properties":{"x":4027,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1577660.263523437],[-10187527.128023438,1580106.248428125],[-10185081.14311875,1580106.248428125],[-10185081.14311875,1577660.263523437],[-10187527.128023438,1577660.263523437]]]]},"properties":{"x":4027,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1580106.248428125],[-10187527.128023438,1582552.2333328128],[-10185081.14311875,1582552.2333328128],[-10185081.14311875,1580106.248428125],[-10187527.128023438,1580106.248428125]]]]},"properties":{"x":4027,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1582552.2333328128],[-10187527.128023438,1584998.2182375006],[-10185081.14311875,1584998.2182375006],[-10185081.14311875,1582552.2333328128],[-10187527.128023438,1582552.2333328128]]]]},"properties":{"x":4027,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1584998.2182375006],[-10187527.128023438,1587444.2031421885],[-10185081.14311875,1587444.2031421885],[-10185081.14311875,1584998.2182375006],[-10187527.128023438,1584998.2182375006]]]]},"properties":{"x":4027,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1587444.2031421885],[-10187527.128023438,1589890.1880468763],[-10185081.14311875,1589890.1880468763],[-10185081.14311875,1587444.2031421885],[-10187527.128023438,1587444.2031421885]]]]},"properties":{"x":4027,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1589890.1880468763],[-10187527.128023438,1592336.1729515642],[-10185081.14311875,1592336.1729515642],[-10185081.14311875,1589890.1880468763],[-10187527.128023438,1589890.1880468763]]]]},"properties":{"x":4027,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1592336.1729515642],[-10187527.128023438,1594782.1578562483],[-10185081.14311875,1594782.1578562483],[-10185081.14311875,1592336.1729515642],[-10187527.128023438,1592336.1729515642]]]]},"properties":{"x":4027,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1594782.1578562483],[-10187527.128023438,1597228.1427609362],[-10185081.14311875,1597228.1427609362],[-10185081.14311875,1594782.1578562483],[-10187527.128023438,1594782.1578562483]]]]},"properties":{"x":4027,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1597228.1427609362],[-10187527.128023438,1599674.127665624],[-10185081.14311875,1599674.127665624],[-10185081.14311875,1597228.1427609362],[-10187527.128023438,1597228.1427609362]]]]},"properties":{"x":4027,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1599674.127665624],[-10187527.128023438,1602120.1125703119],[-10185081.14311875,1602120.1125703119],[-10185081.14311875,1599674.127665624],[-10187527.128023438,1599674.127665624]]]]},"properties":{"x":4027,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1602120.1125703119],[-10187527.128023438,1604566.0974749997],[-10185081.14311875,1604566.0974749997],[-10185081.14311875,1602120.1125703119],[-10187527.128023438,1602120.1125703119]]]]},"properties":{"x":4027,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1604566.0974749997],[-10187527.128023438,1607012.0823796876],[-10185081.14311875,1607012.0823796876],[-10185081.14311875,1604566.0974749997],[-10187527.128023438,1604566.0974749997]]]]},"properties":{"x":4027,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1607012.0823796876],[-10187527.128023438,1609458.0672843754],[-10185081.14311875,1609458.0672843754],[-10185081.14311875,1607012.0823796876],[-10187527.128023438,1607012.0823796876]]]]},"properties":{"x":4027,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1609458.0672843754],[-10187527.128023438,1611904.0521890633],[-10185081.14311875,1611904.0521890633],[-10185081.14311875,1609458.0672843754],[-10187527.128023438,1609458.0672843754]]]]},"properties":{"x":4027,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1611904.0521890633],[-10187527.128023438,1614350.0370937511],[-10185081.14311875,1614350.0370937511],[-10185081.14311875,1611904.0521890633],[-10187527.128023438,1611904.0521890633]]]]},"properties":{"x":4027,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1614350.0370937511],[-10187527.128023438,1616796.021998439],[-10185081.14311875,1616796.021998439],[-10185081.14311875,1614350.0370937511],[-10187527.128023438,1614350.0370937511]]]]},"properties":{"x":4027,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1616796.021998439],[-10187527.128023438,1619242.0069031268],[-10185081.14311875,1619242.0069031268],[-10185081.14311875,1616796.021998439],[-10187527.128023438,1616796.021998439]]]]},"properties":{"x":4027,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1619242.0069031268],[-10187527.128023438,1621687.991807811],[-10185081.14311875,1621687.991807811],[-10185081.14311875,1619242.0069031268],[-10187527.128023438,1619242.0069031268]]]]},"properties":{"x":4027,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1621687.991807811],[-10187527.128023438,1624133.9767124988],[-10185081.14311875,1624133.9767124988],[-10185081.14311875,1621687.991807811],[-10187527.128023438,1621687.991807811]]]]},"properties":{"x":4027,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10187527.128023438,1624133.9767124988],[-10187527.128023438,1626579.9616171867],[-10185081.14311875,1626579.9616171867],[-10185081.14311875,1624133.9767124988],[-10187527.128023438,1624133.9767124988]]]]},"properties":{"x":4027,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1562984.3540953137],[-10185081.14311875,1565430.3390000015],[-10182635.158214062,1565430.3390000015],[-10182635.158214062,1562984.3540953137],[-10185081.14311875,1562984.3540953137]]]]},"properties":{"x":4028,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1565430.3390000015],[-10185081.14311875,1567876.3239046894],[-10182635.158214062,1567876.3239046894],[-10182635.158214062,1565430.3390000015],[-10185081.14311875,1565430.3390000015]]]]},"properties":{"x":4028,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1567876.3239046894],[-10185081.14311875,1570322.3088093735],[-10182635.158214062,1570322.3088093735],[-10182635.158214062,1567876.3239046894],[-10185081.14311875,1567876.3239046894]]]]},"properties":{"x":4028,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1570322.3088093735],[-10185081.14311875,1572768.2937140614],[-10182635.158214062,1572768.2937140614],[-10182635.158214062,1570322.3088093735],[-10185081.14311875,1570322.3088093735]]]]},"properties":{"x":4028,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1572768.2937140614],[-10185081.14311875,1575214.2786187492],[-10182635.158214062,1575214.2786187492],[-10182635.158214062,1572768.2937140614],[-10185081.14311875,1572768.2937140614]]]]},"properties":{"x":4028,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1575214.2786187492],[-10185081.14311875,1577660.263523437],[-10182635.158214062,1577660.263523437],[-10182635.158214062,1575214.2786187492],[-10185081.14311875,1575214.2786187492]]]]},"properties":{"x":4028,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1577660.263523437],[-10185081.14311875,1580106.248428125],[-10182635.158214062,1580106.248428125],[-10182635.158214062,1577660.263523437],[-10185081.14311875,1577660.263523437]]]]},"properties":{"x":4028,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1580106.248428125],[-10185081.14311875,1582552.2333328128],[-10182635.158214062,1582552.2333328128],[-10182635.158214062,1580106.248428125],[-10185081.14311875,1580106.248428125]]]]},"properties":{"x":4028,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1582552.2333328128],[-10185081.14311875,1584998.2182375006],[-10182635.158214062,1584998.2182375006],[-10182635.158214062,1582552.2333328128],[-10185081.14311875,1582552.2333328128]]]]},"properties":{"x":4028,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1584998.2182375006],[-10185081.14311875,1587444.2031421885],[-10182635.158214062,1587444.2031421885],[-10182635.158214062,1584998.2182375006],[-10185081.14311875,1584998.2182375006]]]]},"properties":{"x":4028,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1587444.2031421885],[-10185081.14311875,1589890.1880468763],[-10182635.158214062,1589890.1880468763],[-10182635.158214062,1587444.2031421885],[-10185081.14311875,1587444.2031421885]]]]},"properties":{"x":4028,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1589890.1880468763],[-10185081.14311875,1592336.1729515642],[-10182635.158214062,1592336.1729515642],[-10182635.158214062,1589890.1880468763],[-10185081.14311875,1589890.1880468763]]]]},"properties":{"x":4028,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1592336.1729515642],[-10185081.14311875,1594782.1578562483],[-10182635.158214062,1594782.1578562483],[-10182635.158214062,1592336.1729515642],[-10185081.14311875,1592336.1729515642]]]]},"properties":{"x":4028,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1594782.1578562483],[-10185081.14311875,1597228.1427609362],[-10182635.158214062,1597228.1427609362],[-10182635.158214062,1594782.1578562483],[-10185081.14311875,1594782.1578562483]]]]},"properties":{"x":4028,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1597228.1427609362],[-10185081.14311875,1599674.127665624],[-10182635.158214062,1599674.127665624],[-10182635.158214062,1597228.1427609362],[-10185081.14311875,1597228.1427609362]]]]},"properties":{"x":4028,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1599674.127665624],[-10185081.14311875,1602120.1125703119],[-10182635.158214062,1602120.1125703119],[-10182635.158214062,1599674.127665624],[-10185081.14311875,1599674.127665624]]]]},"properties":{"x":4028,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1602120.1125703119],[-10185081.14311875,1604566.0974749997],[-10182635.158214062,1604566.0974749997],[-10182635.158214062,1602120.1125703119],[-10185081.14311875,1602120.1125703119]]]]},"properties":{"x":4028,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1604566.0974749997],[-10185081.14311875,1607012.0823796876],[-10182635.158214062,1607012.0823796876],[-10182635.158214062,1604566.0974749997],[-10185081.14311875,1604566.0974749997]]]]},"properties":{"x":4028,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1607012.0823796876],[-10185081.14311875,1609458.0672843754],[-10182635.158214062,1609458.0672843754],[-10182635.158214062,1607012.0823796876],[-10185081.14311875,1607012.0823796876]]]]},"properties":{"x":4028,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1609458.0672843754],[-10185081.14311875,1611904.0521890633],[-10182635.158214062,1611904.0521890633],[-10182635.158214062,1609458.0672843754],[-10185081.14311875,1609458.0672843754]]]]},"properties":{"x":4028,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1611904.0521890633],[-10185081.14311875,1614350.0370937511],[-10182635.158214062,1614350.0370937511],[-10182635.158214062,1611904.0521890633],[-10185081.14311875,1611904.0521890633]]]]},"properties":{"x":4028,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1614350.0370937511],[-10185081.14311875,1616796.021998439],[-10182635.158214062,1616796.021998439],[-10182635.158214062,1614350.0370937511],[-10185081.14311875,1614350.0370937511]]]]},"properties":{"x":4028,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1616796.021998439],[-10185081.14311875,1619242.0069031268],[-10182635.158214062,1619242.0069031268],[-10182635.158214062,1616796.021998439],[-10185081.14311875,1616796.021998439]]]]},"properties":{"x":4028,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1619242.0069031268],[-10185081.14311875,1621687.991807811],[-10182635.158214062,1621687.991807811],[-10182635.158214062,1619242.0069031268],[-10185081.14311875,1619242.0069031268]]]]},"properties":{"x":4028,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1621687.991807811],[-10185081.14311875,1624133.9767124988],[-10182635.158214062,1624133.9767124988],[-10182635.158214062,1621687.991807811],[-10185081.14311875,1621687.991807811]]]]},"properties":{"x":4028,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10185081.14311875,1624133.9767124988],[-10185081.14311875,1626579.9616171867],[-10182635.158214062,1626579.9616171867],[-10182635.158214062,1624133.9767124988],[-10185081.14311875,1624133.9767124988]]]]},"properties":{"x":4028,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1562984.3540953137],[-10182635.158214062,1565430.3390000015],[-10180189.173309376,1565430.3390000015],[-10180189.173309376,1562984.3540953137],[-10182635.158214062,1562984.3540953137]]]]},"properties":{"x":4029,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1565430.3390000015],[-10182635.158214062,1567876.3239046894],[-10180189.173309376,1567876.3239046894],[-10180189.173309376,1565430.3390000015],[-10182635.158214062,1565430.3390000015]]]]},"properties":{"x":4029,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1567876.3239046894],[-10182635.158214062,1570322.3088093735],[-10180189.173309376,1570322.3088093735],[-10180189.173309376,1567876.3239046894],[-10182635.158214062,1567876.3239046894]]]]},"properties":{"x":4029,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1570322.3088093735],[-10182635.158214062,1572768.2937140614],[-10180189.173309376,1572768.2937140614],[-10180189.173309376,1570322.3088093735],[-10182635.158214062,1570322.3088093735]]]]},"properties":{"x":4029,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1572768.2937140614],[-10182635.158214062,1575214.2786187492],[-10180189.173309376,1575214.2786187492],[-10180189.173309376,1572768.2937140614],[-10182635.158214062,1572768.2937140614]]]]},"properties":{"x":4029,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1575214.2786187492],[-10182635.158214062,1577660.263523437],[-10180189.173309376,1577660.263523437],[-10180189.173309376,1575214.2786187492],[-10182635.158214062,1575214.2786187492]]]]},"properties":{"x":4029,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1577660.263523437],[-10182635.158214062,1580106.248428125],[-10180189.173309376,1580106.248428125],[-10180189.173309376,1577660.263523437],[-10182635.158214062,1577660.263523437]]]]},"properties":{"x":4029,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1580106.248428125],[-10182635.158214062,1582552.2333328128],[-10180189.173309376,1582552.2333328128],[-10180189.173309376,1580106.248428125],[-10182635.158214062,1580106.248428125]]]]},"properties":{"x":4029,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1582552.2333328128],[-10182635.158214062,1584998.2182375006],[-10180189.173309376,1584998.2182375006],[-10180189.173309376,1582552.2333328128],[-10182635.158214062,1582552.2333328128]]]]},"properties":{"x":4029,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1584998.2182375006],[-10182635.158214062,1587444.2031421885],[-10180189.173309376,1587444.2031421885],[-10180189.173309376,1584998.2182375006],[-10182635.158214062,1584998.2182375006]]]]},"properties":{"x":4029,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1587444.2031421885],[-10182635.158214062,1589890.1880468763],[-10180189.173309376,1589890.1880468763],[-10180189.173309376,1587444.2031421885],[-10182635.158214062,1587444.2031421885]]]]},"properties":{"x":4029,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1589890.1880468763],[-10182635.158214062,1592336.1729515642],[-10180189.173309376,1592336.1729515642],[-10180189.173309376,1589890.1880468763],[-10182635.158214062,1589890.1880468763]]]]},"properties":{"x":4029,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1592336.1729515642],[-10182635.158214062,1594782.1578562483],[-10180189.173309376,1594782.1578562483],[-10180189.173309376,1592336.1729515642],[-10182635.158214062,1592336.1729515642]]]]},"properties":{"x":4029,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1594782.1578562483],[-10182635.158214062,1597228.1427609362],[-10180189.173309376,1597228.1427609362],[-10180189.173309376,1594782.1578562483],[-10182635.158214062,1594782.1578562483]]]]},"properties":{"x":4029,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1597228.1427609362],[-10182635.158214062,1599674.127665624],[-10180189.173309376,1599674.127665624],[-10180189.173309376,1597228.1427609362],[-10182635.158214062,1597228.1427609362]]]]},"properties":{"x":4029,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1599674.127665624],[-10182635.158214062,1602120.1125703119],[-10180189.173309376,1602120.1125703119],[-10180189.173309376,1599674.127665624],[-10182635.158214062,1599674.127665624]]]]},"properties":{"x":4029,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1602120.1125703119],[-10182635.158214062,1604566.0974749997],[-10180189.173309376,1604566.0974749997],[-10180189.173309376,1602120.1125703119],[-10182635.158214062,1602120.1125703119]]]]},"properties":{"x":4029,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1604566.0974749997],[-10182635.158214062,1607012.0823796876],[-10180189.173309376,1607012.0823796876],[-10180189.173309376,1604566.0974749997],[-10182635.158214062,1604566.0974749997]]]]},"properties":{"x":4029,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1607012.0823796876],[-10182635.158214062,1609458.0672843754],[-10180189.173309376,1609458.0672843754],[-10180189.173309376,1607012.0823796876],[-10182635.158214062,1607012.0823796876]]]]},"properties":{"x":4029,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1609458.0672843754],[-10182635.158214062,1611904.0521890633],[-10180189.173309376,1611904.0521890633],[-10180189.173309376,1609458.0672843754],[-10182635.158214062,1609458.0672843754]]]]},"properties":{"x":4029,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1611904.0521890633],[-10182635.158214062,1614350.0370937511],[-10180189.173309376,1614350.0370937511],[-10180189.173309376,1611904.0521890633],[-10182635.158214062,1611904.0521890633]]]]},"properties":{"x":4029,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1614350.0370937511],[-10182635.158214062,1616796.021998439],[-10180189.173309376,1616796.021998439],[-10180189.173309376,1614350.0370937511],[-10182635.158214062,1614350.0370937511]]]]},"properties":{"x":4029,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1616796.021998439],[-10182635.158214062,1619242.0069031268],[-10180189.173309376,1619242.0069031268],[-10180189.173309376,1616796.021998439],[-10182635.158214062,1616796.021998439]]]]},"properties":{"x":4029,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1619242.0069031268],[-10182635.158214062,1621687.991807811],[-10180189.173309376,1621687.991807811],[-10180189.173309376,1619242.0069031268],[-10182635.158214062,1619242.0069031268]]]]},"properties":{"x":4029,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1621687.991807811],[-10182635.158214062,1624133.9767124988],[-10180189.173309376,1624133.9767124988],[-10180189.173309376,1621687.991807811],[-10182635.158214062,1621687.991807811]]]]},"properties":{"x":4029,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10182635.158214062,1624133.9767124988],[-10182635.158214062,1626579.9616171867],[-10180189.173309376,1626579.9616171867],[-10180189.173309376,1624133.9767124988],[-10182635.158214062,1624133.9767124988]]]]},"properties":{"x":4029,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1562984.3540953137],[-10180189.173309376,1565430.3390000015],[-10177743.188404689,1565430.3390000015],[-10177743.188404689,1562984.3540953137],[-10180189.173309376,1562984.3540953137]]]]},"properties":{"x":4030,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1565430.3390000015],[-10180189.173309376,1567876.3239046894],[-10177743.188404689,1567876.3239046894],[-10177743.188404689,1565430.3390000015],[-10180189.173309376,1565430.3390000015]]]]},"properties":{"x":4030,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1567876.3239046894],[-10180189.173309376,1570322.3088093735],[-10177743.188404689,1570322.3088093735],[-10177743.188404689,1567876.3239046894],[-10180189.173309376,1567876.3239046894]]]]},"properties":{"x":4030,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1570322.3088093735],[-10180189.173309376,1572768.2937140614],[-10177743.188404689,1572768.2937140614],[-10177743.188404689,1570322.3088093735],[-10180189.173309376,1570322.3088093735]]]]},"properties":{"x":4030,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1572768.2937140614],[-10180189.173309376,1575214.2786187492],[-10177743.188404689,1575214.2786187492],[-10177743.188404689,1572768.2937140614],[-10180189.173309376,1572768.2937140614]]]]},"properties":{"x":4030,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1575214.2786187492],[-10180189.173309376,1577660.263523437],[-10177743.188404689,1577660.263523437],[-10177743.188404689,1575214.2786187492],[-10180189.173309376,1575214.2786187492]]]]},"properties":{"x":4030,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1577660.263523437],[-10180189.173309376,1580106.248428125],[-10177743.188404689,1580106.248428125],[-10177743.188404689,1577660.263523437],[-10180189.173309376,1577660.263523437]]]]},"properties":{"x":4030,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1580106.248428125],[-10180189.173309376,1582552.2333328128],[-10177743.188404689,1582552.2333328128],[-10177743.188404689,1580106.248428125],[-10180189.173309376,1580106.248428125]]]]},"properties":{"x":4030,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1582552.2333328128],[-10180189.173309376,1584998.2182375006],[-10177743.188404689,1584998.2182375006],[-10177743.188404689,1582552.2333328128],[-10180189.173309376,1582552.2333328128]]]]},"properties":{"x":4030,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1584998.2182375006],[-10180189.173309376,1587444.2031421885],[-10177743.188404689,1587444.2031421885],[-10177743.188404689,1584998.2182375006],[-10180189.173309376,1584998.2182375006]]]]},"properties":{"x":4030,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1587444.2031421885],[-10180189.173309376,1589890.1880468763],[-10177743.188404689,1589890.1880468763],[-10177743.188404689,1587444.2031421885],[-10180189.173309376,1587444.2031421885]]]]},"properties":{"x":4030,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1589890.1880468763],[-10180189.173309376,1592336.1729515642],[-10177743.188404689,1592336.1729515642],[-10177743.188404689,1589890.1880468763],[-10180189.173309376,1589890.1880468763]]]]},"properties":{"x":4030,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1592336.1729515642],[-10180189.173309376,1594782.1578562483],[-10177743.188404689,1594782.1578562483],[-10177743.188404689,1592336.1729515642],[-10180189.173309376,1592336.1729515642]]]]},"properties":{"x":4030,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1594782.1578562483],[-10180189.173309376,1597228.1427609362],[-10177743.188404689,1597228.1427609362],[-10177743.188404689,1594782.1578562483],[-10180189.173309376,1594782.1578562483]]]]},"properties":{"x":4030,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1597228.1427609362],[-10180189.173309376,1599674.127665624],[-10177743.188404689,1599674.127665624],[-10177743.188404689,1597228.1427609362],[-10180189.173309376,1597228.1427609362]]]]},"properties":{"x":4030,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1599674.127665624],[-10180189.173309376,1602120.1125703119],[-10177743.188404689,1602120.1125703119],[-10177743.188404689,1599674.127665624],[-10180189.173309376,1599674.127665624]]]]},"properties":{"x":4030,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1602120.1125703119],[-10180189.173309376,1604566.0974749997],[-10177743.188404689,1604566.0974749997],[-10177743.188404689,1602120.1125703119],[-10180189.173309376,1602120.1125703119]]]]},"properties":{"x":4030,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1604566.0974749997],[-10180189.173309376,1607012.0823796876],[-10177743.188404689,1607012.0823796876],[-10177743.188404689,1604566.0974749997],[-10180189.173309376,1604566.0974749997]]]]},"properties":{"x":4030,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1607012.0823796876],[-10180189.173309376,1609458.0672843754],[-10177743.188404689,1609458.0672843754],[-10177743.188404689,1607012.0823796876],[-10180189.173309376,1607012.0823796876]]]]},"properties":{"x":4030,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1609458.0672843754],[-10180189.173309376,1611904.0521890633],[-10177743.188404689,1611904.0521890633],[-10177743.188404689,1609458.0672843754],[-10180189.173309376,1609458.0672843754]]]]},"properties":{"x":4030,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1611904.0521890633],[-10180189.173309376,1614350.0370937511],[-10177743.188404689,1614350.0370937511],[-10177743.188404689,1611904.0521890633],[-10180189.173309376,1611904.0521890633]]]]},"properties":{"x":4030,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1614350.0370937511],[-10180189.173309376,1616796.021998439],[-10177743.188404689,1616796.021998439],[-10177743.188404689,1614350.0370937511],[-10180189.173309376,1614350.0370937511]]]]},"properties":{"x":4030,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1616796.021998439],[-10180189.173309376,1619242.0069031268],[-10177743.188404689,1619242.0069031268],[-10177743.188404689,1616796.021998439],[-10180189.173309376,1616796.021998439]]]]},"properties":{"x":4030,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1619242.0069031268],[-10180189.173309376,1621687.991807811],[-10177743.188404689,1621687.991807811],[-10177743.188404689,1619242.0069031268],[-10180189.173309376,1619242.0069031268]]]]},"properties":{"x":4030,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1621687.991807811],[-10180189.173309376,1624133.9767124988],[-10177743.188404689,1624133.9767124988],[-10177743.188404689,1621687.991807811],[-10180189.173309376,1621687.991807811]]]]},"properties":{"x":4030,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10180189.173309376,1624133.9767124988],[-10180189.173309376,1626579.9616171867],[-10177743.188404689,1626579.9616171867],[-10177743.188404689,1624133.9767124988],[-10180189.173309376,1624133.9767124988]]]]},"properties":{"x":4030,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1562984.3540953137],[-10177743.188404689,1565430.3390000015],[-10175297.2035,1565430.3390000015],[-10175297.2035,1562984.3540953137],[-10177743.188404689,1562984.3540953137]]]]},"properties":{"x":4031,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1565430.3390000015],[-10177743.188404689,1567876.3239046894],[-10175297.2035,1567876.3239046894],[-10175297.2035,1565430.3390000015],[-10177743.188404689,1565430.3390000015]]]]},"properties":{"x":4031,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1567876.3239046894],[-10177743.188404689,1570322.3088093735],[-10175297.2035,1570322.3088093735],[-10175297.2035,1567876.3239046894],[-10177743.188404689,1567876.3239046894]]]]},"properties":{"x":4031,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1570322.3088093735],[-10177743.188404689,1572768.2937140614],[-10175297.2035,1572768.2937140614],[-10175297.2035,1570322.3088093735],[-10177743.188404689,1570322.3088093735]]]]},"properties":{"x":4031,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1572768.2937140614],[-10177743.188404689,1575214.2786187492],[-10175297.2035,1575214.2786187492],[-10175297.2035,1572768.2937140614],[-10177743.188404689,1572768.2937140614]]]]},"properties":{"x":4031,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1575214.2786187492],[-10177743.188404689,1577660.263523437],[-10175297.2035,1577660.263523437],[-10175297.2035,1575214.2786187492],[-10177743.188404689,1575214.2786187492]]]]},"properties":{"x":4031,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1577660.263523437],[-10177743.188404689,1580106.248428125],[-10175297.2035,1580106.248428125],[-10175297.2035,1577660.263523437],[-10177743.188404689,1577660.263523437]]]]},"properties":{"x":4031,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1580106.248428125],[-10177743.188404689,1582552.2333328128],[-10175297.2035,1582552.2333328128],[-10175297.2035,1580106.248428125],[-10177743.188404689,1580106.248428125]]]]},"properties":{"x":4031,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1582552.2333328128],[-10177743.188404689,1584998.2182375006],[-10175297.2035,1584998.2182375006],[-10175297.2035,1582552.2333328128],[-10177743.188404689,1582552.2333328128]]]]},"properties":{"x":4031,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1584998.2182375006],[-10177743.188404689,1587444.2031421885],[-10175297.2035,1587444.2031421885],[-10175297.2035,1584998.2182375006],[-10177743.188404689,1584998.2182375006]]]]},"properties":{"x":4031,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1587444.2031421885],[-10177743.188404689,1589890.1880468763],[-10175297.2035,1589890.1880468763],[-10175297.2035,1587444.2031421885],[-10177743.188404689,1587444.2031421885]]]]},"properties":{"x":4031,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1589890.1880468763],[-10177743.188404689,1592336.1729515642],[-10175297.2035,1592336.1729515642],[-10175297.2035,1589890.1880468763],[-10177743.188404689,1589890.1880468763]]]]},"properties":{"x":4031,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1592336.1729515642],[-10177743.188404689,1594782.1578562483],[-10175297.2035,1594782.1578562483],[-10175297.2035,1592336.1729515642],[-10177743.188404689,1592336.1729515642]]]]},"properties":{"x":4031,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1594782.1578562483],[-10177743.188404689,1597228.1427609362],[-10175297.2035,1597228.1427609362],[-10175297.2035,1594782.1578562483],[-10177743.188404689,1594782.1578562483]]]]},"properties":{"x":4031,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1597228.1427609362],[-10177743.188404689,1599674.127665624],[-10175297.2035,1599674.127665624],[-10175297.2035,1597228.1427609362],[-10177743.188404689,1597228.1427609362]]]]},"properties":{"x":4031,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1599674.127665624],[-10177743.188404689,1602120.1125703119],[-10175297.2035,1602120.1125703119],[-10175297.2035,1599674.127665624],[-10177743.188404689,1599674.127665624]]]]},"properties":{"x":4031,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1602120.1125703119],[-10177743.188404689,1604566.0974749997],[-10175297.2035,1604566.0974749997],[-10175297.2035,1602120.1125703119],[-10177743.188404689,1602120.1125703119]]]]},"properties":{"x":4031,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1604566.0974749997],[-10177743.188404689,1607012.0823796876],[-10175297.2035,1607012.0823796876],[-10175297.2035,1604566.0974749997],[-10177743.188404689,1604566.0974749997]]]]},"properties":{"x":4031,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1607012.0823796876],[-10177743.188404689,1609458.0672843754],[-10175297.2035,1609458.0672843754],[-10175297.2035,1607012.0823796876],[-10177743.188404689,1607012.0823796876]]]]},"properties":{"x":4031,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1609458.0672843754],[-10177743.188404689,1611904.0521890633],[-10175297.2035,1611904.0521890633],[-10175297.2035,1609458.0672843754],[-10177743.188404689,1609458.0672843754]]]]},"properties":{"x":4031,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1611904.0521890633],[-10177743.188404689,1614350.0370937511],[-10175297.2035,1614350.0370937511],[-10175297.2035,1611904.0521890633],[-10177743.188404689,1611904.0521890633]]]]},"properties":{"x":4031,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1614350.0370937511],[-10177743.188404689,1616796.021998439],[-10175297.2035,1616796.021998439],[-10175297.2035,1614350.0370937511],[-10177743.188404689,1614350.0370937511]]]]},"properties":{"x":4031,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1616796.021998439],[-10177743.188404689,1619242.0069031268],[-10175297.2035,1619242.0069031268],[-10175297.2035,1616796.021998439],[-10177743.188404689,1616796.021998439]]]]},"properties":{"x":4031,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1619242.0069031268],[-10177743.188404689,1621687.991807811],[-10175297.2035,1621687.991807811],[-10175297.2035,1619242.0069031268],[-10177743.188404689,1619242.0069031268]]]]},"properties":{"x":4031,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1621687.991807811],[-10177743.188404689,1624133.9767124988],[-10175297.2035,1624133.9767124988],[-10175297.2035,1621687.991807811],[-10177743.188404689,1621687.991807811]]]]},"properties":{"x":4031,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10177743.188404689,1624133.9767124988],[-10177743.188404689,1626579.9616171867],[-10175297.2035,1626579.9616171867],[-10175297.2035,1624133.9767124988],[-10177743.188404689,1624133.9767124988]]]]},"properties":{"x":4031,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1562984.3540953137],[-10175297.2035,1565430.3390000015],[-10172851.218595313,1565430.3390000015],[-10172851.218595313,1562984.3540953137],[-10175297.2035,1562984.3540953137]]]]},"properties":{"x":4032,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1565430.3390000015],[-10175297.2035,1567876.3239046894],[-10172851.218595313,1567876.3239046894],[-10172851.218595313,1565430.3390000015],[-10175297.2035,1565430.3390000015]]]]},"properties":{"x":4032,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1567876.3239046894],[-10175297.2035,1570322.3088093735],[-10172851.218595313,1570322.3088093735],[-10172851.218595313,1567876.3239046894],[-10175297.2035,1567876.3239046894]]]]},"properties":{"x":4032,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1570322.3088093735],[-10175297.2035,1572768.2937140614],[-10172851.218595313,1572768.2937140614],[-10172851.218595313,1570322.3088093735],[-10175297.2035,1570322.3088093735]]]]},"properties":{"x":4032,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1572768.2937140614],[-10175297.2035,1575214.2786187492],[-10172851.218595313,1575214.2786187492],[-10172851.218595313,1572768.2937140614],[-10175297.2035,1572768.2937140614]]]]},"properties":{"x":4032,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1575214.2786187492],[-10175297.2035,1577660.263523437],[-10172851.218595313,1577660.263523437],[-10172851.218595313,1575214.2786187492],[-10175297.2035,1575214.2786187492]]]]},"properties":{"x":4032,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1577660.263523437],[-10175297.2035,1580106.248428125],[-10172851.218595313,1580106.248428125],[-10172851.218595313,1577660.263523437],[-10175297.2035,1577660.263523437]]]]},"properties":{"x":4032,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1580106.248428125],[-10175297.2035,1582552.2333328128],[-10172851.218595313,1582552.2333328128],[-10172851.218595313,1580106.248428125],[-10175297.2035,1580106.248428125]]]]},"properties":{"x":4032,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1582552.2333328128],[-10175297.2035,1584998.2182375006],[-10172851.218595313,1584998.2182375006],[-10172851.218595313,1582552.2333328128],[-10175297.2035,1582552.2333328128]]]]},"properties":{"x":4032,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1584998.2182375006],[-10175297.2035,1587444.2031421885],[-10172851.218595313,1587444.2031421885],[-10172851.218595313,1584998.2182375006],[-10175297.2035,1584998.2182375006]]]]},"properties":{"x":4032,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1587444.2031421885],[-10175297.2035,1589890.1880468763],[-10172851.218595313,1589890.1880468763],[-10172851.218595313,1587444.2031421885],[-10175297.2035,1587444.2031421885]]]]},"properties":{"x":4032,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1589890.1880468763],[-10175297.2035,1592336.1729515642],[-10172851.218595313,1592336.1729515642],[-10172851.218595313,1589890.1880468763],[-10175297.2035,1589890.1880468763]]]]},"properties":{"x":4032,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1592336.1729515642],[-10175297.2035,1594782.1578562483],[-10172851.218595313,1594782.1578562483],[-10172851.218595313,1592336.1729515642],[-10175297.2035,1592336.1729515642]]]]},"properties":{"x":4032,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1594782.1578562483],[-10175297.2035,1597228.1427609362],[-10172851.218595313,1597228.1427609362],[-10172851.218595313,1594782.1578562483],[-10175297.2035,1594782.1578562483]]]]},"properties":{"x":4032,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1597228.1427609362],[-10175297.2035,1599674.127665624],[-10172851.218595313,1599674.127665624],[-10172851.218595313,1597228.1427609362],[-10175297.2035,1597228.1427609362]]]]},"properties":{"x":4032,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1599674.127665624],[-10175297.2035,1602120.1125703119],[-10172851.218595313,1602120.1125703119],[-10172851.218595313,1599674.127665624],[-10175297.2035,1599674.127665624]]]]},"properties":{"x":4032,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1602120.1125703119],[-10175297.2035,1604566.0974749997],[-10172851.218595313,1604566.0974749997],[-10172851.218595313,1602120.1125703119],[-10175297.2035,1602120.1125703119]]]]},"properties":{"x":4032,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1604566.0974749997],[-10175297.2035,1607012.0823796876],[-10172851.218595313,1607012.0823796876],[-10172851.218595313,1604566.0974749997],[-10175297.2035,1604566.0974749997]]]]},"properties":{"x":4032,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1607012.0823796876],[-10175297.2035,1609458.0672843754],[-10172851.218595313,1609458.0672843754],[-10172851.218595313,1607012.0823796876],[-10175297.2035,1607012.0823796876]]]]},"properties":{"x":4032,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1609458.0672843754],[-10175297.2035,1611904.0521890633],[-10172851.218595313,1611904.0521890633],[-10172851.218595313,1609458.0672843754],[-10175297.2035,1609458.0672843754]]]]},"properties":{"x":4032,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1611904.0521890633],[-10175297.2035,1614350.0370937511],[-10172851.218595313,1614350.0370937511],[-10172851.218595313,1611904.0521890633],[-10175297.2035,1611904.0521890633]]]]},"properties":{"x":4032,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1614350.0370937511],[-10175297.2035,1616796.021998439],[-10172851.218595313,1616796.021998439],[-10172851.218595313,1614350.0370937511],[-10175297.2035,1614350.0370937511]]]]},"properties":{"x":4032,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1616796.021998439],[-10175297.2035,1619242.0069031268],[-10172851.218595313,1619242.0069031268],[-10172851.218595313,1616796.021998439],[-10175297.2035,1616796.021998439]]]]},"properties":{"x":4032,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1619242.0069031268],[-10175297.2035,1621687.991807811],[-10172851.218595313,1621687.991807811],[-10172851.218595313,1619242.0069031268],[-10175297.2035,1619242.0069031268]]]]},"properties":{"x":4032,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1621687.991807811],[-10175297.2035,1624133.9767124988],[-10172851.218595313,1624133.9767124988],[-10172851.218595313,1621687.991807811],[-10175297.2035,1621687.991807811]]]]},"properties":{"x":4032,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10175297.2035,1624133.9767124988],[-10175297.2035,1626579.9616171867],[-10172851.218595313,1626579.9616171867],[-10172851.218595313,1624133.9767124988],[-10175297.2035,1624133.9767124988]]]]},"properties":{"x":4032,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1562984.3540953137],[-10172851.218595313,1565430.3390000015],[-10170405.233690625,1565430.3390000015],[-10170405.233690625,1562984.3540953137],[-10172851.218595313,1562984.3540953137]]]]},"properties":{"x":4033,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1565430.3390000015],[-10172851.218595313,1567876.3239046894],[-10170405.233690625,1567876.3239046894],[-10170405.233690625,1565430.3390000015],[-10172851.218595313,1565430.3390000015]]]]},"properties":{"x":4033,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1567876.3239046894],[-10172851.218595313,1570322.3088093735],[-10170405.233690625,1570322.3088093735],[-10170405.233690625,1567876.3239046894],[-10172851.218595313,1567876.3239046894]]]]},"properties":{"x":4033,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1570322.3088093735],[-10172851.218595313,1572768.2937140614],[-10170405.233690625,1572768.2937140614],[-10170405.233690625,1570322.3088093735],[-10172851.218595313,1570322.3088093735]]]]},"properties":{"x":4033,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1572768.2937140614],[-10172851.218595313,1575214.2786187492],[-10170405.233690625,1575214.2786187492],[-10170405.233690625,1572768.2937140614],[-10172851.218595313,1572768.2937140614]]]]},"properties":{"x":4033,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1575214.2786187492],[-10172851.218595313,1577660.263523437],[-10170405.233690625,1577660.263523437],[-10170405.233690625,1575214.2786187492],[-10172851.218595313,1575214.2786187492]]]]},"properties":{"x":4033,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1577660.263523437],[-10172851.218595313,1580106.248428125],[-10170405.233690625,1580106.248428125],[-10170405.233690625,1577660.263523437],[-10172851.218595313,1577660.263523437]]]]},"properties":{"x":4033,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1580106.248428125],[-10172851.218595313,1582552.2333328128],[-10170405.233690625,1582552.2333328128],[-10170405.233690625,1580106.248428125],[-10172851.218595313,1580106.248428125]]]]},"properties":{"x":4033,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1582552.2333328128],[-10172851.218595313,1584998.2182375006],[-10170405.233690625,1584998.2182375006],[-10170405.233690625,1582552.2333328128],[-10172851.218595313,1582552.2333328128]]]]},"properties":{"x":4033,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1584998.2182375006],[-10172851.218595313,1587444.2031421885],[-10170405.233690625,1587444.2031421885],[-10170405.233690625,1584998.2182375006],[-10172851.218595313,1584998.2182375006]]]]},"properties":{"x":4033,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1587444.2031421885],[-10172851.218595313,1589890.1880468763],[-10170405.233690625,1589890.1880468763],[-10170405.233690625,1587444.2031421885],[-10172851.218595313,1587444.2031421885]]]]},"properties":{"x":4033,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1589890.1880468763],[-10172851.218595313,1592336.1729515642],[-10170405.233690625,1592336.1729515642],[-10170405.233690625,1589890.1880468763],[-10172851.218595313,1589890.1880468763]]]]},"properties":{"x":4033,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1592336.1729515642],[-10172851.218595313,1594782.1578562483],[-10170405.233690625,1594782.1578562483],[-10170405.233690625,1592336.1729515642],[-10172851.218595313,1592336.1729515642]]]]},"properties":{"x":4033,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1594782.1578562483],[-10172851.218595313,1597228.1427609362],[-10170405.233690625,1597228.1427609362],[-10170405.233690625,1594782.1578562483],[-10172851.218595313,1594782.1578562483]]]]},"properties":{"x":4033,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1597228.1427609362],[-10172851.218595313,1599674.127665624],[-10170405.233690625,1599674.127665624],[-10170405.233690625,1597228.1427609362],[-10172851.218595313,1597228.1427609362]]]]},"properties":{"x":4033,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1599674.127665624],[-10172851.218595313,1602120.1125703119],[-10170405.233690625,1602120.1125703119],[-10170405.233690625,1599674.127665624],[-10172851.218595313,1599674.127665624]]]]},"properties":{"x":4033,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1602120.1125703119],[-10172851.218595313,1604566.0974749997],[-10170405.233690625,1604566.0974749997],[-10170405.233690625,1602120.1125703119],[-10172851.218595313,1602120.1125703119]]]]},"properties":{"x":4033,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1604566.0974749997],[-10172851.218595313,1607012.0823796876],[-10170405.233690625,1607012.0823796876],[-10170405.233690625,1604566.0974749997],[-10172851.218595313,1604566.0974749997]]]]},"properties":{"x":4033,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1607012.0823796876],[-10172851.218595313,1609458.0672843754],[-10170405.233690625,1609458.0672843754],[-10170405.233690625,1607012.0823796876],[-10172851.218595313,1607012.0823796876]]]]},"properties":{"x":4033,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1609458.0672843754],[-10172851.218595313,1611904.0521890633],[-10170405.233690625,1611904.0521890633],[-10170405.233690625,1609458.0672843754],[-10172851.218595313,1609458.0672843754]]]]},"properties":{"x":4033,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1611904.0521890633],[-10172851.218595313,1614350.0370937511],[-10170405.233690625,1614350.0370937511],[-10170405.233690625,1611904.0521890633],[-10172851.218595313,1611904.0521890633]]]]},"properties":{"x":4033,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1614350.0370937511],[-10172851.218595313,1616796.021998439],[-10170405.233690625,1616796.021998439],[-10170405.233690625,1614350.0370937511],[-10172851.218595313,1614350.0370937511]]]]},"properties":{"x":4033,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1616796.021998439],[-10172851.218595313,1619242.0069031268],[-10170405.233690625,1619242.0069031268],[-10170405.233690625,1616796.021998439],[-10172851.218595313,1616796.021998439]]]]},"properties":{"x":4033,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1619242.0069031268],[-10172851.218595313,1621687.991807811],[-10170405.233690625,1621687.991807811],[-10170405.233690625,1619242.0069031268],[-10172851.218595313,1619242.0069031268]]]]},"properties":{"x":4033,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1621687.991807811],[-10172851.218595313,1624133.9767124988],[-10170405.233690625,1624133.9767124988],[-10170405.233690625,1621687.991807811],[-10172851.218595313,1621687.991807811]]]]},"properties":{"x":4033,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10172851.218595313,1624133.9767124988],[-10172851.218595313,1626579.9616171867],[-10170405.233690625,1626579.9616171867],[-10170405.233690625,1624133.9767124988],[-10172851.218595313,1624133.9767124988]]]]},"properties":{"x":4033,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1562984.3540953137],[-10170405.233690625,1565430.3390000015],[-10167959.248785937,1565430.3390000015],[-10167959.248785937,1562984.3540953137],[-10170405.233690625,1562984.3540953137]]]]},"properties":{"x":4034,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1565430.3390000015],[-10170405.233690625,1567876.3239046894],[-10167959.248785937,1567876.3239046894],[-10167959.248785937,1565430.3390000015],[-10170405.233690625,1565430.3390000015]]]]},"properties":{"x":4034,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1567876.3239046894],[-10170405.233690625,1570322.3088093735],[-10167959.248785937,1570322.3088093735],[-10167959.248785937,1567876.3239046894],[-10170405.233690625,1567876.3239046894]]]]},"properties":{"x":4034,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1570322.3088093735],[-10170405.233690625,1572768.2937140614],[-10167959.248785937,1572768.2937140614],[-10167959.248785937,1570322.3088093735],[-10170405.233690625,1570322.3088093735]]]]},"properties":{"x":4034,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1572768.2937140614],[-10170405.233690625,1575214.2786187492],[-10167959.248785937,1575214.2786187492],[-10167959.248785937,1572768.2937140614],[-10170405.233690625,1572768.2937140614]]]]},"properties":{"x":4034,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1575214.2786187492],[-10170405.233690625,1577660.263523437],[-10167959.248785937,1577660.263523437],[-10167959.248785937,1575214.2786187492],[-10170405.233690625,1575214.2786187492]]]]},"properties":{"x":4034,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1577660.263523437],[-10170405.233690625,1580106.248428125],[-10167959.248785937,1580106.248428125],[-10167959.248785937,1577660.263523437],[-10170405.233690625,1577660.263523437]]]]},"properties":{"x":4034,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1580106.248428125],[-10170405.233690625,1582552.2333328128],[-10167959.248785937,1582552.2333328128],[-10167959.248785937,1580106.248428125],[-10170405.233690625,1580106.248428125]]]]},"properties":{"x":4034,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1582552.2333328128],[-10170405.233690625,1584998.2182375006],[-10167959.248785937,1584998.2182375006],[-10167959.248785937,1582552.2333328128],[-10170405.233690625,1582552.2333328128]]]]},"properties":{"x":4034,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1584998.2182375006],[-10170405.233690625,1587444.2031421885],[-10167959.248785937,1587444.2031421885],[-10167959.248785937,1584998.2182375006],[-10170405.233690625,1584998.2182375006]]]]},"properties":{"x":4034,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1587444.2031421885],[-10170405.233690625,1589890.1880468763],[-10167959.248785937,1589890.1880468763],[-10167959.248785937,1587444.2031421885],[-10170405.233690625,1587444.2031421885]]]]},"properties":{"x":4034,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1589890.1880468763],[-10170405.233690625,1592336.1729515642],[-10167959.248785937,1592336.1729515642],[-10167959.248785937,1589890.1880468763],[-10170405.233690625,1589890.1880468763]]]]},"properties":{"x":4034,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1592336.1729515642],[-10170405.233690625,1594782.1578562483],[-10167959.248785937,1594782.1578562483],[-10167959.248785937,1592336.1729515642],[-10170405.233690625,1592336.1729515642]]]]},"properties":{"x":4034,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1594782.1578562483],[-10170405.233690625,1597228.1427609362],[-10167959.248785937,1597228.1427609362],[-10167959.248785937,1594782.1578562483],[-10170405.233690625,1594782.1578562483]]]]},"properties":{"x":4034,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1597228.1427609362],[-10170405.233690625,1599674.127665624],[-10167959.248785937,1599674.127665624],[-10167959.248785937,1597228.1427609362],[-10170405.233690625,1597228.1427609362]]]]},"properties":{"x":4034,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1599674.127665624],[-10170405.233690625,1602120.1125703119],[-10167959.248785937,1602120.1125703119],[-10167959.248785937,1599674.127665624],[-10170405.233690625,1599674.127665624]]]]},"properties":{"x":4034,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1602120.1125703119],[-10170405.233690625,1604566.0974749997],[-10167959.248785937,1604566.0974749997],[-10167959.248785937,1602120.1125703119],[-10170405.233690625,1602120.1125703119]]]]},"properties":{"x":4034,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1604566.0974749997],[-10170405.233690625,1607012.0823796876],[-10167959.248785937,1607012.0823796876],[-10167959.248785937,1604566.0974749997],[-10170405.233690625,1604566.0974749997]]]]},"properties":{"x":4034,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1607012.0823796876],[-10170405.233690625,1609458.0672843754],[-10167959.248785937,1609458.0672843754],[-10167959.248785937,1607012.0823796876],[-10170405.233690625,1607012.0823796876]]]]},"properties":{"x":4034,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1609458.0672843754],[-10170405.233690625,1611904.0521890633],[-10167959.248785937,1611904.0521890633],[-10167959.248785937,1609458.0672843754],[-10170405.233690625,1609458.0672843754]]]]},"properties":{"x":4034,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1611904.0521890633],[-10170405.233690625,1614350.0370937511],[-10167959.248785937,1614350.0370937511],[-10167959.248785937,1611904.0521890633],[-10170405.233690625,1611904.0521890633]]]]},"properties":{"x":4034,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1614350.0370937511],[-10170405.233690625,1616796.021998439],[-10167959.248785937,1616796.021998439],[-10167959.248785937,1614350.0370937511],[-10170405.233690625,1614350.0370937511]]]]},"properties":{"x":4034,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1616796.021998439],[-10170405.233690625,1619242.0069031268],[-10167959.248785937,1619242.0069031268],[-10167959.248785937,1616796.021998439],[-10170405.233690625,1616796.021998439]]]]},"properties":{"x":4034,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1619242.0069031268],[-10170405.233690625,1621687.991807811],[-10167959.248785937,1621687.991807811],[-10167959.248785937,1619242.0069031268],[-10170405.233690625,1619242.0069031268]]]]},"properties":{"x":4034,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1621687.991807811],[-10170405.233690625,1624133.9767124988],[-10167959.248785937,1624133.9767124988],[-10167959.248785937,1621687.991807811],[-10170405.233690625,1621687.991807811]]]]},"properties":{"x":4034,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10170405.233690625,1624133.9767124988],[-10170405.233690625,1626579.9616171867],[-10167959.248785937,1626579.9616171867],[-10167959.248785937,1624133.9767124988],[-10170405.233690625,1624133.9767124988]]]]},"properties":{"x":4034,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1562984.3540953137],[-10167959.248785937,1565430.3390000015],[-10165513.263881251,1565430.3390000015],[-10165513.263881251,1562984.3540953137],[-10167959.248785937,1562984.3540953137]]]]},"properties":{"x":4035,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1565430.3390000015],[-10167959.248785937,1567876.3239046894],[-10165513.263881251,1567876.3239046894],[-10165513.263881251,1565430.3390000015],[-10167959.248785937,1565430.3390000015]]]]},"properties":{"x":4035,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1567876.3239046894],[-10167959.248785937,1570322.3088093735],[-10165513.263881251,1570322.3088093735],[-10165513.263881251,1567876.3239046894],[-10167959.248785937,1567876.3239046894]]]]},"properties":{"x":4035,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1570322.3088093735],[-10167959.248785937,1572768.2937140614],[-10165513.263881251,1572768.2937140614],[-10165513.263881251,1570322.3088093735],[-10167959.248785937,1570322.3088093735]]]]},"properties":{"x":4035,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1572768.2937140614],[-10167959.248785937,1575214.2786187492],[-10165513.263881251,1575214.2786187492],[-10165513.263881251,1572768.2937140614],[-10167959.248785937,1572768.2937140614]]]]},"properties":{"x":4035,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1575214.2786187492],[-10167959.248785937,1577660.263523437],[-10165513.263881251,1577660.263523437],[-10165513.263881251,1575214.2786187492],[-10167959.248785937,1575214.2786187492]]]]},"properties":{"x":4035,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1577660.263523437],[-10167959.248785937,1580106.248428125],[-10165513.263881251,1580106.248428125],[-10165513.263881251,1577660.263523437],[-10167959.248785937,1577660.263523437]]]]},"properties":{"x":4035,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1580106.248428125],[-10167959.248785937,1582552.2333328128],[-10165513.263881251,1582552.2333328128],[-10165513.263881251,1580106.248428125],[-10167959.248785937,1580106.248428125]]]]},"properties":{"x":4035,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1582552.2333328128],[-10167959.248785937,1584998.2182375006],[-10165513.263881251,1584998.2182375006],[-10165513.263881251,1582552.2333328128],[-10167959.248785937,1582552.2333328128]]]]},"properties":{"x":4035,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1584998.2182375006],[-10167959.248785937,1587444.2031421885],[-10165513.263881251,1587444.2031421885],[-10165513.263881251,1584998.2182375006],[-10167959.248785937,1584998.2182375006]]]]},"properties":{"x":4035,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1587444.2031421885],[-10167959.248785937,1589890.1880468763],[-10165513.263881251,1589890.1880468763],[-10165513.263881251,1587444.2031421885],[-10167959.248785937,1587444.2031421885]]]]},"properties":{"x":4035,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1589890.1880468763],[-10167959.248785937,1592336.1729515642],[-10165513.263881251,1592336.1729515642],[-10165513.263881251,1589890.1880468763],[-10167959.248785937,1589890.1880468763]]]]},"properties":{"x":4035,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1592336.1729515642],[-10167959.248785937,1594782.1578562483],[-10165513.263881251,1594782.1578562483],[-10165513.263881251,1592336.1729515642],[-10167959.248785937,1592336.1729515642]]]]},"properties":{"x":4035,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1594782.1578562483],[-10167959.248785937,1597228.1427609362],[-10165513.263881251,1597228.1427609362],[-10165513.263881251,1594782.1578562483],[-10167959.248785937,1594782.1578562483]]]]},"properties":{"x":4035,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1597228.1427609362],[-10167959.248785937,1599674.127665624],[-10165513.263881251,1599674.127665624],[-10165513.263881251,1597228.1427609362],[-10167959.248785937,1597228.1427609362]]]]},"properties":{"x":4035,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1599674.127665624],[-10167959.248785937,1602120.1125703119],[-10165513.263881251,1602120.1125703119],[-10165513.263881251,1599674.127665624],[-10167959.248785937,1599674.127665624]]]]},"properties":{"x":4035,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1602120.1125703119],[-10167959.248785937,1604566.0974749997],[-10165513.263881251,1604566.0974749997],[-10165513.263881251,1602120.1125703119],[-10167959.248785937,1602120.1125703119]]]]},"properties":{"x":4035,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1604566.0974749997],[-10167959.248785937,1607012.0823796876],[-10165513.263881251,1607012.0823796876],[-10165513.263881251,1604566.0974749997],[-10167959.248785937,1604566.0974749997]]]]},"properties":{"x":4035,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1607012.0823796876],[-10167959.248785937,1609458.0672843754],[-10165513.263881251,1609458.0672843754],[-10165513.263881251,1607012.0823796876],[-10167959.248785937,1607012.0823796876]]]]},"properties":{"x":4035,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1609458.0672843754],[-10167959.248785937,1611904.0521890633],[-10165513.263881251,1611904.0521890633],[-10165513.263881251,1609458.0672843754],[-10167959.248785937,1609458.0672843754]]]]},"properties":{"x":4035,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1611904.0521890633],[-10167959.248785937,1614350.0370937511],[-10165513.263881251,1614350.0370937511],[-10165513.263881251,1611904.0521890633],[-10167959.248785937,1611904.0521890633]]]]},"properties":{"x":4035,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1614350.0370937511],[-10167959.248785937,1616796.021998439],[-10165513.263881251,1616796.021998439],[-10165513.263881251,1614350.0370937511],[-10167959.248785937,1614350.0370937511]]]]},"properties":{"x":4035,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1616796.021998439],[-10167959.248785937,1619242.0069031268],[-10165513.263881251,1619242.0069031268],[-10165513.263881251,1616796.021998439],[-10167959.248785937,1616796.021998439]]]]},"properties":{"x":4035,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1619242.0069031268],[-10167959.248785937,1621687.991807811],[-10165513.263881251,1621687.991807811],[-10165513.263881251,1619242.0069031268],[-10167959.248785937,1619242.0069031268]]]]},"properties":{"x":4035,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1621687.991807811],[-10167959.248785937,1624133.9767124988],[-10165513.263881251,1624133.9767124988],[-10165513.263881251,1621687.991807811],[-10167959.248785937,1621687.991807811]]]]},"properties":{"x":4035,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10167959.248785937,1624133.9767124988],[-10167959.248785937,1626579.9616171867],[-10165513.263881251,1626579.9616171867],[-10165513.263881251,1624133.9767124988],[-10167959.248785937,1624133.9767124988]]]]},"properties":{"x":4035,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1562984.3540953137],[-10165513.263881251,1565430.3390000015],[-10163067.278976563,1565430.3390000015],[-10163067.278976563,1562984.3540953137],[-10165513.263881251,1562984.3540953137]]]]},"properties":{"x":4036,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1565430.3390000015],[-10165513.263881251,1567876.3239046894],[-10163067.278976563,1567876.3239046894],[-10163067.278976563,1565430.3390000015],[-10165513.263881251,1565430.3390000015]]]]},"properties":{"x":4036,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1567876.3239046894],[-10165513.263881251,1570322.3088093735],[-10163067.278976563,1570322.3088093735],[-10163067.278976563,1567876.3239046894],[-10165513.263881251,1567876.3239046894]]]]},"properties":{"x":4036,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1570322.3088093735],[-10165513.263881251,1572768.2937140614],[-10163067.278976563,1572768.2937140614],[-10163067.278976563,1570322.3088093735],[-10165513.263881251,1570322.3088093735]]]]},"properties":{"x":4036,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1572768.2937140614],[-10165513.263881251,1575214.2786187492],[-10163067.278976563,1575214.2786187492],[-10163067.278976563,1572768.2937140614],[-10165513.263881251,1572768.2937140614]]]]},"properties":{"x":4036,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1575214.2786187492],[-10165513.263881251,1577660.263523437],[-10163067.278976563,1577660.263523437],[-10163067.278976563,1575214.2786187492],[-10165513.263881251,1575214.2786187492]]]]},"properties":{"x":4036,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1577660.263523437],[-10165513.263881251,1580106.248428125],[-10163067.278976563,1580106.248428125],[-10163067.278976563,1577660.263523437],[-10165513.263881251,1577660.263523437]]]]},"properties":{"x":4036,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1580106.248428125],[-10165513.263881251,1582552.2333328128],[-10163067.278976563,1582552.2333328128],[-10163067.278976563,1580106.248428125],[-10165513.263881251,1580106.248428125]]]]},"properties":{"x":4036,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1582552.2333328128],[-10165513.263881251,1584998.2182375006],[-10163067.278976563,1584998.2182375006],[-10163067.278976563,1582552.2333328128],[-10165513.263881251,1582552.2333328128]]]]},"properties":{"x":4036,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1584998.2182375006],[-10165513.263881251,1587444.2031421885],[-10163067.278976563,1587444.2031421885],[-10163067.278976563,1584998.2182375006],[-10165513.263881251,1584998.2182375006]]]]},"properties":{"x":4036,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1587444.2031421885],[-10165513.263881251,1589890.1880468763],[-10163067.278976563,1589890.1880468763],[-10163067.278976563,1587444.2031421885],[-10165513.263881251,1587444.2031421885]]]]},"properties":{"x":4036,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1589890.1880468763],[-10165513.263881251,1592336.1729515642],[-10163067.278976563,1592336.1729515642],[-10163067.278976563,1589890.1880468763],[-10165513.263881251,1589890.1880468763]]]]},"properties":{"x":4036,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1592336.1729515642],[-10165513.263881251,1594782.1578562483],[-10163067.278976563,1594782.1578562483],[-10163067.278976563,1592336.1729515642],[-10165513.263881251,1592336.1729515642]]]]},"properties":{"x":4036,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1594782.1578562483],[-10165513.263881251,1597228.1427609362],[-10163067.278976563,1597228.1427609362],[-10163067.278976563,1594782.1578562483],[-10165513.263881251,1594782.1578562483]]]]},"properties":{"x":4036,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1597228.1427609362],[-10165513.263881251,1599674.127665624],[-10163067.278976563,1599674.127665624],[-10163067.278976563,1597228.1427609362],[-10165513.263881251,1597228.1427609362]]]]},"properties":{"x":4036,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1599674.127665624],[-10165513.263881251,1602120.1125703119],[-10163067.278976563,1602120.1125703119],[-10163067.278976563,1599674.127665624],[-10165513.263881251,1599674.127665624]]]]},"properties":{"x":4036,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1602120.1125703119],[-10165513.263881251,1604566.0974749997],[-10163067.278976563,1604566.0974749997],[-10163067.278976563,1602120.1125703119],[-10165513.263881251,1602120.1125703119]]]]},"properties":{"x":4036,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1604566.0974749997],[-10165513.263881251,1607012.0823796876],[-10163067.278976563,1607012.0823796876],[-10163067.278976563,1604566.0974749997],[-10165513.263881251,1604566.0974749997]]]]},"properties":{"x":4036,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1607012.0823796876],[-10165513.263881251,1609458.0672843754],[-10163067.278976563,1609458.0672843754],[-10163067.278976563,1607012.0823796876],[-10165513.263881251,1607012.0823796876]]]]},"properties":{"x":4036,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1609458.0672843754],[-10165513.263881251,1611904.0521890633],[-10163067.278976563,1611904.0521890633],[-10163067.278976563,1609458.0672843754],[-10165513.263881251,1609458.0672843754]]]]},"properties":{"x":4036,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1611904.0521890633],[-10165513.263881251,1614350.0370937511],[-10163067.278976563,1614350.0370937511],[-10163067.278976563,1611904.0521890633],[-10165513.263881251,1611904.0521890633]]]]},"properties":{"x":4036,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1614350.0370937511],[-10165513.263881251,1616796.021998439],[-10163067.278976563,1616796.021998439],[-10163067.278976563,1614350.0370937511],[-10165513.263881251,1614350.0370937511]]]]},"properties":{"x":4036,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1616796.021998439],[-10165513.263881251,1619242.0069031268],[-10163067.278976563,1619242.0069031268],[-10163067.278976563,1616796.021998439],[-10165513.263881251,1616796.021998439]]]]},"properties":{"x":4036,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1619242.0069031268],[-10165513.263881251,1621687.991807811],[-10163067.278976563,1621687.991807811],[-10163067.278976563,1619242.0069031268],[-10165513.263881251,1619242.0069031268]]]]},"properties":{"x":4036,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1621687.991807811],[-10165513.263881251,1624133.9767124988],[-10163067.278976563,1624133.9767124988],[-10163067.278976563,1621687.991807811],[-10165513.263881251,1621687.991807811]]]]},"properties":{"x":4036,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10165513.263881251,1624133.9767124988],[-10165513.263881251,1626579.9616171867],[-10163067.278976563,1626579.9616171867],[-10163067.278976563,1624133.9767124988],[-10165513.263881251,1624133.9767124988]]]]},"properties":{"x":4036,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1562984.3540953137],[-10163067.278976563,1565430.3390000015],[-10160621.294071876,1565430.3390000015],[-10160621.294071876,1562984.3540953137],[-10163067.278976563,1562984.3540953137]]]]},"properties":{"x":4037,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1565430.3390000015],[-10163067.278976563,1567876.3239046894],[-10160621.294071876,1567876.3239046894],[-10160621.294071876,1565430.3390000015],[-10163067.278976563,1565430.3390000015]]]]},"properties":{"x":4037,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1567876.3239046894],[-10163067.278976563,1570322.3088093735],[-10160621.294071876,1570322.3088093735],[-10160621.294071876,1567876.3239046894],[-10163067.278976563,1567876.3239046894]]]]},"properties":{"x":4037,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1570322.3088093735],[-10163067.278976563,1572768.2937140614],[-10160621.294071876,1572768.2937140614],[-10160621.294071876,1570322.3088093735],[-10163067.278976563,1570322.3088093735]]]]},"properties":{"x":4037,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1572768.2937140614],[-10163067.278976563,1575214.2786187492],[-10160621.294071876,1575214.2786187492],[-10160621.294071876,1572768.2937140614],[-10163067.278976563,1572768.2937140614]]]]},"properties":{"x":4037,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1575214.2786187492],[-10163067.278976563,1577660.263523437],[-10160621.294071876,1577660.263523437],[-10160621.294071876,1575214.2786187492],[-10163067.278976563,1575214.2786187492]]]]},"properties":{"x":4037,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1577660.263523437],[-10163067.278976563,1580106.248428125],[-10160621.294071876,1580106.248428125],[-10160621.294071876,1577660.263523437],[-10163067.278976563,1577660.263523437]]]]},"properties":{"x":4037,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1580106.248428125],[-10163067.278976563,1582552.2333328128],[-10160621.294071876,1582552.2333328128],[-10160621.294071876,1580106.248428125],[-10163067.278976563,1580106.248428125]]]]},"properties":{"x":4037,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1582552.2333328128],[-10163067.278976563,1584998.2182375006],[-10160621.294071876,1584998.2182375006],[-10160621.294071876,1582552.2333328128],[-10163067.278976563,1582552.2333328128]]]]},"properties":{"x":4037,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1584998.2182375006],[-10163067.278976563,1587444.2031421885],[-10160621.294071876,1587444.2031421885],[-10160621.294071876,1584998.2182375006],[-10163067.278976563,1584998.2182375006]]]]},"properties":{"x":4037,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1587444.2031421885],[-10163067.278976563,1589890.1880468763],[-10160621.294071876,1589890.1880468763],[-10160621.294071876,1587444.2031421885],[-10163067.278976563,1587444.2031421885]]]]},"properties":{"x":4037,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1589890.1880468763],[-10163067.278976563,1592336.1729515642],[-10160621.294071876,1592336.1729515642],[-10160621.294071876,1589890.1880468763],[-10163067.278976563,1589890.1880468763]]]]},"properties":{"x":4037,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1592336.1729515642],[-10163067.278976563,1594782.1578562483],[-10160621.294071876,1594782.1578562483],[-10160621.294071876,1592336.1729515642],[-10163067.278976563,1592336.1729515642]]]]},"properties":{"x":4037,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1594782.1578562483],[-10163067.278976563,1597228.1427609362],[-10160621.294071876,1597228.1427609362],[-10160621.294071876,1594782.1578562483],[-10163067.278976563,1594782.1578562483]]]]},"properties":{"x":4037,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1597228.1427609362],[-10163067.278976563,1599674.127665624],[-10160621.294071876,1599674.127665624],[-10160621.294071876,1597228.1427609362],[-10163067.278976563,1597228.1427609362]]]]},"properties":{"x":4037,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1599674.127665624],[-10163067.278976563,1602120.1125703119],[-10160621.294071876,1602120.1125703119],[-10160621.294071876,1599674.127665624],[-10163067.278976563,1599674.127665624]]]]},"properties":{"x":4037,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1602120.1125703119],[-10163067.278976563,1604566.0974749997],[-10160621.294071876,1604566.0974749997],[-10160621.294071876,1602120.1125703119],[-10163067.278976563,1602120.1125703119]]]]},"properties":{"x":4037,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1604566.0974749997],[-10163067.278976563,1607012.0823796876],[-10160621.294071876,1607012.0823796876],[-10160621.294071876,1604566.0974749997],[-10163067.278976563,1604566.0974749997]]]]},"properties":{"x":4037,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1607012.0823796876],[-10163067.278976563,1609458.0672843754],[-10160621.294071876,1609458.0672843754],[-10160621.294071876,1607012.0823796876],[-10163067.278976563,1607012.0823796876]]]]},"properties":{"x":4037,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1609458.0672843754],[-10163067.278976563,1611904.0521890633],[-10160621.294071876,1611904.0521890633],[-10160621.294071876,1609458.0672843754],[-10163067.278976563,1609458.0672843754]]]]},"properties":{"x":4037,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1611904.0521890633],[-10163067.278976563,1614350.0370937511],[-10160621.294071876,1614350.0370937511],[-10160621.294071876,1611904.0521890633],[-10163067.278976563,1611904.0521890633]]]]},"properties":{"x":4037,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1614350.0370937511],[-10163067.278976563,1616796.021998439],[-10160621.294071876,1616796.021998439],[-10160621.294071876,1614350.0370937511],[-10163067.278976563,1614350.0370937511]]]]},"properties":{"x":4037,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1616796.021998439],[-10163067.278976563,1619242.0069031268],[-10160621.294071876,1619242.0069031268],[-10160621.294071876,1616796.021998439],[-10163067.278976563,1616796.021998439]]]]},"properties":{"x":4037,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1619242.0069031268],[-10163067.278976563,1621687.991807811],[-10160621.294071876,1621687.991807811],[-10160621.294071876,1619242.0069031268],[-10163067.278976563,1619242.0069031268]]]]},"properties":{"x":4037,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1621687.991807811],[-10163067.278976563,1624133.9767124988],[-10160621.294071876,1624133.9767124988],[-10160621.294071876,1621687.991807811],[-10163067.278976563,1621687.991807811]]]]},"properties":{"x":4037,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10163067.278976563,1624133.9767124988],[-10163067.278976563,1626579.9616171867],[-10160621.294071876,1626579.9616171867],[-10160621.294071876,1624133.9767124988],[-10163067.278976563,1624133.9767124988]]]]},"properties":{"x":4037,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1562984.3540953137],[-10160621.294071876,1565430.3390000015],[-10158175.309167188,1565430.3390000015],[-10158175.309167188,1562984.3540953137],[-10160621.294071876,1562984.3540953137]]]]},"properties":{"x":4038,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1565430.3390000015],[-10160621.294071876,1567876.3239046894],[-10158175.309167188,1567876.3239046894],[-10158175.309167188,1565430.3390000015],[-10160621.294071876,1565430.3390000015]]]]},"properties":{"x":4038,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1567876.3239046894],[-10160621.294071876,1570322.3088093735],[-10158175.309167188,1570322.3088093735],[-10158175.309167188,1567876.3239046894],[-10160621.294071876,1567876.3239046894]]]]},"properties":{"x":4038,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1570322.3088093735],[-10160621.294071876,1572768.2937140614],[-10158175.309167188,1572768.2937140614],[-10158175.309167188,1570322.3088093735],[-10160621.294071876,1570322.3088093735]]]]},"properties":{"x":4038,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1572768.2937140614],[-10160621.294071876,1575214.2786187492],[-10158175.309167188,1575214.2786187492],[-10158175.309167188,1572768.2937140614],[-10160621.294071876,1572768.2937140614]]]]},"properties":{"x":4038,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1575214.2786187492],[-10160621.294071876,1577660.263523437],[-10158175.309167188,1577660.263523437],[-10158175.309167188,1575214.2786187492],[-10160621.294071876,1575214.2786187492]]]]},"properties":{"x":4038,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1577660.263523437],[-10160621.294071876,1580106.248428125],[-10158175.309167188,1580106.248428125],[-10158175.309167188,1577660.263523437],[-10160621.294071876,1577660.263523437]]]]},"properties":{"x":4038,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1580106.248428125],[-10160621.294071876,1582552.2333328128],[-10158175.309167188,1582552.2333328128],[-10158175.309167188,1580106.248428125],[-10160621.294071876,1580106.248428125]]]]},"properties":{"x":4038,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1582552.2333328128],[-10160621.294071876,1584998.2182375006],[-10158175.309167188,1584998.2182375006],[-10158175.309167188,1582552.2333328128],[-10160621.294071876,1582552.2333328128]]]]},"properties":{"x":4038,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1584998.2182375006],[-10160621.294071876,1587444.2031421885],[-10158175.309167188,1587444.2031421885],[-10158175.309167188,1584998.2182375006],[-10160621.294071876,1584998.2182375006]]]]},"properties":{"x":4038,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1587444.2031421885],[-10160621.294071876,1589890.1880468763],[-10158175.309167188,1589890.1880468763],[-10158175.309167188,1587444.2031421885],[-10160621.294071876,1587444.2031421885]]]]},"properties":{"x":4038,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1589890.1880468763],[-10160621.294071876,1592336.1729515642],[-10158175.309167188,1592336.1729515642],[-10158175.309167188,1589890.1880468763],[-10160621.294071876,1589890.1880468763]]]]},"properties":{"x":4038,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1592336.1729515642],[-10160621.294071876,1594782.1578562483],[-10158175.309167188,1594782.1578562483],[-10158175.309167188,1592336.1729515642],[-10160621.294071876,1592336.1729515642]]]]},"properties":{"x":4038,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1594782.1578562483],[-10160621.294071876,1597228.1427609362],[-10158175.309167188,1597228.1427609362],[-10158175.309167188,1594782.1578562483],[-10160621.294071876,1594782.1578562483]]]]},"properties":{"x":4038,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1597228.1427609362],[-10160621.294071876,1599674.127665624],[-10158175.309167188,1599674.127665624],[-10158175.309167188,1597228.1427609362],[-10160621.294071876,1597228.1427609362]]]]},"properties":{"x":4038,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1599674.127665624],[-10160621.294071876,1602120.1125703119],[-10158175.309167188,1602120.1125703119],[-10158175.309167188,1599674.127665624],[-10160621.294071876,1599674.127665624]]]]},"properties":{"x":4038,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1602120.1125703119],[-10160621.294071876,1604566.0974749997],[-10158175.309167188,1604566.0974749997],[-10158175.309167188,1602120.1125703119],[-10160621.294071876,1602120.1125703119]]]]},"properties":{"x":4038,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1604566.0974749997],[-10160621.294071876,1607012.0823796876],[-10158175.309167188,1607012.0823796876],[-10158175.309167188,1604566.0974749997],[-10160621.294071876,1604566.0974749997]]]]},"properties":{"x":4038,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1607012.0823796876],[-10160621.294071876,1609458.0672843754],[-10158175.309167188,1609458.0672843754],[-10158175.309167188,1607012.0823796876],[-10160621.294071876,1607012.0823796876]]]]},"properties":{"x":4038,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1609458.0672843754],[-10160621.294071876,1611904.0521890633],[-10158175.309167188,1611904.0521890633],[-10158175.309167188,1609458.0672843754],[-10160621.294071876,1609458.0672843754]]]]},"properties":{"x":4038,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1611904.0521890633],[-10160621.294071876,1614350.0370937511],[-10158175.309167188,1614350.0370937511],[-10158175.309167188,1611904.0521890633],[-10160621.294071876,1611904.0521890633]]]]},"properties":{"x":4038,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1614350.0370937511],[-10160621.294071876,1616796.021998439],[-10158175.309167188,1616796.021998439],[-10158175.309167188,1614350.0370937511],[-10160621.294071876,1614350.0370937511]]]]},"properties":{"x":4038,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1616796.021998439],[-10160621.294071876,1619242.0069031268],[-10158175.309167188,1619242.0069031268],[-10158175.309167188,1616796.021998439],[-10160621.294071876,1616796.021998439]]]]},"properties":{"x":4038,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1619242.0069031268],[-10160621.294071876,1621687.991807811],[-10158175.309167188,1621687.991807811],[-10158175.309167188,1619242.0069031268],[-10160621.294071876,1619242.0069031268]]]]},"properties":{"x":4038,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1621687.991807811],[-10160621.294071876,1624133.9767124988],[-10158175.309167188,1624133.9767124988],[-10158175.309167188,1621687.991807811],[-10160621.294071876,1621687.991807811]]]]},"properties":{"x":4038,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10160621.294071876,1624133.9767124988],[-10160621.294071876,1626579.9616171867],[-10158175.309167188,1626579.9616171867],[-10158175.309167188,1624133.9767124988],[-10160621.294071876,1624133.9767124988]]]]},"properties":{"x":4038,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1562984.3540953137],[-10158175.309167188,1565430.3390000015],[-10155729.3242625,1565430.3390000015],[-10155729.3242625,1562984.3540953137],[-10158175.309167188,1562984.3540953137]]]]},"properties":{"x":4039,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1565430.3390000015],[-10158175.309167188,1567876.3239046894],[-10155729.3242625,1567876.3239046894],[-10155729.3242625,1565430.3390000015],[-10158175.309167188,1565430.3390000015]]]]},"properties":{"x":4039,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1567876.3239046894],[-10158175.309167188,1570322.3088093735],[-10155729.3242625,1570322.3088093735],[-10155729.3242625,1567876.3239046894],[-10158175.309167188,1567876.3239046894]]]]},"properties":{"x":4039,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1570322.3088093735],[-10158175.309167188,1572768.2937140614],[-10155729.3242625,1572768.2937140614],[-10155729.3242625,1570322.3088093735],[-10158175.309167188,1570322.3088093735]]]]},"properties":{"x":4039,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1572768.2937140614],[-10158175.309167188,1575214.2786187492],[-10155729.3242625,1575214.2786187492],[-10155729.3242625,1572768.2937140614],[-10158175.309167188,1572768.2937140614]]]]},"properties":{"x":4039,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1575214.2786187492],[-10158175.309167188,1577660.263523437],[-10155729.3242625,1577660.263523437],[-10155729.3242625,1575214.2786187492],[-10158175.309167188,1575214.2786187492]]]]},"properties":{"x":4039,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1577660.263523437],[-10158175.309167188,1580106.248428125],[-10155729.3242625,1580106.248428125],[-10155729.3242625,1577660.263523437],[-10158175.309167188,1577660.263523437]]]]},"properties":{"x":4039,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1580106.248428125],[-10158175.309167188,1582552.2333328128],[-10155729.3242625,1582552.2333328128],[-10155729.3242625,1580106.248428125],[-10158175.309167188,1580106.248428125]]]]},"properties":{"x":4039,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1582552.2333328128],[-10158175.309167188,1584998.2182375006],[-10155729.3242625,1584998.2182375006],[-10155729.3242625,1582552.2333328128],[-10158175.309167188,1582552.2333328128]]]]},"properties":{"x":4039,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1584998.2182375006],[-10158175.309167188,1587444.2031421885],[-10155729.3242625,1587444.2031421885],[-10155729.3242625,1584998.2182375006],[-10158175.309167188,1584998.2182375006]]]]},"properties":{"x":4039,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1587444.2031421885],[-10158175.309167188,1589890.1880468763],[-10155729.3242625,1589890.1880468763],[-10155729.3242625,1587444.2031421885],[-10158175.309167188,1587444.2031421885]]]]},"properties":{"x":4039,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1589890.1880468763],[-10158175.309167188,1592336.1729515642],[-10155729.3242625,1592336.1729515642],[-10155729.3242625,1589890.1880468763],[-10158175.309167188,1589890.1880468763]]]]},"properties":{"x":4039,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1592336.1729515642],[-10158175.309167188,1594782.1578562483],[-10155729.3242625,1594782.1578562483],[-10155729.3242625,1592336.1729515642],[-10158175.309167188,1592336.1729515642]]]]},"properties":{"x":4039,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1594782.1578562483],[-10158175.309167188,1597228.1427609362],[-10155729.3242625,1597228.1427609362],[-10155729.3242625,1594782.1578562483],[-10158175.309167188,1594782.1578562483]]]]},"properties":{"x":4039,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1597228.1427609362],[-10158175.309167188,1599674.127665624],[-10155729.3242625,1599674.127665624],[-10155729.3242625,1597228.1427609362],[-10158175.309167188,1597228.1427609362]]]]},"properties":{"x":4039,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1599674.127665624],[-10158175.309167188,1602120.1125703119],[-10155729.3242625,1602120.1125703119],[-10155729.3242625,1599674.127665624],[-10158175.309167188,1599674.127665624]]]]},"properties":{"x":4039,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1602120.1125703119],[-10158175.309167188,1604566.0974749997],[-10155729.3242625,1604566.0974749997],[-10155729.3242625,1602120.1125703119],[-10158175.309167188,1602120.1125703119]]]]},"properties":{"x":4039,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1604566.0974749997],[-10158175.309167188,1607012.0823796876],[-10155729.3242625,1607012.0823796876],[-10155729.3242625,1604566.0974749997],[-10158175.309167188,1604566.0974749997]]]]},"properties":{"x":4039,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1607012.0823796876],[-10158175.309167188,1609458.0672843754],[-10155729.3242625,1609458.0672843754],[-10155729.3242625,1607012.0823796876],[-10158175.309167188,1607012.0823796876]]]]},"properties":{"x":4039,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1609458.0672843754],[-10158175.309167188,1611904.0521890633],[-10155729.3242625,1611904.0521890633],[-10155729.3242625,1609458.0672843754],[-10158175.309167188,1609458.0672843754]]]]},"properties":{"x":4039,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1611904.0521890633],[-10158175.309167188,1614350.0370937511],[-10155729.3242625,1614350.0370937511],[-10155729.3242625,1611904.0521890633],[-10158175.309167188,1611904.0521890633]]]]},"properties":{"x":4039,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1614350.0370937511],[-10158175.309167188,1616796.021998439],[-10155729.3242625,1616796.021998439],[-10155729.3242625,1614350.0370937511],[-10158175.309167188,1614350.0370937511]]]]},"properties":{"x":4039,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1616796.021998439],[-10158175.309167188,1619242.0069031268],[-10155729.3242625,1619242.0069031268],[-10155729.3242625,1616796.021998439],[-10158175.309167188,1616796.021998439]]]]},"properties":{"x":4039,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1619242.0069031268],[-10158175.309167188,1621687.991807811],[-10155729.3242625,1621687.991807811],[-10155729.3242625,1619242.0069031268],[-10158175.309167188,1619242.0069031268]]]]},"properties":{"x":4039,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1621687.991807811],[-10158175.309167188,1624133.9767124988],[-10155729.3242625,1624133.9767124988],[-10155729.3242625,1621687.991807811],[-10158175.309167188,1621687.991807811]]]]},"properties":{"x":4039,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10158175.309167188,1624133.9767124988],[-10158175.309167188,1626579.9616171867],[-10155729.3242625,1626579.9616171867],[-10155729.3242625,1624133.9767124988],[-10158175.309167188,1624133.9767124988]]]]},"properties":{"x":4039,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1562984.3540953137],[-10155729.3242625,1565430.3390000015],[-10153283.339357814,1565430.3390000015],[-10153283.339357814,1562984.3540953137],[-10155729.3242625,1562984.3540953137]]]]},"properties":{"x":4040,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1565430.3390000015],[-10155729.3242625,1567876.3239046894],[-10153283.339357814,1567876.3239046894],[-10153283.339357814,1565430.3390000015],[-10155729.3242625,1565430.3390000015]]]]},"properties":{"x":4040,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1567876.3239046894],[-10155729.3242625,1570322.3088093735],[-10153283.339357814,1570322.3088093735],[-10153283.339357814,1567876.3239046894],[-10155729.3242625,1567876.3239046894]]]]},"properties":{"x":4040,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1570322.3088093735],[-10155729.3242625,1572768.2937140614],[-10153283.339357814,1572768.2937140614],[-10153283.339357814,1570322.3088093735],[-10155729.3242625,1570322.3088093735]]]]},"properties":{"x":4040,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1572768.2937140614],[-10155729.3242625,1575214.2786187492],[-10153283.339357814,1575214.2786187492],[-10153283.339357814,1572768.2937140614],[-10155729.3242625,1572768.2937140614]]]]},"properties":{"x":4040,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1575214.2786187492],[-10155729.3242625,1577660.263523437],[-10153283.339357814,1577660.263523437],[-10153283.339357814,1575214.2786187492],[-10155729.3242625,1575214.2786187492]]]]},"properties":{"x":4040,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1577660.263523437],[-10155729.3242625,1580106.248428125],[-10153283.339357814,1580106.248428125],[-10153283.339357814,1577660.263523437],[-10155729.3242625,1577660.263523437]]]]},"properties":{"x":4040,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1580106.248428125],[-10155729.3242625,1582552.2333328128],[-10153283.339357814,1582552.2333328128],[-10153283.339357814,1580106.248428125],[-10155729.3242625,1580106.248428125]]]]},"properties":{"x":4040,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1582552.2333328128],[-10155729.3242625,1584998.2182375006],[-10153283.339357814,1584998.2182375006],[-10153283.339357814,1582552.2333328128],[-10155729.3242625,1582552.2333328128]]]]},"properties":{"x":4040,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1584998.2182375006],[-10155729.3242625,1587444.2031421885],[-10153283.339357814,1587444.2031421885],[-10153283.339357814,1584998.2182375006],[-10155729.3242625,1584998.2182375006]]]]},"properties":{"x":4040,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1587444.2031421885],[-10155729.3242625,1589890.1880468763],[-10153283.339357814,1589890.1880468763],[-10153283.339357814,1587444.2031421885],[-10155729.3242625,1587444.2031421885]]]]},"properties":{"x":4040,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1589890.1880468763],[-10155729.3242625,1592336.1729515642],[-10153283.339357814,1592336.1729515642],[-10153283.339357814,1589890.1880468763],[-10155729.3242625,1589890.1880468763]]]]},"properties":{"x":4040,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1592336.1729515642],[-10155729.3242625,1594782.1578562483],[-10153283.339357814,1594782.1578562483],[-10153283.339357814,1592336.1729515642],[-10155729.3242625,1592336.1729515642]]]]},"properties":{"x":4040,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1594782.1578562483],[-10155729.3242625,1597228.1427609362],[-10153283.339357814,1597228.1427609362],[-10153283.339357814,1594782.1578562483],[-10155729.3242625,1594782.1578562483]]]]},"properties":{"x":4040,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1597228.1427609362],[-10155729.3242625,1599674.127665624],[-10153283.339357814,1599674.127665624],[-10153283.339357814,1597228.1427609362],[-10155729.3242625,1597228.1427609362]]]]},"properties":{"x":4040,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1599674.127665624],[-10155729.3242625,1602120.1125703119],[-10153283.339357814,1602120.1125703119],[-10153283.339357814,1599674.127665624],[-10155729.3242625,1599674.127665624]]]]},"properties":{"x":4040,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1602120.1125703119],[-10155729.3242625,1604566.0974749997],[-10153283.339357814,1604566.0974749997],[-10153283.339357814,1602120.1125703119],[-10155729.3242625,1602120.1125703119]]]]},"properties":{"x":4040,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1604566.0974749997],[-10155729.3242625,1607012.0823796876],[-10153283.339357814,1607012.0823796876],[-10153283.339357814,1604566.0974749997],[-10155729.3242625,1604566.0974749997]]]]},"properties":{"x":4040,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1607012.0823796876],[-10155729.3242625,1609458.0672843754],[-10153283.339357814,1609458.0672843754],[-10153283.339357814,1607012.0823796876],[-10155729.3242625,1607012.0823796876]]]]},"properties":{"x":4040,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1609458.0672843754],[-10155729.3242625,1611904.0521890633],[-10153283.339357814,1611904.0521890633],[-10153283.339357814,1609458.0672843754],[-10155729.3242625,1609458.0672843754]]]]},"properties":{"x":4040,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1611904.0521890633],[-10155729.3242625,1614350.0370937511],[-10153283.339357814,1614350.0370937511],[-10153283.339357814,1611904.0521890633],[-10155729.3242625,1611904.0521890633]]]]},"properties":{"x":4040,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1614350.0370937511],[-10155729.3242625,1616796.021998439],[-10153283.339357814,1616796.021998439],[-10153283.339357814,1614350.0370937511],[-10155729.3242625,1614350.0370937511]]]]},"properties":{"x":4040,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1616796.021998439],[-10155729.3242625,1619242.0069031268],[-10153283.339357814,1619242.0069031268],[-10153283.339357814,1616796.021998439],[-10155729.3242625,1616796.021998439]]]]},"properties":{"x":4040,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1619242.0069031268],[-10155729.3242625,1621687.991807811],[-10153283.339357814,1621687.991807811],[-10153283.339357814,1619242.0069031268],[-10155729.3242625,1619242.0069031268]]]]},"properties":{"x":4040,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1621687.991807811],[-10155729.3242625,1624133.9767124988],[-10153283.339357814,1624133.9767124988],[-10153283.339357814,1621687.991807811],[-10155729.3242625,1621687.991807811]]]]},"properties":{"x":4040,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10155729.3242625,1624133.9767124988],[-10155729.3242625,1626579.9616171867],[-10153283.339357814,1626579.9616171867],[-10153283.339357814,1624133.9767124988],[-10155729.3242625,1624133.9767124988]]]]},"properties":{"x":4040,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1562984.3540953137],[-10153283.339357814,1565430.3390000015],[-10150837.354453126,1565430.3390000015],[-10150837.354453126,1562984.3540953137],[-10153283.339357814,1562984.3540953137]]]]},"properties":{"x":4041,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1565430.3390000015],[-10153283.339357814,1567876.3239046894],[-10150837.354453126,1567876.3239046894],[-10150837.354453126,1565430.3390000015],[-10153283.339357814,1565430.3390000015]]]]},"properties":{"x":4041,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1567876.3239046894],[-10153283.339357814,1570322.3088093735],[-10150837.354453126,1570322.3088093735],[-10150837.354453126,1567876.3239046894],[-10153283.339357814,1567876.3239046894]]]]},"properties":{"x":4041,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1570322.3088093735],[-10153283.339357814,1572768.2937140614],[-10150837.354453126,1572768.2937140614],[-10150837.354453126,1570322.3088093735],[-10153283.339357814,1570322.3088093735]]]]},"properties":{"x":4041,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1572768.2937140614],[-10153283.339357814,1575214.2786187492],[-10150837.354453126,1575214.2786187492],[-10150837.354453126,1572768.2937140614],[-10153283.339357814,1572768.2937140614]]]]},"properties":{"x":4041,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1575214.2786187492],[-10153283.339357814,1577660.263523437],[-10150837.354453126,1577660.263523437],[-10150837.354453126,1575214.2786187492],[-10153283.339357814,1575214.2786187492]]]]},"properties":{"x":4041,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1577660.263523437],[-10153283.339357814,1580106.248428125],[-10150837.354453126,1580106.248428125],[-10150837.354453126,1577660.263523437],[-10153283.339357814,1577660.263523437]]]]},"properties":{"x":4041,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1580106.248428125],[-10153283.339357814,1582552.2333328128],[-10150837.354453126,1582552.2333328128],[-10150837.354453126,1580106.248428125],[-10153283.339357814,1580106.248428125]]]]},"properties":{"x":4041,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1582552.2333328128],[-10153283.339357814,1584998.2182375006],[-10150837.354453126,1584998.2182375006],[-10150837.354453126,1582552.2333328128],[-10153283.339357814,1582552.2333328128]]]]},"properties":{"x":4041,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1584998.2182375006],[-10153283.339357814,1587444.2031421885],[-10150837.354453126,1587444.2031421885],[-10150837.354453126,1584998.2182375006],[-10153283.339357814,1584998.2182375006]]]]},"properties":{"x":4041,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1587444.2031421885],[-10153283.339357814,1589890.1880468763],[-10150837.354453126,1589890.1880468763],[-10150837.354453126,1587444.2031421885],[-10153283.339357814,1587444.2031421885]]]]},"properties":{"x":4041,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1589890.1880468763],[-10153283.339357814,1592336.1729515642],[-10150837.354453126,1592336.1729515642],[-10150837.354453126,1589890.1880468763],[-10153283.339357814,1589890.1880468763]]]]},"properties":{"x":4041,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1592336.1729515642],[-10153283.339357814,1594782.1578562483],[-10150837.354453126,1594782.1578562483],[-10150837.354453126,1592336.1729515642],[-10153283.339357814,1592336.1729515642]]]]},"properties":{"x":4041,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1594782.1578562483],[-10153283.339357814,1597228.1427609362],[-10150837.354453126,1597228.1427609362],[-10150837.354453126,1594782.1578562483],[-10153283.339357814,1594782.1578562483]]]]},"properties":{"x":4041,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1597228.1427609362],[-10153283.339357814,1599674.127665624],[-10150837.354453126,1599674.127665624],[-10150837.354453126,1597228.1427609362],[-10153283.339357814,1597228.1427609362]]]]},"properties":{"x":4041,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1599674.127665624],[-10153283.339357814,1602120.1125703119],[-10150837.354453126,1602120.1125703119],[-10150837.354453126,1599674.127665624],[-10153283.339357814,1599674.127665624]]]]},"properties":{"x":4041,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1602120.1125703119],[-10153283.339357814,1604566.0974749997],[-10150837.354453126,1604566.0974749997],[-10150837.354453126,1602120.1125703119],[-10153283.339357814,1602120.1125703119]]]]},"properties":{"x":4041,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1604566.0974749997],[-10153283.339357814,1607012.0823796876],[-10150837.354453126,1607012.0823796876],[-10150837.354453126,1604566.0974749997],[-10153283.339357814,1604566.0974749997]]]]},"properties":{"x":4041,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1607012.0823796876],[-10153283.339357814,1609458.0672843754],[-10150837.354453126,1609458.0672843754],[-10150837.354453126,1607012.0823796876],[-10153283.339357814,1607012.0823796876]]]]},"properties":{"x":4041,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1609458.0672843754],[-10153283.339357814,1611904.0521890633],[-10150837.354453126,1611904.0521890633],[-10150837.354453126,1609458.0672843754],[-10153283.339357814,1609458.0672843754]]]]},"properties":{"x":4041,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1611904.0521890633],[-10153283.339357814,1614350.0370937511],[-10150837.354453126,1614350.0370937511],[-10150837.354453126,1611904.0521890633],[-10153283.339357814,1611904.0521890633]]]]},"properties":{"x":4041,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1614350.0370937511],[-10153283.339357814,1616796.021998439],[-10150837.354453126,1616796.021998439],[-10150837.354453126,1614350.0370937511],[-10153283.339357814,1614350.0370937511]]]]},"properties":{"x":4041,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1616796.021998439],[-10153283.339357814,1619242.0069031268],[-10150837.354453126,1619242.0069031268],[-10150837.354453126,1616796.021998439],[-10153283.339357814,1616796.021998439]]]]},"properties":{"x":4041,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1619242.0069031268],[-10153283.339357814,1621687.991807811],[-10150837.354453126,1621687.991807811],[-10150837.354453126,1619242.0069031268],[-10153283.339357814,1619242.0069031268]]]]},"properties":{"x":4041,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1621687.991807811],[-10153283.339357814,1624133.9767124988],[-10150837.354453126,1624133.9767124988],[-10150837.354453126,1621687.991807811],[-10153283.339357814,1621687.991807811]]]]},"properties":{"x":4041,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10153283.339357814,1624133.9767124988],[-10153283.339357814,1626579.9616171867],[-10150837.354453126,1626579.9616171867],[-10150837.354453126,1624133.9767124988],[-10153283.339357814,1624133.9767124988]]]]},"properties":{"x":4041,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1562984.3540953137],[-10150837.354453126,1565430.3390000015],[-10148391.369548438,1565430.3390000015],[-10148391.369548438,1562984.3540953137],[-10150837.354453126,1562984.3540953137]]]]},"properties":{"x":4042,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1565430.3390000015],[-10150837.354453126,1567876.3239046894],[-10148391.369548438,1567876.3239046894],[-10148391.369548438,1565430.3390000015],[-10150837.354453126,1565430.3390000015]]]]},"properties":{"x":4042,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1567876.3239046894],[-10150837.354453126,1570322.3088093735],[-10148391.369548438,1570322.3088093735],[-10148391.369548438,1567876.3239046894],[-10150837.354453126,1567876.3239046894]]]]},"properties":{"x":4042,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1570322.3088093735],[-10150837.354453126,1572768.2937140614],[-10148391.369548438,1572768.2937140614],[-10148391.369548438,1570322.3088093735],[-10150837.354453126,1570322.3088093735]]]]},"properties":{"x":4042,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1572768.2937140614],[-10150837.354453126,1575214.2786187492],[-10148391.369548438,1575214.2786187492],[-10148391.369548438,1572768.2937140614],[-10150837.354453126,1572768.2937140614]]]]},"properties":{"x":4042,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1575214.2786187492],[-10150837.354453126,1577660.263523437],[-10148391.369548438,1577660.263523437],[-10148391.369548438,1575214.2786187492],[-10150837.354453126,1575214.2786187492]]]]},"properties":{"x":4042,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1577660.263523437],[-10150837.354453126,1580106.248428125],[-10148391.369548438,1580106.248428125],[-10148391.369548438,1577660.263523437],[-10150837.354453126,1577660.263523437]]]]},"properties":{"x":4042,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1580106.248428125],[-10150837.354453126,1582552.2333328128],[-10148391.369548438,1582552.2333328128],[-10148391.369548438,1580106.248428125],[-10150837.354453126,1580106.248428125]]]]},"properties":{"x":4042,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1582552.2333328128],[-10150837.354453126,1584998.2182375006],[-10148391.369548438,1584998.2182375006],[-10148391.369548438,1582552.2333328128],[-10150837.354453126,1582552.2333328128]]]]},"properties":{"x":4042,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1584998.2182375006],[-10150837.354453126,1587444.2031421885],[-10148391.369548438,1587444.2031421885],[-10148391.369548438,1584998.2182375006],[-10150837.354453126,1584998.2182375006]]]]},"properties":{"x":4042,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1587444.2031421885],[-10150837.354453126,1589890.1880468763],[-10148391.369548438,1589890.1880468763],[-10148391.369548438,1587444.2031421885],[-10150837.354453126,1587444.2031421885]]]]},"properties":{"x":4042,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1589890.1880468763],[-10150837.354453126,1592336.1729515642],[-10148391.369548438,1592336.1729515642],[-10148391.369548438,1589890.1880468763],[-10150837.354453126,1589890.1880468763]]]]},"properties":{"x":4042,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1592336.1729515642],[-10150837.354453126,1594782.1578562483],[-10148391.369548438,1594782.1578562483],[-10148391.369548438,1592336.1729515642],[-10150837.354453126,1592336.1729515642]]]]},"properties":{"x":4042,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1594782.1578562483],[-10150837.354453126,1597228.1427609362],[-10148391.369548438,1597228.1427609362],[-10148391.369548438,1594782.1578562483],[-10150837.354453126,1594782.1578562483]]]]},"properties":{"x":4042,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1597228.1427609362],[-10150837.354453126,1599674.127665624],[-10148391.369548438,1599674.127665624],[-10148391.369548438,1597228.1427609362],[-10150837.354453126,1597228.1427609362]]]]},"properties":{"x":4042,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1599674.127665624],[-10150837.354453126,1602120.1125703119],[-10148391.369548438,1602120.1125703119],[-10148391.369548438,1599674.127665624],[-10150837.354453126,1599674.127665624]]]]},"properties":{"x":4042,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1602120.1125703119],[-10150837.354453126,1604566.0974749997],[-10148391.369548438,1604566.0974749997],[-10148391.369548438,1602120.1125703119],[-10150837.354453126,1602120.1125703119]]]]},"properties":{"x":4042,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1604566.0974749997],[-10150837.354453126,1607012.0823796876],[-10148391.369548438,1607012.0823796876],[-10148391.369548438,1604566.0974749997],[-10150837.354453126,1604566.0974749997]]]]},"properties":{"x":4042,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1607012.0823796876],[-10150837.354453126,1609458.0672843754],[-10148391.369548438,1609458.0672843754],[-10148391.369548438,1607012.0823796876],[-10150837.354453126,1607012.0823796876]]]]},"properties":{"x":4042,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1609458.0672843754],[-10150837.354453126,1611904.0521890633],[-10148391.369548438,1611904.0521890633],[-10148391.369548438,1609458.0672843754],[-10150837.354453126,1609458.0672843754]]]]},"properties":{"x":4042,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1611904.0521890633],[-10150837.354453126,1614350.0370937511],[-10148391.369548438,1614350.0370937511],[-10148391.369548438,1611904.0521890633],[-10150837.354453126,1611904.0521890633]]]]},"properties":{"x":4042,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1614350.0370937511],[-10150837.354453126,1616796.021998439],[-10148391.369548438,1616796.021998439],[-10148391.369548438,1614350.0370937511],[-10150837.354453126,1614350.0370937511]]]]},"properties":{"x":4042,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1616796.021998439],[-10150837.354453126,1619242.0069031268],[-10148391.369548438,1619242.0069031268],[-10148391.369548438,1616796.021998439],[-10150837.354453126,1616796.021998439]]]]},"properties":{"x":4042,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1619242.0069031268],[-10150837.354453126,1621687.991807811],[-10148391.369548438,1621687.991807811],[-10148391.369548438,1619242.0069031268],[-10150837.354453126,1619242.0069031268]]]]},"properties":{"x":4042,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1621687.991807811],[-10150837.354453126,1624133.9767124988],[-10148391.369548438,1624133.9767124988],[-10148391.369548438,1621687.991807811],[-10150837.354453126,1621687.991807811]]]]},"properties":{"x":4042,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10150837.354453126,1624133.9767124988],[-10150837.354453126,1626579.9616171867],[-10148391.369548438,1626579.9616171867],[-10148391.369548438,1624133.9767124988],[-10150837.354453126,1624133.9767124988]]]]},"properties":{"x":4042,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1562984.3540953137],[-10148391.369548438,1565430.3390000015],[-10145945.38464375,1565430.3390000015],[-10145945.38464375,1562984.3540953137],[-10148391.369548438,1562984.3540953137]]]]},"properties":{"x":4043,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1565430.3390000015],[-10148391.369548438,1567876.3239046894],[-10145945.38464375,1567876.3239046894],[-10145945.38464375,1565430.3390000015],[-10148391.369548438,1565430.3390000015]]]]},"properties":{"x":4043,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1567876.3239046894],[-10148391.369548438,1570322.3088093735],[-10145945.38464375,1570322.3088093735],[-10145945.38464375,1567876.3239046894],[-10148391.369548438,1567876.3239046894]]]]},"properties":{"x":4043,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1570322.3088093735],[-10148391.369548438,1572768.2937140614],[-10145945.38464375,1572768.2937140614],[-10145945.38464375,1570322.3088093735],[-10148391.369548438,1570322.3088093735]]]]},"properties":{"x":4043,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1572768.2937140614],[-10148391.369548438,1575214.2786187492],[-10145945.38464375,1575214.2786187492],[-10145945.38464375,1572768.2937140614],[-10148391.369548438,1572768.2937140614]]]]},"properties":{"x":4043,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1575214.2786187492],[-10148391.369548438,1577660.263523437],[-10145945.38464375,1577660.263523437],[-10145945.38464375,1575214.2786187492],[-10148391.369548438,1575214.2786187492]]]]},"properties":{"x":4043,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1577660.263523437],[-10148391.369548438,1580106.248428125],[-10145945.38464375,1580106.248428125],[-10145945.38464375,1577660.263523437],[-10148391.369548438,1577660.263523437]]]]},"properties":{"x":4043,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1580106.248428125],[-10148391.369548438,1582552.2333328128],[-10145945.38464375,1582552.2333328128],[-10145945.38464375,1580106.248428125],[-10148391.369548438,1580106.248428125]]]]},"properties":{"x":4043,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1582552.2333328128],[-10148391.369548438,1584998.2182375006],[-10145945.38464375,1584998.2182375006],[-10145945.38464375,1582552.2333328128],[-10148391.369548438,1582552.2333328128]]]]},"properties":{"x":4043,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1584998.2182375006],[-10148391.369548438,1587444.2031421885],[-10145945.38464375,1587444.2031421885],[-10145945.38464375,1584998.2182375006],[-10148391.369548438,1584998.2182375006]]]]},"properties":{"x":4043,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1587444.2031421885],[-10148391.369548438,1589890.1880468763],[-10145945.38464375,1589890.1880468763],[-10145945.38464375,1587444.2031421885],[-10148391.369548438,1587444.2031421885]]]]},"properties":{"x":4043,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1589890.1880468763],[-10148391.369548438,1592336.1729515642],[-10145945.38464375,1592336.1729515642],[-10145945.38464375,1589890.1880468763],[-10148391.369548438,1589890.1880468763]]]]},"properties":{"x":4043,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1592336.1729515642],[-10148391.369548438,1594782.1578562483],[-10145945.38464375,1594782.1578562483],[-10145945.38464375,1592336.1729515642],[-10148391.369548438,1592336.1729515642]]]]},"properties":{"x":4043,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1594782.1578562483],[-10148391.369548438,1597228.1427609362],[-10145945.38464375,1597228.1427609362],[-10145945.38464375,1594782.1578562483],[-10148391.369548438,1594782.1578562483]]]]},"properties":{"x":4043,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1597228.1427609362],[-10148391.369548438,1599674.127665624],[-10145945.38464375,1599674.127665624],[-10145945.38464375,1597228.1427609362],[-10148391.369548438,1597228.1427609362]]]]},"properties":{"x":4043,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1599674.127665624],[-10148391.369548438,1602120.1125703119],[-10145945.38464375,1602120.1125703119],[-10145945.38464375,1599674.127665624],[-10148391.369548438,1599674.127665624]]]]},"properties":{"x":4043,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1602120.1125703119],[-10148391.369548438,1604566.0974749997],[-10145945.38464375,1604566.0974749997],[-10145945.38464375,1602120.1125703119],[-10148391.369548438,1602120.1125703119]]]]},"properties":{"x":4043,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1604566.0974749997],[-10148391.369548438,1607012.0823796876],[-10145945.38464375,1607012.0823796876],[-10145945.38464375,1604566.0974749997],[-10148391.369548438,1604566.0974749997]]]]},"properties":{"x":4043,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1607012.0823796876],[-10148391.369548438,1609458.0672843754],[-10145945.38464375,1609458.0672843754],[-10145945.38464375,1607012.0823796876],[-10148391.369548438,1607012.0823796876]]]]},"properties":{"x":4043,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1609458.0672843754],[-10148391.369548438,1611904.0521890633],[-10145945.38464375,1611904.0521890633],[-10145945.38464375,1609458.0672843754],[-10148391.369548438,1609458.0672843754]]]]},"properties":{"x":4043,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1611904.0521890633],[-10148391.369548438,1614350.0370937511],[-10145945.38464375,1614350.0370937511],[-10145945.38464375,1611904.0521890633],[-10148391.369548438,1611904.0521890633]]]]},"properties":{"x":4043,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1614350.0370937511],[-10148391.369548438,1616796.021998439],[-10145945.38464375,1616796.021998439],[-10145945.38464375,1614350.0370937511],[-10148391.369548438,1614350.0370937511]]]]},"properties":{"x":4043,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1616796.021998439],[-10148391.369548438,1619242.0069031268],[-10145945.38464375,1619242.0069031268],[-10145945.38464375,1616796.021998439],[-10148391.369548438,1616796.021998439]]]]},"properties":{"x":4043,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1619242.0069031268],[-10148391.369548438,1621687.991807811],[-10145945.38464375,1621687.991807811],[-10145945.38464375,1619242.0069031268],[-10148391.369548438,1619242.0069031268]]]]},"properties":{"x":4043,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1621687.991807811],[-10148391.369548438,1624133.9767124988],[-10145945.38464375,1624133.9767124988],[-10145945.38464375,1621687.991807811],[-10148391.369548438,1621687.991807811]]]]},"properties":{"x":4043,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10148391.369548438,1624133.9767124988],[-10148391.369548438,1626579.9616171867],[-10145945.38464375,1626579.9616171867],[-10145945.38464375,1624133.9767124988],[-10148391.369548438,1624133.9767124988]]]]},"properties":{"x":4043,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1562984.3540953137],[-10145945.38464375,1565430.3390000015],[-10143499.399739062,1565430.3390000015],[-10143499.399739062,1562984.3540953137],[-10145945.38464375,1562984.3540953137]]]]},"properties":{"x":4044,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1565430.3390000015],[-10145945.38464375,1567876.3239046894],[-10143499.399739062,1567876.3239046894],[-10143499.399739062,1565430.3390000015],[-10145945.38464375,1565430.3390000015]]]]},"properties":{"x":4044,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1567876.3239046894],[-10145945.38464375,1570322.3088093735],[-10143499.399739062,1570322.3088093735],[-10143499.399739062,1567876.3239046894],[-10145945.38464375,1567876.3239046894]]]]},"properties":{"x":4044,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1570322.3088093735],[-10145945.38464375,1572768.2937140614],[-10143499.399739062,1572768.2937140614],[-10143499.399739062,1570322.3088093735],[-10145945.38464375,1570322.3088093735]]]]},"properties":{"x":4044,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1572768.2937140614],[-10145945.38464375,1575214.2786187492],[-10143499.399739062,1575214.2786187492],[-10143499.399739062,1572768.2937140614],[-10145945.38464375,1572768.2937140614]]]]},"properties":{"x":4044,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1575214.2786187492],[-10145945.38464375,1577660.263523437],[-10143499.399739062,1577660.263523437],[-10143499.399739062,1575214.2786187492],[-10145945.38464375,1575214.2786187492]]]]},"properties":{"x":4044,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1577660.263523437],[-10145945.38464375,1580106.248428125],[-10143499.399739062,1580106.248428125],[-10143499.399739062,1577660.263523437],[-10145945.38464375,1577660.263523437]]]]},"properties":{"x":4044,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1580106.248428125],[-10145945.38464375,1582552.2333328128],[-10143499.399739062,1582552.2333328128],[-10143499.399739062,1580106.248428125],[-10145945.38464375,1580106.248428125]]]]},"properties":{"x":4044,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1582552.2333328128],[-10145945.38464375,1584998.2182375006],[-10143499.399739062,1584998.2182375006],[-10143499.399739062,1582552.2333328128],[-10145945.38464375,1582552.2333328128]]]]},"properties":{"x":4044,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1584998.2182375006],[-10145945.38464375,1587444.2031421885],[-10143499.399739062,1587444.2031421885],[-10143499.399739062,1584998.2182375006],[-10145945.38464375,1584998.2182375006]]]]},"properties":{"x":4044,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1587444.2031421885],[-10145945.38464375,1589890.1880468763],[-10143499.399739062,1589890.1880468763],[-10143499.399739062,1587444.2031421885],[-10145945.38464375,1587444.2031421885]]]]},"properties":{"x":4044,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1589890.1880468763],[-10145945.38464375,1592336.1729515642],[-10143499.399739062,1592336.1729515642],[-10143499.399739062,1589890.1880468763],[-10145945.38464375,1589890.1880468763]]]]},"properties":{"x":4044,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1592336.1729515642],[-10145945.38464375,1594782.1578562483],[-10143499.399739062,1594782.1578562483],[-10143499.399739062,1592336.1729515642],[-10145945.38464375,1592336.1729515642]]]]},"properties":{"x":4044,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1594782.1578562483],[-10145945.38464375,1597228.1427609362],[-10143499.399739062,1597228.1427609362],[-10143499.399739062,1594782.1578562483],[-10145945.38464375,1594782.1578562483]]]]},"properties":{"x":4044,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1597228.1427609362],[-10145945.38464375,1599674.127665624],[-10143499.399739062,1599674.127665624],[-10143499.399739062,1597228.1427609362],[-10145945.38464375,1597228.1427609362]]]]},"properties":{"x":4044,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1599674.127665624],[-10145945.38464375,1602120.1125703119],[-10143499.399739062,1602120.1125703119],[-10143499.399739062,1599674.127665624],[-10145945.38464375,1599674.127665624]]]]},"properties":{"x":4044,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1602120.1125703119],[-10145945.38464375,1604566.0974749997],[-10143499.399739062,1604566.0974749997],[-10143499.399739062,1602120.1125703119],[-10145945.38464375,1602120.1125703119]]]]},"properties":{"x":4044,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1604566.0974749997],[-10145945.38464375,1607012.0823796876],[-10143499.399739062,1607012.0823796876],[-10143499.399739062,1604566.0974749997],[-10145945.38464375,1604566.0974749997]]]]},"properties":{"x":4044,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1607012.0823796876],[-10145945.38464375,1609458.0672843754],[-10143499.399739062,1609458.0672843754],[-10143499.399739062,1607012.0823796876],[-10145945.38464375,1607012.0823796876]]]]},"properties":{"x":4044,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1609458.0672843754],[-10145945.38464375,1611904.0521890633],[-10143499.399739062,1611904.0521890633],[-10143499.399739062,1609458.0672843754],[-10145945.38464375,1609458.0672843754]]]]},"properties":{"x":4044,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1611904.0521890633],[-10145945.38464375,1614350.0370937511],[-10143499.399739062,1614350.0370937511],[-10143499.399739062,1611904.0521890633],[-10145945.38464375,1611904.0521890633]]]]},"properties":{"x":4044,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1614350.0370937511],[-10145945.38464375,1616796.021998439],[-10143499.399739062,1616796.021998439],[-10143499.399739062,1614350.0370937511],[-10145945.38464375,1614350.0370937511]]]]},"properties":{"x":4044,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1616796.021998439],[-10145945.38464375,1619242.0069031268],[-10143499.399739062,1619242.0069031268],[-10143499.399739062,1616796.021998439],[-10145945.38464375,1616796.021998439]]]]},"properties":{"x":4044,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1619242.0069031268],[-10145945.38464375,1621687.991807811],[-10143499.399739062,1621687.991807811],[-10143499.399739062,1619242.0069031268],[-10145945.38464375,1619242.0069031268]]]]},"properties":{"x":4044,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1621687.991807811],[-10145945.38464375,1624133.9767124988],[-10143499.399739062,1624133.9767124988],[-10143499.399739062,1621687.991807811],[-10145945.38464375,1621687.991807811]]]]},"properties":{"x":4044,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10145945.38464375,1624133.9767124988],[-10145945.38464375,1626579.9616171867],[-10143499.399739062,1626579.9616171867],[-10143499.399739062,1624133.9767124988],[-10145945.38464375,1624133.9767124988]]]]},"properties":{"x":4044,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1562984.3540953137],[-10143499.399739062,1565430.3390000015],[-10141053.414834376,1565430.3390000015],[-10141053.414834376,1562984.3540953137],[-10143499.399739062,1562984.3540953137]]]]},"properties":{"x":4045,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1565430.3390000015],[-10143499.399739062,1567876.3239046894],[-10141053.414834376,1567876.3239046894],[-10141053.414834376,1565430.3390000015],[-10143499.399739062,1565430.3390000015]]]]},"properties":{"x":4045,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1567876.3239046894],[-10143499.399739062,1570322.3088093735],[-10141053.414834376,1570322.3088093735],[-10141053.414834376,1567876.3239046894],[-10143499.399739062,1567876.3239046894]]]]},"properties":{"x":4045,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1570322.3088093735],[-10143499.399739062,1572768.2937140614],[-10141053.414834376,1572768.2937140614],[-10141053.414834376,1570322.3088093735],[-10143499.399739062,1570322.3088093735]]]]},"properties":{"x":4045,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1572768.2937140614],[-10143499.399739062,1575214.2786187492],[-10141053.414834376,1575214.2786187492],[-10141053.414834376,1572768.2937140614],[-10143499.399739062,1572768.2937140614]]]]},"properties":{"x":4045,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1575214.2786187492],[-10143499.399739062,1577660.263523437],[-10141053.414834376,1577660.263523437],[-10141053.414834376,1575214.2786187492],[-10143499.399739062,1575214.2786187492]]]]},"properties":{"x":4045,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1577660.263523437],[-10143499.399739062,1580106.248428125],[-10141053.414834376,1580106.248428125],[-10141053.414834376,1577660.263523437],[-10143499.399739062,1577660.263523437]]]]},"properties":{"x":4045,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1580106.248428125],[-10143499.399739062,1582552.2333328128],[-10141053.414834376,1582552.2333328128],[-10141053.414834376,1580106.248428125],[-10143499.399739062,1580106.248428125]]]]},"properties":{"x":4045,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1582552.2333328128],[-10143499.399739062,1584998.2182375006],[-10141053.414834376,1584998.2182375006],[-10141053.414834376,1582552.2333328128],[-10143499.399739062,1582552.2333328128]]]]},"properties":{"x":4045,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1584998.2182375006],[-10143499.399739062,1587444.2031421885],[-10141053.414834376,1587444.2031421885],[-10141053.414834376,1584998.2182375006],[-10143499.399739062,1584998.2182375006]]]]},"properties":{"x":4045,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1587444.2031421885],[-10143499.399739062,1589890.1880468763],[-10141053.414834376,1589890.1880468763],[-10141053.414834376,1587444.2031421885],[-10143499.399739062,1587444.2031421885]]]]},"properties":{"x":4045,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1589890.1880468763],[-10143499.399739062,1592336.1729515642],[-10141053.414834376,1592336.1729515642],[-10141053.414834376,1589890.1880468763],[-10143499.399739062,1589890.1880468763]]]]},"properties":{"x":4045,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1592336.1729515642],[-10143499.399739062,1594782.1578562483],[-10141053.414834376,1594782.1578562483],[-10141053.414834376,1592336.1729515642],[-10143499.399739062,1592336.1729515642]]]]},"properties":{"x":4045,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1594782.1578562483],[-10143499.399739062,1597228.1427609362],[-10141053.414834376,1597228.1427609362],[-10141053.414834376,1594782.1578562483],[-10143499.399739062,1594782.1578562483]]]]},"properties":{"x":4045,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1597228.1427609362],[-10143499.399739062,1599674.127665624],[-10141053.414834376,1599674.127665624],[-10141053.414834376,1597228.1427609362],[-10143499.399739062,1597228.1427609362]]]]},"properties":{"x":4045,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1599674.127665624],[-10143499.399739062,1602120.1125703119],[-10141053.414834376,1602120.1125703119],[-10141053.414834376,1599674.127665624],[-10143499.399739062,1599674.127665624]]]]},"properties":{"x":4045,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1602120.1125703119],[-10143499.399739062,1604566.0974749997],[-10141053.414834376,1604566.0974749997],[-10141053.414834376,1602120.1125703119],[-10143499.399739062,1602120.1125703119]]]]},"properties":{"x":4045,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1604566.0974749997],[-10143499.399739062,1607012.0823796876],[-10141053.414834376,1607012.0823796876],[-10141053.414834376,1604566.0974749997],[-10143499.399739062,1604566.0974749997]]]]},"properties":{"x":4045,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1607012.0823796876],[-10143499.399739062,1609458.0672843754],[-10141053.414834376,1609458.0672843754],[-10141053.414834376,1607012.0823796876],[-10143499.399739062,1607012.0823796876]]]]},"properties":{"x":4045,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1609458.0672843754],[-10143499.399739062,1611904.0521890633],[-10141053.414834376,1611904.0521890633],[-10141053.414834376,1609458.0672843754],[-10143499.399739062,1609458.0672843754]]]]},"properties":{"x":4045,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1611904.0521890633],[-10143499.399739062,1614350.0370937511],[-10141053.414834376,1614350.0370937511],[-10141053.414834376,1611904.0521890633],[-10143499.399739062,1611904.0521890633]]]]},"properties":{"x":4045,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1614350.0370937511],[-10143499.399739062,1616796.021998439],[-10141053.414834376,1616796.021998439],[-10141053.414834376,1614350.0370937511],[-10143499.399739062,1614350.0370937511]]]]},"properties":{"x":4045,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1616796.021998439],[-10143499.399739062,1619242.0069031268],[-10141053.414834376,1619242.0069031268],[-10141053.414834376,1616796.021998439],[-10143499.399739062,1616796.021998439]]]]},"properties":{"x":4045,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1619242.0069031268],[-10143499.399739062,1621687.991807811],[-10141053.414834376,1621687.991807811],[-10141053.414834376,1619242.0069031268],[-10143499.399739062,1619242.0069031268]]]]},"properties":{"x":4045,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1621687.991807811],[-10143499.399739062,1624133.9767124988],[-10141053.414834376,1624133.9767124988],[-10141053.414834376,1621687.991807811],[-10143499.399739062,1621687.991807811]]]]},"properties":{"x":4045,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10143499.399739062,1624133.9767124988],[-10143499.399739062,1626579.9616171867],[-10141053.414834376,1626579.9616171867],[-10141053.414834376,1624133.9767124988],[-10143499.399739062,1624133.9767124988]]]]},"properties":{"x":4045,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1562984.3540953137],[-10141053.414834376,1565430.3390000015],[-10138607.429929689,1565430.3390000015],[-10138607.429929689,1562984.3540953137],[-10141053.414834376,1562984.3540953137]]]]},"properties":{"x":4046,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1565430.3390000015],[-10141053.414834376,1567876.3239046894],[-10138607.429929689,1567876.3239046894],[-10138607.429929689,1565430.3390000015],[-10141053.414834376,1565430.3390000015]]]]},"properties":{"x":4046,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1567876.3239046894],[-10141053.414834376,1570322.3088093735],[-10138607.429929689,1570322.3088093735],[-10138607.429929689,1567876.3239046894],[-10141053.414834376,1567876.3239046894]]]]},"properties":{"x":4046,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1570322.3088093735],[-10141053.414834376,1572768.2937140614],[-10138607.429929689,1572768.2937140614],[-10138607.429929689,1570322.3088093735],[-10141053.414834376,1570322.3088093735]]]]},"properties":{"x":4046,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1572768.2937140614],[-10141053.414834376,1575214.2786187492],[-10138607.429929689,1575214.2786187492],[-10138607.429929689,1572768.2937140614],[-10141053.414834376,1572768.2937140614]]]]},"properties":{"x":4046,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1575214.2786187492],[-10141053.414834376,1577660.263523437],[-10138607.429929689,1577660.263523437],[-10138607.429929689,1575214.2786187492],[-10141053.414834376,1575214.2786187492]]]]},"properties":{"x":4046,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1577660.263523437],[-10141053.414834376,1580106.248428125],[-10138607.429929689,1580106.248428125],[-10138607.429929689,1577660.263523437],[-10141053.414834376,1577660.263523437]]]]},"properties":{"x":4046,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1580106.248428125],[-10141053.414834376,1582552.2333328128],[-10138607.429929689,1582552.2333328128],[-10138607.429929689,1580106.248428125],[-10141053.414834376,1580106.248428125]]]]},"properties":{"x":4046,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1582552.2333328128],[-10141053.414834376,1584998.2182375006],[-10138607.429929689,1584998.2182375006],[-10138607.429929689,1582552.2333328128],[-10141053.414834376,1582552.2333328128]]]]},"properties":{"x":4046,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1584998.2182375006],[-10141053.414834376,1587444.2031421885],[-10138607.429929689,1587444.2031421885],[-10138607.429929689,1584998.2182375006],[-10141053.414834376,1584998.2182375006]]]]},"properties":{"x":4046,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1587444.2031421885],[-10141053.414834376,1589890.1880468763],[-10138607.429929689,1589890.1880468763],[-10138607.429929689,1587444.2031421885],[-10141053.414834376,1587444.2031421885]]]]},"properties":{"x":4046,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1589890.1880468763],[-10141053.414834376,1592336.1729515642],[-10138607.429929689,1592336.1729515642],[-10138607.429929689,1589890.1880468763],[-10141053.414834376,1589890.1880468763]]]]},"properties":{"x":4046,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1592336.1729515642],[-10141053.414834376,1594782.1578562483],[-10138607.429929689,1594782.1578562483],[-10138607.429929689,1592336.1729515642],[-10141053.414834376,1592336.1729515642]]]]},"properties":{"x":4046,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1594782.1578562483],[-10141053.414834376,1597228.1427609362],[-10138607.429929689,1597228.1427609362],[-10138607.429929689,1594782.1578562483],[-10141053.414834376,1594782.1578562483]]]]},"properties":{"x":4046,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1597228.1427609362],[-10141053.414834376,1599674.127665624],[-10138607.429929689,1599674.127665624],[-10138607.429929689,1597228.1427609362],[-10141053.414834376,1597228.1427609362]]]]},"properties":{"x":4046,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1599674.127665624],[-10141053.414834376,1602120.1125703119],[-10138607.429929689,1602120.1125703119],[-10138607.429929689,1599674.127665624],[-10141053.414834376,1599674.127665624]]]]},"properties":{"x":4046,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1602120.1125703119],[-10141053.414834376,1604566.0974749997],[-10138607.429929689,1604566.0974749997],[-10138607.429929689,1602120.1125703119],[-10141053.414834376,1602120.1125703119]]]]},"properties":{"x":4046,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1604566.0974749997],[-10141053.414834376,1607012.0823796876],[-10138607.429929689,1607012.0823796876],[-10138607.429929689,1604566.0974749997],[-10141053.414834376,1604566.0974749997]]]]},"properties":{"x":4046,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1607012.0823796876],[-10141053.414834376,1609458.0672843754],[-10138607.429929689,1609458.0672843754],[-10138607.429929689,1607012.0823796876],[-10141053.414834376,1607012.0823796876]]]]},"properties":{"x":4046,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1609458.0672843754],[-10141053.414834376,1611904.0521890633],[-10138607.429929689,1611904.0521890633],[-10138607.429929689,1609458.0672843754],[-10141053.414834376,1609458.0672843754]]]]},"properties":{"x":4046,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1611904.0521890633],[-10141053.414834376,1614350.0370937511],[-10138607.429929689,1614350.0370937511],[-10138607.429929689,1611904.0521890633],[-10141053.414834376,1611904.0521890633]]]]},"properties":{"x":4046,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1614350.0370937511],[-10141053.414834376,1616796.021998439],[-10138607.429929689,1616796.021998439],[-10138607.429929689,1614350.0370937511],[-10141053.414834376,1614350.0370937511]]]]},"properties":{"x":4046,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1616796.021998439],[-10141053.414834376,1619242.0069031268],[-10138607.429929689,1619242.0069031268],[-10138607.429929689,1616796.021998439],[-10141053.414834376,1616796.021998439]]]]},"properties":{"x":4046,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1619242.0069031268],[-10141053.414834376,1621687.991807811],[-10138607.429929689,1621687.991807811],[-10138607.429929689,1619242.0069031268],[-10141053.414834376,1619242.0069031268]]]]},"properties":{"x":4046,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1621687.991807811],[-10141053.414834376,1624133.9767124988],[-10138607.429929689,1624133.9767124988],[-10138607.429929689,1621687.991807811],[-10141053.414834376,1621687.991807811]]]]},"properties":{"x":4046,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10141053.414834376,1624133.9767124988],[-10141053.414834376,1626579.9616171867],[-10138607.429929689,1626579.9616171867],[-10138607.429929689,1624133.9767124988],[-10141053.414834376,1624133.9767124988]]]]},"properties":{"x":4046,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1562984.3540953137],[-10138607.429929689,1565430.3390000015],[-10136161.445025,1565430.3390000015],[-10136161.445025,1562984.3540953137],[-10138607.429929689,1562984.3540953137]]]]},"properties":{"x":4047,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1565430.3390000015],[-10138607.429929689,1567876.3239046894],[-10136161.445025,1567876.3239046894],[-10136161.445025,1565430.3390000015],[-10138607.429929689,1565430.3390000015]]]]},"properties":{"x":4047,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1567876.3239046894],[-10138607.429929689,1570322.3088093735],[-10136161.445025,1570322.3088093735],[-10136161.445025,1567876.3239046894],[-10138607.429929689,1567876.3239046894]]]]},"properties":{"x":4047,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1570322.3088093735],[-10138607.429929689,1572768.2937140614],[-10136161.445025,1572768.2937140614],[-10136161.445025,1570322.3088093735],[-10138607.429929689,1570322.3088093735]]]]},"properties":{"x":4047,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1572768.2937140614],[-10138607.429929689,1575214.2786187492],[-10136161.445025,1575214.2786187492],[-10136161.445025,1572768.2937140614],[-10138607.429929689,1572768.2937140614]]]]},"properties":{"x":4047,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1575214.2786187492],[-10138607.429929689,1577660.263523437],[-10136161.445025,1577660.263523437],[-10136161.445025,1575214.2786187492],[-10138607.429929689,1575214.2786187492]]]]},"properties":{"x":4047,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1577660.263523437],[-10138607.429929689,1580106.248428125],[-10136161.445025,1580106.248428125],[-10136161.445025,1577660.263523437],[-10138607.429929689,1577660.263523437]]]]},"properties":{"x":4047,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1580106.248428125],[-10138607.429929689,1582552.2333328128],[-10136161.445025,1582552.2333328128],[-10136161.445025,1580106.248428125],[-10138607.429929689,1580106.248428125]]]]},"properties":{"x":4047,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1582552.2333328128],[-10138607.429929689,1584998.2182375006],[-10136161.445025,1584998.2182375006],[-10136161.445025,1582552.2333328128],[-10138607.429929689,1582552.2333328128]]]]},"properties":{"x":4047,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1584998.2182375006],[-10138607.429929689,1587444.2031421885],[-10136161.445025,1587444.2031421885],[-10136161.445025,1584998.2182375006],[-10138607.429929689,1584998.2182375006]]]]},"properties":{"x":4047,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1587444.2031421885],[-10138607.429929689,1589890.1880468763],[-10136161.445025,1589890.1880468763],[-10136161.445025,1587444.2031421885],[-10138607.429929689,1587444.2031421885]]]]},"properties":{"x":4047,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1589890.1880468763],[-10138607.429929689,1592336.1729515642],[-10136161.445025,1592336.1729515642],[-10136161.445025,1589890.1880468763],[-10138607.429929689,1589890.1880468763]]]]},"properties":{"x":4047,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1592336.1729515642],[-10138607.429929689,1594782.1578562483],[-10136161.445025,1594782.1578562483],[-10136161.445025,1592336.1729515642],[-10138607.429929689,1592336.1729515642]]]]},"properties":{"x":4047,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1594782.1578562483],[-10138607.429929689,1597228.1427609362],[-10136161.445025,1597228.1427609362],[-10136161.445025,1594782.1578562483],[-10138607.429929689,1594782.1578562483]]]]},"properties":{"x":4047,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1597228.1427609362],[-10138607.429929689,1599674.127665624],[-10136161.445025,1599674.127665624],[-10136161.445025,1597228.1427609362],[-10138607.429929689,1597228.1427609362]]]]},"properties":{"x":4047,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1599674.127665624],[-10138607.429929689,1602120.1125703119],[-10136161.445025,1602120.1125703119],[-10136161.445025,1599674.127665624],[-10138607.429929689,1599674.127665624]]]]},"properties":{"x":4047,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1602120.1125703119],[-10138607.429929689,1604566.0974749997],[-10136161.445025,1604566.0974749997],[-10136161.445025,1602120.1125703119],[-10138607.429929689,1602120.1125703119]]]]},"properties":{"x":4047,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1604566.0974749997],[-10138607.429929689,1607012.0823796876],[-10136161.445025,1607012.0823796876],[-10136161.445025,1604566.0974749997],[-10138607.429929689,1604566.0974749997]]]]},"properties":{"x":4047,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1607012.0823796876],[-10138607.429929689,1609458.0672843754],[-10136161.445025,1609458.0672843754],[-10136161.445025,1607012.0823796876],[-10138607.429929689,1607012.0823796876]]]]},"properties":{"x":4047,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1609458.0672843754],[-10138607.429929689,1611904.0521890633],[-10136161.445025,1611904.0521890633],[-10136161.445025,1609458.0672843754],[-10138607.429929689,1609458.0672843754]]]]},"properties":{"x":4047,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1611904.0521890633],[-10138607.429929689,1614350.0370937511],[-10136161.445025,1614350.0370937511],[-10136161.445025,1611904.0521890633],[-10138607.429929689,1611904.0521890633]]]]},"properties":{"x":4047,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1614350.0370937511],[-10138607.429929689,1616796.021998439],[-10136161.445025,1616796.021998439],[-10136161.445025,1614350.0370937511],[-10138607.429929689,1614350.0370937511]]]]},"properties":{"x":4047,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1616796.021998439],[-10138607.429929689,1619242.0069031268],[-10136161.445025,1619242.0069031268],[-10136161.445025,1616796.021998439],[-10138607.429929689,1616796.021998439]]]]},"properties":{"x":4047,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1619242.0069031268],[-10138607.429929689,1621687.991807811],[-10136161.445025,1621687.991807811],[-10136161.445025,1619242.0069031268],[-10138607.429929689,1619242.0069031268]]]]},"properties":{"x":4047,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1621687.991807811],[-10138607.429929689,1624133.9767124988],[-10136161.445025,1624133.9767124988],[-10136161.445025,1621687.991807811],[-10138607.429929689,1621687.991807811]]]]},"properties":{"x":4047,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10138607.429929689,1624133.9767124988],[-10138607.429929689,1626579.9616171867],[-10136161.445025,1626579.9616171867],[-10136161.445025,1624133.9767124988],[-10138607.429929689,1624133.9767124988]]]]},"properties":{"x":4047,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1562984.3540953137],[-10136161.445025,1565430.3390000015],[-10133715.460120313,1565430.3390000015],[-10133715.460120313,1562984.3540953137],[-10136161.445025,1562984.3540953137]]]]},"properties":{"x":4048,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1565430.3390000015],[-10136161.445025,1567876.3239046894],[-10133715.460120313,1567876.3239046894],[-10133715.460120313,1565430.3390000015],[-10136161.445025,1565430.3390000015]]]]},"properties":{"x":4048,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1567876.3239046894],[-10136161.445025,1570322.3088093735],[-10133715.460120313,1570322.3088093735],[-10133715.460120313,1567876.3239046894],[-10136161.445025,1567876.3239046894]]]]},"properties":{"x":4048,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1570322.3088093735],[-10136161.445025,1572768.2937140614],[-10133715.460120313,1572768.2937140614],[-10133715.460120313,1570322.3088093735],[-10136161.445025,1570322.3088093735]]]]},"properties":{"x":4048,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1572768.2937140614],[-10136161.445025,1575214.2786187492],[-10133715.460120313,1575214.2786187492],[-10133715.460120313,1572768.2937140614],[-10136161.445025,1572768.2937140614]]]]},"properties":{"x":4048,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1575214.2786187492],[-10136161.445025,1577660.263523437],[-10133715.460120313,1577660.263523437],[-10133715.460120313,1575214.2786187492],[-10136161.445025,1575214.2786187492]]]]},"properties":{"x":4048,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1577660.263523437],[-10136161.445025,1580106.248428125],[-10133715.460120313,1580106.248428125],[-10133715.460120313,1577660.263523437],[-10136161.445025,1577660.263523437]]]]},"properties":{"x":4048,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1580106.248428125],[-10136161.445025,1582552.2333328128],[-10133715.460120313,1582552.2333328128],[-10133715.460120313,1580106.248428125],[-10136161.445025,1580106.248428125]]]]},"properties":{"x":4048,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1582552.2333328128],[-10136161.445025,1584998.2182375006],[-10133715.460120313,1584998.2182375006],[-10133715.460120313,1582552.2333328128],[-10136161.445025,1582552.2333328128]]]]},"properties":{"x":4048,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1584998.2182375006],[-10136161.445025,1587444.2031421885],[-10133715.460120313,1587444.2031421885],[-10133715.460120313,1584998.2182375006],[-10136161.445025,1584998.2182375006]]]]},"properties":{"x":4048,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1587444.2031421885],[-10136161.445025,1589890.1880468763],[-10133715.460120313,1589890.1880468763],[-10133715.460120313,1587444.2031421885],[-10136161.445025,1587444.2031421885]]]]},"properties":{"x":4048,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1589890.1880468763],[-10136161.445025,1592336.1729515642],[-10133715.460120313,1592336.1729515642],[-10133715.460120313,1589890.1880468763],[-10136161.445025,1589890.1880468763]]]]},"properties":{"x":4048,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1592336.1729515642],[-10136161.445025,1594782.1578562483],[-10133715.460120313,1594782.1578562483],[-10133715.460120313,1592336.1729515642],[-10136161.445025,1592336.1729515642]]]]},"properties":{"x":4048,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1594782.1578562483],[-10136161.445025,1597228.1427609362],[-10133715.460120313,1597228.1427609362],[-10133715.460120313,1594782.1578562483],[-10136161.445025,1594782.1578562483]]]]},"properties":{"x":4048,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1597228.1427609362],[-10136161.445025,1599674.127665624],[-10133715.460120313,1599674.127665624],[-10133715.460120313,1597228.1427609362],[-10136161.445025,1597228.1427609362]]]]},"properties":{"x":4048,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1599674.127665624],[-10136161.445025,1602120.1125703119],[-10133715.460120313,1602120.1125703119],[-10133715.460120313,1599674.127665624],[-10136161.445025,1599674.127665624]]]]},"properties":{"x":4048,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1602120.1125703119],[-10136161.445025,1604566.0974749997],[-10133715.460120313,1604566.0974749997],[-10133715.460120313,1602120.1125703119],[-10136161.445025,1602120.1125703119]]]]},"properties":{"x":4048,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1604566.0974749997],[-10136161.445025,1607012.0823796876],[-10133715.460120313,1607012.0823796876],[-10133715.460120313,1604566.0974749997],[-10136161.445025,1604566.0974749997]]]]},"properties":{"x":4048,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1607012.0823796876],[-10136161.445025,1609458.0672843754],[-10133715.460120313,1609458.0672843754],[-10133715.460120313,1607012.0823796876],[-10136161.445025,1607012.0823796876]]]]},"properties":{"x":4048,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1609458.0672843754],[-10136161.445025,1611904.0521890633],[-10133715.460120313,1611904.0521890633],[-10133715.460120313,1609458.0672843754],[-10136161.445025,1609458.0672843754]]]]},"properties":{"x":4048,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1611904.0521890633],[-10136161.445025,1614350.0370937511],[-10133715.460120313,1614350.0370937511],[-10133715.460120313,1611904.0521890633],[-10136161.445025,1611904.0521890633]]]]},"properties":{"x":4048,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1614350.0370937511],[-10136161.445025,1616796.021998439],[-10133715.460120313,1616796.021998439],[-10133715.460120313,1614350.0370937511],[-10136161.445025,1614350.0370937511]]]]},"properties":{"x":4048,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1616796.021998439],[-10136161.445025,1619242.0069031268],[-10133715.460120313,1619242.0069031268],[-10133715.460120313,1616796.021998439],[-10136161.445025,1616796.021998439]]]]},"properties":{"x":4048,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1619242.0069031268],[-10136161.445025,1621687.991807811],[-10133715.460120313,1621687.991807811],[-10133715.460120313,1619242.0069031268],[-10136161.445025,1619242.0069031268]]]]},"properties":{"x":4048,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1621687.991807811],[-10136161.445025,1624133.9767124988],[-10133715.460120313,1624133.9767124988],[-10133715.460120313,1621687.991807811],[-10136161.445025,1621687.991807811]]]]},"properties":{"x":4048,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10136161.445025,1624133.9767124988],[-10136161.445025,1626579.9616171867],[-10133715.460120313,1626579.9616171867],[-10133715.460120313,1624133.9767124988],[-10136161.445025,1624133.9767124988]]]]},"properties":{"x":4048,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1562984.3540953137],[-10133715.460120313,1565430.3390000015],[-10131269.475215625,1565430.3390000015],[-10131269.475215625,1562984.3540953137],[-10133715.460120313,1562984.3540953137]]]]},"properties":{"x":4049,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1565430.3390000015],[-10133715.460120313,1567876.3239046894],[-10131269.475215625,1567876.3239046894],[-10131269.475215625,1565430.3390000015],[-10133715.460120313,1565430.3390000015]]]]},"properties":{"x":4049,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1567876.3239046894],[-10133715.460120313,1570322.3088093735],[-10131269.475215625,1570322.3088093735],[-10131269.475215625,1567876.3239046894],[-10133715.460120313,1567876.3239046894]]]]},"properties":{"x":4049,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1570322.3088093735],[-10133715.460120313,1572768.2937140614],[-10131269.475215625,1572768.2937140614],[-10131269.475215625,1570322.3088093735],[-10133715.460120313,1570322.3088093735]]]]},"properties":{"x":4049,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1572768.2937140614],[-10133715.460120313,1575214.2786187492],[-10131269.475215625,1575214.2786187492],[-10131269.475215625,1572768.2937140614],[-10133715.460120313,1572768.2937140614]]]]},"properties":{"x":4049,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1575214.2786187492],[-10133715.460120313,1577660.263523437],[-10131269.475215625,1577660.263523437],[-10131269.475215625,1575214.2786187492],[-10133715.460120313,1575214.2786187492]]]]},"properties":{"x":4049,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1577660.263523437],[-10133715.460120313,1580106.248428125],[-10131269.475215625,1580106.248428125],[-10131269.475215625,1577660.263523437],[-10133715.460120313,1577660.263523437]]]]},"properties":{"x":4049,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1580106.248428125],[-10133715.460120313,1582552.2333328128],[-10131269.475215625,1582552.2333328128],[-10131269.475215625,1580106.248428125],[-10133715.460120313,1580106.248428125]]]]},"properties":{"x":4049,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1582552.2333328128],[-10133715.460120313,1584998.2182375006],[-10131269.475215625,1584998.2182375006],[-10131269.475215625,1582552.2333328128],[-10133715.460120313,1582552.2333328128]]]]},"properties":{"x":4049,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1584998.2182375006],[-10133715.460120313,1587444.2031421885],[-10131269.475215625,1587444.2031421885],[-10131269.475215625,1584998.2182375006],[-10133715.460120313,1584998.2182375006]]]]},"properties":{"x":4049,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1587444.2031421885],[-10133715.460120313,1589890.1880468763],[-10131269.475215625,1589890.1880468763],[-10131269.475215625,1587444.2031421885],[-10133715.460120313,1587444.2031421885]]]]},"properties":{"x":4049,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1589890.1880468763],[-10133715.460120313,1592336.1729515642],[-10131269.475215625,1592336.1729515642],[-10131269.475215625,1589890.1880468763],[-10133715.460120313,1589890.1880468763]]]]},"properties":{"x":4049,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1592336.1729515642],[-10133715.460120313,1594782.1578562483],[-10131269.475215625,1594782.1578562483],[-10131269.475215625,1592336.1729515642],[-10133715.460120313,1592336.1729515642]]]]},"properties":{"x":4049,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1594782.1578562483],[-10133715.460120313,1597228.1427609362],[-10131269.475215625,1597228.1427609362],[-10131269.475215625,1594782.1578562483],[-10133715.460120313,1594782.1578562483]]]]},"properties":{"x":4049,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1597228.1427609362],[-10133715.460120313,1599674.127665624],[-10131269.475215625,1599674.127665624],[-10131269.475215625,1597228.1427609362],[-10133715.460120313,1597228.1427609362]]]]},"properties":{"x":4049,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1599674.127665624],[-10133715.460120313,1602120.1125703119],[-10131269.475215625,1602120.1125703119],[-10131269.475215625,1599674.127665624],[-10133715.460120313,1599674.127665624]]]]},"properties":{"x":4049,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1602120.1125703119],[-10133715.460120313,1604566.0974749997],[-10131269.475215625,1604566.0974749997],[-10131269.475215625,1602120.1125703119],[-10133715.460120313,1602120.1125703119]]]]},"properties":{"x":4049,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1604566.0974749997],[-10133715.460120313,1607012.0823796876],[-10131269.475215625,1607012.0823796876],[-10131269.475215625,1604566.0974749997],[-10133715.460120313,1604566.0974749997]]]]},"properties":{"x":4049,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1607012.0823796876],[-10133715.460120313,1609458.0672843754],[-10131269.475215625,1609458.0672843754],[-10131269.475215625,1607012.0823796876],[-10133715.460120313,1607012.0823796876]]]]},"properties":{"x":4049,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1609458.0672843754],[-10133715.460120313,1611904.0521890633],[-10131269.475215625,1611904.0521890633],[-10131269.475215625,1609458.0672843754],[-10133715.460120313,1609458.0672843754]]]]},"properties":{"x":4049,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1611904.0521890633],[-10133715.460120313,1614350.0370937511],[-10131269.475215625,1614350.0370937511],[-10131269.475215625,1611904.0521890633],[-10133715.460120313,1611904.0521890633]]]]},"properties":{"x":4049,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1614350.0370937511],[-10133715.460120313,1616796.021998439],[-10131269.475215625,1616796.021998439],[-10131269.475215625,1614350.0370937511],[-10133715.460120313,1614350.0370937511]]]]},"properties":{"x":4049,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1616796.021998439],[-10133715.460120313,1619242.0069031268],[-10131269.475215625,1619242.0069031268],[-10131269.475215625,1616796.021998439],[-10133715.460120313,1616796.021998439]]]]},"properties":{"x":4049,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1619242.0069031268],[-10133715.460120313,1621687.991807811],[-10131269.475215625,1621687.991807811],[-10131269.475215625,1619242.0069031268],[-10133715.460120313,1619242.0069031268]]]]},"properties":{"x":4049,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1621687.991807811],[-10133715.460120313,1624133.9767124988],[-10131269.475215625,1624133.9767124988],[-10131269.475215625,1621687.991807811],[-10133715.460120313,1621687.991807811]]]]},"properties":{"x":4049,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10133715.460120313,1624133.9767124988],[-10133715.460120313,1626579.9616171867],[-10131269.475215625,1626579.9616171867],[-10131269.475215625,1624133.9767124988],[-10133715.460120313,1624133.9767124988]]]]},"properties":{"x":4049,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1562984.3540953137],[-10131269.475215625,1565430.3390000015],[-10128823.490310939,1565430.3390000015],[-10128823.490310939,1562984.3540953137],[-10131269.475215625,1562984.3540953137]]]]},"properties":{"x":4050,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1565430.3390000015],[-10131269.475215625,1567876.3239046894],[-10128823.490310939,1567876.3239046894],[-10128823.490310939,1565430.3390000015],[-10131269.475215625,1565430.3390000015]]]]},"properties":{"x":4050,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1567876.3239046894],[-10131269.475215625,1570322.3088093735],[-10128823.490310939,1570322.3088093735],[-10128823.490310939,1567876.3239046894],[-10131269.475215625,1567876.3239046894]]]]},"properties":{"x":4050,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1570322.3088093735],[-10131269.475215625,1572768.2937140614],[-10128823.490310939,1572768.2937140614],[-10128823.490310939,1570322.3088093735],[-10131269.475215625,1570322.3088093735]]]]},"properties":{"x":4050,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1572768.2937140614],[-10131269.475215625,1575214.2786187492],[-10128823.490310939,1575214.2786187492],[-10128823.490310939,1572768.2937140614],[-10131269.475215625,1572768.2937140614]]]]},"properties":{"x":4050,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1575214.2786187492],[-10131269.475215625,1577660.263523437],[-10128823.490310939,1577660.263523437],[-10128823.490310939,1575214.2786187492],[-10131269.475215625,1575214.2786187492]]]]},"properties":{"x":4050,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1577660.263523437],[-10131269.475215625,1580106.248428125],[-10128823.490310939,1580106.248428125],[-10128823.490310939,1577660.263523437],[-10131269.475215625,1577660.263523437]]]]},"properties":{"x":4050,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1580106.248428125],[-10131269.475215625,1582552.2333328128],[-10128823.490310939,1582552.2333328128],[-10128823.490310939,1580106.248428125],[-10131269.475215625,1580106.248428125]]]]},"properties":{"x":4050,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1582552.2333328128],[-10131269.475215625,1584998.2182375006],[-10128823.490310939,1584998.2182375006],[-10128823.490310939,1582552.2333328128],[-10131269.475215625,1582552.2333328128]]]]},"properties":{"x":4050,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1584998.2182375006],[-10131269.475215625,1587444.2031421885],[-10128823.490310939,1587444.2031421885],[-10128823.490310939,1584998.2182375006],[-10131269.475215625,1584998.2182375006]]]]},"properties":{"x":4050,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1587444.2031421885],[-10131269.475215625,1589890.1880468763],[-10128823.490310939,1589890.1880468763],[-10128823.490310939,1587444.2031421885],[-10131269.475215625,1587444.2031421885]]]]},"properties":{"x":4050,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1589890.1880468763],[-10131269.475215625,1592336.1729515642],[-10128823.490310939,1592336.1729515642],[-10128823.490310939,1589890.1880468763],[-10131269.475215625,1589890.1880468763]]]]},"properties":{"x":4050,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1592336.1729515642],[-10131269.475215625,1594782.1578562483],[-10128823.490310939,1594782.1578562483],[-10128823.490310939,1592336.1729515642],[-10131269.475215625,1592336.1729515642]]]]},"properties":{"x":4050,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1594782.1578562483],[-10131269.475215625,1597228.1427609362],[-10128823.490310939,1597228.1427609362],[-10128823.490310939,1594782.1578562483],[-10131269.475215625,1594782.1578562483]]]]},"properties":{"x":4050,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1597228.1427609362],[-10131269.475215625,1599674.127665624],[-10128823.490310939,1599674.127665624],[-10128823.490310939,1597228.1427609362],[-10131269.475215625,1597228.1427609362]]]]},"properties":{"x":4050,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1599674.127665624],[-10131269.475215625,1602120.1125703119],[-10128823.490310939,1602120.1125703119],[-10128823.490310939,1599674.127665624],[-10131269.475215625,1599674.127665624]]]]},"properties":{"x":4050,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1602120.1125703119],[-10131269.475215625,1604566.0974749997],[-10128823.490310939,1604566.0974749997],[-10128823.490310939,1602120.1125703119],[-10131269.475215625,1602120.1125703119]]]]},"properties":{"x":4050,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1604566.0974749997],[-10131269.475215625,1607012.0823796876],[-10128823.490310939,1607012.0823796876],[-10128823.490310939,1604566.0974749997],[-10131269.475215625,1604566.0974749997]]]]},"properties":{"x":4050,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1607012.0823796876],[-10131269.475215625,1609458.0672843754],[-10128823.490310939,1609458.0672843754],[-10128823.490310939,1607012.0823796876],[-10131269.475215625,1607012.0823796876]]]]},"properties":{"x":4050,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1609458.0672843754],[-10131269.475215625,1611904.0521890633],[-10128823.490310939,1611904.0521890633],[-10128823.490310939,1609458.0672843754],[-10131269.475215625,1609458.0672843754]]]]},"properties":{"x":4050,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1611904.0521890633],[-10131269.475215625,1614350.0370937511],[-10128823.490310939,1614350.0370937511],[-10128823.490310939,1611904.0521890633],[-10131269.475215625,1611904.0521890633]]]]},"properties":{"x":4050,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1614350.0370937511],[-10131269.475215625,1616796.021998439],[-10128823.490310939,1616796.021998439],[-10128823.490310939,1614350.0370937511],[-10131269.475215625,1614350.0370937511]]]]},"properties":{"x":4050,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1616796.021998439],[-10131269.475215625,1619242.0069031268],[-10128823.490310939,1619242.0069031268],[-10128823.490310939,1616796.021998439],[-10131269.475215625,1616796.021998439]]]]},"properties":{"x":4050,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1619242.0069031268],[-10131269.475215625,1621687.991807811],[-10128823.490310939,1621687.991807811],[-10128823.490310939,1619242.0069031268],[-10131269.475215625,1619242.0069031268]]]]},"properties":{"x":4050,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1621687.991807811],[-10131269.475215625,1624133.9767124988],[-10128823.490310939,1624133.9767124988],[-10128823.490310939,1621687.991807811],[-10131269.475215625,1621687.991807811]]]]},"properties":{"x":4050,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10131269.475215625,1624133.9767124988],[-10131269.475215625,1626579.9616171867],[-10128823.490310939,1626579.9616171867],[-10128823.490310939,1624133.9767124988],[-10131269.475215625,1624133.9767124988]]]]},"properties":{"x":4050,"y":8856,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1562984.3540953137],[-10128823.490310939,1565430.3390000015],[-10126377.505406251,1565430.3390000015],[-10126377.505406251,1562984.3540953137],[-10128823.490310939,1562984.3540953137]]]]},"properties":{"x":4051,"y":8831,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1565430.3390000015],[-10128823.490310939,1567876.3239046894],[-10126377.505406251,1567876.3239046894],[-10126377.505406251,1565430.3390000015],[-10128823.490310939,1565430.3390000015]]]]},"properties":{"x":4051,"y":8832,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1567876.3239046894],[-10128823.490310939,1570322.3088093735],[-10126377.505406251,1570322.3088093735],[-10126377.505406251,1567876.3239046894],[-10128823.490310939,1567876.3239046894]]]]},"properties":{"x":4051,"y":8833,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1570322.3088093735],[-10128823.490310939,1572768.2937140614],[-10126377.505406251,1572768.2937140614],[-10126377.505406251,1570322.3088093735],[-10128823.490310939,1570322.3088093735]]]]},"properties":{"x":4051,"y":8834,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1572768.2937140614],[-10128823.490310939,1575214.2786187492],[-10126377.505406251,1575214.2786187492],[-10126377.505406251,1572768.2937140614],[-10128823.490310939,1572768.2937140614]]]]},"properties":{"x":4051,"y":8835,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1575214.2786187492],[-10128823.490310939,1577660.263523437],[-10126377.505406251,1577660.263523437],[-10126377.505406251,1575214.2786187492],[-10128823.490310939,1575214.2786187492]]]]},"properties":{"x":4051,"y":8836,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1577660.263523437],[-10128823.490310939,1580106.248428125],[-10126377.505406251,1580106.248428125],[-10126377.505406251,1577660.263523437],[-10128823.490310939,1577660.263523437]]]]},"properties":{"x":4051,"y":8837,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1580106.248428125],[-10128823.490310939,1582552.2333328128],[-10126377.505406251,1582552.2333328128],[-10126377.505406251,1580106.248428125],[-10128823.490310939,1580106.248428125]]]]},"properties":{"x":4051,"y":8838,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1582552.2333328128],[-10128823.490310939,1584998.2182375006],[-10126377.505406251,1584998.2182375006],[-10126377.505406251,1582552.2333328128],[-10128823.490310939,1582552.2333328128]]]]},"properties":{"x":4051,"y":8839,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1584998.2182375006],[-10128823.490310939,1587444.2031421885],[-10126377.505406251,1587444.2031421885],[-10126377.505406251,1584998.2182375006],[-10128823.490310939,1584998.2182375006]]]]},"properties":{"x":4051,"y":8840,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1587444.2031421885],[-10128823.490310939,1589890.1880468763],[-10126377.505406251,1589890.1880468763],[-10126377.505406251,1587444.2031421885],[-10128823.490310939,1587444.2031421885]]]]},"properties":{"x":4051,"y":8841,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1589890.1880468763],[-10128823.490310939,1592336.1729515642],[-10126377.505406251,1592336.1729515642],[-10126377.505406251,1589890.1880468763],[-10128823.490310939,1589890.1880468763]]]]},"properties":{"x":4051,"y":8842,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1592336.1729515642],[-10128823.490310939,1594782.1578562483],[-10126377.505406251,1594782.1578562483],[-10126377.505406251,1592336.1729515642],[-10128823.490310939,1592336.1729515642]]]]},"properties":{"x":4051,"y":8843,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1594782.1578562483],[-10128823.490310939,1597228.1427609362],[-10126377.505406251,1597228.1427609362],[-10126377.505406251,1594782.1578562483],[-10128823.490310939,1594782.1578562483]]]]},"properties":{"x":4051,"y":8844,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1597228.1427609362],[-10128823.490310939,1599674.127665624],[-10126377.505406251,1599674.127665624],[-10126377.505406251,1597228.1427609362],[-10128823.490310939,1597228.1427609362]]]]},"properties":{"x":4051,"y":8845,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1599674.127665624],[-10128823.490310939,1602120.1125703119],[-10126377.505406251,1602120.1125703119],[-10126377.505406251,1599674.127665624],[-10128823.490310939,1599674.127665624]]]]},"properties":{"x":4051,"y":8846,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1602120.1125703119],[-10128823.490310939,1604566.0974749997],[-10126377.505406251,1604566.0974749997],[-10126377.505406251,1602120.1125703119],[-10128823.490310939,1602120.1125703119]]]]},"properties":{"x":4051,"y":8847,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1604566.0974749997],[-10128823.490310939,1607012.0823796876],[-10126377.505406251,1607012.0823796876],[-10126377.505406251,1604566.0974749997],[-10128823.490310939,1604566.0974749997]]]]},"properties":{"x":4051,"y":8848,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1607012.0823796876],[-10128823.490310939,1609458.0672843754],[-10126377.505406251,1609458.0672843754],[-10126377.505406251,1607012.0823796876],[-10128823.490310939,1607012.0823796876]]]]},"properties":{"x":4051,"y":8849,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1609458.0672843754],[-10128823.490310939,1611904.0521890633],[-10126377.505406251,1611904.0521890633],[-10126377.505406251,1609458.0672843754],[-10128823.490310939,1609458.0672843754]]]]},"properties":{"x":4051,"y":8850,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1611904.0521890633],[-10128823.490310939,1614350.0370937511],[-10126377.505406251,1614350.0370937511],[-10126377.505406251,1611904.0521890633],[-10128823.490310939,1611904.0521890633]]]]},"properties":{"x":4051,"y":8851,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1614350.0370937511],[-10128823.490310939,1616796.021998439],[-10126377.505406251,1616796.021998439],[-10126377.505406251,1614350.0370937511],[-10128823.490310939,1614350.0370937511]]]]},"properties":{"x":4051,"y":8852,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1616796.021998439],[-10128823.490310939,1619242.0069031268],[-10126377.505406251,1619242.0069031268],[-10126377.505406251,1616796.021998439],[-10128823.490310939,1616796.021998439]]]]},"properties":{"x":4051,"y":8853,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1619242.0069031268],[-10128823.490310939,1621687.991807811],[-10126377.505406251,1621687.991807811],[-10126377.505406251,1619242.0069031268],[-10128823.490310939,1619242.0069031268]]]]},"properties":{"x":4051,"y":8854,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1621687.991807811],[-10128823.490310939,1624133.9767124988],[-10126377.505406251,1624133.9767124988],[-10126377.505406251,1621687.991807811],[-10128823.490310939,1621687.991807811]]]]},"properties":{"x":4051,"y":8855,"zoom":14,"isSquare":true}},{"type":"Feature","geometry":{"type":"MultiPolygon","coordinates":[[[[-10128823.490310939,1624133.9767124988],[-10128823.490310939,1626579.9616171867],[-10126377.505406251,1626579.9616171867],[-10126377.505406251,1624133.9767124988],[-10128823.490310939,1624133.9767124988]]]]},"properties":{"x":4051,"y":8856,"zoom":14,"isSquare":true}}]}} diff --git a/tests/backend/helpers/test_files/canned_draft_project.json b/tests/backend/helpers/test_files/canned_draft_project.json deleted file mode 100644 index 01dce9f5ae..0000000000 --- a/tests/backend/helpers/test_files/canned_draft_project.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "areaOfInterest": { - "type": "FeatureCollection", - "features": [ - { - "id": "de744f407ca8d92a7298ad2a13d362f5", - "type": "Feature", - "properties": {}, - "geometry": { - "coordinates": [ - [ - [ - 84.767265, - 27.808938 - ], - [ - 84.774481, - 27.808117 - ], - [ - 84.774327, - 27.803786 - ], - [ - 84.765719, - 27.805017 - ], - [ - 84.767265, - 27.808938 - ] - ] - ], - "type": "Polygon" - } - } - ] - }, - "projectName": "Test", - "organisation": 23, - "tasks": { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "properties": { - "x": 753, - "y": 594, - "zoom": 10, - "isSquare": false - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 84.767265, - 27.808938 - ], - [ - 84.774481, - 27.808117 - ], - [ - 84.774327, - 27.803786 - ], - [ - 84.765719, - 27.805017 - ], - [ - 84.767265, - 27.808938 - ] - ] - ] - ] - } - } - ] - }, - "arbitraryTasks": false -} diff --git a/tests/backend/helpers/test_files/canned_kml_project.json b/tests/backend/helpers/test_files/canned_kml_project.json deleted file mode 100644 index 79d4c43455..0000000000 --- a/tests/backend/helpers/test_files/canned_kml_project.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "areaOfInterest": { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - -4.65996216497632, - 55.95041925350509, - 0 - ], - [ - -4.95173413390339, - 56.262794514545504, - 0 - ], - [ - -4.67367146099783, - 56.2434516969104, - 0 - ], - [ - -4.66709656284914, - 56.2435936767028, - 0 - ], - [ - -4.0046243330544, - 56.03981437664169, - 0 - ], - [ - -4.35742797997559, - 55.48727395069889, - 0 - ], - [ - -4.65996216497632, - 55.95041925350509, - 0 - ] - ] - ] - }, - "properties": null - } - ] - }, - "projectName": "kml", - "tasks": null, - "arbitraryTasks": true -} diff --git a/tests/backend/helpers/test_files/canned_project_detail.json b/tests/backend/helpers/test_files/canned_project_detail.json deleted file mode 100644 index 3affb09ed3..0000000000 --- a/tests/backend/helpers/test_files/canned_project_detail.json +++ /dev/null @@ -1,180 +0,0 @@ -{ - "projectId": 8653, - "status": "PUBLISHED", - "projectPriority": "URGENT", - "areaOfInterest": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 83.771175, - 28.095768 - ], - [ - 83.773586, - 28.095757 - ], - [ - 83.773428, - 28.094146 - ], - [ - 83.770834, - 28.094479 - ], - [ - 83.771175, - 28.095768 - ] - ] - ] - ] - }, - "aoiBBOX": [ - 83.770834, - 28.094146, - 83.773586, - 28.095768 - ], - "tasks": { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 83.771175, - 28.095768 - ], - [ - 83.773586, - 28.095757 - ], - [ - 83.773428, - 28.094146 - ], - [ - 83.770834, - 28.094479 - ], - [ - 83.771175, - 28.095768 - ] - ] - ] - ] - }, - "properties": { - "taskId": 1, - "taskX": 48018, - "taskY": 38100, - "taskZoom": 16, - "taskIsSquare": false, - "taskStatus": "READY", - "lockedBy": null - } - } - ] - }, - "defaultLocale": "en", - "projectInfo": { - "locale": "en", - "name": "Test", - "shortDescription": "", - "description": "", - "instructions": "", - "perTaskInstructions": "" - }, - "projectInfoLocales": [ - { - "locale": "en", - "name": "Test", - "shortDescription": "Test short description", - "description": "Test description", - "instructions": "Testing detailed instructions", - "perTaskInstructions": "Tests" - } - ], - "difficulty": "EASY", - "mappingPermission": "ANY", - "validationPermission": "LEVEL", - "enforceRandomTaskSelection": false, - "private": false, - "changesetComment": "#hot-tm-stage-project-8653", - "osmchaFilterId": null, - "dueDate": null, - "imagery": null, - "idPresets": null, - "rapidPowerUser": false, - "mappingTypes": [ - "ROADS", - "BUILDINGS" - ], - "campaigns": [], - "organisation": 23, - "organisationName": "Kathmandu Living Labs", - "organisationSlug": "KLL", - "organisationLogo": "https://cdn.hotosm.org/tasking-manager/uploads/1652896455106_main-logo.png", - "countryTag": [ - "Nepal" - ], - "licenseId": null, - "allowedUsernames": [], - "priorityAreas": [ - { - "coordinates": [ - [ - [ - 83.77175831878799, - 28.095285381948983 - ], - [ - 83.77256705935366, - 28.095301973647963 - ], - [ - 83.77252317420658, - 28.094837405100535 - ], - [ - 83.77168935641481, - 28.094876119222604 - ], - [ - 83.77175831878799, - 28.095285381948983 - ] - ] - ], - "type": "Polygon" - } - ], - "created": "2022-05-19T04:59:47.310401Z", - "lastUpdated": "2022-05-19T04:59:47.305580Z", - "author": "Thinkwhere Test", - "activeMappers": 0, - "percentMapped": 0, - "percentValidated": 0, - "percentBadImagery": 0, - "taskCreationMode": "GRID", - "teams": [], - "mappingEditors": [ - "ID", - "JOSM", - "CUSTOM" - ], - "validationEditors": [ - "ID", - "JOSM", - "CUSTOM" - ], - "interests": [], - "extraIdParams": "" -} diff --git a/tests/backend/helpers/test_files/clipped_feature_collection.json b/tests/backend/helpers/test_files/clipped_feature_collection.json deleted file mode 100644 index c81c2f4eb2..0000000000 --- a/tests/backend/helpers/test_files/clipped_feature_collection.json +++ /dev/null @@ -1,1145 +0,0 @@ -{ - "type":"FeatureCollection", - "features":[ - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275034.3899838, - 2828857.9792994 - ], - [ - 1275046.0685966, - 2828857.9792994 - ], - [ - 1275046.0685966, - 2828781.5422711 - ], - [ - 1275016.6455452, - 2828781.5422711 - ], - [ - 1275034.3899838, - 2828857.9792994 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278824, - "y":299152, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275046.0685966, - 2828908.286806 - ], - [ - 1275046.0685966, - 2828857.9792994 - ], - [ - 1275034.3899838, - 2828857.9792994 - ], - [ - 1275046.0685966, - 2828908.286806 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278824, - "y":299153, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275046.0685966, - 2828781.5422711 - ], - [ - 1275046.0685966, - 2828857.9792994 - ], - [ - 1275122.5056249, - 2828857.9792994 - ], - [ - 1275122.5056249, - 2828781.5422711 - ], - [ - 1275046.0685966, - 2828781.5422711 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278825, - "y":299152, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275052.1344223, - 2828934.4163276 - ], - [ - 1275122.5056249, - 2828934.4163276 - ], - [ - 1275122.5056249, - 2828857.9792994 - ], - [ - 1275046.0685966, - 2828857.9792994 - ], - [ - 1275046.0685966, - 2828908.286806 - ], - [ - 1275052.1344223, - 2828934.4163276 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278825, - "y":299153, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275069.8788608, - 2829010.8533559 - ], - [ - 1275122.5056249, - 2829010.8533559 - ], - [ - 1275122.5056249, - 2828934.4163276 - ], - [ - 1275052.1344223, - 2828934.4163276 - ], - [ - 1275069.8788608, - 2829010.8533559 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278825, - "y":299154, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275087.6232994, - 2829087.2903842 - ], - [ - 1275122.5056249, - 2829087.2903842 - ], - [ - 1275122.5056249, - 2829010.8533559 - ], - [ - 1275069.8788608, - 2829010.8533559 - ], - [ - 1275087.6232994, - 2829087.2903842 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278825, - "y":299155, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275122.5056249, - 2828781.5422711 - ], - [ - 1275122.5056249, - 2828857.9792994 - ], - [ - 1275198.9426532, - 2828857.9792994 - ], - [ - 1275198.9426532, - 2828781.5422711 - ], - [ - 1275122.5056249, - 2828781.5422711 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278826, - "y":299152, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275122.5056249, - 2828857.9792994 - ], - [ - 1275122.5056249, - 2828934.4163276 - ], - [ - 1275198.9426532, - 2828934.4163276 - ], - [ - 1275198.9426532, - 2828857.9792994 - ], - [ - 1275122.5056249, - 2828857.9792994 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278826, - "y":299153, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275122.5056249, - 2828934.4163276 - ], - [ - 1275122.5056249, - 2829010.8533559 - ], - [ - 1275198.9426532, - 2829010.8533559 - ], - [ - 1275198.9426532, - 2828934.4163276 - ], - [ - 1275122.5056249, - 2828934.4163276 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278826, - "y":299154, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275122.5056249, - 2829010.8533559 - ], - [ - 1275122.5056249, - 2829087.2903842 - ], - [ - 1275198.9426532, - 2829087.2903842 - ], - [ - 1275198.9426532, - 2829010.8533559 - ], - [ - 1275122.5056249, - 2829010.8533559 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278826, - "y":299155, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275275.3796814, - 2828783.0982896 - ], - [ - 1275200.6907704, - 2828781.5422711 - ], - [ - 1275198.9426532, - 2828781.5422711 - ], - [ - 1275198.9426532, - 2828857.9792994 - ], - [ - 1275275.3796814, - 2828857.9792994 - ], - [ - 1275275.3796814, - 2828783.0982896 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278827, - "y":299152, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275198.9426532, - 2828857.9792994 - ], - [ - 1275198.9426532, - 2828934.4163276 - ], - [ - 1275275.3796814, - 2828934.4163276 - ], - [ - 1275275.3796814, - 2828857.9792994 - ], - [ - 1275198.9426532, - 2828857.9792994 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278827, - "y":299153, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275198.9426532, - 2828934.4163276 - ], - [ - 1275198.9426532, - 2829010.8533559 - ], - [ - 1275275.3796814, - 2829010.8533559 - ], - [ - 1275275.3796814, - 2828934.4163276 - ], - [ - 1275198.9426532, - 2828934.4163276 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278827, - "y":299154, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275198.9426532, - 2829010.8533559 - ], - [ - 1275198.9426532, - 2829087.2903842 - ], - [ - 1275275.3796814, - 2829087.2903842 - ], - [ - 1275275.3796814, - 2829010.8533559 - ], - [ - 1275198.9426532, - 2829010.8533559 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278827, - "y":299155, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275581.1277945, - 2829087.2903842 - ], - [ - 1275581.1277945, - 2829163.7274125 - ], - [ - 1275657.5648228, - 2829163.7274125 - ], - [ - 1275657.5648228, - 2829087.2903842 - ], - [ - 1275581.1277945, - 2829087.2903842 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278832, - "y":299156, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275581.1277945, - 2829163.7274125 - ], - [ - 1275581.1277945, - 2829240.1644407 - ], - [ - 1275657.5648228, - 2829240.1644407 - ], - [ - 1275657.5648228, - 2829163.7274125 - ], - [ - 1275581.1277945, - 2829163.7274125 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278832, - "y":299157, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275581.1277945, - 2829306.6212479 - ], - [ - 1275657.5648228, - 2829305.5596227 - ], - [ - 1275657.5648228, - 2829240.1644407 - ], - [ - 1275581.1277945, - 2829240.1644407 - ], - [ - 1275581.1277945, - 2829306.6212479 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278832, - "y":299158, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275657.5648228, - 2829087.2903842 - ], - [ - 1275657.5648228, - 2829163.7274125 - ], - [ - 1275734.0018511, - 2829163.7274125 - ], - [ - 1275734.0018511, - 2829087.2903842 - ], - [ - 1275657.5648228, - 2829087.2903842 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278833, - "y":299156, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275657.5648228, - 2829163.7274125 - ], - [ - 1275657.5648228, - 2829240.1644407 - ], - [ - 1275734.0018511, - 2829240.1644407 - ], - [ - 1275734.0018511, - 2829163.7274125 - ], - [ - 1275657.5648228, - 2829163.7274125 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278833, - "y":299157, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275734.0018511, - 2829304.4979975 - ], - [ - 1275734.0018511, - 2829240.1644407 - ], - [ - 1275657.5648228, - 2829240.1644407 - ], - [ - 1275657.5648228, - 2829305.5596227 - ], - [ - 1275734.0018511, - 2829304.4979975 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278833, - "y":299158, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275734.0018511, - 2829087.2903842 - ], - [ - 1275734.0018511, - 2829163.7274125 - ], - [ - 1275810.4388793, - 2829163.7274125 - ], - [ - 1275810.4388793, - 2829087.2903842 - ], - [ - 1275734.0018511, - 2829087.2903842 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278834, - "y":299156, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275734.0018511, - 2829163.7274125 - ], - [ - 1275734.0018511, - 2829240.1644407 - ], - [ - 1275810.4388793, - 2829240.1644407 - ], - [ - 1275810.4388793, - 2829163.7274125 - ], - [ - 1275734.0018511, - 2829163.7274125 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":true, - "x":278834, - "y":299157, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275810.4388793, - 2829303.4363723 - ], - [ - 1275810.4388793, - 2829240.1644407 - ], - [ - 1275734.0018511, - 2829240.1644407 - ], - [ - 1275734.0018511, - 2829304.4979975 - ], - [ - 1275810.4388793, - 2829303.4363723 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278834, - "y":299158, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275810.4388793, - 2829087.2903842 - ], - [ - 1275810.4388793, - 2829163.7274125 - ], - [ - 1275856.8401371, - 2829163.7274125 - ], - [ - 1275872.7042755, - 2829087.2903842 - ], - [ - 1275810.4388793, - 2829087.2903842 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278835, - "y":299156, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275856.8401371, - 2829163.7274125 - ], - [ - 1275810.4388793, - 2829163.7274125 - ], - [ - 1275810.4388793, - 2829240.1644407 - ], - [ - 1275840.9759988, - 2829240.1644407 - ], - [ - 1275856.8401371, - 2829163.7274125 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278835, - "y":299157, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275827.8945302, - 2829303.1939328 - ], - [ - 1275840.9759988, - 2829240.1644407 - ], - [ - 1275810.4388793, - 2829240.1644407 - ], - [ - 1275810.4388793, - 2829303.4363723 - ], - [ - 1275827.8945302, - 2829303.1939328 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278835, - "y":299158, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275886.8759076, - 2828795.8377961 - ], - [ - 1275886.8759076, - 2828857.9792994 - ], - [ - 1275920.2974494, - 2828857.9792994 - ], - [ - 1275932.995444, - 2828796.7986204 - ], - [ - 1275886.8759076, - 2828795.8377961 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278836, - "y":299152, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275886.8759076, - 2828934.4163276 - ], - [ - 1275904.4330133, - 2828934.4163276 - ], - [ - 1275920.2974494, - 2828857.9792994 - ], - [ - 1275886.8759076, - 2828857.9792994 - ], - [ - 1275886.8759076, - 2828934.4163276 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278836, - "y":299153, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275886.8759076, - 2829010.8533559 - ], - [ - 1275888.5685772, - 2829010.8533559 - ], - [ - 1275904.4330133, - 2828934.4163276 - ], - [ - 1275886.8759076, - 2828934.4163276 - ], - [ - 1275886.8759076, - 2829010.8533559 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278836, - "y":299154, - "zoom":19 - } - }, - { - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - 1275886.8759076, - 2829019.00887 - ], - [ - 1275888.5685772, - 2829010.8533559 - ], - [ - 1275886.8759076, - 2829010.8533559 - ], - [ - 1275886.8759076, - 2829019.00887 - ] - ] - ] - ] - }, - "properties":{ - "isSquare":false, - "x":278836, - "y":299155, - "zoom":19 - } - } - ] -} diff --git a/tests/backend/helpers/test_files/feature_collection.json b/tests/backend/helpers/test_files/feature_collection.json deleted file mode 100644 index 79c474a2fc..0000000000 --- a/tests/backend/helpers/test_files/feature_collection.json +++ /dev/null @@ -1,1145 +0,0 @@ -{ - "features": [ - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2828781.5422710925 - ], - [ - 1274969.631568361, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828781.5422710925 - ], - [ - 1274969.631568361, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278824, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2828857.9792993665 - ], - [ - 1274969.631568361, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1274969.631568361, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278824, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828781.5422710925 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828781.5422710925 - ], - [ - 1275046.0685966313, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299154, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2829010.853355907 - ], - [ - 1275046.0685966313, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275046.0685966313, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828781.5422710925 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828781.5422710925 - ], - [ - 1275122.5056249015, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299154, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828781.5422710925 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275275.3796814457, - 2828857.9792993665 - ], - [ - 1275275.3796814457, - 2828781.5422710925 - ], - [ - 1275198.9426531754, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275275.3796814457, - 2828934.4163276367 - ], - [ - 1275275.3796814457, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275275.3796814457, - 2829010.853355907 - ], - [ - 1275275.3796814457, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299154, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275275.3796814457, - 2829087.290384181 - ], - [ - 1275275.3796814457, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278832, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278832, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829316.601468995 - ], - [ - 1275657.5648228042, - 2829316.601468995 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278832, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278833, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278833, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829316.601468995 - ], - [ - 1275734.0018510744, - 2829316.601468995 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278833, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278834, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278834, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829316.601468995 - ], - [ - 1275810.4388793446, - 2829316.601468995 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278834, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275886.8759076186, - 2829163.727412451 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278835, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275886.8759076186, - 2829240.1644407213 - ], - [ - 1275886.8759076186, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278835, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829316.601468995 - ], - [ - 1275886.8759076186, - 2829316.601468995 - ], - [ - 1275886.8759076186, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278835, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828781.5422710925 - ], - [ - 1275886.8759076186, - 2828857.9792993665 - ], - [ - 1275963.3129358888, - 2828857.9792993665 - ], - [ - 1275963.3129358888, - 2828781.5422710925 - ], - [ - 1275886.8759076186, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278836, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828857.9792993665 - ], - [ - 1275886.8759076186, - 2828934.4163276367 - ], - [ - 1275963.3129358888, - 2828934.4163276367 - ], - [ - 1275963.3129358888, - 2828857.9792993665 - ], - [ - 1275886.8759076186, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278836, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828934.4163276367 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275963.3129358888, - 2829010.853355907 - ], - [ - 1275963.3129358888, - 2828934.4163276367 - ], - [ - 1275886.8759076186, - 2828934.4163276367 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278836, - "y": 299154, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275963.3129358888, - 2829087.290384181 - ], - [ - 1275963.3129358888, - 2829010.853355907 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278836, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - } - ], - "type": "FeatureCollection" -} diff --git a/tests/backend/helpers/test_files/feature_collection_one_multipolygon.json b/tests/backend/helpers/test_files/feature_collection_one_multipolygon.json deleted file mode 100644 index 5f38017036..0000000000 --- a/tests/backend/helpers/test_files/feature_collection_one_multipolygon.json +++ /dev/null @@ -1,1563 +0,0 @@ -{ - "features": [ - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2828781.5422710925 - ], - [ - 1274969.631568361, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828781.5422710925 - ], - [ - 1274969.631568361, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278824, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2828857.9792993665 - ], - [ - 1274969.631568361, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1274969.631568361, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278824, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828781.5422710925 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828781.5422710925 - ], - [ - 1275046.0685966313, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299154, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2829010.853355907 - ], - [ - 1275046.0685966313, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275046.0685966313, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2829087.290384181 - ], - [ - 1275046.0685966313, - 2829163.727412451 - ], - [ - 1275122.5056249015, - 2829163.727412451 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275046.0685966313, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278825, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828781.5422710925 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828781.5422710925 - ], - [ - 1275122.5056249015, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299154, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829163.727412451 - ], - [ - 1275198.9426531754, - 2829163.727412451 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278826, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828781.5422710925 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275275.3796814457, - 2828857.9792993665 - ], - [ - 1275275.3796814457, - 2828781.5422710925 - ], - [ - 1275198.9426531754, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275275.3796814457, - 2828934.4163276367 - ], - [ - 1275275.3796814457, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275275.3796814457, - 2829010.853355907 - ], - [ - 1275275.3796814457, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299154, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275275.3796814457, - 2829087.290384181 - ], - [ - 1275275.3796814457, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829163.727412451 - ], - [ - 1275275.3796814457, - 2829163.727412451 - ], - [ - 1275275.3796814457, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278827, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2829010.853355907 - ], - [ - 1275504.69076626, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829010.853355907 - ], - [ - 1275504.69076626, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278831, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2829087.290384181 - ], - [ - 1275504.69076626, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275504.69076626, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278831, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2829163.727412451 - ], - [ - 1275504.69076626, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275504.69076626, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278831, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2829240.1644407213 - ], - [ - 1275504.69076626, - 2829316.601468995 - ], - [ - 1275581.1277945302, - 2829316.601468995 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275504.69076626, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278831, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829010.853355907 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829010.853355907 - ], - [ - 1275581.1277945302, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278832, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278832, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278832, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829316.601468995 - ], - [ - 1275657.5648228042, - 2829316.601468995 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278832, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829010.853355907 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829010.853355907 - ], - [ - 1275657.5648228042, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278833, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278833, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278833, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829316.601468995 - ], - [ - 1275734.0018510744, - 2829316.601468995 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278833, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829010.853355907 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829010.853355907 - ], - [ - 1275734.0018510744, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278834, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278834, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278834, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829316.601468995 - ], - [ - 1275810.4388793446, - 2829316.601468995 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278834, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829010.853355907 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275810.4388793446, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278835, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275886.8759076186, - 2829163.727412451 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278835, - "y": 299156, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275886.8759076186, - 2829240.1644407213 - ], - [ - 1275886.8759076186, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278835, - "y": 299157, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829316.601468995 - ], - [ - 1275886.8759076186, - 2829316.601468995 - ], - [ - 1275886.8759076186, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278835, - "y": 299158, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828781.5422710925 - ], - [ - 1275886.8759076186, - 2828857.9792993665 - ], - [ - 1275963.3129358888, - 2828857.9792993665 - ], - [ - 1275963.3129358888, - 2828781.5422710925 - ], - [ - 1275886.8759076186, - 2828781.5422710925 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278836, - "y": 299152, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828857.9792993665 - ], - [ - 1275886.8759076186, - 2828934.4163276367 - ], - [ - 1275963.3129358888, - 2828934.4163276367 - ], - [ - 1275963.3129358888, - 2828857.9792993665 - ], - [ - 1275886.8759076186, - 2828857.9792993665 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278836, - "y": 299153, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828934.4163276367 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275963.3129358888, - 2829010.853355907 - ], - [ - 1275963.3129358888, - 2828934.4163276367 - ], - [ - 1275886.8759076186, - 2828934.4163276367 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278836, - "y": 299154, - "zoom": 19 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275963.3129358888, - 2829087.290384181 - ], - [ - 1275963.3129358888, - 2829010.853355907 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 278836, - "y": 299155, - "zoom": 19 - }, - "type": "Feature" - } - ], - "type": "FeatureCollection" -} diff --git a/tests/backend/helpers/test_files/multi_polygon.json b/tests/backend/helpers/test_files/multi_polygon.json deleted file mode 100644 index 0806502ef9..0000000000 --- a/tests/backend/helpers/test_files/multi_polygon.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "coordinates": [ - [ - [ - [ - 1275275.379681445, - 2828783.098289569 - ], - [ - 1275200.690770448, - 2828781.542271093 - ], - [ - 1275016.64554516, - 2828781.542271093 - ], - [ - 1275087.623299365, - 2829087.290384181 - ], - [ - 1275275.379681445, - 2829087.290384181 - ], - [ - 1275275.379681445, - 2828783.098289569 - ] - ] - ], - [ - [ - [ - 1275581.12779453, - 2829306.621247852 - ], - [ - 1275827.894530152, - 2829303.193932765 - ], - [ - 1275872.704275511, - 2829087.290384181 - ], - [ - 1275581.12779453, - 2829087.290384181 - ], - [ - 1275581.12779453, - 2829306.621247852 - ] - ] - ], - [ - [ - [ - 1275886.875907619, - 2829019.008869979 - ], - [ - 1275932.995444044, - 2828796.798620377 - ], - [ - 1275886.875907619, - 2828795.837796132 - ], - [ - 1275886.875907619, - 2829019.008869979 - ] - ] - ] - ], - "type": "MultiPolygon" -} diff --git a/tests/backend/helpers/test_files/multi_polygon_dissolved.json b/tests/backend/helpers/test_files/multi_polygon_dissolved.json deleted file mode 100644 index 08c86cf7fa..0000000000 --- a/tests/backend/helpers/test_files/multi_polygon_dissolved.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "coordinates": [ - [ - [ - [ - 1275886.875907619, - 2829019.008869979 - ], - [ - 1275932.995444044, - 2828796.798620377 - ], - [ - 1275886.875907619, - 2828795.837796132 - ], - [ - 1275886.875907619, - 2829019.008869979 - ] - ] - ], - [ - [ - [ - 1275275.379681445, - 2828783.098289569 - ], - [ - 1275200.690770448, - 2828781.542271093 - ], - [ - 1275016.64554516, - 2828781.542271093 - ], - [ - 1275087.623299365, - 2829087.290384181 - ], - [ - 1275275.379681445, - 2829087.290384181 - ], - [ - 1275275.379681445, - 2828783.098289569 - ] - ] - ], - [ - [ - [ - 1275581.12779453, - 2829306.621247852 - ], - [ - 1275827.894530152, - 2829303.193932765 - ], - [ - 1275872.704275511, - 2829087.290384181 - ], - [ - 1275581.12779453, - 2829087.290384181 - ], - [ - 1275581.12779453, - 2829306.621247852 - ] - ] - ] - ], - "type": "MultiPolygon" -} diff --git a/tests/backend/helpers/test_files/non_square_project_aoi.json b/tests/backend/helpers/test_files/non_square_project_aoi.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/helpers/test_files/non_square_split_results.json b/tests/backend/helpers/test_files/non_square_split_results.json deleted file mode 100644 index 67ef17f98b..0000000000 --- a/tests/backend/helpers/test_files/non_square_split_results.json +++ /dev/null @@ -1,214 +0,0 @@ -[ - { - "geometry": { - "coordinates": [ - [ - [ - [ - 152.401608, - -31.9521622 - ], - [ - 151.875, - -31.9521622 - ], - [ - 151.875, - -31.3112796 - ], - [ - 152.401608, - -31.3112796 - ], - [ - 152.401608, - -31.9521622 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": false, - "x": null, - "y": null, - "zoom": null - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 151.875, - -31.3112796 - ], - [ - 151.875, - -30.7512778 - ], - [ - 152.401608, - -30.7512778 - ], - [ - 152.401608, - -31.3112796 - ], - [ - 151.875, - -31.3112796 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": false, - "x": null, - "y": null, - "zoom": null - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 152.9646946, - -31.3112796 - ], - [ - 152.9646946, - -31.3148763 - ], - [ - 152.9409267, - -31.3605527 - ], - [ - 152.9495622, - -31.4453842 - ], - [ - 152.9052747, - -31.4771805 - ], - [ - 152.8577388, - -31.5734156 - ], - [ - 152.8042608, - -31.6695516 - ], - [ - 152.7329569, - -31.8160937 - ], - [ - 152.673537, - -31.8817097 - ], - [ - 152.5951471, - -31.9521622 - ], - [ - 152.401608, - -31.9521622 - ], - [ - 152.401608, - -31.3112796 - ], - [ - 152.9646946, - -31.3112796 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": false, - "x": null, - "y": null, - "zoom": null - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - 153.0026299, - -30.7512778 - ], - [ - 153.0122306, - -30.80077 - ], - [ - 153.0419406, - -30.8568964 - ], - [ - 153.0894765, - -30.91299 - ], - [ - 153.0478825, - -30.994522 - ], - [ - 153.0419406, - -31.0658054 - ], - [ - 153.0003466, - -31.1268629 - ], - [ - 152.9646946, - -31.223457 - ], - [ - 152.9646946, - -31.3112796 - ], - [ - 152.401608, - -31.3112796 - ], - [ - 152.401608, - -30.7512778 - ], - [ - 153.0026299, - -30.7512778 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": false, - "x": null, - "y": null, - "zoom": null - }, - "type": "Feature" - } -] diff --git a/tests/backend/helpers/test_files/non_square_task.json b/tests/backend/helpers/test_files/non_square_task.json deleted file mode 100644 index c88d7cd023..0000000000 --- a/tests/backend/helpers/test_files/non_square_task.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [153.002629854192, -30.7512777712788], - [153.012230588, -30.800769981], - [153.041940554, -30.8568964], - [153.0894765, -30.912989989], - [153.047882548, -30.994521987], - [153.041940554, -31.065805365], - [153.000346602, -31.126862915], - [152.964694643, -31.223457045], - [152.964694643, -31.314876311], - [152.94092667, -31.360552708], - [152.949562214, -31.445384196], - [152.905274711, -31.47718046], - [152.857738766, -31.573415644], - [152.804260827, -31.669551593], - [152.732956909, -31.816093707], - [152.673536977, -31.881709671], - [152.595147099906, -31.9521622328954], - [151.874999972795, -31.9521622328954], - [151.874999972795, -30.7512777712788], - [153.002629854192, -30.7512777712788] - ] - ] - ] - }, - "properties": { - "x": 236, - "y": 104, - "zoom": 8, - "isSquare": false - } -} diff --git a/tests/backend/helpers/test_files/osm_sample.xml b/tests/backend/helpers/test_files/osm_sample.xml deleted file mode 100644 index e047ba76d7..0000000000 --- a/tests/backend/helpers/test_files/osm_sample.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/backend/helpers/test_files/osm_user_details.json b/tests/backend/helpers/test_files/osm_user_details.json deleted file mode 100644 index f8ab062926..0000000000 --- a/tests/backend/helpers/test_files/osm_user_details.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "version": "0.6", - "generator": "OpenStreetMap server", - "copyright": "OpenStreetMap and contributors", - "attribution": "http://www.openstreetmap.org/copyright", - "license": "http://opendatacommons.org/licenses/odbl/1-0/", - "user": { - "id": 7777777, - "display_name": "Thinkwhere Test", - "account_created": "2017-01-23T16:23:22Z", - "description": "", - "contributor_terms": { - "agreed": true, - "pd": false - }, - "roles": [], - "changesets": { - "count": 16 - }, - "traces": { - "count": 0 - }, - "blocks": { - "received": { - "count": 0, - "active": 0 - } - }, - "home": { - "lat": 39.1109, - "lon": -2.991, - "zoom": 3 - }, - "languages": [ - "Spa." - ], - "messages": { - "received": { - "count": 0, - "unread": 0 - }, - "sent": { - "count": 0 - } - } - } -} diff --git a/tests/backend/helpers/test_files/osm_user_details_changed_name.xml b/tests/backend/helpers/test_files/osm_user_details_changed_name.xml deleted file mode 100644 index f0a672d63a..0000000000 --- a/tests/backend/helpers/test_files/osm_user_details_changed_name.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - en-GB - en - - - - - - - diff --git a/tests/backend/helpers/test_files/osm_user_details_simple.xml b/tests/backend/helpers/test_files/osm_user_details_simple.xml deleted file mode 100644 index 1b55db0e92..0000000000 --- a/tests/backend/helpers/test_files/osm_user_details_simple.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/tests/backend/helpers/test_files/search_bbox_feature.json b/tests/backend/helpers/test_files/search_bbox_feature.json deleted file mode 100644 index e7bab897c4..0000000000 --- a/tests/backend/helpers/test_files/search_bbox_feature.json +++ /dev/null @@ -1,2917 +0,0 @@ -{ - "coordinates": [ - [ - [ - [ - 34.0893707268651, - -0.536513984601753 - ], - [ - 34.0837097165999, - -0.535368025180619 - ], - [ - 34.0824012756666, - -0.522611022751177 - ], - [ - 34.0835189818563, - -0.521118998858031 - ], - [ - 34.0859489436038, - -0.520412028506349 - ], - [ - 34.0887794491696, - -0.522691011775293 - ], - [ - 34.0938186647061, - -0.53062498601422 - ], - [ - 34.0922393800162, - -0.534533023725973 - ], - [ - 34.0893707268651, - -0.536513984601753 - ] - ] - ], - [ - [ - [ - 34.0964317315364, - -0.473861009201641 - ], - [ - 34.0903701783458, - -0.477777987607268 - ], - [ - 34.0894088743771, - -0.480300993106367 - ], - [ - 34.0840606689686, - -0.483107000623554 - ], - [ - 34.0832290642053, - -0.485565990460461 - ], - [ - 34.0777206420479, - -0.488045990479494 - ], - [ - 34.0756301877947, - -0.48638200784417 - ], - [ - 34.0795097347646, - -0.483161986306938 - ], - [ - 34.0812988279751, - -0.477977007985046 - ], - [ - 34.0807914731244, - -0.474739998452093 - ], - [ - 34.0869102477411, - -0.474655986304899 - ], - [ - 34.0935516357163, - -0.469579995295603 - ], - [ - 34.0973091126488, - -0.472213000194603 - ], - [ - 34.0964317315364, - -0.473861009201641 - ] - ] - ], - [ - [ - [ - 33.9454116820645, - -0.463559001916262 - ], - [ - 33.9395599365248, - -0.463423997083882 - ], - [ - 33.9403190610894, - -0.459735006029653 - ], - [ - 33.945270538096, - -0.461468995234408 - ], - [ - 33.9454116820645, - -0.463559001916262 - ] - ] - ], - [ - [ - [ - 33.955379485646, - -0.439756006467532 - ], - [ - 33.9534111015895, - -0.441495001379958 - ], - [ - 33.9522895809163, - -0.436744988255081 - ], - [ - 33.9562606813082, - -0.436861009014392 - ], - [ - 33.955379485646, - -0.439756006467532 - ] - ] - ], - [ - [ - [ - 34.0426788324311, - -0.441617995922242 - ], - [ - 34.0579109193315, - -0.454786986694148 - ], - [ - 34.0618209834879, - -0.466004014204983 - ], - [ - 34.0680007929779, - -0.475248992840064 - ], - [ - 34.0617904656388, - -0.483705997355769 - ], - [ - 34.0581703181331, - -0.486158997364131 - ], - [ - 34.0514488214515, - -0.48744401352108 - ], - [ - 34.0425796502369, - -0.492495000572894 - ], - [ - 34.0173301691978, - -0.49810600351348 - ], - [ - 33.9986495967674, - -0.499177009522071 - ], - [ - 33.9948692319355, - -0.495505989061121 - ], - [ - 33.9925994866689, - -0.489533991119976 - ], - [ - 33.9869308467725, - -0.485076010336786 - ], - [ - 33.9746284482024, - -0.482282013259886 - ], - [ - 33.9698791503386, - -0.478166014668594 - ], - [ - 33.9621696468858, - -0.480320007289396 - ], - [ - 33.959869384821, - -0.4795329870708 - ], - [ - 33.9616203304768, - -0.476166993823649 - ], - [ - 33.9591789242271, - -0.474866003235944 - ], - [ - 33.9557609557607, - -0.476051002849935 - ], - [ - 33.9492187498746, - -0.472840011421986 - ], - [ - 33.9448890686212, - -0.473563998816022 - ], - [ - 33.9456787106334, - -0.471403986181399 - ], - [ - 33.9551696776208, - -0.467249006781304 - ], - [ - 33.9556808469152, - -0.463665991905308 - ], - [ - 33.9537200921702, - -0.46022900949028 - ], - [ - 33.9546508785988, - -0.458112001448788 - ], - [ - 33.9502983093133, - -0.45217698870175 - ], - [ - 33.9588890074224, - -0.451597989312783 - ], - [ - 33.9601211547147, - -0.446150988264086 - ], - [ - 33.9670181272535, - -0.441754013979948 - ], - [ - 33.9700202941679, - -0.442532002917132 - ], - [ - 33.9751205437283, - -0.451126009810991 - ], - [ - 33.9788589470794, - -0.451622992748461 - ], - [ - 33.9860610955408, - -0.448074013291747 - ], - [ - 33.993858337062, - -0.441381007317147 - ], - [ - 33.9966392511954, - -0.441868007649385 - ], - [ - 34.0144500725981, - -0.436924994268909 - ], - [ - 34.0217704769388, - -0.426748991155693 - ], - [ - 34.0259399414171, - -0.424603999414845 - ], - [ - 34.0310096737433, - -0.425832003288011 - ], - [ - 34.0374183653533, - -0.436044991164478 - ], - [ - 34.0426788324311, - -0.441617995922242 - ] - ] - ], - [ - [ - [ - 34.2754516596662, - -0.401969999488986 - ], - [ - 34.2715797423912, - -0.401030987644172 - ], - [ - 34.2744903559876, - -0.400332987688116 - ], - [ - 34.2754516596662, - -0.401969999488986 - ] - ] - ], - [ - [ - [ - 34.2781715389658, - -0.381237000492777 - ], - [ - 34.2761688228689, - -0.382865995608465 - ], - [ - 34.2743492121104, - -0.381680995640269 - ], - [ - 34.2783508301769, - -0.379925996760625 - ], - [ - 34.2781715389658, - -0.381237000492777 - ] - ] - ], - [ - [ - [ - 34.2143287655156, - -0.395693004366286 - ], - [ - 34.2142906182445, - -0.405660004031797 - ], - [ - 34.2120018004263, - -0.411262006264649 - ], - [ - 34.204349517321, - -0.415695012092491 - ], - [ - 34.2029495239652, - -0.419582993174731 - ], - [ - 34.1996002197026, - -0.421483993822473 - ], - [ - 34.1877708433517, - -0.421559006677778 - ], - [ - 34.1794395440855, - -0.427493990015186 - ], - [ - 34.1756782531266, - -0.432850003983613 - ], - [ - 34.165271758304, - -0.438524991595183 - ], - [ - 34.1613998410085, - -0.444068014742153 - ], - [ - 34.1456985469489, - -0.429895997800304 - ], - [ - 34.1378898619166, - -0.428847998925689 - ], - [ - 34.136909484728, - -0.432891011472217 - ], - [ - 34.134300231592, - -0.433950991107749 - ], - [ - 34.1333389278868, - -0.437920988165511 - ], - [ - 34.1311607357573, - -0.438971996391205 - ], - [ - 34.1283798215211, - -0.437976003020405 - ], - [ - 34.1264610287079, - -0.433889001655333 - ], - [ - 34.1176605223996, - -0.427177011840722 - ], - [ - 34.1166992184456, - -0.422545999545391 - ], - [ - 34.1192703248463, - -0.411130011306752 - ], - [ - 34.1313514703541, - -0.415950000813917 - ], - [ - 34.1384315486929, - -0.412773013288862 - ], - [ - 34.1467704774138, - -0.40178999330445 - ], - [ - 34.1569900507969, - -0.399167001650706 - ], - [ - 34.1601295471043, - -0.394279987164107 - ], - [ - 34.160659789502, - -0.3878209894747 - ], - [ - 34.1580696104563, - -0.384274989420933 - ], - [ - 34.1581687924587, - -0.37681299451016 - ], - [ - 34.1667213436273, - -0.378331006020431 - ], - [ - 34.1715507505398, - -0.380257010370037 - ], - [ - 34.1740303033703, - -0.384128988337088 - ], - [ - 34.1842308041676, - -0.388287991819939 - ], - [ - 34.1941604611658, - -0.39040300288116 - ], - [ - 34.1969604491079, - -0.398047000614702 - ], - [ - 34.1994781489183, - -0.400009989819131 - ], - [ - 34.2037086481541, - -0.397612005717622 - ], - [ - 34.2089195247285, - -0.390827000545428 - ], - [ - 34.2076797480607, - -0.387234986055222 - ], - [ - 34.2105598449187, - -0.376715004601617 - ], - [ - 34.2103385922229, - -0.36443001056801 - ], - [ - 34.2191810601522, - -0.36015901038489 - ], - [ - 34.2211189268839, - -0.354171991759936 - ], - [ - 34.2236709588762, - -0.356640011645463 - ], - [ - 34.2278518671235, - -0.357789009821622 - ], - [ - 34.2276496881491, - -0.359632999264451 - ], - [ - 34.2177581787943, - -0.380856007496425 - ], - [ - 34.2143287655156, - -0.395693004366286 - ] - ] - ], - [ - [ - [ - 34.2518005369727, - -0.355477988879186 - ], - [ - 34.2492980956664, - -0.356083989530268 - ], - [ - 34.2500114441154, - -0.352638006396314 - ], - [ - 34.2546806336564, - -0.351561993650388 - ], - [ - 34.2518005369727, - -0.355477988879186 - ] - ] - ], - [ - [ - [ - 34.2636184686575, - -0.346350014132461 - ], - [ - 34.2605094907419, - -0.351669013877824 - ], - [ - 34.2555198663605, - -0.3504230086018 - ], - [ - 34.2567787165965, - -0.34663200411094 - ], - [ - 34.2636184686575, - -0.346350014132461 - ] - ] - ], - [ - [ - [ - 34.7582206719739, - -0.31252101087114 - ], - [ - 34.7583808897327, - -0.31669801508201 - ], - [ - 34.7630691524777, - -0.315403998108347 - ], - [ - 34.7676086423743, - -0.314383000305777 - ], - [ - 34.7735099793049, - -0.320845991625677 - ], - [ - 34.7772483822775, - -0.320601999839968 - ], - [ - 34.7792587277671, - -0.322156995636362 - ], - [ - 34.7803993223333, - -0.325801014855357 - ], - [ - 34.7830009457264, - -0.324263006498863 - ], - [ - 34.7873992919402, - -0.332888990771244 - ], - [ - 34.7825813293905, - -0.334661990704691 - ], - [ - 34.7857704159269, - -0.346581995440046 - ], - [ - 34.7891006467147, - -0.345259994365036 - ], - [ - 34.7910690307328, - -0.345991999112342 - ], - [ - 34.7900810241752, - -0.348499000422978 - ], - [ - 34.7909393311158, - -0.350154012735152 - ], - [ - 34.7962989806356, - -0.351779014158352 - ], - [ - 34.7963409423905, - -0.353913993008774 - ], - [ - 34.799270629772, - -0.35537099866552 - ], - [ - 34.8058509826727, - -0.356851994946864 - ], - [ - 34.8103294373075, - -0.35494199412092 - ], - [ - 34.811920165839, - -0.361380994683084 - ], - [ - 34.8153495787066, - -0.367538988586328 - ], - [ - 34.822010040142, - -0.375279009500654 - ], - [ - 34.8231887818121, - -0.388823986316104 - ], - [ - 34.8349685665297, - -0.390866011737571 - ], - [ - 34.8395805358943, - -0.39437299970995 - ], - [ - 34.8547096251044, - -0.393049001816052 - ], - [ - 34.8581581113839, - -0.393871993094201 - ], - [ - 34.8591995235789, - -0.396349012801326 - ], - [ - 34.8614196776106, - -0.397379994409412 - ], - [ - 34.864028930384, - -0.397596001585913 - ], - [ - 34.8667411800724, - -0.39584100258521 - ], - [ - 34.8800506592569, - -0.398986011932382 - ], - [ - 34.882549285679, - -0.39778301152296 - ], - [ - 34.8892898558066, - -0.404336005388276 - ], - [ - 34.8909606930819, - -0.403268993253184 - ], - [ - 34.8915901180646, - -0.399742990849798 - ], - [ - 34.8960609436001, - -0.398467004451745 - ], - [ - 34.9023208614997, - -0.393781006539643 - ], - [ - 34.9141883848943, - -0.389872014812091 - ], - [ - 34.9129295347827, - -0.397105991776296 - ], - [ - 34.9135284423775, - -0.406210988992565 - ], - [ - 34.9157791136356, - -0.408109992857834 - ], - [ - 34.9262809752293, - -0.406415999172597 - ], - [ - 34.9296684262365, - -0.415033996126971 - ], - [ - 34.9339103697409, - -0.415926993119768 - ], - [ - 34.9367218016871, - -0.414869993979198 - ], - [ - 34.9400482174569, - -0.417192012124249 - ], - [ - 34.9476394649912, - -0.418792009368722 - ], - [ - 34.9588203430649, - -0.419268012259248 - ], - [ - 34.964580535695, - -0.414997011740574 - ], - [ - 34.9682312010619, - -0.416606009222934 - ], - [ - 34.9742088316808, - -0.414806008342675 - ], - [ - 34.9797897336172, - -0.416812002955495 - ], - [ - 34.9864196774759, - -0.416004985686217 - ], - [ - 34.9888610840591, - -0.41196200288656 - ], - [ - 35.0020790099141, - -0.408315003142937 - ], - [ - 35.0098304748598, - -0.393557995512931 - ], - [ - 35.0165290828926, - -0.400588989310594 - ], - [ - 35.020030975015, - -0.407977998203072 - ], - [ - 35.0201301573808, - -0.413237988913887 - ], - [ - 35.0087089539056, - -0.422464013032612 - ], - [ - 34.984081268035, - -0.435945004299202 - ], - [ - 34.9849891660104, - -0.438230991460368 - ], - [ - 34.9612197872309, - -0.448563993126587 - ], - [ - 34.9566688537146, - -0.453774988592296 - ], - [ - 34.9549102782375, - -0.452564001210013 - ], - [ - 34.9318504333034, - -0.470339000564194 - ], - [ - 34.913478851067, - -0.478635013276366 - ], - [ - 34.9130516050926, - -0.481783002938289 - ], - [ - 34.903900146467, - -0.484786987561828 - ], - [ - 34.9031181333965, - -0.482174992638721 - ], - [ - 34.8889503477, - -0.486799001910646 - ], - [ - 34.8890991210648, - -0.488941997632412 - ], - [ - 34.8768196104796, - -0.494208991844917 - ], - [ - 34.8734207150136, - -0.492906988010304 - ], - [ - 34.8568992612835, - -0.506024003234788 - ], - [ - 34.844890594425, - -0.513670027293837 - ], - [ - 34.8381004330379, - -0.516238987710852 - ], - [ - 34.8374481199198, - -0.518221974371861 - ], - [ - 34.8363800047042, - -0.516646981491657 - ], - [ - 34.8180885311651, - -0.519816994747283 - ], - [ - 34.8184700009565, - -0.523418009515079 - ], - [ - 34.8106613157707, - -0.526766002395344 - ], - [ - 34.8081092832507, - -0.524913012938803 - ], - [ - 34.791728973295, - -0.533563017878239 - ], - [ - 34.7921409604513, - -0.536637008237299 - ], - [ - 34.7841415404687, - -0.54204797741411 - ], - [ - 34.7818489074306, - -0.539662003610068 - ], - [ - 34.7724494933551, - -0.543299019671276 - ], - [ - 34.7598190305008, - -0.551342010749138 - ], - [ - 34.7590904232552, - -0.554727018199034 - ], - [ - 34.7576103208967, - -0.552761972309827 - ], - [ - 34.7526588440351, - -0.557133019010684 - ], - [ - 34.7405891414782, - -0.55939000844221 - ], - [ - 34.7276000973846, - -0.556751013019578 - ], - [ - 34.7248611448276, - -0.55805397054927 - ], - [ - 34.7239189148249, - -0.562395990012802 - ], - [ - 34.7205581663754, - -0.563807010858834 - ], - [ - 34.7084693905658, - -0.56334197550079 - ], - [ - 34.7025794979385, - -0.57107502236711 - ], - [ - 34.7027893065484, - -0.574231028654441 - ], - [ - 34.7006187437383, - -0.578173995100854 - ], - [ - 34.6939506531515, - -0.585781991773064 - ], - [ - 34.6956901546825, - -0.588460028169261 - ], - [ - 34.6820793151083, - -0.605611026354928 - ], - [ - 34.6772689817705, - -0.607928991417576 - ], - [ - 34.6687088010492, - -0.608528018135938 - ], - [ - 34.6579513547959, - -0.608295023463937 - ], - [ - 34.6559104916652, - -0.606912016991926 - ], - [ - 34.6537895201871, - -0.609516978259065 - ], - [ - 34.6391716004, - -0.634738028207663 - ], - [ - 34.6383705139055, - -0.637398004544013 - ], - [ - 34.6397781372785, - -0.638979017954337 - ], - [ - 34.6343193051887, - -0.665705025246125 - ], - [ - 34.6205406186134, - -0.658393025710317 - ], - [ - 34.6131210324846, - -0.656325995932842 - ], - [ - 34.5904312130281, - -0.654632985651808 - ], - [ - 34.581218719295, - -0.654644012660536 - ], - [ - 34.5782089233828, - -0.661484003434846 - ], - [ - 34.5757789609572, - -0.663455009692252 - ], - [ - 34.5589103696885, - -0.668734014040843 - ], - [ - 34.5568008421623, - -0.676910996394468 - ], - [ - 34.5484886165825, - -0.689158976147545 - ], - [ - 34.546669006078, - -0.691166996901663 - ], - [ - 34.5432510376571, - -0.691955983595508 - ], - [ - 34.5411796568859, - -0.694706976771434 - ], - [ - 34.5331611633244, - -0.710030973139712 - ], - [ - 34.5330390927199, - -0.738547981046071 - ], - [ - 34.5311889646065, - -0.74408400068167 - ], - [ - 34.5243301391048, - -0.751465976566904 - ], - [ - 34.523319244073, - -0.755219996094406 - ], - [ - 34.4829406738704, - -0.790274977619968 - ], - [ - 34.481559753165, - -0.802295029175752 - ], - [ - 34.4693298338285, - -0.825273990933598 - ], - [ - 34.4647102352386, - -0.837071001531768 - ], - [ - 34.4626693723591, - -0.851777970927684 - ], - [ - 34.463150024297, - -0.86771601449314 - ], - [ - 34.439430236495, - -0.847472012212406 - ], - [ - 34.4319496151321, - -0.84376698732516 - ], - [ - 34.427528381048, - -0.838150978357247 - ], - [ - 34.4123306274858, - -0.830712020621397 - ], - [ - 34.403789520136, - -0.824156999657325 - ], - [ - 34.3919181822002, - -0.820127010642739 - ], - [ - 34.3891296386327, - -0.817822992967247 - ], - [ - 34.385238647331, - -0.822346985545578 - ], - [ - 34.3878517148165, - -0.828027010274183 - ], - [ - 34.3914909362143, - -0.830556988990309 - ], - [ - 34.3912887569553, - -0.832229972125801 - ], - [ - 34.3883514403493, - -0.835080981457174 - ], - [ - 34.3813896176497, - -0.847465992037647 - ], - [ - 34.3720703123242, - -0.849992990548269 - ], - [ - 34.3659706116052, - -0.855206012842816 - ], - [ - 34.3547210691039, - -0.853002011902929 - ], - [ - 34.3498115536549, - -0.850507974769047 - ], - [ - 34.3469085691785, - -0.850807011304048 - ], - [ - 34.3483581542548, - -0.857419014179398 - ], - [ - 34.3378715512162, - -0.857151985548191 - ], - [ - 34.3353996275051, - -0.861966013846852 - ], - [ - 34.3323783872629, - -0.864336014174842 - ], - [ - 34.3219299313395, - -0.866934001400902 - ], - [ - 34.3207893371094, - -0.869368016840148 - ], - [ - 34.3120613097195, - -0.862017989402179 - ], - [ - 34.2967910765639, - -0.841571986879134 - ], - [ - 34.2831993100554, - -0.829490006164039 - ], - [ - 34.2800292969425, - -0.827283978678287 - ], - [ - 34.2706985473092, - -0.826963007798812 - ], - [ - 34.255760192745, - -0.823557973140846 - ], - [ - 34.2516403194844, - -0.819657981545666 - ], - [ - 34.2500114439606, - -0.813898980606246 - ], - [ - 34.2352981564387, - -0.796841025397369 - ], - [ - 34.2297096252092, - -0.785510003755067 - ], - [ - 34.2168884277723, - -0.774847984475694 - ], - [ - 34.2137908932448, - -0.773727000078476 - ], - [ - 34.2022590634571, - -0.756389021871654 - ], - [ - 34.1978187557433, - -0.755196988621768 - ], - [ - 34.1961212158267, - -0.755307019070076 - ], - [ - 34.1938896178212, - -0.763637006417354 - ], - [ - 34.1874885558975, - -0.769863009458919 - ], - [ - 34.1785888671669, - -0.768164992467638 - ], - [ - 34.1735115048629, - -0.775547981240602 - ], - [ - 34.1637001037083, - -0.777657985893913 - ], - [ - 34.146179199202, - -0.78438401217971 - ], - [ - 34.1350784301819, - -0.790953993738234 - ], - [ - 34.1248512266192, - -0.794811010392652 - ], - [ - 34.1202583310897, - -0.787449002496724 - ], - [ - 34.1031608581006, - -0.787481009961492 - ], - [ - 34.0980987548552, - -0.789156019846152 - ], - [ - 34.0904998777627, - -0.793381989008938 - ], - [ - 34.0821304321186, - -0.805714011166162 - ], - [ - 34.0756301878191, - -0.807959020223218 - ], - [ - 34.0731887813577, - -0.805734992162836 - ], - [ - 34.0713806149705, - -0.799772024263116 - ], - [ - 34.070911407347, - -0.795912028064797 - ], - [ - 34.0761718746124, - -0.788185000296319 - ], - [ - 34.0791702268929, - -0.786366999075553 - ], - [ - 34.0781211854283, - -0.77315700064691 - ], - [ - 34.0756797788177, - -0.770870983553066 - ], - [ - 34.0727310176464, - -0.771928012775884 - ], - [ - 34.0707702635395, - -0.774968982057692 - ], - [ - 34.0678100581323, - -0.776280999365201 - ], - [ - 34.0652008054693, - -0.775638997715759 - ], - [ - 34.0682983398867, - -0.769587993507218 - ], - [ - 34.0722885124991, - -0.765767992213887 - ], - [ - 34.0734596248886, - -0.75789797296986 - ], - [ - 34.0711402893946, - -0.742384017023116 - ], - [ - 34.0682716362661, - -0.738946974186464 - ], - [ - 34.0656585691013, - -0.731875002658081 - ], - [ - 34.0589599610651, - -0.72876399809079 - ], - [ - 34.0561790467475, - -0.7291809921991 - ], - [ - 34.0511894221542, - -0.732782006194536 - ], - [ - 34.0431709283489, - -0.734619022046682 - ], - [ - 34.0432586663373, - -0.739524007362461 - ], - [ - 34.0412483211126, - -0.742564022830797 - ], - [ - 34.0390701292639, - -0.743134022115547 - ], - [ - 34.0375518798052, - -0.741271973341088 - ], - [ - 34.0341415399172, - -0.742411017949055 - ], - [ - 34.0290107721199, - -0.740079999563629 - ], - [ - 34.0344581600094, - -0.738240004025029 - ], - [ - 34.0370407099569, - -0.735108971714719 - ], - [ - 34.0365409849073, - -0.729981005287054 - ], - [ - 34.0402297971026, - -0.730431974673244 - ], - [ - 34.0455207822751, - -0.72615200287414 - ], - [ - 34.0493698114945, - -0.72751700888947 - ], - [ - 34.0549507137005, - -0.722702980450744 - ], - [ - 34.057571411253, - -0.717764974292993 - ], - [ - 34.0569000236933, - -0.714806020454154 - ], - [ - 34.04867935143, - -0.710771978655859 - ], - [ - 34.0502204887992, - -0.701833010373213 - ], - [ - 34.0476188661232, - -0.696263015386548 - ], - [ - 34.0508689874669, - -0.688364028892766 - ], - [ - 34.0486183167265, - -0.685244023969903 - ], - [ - 34.0509605408343, - -0.682855010357811 - ], - [ - 34.0527191162991, - -0.682901025140196 - ], - [ - 34.05387115413, - -0.67493999052484 - ], - [ - 34.0474395745586, - -0.666799008970179 - ], - [ - 34.0528297425442, - -0.653914988114916 - ], - [ - 34.0501098632817, - -0.649474978372914 - ], - [ - 34.0444602961453, - -0.650641978499759 - ], - [ - 34.0443992613612, - -0.648643016910792 - ], - [ - 34.0485992431052, - -0.645349979282076 - ], - [ - 34.050479888771, - -0.645856023060513 - ], - [ - 34.0521888733874, - -0.63608497387884 - ], - [ - 34.0674095147023, - -0.634290993351509 - ], - [ - 34.0785484311953, - -0.62570297740823 - ], - [ - 34.088008880649, - -0.611697971865403 - ], - [ - 34.0916709895808, - -0.610395014213498 - ], - [ - 34.0937614438246, - -0.605754018462416 - ], - [ - 34.0918388365711, - -0.600144982953824 - ], - [ - 34.0879898064917, - -0.596826971219836 - ], - [ - 34.0745315544818, - -0.597922981413904 - ], - [ - 34.0739402768513, - -0.595815003636328 - ], - [ - 34.0774497980607, - -0.5891940001894 - ], - [ - 34.0760116570081, - -0.586480021509032 - ], - [ - 34.0684509274621, - -0.583840012666918 - ], - [ - 34.0651397701482, - -0.576095999009033 - ], - [ - 34.0606918334776, - -0.572252988952719 - ], - [ - 34.0639114377092, - -0.567799985398557 - ], - [ - 34.0726585385331, - -0.56365597311954 - ], - [ - 34.0796394349264, - -0.56975299151503 - ], - [ - 34.083549499657, - -0.571188987051289 - ], - [ - 34.0907783504521, - -0.570609986860741 - ], - [ - 34.1054115294824, - -0.559733987424752 - ], - [ - 34.107849120367, - -0.552416026847594 - ], - [ - 34.1064682007827, - -0.547809005070191 - ], - [ - 34.1071090695246, - -0.543847978198801 - ], - [ - 34.1143112175524, - -0.536817014212047 - ], - [ - 34.1167907714685, - -0.539178014319734 - ], - [ - 34.1197319029813, - -0.550728977437468 - ], - [ - 34.1235885614383, - -0.552347004589108 - ], - [ - 34.1289405823148, - -0.551360011161143 - ], - [ - 34.1317291253374, - -0.552417993454294 - ], - [ - 34.1394081113554, - -0.548582017566871 - ], - [ - 34.1423187250372, - -0.544880986087096 - ], - [ - 34.144321441609, - -0.545468986685797 - ], - [ - 34.1475105283877, - -0.543361008615654 - ], - [ - 34.152400970355, - -0.543421984053153 - ], - [ - 34.156341552752, - -0.545683026385006 - ], - [ - 34.1595382683595, - -0.540082991103644 - ], - [ - 34.1603202817098, - -0.515251994711433 - ], - [ - 34.1581497192617, - -0.504496992292562 - ], - [ - 34.1604881281574, - -0.499439001384675 - ], - [ - 34.1609497063407, - -0.489695996220955 - ], - [ - 34.163379669048, - -0.483860999881784 - ], - [ - 34.1732902527968, - -0.470301002784427 - ], - [ - 34.1869506834279, - -0.460844010098408 - ], - [ - 34.1926994320973, - -0.454766006007449 - ], - [ - 34.2032890318822, - -0.4207769933714 - ], - [ - 34.2061386102449, - -0.424387008706865 - ], - [ - 34.2087097168159, - -0.431968003499942 - ], - [ - 34.2182998652968, - -0.438279002810108 - ], - [ - 34.2254219053305, - -0.436731010872808 - ], - [ - 34.2365684502905, - -0.441911995742642 - ], - [ - 34.2524681086205, - -0.436401009552138 - ], - [ - 34.2529907221092, - -0.44451698703856 - ], - [ - 34.2594184869813, - -0.446025997923519 - ], - [ - 34.2629013060622, - -0.452048987886204 - ], - [ - 34.2688789366629, - -0.45137000094824 - ], - [ - 34.2703590387349, - -0.455511004157731 - ], - [ - 34.2741394036691, - -0.458741009483158 - ], - [ - 34.280330657895, - -0.456106007033767 - ], - [ - 34.2824592583154, - -0.45748299434674 - ], - [ - 34.2834892273559, - -0.459463000604624 - ], - [ - 34.2800407402638, - -0.460276991155232 - ], - [ - 34.2789001466036, - -0.463705003632667 - ], - [ - 34.283550261735, - -0.469538987016963 - ], - [ - 34.2834396362384, - -0.473872006067547 - ], - [ - 34.2976913450659, - -0.475064009430141 - ], - [ - 34.3135986329124, - -0.480857998356647 - ], - [ - 34.3105201715903, - -0.474254995573612 - ], - [ - 34.3003311153427, - -0.467819005557572 - ], - [ - 34.3049507136834, - -0.463645995390642 - ], - [ - 34.3085594172338, - -0.463880002625653 - ], - [ - 34.315311431233, - -0.459791988851047 - ], - [ - 34.317020415631, - -0.451388002025403 - ], - [ - 34.3193092341998, - -0.450635999371566 - ], - [ - 34.3215293879414, - -0.453613012918267 - ], - [ - 34.3230705258005, - -0.463761985581871 - ], - [ - 34.3267593379654, - -0.468165010196024 - ], - [ - 34.3342285152181, - -0.471148014610527 - ], - [ - 34.3357505794744, - -0.473010987297488 - ], - [ - 34.3354301451036, - -0.4886249906958 - ], - [ - 34.3418083185914, - -0.493146986526297 - ], - [ - 34.3470687859187, - -0.500118971602229 - ], - [ - 34.3529014582467, - -0.493514001737942 - ], - [ - 34.3521194456529, - -0.483509987777601 - ], - [ - 34.366508483601, - -0.479157001339806 - ], - [ - 34.3675308224165, - -0.476034999154943 - ], - [ - 34.3668594355767, - -0.464170009646362 - ], - [ - 34.3624382015901, - -0.459681987671771 - ], - [ - 34.3632583617092, - -0.456544012204122 - ], - [ - 34.3678703301685, - -0.453404993492671 - ], - [ - 34.3700981136261, - -0.449063987204993 - ], - [ - 34.3764991752945, - -0.456070005798174 - ], - [ - 34.3916893006763, - -0.458047985911118 - ], - [ - 34.401031494224, - -0.456772000208509 - ], - [ - 34.4029693602712, - -0.467581987417169 - ], - [ - 34.4088096617819, - -0.469994991905746 - ], - [ - 34.4044914238342, - -0.472618013842378 - ], - [ - 34.4040718075724, - -0.475937009620412 - ], - [ - 34.4056816096003, - -0.479736000529644 - ], - [ - 34.4168281556415, - -0.486526012354353 - ], - [ - 34.4182815549457, - -0.498194993204119 - ], - [ - 34.4238395691904, - -0.497153014227329 - ], - [ - 34.4309196471564, - -0.492648006171129 - ], - [ - 34.4334793087006, - -0.493081003646959 - ], - [ - 34.4351005552834, - -0.49733999363866 - ], - [ - 34.4360809325886, - -0.50118499989729 - ], - [ - 34.434089660598, - -0.510565996614679 - ], - [ - 34.424320220237, - -0.509644985527284 - ], - [ - 34.4156608576732, - -0.522058010291885 - ], - [ - 34.4154510495269, - -0.533038020703262 - ], - [ - 34.4202499384653, - -0.538254976419576 - ], - [ - 34.4232292167982, - -0.537786007495437 - ], - [ - 34.43722915608, - -0.530489981734109 - ], - [ - 34.4576988221713, - -0.52347499174317 - ], - [ - 34.4714088432659, - -0.515331984031223 - ], - [ - 34.4840393059932, - -0.510987997642402 - ], - [ - 34.486560821311, - -0.508825003996875 - ], - [ - 34.4892196652765, - -0.502313018317028 - ], - [ - 34.4898605347394, - -0.496461004262265 - ], - [ - 34.4885215756286, - -0.494433999326097 - ], - [ - 34.4913215631515, - -0.492246002432743 - ], - [ - 34.4953498838338, - -0.493075997261786 - ], - [ - 34.4951210022943, - -0.491421014145014 - ], - [ - 34.4967803952732, - -0.490705997263222 - ], - [ - 34.5017700192491, - -0.491519004300737 - ], - [ - 34.5097999569706, - -0.474269002690856 - ], - [ - 34.4976615900979, - -0.461302995572214 - ], - [ - 34.4897499083798, - -0.457078993406483 - ], - [ - 34.4789581294039, - -0.445430994406663 - ], - [ - 34.4715805049799, - -0.441020995268441 - ], - [ - 34.466499328408, - -0.432491988560971 - ], - [ - 34.4506492612813, - -0.415082007832338 - ], - [ - 34.4478988645194, - -0.403017997841618 - ], - [ - 34.4443511956121, - -0.398584991931709 - ], - [ - 34.4436111447052, - -0.39542201172729 - ], - [ - 34.4468612671222, - -0.391503989593715 - ], - [ - 34.4472808838166, - -0.385053992888977 - ], - [ - 34.4562110896362, - -0.367188007367484 - ], - [ - 34.4594993588715, - -0.354263008206138 - ], - [ - 34.4777793883361, - -0.346300005779269 - ], - [ - 34.4901199339982, - -0.34630900690649 - ], - [ - 34.4986915589147, - -0.339442015196204 - ], - [ - 34.5182800293198, - -0.333279013679969 - ], - [ - 34.5369796747646, - -0.328709006646547 - ], - [ - 34.5505218502734, - -0.328009992847082 - ], - [ - 34.5661201477624, - -0.330810994514755 - ], - [ - 34.5712890621413, - -0.336508989801025 - ], - [ - 34.5864715573582, - -0.3466799859601 - ], - [ - 34.5956306454186, - -0.348459988858955 - ], - [ - 34.6072006223563, - -0.348713010832994 - ], - [ - 34.6107215880723, - -0.343385011144085 - ], - [ - 34.6141014098723, - -0.341919005308692 - ], - [ - 34.6267089844781, - -0.340615987849872 - ], - [ - 34.6286888119123, - -0.341156005802005 - ], - [ - 34.6325187675872, - -0.350391001042175 - ], - [ - 34.6447486877118, - -0.352214009250388 - ], - [ - 34.6584892268869, - -0.356934011228453 - ], - [ - 34.6620483394615, - -0.356644988285097 - ], - [ - 34.6638908386978, - -0.354889989433075 - ], - [ - 34.6727981561785, - -0.357482999764506 - ], - [ - 34.6768302916616, - -0.356974989931195 - ], - [ - 34.6861915588006, - -0.352155000077462 - ], - [ - 34.6959991451256, - -0.354178995010005 - ], - [ - 34.6998481746875, - -0.353742986990006 - ], - [ - 34.7048492426555, - -0.350946993123794 - ], - [ - 34.7092781065951, - -0.354761988308264 - ], - [ - 34.7306289671357, - -0.356649011863722 - ], - [ - 34.7413291932561, - -0.352975011359628 - ], - [ - 34.7559013363737, - -0.352964014576499 - ], - [ - 34.7630996703498, - -0.336782008282447 - ], - [ - 34.763130187823, - -0.327603996050633 - ], - [ - 34.7587394710526, - -0.322838008741381 - ], - [ - 34.7507514951339, - -0.320596009467681 - ], - [ - 34.7471885678729, - -0.312557012604734 - ], - [ - 34.7473487852729, - -0.308162987982089 - ], - [ - 34.7454299924869, - -0.304329008317231 - ], - [ - 34.7516098015184, - -0.300310999323709 - ], - [ - 34.7524299622871, - -0.293628990558029 - ], - [ - 34.7575492852908, - -0.300999999306465 - ], - [ - 34.7566299433373, - -0.308676005154477 - ], - [ - 34.7582206719739, - -0.31252101087114 - ] - ] - ], - [ - [ - [ - 34.3994903560935, - -0.254267991244887 - ], - [ - 34.3970108032719, - -0.253908008974494 - ], - [ - 34.4013214111923, - -0.251022995196485 - ], - [ - 34.4017791743855, - -0.252530992768988 - ], - [ - 34.3994903560935, - -0.254267991244887 - ] - ] - ], - [ - [ - [ - 34.1367187496645, - -0.24409900678151 - ], - [ - 34.1348915094622, - -0.246243000392158 - ], - [ - 34.1344490048806, - -0.241639003507447 - ], - [ - 34.1362686151219, - -0.241992995808608 - ], - [ - 34.1367187496645, - -0.24409900678151 - ] - ] - ], - [ - [ - [ - 34.1424903865964, - -0.226278006942752 - ], - [ - 34.1440010069603, - -0.227889001630092 - ], - [ - 34.1479988097435, - -0.227724999554172 - ], - [ - 34.1474494933468, - -0.233108998002222 - ], - [ - 34.1487312313635, - -0.235117003691857 - ], - [ - 34.1431007386267, - -0.241015002285198 - ], - [ - 34.1433792107537, - -0.245220005740591 - ], - [ - 34.1419181823993, - -0.245383993358565 - ], - [ - 34.1405982970632, - -0.243122995248227 - ], - [ - 34.141139983766, - -0.23482699730886 - ], - [ - 34.1335601804736, - -0.231389999441659 - ], - [ - 34.1395797731, - -0.230031997591843 - ], - [ - 34.1402587885971, - -0.227228999215948 - ], - [ - 34.1424903865964, - -0.226278006942752 - ] - ] - ], - [ - [ - [ - 34.1140289307814, - -0.214855000728845 - ], - [ - 34.1142387386113, - -0.221377998995979 - ], - [ - 34.1170005791669, - -0.224905997762796 - ], - [ - 34.114749908376, - -0.225765005461102 - ], - [ - 34.1110191342269, - -0.223196998939716 - ], - [ - 34.1095314022483, - -0.220057994860915 - ], - [ - 34.1094894406354, - -0.21593299523273 - ], - [ - 34.1140289307814, - -0.214855000728845 - ] - ] - ], - [ - [ - [ - 34.4601287838158, - -0.215441004048315 - ], - [ - 34.4576797481487, - -0.217079997201956 - ], - [ - 34.4563102723182, - -0.215496004321451 - ], - [ - 34.4568099972457, - -0.213398993618589 - ], - [ - 34.4675712579274, - -0.2100050007577 - ], - [ - 34.4601287838158, - -0.215441004048315 - ] - ] - ], - [ - [ - [ - 34.518421173039, - -0.206698000877984 - ], - [ - 34.5200386045181, - -0.20788300095285 - ], - [ - 34.5236816405419, - -0.206997007583868 - ], - [ - 34.5239410394751, - -0.208343998064179 - ], - [ - 34.5185508722993, - -0.213635995966025 - ], - [ - 34.5161590576878, - -0.214614004630746 - ], - [ - 34.5155715941595, - -0.211816997059059 - ], - [ - 34.5119209287706, - -0.2104970066698 - ], - [ - 34.5082283014411, - -0.216396004245904 - ], - [ - 34.5004692075734, - -0.213556006777153 - ], - [ - 34.4984397885346, - -0.218287006036259 - ], - [ - 34.4964790342599, - -0.217318997325647 - ], - [ - 34.4956092831303, - -0.212118000349885 - ], - [ - 34.502929687432, - -0.200975001600127 - ], - [ - 34.509170532324, - -0.196326002751571 - ], - [ - 34.5174217224807, - -0.194516003818882 - ], - [ - 34.5191917419178, - -0.196198002003704 - ], - [ - 34.5162200921552, - -0.202952996325382 - ], - [ - 34.518421173039, - -0.206698000877984 - ] - ] - ], - [ - [ - [ - 34.0568504333938, - -0.192895994180268 - ], - [ - 34.055400848418, - -0.193039000564602 - ], - [ - 34.0549697873727, - -0.191231996185407 - ], - [ - 34.0574417114117, - -0.189449995967354 - ], - [ - 34.0568504333938, - -0.192895994180268 - ] - ] - ], - [ - [ - [ - 34.5378608703482, - -0.183923006587942 - ], - [ - 34.5444297783191, - -0.186717003994445 - ], - [ - 34.5436210627033, - -0.18843500334416 - ], - [ - 34.5395889277135, - -0.189955994372752 - ], - [ - 34.5374298094948, - -0.188463002717202 - ], - [ - 34.536289215183, - -0.186029002680658 - ], - [ - 34.5378608703482, - -0.183923006587942 - ] - ] - ], - [ - [ - [ - 34.5419311520741, - -0.177554995459931 - ], - [ - 34.5372085568702, - -0.177201002756337 - ], - [ - 34.5354614251704, - -0.175465003046841 - ], - [ - 34.5363998405701, - -0.1735209974197 - ], - [ - 34.5393600456777, - -0.172552004755814 - ], - [ - 34.5441207884934, - -0.174659997249441 - ], - [ - 34.5419311520741, - -0.177554995459931 - ] - ] - ], - [ - [ - [ - 34.5511016838423, - -0.182683006154941 - ], - [ - 34.5497207642557, - -0.183956995819815 - ], - [ - 34.5482292169827, - -0.18155199332737 - ], - [ - 34.5453987115703, - -0.172923997004285 - ], - [ - 34.5487403871132, - -0.171819999859916 - ], - [ - 34.5495491024781, - -0.173067003763431 - ], - [ - 34.5491409300549, - -0.176477000202428 - ], - [ - 34.5524291988164, - -0.179000005227063 - ], - [ - 34.5511016838423, - -0.182683006154941 - ] - ] - ], - [ - [ - [ - 34.6083106991855, - -0.160131007388101 - ], - [ - 34.6149406427355, - -0.159730002525364 - ], - [ - 34.608940123785, - -0.166026994763317 - ], - [ - 34.6068801877634, - -0.165728003413682 - ], - [ - 34.6035194389719, - -0.169064999321015 - ], - [ - 34.6028289792516, - -0.16241699502844 - ], - [ - 34.6003990167273, - -0.160761997604623 - ], - [ - 34.6007881163203, - -0.158963993230258 - ], - [ - 34.6083106991855, - -0.160131007388101 - ] - ] - ], - [ - [ - [ - 34.045108794793, - -0.135089994200292 - ], - [ - 34.043380737124, - -0.136049002725151 - ], - [ - 34.0413894648103, - -0.133091002945988 - ], - [ - 34.0467910759328, - -0.131053999547496 - ], - [ - 34.0495986939957, - -0.132810995049119 - ], - [ - 34.045108794793, - -0.135089994200292 - ] - ] - ], - [ - [ - [ - 34.0102806089366, - -0.128078997777673 - ], - [ - 34.0132789612483, - -0.128405005153257 - ], - [ - 34.0161590573009, - -0.126378998698566 - ], - [ - 34.0177001950656, - -0.130412996241417 - ], - [ - 34.0238304137994, - -0.133670002439227 - ], - [ - 34.0317001341465, - -0.128378004044975 - ], - [ - 34.0367202754878, - -0.126586005443822 - ], - [ - 34.0388107294861, - -0.127607003204381 - ], - [ - 34.0369911191701, - -0.130215004542825 - ], - [ - 34.0267601010053, - -0.135308995968923 - ], - [ - 34.0240211487638, - -0.141975000926457 - ], - [ - 34.0196914668423, - -0.140771999875237 - ], - [ - 34.0166702266165, - -0.143105999013996 - ], - [ - 34.0095405575111, - -0.141286999235816 - ], - [ - 34.00308990427, - -0.136683002556363 - ], - [ - 34.0004692078828, - -0.137262002154141 - ], - [ - 33.9991111751425, - -0.139939993995134 - ], - [ - 33.9956207269556, - -0.134287998315211 - ], - [ - 33.9916610713048, - -0.133346006817162 - ], - [ - 33.9866561887919, - -0.136118993785121 - ], - [ - 33.9867858880363, - -0.127811998463105 - ], - [ - 33.9913787837895, - -0.126678004990381 - ], - [ - 33.9958686828561, - -0.121123001650573 - ], - [ - 34.0060005185283, - -0.124252997846045 - ], - [ - 34.0102806089366, - -0.128078997777673 - ] - ] - ], - [ - [ - [ - 34.0999984741821, - -0.135629996806123 - ], - [ - 34.0973281854461, - -0.13674199632561 - ], - [ - 34.0929489136276, - -0.134572998173591 - ], - [ - 34.0923995964831, - -0.129841000467649 - ], - [ - 34.0875015256742, - -0.126992002052066 - ], - [ - 34.0911407468937, - -0.124214001415072 - ], - [ - 34.0930213922766, - -0.120668001512562 - ], - [ - 34.097450255924, - -0.122630000202121 - ], - [ - 34.1001281732362, - -0.127587005499911 - ], - [ - 34.0999984741821, - -0.135629996806123 - ] - ] - ] - ], - "type": "MultiPolygon" -} diff --git a/tests/backend/helpers/test_files/search_bbox_result.json b/tests/backend/helpers/test_files/search_bbox_result.json deleted file mode 100644 index 6e24b77383..0000000000 --- a/tests/backend/helpers/test_files/search_bbox_result.json +++ /dev/null @@ -1,2930 +0,0 @@ -{ - "features": [ - { - "geometry": { - "coordinates": [ - [ - [ - [ - 34.0893707268651, - -0.536513984601753 - ], - [ - 34.0837097165999, - -0.535368025180619 - ], - [ - 34.0824012756666, - -0.522611022751177 - ], - [ - 34.0835189818563, - -0.521118998858031 - ], - [ - 34.0859489436038, - -0.520412028506349 - ], - [ - 34.0887794491696, - -0.522691011775293 - ], - [ - 34.0938186647061, - -0.53062498601422 - ], - [ - 34.0922393800162, - -0.534533023725973 - ], - [ - 34.0893707268651, - -0.536513984601753 - ] - ] - ], - [ - [ - [ - 34.0964317315364, - -0.473861009201641 - ], - [ - 34.0903701783458, - -0.477777987607268 - ], - [ - 34.0894088743771, - -0.480300993106367 - ], - [ - 34.0840606689686, - -0.483107000623554 - ], - [ - 34.0832290642053, - -0.485565990460461 - ], - [ - 34.0777206420479, - -0.488045990479494 - ], - [ - 34.0756301877947, - -0.48638200784417 - ], - [ - 34.0795097347646, - -0.483161986306938 - ], - [ - 34.0812988279751, - -0.477977007985046 - ], - [ - 34.0807914731244, - -0.474739998452093 - ], - [ - 34.0869102477411, - -0.474655986304899 - ], - [ - 34.0935516357163, - -0.469579995295603 - ], - [ - 34.0973091126488, - -0.472213000194603 - ], - [ - 34.0964317315364, - -0.473861009201641 - ] - ] - ], - [ - [ - [ - 33.9454116820645, - -0.463559001916262 - ], - [ - 33.9395599365248, - -0.463423997083882 - ], - [ - 33.9403190610894, - -0.459735006029653 - ], - [ - 33.945270538096, - -0.461468995234408 - ], - [ - 33.9454116820645, - -0.463559001916262 - ] - ] - ], - [ - [ - [ - 33.955379485646, - -0.439756006467532 - ], - [ - 33.9534111015895, - -0.441495001379958 - ], - [ - 33.9522895809163, - -0.436744988255081 - ], - [ - 33.9562606813082, - -0.436861009014392 - ], - [ - 33.955379485646, - -0.439756006467532 - ] - ] - ], - [ - [ - [ - 34.0426788324311, - -0.441617995922242 - ], - [ - 34.0579109193315, - -0.454786986694148 - ], - [ - 34.0618209834879, - -0.466004014204983 - ], - [ - 34.0680007929779, - -0.475248992840064 - ], - [ - 34.0617904656388, - -0.483705997355769 - ], - [ - 34.0581703181331, - -0.486158997364131 - ], - [ - 34.0514488214515, - -0.48744401352108 - ], - [ - 34.0425796502369, - -0.492495000572894 - ], - [ - 34.0173301691978, - -0.49810600351348 - ], - [ - 33.9986495967674, - -0.499177009522071 - ], - [ - 33.9948692319355, - -0.495505989061121 - ], - [ - 33.9925994866689, - -0.489533991119976 - ], - [ - 33.9869308467725, - -0.485076010336786 - ], - [ - 33.9746284482024, - -0.482282013259886 - ], - [ - 33.9698791503386, - -0.478166014668594 - ], - [ - 33.9621696468858, - -0.480320007289396 - ], - [ - 33.959869384821, - -0.4795329870708 - ], - [ - 33.9616203304768, - -0.476166993823649 - ], - [ - 33.9591789242271, - -0.474866003235944 - ], - [ - 33.9557609557607, - -0.476051002849935 - ], - [ - 33.9492187498746, - -0.472840011421986 - ], - [ - 33.9448890686212, - -0.473563998816022 - ], - [ - 33.9456787106334, - -0.471403986181399 - ], - [ - 33.9551696776208, - -0.467249006781304 - ], - [ - 33.9556808469152, - -0.463665991905308 - ], - [ - 33.9537200921702, - -0.46022900949028 - ], - [ - 33.9546508785988, - -0.458112001448788 - ], - [ - 33.9502983093133, - -0.45217698870175 - ], - [ - 33.9588890074224, - -0.451597989312783 - ], - [ - 33.9601211547147, - -0.446150988264086 - ], - [ - 33.9670181272535, - -0.441754013979948 - ], - [ - 33.9700202941679, - -0.442532002917132 - ], - [ - 33.9751205437283, - -0.451126009810991 - ], - [ - 33.9788589470794, - -0.451622992748461 - ], - [ - 33.9860610955408, - -0.448074013291747 - ], - [ - 33.993858337062, - -0.441381007317147 - ], - [ - 33.9966392511954, - -0.441868007649385 - ], - [ - 34.0144500725981, - -0.436924994268909 - ], - [ - 34.0217704769388, - -0.426748991155693 - ], - [ - 34.0259399414171, - -0.424603999414845 - ], - [ - 34.0310096737433, - -0.425832003288011 - ], - [ - 34.0374183653533, - -0.436044991164478 - ], - [ - 34.0426788324311, - -0.441617995922242 - ] - ] - ], - [ - [ - [ - 34.2754516596662, - -0.401969999488986 - ], - [ - 34.2715797423912, - -0.401030987644172 - ], - [ - 34.2744903559876, - -0.400332987688116 - ], - [ - 34.2754516596662, - -0.401969999488986 - ] - ] - ], - [ - [ - [ - 34.2781715389658, - -0.381237000492777 - ], - [ - 34.2761688228689, - -0.382865995608465 - ], - [ - 34.2743492121104, - -0.381680995640269 - ], - [ - 34.2783508301769, - -0.379925996760625 - ], - [ - 34.2781715389658, - -0.381237000492777 - ] - ] - ], - [ - [ - [ - 34.2143287655156, - -0.395693004366286 - ], - [ - 34.2142906182445, - -0.405660004031797 - ], - [ - 34.2120018004263, - -0.411262006264649 - ], - [ - 34.204349517321, - -0.415695012092491 - ], - [ - 34.2029495239652, - -0.419582993174731 - ], - [ - 34.1996002197026, - -0.421483993822473 - ], - [ - 34.1877708433517, - -0.421559006677778 - ], - [ - 34.1794395440855, - -0.427493990015186 - ], - [ - 34.1756782531266, - -0.432850003983613 - ], - [ - 34.165271758304, - -0.438524991595183 - ], - [ - 34.1613998410085, - -0.444068014742153 - ], - [ - 34.1456985469489, - -0.429895997800304 - ], - [ - 34.1378898619166, - -0.428847998925689 - ], - [ - 34.136909484728, - -0.432891011472217 - ], - [ - 34.134300231592, - -0.433950991107749 - ], - [ - 34.1333389278868, - -0.437920988165511 - ], - [ - 34.1311607357573, - -0.438971996391205 - ], - [ - 34.1283798215211, - -0.437976003020405 - ], - [ - 34.1264610287079, - -0.433889001655333 - ], - [ - 34.1176605223996, - -0.427177011840722 - ], - [ - 34.1166992184456, - -0.422545999545391 - ], - [ - 34.1192703248463, - -0.411130011306752 - ], - [ - 34.1313514703541, - -0.415950000813917 - ], - [ - 34.1384315486929, - -0.412773013288862 - ], - [ - 34.1467704774138, - -0.40178999330445 - ], - [ - 34.1569900507969, - -0.399167001650706 - ], - [ - 34.1601295471043, - -0.394279987164107 - ], - [ - 34.160659789502, - -0.3878209894747 - ], - [ - 34.1580696104563, - -0.384274989420933 - ], - [ - 34.1581687924587, - -0.37681299451016 - ], - [ - 34.1667213436273, - -0.378331006020431 - ], - [ - 34.1715507505398, - -0.380257010370037 - ], - [ - 34.1740303033703, - -0.384128988337088 - ], - [ - 34.1842308041676, - -0.388287991819939 - ], - [ - 34.1941604611658, - -0.39040300288116 - ], - [ - 34.1969604491079, - -0.398047000614702 - ], - [ - 34.1994781489183, - -0.400009989819131 - ], - [ - 34.2037086481541, - -0.397612005717622 - ], - [ - 34.2089195247285, - -0.390827000545428 - ], - [ - 34.2076797480607, - -0.387234986055222 - ], - [ - 34.2105598449187, - -0.376715004601617 - ], - [ - 34.2103385922229, - -0.36443001056801 - ], - [ - 34.2191810601522, - -0.36015901038489 - ], - [ - 34.2211189268839, - -0.354171991759936 - ], - [ - 34.2236709588762, - -0.356640011645463 - ], - [ - 34.2278518671235, - -0.357789009821622 - ], - [ - 34.2276496881491, - -0.359632999264451 - ], - [ - 34.2177581787943, - -0.380856007496425 - ], - [ - 34.2143287655156, - -0.395693004366286 - ] - ] - ], - [ - [ - [ - 34.2518005369727, - -0.355477988879186 - ], - [ - 34.2492980956664, - -0.356083989530268 - ], - [ - 34.2500114441154, - -0.352638006396314 - ], - [ - 34.2546806336564, - -0.351561993650388 - ], - [ - 34.2518005369727, - -0.355477988879186 - ] - ] - ], - [ - [ - [ - 34.2636184686575, - -0.346350014132461 - ], - [ - 34.2605094907419, - -0.351669013877824 - ], - [ - 34.2555198663605, - -0.3504230086018 - ], - [ - 34.2567787165965, - -0.34663200411094 - ], - [ - 34.2636184686575, - -0.346350014132461 - ] - ] - ], - [ - [ - [ - 34.7582206719739, - -0.31252101087114 - ], - [ - 34.7583808897327, - -0.31669801508201 - ], - [ - 34.7630691524777, - -0.315403998108347 - ], - [ - 34.7676086423743, - -0.314383000305777 - ], - [ - 34.7735099793049, - -0.320845991625677 - ], - [ - 34.7772483822775, - -0.320601999839968 - ], - [ - 34.7792587277671, - -0.322156995636362 - ], - [ - 34.7803993223333, - -0.325801014855357 - ], - [ - 34.7830009457264, - -0.324263006498863 - ], - [ - 34.7873992919402, - -0.332888990771244 - ], - [ - 34.7825813293905, - -0.334661990704691 - ], - [ - 34.7857704159269, - -0.346581995440046 - ], - [ - 34.7891006467147, - -0.345259994365036 - ], - [ - 34.7910690307328, - -0.345991999112342 - ], - [ - 34.7900810241752, - -0.348499000422978 - ], - [ - 34.7909393311158, - -0.350154012735152 - ], - [ - 34.7962989806356, - -0.351779014158352 - ], - [ - 34.7963409423905, - -0.353913993008774 - ], - [ - 34.799270629772, - -0.35537099866552 - ], - [ - 34.8058509826727, - -0.356851994946864 - ], - [ - 34.8103294373075, - -0.35494199412092 - ], - [ - 34.811920165839, - -0.361380994683084 - ], - [ - 34.8153495787066, - -0.367538988586328 - ], - [ - 34.822010040142, - -0.375279009500654 - ], - [ - 34.8231887818121, - -0.388823986316104 - ], - [ - 34.8349685665297, - -0.390866011737571 - ], - [ - 34.8395805358943, - -0.39437299970995 - ], - [ - 34.8547096251044, - -0.393049001816052 - ], - [ - 34.8581581113839, - -0.393871993094201 - ], - [ - 34.8591995235789, - -0.396349012801326 - ], - [ - 34.8614196776106, - -0.397379994409412 - ], - [ - 34.864028930384, - -0.397596001585913 - ], - [ - 34.8667411800724, - -0.39584100258521 - ], - [ - 34.8800506592569, - -0.398986011932382 - ], - [ - 34.882549285679, - -0.39778301152296 - ], - [ - 34.8892898558066, - -0.404336005388276 - ], - [ - 34.8909606930819, - -0.403268993253184 - ], - [ - 34.8915901180646, - -0.399742990849798 - ], - [ - 34.8960609436001, - -0.398467004451745 - ], - [ - 34.9023208614997, - -0.393781006539643 - ], - [ - 34.9141883848943, - -0.389872014812091 - ], - [ - 34.9129295347827, - -0.397105991776296 - ], - [ - 34.9135284423775, - -0.406210988992565 - ], - [ - 34.9157791136356, - -0.408109992857834 - ], - [ - 34.9262809752293, - -0.406415999172597 - ], - [ - 34.9296684262365, - -0.415033996126971 - ], - [ - 34.9339103697409, - -0.415926993119768 - ], - [ - 34.9367218016871, - -0.414869993979198 - ], - [ - 34.9400482174569, - -0.417192012124249 - ], - [ - 34.9476394649912, - -0.418792009368722 - ], - [ - 34.9588203430649, - -0.419268012259248 - ], - [ - 34.964580535695, - -0.414997011740574 - ], - [ - 34.9682312010619, - -0.416606009222934 - ], - [ - 34.9742088316808, - -0.414806008342675 - ], - [ - 34.9797897336172, - -0.416812002955495 - ], - [ - 34.9864196774759, - -0.416004985686217 - ], - [ - 34.9888610840591, - -0.41196200288656 - ], - [ - 35.0020790099141, - -0.408315003142937 - ], - [ - 35.0098304748598, - -0.393557995512931 - ], - [ - 35.0165290828926, - -0.400588989310594 - ], - [ - 35.020030975015, - -0.407977998203072 - ], - [ - 35.0201301573808, - -0.413237988913887 - ], - [ - 35.0087089539056, - -0.422464013032612 - ], - [ - 34.984081268035, - -0.435945004299202 - ], - [ - 34.9849891660104, - -0.438230991460368 - ], - [ - 34.9612197872309, - -0.448563993126587 - ], - [ - 34.9566688537146, - -0.453774988592296 - ], - [ - 34.9549102782375, - -0.452564001210013 - ], - [ - 34.9318504333034, - -0.470339000564194 - ], - [ - 34.913478851067, - -0.478635013276366 - ], - [ - 34.9130516050926, - -0.481783002938289 - ], - [ - 34.903900146467, - -0.484786987561828 - ], - [ - 34.9031181333965, - -0.482174992638721 - ], - [ - 34.8889503477, - -0.486799001910646 - ], - [ - 34.8890991210648, - -0.488941997632412 - ], - [ - 34.8768196104796, - -0.494208991844917 - ], - [ - 34.8734207150136, - -0.492906988010304 - ], - [ - 34.8568992612835, - -0.506024003234788 - ], - [ - 34.844890594425, - -0.513670027293837 - ], - [ - 34.8381004330379, - -0.516238987710852 - ], - [ - 34.8374481199198, - -0.518221974371861 - ], - [ - 34.8363800047042, - -0.516646981491657 - ], - [ - 34.8180885311651, - -0.519816994747283 - ], - [ - 34.8184700009565, - -0.523418009515079 - ], - [ - 34.8106613157707, - -0.526766002395344 - ], - [ - 34.8081092832507, - -0.524913012938803 - ], - [ - 34.791728973295, - -0.533563017878239 - ], - [ - 34.7921409604513, - -0.536637008237299 - ], - [ - 34.7841415404687, - -0.54204797741411 - ], - [ - 34.7818489074306, - -0.539662003610068 - ], - [ - 34.7724494933551, - -0.543299019671276 - ], - [ - 34.7598190305008, - -0.551342010749138 - ], - [ - 34.7590904232552, - -0.554727018199034 - ], - [ - 34.7576103208967, - -0.552761972309827 - ], - [ - 34.7526588440351, - -0.557133019010684 - ], - [ - 34.7405891414782, - -0.55939000844221 - ], - [ - 34.7276000973846, - -0.556751013019578 - ], - [ - 34.7248611448276, - -0.55805397054927 - ], - [ - 34.7239189148249, - -0.562395990012802 - ], - [ - 34.7205581663754, - -0.563807010858834 - ], - [ - 34.7084693905658, - -0.56334197550079 - ], - [ - 34.7025794979385, - -0.57107502236711 - ], - [ - 34.7027893065484, - -0.574231028654441 - ], - [ - 34.7006187437383, - -0.578173995100854 - ], - [ - 34.6939506531515, - -0.585781991773064 - ], - [ - 34.6956901546825, - -0.588460028169261 - ], - [ - 34.6820793151083, - -0.605611026354928 - ], - [ - 34.6772689817705, - -0.607928991417576 - ], - [ - 34.6687088010492, - -0.608528018135938 - ], - [ - 34.6579513547959, - -0.608295023463937 - ], - [ - 34.6559104916652, - -0.606912016991926 - ], - [ - 34.6537895201871, - -0.609516978259065 - ], - [ - 34.6391716004, - -0.634738028207663 - ], - [ - 34.6383705139055, - -0.637398004544013 - ], - [ - 34.6397781372785, - -0.638979017954337 - ], - [ - 34.6343193051887, - -0.665705025246125 - ], - [ - 34.6205406186134, - -0.658393025710317 - ], - [ - 34.6131210324846, - -0.656325995932842 - ], - [ - 34.5904312130281, - -0.654632985651808 - ], - [ - 34.581218719295, - -0.654644012660536 - ], - [ - 34.5782089233828, - -0.661484003434846 - ], - [ - 34.5757789609572, - -0.663455009692252 - ], - [ - 34.5589103696885, - -0.668734014040843 - ], - [ - 34.5568008421623, - -0.676910996394468 - ], - [ - 34.5484886165825, - -0.689158976147545 - ], - [ - 34.546669006078, - -0.691166996901663 - ], - [ - 34.5432510376571, - -0.691955983595508 - ], - [ - 34.5411796568859, - -0.694706976771434 - ], - [ - 34.5331611633244, - -0.710030973139712 - ], - [ - 34.5330390927199, - -0.738547981046071 - ], - [ - 34.5311889646065, - -0.74408400068167 - ], - [ - 34.5243301391048, - -0.751465976566904 - ], - [ - 34.523319244073, - -0.755219996094406 - ], - [ - 34.4829406738704, - -0.790274977619968 - ], - [ - 34.481559753165, - -0.802295029175752 - ], - [ - 34.4693298338285, - -0.825273990933598 - ], - [ - 34.4647102352386, - -0.837071001531768 - ], - [ - 34.4626693723591, - -0.851777970927684 - ], - [ - 34.463150024297, - -0.86771601449314 - ], - [ - 34.439430236495, - -0.847472012212406 - ], - [ - 34.4319496151321, - -0.84376698732516 - ], - [ - 34.427528381048, - -0.838150978357247 - ], - [ - 34.4123306274858, - -0.830712020621397 - ], - [ - 34.403789520136, - -0.824156999657325 - ], - [ - 34.3919181822002, - -0.820127010642739 - ], - [ - 34.3891296386327, - -0.817822992967247 - ], - [ - 34.385238647331, - -0.822346985545578 - ], - [ - 34.3878517148165, - -0.828027010274183 - ], - [ - 34.3914909362143, - -0.830556988990309 - ], - [ - 34.3912887569553, - -0.832229972125801 - ], - [ - 34.3883514403493, - -0.835080981457174 - ], - [ - 34.3813896176497, - -0.847465992037647 - ], - [ - 34.3720703123242, - -0.849992990548269 - ], - [ - 34.3659706116052, - -0.855206012842816 - ], - [ - 34.3547210691039, - -0.853002011902929 - ], - [ - 34.3498115536549, - -0.850507974769047 - ], - [ - 34.3469085691785, - -0.850807011304048 - ], - [ - 34.3483581542548, - -0.857419014179398 - ], - [ - 34.3378715512162, - -0.857151985548191 - ], - [ - 34.3353996275051, - -0.861966013846852 - ], - [ - 34.3323783872629, - -0.864336014174842 - ], - [ - 34.3219299313395, - -0.866934001400902 - ], - [ - 34.3207893371094, - -0.869368016840148 - ], - [ - 34.3120613097195, - -0.862017989402179 - ], - [ - 34.2967910765639, - -0.841571986879134 - ], - [ - 34.2831993100554, - -0.829490006164039 - ], - [ - 34.2800292969425, - -0.827283978678287 - ], - [ - 34.2706985473092, - -0.826963007798812 - ], - [ - 34.255760192745, - -0.823557973140846 - ], - [ - 34.2516403194844, - -0.819657981545666 - ], - [ - 34.2500114439606, - -0.813898980606246 - ], - [ - 34.2352981564387, - -0.796841025397369 - ], - [ - 34.2297096252092, - -0.785510003755067 - ], - [ - 34.2168884277723, - -0.774847984475694 - ], - [ - 34.2137908932448, - -0.773727000078476 - ], - [ - 34.2022590634571, - -0.756389021871654 - ], - [ - 34.1978187557433, - -0.755196988621768 - ], - [ - 34.1961212158267, - -0.755307019070076 - ], - [ - 34.1938896178212, - -0.763637006417354 - ], - [ - 34.1874885558975, - -0.769863009458919 - ], - [ - 34.1785888671669, - -0.768164992467638 - ], - [ - 34.1735115048629, - -0.775547981240602 - ], - [ - 34.1637001037083, - -0.777657985893913 - ], - [ - 34.146179199202, - -0.78438401217971 - ], - [ - 34.1350784301819, - -0.790953993738234 - ], - [ - 34.1248512266192, - -0.794811010392652 - ], - [ - 34.1202583310897, - -0.787449002496724 - ], - [ - 34.1031608581006, - -0.787481009961492 - ], - [ - 34.0980987548552, - -0.789156019846152 - ], - [ - 34.0904998777627, - -0.793381989008938 - ], - [ - 34.0821304321186, - -0.805714011166162 - ], - [ - 34.0756301878191, - -0.807959020223218 - ], - [ - 34.0731887813577, - -0.805734992162836 - ], - [ - 34.0713806149705, - -0.799772024263116 - ], - [ - 34.070911407347, - -0.795912028064797 - ], - [ - 34.0761718746124, - -0.788185000296319 - ], - [ - 34.0791702268929, - -0.786366999075553 - ], - [ - 34.0781211854283, - -0.77315700064691 - ], - [ - 34.0756797788177, - -0.770870983553066 - ], - [ - 34.0727310176464, - -0.771928012775884 - ], - [ - 34.0707702635395, - -0.774968982057692 - ], - [ - 34.0678100581323, - -0.776280999365201 - ], - [ - 34.0652008054693, - -0.775638997715759 - ], - [ - 34.0682983398867, - -0.769587993507218 - ], - [ - 34.0722885124991, - -0.765767992213887 - ], - [ - 34.0734596248886, - -0.75789797296986 - ], - [ - 34.0711402893946, - -0.742384017023116 - ], - [ - 34.0682716362661, - -0.738946974186464 - ], - [ - 34.0656585691013, - -0.731875002658081 - ], - [ - 34.0589599610651, - -0.72876399809079 - ], - [ - 34.0561790467475, - -0.7291809921991 - ], - [ - 34.0511894221542, - -0.732782006194536 - ], - [ - 34.0431709283489, - -0.734619022046682 - ], - [ - 34.0432586663373, - -0.739524007362461 - ], - [ - 34.0412483211126, - -0.742564022830797 - ], - [ - 34.0390701292639, - -0.743134022115547 - ], - [ - 34.0375518798052, - -0.741271973341088 - ], - [ - 34.0341415399172, - -0.742411017949055 - ], - [ - 34.0290107721199, - -0.740079999563629 - ], - [ - 34.0344581600094, - -0.738240004025029 - ], - [ - 34.0370407099569, - -0.735108971714719 - ], - [ - 34.0365409849073, - -0.729981005287054 - ], - [ - 34.0402297971026, - -0.730431974673244 - ], - [ - 34.0455207822751, - -0.72615200287414 - ], - [ - 34.0493698114945, - -0.72751700888947 - ], - [ - 34.0549507137005, - -0.722702980450744 - ], - [ - 34.057571411253, - -0.717764974292993 - ], - [ - 34.0569000236933, - -0.714806020454154 - ], - [ - 34.04867935143, - -0.710771978655859 - ], - [ - 34.0502204887992, - -0.701833010373213 - ], - [ - 34.0476188661232, - -0.696263015386548 - ], - [ - 34.0508689874669, - -0.688364028892766 - ], - [ - 34.0486183167265, - -0.685244023969903 - ], - [ - 34.0509605408343, - -0.682855010357811 - ], - [ - 34.0527191162991, - -0.682901025140196 - ], - [ - 34.05387115413, - -0.67493999052484 - ], - [ - 34.0474395745586, - -0.666799008970179 - ], - [ - 34.0528297425442, - -0.653914988114916 - ], - [ - 34.0501098632817, - -0.649474978372914 - ], - [ - 34.0444602961453, - -0.650641978499759 - ], - [ - 34.0443992613612, - -0.648643016910792 - ], - [ - 34.0485992431052, - -0.645349979282076 - ], - [ - 34.050479888771, - -0.645856023060513 - ], - [ - 34.0521888733874, - -0.63608497387884 - ], - [ - 34.0674095147023, - -0.634290993351509 - ], - [ - 34.0785484311953, - -0.62570297740823 - ], - [ - 34.088008880649, - -0.611697971865403 - ], - [ - 34.0916709895808, - -0.610395014213498 - ], - [ - 34.0937614438246, - -0.605754018462416 - ], - [ - 34.0918388365711, - -0.600144982953824 - ], - [ - 34.0879898064917, - -0.596826971219836 - ], - [ - 34.0745315544818, - -0.597922981413904 - ], - [ - 34.0739402768513, - -0.595815003636328 - ], - [ - 34.0774497980607, - -0.5891940001894 - ], - [ - 34.0760116570081, - -0.586480021509032 - ], - [ - 34.0684509274621, - -0.583840012666918 - ], - [ - 34.0651397701482, - -0.576095999009033 - ], - [ - 34.0606918334776, - -0.572252988952719 - ], - [ - 34.0639114377092, - -0.567799985398557 - ], - [ - 34.0726585385331, - -0.56365597311954 - ], - [ - 34.0796394349264, - -0.56975299151503 - ], - [ - 34.083549499657, - -0.571188987051289 - ], - [ - 34.0907783504521, - -0.570609986860741 - ], - [ - 34.1054115294824, - -0.559733987424752 - ], - [ - 34.107849120367, - -0.552416026847594 - ], - [ - 34.1064682007827, - -0.547809005070191 - ], - [ - 34.1071090695246, - -0.543847978198801 - ], - [ - 34.1143112175524, - -0.536817014212047 - ], - [ - 34.1167907714685, - -0.539178014319734 - ], - [ - 34.1197319029813, - -0.550728977437468 - ], - [ - 34.1235885614383, - -0.552347004589108 - ], - [ - 34.1289405823148, - -0.551360011161143 - ], - [ - 34.1317291253374, - -0.552417993454294 - ], - [ - 34.1394081113554, - -0.548582017566871 - ], - [ - 34.1423187250372, - -0.544880986087096 - ], - [ - 34.144321441609, - -0.545468986685797 - ], - [ - 34.1475105283877, - -0.543361008615654 - ], - [ - 34.152400970355, - -0.543421984053153 - ], - [ - 34.156341552752, - -0.545683026385006 - ], - [ - 34.1595382683595, - -0.540082991103644 - ], - [ - 34.1603202817098, - -0.515251994711433 - ], - [ - 34.1581497192617, - -0.504496992292562 - ], - [ - 34.1604881281574, - -0.499439001384675 - ], - [ - 34.1609497063407, - -0.489695996220955 - ], - [ - 34.163379669048, - -0.483860999881784 - ], - [ - 34.1732902527968, - -0.470301002784427 - ], - [ - 34.1869506834279, - -0.460844010098408 - ], - [ - 34.1926994320973, - -0.454766006007449 - ], - [ - 34.2032890318822, - -0.4207769933714 - ], - [ - 34.2061386102449, - -0.424387008706865 - ], - [ - 34.2087097168159, - -0.431968003499942 - ], - [ - 34.2182998652968, - -0.438279002810108 - ], - [ - 34.2254219053305, - -0.436731010872808 - ], - [ - 34.2365684502905, - -0.441911995742642 - ], - [ - 34.2524681086205, - -0.436401009552138 - ], - [ - 34.2529907221092, - -0.44451698703856 - ], - [ - 34.2594184869813, - -0.446025997923519 - ], - [ - 34.2629013060622, - -0.452048987886204 - ], - [ - 34.2688789366629, - -0.45137000094824 - ], - [ - 34.2703590387349, - -0.455511004157731 - ], - [ - 34.2741394036691, - -0.458741009483158 - ], - [ - 34.280330657895, - -0.456106007033767 - ], - [ - 34.2824592583154, - -0.45748299434674 - ], - [ - 34.2834892273559, - -0.459463000604624 - ], - [ - 34.2800407402638, - -0.460276991155232 - ], - [ - 34.2789001466036, - -0.463705003632667 - ], - [ - 34.283550261735, - -0.469538987016963 - ], - [ - 34.2834396362384, - -0.473872006067547 - ], - [ - 34.2976913450659, - -0.475064009430141 - ], - [ - 34.3135986329124, - -0.480857998356647 - ], - [ - 34.3105201715903, - -0.474254995573612 - ], - [ - 34.3003311153427, - -0.467819005557572 - ], - [ - 34.3049507136834, - -0.463645995390642 - ], - [ - 34.3085594172338, - -0.463880002625653 - ], - [ - 34.315311431233, - -0.459791988851047 - ], - [ - 34.317020415631, - -0.451388002025403 - ], - [ - 34.3193092341998, - -0.450635999371566 - ], - [ - 34.3215293879414, - -0.453613012918267 - ], - [ - 34.3230705258005, - -0.463761985581871 - ], - [ - 34.3267593379654, - -0.468165010196024 - ], - [ - 34.3342285152181, - -0.471148014610527 - ], - [ - 34.3357505794744, - -0.473010987297488 - ], - [ - 34.3354301451036, - -0.4886249906958 - ], - [ - 34.3418083185914, - -0.493146986526297 - ], - [ - 34.3470687859187, - -0.500118971602229 - ], - [ - 34.3529014582467, - -0.493514001737942 - ], - [ - 34.3521194456529, - -0.483509987777601 - ], - [ - 34.366508483601, - -0.479157001339806 - ], - [ - 34.3675308224165, - -0.476034999154943 - ], - [ - 34.3668594355767, - -0.464170009646362 - ], - [ - 34.3624382015901, - -0.459681987671771 - ], - [ - 34.3632583617092, - -0.456544012204122 - ], - [ - 34.3678703301685, - -0.453404993492671 - ], - [ - 34.3700981136261, - -0.449063987204993 - ], - [ - 34.3764991752945, - -0.456070005798174 - ], - [ - 34.3916893006763, - -0.458047985911118 - ], - [ - 34.401031494224, - -0.456772000208509 - ], - [ - 34.4029693602712, - -0.467581987417169 - ], - [ - 34.4088096617819, - -0.469994991905746 - ], - [ - 34.4044914238342, - -0.472618013842378 - ], - [ - 34.4040718075724, - -0.475937009620412 - ], - [ - 34.4056816096003, - -0.479736000529644 - ], - [ - 34.4168281556415, - -0.486526012354353 - ], - [ - 34.4182815549457, - -0.498194993204119 - ], - [ - 34.4238395691904, - -0.497153014227329 - ], - [ - 34.4309196471564, - -0.492648006171129 - ], - [ - 34.4334793087006, - -0.493081003646959 - ], - [ - 34.4351005552834, - -0.49733999363866 - ], - [ - 34.4360809325886, - -0.50118499989729 - ], - [ - 34.434089660598, - -0.510565996614679 - ], - [ - 34.424320220237, - -0.509644985527284 - ], - [ - 34.4156608576732, - -0.522058010291885 - ], - [ - 34.4154510495269, - -0.533038020703262 - ], - [ - 34.4202499384653, - -0.538254976419576 - ], - [ - 34.4232292167982, - -0.537786007495437 - ], - [ - 34.43722915608, - -0.530489981734109 - ], - [ - 34.4576988221713, - -0.52347499174317 - ], - [ - 34.4714088432659, - -0.515331984031223 - ], - [ - 34.4840393059932, - -0.510987997642402 - ], - [ - 34.486560821311, - -0.508825003996875 - ], - [ - 34.4892196652765, - -0.502313018317028 - ], - [ - 34.4898605347394, - -0.496461004262265 - ], - [ - 34.4885215756286, - -0.494433999326097 - ], - [ - 34.4913215631515, - -0.492246002432743 - ], - [ - 34.4953498838338, - -0.493075997261786 - ], - [ - 34.4951210022943, - -0.491421014145014 - ], - [ - 34.4967803952732, - -0.490705997263222 - ], - [ - 34.5017700192491, - -0.491519004300737 - ], - [ - 34.5097999569706, - -0.474269002690856 - ], - [ - 34.4976615900979, - -0.461302995572214 - ], - [ - 34.4897499083798, - -0.457078993406483 - ], - [ - 34.4789581294039, - -0.445430994406663 - ], - [ - 34.4715805049799, - -0.441020995268441 - ], - [ - 34.466499328408, - -0.432491988560971 - ], - [ - 34.4506492612813, - -0.415082007832338 - ], - [ - 34.4478988645194, - -0.403017997841618 - ], - [ - 34.4443511956121, - -0.398584991931709 - ], - [ - 34.4436111447052, - -0.39542201172729 - ], - [ - 34.4468612671222, - -0.391503989593715 - ], - [ - 34.4472808838166, - -0.385053992888977 - ], - [ - 34.4562110896362, - -0.367188007367484 - ], - [ - 34.4594993588715, - -0.354263008206138 - ], - [ - 34.4777793883361, - -0.346300005779269 - ], - [ - 34.4901199339982, - -0.34630900690649 - ], - [ - 34.4986915589147, - -0.339442015196204 - ], - [ - 34.5182800293198, - -0.333279013679969 - ], - [ - 34.5369796747646, - -0.328709006646547 - ], - [ - 34.5505218502734, - -0.328009992847082 - ], - [ - 34.5661201477624, - -0.330810994514755 - ], - [ - 34.5712890621413, - -0.336508989801025 - ], - [ - 34.5864715573582, - -0.3466799859601 - ], - [ - 34.5956306454186, - -0.348459988858955 - ], - [ - 34.6072006223563, - -0.348713010832994 - ], - [ - 34.6107215880723, - -0.343385011144085 - ], - [ - 34.6141014098723, - -0.341919005308692 - ], - [ - 34.6267089844781, - -0.340615987849872 - ], - [ - 34.6286888119123, - -0.341156005802005 - ], - [ - 34.6325187675872, - -0.350391001042175 - ], - [ - 34.6447486877118, - -0.352214009250388 - ], - [ - 34.6584892268869, - -0.356934011228453 - ], - [ - 34.6620483394615, - -0.356644988285097 - ], - [ - 34.6638908386978, - -0.354889989433075 - ], - [ - 34.6727981561785, - -0.357482999764506 - ], - [ - 34.6768302916616, - -0.356974989931195 - ], - [ - 34.6861915588006, - -0.352155000077462 - ], - [ - 34.6959991451256, - -0.354178995010005 - ], - [ - 34.6998481746875, - -0.353742986990006 - ], - [ - 34.7048492426555, - -0.350946993123794 - ], - [ - 34.7092781065951, - -0.354761988308264 - ], - [ - 34.7306289671357, - -0.356649011863722 - ], - [ - 34.7413291932561, - -0.352975011359628 - ], - [ - 34.7559013363737, - -0.352964014576499 - ], - [ - 34.7630996703498, - -0.336782008282447 - ], - [ - 34.763130187823, - -0.327603996050633 - ], - [ - 34.7587394710526, - -0.322838008741381 - ], - [ - 34.7507514951339, - -0.320596009467681 - ], - [ - 34.7471885678729, - -0.312557012604734 - ], - [ - 34.7473487852729, - -0.308162987982089 - ], - [ - 34.7454299924869, - -0.304329008317231 - ], - [ - 34.7516098015184, - -0.300310999323709 - ], - [ - 34.7524299622871, - -0.293628990558029 - ], - [ - 34.7575492852908, - -0.300999999306465 - ], - [ - 34.7566299433373, - -0.308676005154477 - ], - [ - 34.7582206719739, - -0.31252101087114 - ] - ] - ], - [ - [ - [ - 34.3994903560935, - -0.254267991244887 - ], - [ - 34.3970108032719, - -0.253908008974494 - ], - [ - 34.4013214111923, - -0.251022995196485 - ], - [ - 34.4017791743855, - -0.252530992768988 - ], - [ - 34.3994903560935, - -0.254267991244887 - ] - ] - ], - [ - [ - [ - 34.1367187496645, - -0.24409900678151 - ], - [ - 34.1348915094622, - -0.246243000392158 - ], - [ - 34.1344490048806, - -0.241639003507447 - ], - [ - 34.1362686151219, - -0.241992995808608 - ], - [ - 34.1367187496645, - -0.24409900678151 - ] - ] - ], - [ - [ - [ - 34.1424903865964, - -0.226278006942752 - ], - [ - 34.1440010069603, - -0.227889001630092 - ], - [ - 34.1479988097435, - -0.227724999554172 - ], - [ - 34.1474494933468, - -0.233108998002222 - ], - [ - 34.1487312313635, - -0.235117003691857 - ], - [ - 34.1431007386267, - -0.241015002285198 - ], - [ - 34.1433792107537, - -0.245220005740591 - ], - [ - 34.1419181823993, - -0.245383993358565 - ], - [ - 34.1405982970632, - -0.243122995248227 - ], - [ - 34.141139983766, - -0.23482699730886 - ], - [ - 34.1335601804736, - -0.231389999441659 - ], - [ - 34.1395797731, - -0.230031997591843 - ], - [ - 34.1402587885971, - -0.227228999215948 - ], - [ - 34.1424903865964, - -0.226278006942752 - ] - ] - ], - [ - [ - [ - 34.1140289307814, - -0.214855000728845 - ], - [ - 34.1142387386113, - -0.221377998995979 - ], - [ - 34.1170005791669, - -0.224905997762796 - ], - [ - 34.114749908376, - -0.225765005461102 - ], - [ - 34.1110191342269, - -0.223196998939716 - ], - [ - 34.1095314022483, - -0.220057994860915 - ], - [ - 34.1094894406354, - -0.21593299523273 - ], - [ - 34.1140289307814, - -0.214855000728845 - ] - ] - ], - [ - [ - [ - 34.4601287838158, - -0.215441004048315 - ], - [ - 34.4576797481487, - -0.217079997201956 - ], - [ - 34.4563102723182, - -0.215496004321451 - ], - [ - 34.4568099972457, - -0.213398993618589 - ], - [ - 34.4675712579274, - -0.2100050007577 - ], - [ - 34.4601287838158, - -0.215441004048315 - ] - ] - ], - [ - [ - [ - 34.518421173039, - -0.206698000877984 - ], - [ - 34.5200386045181, - -0.20788300095285 - ], - [ - 34.5236816405419, - -0.206997007583868 - ], - [ - 34.5239410394751, - -0.208343998064179 - ], - [ - 34.5185508722993, - -0.213635995966025 - ], - [ - 34.5161590576878, - -0.214614004630746 - ], - [ - 34.5155715941595, - -0.211816997059059 - ], - [ - 34.5119209287706, - -0.2104970066698 - ], - [ - 34.5082283014411, - -0.216396004245904 - ], - [ - 34.5004692075734, - -0.213556006777153 - ], - [ - 34.4984397885346, - -0.218287006036259 - ], - [ - 34.4964790342599, - -0.217318997325647 - ], - [ - 34.4956092831303, - -0.212118000349885 - ], - [ - 34.502929687432, - -0.200975001600127 - ], - [ - 34.509170532324, - -0.196326002751571 - ], - [ - 34.5174217224807, - -0.194516003818882 - ], - [ - 34.5191917419178, - -0.196198002003704 - ], - [ - 34.5162200921552, - -0.202952996325382 - ], - [ - 34.518421173039, - -0.206698000877984 - ] - ] - ], - [ - [ - [ - 34.0568504333938, - -0.192895994180268 - ], - [ - 34.055400848418, - -0.193039000564602 - ], - [ - 34.0549697873727, - -0.191231996185407 - ], - [ - 34.0574417114117, - -0.189449995967354 - ], - [ - 34.0568504333938, - -0.192895994180268 - ] - ] - ], - [ - [ - [ - 34.5378608703482, - -0.183923006587942 - ], - [ - 34.5444297783191, - -0.186717003994445 - ], - [ - 34.5436210627033, - -0.18843500334416 - ], - [ - 34.5395889277135, - -0.189955994372752 - ], - [ - 34.5374298094948, - -0.188463002717202 - ], - [ - 34.536289215183, - -0.186029002680658 - ], - [ - 34.5378608703482, - -0.183923006587942 - ] - ] - ], - [ - [ - [ - 34.5419311520741, - -0.177554995459931 - ], - [ - 34.5372085568702, - -0.177201002756337 - ], - [ - 34.5354614251704, - -0.175465003046841 - ], - [ - 34.5363998405701, - -0.1735209974197 - ], - [ - 34.5393600456777, - -0.172552004755814 - ], - [ - 34.5441207884934, - -0.174659997249441 - ], - [ - 34.5419311520741, - -0.177554995459931 - ] - ] - ], - [ - [ - [ - 34.5511016838423, - -0.182683006154941 - ], - [ - 34.5497207642557, - -0.183956995819815 - ], - [ - 34.5482292169827, - -0.18155199332737 - ], - [ - 34.5453987115703, - -0.172923997004285 - ], - [ - 34.5487403871132, - -0.171819999859916 - ], - [ - 34.5495491024781, - -0.173067003763431 - ], - [ - 34.5491409300549, - -0.176477000202428 - ], - [ - 34.5524291988164, - -0.179000005227063 - ], - [ - 34.5511016838423, - -0.182683006154941 - ] - ] - ], - [ - [ - [ - 34.6083106991855, - -0.160131007388101 - ], - [ - 34.6149406427355, - -0.159730002525364 - ], - [ - 34.608940123785, - -0.166026994763317 - ], - [ - 34.6068801877634, - -0.165728003413682 - ], - [ - 34.6035194389719, - -0.169064999321015 - ], - [ - 34.6028289792516, - -0.16241699502844 - ], - [ - 34.6003990167273, - -0.160761997604623 - ], - [ - 34.6007881163203, - -0.158963993230258 - ], - [ - 34.6083106991855, - -0.160131007388101 - ] - ] - ], - [ - [ - [ - 34.045108794793, - -0.135089994200292 - ], - [ - 34.043380737124, - -0.136049002725151 - ], - [ - 34.0413894648103, - -0.133091002945988 - ], - [ - 34.0467910759328, - -0.131053999547496 - ], - [ - 34.0495986939957, - -0.132810995049119 - ], - [ - 34.045108794793, - -0.135089994200292 - ] - ] - ], - [ - [ - [ - 34.0102806089366, - -0.128078997777673 - ], - [ - 34.0132789612483, - -0.128405005153257 - ], - [ - 34.0161590573009, - -0.126378998698566 - ], - [ - 34.0177001950656, - -0.130412996241417 - ], - [ - 34.0238304137994, - -0.133670002439227 - ], - [ - 34.0317001341465, - -0.128378004044975 - ], - [ - 34.0367202754878, - -0.126586005443822 - ], - [ - 34.0388107294861, - -0.127607003204381 - ], - [ - 34.0369911191701, - -0.130215004542825 - ], - [ - 34.0267601010053, - -0.135308995968923 - ], - [ - 34.0240211487638, - -0.141975000926457 - ], - [ - 34.0196914668423, - -0.140771999875237 - ], - [ - 34.0166702266165, - -0.143105999013996 - ], - [ - 34.0095405575111, - -0.141286999235816 - ], - [ - 34.00308990427, - -0.136683002556363 - ], - [ - 34.0004692078828, - -0.137262002154141 - ], - [ - 33.9991111751425, - -0.139939993995134 - ], - [ - 33.9956207269556, - -0.134287998315211 - ], - [ - 33.9916610713048, - -0.133346006817162 - ], - [ - 33.9866561887919, - -0.136118993785121 - ], - [ - 33.9867858880363, - -0.127811998463105 - ], - [ - 33.9913787837895, - -0.126678004990381 - ], - [ - 33.9958686828561, - -0.121123001650573 - ], - [ - 34.0060005185283, - -0.124252997846045 - ], - [ - 34.0102806089366, - -0.128078997777673 - ] - ] - ], - [ - [ - [ - 34.0999984741821, - -0.135629996806123 - ], - [ - 34.0973281854461, - -0.13674199632561 - ], - [ - 34.0929489136276, - -0.134572998173591 - ], - [ - 34.0923995964831, - -0.129841000467649 - ], - [ - 34.0875015256742, - -0.126992002052066 - ], - [ - 34.0911407468937, - -0.124214001415072 - ], - [ - 34.0930213922766, - -0.120668001512562 - ], - [ - 34.097450255924, - -0.122630000202121 - ], - [ - 34.1001281732362, - -0.127587005499911 - ], - [ - 34.0999984741821, - -0.135629996806123 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "projectId": 2274, - "projectName": "PEPFAR Kenya: Homa Bay", - "projectStatus": "ARCHIVED" - }, - "type": "Feature" - } - ], - "type": "FeatureCollection" -} diff --git a/tests/backend/helpers/test_files/self_intersecting_aoi.json b/tests/backend/helpers/test_files/self_intersecting_aoi.json deleted file mode 100644 index 0f2081fb55..0000000000 --- a/tests/backend/helpers/test_files/self_intersecting_aoi.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "areaOfInterest": { - "type": "FeatureCollection", - "features": [ - { - "id": "c80597d7c1465de9a626abb42c8ce3e9", - "type": "Feature", - "properties": {}, - "geometry": { - "coordinates": [ - [ - [ - 83.90260192613022, - 28.00981666293339 - ], - [ - 83.9463765105823, - 28.011172694480237 - ], - [ - 83.93869675892398, - 27.96980605451823 - ], - [ - 83.97709551721579, - 27.990152287354846 - ], - [ - 83.90260192613022, - 28.00981666293339 - ] - ] - ], - "type": "Polygon" - } - } - ] - }, - "clipToAoi": true, - "grid": { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "properties": { - "x": 1501, - "y": 1189, - "zoom": 11, - "isSquare": true - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 83.84765624665238, - 27.83907609375386 - ], - [ - 84.02343749664536, - 27.83907609375386 - ], - [ - 84.02343749664536, - 27.994401410017474 - ], - [ - 83.84765624665238, - 27.994401410017474 - ], - [ - 83.84765624665238, - 27.83907609375386 - ] - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "x": 1501, - "y": 1190, - "zoom": 11, - "isSquare": true - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 83.84765624665238, - 27.994401410017474 - ], - [ - 84.02343749664536, - 27.994401410017474 - ], - [ - 84.02343749664536, - 28.14950321051117 - ], - [ - 83.84765624665238, - 28.14950321051117 - ], - [ - 83.84765624665238, - 27.994401410017474 - ] - ] - ] - ] - } - } - ] - } - } diff --git a/tests/backend/helpers/test_files/split_task.json b/tests/backend/helpers/test_files/split_task.json deleted file mode 100644 index 047218e27a..0000000000 --- a/tests/backend/helpers/test_files/split_task.json +++ /dev/null @@ -1,154 +0,0 @@ -[ - { - "geometry": { - "coordinates": [ - [ - [ - [ - -2.4609375, - 54.876606647 - ], - [ - -2.373046875, - 54.876606647 - ], - [ - -2.373046875, - 54.927141858 - ], - [ - -2.4609375, - 54.927141858 - ], - [ - -2.4609375, - 54.876606647 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 2020, - "y": 2798, - "zoom": 12 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - -2.4609375, - 54.927141858 - ], - [ - -2.373046875, - 54.927141858 - ], - [ - -2.373046875, - 54.977613664 - ], - [ - -2.4609375, - 54.977613664 - ], - [ - -2.4609375, - 54.927141858 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 2020, - "y": 2799, - "zoom": 12 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - -2.373046875, - 54.876606647 - ], - [ - -2.28515625, - 54.876606647 - ], - [ - -2.28515625, - 54.927141858 - ], - [ - -2.373046875, - 54.927141858 - ], - [ - -2.373046875, - 54.876606647 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 2021, - "y": 2798, - "zoom": 12 - }, - "type": "Feature" - }, - { - "geometry": { - "coordinates": [ - [ - [ - [ - -2.373046875, - 54.927141858 - ], - [ - -2.28515625, - 54.927141858 - ], - [ - -2.28515625, - 54.977613664 - ], - [ - -2.373046875, - 54.977613664 - ], - [ - -2.373046875, - 54.927141858 - ] - ] - ] - ], - "type": "MultiPolygon" - }, - "properties": { - "isSquare": true, - "x": 2021, - "y": 2799, - "zoom": 12 - }, - "type": "Feature" - } -] diff --git a/tests/backend/helpers/test_files/splittable_task.json b/tests/backend/helpers/test_files/splittable_task.json deleted file mode 100644 index 2c488286c6..0000000000 --- a/tests/backend/helpers/test_files/splittable_task.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "type":"Feature", - "geometry":{ - "type":"MultiPolygon", - "coordinates":[ - [ - [ - [ - -2.4609374995591673, - 54.8766066473153 - ], - [ - -2.4609374995591673, - 54.97761366390182 - ], - [ - -2.2851562495906625, - 54.97761366390182 - ], - [ - -2.2851562495906625, - 54.8766066473153 - ], - [ - -2.4609374995591673, - 54.8766066473153 - ] - ] - ] - ] - }, - "properties":{ - "x":1010, - "y":1399, - "zoom":11, - "isSquare":true - } -} diff --git a/tests/backend/helpers/test_files/tasks_from_aoi_features.json b/tests/backend/helpers/test_files/tasks_from_aoi_features.json deleted file mode 100644 index 4adfd3db51..0000000000 --- a/tests/backend/helpers/test_files/tasks_from_aoi_features.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "features":[ - { - "geometry":{ - "coordinates":[ - [ - [ - [ - 1275275.3796814454, - 2828783.0982895694 - ], - [ - 1275200.6907704484, - 2828781.542271093 - ], - [ - 1275016.6455451597, - 2828781.542271093 - ], - [ - 1275275.3796814454, - 2828783.0982895694 - ] - ] - ] - ], - "type":"MultiPolygon" - }, - "properties":{ - "isSquare": false, - "x": null, - "y": null, - "zoom": null, - "extra_properties":{ - "foo":"bar" - } - }, - "type":"Feature" - } - ], - "type":"FeatureCollection" -} diff --git a/tests/backend/helpers/test_files/test_aoi.json b/tests/backend/helpers/test_files/test_aoi.json deleted file mode 100644 index 588623da3c..0000000000 --- a/tests/backend/helpers/test_files/test_aoi.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "features": [ - { - "type": "Feature", - "geometry": { - "coordinates": [ - [ - [ - [-4.0237, 56.0904], - [-3.9111, 56.1715], - [-3.8122, 56.098], - [-4.0237, 56.0904] - ] - ] - ], - "properties": { - "x": 2402, - "y": 1736, - "zoom": 12 - }, - "type": "MultiPolygon" - } - } - ], - "type": "FeatureCollection" -} diff --git a/tests/backend/helpers/test_files/test_arbitrary.json b/tests/backend/helpers/test_files/test_arbitrary.json deleted file mode 100644 index 5a71106fe4..0000000000 --- a/tests/backend/helpers/test_files/test_arbitrary.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "areaOfInterest": { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 1275275.3796814454, - 2828783.0982895694 - ], - [ - 1275200.6907704484, - 2828781.542271093 - ], - [ - 1275016.6455451597, - 2828781.542271093 - ], - [ - 1275275.3796814454, - 2828783.0982895694 - ] - ] - ] - }, - "properties": { - "foo": "bar" - } - } - ] - } -} diff --git a/tests/backend/helpers/test_files/test_grid.json b/tests/backend/helpers/test_files/test_grid.json deleted file mode 100644 index a178ab6298..0000000000 --- a/tests/backend/helpers/test_files/test_grid.json +++ /dev/null @@ -1,3576 +0,0 @@ -{ - "areaOfInterest": { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 1275275.3796814454, - 2828783.0982895694 - ], - [ - 1275200.6907704484, - 2828781.542271093 - ], - [ - 1275016.6455451597, - 2828781.542271093 - ], - [ - 1275087.6232993654, - 2829087.2903841813 - ], - [ - 1275275.3796814454, - 2829087.2903841813 - ], - [ - 1275275.3796814454, - 2828783.0982895694 - ] - ] - ] - }, - "properties": { - "x": 69706, - "y": 74788, - "zoom": 17 - } - }, - { - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 1275581.1277945302, - 2829306.621247852 - ], - [ - 1275827.894530152, - 2829303.193932765 - ], - [ - 1275872.7042755112, - 2829087.2903841813 - ], - [ - 1275581.1277945302, - 2829087.2903841813 - ], - [ - 1275581.1277945302, - 2829306.621247852 - ] - ] - ] - }, - "properties": { - "x": 69708, - "y": 74789, - "zoom": 17 - } - }, - { - "type": "Feature", - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [ - 1275886.8759076186, - 2829019.008869979 - ], - [ - 1275932.9954440442, - 2828796.798620377 - ], - [ - 1275886.8759076186, - 2828795.8377961316 - ], - [ - 1275886.8759076186, - 2829019.008869979 - ] - ] - ] - }, - "properties": { - "x": 69709, - "y": 74788, - "zoom": 17 - } - } - ] - }, - "clipToAoi": false, - "grid": { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2828781.5422710925 - ], - [ - 1274969.631568361, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828781.5422710925 - ], - [ - 1274969.631568361, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278824, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2828857.9792993665 - ], - [ - 1274969.631568361, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1274969.631568361, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278824, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2828934.4163276367 - ], - [ - 1274969.631568361, - 2829010.853355907 - ], - [ - 1275046.0685966313, - 2829010.853355907 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1274969.631568361, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278824, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2829010.853355907 - ], - [ - 1274969.631568361, - 2829087.290384181 - ], - [ - 1275046.0685966313, - 2829087.290384181 - ], - [ - 1275046.0685966313, - 2829010.853355907 - ], - [ - 1274969.631568361, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278824, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2829087.290384181 - ], - [ - 1274969.631568361, - 2829163.727412451 - ], - [ - 1275046.0685966313, - 2829163.727412451 - ], - [ - 1275046.0685966313, - 2829087.290384181 - ], - [ - 1274969.631568361, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278824, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2829163.727412451 - ], - [ - 1274969.631568361, - 2829240.1644407213 - ], - [ - 1275046.0685966313, - 2829240.1644407213 - ], - [ - 1275046.0685966313, - 2829163.727412451 - ], - [ - 1274969.631568361, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278824, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1274969.631568361, - 2829240.1644407213 - ], - [ - 1274969.631568361, - 2829316.601468995 - ], - [ - 1275046.0685966313, - 2829316.601468995 - ], - [ - 1275046.0685966313, - 2829240.1644407213 - ], - [ - 1274969.631568361, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278824, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828781.5422710925 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828781.5422710925 - ], - [ - 1275046.0685966313, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278825, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275046.0685966313, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278825, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275046.0685966313, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278825, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2829010.853355907 - ], - [ - 1275046.0685966313, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275046.0685966313, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278825, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2829087.290384181 - ], - [ - 1275046.0685966313, - 2829163.727412451 - ], - [ - 1275122.5056249015, - 2829163.727412451 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275046.0685966313, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278825, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2829163.727412451 - ], - [ - 1275046.0685966313, - 2829240.1644407213 - ], - [ - 1275122.5056249015, - 2829240.1644407213 - ], - [ - 1275122.5056249015, - 2829163.727412451 - ], - [ - 1275046.0685966313, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278825, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275046.0685966313, - 2829240.1644407213 - ], - [ - 1275046.0685966313, - 2829316.601468995 - ], - [ - 1275122.5056249015, - 2829316.601468995 - ], - [ - 1275122.5056249015, - 2829240.1644407213 - ], - [ - 1275046.0685966313, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278825, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828781.5422710925 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828781.5422710925 - ], - [ - 1275122.5056249015, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278826, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275122.5056249015, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278826, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275122.5056249015, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278826, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275122.5056249015, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278826, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829163.727412451 - ], - [ - 1275198.9426531754, - 2829163.727412451 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275122.5056249015, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278826, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2829163.727412451 - ], - [ - 1275122.5056249015, - 2829240.1644407213 - ], - [ - 1275198.9426531754, - 2829240.1644407213 - ], - [ - 1275198.9426531754, - 2829163.727412451 - ], - [ - 1275122.5056249015, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278826, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275122.5056249015, - 2829240.1644407213 - ], - [ - 1275122.5056249015, - 2829316.601468995 - ], - [ - 1275198.9426531754, - 2829316.601468995 - ], - [ - 1275198.9426531754, - 2829240.1644407213 - ], - [ - 1275122.5056249015, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278826, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828781.5422710925 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275275.3796814457, - 2828857.9792993665 - ], - [ - 1275275.3796814457, - 2828781.5422710925 - ], - [ - 1275198.9426531754, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278827, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275275.3796814457, - 2828934.4163276367 - ], - [ - 1275275.3796814457, - 2828857.9792993665 - ], - [ - 1275198.9426531754, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278827, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275275.3796814457, - 2829010.853355907 - ], - [ - 1275275.3796814457, - 2828934.4163276367 - ], - [ - 1275198.9426531754, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278827, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275275.3796814457, - 2829087.290384181 - ], - [ - 1275275.3796814457, - 2829010.853355907 - ], - [ - 1275198.9426531754, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278827, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829163.727412451 - ], - [ - 1275275.3796814457, - 2829163.727412451 - ], - [ - 1275275.3796814457, - 2829087.290384181 - ], - [ - 1275198.9426531754, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278827, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2829163.727412451 - ], - [ - 1275198.9426531754, - 2829240.1644407213 - ], - [ - 1275275.3796814457, - 2829240.1644407213 - ], - [ - 1275275.3796814457, - 2829163.727412451 - ], - [ - 1275198.9426531754, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278827, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275198.9426531754, - 2829240.1644407213 - ], - [ - 1275198.9426531754, - 2829316.601468995 - ], - [ - 1275275.3796814457, - 2829316.601468995 - ], - [ - 1275275.3796814457, - 2829240.1644407213 - ], - [ - 1275198.9426531754, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278827, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275275.3796814457, - 2828781.5422710925 - ], - [ - 1275275.3796814457, - 2828857.9792993665 - ], - [ - 1275351.8167097159, - 2828857.9792993665 - ], - [ - 1275351.8167097159, - 2828781.5422710925 - ], - [ - 1275275.3796814457, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278828, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275275.3796814457, - 2828857.9792993665 - ], - [ - 1275275.3796814457, - 2828934.4163276367 - ], - [ - 1275351.8167097159, - 2828934.4163276367 - ], - [ - 1275351.8167097159, - 2828857.9792993665 - ], - [ - 1275275.3796814457, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278828, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275275.3796814457, - 2828934.4163276367 - ], - [ - 1275275.3796814457, - 2829010.853355907 - ], - [ - 1275351.8167097159, - 2829010.853355907 - ], - [ - 1275351.8167097159, - 2828934.4163276367 - ], - [ - 1275275.3796814457, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278828, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275275.3796814457, - 2829010.853355907 - ], - [ - 1275275.3796814457, - 2829087.290384181 - ], - [ - 1275351.8167097159, - 2829087.290384181 - ], - [ - 1275351.8167097159, - 2829010.853355907 - ], - [ - 1275275.3796814457, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278828, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275275.3796814457, - 2829087.290384181 - ], - [ - 1275275.3796814457, - 2829163.727412451 - ], - [ - 1275351.8167097159, - 2829163.727412451 - ], - [ - 1275351.8167097159, - 2829087.290384181 - ], - [ - 1275275.3796814457, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278828, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275275.3796814457, - 2829163.727412451 - ], - [ - 1275275.3796814457, - 2829240.1644407213 - ], - [ - 1275351.8167097159, - 2829240.1644407213 - ], - [ - 1275351.8167097159, - 2829163.727412451 - ], - [ - 1275275.3796814457, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278828, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275275.3796814457, - 2829240.1644407213 - ], - [ - 1275275.3796814457, - 2829316.601468995 - ], - [ - 1275351.8167097159, - 2829316.601468995 - ], - [ - 1275351.8167097159, - 2829240.1644407213 - ], - [ - 1275275.3796814457, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278828, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275351.8167097159, - 2828781.5422710925 - ], - [ - 1275351.8167097159, - 2828857.9792993665 - ], - [ - 1275428.2537379898, - 2828857.9792993665 - ], - [ - 1275428.2537379898, - 2828781.5422710925 - ], - [ - 1275351.8167097159, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278829, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275351.8167097159, - 2828857.9792993665 - ], - [ - 1275351.8167097159, - 2828934.4163276367 - ], - [ - 1275428.2537379898, - 2828934.4163276367 - ], - [ - 1275428.2537379898, - 2828857.9792993665 - ], - [ - 1275351.8167097159, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278829, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275351.8167097159, - 2828934.4163276367 - ], - [ - 1275351.8167097159, - 2829010.853355907 - ], - [ - 1275428.2537379898, - 2829010.853355907 - ], - [ - 1275428.2537379898, - 2828934.4163276367 - ], - [ - 1275351.8167097159, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278829, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275351.8167097159, - 2829010.853355907 - ], - [ - 1275351.8167097159, - 2829087.290384181 - ], - [ - 1275428.2537379898, - 2829087.290384181 - ], - [ - 1275428.2537379898, - 2829010.853355907 - ], - [ - 1275351.8167097159, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278829, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275351.8167097159, - 2829087.290384181 - ], - [ - 1275351.8167097159, - 2829163.727412451 - ], - [ - 1275428.2537379898, - 2829163.727412451 - ], - [ - 1275428.2537379898, - 2829087.290384181 - ], - [ - 1275351.8167097159, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278829, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275351.8167097159, - 2829163.727412451 - ], - [ - 1275351.8167097159, - 2829240.1644407213 - ], - [ - 1275428.2537379898, - 2829240.1644407213 - ], - [ - 1275428.2537379898, - 2829163.727412451 - ], - [ - 1275351.8167097159, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278829, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275351.8167097159, - 2829240.1644407213 - ], - [ - 1275351.8167097159, - 2829316.601468995 - ], - [ - 1275428.2537379898, - 2829316.601468995 - ], - [ - 1275428.2537379898, - 2829240.1644407213 - ], - [ - 1275351.8167097159, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278829, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275428.2537379898, - 2828781.5422710925 - ], - [ - 1275428.2537379898, - 2828857.9792993665 - ], - [ - 1275504.69076626, - 2828857.9792993665 - ], - [ - 1275504.69076626, - 2828781.5422710925 - ], - [ - 1275428.2537379898, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278830, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275428.2537379898, - 2828857.9792993665 - ], - [ - 1275428.2537379898, - 2828934.4163276367 - ], - [ - 1275504.69076626, - 2828934.4163276367 - ], - [ - 1275504.69076626, - 2828857.9792993665 - ], - [ - 1275428.2537379898, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278830, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275428.2537379898, - 2828934.4163276367 - ], - [ - 1275428.2537379898, - 2829010.853355907 - ], - [ - 1275504.69076626, - 2829010.853355907 - ], - [ - 1275504.69076626, - 2828934.4163276367 - ], - [ - 1275428.2537379898, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278830, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275428.2537379898, - 2829010.853355907 - ], - [ - 1275428.2537379898, - 2829087.290384181 - ], - [ - 1275504.69076626, - 2829087.290384181 - ], - [ - 1275504.69076626, - 2829010.853355907 - ], - [ - 1275428.2537379898, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278830, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275428.2537379898, - 2829087.290384181 - ], - [ - 1275428.2537379898, - 2829163.727412451 - ], - [ - 1275504.69076626, - 2829163.727412451 - ], - [ - 1275504.69076626, - 2829087.290384181 - ], - [ - 1275428.2537379898, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278830, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275428.2537379898, - 2829163.727412451 - ], - [ - 1275428.2537379898, - 2829240.1644407213 - ], - [ - 1275504.69076626, - 2829240.1644407213 - ], - [ - 1275504.69076626, - 2829163.727412451 - ], - [ - 1275428.2537379898, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278830, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275428.2537379898, - 2829240.1644407213 - ], - [ - 1275428.2537379898, - 2829316.601468995 - ], - [ - 1275504.69076626, - 2829316.601468995 - ], - [ - 1275504.69076626, - 2829240.1644407213 - ], - [ - 1275428.2537379898, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278830, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2828781.5422710925 - ], - [ - 1275504.69076626, - 2828857.9792993665 - ], - [ - 1275581.1277945302, - 2828857.9792993665 - ], - [ - 1275581.1277945302, - 2828781.5422710925 - ], - [ - 1275504.69076626, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278831, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2828857.9792993665 - ], - [ - 1275504.69076626, - 2828934.4163276367 - ], - [ - 1275581.1277945302, - 2828934.4163276367 - ], - [ - 1275581.1277945302, - 2828857.9792993665 - ], - [ - 1275504.69076626, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278831, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2828934.4163276367 - ], - [ - 1275504.69076626, - 2829010.853355907 - ], - [ - 1275581.1277945302, - 2829010.853355907 - ], - [ - 1275581.1277945302, - 2828934.4163276367 - ], - [ - 1275504.69076626, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278831, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2829010.853355907 - ], - [ - 1275504.69076626, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829010.853355907 - ], - [ - 1275504.69076626, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278831, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2829087.290384181 - ], - [ - 1275504.69076626, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275504.69076626, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278831, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2829163.727412451 - ], - [ - 1275504.69076626, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275504.69076626, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278831, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275504.69076626, - 2829240.1644407213 - ], - [ - 1275504.69076626, - 2829316.601468995 - ], - [ - 1275581.1277945302, - 2829316.601468995 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275504.69076626, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278831, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2828781.5422710925 - ], - [ - 1275581.1277945302, - 2828857.9792993665 - ], - [ - 1275657.5648228042, - 2828857.9792993665 - ], - [ - 1275657.5648228042, - 2828781.5422710925 - ], - [ - 1275581.1277945302, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278832, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2828857.9792993665 - ], - [ - 1275581.1277945302, - 2828934.4163276367 - ], - [ - 1275657.5648228042, - 2828934.4163276367 - ], - [ - 1275657.5648228042, - 2828857.9792993665 - ], - [ - 1275581.1277945302, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278832, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2828934.4163276367 - ], - [ - 1275581.1277945302, - 2829010.853355907 - ], - [ - 1275657.5648228042, - 2829010.853355907 - ], - [ - 1275657.5648228042, - 2828934.4163276367 - ], - [ - 1275581.1277945302, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278832, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829010.853355907 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829010.853355907 - ], - [ - 1275581.1277945302, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278832, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275581.1277945302, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278832, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275581.1277945302, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278832, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275581.1277945302, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829316.601468995 - ], - [ - 1275657.5648228042, - 2829316.601468995 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275581.1277945302, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278832, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2828781.5422710925 - ], - [ - 1275657.5648228042, - 2828857.9792993665 - ], - [ - 1275734.0018510744, - 2828857.9792993665 - ], - [ - 1275734.0018510744, - 2828781.5422710925 - ], - [ - 1275657.5648228042, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278833, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2828857.9792993665 - ], - [ - 1275657.5648228042, - 2828934.4163276367 - ], - [ - 1275734.0018510744, - 2828934.4163276367 - ], - [ - 1275734.0018510744, - 2828857.9792993665 - ], - [ - 1275657.5648228042, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278833, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2828934.4163276367 - ], - [ - 1275657.5648228042, - 2829010.853355907 - ], - [ - 1275734.0018510744, - 2829010.853355907 - ], - [ - 1275734.0018510744, - 2828934.4163276367 - ], - [ - 1275657.5648228042, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278833, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829010.853355907 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829010.853355907 - ], - [ - 1275657.5648228042, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278833, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275657.5648228042, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278833, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275657.5648228042, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278833, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275657.5648228042, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829316.601468995 - ], - [ - 1275734.0018510744, - 2829316.601468995 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275657.5648228042, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278833, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2828781.5422710925 - ], - [ - 1275734.0018510744, - 2828857.9792993665 - ], - [ - 1275810.4388793446, - 2828857.9792993665 - ], - [ - 1275810.4388793446, - 2828781.5422710925 - ], - [ - 1275734.0018510744, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278834, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2828857.9792993665 - ], - [ - 1275734.0018510744, - 2828934.4163276367 - ], - [ - 1275810.4388793446, - 2828934.4163276367 - ], - [ - 1275810.4388793446, - 2828857.9792993665 - ], - [ - 1275734.0018510744, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278834, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2828934.4163276367 - ], - [ - 1275734.0018510744, - 2829010.853355907 - ], - [ - 1275810.4388793446, - 2829010.853355907 - ], - [ - 1275810.4388793446, - 2828934.4163276367 - ], - [ - 1275734.0018510744, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278834, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829010.853355907 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829010.853355907 - ], - [ - 1275734.0018510744, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278834, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275734.0018510744, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278834, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275734.0018510744, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278834, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275734.0018510744, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829316.601468995 - ], - [ - 1275810.4388793446, - 2829316.601468995 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275734.0018510744, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278834, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2828781.5422710925 - ], - [ - 1275810.4388793446, - 2828857.9792993665 - ], - [ - 1275886.8759076186, - 2828857.9792993665 - ], - [ - 1275886.8759076186, - 2828781.5422710925 - ], - [ - 1275810.4388793446, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278835, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2828857.9792993665 - ], - [ - 1275810.4388793446, - 2828934.4163276367 - ], - [ - 1275886.8759076186, - 2828934.4163276367 - ], - [ - 1275886.8759076186, - 2828857.9792993665 - ], - [ - 1275810.4388793446, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278835, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2828934.4163276367 - ], - [ - 1275810.4388793446, - 2829010.853355907 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275886.8759076186, - 2828934.4163276367 - ], - [ - 1275810.4388793446, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278835, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829010.853355907 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275810.4388793446, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278835, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275886.8759076186, - 2829163.727412451 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275810.4388793446, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278835, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275886.8759076186, - 2829240.1644407213 - ], - [ - 1275886.8759076186, - 2829163.727412451 - ], - [ - 1275810.4388793446, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278835, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275810.4388793446, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829316.601468995 - ], - [ - 1275886.8759076186, - 2829316.601468995 - ], - [ - 1275886.8759076186, - 2829240.1644407213 - ], - [ - 1275810.4388793446, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278835, - "y": 299158, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828781.5422710925 - ], - [ - 1275886.8759076186, - 2828857.9792993665 - ], - [ - 1275963.3129358888, - 2828857.9792993665 - ], - [ - 1275963.3129358888, - 2828781.5422710925 - ], - [ - 1275886.8759076186, - 2828781.5422710925 - ] - ] - ] - ] - }, - "properties": { - "x": 278836, - "y": 299152, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828857.9792993665 - ], - [ - 1275886.8759076186, - 2828934.4163276367 - ], - [ - 1275963.3129358888, - 2828934.4163276367 - ], - [ - 1275963.3129358888, - 2828857.9792993665 - ], - [ - 1275886.8759076186, - 2828857.9792993665 - ] - ] - ] - ] - }, - "properties": { - "x": 278836, - "y": 299153, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2828934.4163276367 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275963.3129358888, - 2829010.853355907 - ], - [ - 1275963.3129358888, - 2828934.4163276367 - ], - [ - 1275886.8759076186, - 2828934.4163276367 - ] - ] - ] - ] - }, - "properties": { - "x": 278836, - "y": 299154, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2829010.853355907 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275963.3129358888, - 2829087.290384181 - ], - [ - 1275963.3129358888, - 2829010.853355907 - ], - [ - 1275886.8759076186, - 2829010.853355907 - ] - ] - ] - ] - }, - "properties": { - "x": 278836, - "y": 299155, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2829087.290384181 - ], - [ - 1275886.8759076186, - 2829163.727412451 - ], - [ - 1275963.3129358888, - 2829163.727412451 - ], - [ - 1275963.3129358888, - 2829087.290384181 - ], - [ - 1275886.8759076186, - 2829087.290384181 - ] - ] - ] - ] - }, - "properties": { - "x": 278836, - "y": 299156, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2829163.727412451 - ], - [ - 1275886.8759076186, - 2829240.1644407213 - ], - [ - 1275963.3129358888, - 2829240.1644407213 - ], - [ - 1275963.3129358888, - 2829163.727412451 - ], - [ - 1275886.8759076186, - 2829163.727412451 - ] - ] - ] - ] - }, - "properties": { - "x": 278836, - "y": 299157, - "zoom": 19, - "isSquare": true - } - }, - { - "type": "Feature", - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [ - 1275886.8759076186, - 2829240.1644407213 - ], - [ - 1275886.8759076186, - 2829316.601468995 - ], - [ - 1275963.3129358888, - 2829316.601468995 - ], - [ - 1275963.3129358888, - 2829240.1644407213 - ], - [ - 1275886.8759076186, - 2829240.1644407213 - ] - ] - ] - ] - }, - "properties": { - "x": 278836, - "y": 299158, - "zoom": 19, - "isSquare": true - } - } - ] - } -} diff --git a/tests/backend/helpers/test_helpers.py b/tests/backend/helpers/test_helpers.py deleted file mode 100644 index 9764f54501..0000000000 --- a/tests/backend/helpers/test_helpers.py +++ /dev/null @@ -1,391 +0,0 @@ -import base64 -import json -import os -import xml.etree.ElementTree as ET -from typing import Tuple - -import geojson - -from backend.models.dtos.organisation_dto import UpdateOrganisationDTO -from backend.models.dtos.project_dto import ( - DraftProjectDTO, - ProjectDTO, - ProjectInfoDTO, - ProjectPriority, - ProjectStatus, -) -from backend.models.postgis.campaign import Campaign -from backend.models.postgis.message import Message, MessageType -from backend.models.postgis.notification import Notification -from backend.models.postgis.organisation import Organisation -from backend.models.postgis.project import Project, ProjectTeams -from backend.models.postgis.statuses import TaskStatus -from backend.models.postgis.task import Task -from backend.models.postgis.team import Team, TeamMembers -from backend.models.postgis.user import User -from backend.services.interests_service import Interest -from backend.services.license_service import LicenseDTO, LicenseService -from backend.services.mapping_issues_service import ( - MappingIssueCategoryDTO, - MappingIssueCategoryService, -) -from backend.services.users.authentication_service import AuthenticationService - -TEST_USER_ID = 777777 -TEST_USERNAME = "Thinkwhere Test" -TEST_ORGANISATION_NAME = "Kathmandu Living Labs" -TEST_ORGANISATION_SLUG = "KLL" -TEST_ORGANISATION_ID = 23 -TEST_PROJECT_NAME = "Test" -TEST_TEAM_NAME = "Test Team" -TEST_CAMPAIGN_NAME = "Test Campaign" -TEST_CAMPAIGN_ID = 1 -TEST_MESSAGE_SUBJECT = "Test subject" -TEST_MESSAGE_DETAILS = "This is a test message" - - -def get_canned_osm_user_details(): - """Helper method to find test file, dependent on where tests are being run from""" - - location = os.path.join( - os.path.dirname(__file__), "test_files", "osm_user_details.json" - ) - try: - with open(location, "r") as x: - return json.load(x) - except FileNotFoundError: - raise FileNotFoundError("osm_user_details.json not found") - - -def get_canned_osm_user_json_details(): - """Helper method to find test file, dependent on where tests are being run from""" - - location = os.path.join( - os.path.dirname(__file__), "test_files", "osm_user_details.json" - ) - try: - with open(location, "r") as x: - return json.load(x) - except FileNotFoundError: - raise FileNotFoundError("osm_user_details.json not found") - - -def get_canned_osm_user_details_changed_name(): - """Helper method to find test file, dependent on where tests are being run from""" - - location = os.path.join( - os.path.dirname(__file__), "test_files", "osm_user_details_changed_name.xml" - ) - - try: - with open(location, "r"): - return ET.parse(location) - except FileNotFoundError: - raise FileNotFoundError("osm_user_details_changed_name.xml not found") - - -def get_canned_json(name_of_file): - """Read canned Grid request from file""" - - location = os.path.join(os.path.dirname(__file__), "test_files", name_of_file) - - try: - with open(location, "r") as grid_file: - data = json.load(grid_file) - - return data - except FileNotFoundError: - raise FileNotFoundError("json file not found") - - -def get_canned_simplified_osm_user_details(): - """Helper that reads file and returns it as a string""" - location = os.path.join( - os.path.dirname(__file__), "test_files", "osm_user_details_simple.xml" - ) - - with open(location, "r") as osm_file: - data = osm_file.read().replace("\n", "") - - return data - - -def return_canned_user(username=TEST_USERNAME, id=TEST_USER_ID) -> User: - """Returns a canned user""" - test_user = User() - test_user.username = username - test_user.id = id - test_user.mapping_level = 1 - test_user.email_address = None - - return test_user - - -def generate_encoded_token(user_id: int): - "Returns encoded session token along with token scheme" - - session_token = AuthenticationService.generate_session_token_for_user(user_id) - session_token = base64.b64encode(session_token.encode("utf-8")) - return "Token " + session_token.decode("utf-8") - - -def create_canned_user() -> User: - """Generate a canned user in the DB""" - test_user = return_canned_user() - test_user.create() - - return test_user - - -def get_canned_user(username: str) -> User: - test_user = User().get_by_username(username) - return test_user - - -def create_canned_project(name=TEST_PROJECT_NAME) -> Tuple[Project, User]: - """Generates a canned project in the DB to help with integration tests""" - test_aoi_geojson = geojson.loads(json.dumps(get_canned_json("test_aoi.json"))) - - task_feature = geojson.loads(json.dumps(get_canned_json("splittable_task.json"))) - task_non_square_feature = geojson.loads( - json.dumps(get_canned_json("non_square_task.json")) - ) - task_arbitrary_feature = geojson.loads( - json.dumps(get_canned_json("splittable_task.json")) - ) - test_user = get_canned_user(TEST_USERNAME) - if test_user is None: - test_user = create_canned_user() - - test_project_dto = DraftProjectDTO() - test_project_dto.project_name = name - test_project_dto.user_id = test_user.id - test_project_dto.area_of_interest = test_aoi_geojson - test_project = Project() - test_project.create_draft_project(test_project_dto) - test_project.set_project_aoi(test_project_dto) - test_project.total_tasks = 3 - - # Setup test task - test_task = Task.from_geojson_feature(1, task_feature) - test_task.task_status = TaskStatus.MAPPED.value - test_task.mapped_by = test_user.id - test_task.is_square = True - - test_task2 = Task.from_geojson_feature(2, task_non_square_feature) - test_task2.task_status = TaskStatus.READY.value - test_task2.is_square = False - - test_task3 = Task.from_geojson_feature(3, task_arbitrary_feature) - test_task3.task_status = TaskStatus.BADIMAGERY.value - test_task3.mapped_by = test_user.id - test_task3.is_square = True - - test_task4 = Task.from_geojson_feature(4, task_feature) - test_task4.task_status = TaskStatus.VALIDATED.value - test_task4.mapped_by = test_user.id - test_task4.validated_by = test_user.id - test_task4.is_square = True - - test_project.tasks.append(test_task) - test_project.tasks.append(test_task2) - test_project.tasks.append(test_task3) - test_project.tasks.append(test_task4) - test_project.total_tasks = 4 - test_project.tasks_mapped = 1 - test_project.tasks_validated = 1 - test_project.tasks_bad_imagery = 1 - test_project.create() - test_project.set_default_changeset_comment() - - return test_project, test_user - - -def return_canned_draft_project_json(): - """Helper method to find test file, dependent on where tests are being run from""" - - location = os.path.join( - os.path.dirname(__file__), "test_files", "canned_draft_project.json" - ) - try: - with open(location, "r") as x: - return json.load(x) - except FileNotFoundError: - raise FileNotFoundError("canned_draft_project.json not found") - - -def return_canned_organisation( - org_id=TEST_ORGANISATION_ID, - org_name=TEST_ORGANISATION_NAME, - org_slug=TEST_ORGANISATION_SLUG, -) -> Organisation: - "Returns test organisation without writing to db" - test_org = Organisation() - test_org.id = org_id - test_org.name = org_name - test_org.slug = org_slug - - return test_org - - -def create_canned_organisation(): - "Generate a canned organisation in the DB" - test_org = return_canned_organisation() - test_org.create() - - return test_org - - -def get_canned_organisation(org_name: str) -> Organisation: - organisation = Organisation.get_organisation_by_name(org_name) - return organisation - - -def return_canned_team(name=TEST_TEAM_NAME, org_name=TEST_ORGANISATION_NAME) -> Team: - """Returns test team without writing to db""" - test_team = Team() - test_team.name = name - test_org = get_canned_organisation(org_name) - if test_org is None: - test_org = create_canned_organisation() - test_team.organisation = test_org - test_team.organisation_id = test_org.id - - return test_team - - -def create_canned_team() -> Team: - test_team = return_canned_team() - test_team.create() - - return test_team - - -def add_user_to_team(team: Team, user: User, role: int, is_active: bool) -> TeamMembers: - team_member = TeamMembers(team=team, member=user, function=role, active=is_active) - team_member.create() - - return team_member - - -def add_manager_to_organisation(organisation: Organisation, user: User): - org_dto = UpdateOrganisationDTO() - org_dto.managers = [user.username] - organisation.update(org_dto) - organisation.save() - return user.username - - -def assign_team_to_project(project: Project, team: Team, role: int) -> ProjectTeams: - project_team = ProjectTeams(project=project, team=team, role=role) - project_team.create() - - return project_team - - -def update_project_with_info(test_project: Project) -> Project: - locales = [] - test_info = ProjectInfoDTO() - test_info.locale = "en" - test_info.name = "Thinkwhere Test" - test_info.description = "Test Description" - test_info.short_description = "Short description" - test_info.instructions = "Instructions" - locales.append(test_info) - - test_dto = ProjectDTO() - test_dto.project_status = ProjectStatus.PUBLISHED.name - test_dto.project_priority = ProjectPriority.MEDIUM.name - test_dto.default_locale = "en" - test_dto.project_info_locales = locales - test_dto.difficulty = "EASY" - test_dto.mapping_types = ["ROADS"] - test_dto.mapping_editors = ["JOSM", "ID"] - test_dto.validation_editors = ["JOSM"] - test_dto.changeset_comment = "hot-project" - test_dto.private = False - test_project.update(test_dto) - - return test_project - - -def return_canned_campaign( - id=TEST_CAMPAIGN_ID, - name=TEST_CAMPAIGN_NAME, - description=None, - logo=None, -) -> Campaign: - """Returns test campaign without writing to db""" - test_campaign = Campaign() - test_campaign.id = id - test_campaign.name = name - test_campaign.description = description - test_campaign.logo = logo - - return test_campaign - - -def create_canned_campaign( - id=TEST_CAMPAIGN_ID, - name=TEST_CAMPAIGN_NAME, - description=None, - logo=None, -) -> Campaign: - """Creates test campaign without writing to db""" - test_campaign = return_canned_campaign(id, name, description, logo) - test_campaign.create() - - return test_campaign - - -def create_canned_interest(name="test_interest") -> Interest: - """Returns test interest without writing to db - param name: name of interest - return: Interest object - """ - test_interest = Interest() - test_interest.name = name - test_interest.create() - return test_interest - - -def create_canned_license(name="test_license") -> int: - """Returns test license without writing to db - param name: name of license - return: license id - """ - license_dto = LicenseDTO() - license_dto.name = name - license_dto.description = "test license" - license_dto.plain_text = "test license" - test_license = LicenseService.create_licence(license_dto) - return test_license - - -def create_canned_mapping_issue(name="Test Issue") -> int: - issue_dto = MappingIssueCategoryDTO() - issue_dto.name = name - test_issue_id = MappingIssueCategoryService.create_mapping_issue_category(issue_dto) - return test_issue_id - - -def create_canned_message( - subject=TEST_MESSAGE_SUBJECT, - message=TEST_MESSAGE_DETAILS, - message_type=MessageType.SYSTEM.value, -) -> Message: - test_message = Message() - test_message.subject = subject - test_message.message = message - test_message.message_type = message_type - test_message.save() - return test_message - - -def create_canned_notification(user_id, unread_count, date) -> Notification: - test_notification = Notification() - test_notification.user_id = user_id - test_notification.unread_count = unread_count - test_notification.date = date - test_notification.save() - return test_notification diff --git a/tests/backend/integration/__init__.py b/tests/backend/integration/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/__init__.py b/tests/backend/integration/api/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/campaigns/__init__.py b/tests/backend/integration/api/campaigns/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/campaigns/test_resources.py b/tests/backend/integration/api/campaigns/test_resources.py deleted file mode 100644 index c38886ec52..0000000000 --- a/tests/backend/integration/api/campaigns/test_resources.py +++ /dev/null @@ -1,325 +0,0 @@ -from backend.exceptions import get_message_from_sub_code -from backend.models.postgis.statuses import UserRole -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_organisation, - create_canned_user, - generate_encoded_token, - return_canned_campaign, - return_canned_user, -) - -CAMPAIGN_NAME = "Test Campaign" -CAMPAIGN_ID = 1 -NEW_CAMPAIGN_NAME = "New Campaign" -CAMPAIGN_NOT_FOUND_SUB_CODE = "CAMPAIGN_NOT_FOUND" -CAMPAIGN_NOT_FOUND_MESSAGE = get_message_from_sub_code(CAMPAIGN_NOT_FOUND_SUB_CODE) - - -class TestCampaignsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_org = create_canned_organisation() - self.test_admin = return_canned_user("test_user", 11111111) - self.test_admin.create() - self.test_admin.role = UserRole.ADMIN.value - self.test_campaign = return_canned_campaign() - self.test_campaign.create() - self.test_non_admin = create_canned_user() - self.admin_token = generate_encoded_token(self.test_admin.id) - self.non_admin_token = generate_encoded_token(self.test_non_admin.id) - self.endpoint_url = "/api/v2/campaigns/" - - # get - def test_get_campaign_by_id_passes(self): - """ - Test that endpoint returns 200 to retrieve an existent campaign by id - """ - response = self.client.get(f"{self.endpoint_url}{self.test_campaign.id}/") - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body, {"id": CAMPAIGN_ID, "name": CAMPAIGN_NAME}) - - def test_get_non_existent_campaign_by_id_fails(self): - """ - Test that endpoint returns 404 to retrieve a non-existent campaign by id - """ - response = self.client.get(f"{self.endpoint_url}99/") - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], CAMPAIGN_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], CAMPAIGN_NOT_FOUND_SUB_CODE) - self.assertEqual(error_details["details"], {"campaign_id": 99}) - - # patch - def test_update_existent_campaign_by_admin_passes(self): - """ - Test that enpoint returns 200 to update an existent campaign by admin - """ - response = self.client.patch( - f"{self.endpoint_url}{self.test_campaign.id}/", - json={ - "logo": None, - "name": NEW_CAMPAIGN_NAME, - "organisations": [], - "url": None, - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Campaign 1 updated") - - def test_update_existent_campaign_by_non_admin_fails(self): - """ - Test that endpoint returns 403 to update an existent campaign by a non_admin - """ - response = self.client.patch( - f"{self.endpoint_url}{self.test_campaign.id}/", - json={ - "logo": None, - "name": NEW_CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - headers={"Authorization": self.non_admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "CampaignsRestAPI PATCH: User not a Org Manager" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_update_existent_campaign_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 to update a campaign by an unauthenticated user - """ - response = self.client.patch( - f"{self.endpoint_url}{self.test_campaign.id}/", - json={ - "logo": None, - "name": NEW_CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - ) - self.assertEqual(response.status_code, 401) - - def test_update_campaign_using_invalid_request_keys_fails(self): - """ - Test that endpoint returns 400 to update a campaign using invalid keys/data - """ - response = self.client.patch( - f"{self.endpoint_url}{self.test_campaign.id}/", - json={ - "logo": None, - "campaign_name": NEW_CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - headers={"Authorization": self.admin_token}, - ) - self.assertEqual(response.status_code, 400) - - def test_update_non_existent_campaign_by_id_fails(self): - """ - Test that endpoint returns 404 to update a non-existent campaign - """ - response = self.client.patch( - f"{self.endpoint_url}99/", - json={ - "logo": None, - "name": NEW_CAMPAIGN_NAME, - "organisations": [], - "url": None, - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], CAMPAIGN_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], CAMPAIGN_NOT_FOUND_SUB_CODE) - self.assertEqual(error_details["details"], {"campaign_id": 99}) - - # delete - def test_delete_campaign_by_admin_passes(self): - """ - Test that endpoint returns 200 for successful deletion of a campaign - """ - response = self.client.delete( - f"{self.endpoint_url}{self.test_campaign.id}/", - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Campaign deleted") - - def test_delete_campaign_by_non_admin_fails(self): - """ - Test that endpoint returns 403 for deletion of campaign by non-admin - """ - response = self.client.delete( - f"{self.endpoint_url}{self.test_campaign.id}/", - headers={"Authorization": self.non_admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "CampaignsRestAPI DELETE: User not a Org Manager" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_delete_campaign_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 for deletion of campaign by unauthenticated user - """ - response = self.client.delete(f"{self.endpoint_url}{self.test_campaign.id}/") - self.assertEqual(response.status_code, 401) - - def test_delete_non_existent_campaign_fails(self): - """ - Test that endpoint returns 404 for deletion of non-existent campaign - """ - response = self.client.delete( - f"{self.endpoint_url}99/", headers={"Authorization": self.admin_token} - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], CAMPAIGN_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], CAMPAIGN_NOT_FOUND_SUB_CODE) - - -class TestCampaignsAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.endpoint_url = "/api/v2/campaigns/" - self.test_org = create_canned_organisation() - self.test_user = return_canned_user("test_user", 11111111) - self.test_user.create() - self.test_user.role = UserRole.ADMIN.value - self.session_token = generate_encoded_token(self.test_user.id) - - # get - def test_get_existent_campaigns_returns_campaigns_list(self): - """ - Test that endpoint returns 200 for retrieval of exisiting campaigns - """ - test_campaign = return_canned_campaign() - test_campaign.create() - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual( - response_body, {"campaigns": [{"id": 1, "name": "Test Campaign"}]} - ) - - def test_get_non_existent_campaigns_returns_empty_list(self): - """ - Test that endpoint returns empty list if there are no campaigns - """ - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body, {"campaigns": []}) - - # post - def test_create_new_campaign_by_admin_passes(self): - """ - Test that endpoint returns 201 for successful creation of a new campaign - """ - response = self.client.post( - self.endpoint_url, - json={ - "logo": None, - "name": NEW_CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 201) - self.assertEqual(response_body, {"campaignId": 2}) - - def test_create_new_campaign_by_non_admin_fails(self): - """ - Test that endpoint returns 403 creation of a campaign by non-admin - """ - non_admin = create_canned_user() - non_admin_token = generate_encoded_token(non_admin.id) - response = self.client.post( - self.endpoint_url, - json={ - "logo": None, - "name": CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - headers={"Authorization": non_admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "CampaignsAllAPI POST: User not a Org Manager" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_create_new_campaign_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 creation of a campaign by unauthenticated user - """ - response = self.client.post( - self.endpoint_url, - json={ - "logo": None, - "name": CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - ) - self.assertEqual(response.status_code, 401) - - def test_create_new_campaign_with_invalid_request_key_fails(self): - """ - Test that endpoint returns 400 for creation of a new campaign with invalid data/keys - """ - response = self.client.post( - self.endpoint_url, - json={ - "logo": None, - "campaign_name": CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["Error"], '{"campaign_name": "Rogue field"}') - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_create_already_existing_campaign_fails(self): - """ - Test that endpoint returns 409 for creation of already existing campaign - """ - test_campaign = return_canned_campaign() - self.test_org.campaign = [test_campaign] - test_campaign.save() - response = self.client.post( - self.endpoint_url, - json={ - "logo": test_campaign.logo, - "name": test_campaign.name, - "organisations": [self.test_org.id], - "url": test_campaign.url, - }, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 409) - self.assertEqual(response_body["Error"], " Campaign name already exists") - self.assertEqual(response_body["SubCode"], "NameExists") diff --git a/tests/backend/integration/api/comments/__init__.py b/tests/backend/integration/api/comments/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/comments/test_resources.py b/tests/backend/integration/api/comments/test_resources.py deleted file mode 100644 index 94b5d6499b..0000000000 --- a/tests/backend/integration/api/comments/test_resources.py +++ /dev/null @@ -1,318 +0,0 @@ -from unittest.mock import patch - -from backend.exceptions import NotFound, get_message_from_sub_code -from backend.models.postgis.statuses import UserRole -from backend.services.messaging.chat_service import ChatMessageDTO, ChatService -from backend.services.messaging.message_service import MessageService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_project, - generate_encoded_token, - return_canned_user, -) - -TEST_MESSAGE = "Test comment" -PROJECT_NOT_FOUND_SUB_CODE = "PROJECT_NOT_FOUND" -TASK_NOT_FOUND_SUB_CODE = "TASK_NOT_FOUND" -MESSAGE_NOT_FOUND_SUB_CODE = "MESSAGE_NOT_FOUND" -PROJECT_NOT_FOUND_MESSAGE = get_message_from_sub_code(PROJECT_NOT_FOUND_SUB_CODE) -TASK_NOT_FOUND_MESSAGE = get_message_from_sub_code(TASK_NOT_FOUND_SUB_CODE) -MESSAGE_NOT_FOUND_MESSAGE = get_message_from_sub_code(MESSAGE_NOT_FOUND_SUB_CODE) - - -class TestCommentsProjectsAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_token = generate_encoded_token(self.test_author.id) - self.endpoint_url = f"/api/v2/projects/{self.test_project.id}/comments/" - self.non_existent_url = "/api/v2/projects/99/comments/" - - # post - def test_post_comment_to_project_chat_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when an unauthenticated user posts a comment to project chat - """ - response = self.client.post(self.endpoint_url, json={"message": TEST_MESSAGE}) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_post_comment_to_project_chat_by_blocked_user_fails(self): - """ - Test that endpoint returns 403 when a blocked user posts a comment to project chat - """ - # setup - self.test_user = return_canned_user(username="test_user", id=33333) - self.test_user.create() - self.test_user.role = UserRole.READ_ONLY.value - # action - response = self.client.post( - self.endpoint_url, - headers={"Authorization": generate_encoded_token(self.test_user.id)}, - json={"message": TEST_MESSAGE}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual(response_body["Error"], "User is on read only mode") - self.assertEqual(response_body["SubCode"], "ReadOnly") - - def test_invalid_request_to_post_comment_to_project_chat_fails(self): - """ - Test that endpoint returns 400 when an invalid request to post a comment to the project chat is made - """ - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.test_author_token}, - json={"comment": TEST_MESSAGE}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["Error"], "Unable to add chat message") - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_post_comment_to_chat_of_non_existent_project_fails(self): - """ - Test that endpoint returns 404 when user fails to post a comment to a non-existent project chat - """ - response = self.client.post( - self.non_existent_url, - headers={"Authorization": self.test_author_token}, - json={"comment": TEST_MESSAGE}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["Error"], "Unable to add chat message") - self.assertEqual(response_body["SubCode"], "InvalidData") - - @patch.object(MessageService, "send_message_after_chat") - def test_post_comment_to_project_chat_passes(self, mock_send_message): - """ - Test that endpoint returns 201 when user successfully posts a comment to the project chat - """ - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.test_author_token}, - json={"message": TEST_MESSAGE}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 201) - self.assertEqual(len(response_body["chat"]), 1) - chat_details = response_body["chat"][0] - self.assertEqual(chat_details["message"], "

Test comment

") - mock_send_message.assert_called_once() - - # get - def test_get_chat_messages_of_non_existent_project_fails(self): - """ - Test that endpoint returns 404 when retrieving the chat of a non-existent project - """ - response = self.client.get(self.non_existent_url) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], PROJECT_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_get_project_chat_messages_passes(self): - """ - Test that endpoint returns 200 when retrieving the task chat of an existing project - """ - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body, {"chat": [], "pagination": None}) - # to do: add comments and test again - - -class TestCommentsProjectsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_token = generate_encoded_token(self.test_author.id) - self.test_user = return_canned_user(username="test_user", id=10000) - self.test_user.create() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.test_comment = self.create_project_chat(self.test_author) - self.endpoint_url = ( - f"/api/v2/projects/{self.test_project.id}/comments/{self.test_comment.id}/" - ) - self.non_existent_url = f"/api/v2/projects/{self.test_project.id}/comments/100/" - - def create_project_chat(self, user): - """ - Helper method to create a project chat for a user for testing - ---------------- - :param user: User object - :return: Comment object - """ - chat_dto = ChatMessageDTO() - chat_dto.message = "Test Message" - chat_dto.user_id = user.id - chat_dto.project_id = self.test_project.id - chat_dto.timestamp = "2022-06-30T05:45:06.198755Z" - chat_dto.username = user.username - comments = ChatService.post_message( - chat_dto, self.test_project.id, self.test_author.id - ) - return comments.chat[0] - - # delete - def test_delete_comment_returns_401_if_user_not_logged_in(self): - """ - Test that endpoint returns 401 when deleting a comment of a project by an unauthenticated user - """ - # Act - response = self.client.delete(self.endpoint_url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_delete_non_existent_comment_fails(self): - """Test that endpoint returns 404 when deleting a non-existent comment""" - # Act - response = self.client.delete( - self.non_existent_url, headers={"Authorization": self.test_author_token} - ) - response_body = response.get_json() - error_details = response_body["error"] - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], MESSAGE_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], MESSAGE_NOT_FOUND_SUB_CODE) - - def test_returns_403_if_user_not_allowed_to_delete_comment(self): - """ - Test that endpoint returns 403 when deleting a comment - by a user who is not allowed i.e. not the comment author or PM. - """ - # Act - response = self.client.delete( - self.endpoint_url, headers={"Authorization": self.test_user_token} - ) - # Assert - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual(response_body["Error"], " User not allowed to delete message") - self.assertEqual(response_body["SubCode"], "DeletePermissionError") - - def test_comment_can_be_deleted_by_author(self): - """Test that endpoint returns 200 when deleting a comment of a project by the comment author""" - # Arrange - # Let's create a comment by the test user and delete it using the test user - test_comment = self.create_project_chat(self.test_user) - endpoint_url = ( - f"/api/v2/projects/{self.test_project.id}/comments/{test_comment.id}/" - ) - # Act - response = self.client.delete( - endpoint_url, headers={"Authorization": self.test_user_token} - ) - response_body = response.get_json() - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Comment deleted") - with self.assertRaises(NotFound): - ChatService.get_project_chat_by_id(self.test_project.id, test_comment.id) - - def test_pm_can_delete_any_comment(self): - """Test that endpoint returns 200 when deleting a comment of a project by the PM""" - # Arrange - # Let's create a comment by the test user and delete it using the test author - test_comment = self.create_project_chat(self.test_user) - endpoint_url = ( - f"/api/v2/projects/{self.test_project.id}/comments/{test_comment.id}/" - ) - # Act - response = self.client.delete( - endpoint_url, headers={"Authorization": self.test_author_token} - ) - response_body = response.get_json() - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Comment deleted") - with self.assertRaises(NotFound): - ChatService.get_project_chat_by_id(self.test_project.id, test_comment.id) - - -class TestCommentsTasksRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_token = generate_encoded_token(self.test_author.id) - self.endpoint_url = f"/api/v2/projects/{self.test_project.id}/comments/tasks/1/" - self.non_existent_url = "/api/v2/projects/99/comments/tasks/1/" - - # post - def test_post_comment_to_task_chat_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when an unauthenticated user posts a comment to the task chat - """ - response = self.client.post(self.endpoint_url, json={"comment": TEST_MESSAGE}) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_post_comment_to_task_chat_by_blocked_user_fails(self): - """ - Test that endpoint returns 403 when a blocked user posts a comment to the task chat - """ - # setup - self.test_user = return_canned_user("test_user", 33333) - self.test_user.create() - self.test_user.role = UserRole.READ_ONLY.value - # action - response = self.client.post( - self.endpoint_url, - headers={"Authorization": generate_encoded_token(self.test_user.id)}, - json={"comment": TEST_MESSAGE}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual(response_body["Error"], "User is on read only mode") - self.assertEqual(response_body["SubCode"], "ReadOnly") - - def test_post_comment_to_task_chat_using_an_invalid_request_fails(self): - """ - Test that endpoint returns 400 when an invalid request to post a comment to the task chat is made - """ - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.test_author_token}, - json={"message": TEST_MESSAGE}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["Error"], "Unable to add comment") - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_post_comment_to_task_chat_of_non_existent_project_fails(self): - """ - Test that endpoint returns 404 when user fails to post a comment to a non-existent project task chat - """ - response = self.client.post( - self.non_existent_url, - headers={"Authorization": self.test_author_token}, - json={"comment": TEST_MESSAGE}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], PROJECT_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_post_comment_to_task_chat_passes(self): - """ - Test that endpoint returns 201 when user successfully posts a comment to the task chat - """ - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.test_author_token}, - json={"comment": TEST_MESSAGE}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 201) - self.assertEqual(response_body["taskId"], 1) - - # GET method: no tests - # Reason: not fully implemented - # backend/api/comments/resources.py L228 diff --git a/tests/backend/integration/api/countries/__init__.py b/tests/backend/integration/api/countries/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/countries/test_resources.py b/tests/backend/integration/api/countries/test_resources.py deleted file mode 100644 index f4805bca06..0000000000 --- a/tests/backend/integration/api/countries/test_resources.py +++ /dev/null @@ -1,28 +0,0 @@ -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - -TEST_COUNTRY = "Test Country" - - -class TestCountriesRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, _ = create_canned_project() - self.endpoint_url = "/api/v2/countries/" - - def test_get_all_country_tags_passes(self): - """ - Test that endpoint returns 200 when getting all country tags successfully - """ - response1 = self.client.get(self.endpoint_url) - response_body1 = response1.get_json() - self.assertEqual(response1.status_code, 200) - self.assertEqual(len(response_body1["tags"]), 0) - self.assertEqual(response_body1["tags"], []) - # set up: add at least one country tag and test that - self.test_project.country = [TEST_COUNTRY] - response2 = self.client.get(self.endpoint_url) - response_body2 = response2.get_json() - self.assertEqual(response2.status_code, 200) - self.assertEqual(len(response_body2["tags"]), 1) - self.assertEqual(response_body2["tags"], [TEST_COUNTRY]) diff --git a/tests/backend/integration/api/interests/__init__.py b/tests/backend/integration/api/interests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/interests/test_resources.py b/tests/backend/integration/api/interests/test_resources.py deleted file mode 100644 index e345906057..0000000000 --- a/tests/backend/integration/api/interests/test_resources.py +++ /dev/null @@ -1,335 +0,0 @@ -from backend.exceptions import get_message_from_sub_code -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_manager_to_organisation, - create_canned_interest, - create_canned_organisation, - create_canned_user, - generate_encoded_token, -) - -TEST_INTEREST_NAME = "test_interest" -NEW_INTEREST_NAME = "New Interest" -INTEREST_NOT_FOUND_SUB_CODE = "INTEREST_NOT_FOUND" -INTEREST_NOT_FOUND_MESSAGE = get_message_from_sub_code(INTEREST_NOT_FOUND_SUB_CODE) - - -class TestInterestsAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_organisation = create_canned_organisation() - self.test_user = create_canned_user() - self.test_interest = create_canned_interest() - self.session_token = generate_encoded_token(self.test_user.id) - self.endpoint_url = "/api/v2/interests/" - - # post - def test_create_a_new_interest_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 during creation of new interest by an unauthenticated user - """ - response = self.client.post(self.endpoint_url, json={"name": NEW_INTEREST_NAME}) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_create_a_new_interest_by_non_admin_fails(self): - """ - Test that endpoint returns 403 during creation of new interest by non admin - """ - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"name": NEW_INTEREST_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "InterestsAllAPI POST: User not a Org Manager" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_create_a_new_interest_using_invalid_data_fails(self): - """ - Test that endpoint returns 400 during creation of new interest with bad/wrong request data - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"interest_name": NEW_INTEREST_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_create_an_already_existing_interest_by_organisation_admin_fails(self): - """ - Test that endpoint returns 400 when admin creates a new interest that already exists - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"name": TEST_INTEREST_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual( - response_body["Error"], f"Value '{TEST_INTEREST_NAME}' already exists" - ) - self.assertEqual(response_body["SubCode"], "NameExists") - - def test_create_a_new_interest_by_organisation_admin_passes(self): - """ - Test that endpoint returns 200 after successful creation of new interest by admin - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"name": NEW_INTEREST_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["name"], NEW_INTEREST_NAME) - - def test_create_a_new_interest_with_empty_name_fails(self): - """ - Test that endpoint returns 400 when admin creates a new interest with empty name - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"name": ""}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["SubCode"], "InvalidData") - - # get - def test_get_all_interest_passes(self): - """ - Test that endpoint returns 200 when retrieving list of interests - """ - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["interests"]), 1) - self.assertEqual(response_body["interests"][0]["name"], TEST_INTEREST_NAME) - - -class TestInterestsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_organisation = create_canned_organisation() - self.test_user = create_canned_user() - self.test_interest = create_canned_interest() - self.session_token = generate_encoded_token(self.test_user.id) - self.endpoint_url = f"/api/v2/interests/{self.test_interest.id}/" - self.non_existent_interest_url = "/api/v2/interests/99/" - - # get - def test_get_an_interest_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when fetching an interest by an unauthenticated user - """ - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_get_an_interest_by_non_admin_fails(self): - """ - Test that endpoint returns 403 when fetching an interest by non admin - """ - response = self.client.get( - self.endpoint_url, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "InterestsRestAPI GET: User not a Org Manager" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_get_a_non_existent_interest_fails(self): - """ - Test that endpoint returns 404 when fetching a non-existent interest by admin - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.get( - self.non_existent_interest_url, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], INTEREST_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], INTEREST_NOT_FOUND_SUB_CODE) - - def test_get_an_existing_interest_by_organisation_admin_passes(self): - """ - Test that endpoint returns 200 when fetching an existing interest by admin - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.get( - self.endpoint_url, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["name"], TEST_INTEREST_NAME) - - # patch - def test_update_an_interest_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when updating an interest by an unauthenticated user - """ - response = self.client.patch( - self.endpoint_url, json={"name": NEW_INTEREST_NAME} - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_update_an_interest_by_non_admin_fails(self): - """ - Test that endpoint returns 403 when updating an interest by non admin - """ - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"name": NEW_INTEREST_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "InterestsRestAPI PATCH: User not a Org Manager" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_update_a_non_existent_interest_fails(self): - """ - Test that endpoint returns 404 when updating a non-existent interest by admin - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.patch( - self.non_existent_interest_url, - headers={"Authorization": self.session_token}, - json={"name": NEW_INTEREST_NAME}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], INTEREST_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], INTEREST_NOT_FOUND_SUB_CODE) - - def test_update_an_existent_interest_with_invalid_data_fails(self): - """ - Test that endpoint returns 400 when updating an interest using invalid request data - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"interest_name": NEW_INTEREST_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_update_an_interest_with_empty_name_fails(self): - """ - Test that endpoint returns 400 when updating an interest with empty name - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"name": ""}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_update_an_existing_interest_by_organisation_admin_passes(self): - """ - Test that endpoint returns 200 when updating an existing interest by admin - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={"name": NEW_INTEREST_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["name"], NEW_INTEREST_NAME) - - # delete - def test_delete_an_interest_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when deleting an interest by an unauthenticated user - """ - response = self.client.delete(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_delete_an_interest_by_non_admin_fails(self): - """ - Test that endpoint returns 403 when deleting an interest by non admin - """ - response = self.client.delete( - self.endpoint_url, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "InterestsRestAPI DELETE: User not a Org Manager" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_delete_a_non_existent_interest_fails(self): - """ - Test that endpoint returns 404 when deleting a non-existent interest by admin - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.delete( - self.non_existent_interest_url, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], INTEREST_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], INTEREST_NOT_FOUND_SUB_CODE) - - def test_delete_an_existing_interest_by_organisation_admin_passes(self): - """ - Test that endpoint returns 200 when deleting an existing interest by admin - """ - # setup: make test user organisation admin - add_manager_to_organisation(self.test_organisation, self.test_user) - response = self.client.delete( - self.endpoint_url, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Interest deleted") diff --git a/tests/backend/integration/api/issues/__init__.py b/tests/backend/integration/api/issues/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/issues/test_resources.py b/tests/backend/integration/api/issues/test_resources.py deleted file mode 100644 index 46b6bf8e55..0000000000 --- a/tests/backend/integration/api/issues/test_resources.py +++ /dev/null @@ -1,216 +0,0 @@ -from backend.exceptions import get_message_from_sub_code -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_mapping_issue, - create_canned_user, - generate_encoded_token, -) - -TEST_ISSUE_NAME = "Test Issue" -TEST_ISSUE_DESCRIPTION = "Test issue description" -ISSUE_NOT_FOUND_SUB_CODE = "ISSUE_CATEGORY_NOT_FOUND" -ISSUE_NOT_FOUND_MESSAGE = get_message_from_sub_code(ISSUE_NOT_FOUND_SUB_CODE) - - -class TestIssuesRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.test_issue_id = create_canned_mapping_issue() - self.url = f"/api/v2/tasks/issues/categories/{self.test_issue_id}/" - self.non_existent_url = "/api/v2/tasks/issues/categories/99/" - - # get - def test_get_existing_issue_passes(self): - """ - Test that endpoint returns 200 to successfully get an existing issue - """ - response = self.client.get(self.url) - response_json = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_json["name"], TEST_ISSUE_NAME) - - def test_get_non_existent_issue_fails(self): - """ - Test that endpoint returns 404 to get a non existent issue - """ - response = self.client.get(self.non_existent_url) - response_json = response.get_json() - error_details = response_json["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], ISSUE_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], ISSUE_NOT_FOUND_SUB_CODE) - - # patch - def test_update_issue_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 to update an issue by an unauthenticated user - """ - response = self.client.patch( - self.url, - json={"description": TEST_ISSUE_DESCRIPTION, "name": TEST_ISSUE_NAME}, - ) - response_json = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_json["SubCode"], "InvalidToken") - - def test_update_issue_with_invalid_request_data_fails(self): - """ - Test that endpoint returns 400 to update an issue with an invalid request - """ - response = self.client.patch( - self.url, - headers={"Authorization": self.test_user_token}, - json={"issue_description": TEST_ISSUE_DESCRIPTION, "issue_name": ""}, - ) - response_json = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual( - response_json["Error"], "Unable to update mapping issue category" - ) - self.assertEqual(response_json["SubCode"], "InvalidData") - - def test_update_non_existent_issue_fails(self): - """ - Test that endpoint returns 404 to update a non existent issue - """ - response = self.client.patch( - self.non_existent_url, - headers={"Authorization": self.test_user_token}, - json={"description": TEST_ISSUE_DESCRIPTION, "name": TEST_ISSUE_NAME}, - ) - response_json = response.get_json() - error_details = response_json["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], ISSUE_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], ISSUE_NOT_FOUND_SUB_CODE) - - def test_update_mapping_issue_passes(self): - """ - Test that endpoint returns 200 to successfully update an issue - """ - response = self.client.patch( - self.url, - headers={"Authorization": self.test_user_token}, - json={ - "name": "New issue name", - "description": TEST_ISSUE_DESCRIPTION, - }, - ) - response_json = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertNotEqual(response_json["name"], TEST_ISSUE_NAME) - self.assertEqual(response_json["name"], "New issue name") - self.assertEqual(response_json["description"], TEST_ISSUE_DESCRIPTION) - - # delete - def test_delete_issue_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 to delete an issue by an unauthenticated user - """ - response = self.client.delete( - self.url, - ) - response_json = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_json["SubCode"], "InvalidToken") - - def test_delete_non_existent_issue_fails(self): - """ - Test that endpoint returns 404 to delete a non-existent issue - """ - response = self.client.delete( - self.non_existent_url, headers={"Authorization": self.test_user_token} - ) - response_json = response.get_json() - error_details = response_json["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], ISSUE_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], ISSUE_NOT_FOUND_SUB_CODE) - - def test_delete_mapping_issue_passes(self): - """ - Test that endpoint returns 200 to successfully delete an issue - """ - response = self.client.delete( - self.url, headers={"Authorization": self.test_user_token} - ) - response_json = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_json["Success"], "Mapping-issue category deleted") - - -class TestIssuesAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.url = "/api/v2/tasks/issues/categories/" - - # get - def test_get_all_issues_passes(self): - """ - Test that endpoint returns 200 to successfully retrieve all issues - """ - # Act: no issues - response = self.client.get(self.url) - response_json = response.get_json() - # test - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_json["categories"]), 0) - self.assertEqual(response_json["categories"], []) - - # Act: add 1 issue - self.test_issue = create_canned_mapping_issue() - response = self.client.get(self.url) - response_json = response.get_json() - # test - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_json["categories"]), 1) - self.assertEqual(response_json["categories"][0]["name"], TEST_ISSUE_NAME) - - # post - def test_create_issue_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 to create a new issue by an unauthenticated user - """ - response = self.client.post( - self.url, - json={"description": TEST_ISSUE_DESCRIPTION, "name": TEST_ISSUE_NAME}, - ) - response_json = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_json["SubCode"], "InvalidToken") - - def test_update_issue_with_invalid_request_data_fails(self): - """ - Test that endpoint returns 400 to create a new issue with an invalid request - """ - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_token}, - json={"issue_description": TEST_ISSUE_DESCRIPTION, "issue_name": ""}, - ) - response_json = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual( - response_json["Error"], "Unable to create a new mapping issue category" - ) - self.assertEqual(response_json["SubCode"], "InvalidData") - - def test_create_mapping_issue_passes(self): - """ - Test that endpoint returns 200 to successfully create a new issue - """ - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_token}, - json={ - "name": TEST_ISSUE_NAME, - "description": TEST_ISSUE_DESCRIPTION, - }, - ) - response_json = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_json["categoryId"], 1) diff --git a/tests/backend/integration/api/licenses/__init__.py b/tests/backend/integration/api/licenses/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/licenses/test_actions.py b/tests/backend/integration/api/licenses/test_actions.py deleted file mode 100644 index ce20ef4cb4..0000000000 --- a/tests/backend/integration/api/licenses/test_actions.py +++ /dev/null @@ -1,55 +0,0 @@ -from backend.exceptions import get_message_from_sub_code -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_license, - create_canned_user, - generate_encoded_token, -) - -LICENSE_NOT_FOUND_SUB_CODE = "LICENSE_NOT_FOUND" -LICENSE_NOT_FOUND_MESSAGE = get_message_from_sub_code(LICENSE_NOT_FOUND_SUB_CODE) - - -class TestLicensesActionsAcceptAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.test_license_id = create_canned_license() - self.endpoint_url = ( - f"/api/v2/licenses/{self.test_license_id}/actions/accept-for-me/" - ) - - def test_accept_license_terms_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when an unauthenticated user accepts license terms - """ - response = self.client.post(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_accept_terms_of_non_existent_license_fails(self): - """ - Test that endpoint returns 404 when user accepts terms of a non-existent license - """ - response = self.client.post( - "/api/v2/licenses/99/actions/accept-for-me/", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], LICENSE_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], LICENSE_NOT_FOUND_SUB_CODE) - - def test_accept_license_terms_by_authenticated_user_passes(self): - """ - Test that endpoint returns 200 when authenticated user accepts existing license terms - """ - response = self.client.post( - self.endpoint_url, headers={"Authorization": self.test_user_token} - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Terms Accepted") diff --git a/tests/backend/integration/api/licenses/test_resources.py b/tests/backend/integration/api/licenses/test_resources.py deleted file mode 100644 index c34be1b019..0000000000 --- a/tests/backend/integration/api/licenses/test_resources.py +++ /dev/null @@ -1,240 +0,0 @@ -from backend.exceptions import get_message_from_sub_code -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_license, - create_canned_user, - generate_encoded_token, -) - -TEST_LICENSE_NAME = "test_license" -TEST_LICENSE_DESCRIPTION = "test license" -TEST_LICENSE_PLAINTEXT = "test license" -NEW_LICENSE_DESCRIPTION = "A new test license" -NEW_LICENSE_NAME = "New License" -LICENSE_NOT_FOUND_SUB_CODE = "LICENSE_NOT_FOUND" -LICENSE_NOT_FOUND_MESSAGE = get_message_from_sub_code(LICENSE_NOT_FOUND_SUB_CODE) - - -class TestLicensesRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.test_license_id = create_canned_license() - self.single_licence_url = f"/api/v2/licenses/{self.test_license_id}/" - self.all_licences_url = "/api/v2/licenses/" - self.non_existent_url = "/api/v2/licenses/99/" - - # post - def test_create_new_license_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when unauthenticated user creates a new license - """ - response = self.client.post( - self.all_licences_url, - json={ - "description": NEW_LICENSE_DESCRIPTION, - "name": NEW_LICENSE_NAME, - "plainText": "", - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_create_new_license_with_invalid_request_fails(self): - """ - Test that endpoint returns 400 when creating a new license with invalid data - """ - response = self.client.post( - self.all_licences_url, - headers={"Authorization": self.test_user_token}, - json={ - "license_description": [NEW_LICENSE_DESCRIPTION], - "license_name": NEW_LICENSE_NAME, - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["Error"], "Unable to create new mapping license") - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_create_new_license_by_authenticated_user_passes(self): - """ - Test that endoint returns 201 when authenticated user creates new license - """ - response = self.client.post( - self.all_licences_url, - headers={"Authorization": self.test_user_token}, - json={ - "description": NEW_LICENSE_DESCRIPTION, - "name": NEW_LICENSE_NAME, - "plainText": "", - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 201) - self.assertEqual(response_body, {"licenseId": 2}) - - # get - def test_get_non_existent_license_fails(self): - """ - Test that endpoint returns 404 when retrieving a non existent license - """ - response = self.client.get(self.non_existent_url) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], LICENSE_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], LICENSE_NOT_FOUND_SUB_CODE) - - def test_get_license_passes(self): - """ - Test that endpoint returns 200 when retrieving an existing license - """ - response = self.client.get(self.single_licence_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["name"], TEST_LICENSE_NAME) - self.assertEqual(response_body["description"], TEST_LICENSE_DESCRIPTION) - self.assertEqual(response_body["plainText"], TEST_LICENSE_PLAINTEXT) - - # patch - def test_update_license_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when unauthenticated user updates a license - """ - response = self.client.patch( - self.single_licence_url, - json={ - "description": NEW_LICENSE_DESCRIPTION, - "name": NEW_LICENSE_NAME, - "plainText": "", - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_update_license_with_invalid_request_fails(self): - """ - Test that endpoint returns 400 when user updates a license with invalid request data - """ - response = self.client.patch( - self.single_licence_url, - headers={"Authorization": self.test_user_token}, - json={ - "license_description": [NEW_LICENSE_DESCRIPTION], - "license_name": NEW_LICENSE_NAME, - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_update_non_existent_license_by_authenticated_user_fails(self): - """ - Test that endoint returns 404 when authenticated user updates non-existent license - """ - response = self.client.patch( - self.non_existent_url, - headers={"Authorization": self.test_user_token}, - json={ - "description": NEW_LICENSE_DESCRIPTION, - "name": NEW_LICENSE_NAME, - "plainText": "", - }, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], LICENSE_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], LICENSE_NOT_FOUND_SUB_CODE) - - def test_update_license_by_authenticated_user_passes(self): - """ - Test that endoint returns 200 when authenticated user updates existing license - """ - response = self.client.patch( - self.single_licence_url, - headers={"Authorization": self.test_user_token}, - json={ - "description": NEW_LICENSE_DESCRIPTION, - "name": NEW_LICENSE_NAME, - "plainText": "", - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertNotEqual(response_body["name"], TEST_LICENSE_NAME) - self.assertNotEqual(response_body["description"], TEST_LICENSE_DESCRIPTION) - self.assertNotEqual(response_body["plainText"], TEST_LICENSE_PLAINTEXT) - # updated info - self.assertEqual(response_body["name"], NEW_LICENSE_NAME) - self.assertEqual(response_body["description"], NEW_LICENSE_DESCRIPTION) - self.assertEqual(response_body["plainText"], "") - - # delete - def test_delete_license_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when unauthenticated user deletes a license - """ - response = self.client.delete(self.single_licence_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_delete_non_existent_license_by_authenticated_user_fails(self): - """ - Test that endoint returns 404 when authenticated user deletes non-existent license - """ - response = self.client.delete( - self.non_existent_url, - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], LICENSE_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], LICENSE_NOT_FOUND_SUB_CODE) - - def test_delete_license_by_authenticated_user_passes(self): - """ - Test that endoint returns 200 when authenticated user deletes existing license - """ - response = self.client.delete( - self.single_licence_url, - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "License deleted") - - -class TestLicensesAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.endpoint_url = "/api/v2/licenses/" - - def test_get_all_licenses_(self): - """ - Test that endoint returns 200 when retrieving existing licenses - """ - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["licenses"]), 0) - self.assertEqual(response_body["licenses"], []) - # setup: add license - self.test_license_id = create_canned_license() - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["licenses"]), 1) - licenses = response_body["licenses"][0] - self.assertEqual(licenses["licenseId"], 1) - self.assertEqual(licenses["name"], TEST_LICENSE_NAME) - self.assertEqual(licenses["description"], TEST_LICENSE_DESCRIPTION) - self.assertEqual(licenses["plainText"], TEST_LICENSE_PLAINTEXT) diff --git a/tests/backend/integration/api/notifications/__init__.py b/tests/backend/integration/api/notifications/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/notifications/test_actions.py b/tests/backend/integration/api/notifications/test_actions.py deleted file mode 100644 index f71839a4c5..0000000000 --- a/tests/backend/integration/api/notifications/test_actions.py +++ /dev/null @@ -1,52 +0,0 @@ -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_message, - create_canned_user, - generate_encoded_token, -) - -TEST_SUBJECT = "Test subject" -TEST_MESSAGE = "This is a test message" - - -class TestNotificationsActionsDeleteMultipleAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_message_one = create_canned_message( - subject=TEST_SUBJECT, message=TEST_MESSAGE - ) - self.test_message_two = create_canned_message( - subject=TEST_SUBJECT, message=TEST_MESSAGE - ) - self.test_message_one.from_user_id = self.test_user.id - self.test_message_two.from_user_id = self.test_user.id - self.test_user_token = generate_encoded_token(self.test_user.id) - self.url = "/api/v2/notifications/delete-multiple/" - - # delete - def test_delete_multiple_messages_returns_401(self): - """ - Test that endpoint returns 401 for unauthenticated user deleting multiple messages - """ - response = self.client.delete( - self.url, - json={"messageIds": [self.test_message_one.id, self.test_message_two.id]}, - ) - response_body = response.get_json() - - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_delete_multiple_messages_returns_200(self): - """ - Test that endpoint returns 200 for authenticated user deleting multiple messages - """ - response = self.client.delete( - self.url, - headers={"Authorization": self.test_user_token}, - json={"messageIds": [self.test_message_one.id, self.test_message_two.id]}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Messages deleted") diff --git a/tests/backend/integration/api/notifications/test_resources.py b/tests/backend/integration/api/notifications/test_resources.py deleted file mode 100644 index 794d2b0348..0000000000 --- a/tests/backend/integration/api/notifications/test_resources.py +++ /dev/null @@ -1,477 +0,0 @@ -from datetime import datetime, timedelta - -from backend.exceptions import get_message_from_sub_code -from backend.models.postgis.message import MessageType -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_message, - create_canned_notification, - create_canned_project, - create_canned_user, - generate_encoded_token, - return_canned_user, -) - -TEST_SUBJECT = "Test subject" -TEST_MESSAGE = "This is a test message" -NOT_FOUND_SUB_CODE = "MESSAGE_NOT_FOUND" -NOT_FOUND_MESSAGE = get_message_from_sub_code(NOT_FOUND_SUB_CODE) -OLDER_TEST_SUBJECT = "Older Test Subject" -OLDER_TEST_MESSAGE = "This is an older test message" - - -class TestNotificationsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_message = create_canned_message( - subject=TEST_SUBJECT, message=TEST_MESSAGE - ) - self.test_sender = create_canned_user() - self.test_receiver = return_canned_user("Test user", 11111) - self.test_receiver.create() - self.test_message.from_user_id = self.test_sender.id - self.test_message.to_user_id = self.test_receiver.id - - self.test_sender_token = generate_encoded_token(self.test_sender.id) - self.test_receiver_token = generate_encoded_token(self.test_receiver.id) - self.url = f"/api/v2/notifications/{self.test_message.id}/" - self.non_existent_url = "/api/v2/notifications/9999999/" - - def test_get_message_returns_401(self): - """ - Test that endpoint returns 401 when an unauthenticated user accesses a particular message - """ - response = self.client.get(self.url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_get_message_returns_403(self): - """ - Test that endpoint returns 403 when one user accesses another user's messages - """ - response = self.client.get( - self.url, - headers={"Authorization": self.test_sender_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual(response_body["SubCode"], "AccessOtherUserMessage") - - def test_get_message_returns_404(self): - """ - Test that endpoint returns 404 when a user accesses a non-existent message - """ - response = self.client.get( - self.non_existent_url, - headers={"Authorization": self.test_sender_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], NOT_FOUND_SUB_CODE) - - def test_get_message_returns_200(self): - """ - Test that endpoint returns 200 when a user successfully accesses their existent message - """ - response = self.client.get( - self.url, - headers={"Authorization": self.test_receiver_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["subject"], TEST_SUBJECT) - self.assertEqual(response_body["message"], TEST_MESSAGE) - self.assertEqual(response_body["fromUsername"], self.test_sender.username) - - def test_delete_message_returns_401(self): - """ - Test that endpoint returns 401 when an unauthenticated user deletes a message - """ - response = self.client.delete(self.url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_delete_message_returns_403(self): - """ - Test that endpoint returns 403 when a user deletes another user's message - """ - response = self.client.delete( - self.url, - headers={"Authorization": self.test_sender_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual(response_body["SubCode"], "AccessOtherUserMessage") - - def test_delete_message_returns_404(self): - """ - Test that endpoint returns 404 when a user deletes a non-existent message - """ - response = self.client.delete( - self.non_existent_url, - headers={"Authorization": self.test_sender_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], NOT_FOUND_SUB_CODE) - - def test_delete_message_returns_200(self): - """ - Test that endpoint returns 200 when a user successfully deletes their existent message - """ - response = self.client.delete( - self.url, - headers={"Authorization": self.test_receiver_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Message deleted") - - -class TestNotificationsAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.url = "/api/v2/notifications/" - - def test_get_message_notifications_returns_401(self): - """ - Test that endpoint returns 401 when an unauthenticated user accesses messsage notifications - """ - response = self.client.get(self.url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_get_messages_no_query_params_returns_200(self): - """ - Test that endpoint returns 200 when authenticated user accesses their messsage notifications - """ - response = self.client.get( - self.url, - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 0) - self.assertEqual(response_body["userMessages"], []) - - # setup - add a broadcast message - self.test_message = create_canned_message( - subject=TEST_SUBJECT, - message=TEST_MESSAGE, - message_type=MessageType.BROADCAST.value, - ) - self.test_message.to_user_id = self.test_user.id - response = self.client.get( - self.url, - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["pagination"]["page"], 1) - self.assertEqual(response_body["pagination"]["pages"], 1) - self.assertEqual(response_body["pagination"]["perPage"], 10) - self.assertEqual(len(response_body["userMessages"]), 1) - user_messages = response_body["userMessages"][0] - self.assertEqual(user_messages["subject"], TEST_SUBJECT) - self.assertEqual(user_messages["message"], TEST_MESSAGE) - self.assertEqual(user_messages["messageType"], MessageType.BROADCAST.name) - - def test_get_messages_with_query_params_returns_200(self): - """ - Test that endpoint returns 200 when authenticated user accesses their messsage notifications - depending on the query parameter filters - """ - # SETUP:- add a broadcast message - self.test_message = create_canned_message( - subject=TEST_SUBJECT, - message=TEST_MESSAGE, - message_type=MessageType.BROADCAST.value, - ) - self.test_message.to_user_id = self.test_user.id - self.test_message.date = datetime.utcnow() - - # ?from= - # no messages expected since user is not the sender - # ACT - response = self.client.get( - f"{self.url}?from={self.test_user.username}", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 0) - # SETUP: set user as sender of the message - self.test_message.from_user_id = self.test_user.id - # ACT - response = self.client.get( - f"{self.url}?from={self.test_user.username}", - headers={"Authorization": self.test_user_token}, - ) - # 1 message expected since user is the sender - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 1) - - # ?project= - # setup: project - self.test_project, _ = create_canned_project() - # no messages expected since message is not affiliated to any project - # ACT - response = self.client.get( - f"{self.url}?project={self.test_project.id}", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 0) - # SETUP: project affiliation - self.test_message.project_id = self.test_project.id - # 1 message expected since message is affiliated to a project - # ACT - response = self.client.get( - f"{self.url}?project={self.test_project.id}", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 1) - - # ?taskId= - # no messages expected since message is not affiliated to any task - # ACT - response = self.client.get( - f"{self.url}?taskId=1", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 0) - # SETUP: task affiliation - self.test_message.task_id = 1 - # 1 message expected since message is affiliated to a project - # ACT - response = self.client.get( - f"{self.url}?taskId=1", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 1) - - # ?project=&taskId= - # no messages expected since message is not affiliated to unknown task in the project - # ACT - response = self.client.get( - f"{self.url}?project={self.test_project.id}&taskId=1111", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 0) - # 1 message expected since message is affiliated to task 1 in the project - # ACT - response = self.client.get( - f"{self.url}?project={self.test_project.id}&taskId=1", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 1) - - # ?messageType= - # ?messageType=1 - no message expected - # ACT - response = self.client.get( - f"{self.url}?messageType=1", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 0) - # ?messageType=2 - 1 message expected - # ACT - response = self.client.get( - f"{self.url}?messageType=2", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 1) - # ?messageType=1,2,3,4,5 - 1 message expected - # ACT - response = self.client.get( - f"{self.url}?messageType=1,2,3,4,5", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["userMessages"]), 1) - - # ?status - self.test_message.read = False # SETUP: unread message - # ?status=unread - # ACT - response = self.client.get( - f"{self.url}?status=unread", - headers={"Authorization": self.test_user_token}, - ) - unread_response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(unread_response_body["userMessages"]), 1) - # ?status=read - # ACT - response = self.client.get( - f"{self.url}?status=read", - headers={"Authorization": self.test_user_token}, - ) - read_response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(read_response_body["userMessages"]), 0) - - # SETUP: add older message - self.test_older_message = create_canned_message( - subject=OLDER_TEST_SUBJECT, - message=OLDER_TEST_MESSAGE, - message_type=MessageType.MENTION_NOTIFICATION.value, - ) - self.test_older_message.date = datetime.utcnow() - timedelta(days=6) - self.test_older_message.to_user_id = self.test_user.id - - # ?sortBy=date - # ACT - response = self.client.get( - f"{self.url}?sortBy=date", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - user_messages = response_body["userMessages"] - self.assertEqual(len(user_messages), 2) - # 1st message - self.assertEqual(user_messages[0]["subject"], TEST_SUBJECT) - self.assertEqual(user_messages[0]["message"], TEST_MESSAGE) - self.assertEqual(user_messages[0]["messageType"], MessageType.BROADCAST.name) - # 2nd message - self.assertEqual(user_messages[1]["subject"], OLDER_TEST_SUBJECT) - self.assertEqual(user_messages[1]["message"], OLDER_TEST_MESSAGE) - self.assertEqual( - user_messages[1]["messageType"], MessageType.MENTION_NOTIFICATION.name - ) - - # ?sortDirection - # ?sortDirection=desc - Descending order - # ACT - response = self.client.get( - f"{self.url}?sortDirection=desc", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - user_messages = response_body["userMessages"] - self.assertEqual(len(user_messages), 2) - self.assertGreater(user_messages[0]["sentDate"], user_messages[1]["sentDate"]) - # 1st message - self.assertEqual(user_messages[0]["subject"], TEST_SUBJECT) - self.assertEqual(user_messages[0]["message"], TEST_MESSAGE) - self.assertEqual(user_messages[0]["messageType"], MessageType.BROADCAST.name) - # 2nd message - self.assertEqual(user_messages[1]["subject"], OLDER_TEST_SUBJECT) - self.assertEqual(user_messages[1]["message"], OLDER_TEST_MESSAGE) - self.assertEqual( - user_messages[1]["messageType"], MessageType.MENTION_NOTIFICATION.name - ) - - # ?sortDirection=asc - Ascending order - # ACT - response = self.client.get( - f"{self.url}?sortDirection=asc", - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - user_messages = response_body["userMessages"] - self.assertEqual(len(user_messages), 2) - self.assertLess(user_messages[0]["sentDate"], user_messages[1]["sentDate"]) - # 1st message - self.assertEqual(user_messages[0]["subject"], OLDER_TEST_SUBJECT) - self.assertEqual(user_messages[0]["message"], OLDER_TEST_MESSAGE) - self.assertEqual( - user_messages[0]["messageType"], MessageType.MENTION_NOTIFICATION.name - ) - # 2nd message - self.assertEqual(user_messages[1]["subject"], TEST_SUBJECT) - self.assertEqual(user_messages[1]["message"], TEST_MESSAGE) - self.assertEqual(user_messages[1]["messageType"], MessageType.BROADCAST.name) - - -class TestNotificationsQueriesCountUnreadAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.url = "/api/v2/notifications/queries/own/count-unread/" - self.test_message = create_canned_message( - subject=TEST_SUBJECT, message=TEST_MESSAGE - ) - self.test_message.to_user_id = self.test_user.id - - def test_get_unread_count_returns_401(self): - """ - Test that endpoint returns 401 when an unauthenticated user wants to get the unread count - """ - response = self.client.get(self.url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_get_unread_count_returns_200(self): - """ - Test that endpoint returns 200 when an authenticated user successfully gets their unread count - """ - response = self.client.get( - self.url, - headers={"Authorization": self.test_user_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body, {"newMessages": True, "unread": 1}) - - -class TestNotificationsQueriesPostUnreadAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.test_notification = create_canned_notification( - user_id=self.test_user.id, unread_count=1, date=datetime.today() - ) - self.url = "/api/v2/notifications/queries/own/post-unread/" - - def test_post_unread_count_returns_401(self): - """ - Test that endpoint returns 401 when there is no user whose unread count should be updated - """ - response = self.client.post(self.url) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_post_unread_count_returns_200(self): - """ - Test that endpoint returns 200 after updating an authenticated user's unread count - """ - response = self.client.post( - self.url, headers={"Authorization": self.test_user_token} - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body, 1) diff --git a/tests/backend/integration/api/organisations/__init__.py b/tests/backend/integration/api/organisations/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/organisations/test_campaigns.py b/tests/backend/integration/api/organisations/test_campaigns.py deleted file mode 100644 index 883baac9f2..0000000000 --- a/tests/backend/integration/api/organisations/test_campaigns.py +++ /dev/null @@ -1,162 +0,0 @@ -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_organisation, - create_canned_project, - generate_encoded_token, - return_canned_campaign, - return_canned_user, -) -from tests.backend.integration.api.campaigns.test_resources import ( - CAMPAIGN_NOT_FOUND_MESSAGE, - CAMPAIGN_NOT_FOUND_SUB_CODE, -) - -CAMPAIGN_NAME = "New Campaign" -CAMPAIGN_ID = 2 - - -class TestOrganisationsCampaignsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_org = create_canned_organisation() - self.endpoint_url = f"/api/v2/organisations/{self.test_org.id}/campaigns/" - self.test_campaign = return_canned_campaign() - self.test_campaign.create() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("test_user", 11111111) - self.test_user.create() - self.test_org.managers = [self.test_author] - self.test_org.campaign = [self.test_campaign] - self.test_org.save() - self.test_author_session_token = generate_encoded_token(self.test_author.id) - self.test_user_session_token = generate_encoded_token(self.test_user.id) - - # post - def test_add_already_assigned_campaign_to_same_org_fails(self): - """ - Test that the endpoint returns 400 if the campaign had already been assigned to the organisation - """ - response = self.client.post( - f"/api/v2/organisations/{self.test_org.id}/campaigns/{self.test_campaign.id}/", - json={ - "logo": None, - "name": "Test Campaign", - "organisations": [self.test_org.id], - "url": None, - }, - headers={"Authorization": self.test_author_session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual( - response_body["Error"], "Campaign 1 is already assigned to organisation 23." - ) - self.assertEqual(response_body["SubCode"], "CampaignAlreadyAssigned") - - def test_assign_org_new_campaign_passes(self): - """ - Test that the endpoint returns 200 when a new campaign is assigned to the organisation - """ - new_campaign = return_canned_campaign( - id=2, name=CAMPAIGN_NAME, description=None, logo=None - ) - new_campaign.create() - response = self.client.post( - f"/api/v2/organisations/{self.test_org.id}/campaigns/{new_campaign.id}/", - json={ - "logo": None, - "name": CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - headers={"Authorization": self.test_author_session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual( - response_body["Success"], - "campaign with id 2 assigned for organisation with id 23", - ) - - def test_non_org_admin_assigns_new_campaign_to_org_fails(self): - """ - Test that the endpoint returns 403 when a non admin tries to add a new campaign to an organisation - """ - new_campaign = return_canned_campaign( - id=2, name=CAMPAIGN_NAME, description=None, logo=None - ) - new_campaign.create() - response = self.client.post( - f"/api/v2/organisations/{self.test_org.id}/campaigns/{new_campaign.id}/", - json={ - "logo": None, - "name": CAMPAIGN_NAME, - "organisations": [self.test_org.id], - "url": None, - }, - headers={"Authorization": self.test_user_session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "User is not a manager of the organisation" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - # get - def test_get_organisation_campaigns_passes(self): - """ - Test that the endpoint returns 200 when retrieving organisation campaigns - """ - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual( - response_body, {"campaigns": [{"id": 1, "name": "Test Campaign"}]} - ) - - # def test_get_non_existent_organisation_campaigns_fails(self): - # """ - # Test that the endpoint returns 404 when retrieving campaigns for non existent organisation - # """ - # response = self.client.get(f"/api/v2/organisations/111111/campaigns/") - # self.assertEqual(response.status_code, 404) - - # delete - def test_delete_organisation_campaign_by_admin_passes(self): - """Test that the endpoint returns 200 and unassigns a campaign from an organisation""" - response = self.client.delete( - f"/api/v2/organisations/{self.test_org.id}/campaigns/{self.test_campaign.id}/", - headers={"Authorization": self.test_author_session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual( - response_body, - {"Success": "Organisation and campaign unassociated successfully"}, - ) - - def test_delete_organisation_campaign_non_admin_fails(self): - """Test that the endpoint returns 403 when a non admin attempts to delete an organisation campaign""" - response = self.client.delete( - f"/api/v2/organisations/{self.test_org.id}/campaigns/{self.test_campaign.id}/", - headers={"Authorization": self.test_user_session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "User is not a manager of the organisation" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_delete_non_existent_organisation_campaign_fails(self): - """Tests that the endpoint returns 404 when the org admin deletes a non existent campaign""" - response = self.client.delete( - f"/api/v2/organisations/{self.test_org.id}/campaigns/5/", - headers={"Authorization": self.test_author_session_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], CAMPAIGN_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], CAMPAIGN_NOT_FOUND_SUB_CODE) diff --git a/tests/backend/integration/api/organisations/test_resources.py b/tests/backend/integration/api/organisations/test_resources.py deleted file mode 100644 index 2fba3124e8..0000000000 --- a/tests/backend/integration/api/organisations/test_resources.py +++ /dev/null @@ -1,392 +0,0 @@ -import base64 - -from backend.exceptions import get_message_from_sub_code -from backend.services.users.authentication_service import AuthenticationService -from tests.backend.base import BaseTestCase, db -from tests.backend.helpers.test_helpers import ( - add_manager_to_organisation, - create_canned_organisation, - create_canned_project, - create_canned_user, - generate_encoded_token, - return_canned_user, -) - -TEST_USER_ID = 777777 -TEST_USERNAME = "Thinkwhere Test" -ORG_NOT_FOUND_SUB_CODE = "ORGANISATION_NOT_FOUND" -ORG_NOT_FOUND_MESSAGE = get_message_from_sub_code(ORG_NOT_FOUND_SUB_CODE) - - -class TestOrganisationAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.endpoint_url = "/api/v2/organisations/" - self.test_project, self.test_author = create_canned_project() - self.test_org = create_canned_organisation() - add_manager_to_organisation(self.test_org, self.test_author) - self.test_project.organisation = self.test_org - db.session.commit() - - def test_get_all_organisations_returns_required_fields(self): - """Test endpoint returns all required fields""" - - response = self.client.get(self.endpoint_url) - response_body = response.json["organisations"] - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body), 1) - self.assertEqual(response_body[0]["organisationId"], self.test_org.id) - # omitManager is enabled by default but user must be authenticated to get org managers in response - with self.assertRaises(KeyError): - response_body[0]["managers"] - self.assertEqual(response_body[0]["name"], self.test_org.name) - self.assertEqual(response_body[0]["campaigns"], None) - # As omitOrgStats is set to true by default, stats field should not be included in response - with self.assertRaises(KeyError): - response_body[0]["stats"] - - def test_get_all_organisations_doesnt_returns_manager_if_omit_manager_set_true( - self, - ): - """Test managers are not returned is omitManagers is set to True""" - - response = self.client.get(f"{self.endpoint_url}?omitManagers=True") - response_body = response.json["organisations"] - with self.assertRaises(KeyError): - response_body[0]["managers"] - - def test_get_all_org_includes_managers_if_user_is_authenticated(self): - """Test managers are included if user is authenticated""" - - session_token = AuthenticationService.generate_session_token_for_user( - self.test_author.id - ) - session_token = base64.b64encode(session_token.encode("utf-8")) - session_token = "Token " + session_token.decode("utf-8") - response = self.client.get( - self.endpoint_url, headers={"Authorization": session_token} - ) - - response_body = response.json["organisations"] - self.assertEqual( - response_body[0]["managers"][0]["username"], self.test_author.username - ) - - def test_get_all_org_raises_error_if_filter_by_manager_id__on_unauthenticated_request( - self, - ): - "Test 403 is returned if filter by manager id on unauthenticated request" - - response = self.client.get(f"{self.endpoint_url}?manager_user_id=2") - self.assertEqual(response.status_code, 403) - - def test_get_all_org_includes_stats_if_omit_stats_set_false(self): - """Test stats are not returned is omitOrgStats is set to False""" - - response = self.client.get( - f"{self.endpoint_url}?omitOrgStats=False", - ) - response_body = response.json["organisations"] - - self.assertEqual(response_body[0]["stats"]["projects"]["draft"], 1) - - -class TestOrganisationsBySlugRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_org = create_canned_organisation() - self.session_token = generate_encoded_token(self.test_user.id) - self.endpoint_url = f"/api/v2/organisations/{self.test_org.slug}/" - - def test_get_org_by_slug_by_without_token_passes(self): - """ - Test that endpoint returns 200 and and organisation details - """ - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body), 12) - self.assertEqual(response_body["organisationId"], self.test_org.id) - self.assertEqual(response_body["name"], self.test_org.name) - self.assertEqual(response_body["slug"], self.test_org.slug) - self.assertEqual(response_body["name"], self.test_org.name) - self.assertEqual(response_body["logo"], None) - self.assertEqual(response_body["description"], None) - self.assertEqual(response_body["url"], None) - self.assertEqual(response_body["teams"], []) - self.assertEqual(response_body["campaigns"], None) - self.assertEqual(response_body["type"], "FREE") - self.assertEqual(response_body["subscriptionTier"], None) - - def test_get_org_by_slug_by_authorised_user_and_omitManagerList_is_false_passes( - self, - ): - """ - Test that endpoint returns 200 and organisation details including manager details - """ - add_manager_to_organisation(self.test_org, self.test_user) - response = self.client.get( - self.endpoint_url, headers={"Authorization": self.session_token} - ) # by default, omitManagerList=False" - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body), 12) - self.assertEqual(response_body["organisationId"], self.test_org.id) - # Manager list included - self.assertEqual(len(response_body["managers"]), 1) - self.assertEqual( - response_body["managers"], - [{"username": TEST_USERNAME, "pictureUrl": None}], - ) - - def test_get_org_by_slug_by_authorised_user_and_omitManagerList_is_true_passes( - self, - ): - """ - Test that endpoint returns 200 and organisation details excluding manager details - """ - add_manager_to_organisation(self.test_org, self.test_user) - response = self.client.get( - f"{self.endpoint_url}?omitManagerList=True", - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body), 12) - self.assertEqual(response_body["organisationId"], self.test_org.id) - # Manager list omitted - self.assertEqual(len(response_body["managers"]), 0) - self.assertEqual(response_body["managers"], []) - - def test_get_non_existent_org_by_slug_fails(self): - """ - Test that endpoint returns 404 when queried for non existent organisation - """ - response = self.client.get("/api/v2/organisations/random-organisation/") - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], ORG_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], ORG_NOT_FOUND_SUB_CODE) - - -class TestOrganisationsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_org = create_canned_organisation() - self.test_org.managers = [self.test_author] - self.test_org.save() - self.endpoint_url = "/api/v2/organisations/" - self.session_token = generate_encoded_token(self.test_author.id) - - # post method tests - def test_create_org_by_unauthenticated_user_fails(self): - """ - Tests that endpoint returns 401 when unauthenticated user tries to create a new org - """ - response = self.client.post( - self.endpoint_url, - json={"name": "New Org", "slug": "new-org", "managers": ["Test User"]}, - ) - self.assertEqual(response.status_code, 401) - - def test_create_org_with_non_admin_fails(self): - """ - Tests that endpoint returns 403 when non admin tries to create a new org - """ - response = self.client.post( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={ - "name": "New Org", - "slug": "new-org", - "logo": None, - "managers": [TEST_USERNAME], - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "Only admin users can create organisations." - ) - self.assertEqual(response_body["SubCode"], "OnlyAdminAccess") - - # get organisation - def test_get_org_when_omitManagerList_is_false_passes(self): - """ - Test that endpoint returns 200 while retrieving an organisation by id when omitManagersList is false - """ - response = self.client.get( - f"{self.endpoint_url}{self.test_org.id}/", - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["organisationId"], 23) - self.assertEqual(len(response_body["managers"]), 1) - self.assertEqual( - response_body["managers"], - [{"username": TEST_USERNAME, "pictureUrl": None}], - ) - - def test_get_non_existent_org_fails(self): - """ - Test that endpoint returns 404 when queried for non-existent org by id - """ - response = self.client.get( - f"{self.endpoint_url}99/", - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], ORG_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], ORG_NOT_FOUND_SUB_CODE) - - # delete method tests - def test_delete_org_by_admin_user_passes(self): - """ - Test that endpoint returns 200 after deleting existing organisation by org admin - """ - response = self.client.delete( - f"{self.endpoint_url}{self.test_org.id}/", - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Organisation deleted") - - def test_delete_item_by_non_admin_user_fails(self): - """ - Test that endpoint returns 403 when deleting existing organisation by non org admin - """ - non_admin = return_canned_user(username="Random User", id=2222) - non_admin.create() - non_admin_token = generate_encoded_token(non_admin.id) - response = self.client.delete( - f"/api/v2/organisations/{self.test_org.id}/", - headers={"Authorization": non_admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual(response_body["Error"], "User is not an admin for the org") - self.assertEqual(response_body["SubCode"], "UserNotOrgAdmin") - - def test_delete_org_with_projects_fails(self): - """ - Test that endpoint returns 403 when trying to delete organisation with projects - """ - self.test_project.organisation = self.test_org - self.test_project.save() - response = self.client.delete( - f"{self.endpoint_url}{self.test_org.id}/", - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual(response_body["Error"], "Organisation has some projects") - self.assertEqual(response_body["SubCode"], "OrgHasProjects") - - # patch - def test_update_org_details_by_admin_passes(self): - """ - Tests that endpoint returns 200 when admin successfully updates an organisation's details - """ - response = self.client.patch( - f"{self.endpoint_url}{self.test_org.id}/", - headers={"Authorization": self.session_token}, - json={ - "name": "HOT", - "slug": "hot", - "logo": None, - "managers": [TEST_USERNAME], - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body, {"Status": "Updated"}) - - def test_update_org_details_by_non_admin_fails(self): - """ - Tests that endpoint returns 403 when non admin tries to update an organisation's details - """ - non_admin = return_canned_user(username="New User", id=444) - non_admin.create() - non_admin_token = generate_encoded_token(non_admin.id) - response = self.client.patch( - f"{self.endpoint_url}{self.test_org.id}/", - headers={"Authorization": non_admin_token}, - json={ - "name": "HOT", - "slug": "hot", - "logo": None, - "managers": [TEST_USERNAME], - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual(response_body["Error"], "User is not an admin for the org") - self.assertEqual(response_body["SubCode"], "UserNotOrgAdmin") - - def test_update_org_details_with_invalid_data_fails(self): - """ - Tests that endpoint returns 400 when admin tries to update an organisation's details using invalid keys - """ - response = self.client.patch( - f"{self.endpoint_url}{self.test_org.id}/", - headers={"Authorization": self.session_token}, - json={ - "org_name": "HOT", - "org_slug": "hot", - "org_logo": None, - }, - ) - self.assertEqual(response.status_code, 400) - - -class TestOrganisationsStatsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_org = create_canned_organisation() - self.test_project, self.test_author = create_canned_project() - self.test_org.save() - self.test_project.organisation = self.test_org - self.test_project.save() - self.endpoint_url = f"/api/v2/organisations/{self.test_org.id}/statistics/" - - def test_get_org_statistics_passes(self): - """ - Tests that endpoint returns 200 when retrieving an organisation's statistics - """ - response = self.client.get(self.endpoint_url) - self.assertEqual(response.status_code, 200) - response_body = response.get_json() - self.assertEqual( - response_body["projects"], - {"draft": 1, "published": 0, "archived": 0, "recent": 0, "stale": 0}, - ) - self.assertEqual( - response_body["activeTasks"], - { - "badImagery": 0, - "invalidated": 0, - "lockedForMapping": 0, - "lockedForValidation": 0, - "mapped": 0, - "ready": 0, - "validated": 0, - }, - ) - - def test_get_non_existent_org_statistics_fails(self): - """ - Tests that endpoint returns 404 when retrieving a non existent organisation's statistics - """ - response = self.client.get("/api/v2/organisations/99/statistics/") - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], ORG_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], ORG_NOT_FOUND_SUB_CODE) diff --git a/tests/backend/integration/api/projects/__init__.py b/tests/backend/integration/api/projects/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/projects/test_actions.py b/tests/backend/integration/api/projects/test_actions.py deleted file mode 100644 index 973c2d6b49..0000000000 --- a/tests/backend/integration/api/projects/test_actions.py +++ /dev/null @@ -1,435 +0,0 @@ -import json -from unittest.mock import patch - -import geojson - -from backend.models.postgis.statuses import ( - TaskStatus, - TeamMemberFunctions, - TeamRoles, - UserRole, -) -from backend.models.postgis.task import Task -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_manager_to_organisation, - add_user_to_team, - assign_team_to_project, - create_canned_organisation, - create_canned_project, - create_canned_team, - create_canned_user, - generate_encoded_token, - get_canned_json, - return_canned_user, -) - - -class TestProjectActionsIntersectingTilesAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.url = "/api/v2/projects/actions/intersecting-tiles/" - self.test_user = create_canned_user() - self.test_user_access_token = generate_encoded_token(self.test_user.id) - - def test_returns_401_if_not_authenticated(self): - """Test that the endpoint returns 401 if the user is not authenticated""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_400_if_invalid_data(self): - """Test that the endpoint returns 400 if the data is invalid""" - # Act - response = self.client.post( - self.url, - json={"grid": "invalid"}, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 400) - - def test_returns_clipped_grid_if_clip_to_aoi_set_true(self): - """Test that the endpoint returns a clipped grid if clipToAoi is set to true""" - # Arrange - payload = get_canned_json("test_grid.json") - payload["clipToAoi"] = True - expected_response = geojson.loads( - json.dumps(get_canned_json("clipped_feature_collection.json")) - ) - # Act - response = self.client.post( - self.url, - json=payload, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertDeepAlmostEqual(expected_response, geojson.loads(response.text)) - - def test_returns_not_clipped_grid_if_clip_to_aoi_set_false(self): - """Test that the endpoint returns a not clipped grid if clipToAoi is set to false""" - # Arrange - payload = get_canned_json("test_grid.json") - payload["clipToAoi"] = False - expected_response = geojson.loads( - json.dumps(get_canned_json("feature_collection.json")) - ) - # Act - response = self.client.post( - self.url, - json=payload, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertDeepAlmostEqual(expected_response, geojson.loads(response.text)) - - def test_raises_invalid_geojson_exception_if_invalid_aoi(self): - """Test that the endpoint raises an InvalidGeoJson exception if the grid is invalid""" - # Arrange - payload = get_canned_json("test_grid.json") - payload["areaOfInterest"]["features"] = [] - # Act - response = self.client.post( - self.url, - json=payload, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "MustHaveFeatures") - - def test_raises_invalid_geojson_exception_if_self_intersecting_aoi(self): - """Test that the endpoint raises an InvalidGeoJson exception if the aoi is self intersecting""" - # Arrange - payload = get_canned_json("self_intersecting_aoi.json") - # Act - response = self.client.post( - self.url, - json=payload, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "SelfIntersectingAOI") - - -class TestProjectsActionsMessageContributorsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = ( - f"/api/v2/projects/{self.test_project.id}/actions/message-contributors/" - ) - self.test_message = "Test message" - self.test_subject = "Test subject" - self.test_user = return_canned_user("Test User", 1111111) - self.test_user.create() - self.test_user_access_token = generate_encoded_token(self.test_user.id) - self.test_author_access_token = generate_encoded_token(self.test_author.id) - - def test_returns_401_if_not_authenticated(self): - """Test that the endpoint returns 401 if the user is not authenticated""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_project_not_found(self): - """Test that the endpoint returns 404 if the project is not found""" - # Act - response = self.client.post( - "/api/v2/projects/999/actions/message-contributors/", - json={"message": self.test_message, "subject": self.test_subject}, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_403_if_user_dont_have_PM_permissions(self): - """Test that the endpoint returns 403 if the user is not the project author""" - # Act - response = self.client.post( - self.url, - json={"message": self.test_message, "subject": self.test_subject}, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - - def test_returns_400_if_invalid_data(self): - """Test that the endpoint returns 400 if the data is invalid""" - # Act - response = self.client.post( - self.url, - json={"subject": self.test_subject}, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 400) - - @patch("threading.Thread.start") - def test_sends_message_to_contributors_is_allowed_to_project_author( - self, mock_thread - ): - """Test that the endpoint sends a message to the project contributors""" - # Arrange - # Add a contributor to the project - task = Task.get(2, self.test_project.id) - task.lock_task_for_mapping(self.test_user.id) - task.unlock_task(self.test_user.id, TaskStatus.MAPPED) - # Mock the thread start method to avoid application context issues - mock_thread.return_value = None - # Act - response = self.client.post( - self.url, - json={"message": self.test_message, "subject": self.test_subject}, - headers={"Authorization": self.test_author_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(mock_thread.call_count, 1) - - @patch("threading.Thread.start") - def test_sends_message_to_contributors_is_allowed_to_organisation_manager( - self, mock_thread - ): - """Test that the endpoint sends a message to the project contributors""" - # Arrange - test_organisation = create_canned_organisation() - self.test_project.organisation = test_organisation - add_manager_to_organisation(test_organisation, self.test_user) - # Add a contributor to the project - task = Task.get(2, self.test_project.id) - task.lock_task_for_mapping(self.test_user.id) - task.unlock_task(self.test_user.id, TaskStatus.MAPPED) - # Mock the thread start method to avoid application context issues - mock_thread.return_value = None - # Act - response = self.client.post( - self.url, - json={"message": self.test_message, "subject": self.test_subject}, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(mock_thread.call_count, 1) - - @patch("threading.Thread.start") - def test_sends_message_to_contributors_is_allowed_to_admin(self, mock_thread): - """Test that the endpoint sends a message to the project contributors""" - # Arrange - self.test_user.role = UserRole.ADMIN.value - # Add a contributor to the project - task = Task.get(2, self.test_project.id) - task.lock_task_for_mapping(self.test_user.id) - task.unlock_task(self.test_user.id, TaskStatus.MAPPED) - # Mock the thread start method to avoid application context issues - mock_thread.return_value = None - # Act - response = self.client.post( - self.url, - json={"message": self.test_message, "subject": self.test_subject}, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(mock_thread.call_count, 1) - - @patch("threading.Thread.start") - def test_sends_message_to_contributors_is_allowed_to_project_team_members_with_PM_permission( - self, mock_thread - ): - """Test that the endpoint sends a message to the project contributors""" - # Arrange - test_organisation = create_canned_organisation() - self.test_project.organisation = test_organisation - test_team = create_canned_team() - add_user_to_team( - test_team, self.test_user, TeamMemberFunctions.MEMBER.value, True - ) - assign_team_to_project( - self.test_project, test_team, TeamRoles.PROJECT_MANAGER.value - ) - # Add a contributor to the project - task = Task.get(2, self.test_project.id) - task.lock_task_for_mapping(self.test_user.id) - task.unlock_task(self.test_user.id, TaskStatus.MAPPED) - # Mock the thread start method to avoid application context issues - mock_thread.return_value = None - # Act - response = self.client.post( - self.url, - json={"message": self.test_message, "subject": self.test_subject}, - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(mock_thread.call_count, 1) - - -class TestProjectsActionsTransferAPI(BaseTestCase): - """Tests for the transfer project endpoint""" - - def setUp(self): - super().setUp() - self.test_user = return_canned_user("test_user_1", 111111) - self.test_user.create() - self.test_user_access_token = generate_encoded_token(self.test_user.id) - self.test_project, self.test_author = create_canned_project() - self.test_author_access_token = generate_encoded_token(self.test_author.id) - self.url = ( - f"/api/v2/projects/{self.test_project.id}/actions/transfer-ownership/" - ) - self.test_organisation = create_canned_organisation() - self.test_project.organisation = self.test_organisation - self.test_project.save() - - def test_returns_401_if_unauthorized(self): - """Test that the endpoint returns 401 if the user is not logged in""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_project_does_not_exist(self): - """Test that the endpoint returns 404 if the project does not exist""" - # Act - response = self.client.post( - "/api/v2/projects/1111111/actions/transfer-ownership/", - headers={"Authorization": self.test_user_access_token}, - json={"username": "test_user"}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_403_if_user_is_not_project_admin_org_manager_project_author(self): - """Test that the endpoint returns 403 if the user is not the project owner""" - # Arrange - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"username": "test_user_1"}, - ) - # Assert - self.assertEqual(response.status_code, 403) - - def test_returns_403_if_new_owner_is_not_admin_or_manager_of_org_project_is_in_( - self, - ): - """Test returns 403 if the new owner is not admin or a manager of the organisation the project is in""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"username": "test_user_1"}, - ) - # Assert - self.assertEqual(response.status_code, 403) - - def test_returns_404_if_new_owner_does_not_exist(self): - """Test that the endpoint returns 404 if the new owner does not exist""" - # Arrange - self.test_user.role = UserRole.ADMIN.value - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"username": "test_user_2"}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - # Patch the thread start method to avoid application context issues - @patch("threading.Thread.start") - def test_returns_200_if_new_owner_is_admin_or_manager_of_org_project_is_in( - self, mock_thread - ): - """Test that the endpoint returns 200 if the new owner is an admin of the organisation the project is in""" - # Test new owner is admin - # Arrange - self.test_user.role = UserRole.ADMIN.value - test_user_2 = return_canned_user("test_user_2", 222222) - test_user_2.role = UserRole.ADMIN.value - test_user_2.create() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"username": "test_user_2"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(self.test_project.author_id, test_user_2.id) - - # Test new owner is manager of org project is in - # Arrange - test_user_2.role = UserRole.MAPPER.value - test_user_2.save() - add_manager_to_organisation(self.test_organisation, test_user_2) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"username": "test_user_2"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(self.test_project.author_id, test_user_2.id) - - @patch("threading.Thread.start") - def test_returns_200_if_requesting_user_is_project_author(self, mock_thread): - """Test that the endpoint returns 200 if the requesting user is the project author""" - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_author_access_token}, - json={"username": "test_user_1"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(self.test_project.author_id, self.test_user.id) - - @patch("threading.Thread.start") - def test_returns_200_if_requesting_user_is_org_manager(self, mock_thread): - """Test that the endpoint returns 200 if the requesting user is an org manager""" - # Test org manager - # Arrange - test_user_2 = return_canned_user("test_user_2", 222222) - test_user_2.role = UserRole.ADMIN.value - test_user_2.create() - add_manager_to_organisation(self.test_organisation, self.test_user) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"username": "test_user_2"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(self.test_project.author_id, test_user_2.id) - - @patch("threading.Thread.start") - def test_returns_200_if_requesting_user_is_admin(self, mock_thread): - """Test that the endpoint returns 200 if the requesting user is an admin""" - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - test_user_2 = return_canned_user("test_user_2", 222222) - test_user_2.role = UserRole.ADMIN.value - test_user_2.create() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"username": "test_user_2"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(self.test_project.author_id, test_user_2.id) diff --git a/tests/backend/integration/api/projects/test_activities.py b/tests/backend/integration/api/projects/test_activities.py deleted file mode 100644 index 9ae1cf4754..0000000000 --- a/tests/backend/integration/api/projects/test_activities.py +++ /dev/null @@ -1,107 +0,0 @@ -from backend.models.postgis.task import Task, TaskAction, TaskStatus -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - - -class TestProjectsLastActivitiesAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/activities/latest/" - - def test_returns_404_if_project_does_not_exist(self): - """ - Test that the API returns a 404 if the project does not exist - """ - # Act - response = self.client.get("/api/v2/projects/999/activities/latest/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_200_if_project_exists(self): - """ - Test that the API returns a 200 if the project exists - """ - # Arrange - task_2 = Task.get(2, self.test_project.id) - # Lock the task for mapping - task_2.lock_task_for_mapping(self.test_author.id) - # Unlock the task - task_2.unlock_task(self.test_author.id, new_state=TaskStatus.MAPPED) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["activity"]), self.test_project.total_tasks) - self.assertEqual(response.json["activity"][1]["taskId"], 2) - self.assertEqual(response.json["activity"][1]["taskStatus"], "MAPPED") - self.assertEqual( - response.json["activity"][1]["actionBy"], self.test_author.username - ) - - -class TestProjectsActivitiesAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/activities/" - - def test_returns_404_if_project_does_not_exist(self): - """ - Test that the API returns a 404 if the project does not exist - """ - # Act - response = self.client.get("/api/v2/projects/999/activities/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_200_if_project_exists(self): - """ - Test that the API returns a 200 if the project exists - """ - # Arrange - task_2 = Task.get(2, self.test_project.id) - # Lock the task for mapping - task_2.lock_task_for_mapping(self.test_author.id) - # Unlock the task - task_2.unlock_task(self.test_author.id, new_state=TaskStatus.MAPPED) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(list(response.json.keys()), ["pagination", "activity"]) - self.assertEqual( - set(response.json["activity"][0].keys()), - set( - [ - "historyId", - "taskId", - "action", - "actionText", - "actionBy", - "actionDate", - "actionBy", - "pictureUrl", - "issues", - ] - ), - ) - # Since we performed two actions above on task 2 i.e. Locked for mapping and Mapped - self.assertEqual(len(response.json["activity"]), 2) - self.assertEqual(response.json["activity"][0]["taskId"], 2) - self.assertEqual( - response.json["activity"][0]["action"], TaskAction.STATE_CHANGE.name - ) - self.assertEqual( - response.json["activity"][0]["actionText"], TaskStatus.MAPPED.name - ) - self.assertEqual( - response.json["activity"][0]["actionBy"], self.test_author.username - ) - self.assertEqual(response.json["activity"][1]["taskId"], 2) - self.assertEqual( - response.json["activity"][1]["action"], TaskAction.LOCKED_FOR_MAPPING.name - ) - self.assertEqual( - response.json["activity"][1]["actionBy"], self.test_author.username - ) diff --git a/tests/backend/integration/api/projects/test_campaign.py b/tests/backend/integration/api/projects/test_campaign.py deleted file mode 100644 index e633a95a5d..0000000000 --- a/tests/backend/integration/api/projects/test_campaign.py +++ /dev/null @@ -1,211 +0,0 @@ -from backend.models.dtos.campaign_dto import CampaignProjectDTO -from backend.services.campaign_service import CampaignService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_project, - generate_encoded_token, - return_canned_campaign, - return_canned_user, -) - - -class TestGetProjectsCampaignsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_campaign = return_canned_campaign() - self.test_campaign.create() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/campaigns/" - - def test_404_if_project_not_found(self): - # Act - response = self.client.get("/api/v2/projects/999999/campaigns/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_200_if_project_found(self): - # Arrange - campaign_dto = CampaignProjectDTO() - campaign_dto.campaign_id = self.test_campaign.id - campaign_dto.project_id = self.test_project.id - CampaignService.create_campaign_project(campaign_dto) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["campaigns"]), 1) - self.assertEqual(response.json["campaigns"][0]["id"], campaign_dto.campaign_id) - self.assertEqual(response.json["campaigns"][0]["name"], self.test_campaign.name) - - -class TestCAddCampaignProjectAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_campaign = return_canned_campaign() - self.test_campaign.create() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("test_user", 11111111) - self.test_user.create() - self.test_author_session_token = generate_encoded_token(self.test_author.id) - self.test_user_session_token = generate_encoded_token(self.test_user.id) - self.url = f"/api/v2/projects/{self.test_project.id}/campaigns/{self.test_campaign.id}/" - - def test_401_if_not_logged_in(self): - """Test that a user who is not logged in cannot assign a campaign to a project""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_403_if_not_project_manager(self): - """Test that a user who is not a project manager cannot assign a campaign to a project""" - # Act - response = self.client.post( - self.url, headers={"Authorization": self.test_user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - - def test_404_if_project_not_found(self): - """Test that a user who is a project manager cannot assign a campaign to a non-existent project""" - # Act - response = self.client.post( - f"/api/v2/projects/999999/campaigns/{self.test_campaign.id}/", - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_404_if_campaign_not_found(self): - """Test that a user who is a project manager cannot assign a non-existent campaign to a project""" - # Act - response = self.client.post( - f"/api/v2/projects/{self.test_project.id}/campaigns/999999/", - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_200_if_campaign_added(self): - """Test that a user who is a project manager can assign a campaign to a project""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - project_campaigns = CampaignService.get_project_campaigns_as_dto( - self.test_project.id - )["campaigns"] - self.assertEqual(response.status_code, 200) - self.assertEqual(project_campaigns[0]["id"], self.test_campaign.id) - self.assertEqual(project_campaigns[0]["name"], self.test_campaign.name) - - def test_200_if_campaign_already_added(self): - """Test that a user who is a project manager can assign a campaign to a project""" - # Arrange - campaign_dto = CampaignProjectDTO() - campaign_dto.campaign_id = self.test_campaign.id - campaign_dto.project_id = self.test_project.id - CampaignService.create_campaign_project(campaign_dto) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - - def test_200_if_campaign_already_added_to_another_project(self): - """Test that a user who is a project manager can assign a campaign to a project""" - # Arrange - test_project_2, _ = create_canned_project() - campaign_dto = CampaignProjectDTO() - campaign_dto.campaign_id = self.test_campaign.id - campaign_dto.project_id = test_project_2.id - CampaignService.create_campaign_project(campaign_dto) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - - -class TestDeleteCampaignProjectAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_campaign = return_canned_campaign() - self.test_campaign.create() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("test_user", 11111111) - self.test_user.create() - self.test_author_session_token = generate_encoded_token(self.test_author.id) - self.test_user_session_token = generate_encoded_token(self.test_user.id) - self.url = f"/api/v2/projects/{self.test_project.id}/campaigns/{self.test_campaign.id}/" - - def test_401_if_not_logged_in(self): - """Test that a user who is not logged in cannot remove a campaign from a project""" - # Act - response = self.client.delete(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_403_if_not_project_manager(self): - """Test that a user who is not a project manager cannot remove a campaign from a project""" - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.test_user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - - def test_404_if_project_not_found(self): - """Test that a user who is a project manager cannot remove a campaign from a non-existent project""" - # Act - response = self.client.delete( - f"/api/v2/projects/999999/campaigns/{self.test_campaign.id}/", - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_404_if_campaign_not_found(self): - """Test that a user who is a project manager cannot remove a non-existent campaign from a project""" - # Act - response = self.client.delete( - f"/api/v2/projects/{self.test_project.id}/campaigns/999999/", - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_404_if_campaign_not_assigned_to_project(self): - """Test cannot remove a campaign from a project that it is not assigned to""" - # Act - response = self.client.delete( - self.url, - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_200_if_campaign_removed(self): - """Test that a user who is a project manager can remove a campaign from a project""" - # Arrange - campaign_dto = CampaignProjectDTO() - campaign_dto.campaign_id = self.test_campaign.id - campaign_dto.project_id = self.test_project.id - CampaignService.create_campaign_project(campaign_dto) - # Act - response = self.client.delete( - self.url, - headers={"Authorization": self.test_author_session_token}, - ) - # Assert - project_campaigns = CampaignService.get_project_campaigns_as_dto( - self.test_project.id - )["campaigns"] - self.assertEqual(response.status_code, 200) - self.assertEqual(len(project_campaigns), 0) diff --git a/tests/backend/integration/api/projects/test_contributions.py b/tests/backend/integration/api/projects/test_contributions.py deleted file mode 100644 index e893082098..0000000000 --- a/tests/backend/integration/api/projects/test_contributions.py +++ /dev/null @@ -1,176 +0,0 @@ -from datetime import datetime - -from backend.models.postgis.task import Task, TaskStatus -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project, return_canned_user - - -class TestProjectsContributionsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/contributions/" - - def test_returns_404_if_project_does_not_exist(self): - # Act - response = self.client.get("/api/v2/projects/999999/contributions/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_200_if_project_exists(self): - # Arrange - task = Task.get(2, self.test_project.id) - # Lock the task for mapping - task.lock_task_for_mapping(self.test_author.id) - # Unlock the task - task.unlock_task(self.test_author.id, new_state=TaskStatus.MAPPED) - task_2 = Task.get(1, self.test_project.id) - # Lock the task for validation - task_2.lock_task_for_validating(self.test_author.id) - # Unlock the task - task_2.unlock_task(self.test_author.id, new_state=TaskStatus.VALIDATED) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - # Since Tasks 1,4 are mapped, 3 is set as bad imagery and Task 4 validated by the test user during test project - # creation. We expect test user to have 4 contributions - test_user_contribution = response.json["userContributions"][0] - self.assertEqual( - set(test_user_contribution.keys()), - set( - [ - "username", - "mappingLevel", - "pictureUrl", - "mapped", - "validated", - "badImagery", - "total", - "mappedTasks", - "validatedTasks", - "badImageryTasks", - "name", - "dateRegistered", - ] - ), - ) - self.assertEqual(test_user_contribution["username"], self.test_author.username) - self.assertEqual(test_user_contribution["mapped"], 3) - self.assertEqual(test_user_contribution["validated"], 2) - self.assertEqual(test_user_contribution["badImagery"], 1) - self.assertEqual(test_user_contribution["mappedTasks"], [4, 2, 1]) - self.assertEqual(test_user_contribution["badImageryTasks"], [3]) - self.assertEqual(test_user_contribution["validatedTasks"], [4, 1]) - - def test_return_empty_list_if_no_contributions(self): - task1 = Task.get(1, self.test_project.id) - task1.task_status = TaskStatus.READY.value - - task2 = Task.get(2, self.test_project.id) - task2.task_status = TaskStatus.READY.value - - task3 = Task.get(3, self.test_project.id) - task3.task_status = TaskStatus.READY.value - - task4 = Task.get(3, self.test_project.id) - task4.task_status = TaskStatus.READY.value - - response = self.client.get(self.url) - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["userContributions"]), 0) - self.assertEqual(response.json["userContributions"], []) - - def test_returns_list_of_all_contributors(self): - # Setup - # new test user - test_user = return_canned_user("test_user", 11111111) - test_user.create() - # contributions - # Invalidate task 1 by test author - task_1 = Task.get(1, self.test_project.id) - task_1.lock_task_for_validating(self.test_author.id) - task_1.unlock_task(self.test_author.id, new_state=TaskStatus.INVALIDATED) - # Lock task 2 for mapping by test user - task_2 = Task.get(2, self.test_project.id) - task_2.lock_task_for_mapping(test_user.id) - task_2.unlock_task(test_user.id, new_state=TaskStatus.BADIMAGERY) - # Act - response = self.client.get(self.url) - user_contributions_response = response.json["userContributions"] - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(user_contributions_response), 2) - # 1st contributor - # Tasks 3,4 are mapped and task 4 validated by test_author during project creation - self.assertEqual( - user_contributions_response[0]["username"], self.test_author.username - ) - self.assertEqual(user_contributions_response[0]["mapped"], 1) - self.assertEqual(user_contributions_response[0]["validated"], 1) - self.assertEqual(user_contributions_response[0]["badImagery"], 1) - self.assertEqual(user_contributions_response[0]["mappedTasks"], [4]) - self.assertEqual(user_contributions_response[0]["validatedTasks"], [4]) - self.assertEqual(user_contributions_response[0]["badImageryTasks"], [3]) - # 2nd contributor - self.assertEqual(user_contributions_response[1]["username"], test_user.username) - self.assertEqual(user_contributions_response[1]["mapped"], 0) - self.assertEqual(user_contributions_response[1]["badImagery"], 1) - self.assertEqual(user_contributions_response[1]["validated"], 0) - self.assertEqual(user_contributions_response[1]["mappedTasks"], []) - self.assertEqual(user_contributions_response[1]["validatedTasks"], []) - self.assertEqual(user_contributions_response[1]["badImageryTasks"], [2]) - - -class TestProjectsContributionsQueriesDayAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/contributions/queries/day/" - - def test_returns_404_if_project_does_not_exist(self): - # Act - response = self.client.get("/api/v2/projects/999999/contributions/queries/day/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_200_if_project_exists(self): - # Arrange - # Since contribs_by_day calculates the contributions using - # TaskHistory all of the actions need to be registered in TaskHistory. - # Arrange - task_2 = Task.get(2, self.test_project.id) - # Lock the task for mapping - task_2.lock_task_for_mapping(self.test_author.id) - # Unlock the task - task_2.unlock_task(self.test_author.id, new_state=TaskStatus.MAPPED) - task_2.lock_task_for_validating(self.test_author.id) - # Unlock the task - task_2.unlock_task(self.test_author.id, new_state=TaskStatus.VALIDATED) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - # Since we only have history of today, we expect only one element in the stats array - self.assertEqual(len(response.json["stats"]), 1) - self.assertEqual( - set(response.json["stats"][0].keys()), - set( - [ - "date", - "mapped", - "validated", - "cumulative_mapped", - "cumulative_validated", - "total_tasks", - ] - ), - ) - self.assertEqual( - response.json["stats"][0]["date"], datetime.today().strftime("%Y-%m-%d") - ) - self.assertEqual(response.json["stats"][0]["mapped"], 1) - self.assertEqual(response.json["stats"][0]["validated"], 1) - self.assertEqual(response.json["stats"][0]["cumulative_mapped"], 1) - self.assertEqual(response.json["stats"][0]["cumulative_validated"], 1) - self.assertEqual(response.json["stats"][0]["total_tasks"], 4) diff --git a/tests/backend/integration/api/projects/test_favourites.py b/tests/backend/integration/api/projects/test_favourites.py deleted file mode 100644 index 2ece33287f..0000000000 --- a/tests/backend/integration/api/projects/test_favourites.py +++ /dev/null @@ -1,130 +0,0 @@ -from backend.services.project_service import ProjectService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_project, - generate_encoded_token, -) - - -class TestValidateProjectFavouritedAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_session_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/favorite/" - - def test_returns_401_if_no_token(self): - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(401, response.status_code) - - def test_returns_404_if_project_does_not_exist(self): - # Arrange - url = "/api/v2/projects/999/favorite/" - # Act - response = self.client.get( - url, headers={"Authorization": self.test_author_session_token} - ) - # Assert - self.assertEqual(404, response.status_code) - - def test_returns_correct_favourite_status(self): - # Act - response = self.client.get( - self.url, headers={"Authorization": self.test_author_session_token} - ) - # Assert - self.assertEqual(200, response.status_code) - self.assertEqual({"favorited": False}, response.json) - - # Arrange - ProjectService.favorite(self.test_project.id, self.test_author.id) - # Act - response = self.client.get( - self.url, headers={"Authorization": self.test_author_session_token} - ) - # Assert - self.assertEqual(200, response.status_code) - self.assertEqual({"favorited": True}, response.json) - - -class SetProjectFavouriteAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_session_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/favorite/" - - def test_returns_401_if_no_token(self): - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(401, response.status_code) - - def test_returns_404_if_project_does_not_exist(self): - # Arrange - url = "/api/v2/projects/99999/favorite/" - # Act - response = self.client.post( - url, headers={"Authorization": self.test_author_session_token} - ) - # Assert - self.assertEqual(404, response.status_code) - - def test_returns_200_if_user_authenticated_and_project_exists(self): - # Act - response = self.client.post( - self.url, headers={"Authorization": self.test_author_session_token} - ) - # Assert - self.assertEqual(200, response.status_code) - self.assertEqual( - ProjectService.is_favorited(self.test_project.id, self.test_author.id), True - ) - - -class UnsetProjectFavouriteAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_session_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/favorite/" - - def test_returns_401_if_no_token(self): - # Act - response = self.client.delete(self.url) - # Assert - self.assertEqual(401, response.status_code) - - def test_returns_404_if_project_does_not_exist(self): - # Arrange - url = "/api/v2/projects/999999/favorite/" - # Act - response = self.client.delete( - url, headers={"Authorization": self.test_author_session_token} - ) - # Assert - self.assertEqual(404, response.status_code) - - def test_returns_400_on_not_favourited_projects(self): - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.test_author_session_token} - ) - # Assert - self.assertEqual(400, response.status_code) - - def test_returns_200_if_project_unfavourited(self): - # Arrange - ProjectService.favorite(self.test_project.id, self.test_author.id) - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.test_author_session_token} - ) - # Assert - self.assertEqual(200, response.status_code) - self.assertEqual( - ProjectService.is_favorited(self.test_project.id, self.test_author.id), - False, - ) diff --git a/tests/backend/integration/api/projects/test_resources.py b/tests/backend/integration/api/projects/test_resources.py deleted file mode 100644 index df70509542..0000000000 --- a/tests/backend/integration/api/projects/test_resources.py +++ /dev/null @@ -1,2321 +0,0 @@ -from datetime import datetime, timedelta - -import geojson - -from backend.exceptions import NotFound -from backend.models.dtos.campaign_dto import CampaignProjectDTO -from backend.models.dtos.project_dto import ( - DraftProjectDTO, - is_known_editor, - is_known_mapping_permission, - is_known_mapping_type, - is_known_project_difficulty, - is_known_project_priority, - is_known_project_status, - is_known_task_creation_mode, - is_known_validation_permission, -) -from backend.models.postgis.project import Project, ProjectDTO -from backend.models.postgis.statuses import ( - MappingPermission, - MappingTypes, - ProjectDifficulty, - ProjectPriority, - ProjectStatus, - TaskStatus, - TeamMemberFunctions, - TeamRoles, - UserRole, - ValidationPermission, -) -from backend.models.postgis.task import Task -from backend.services.campaign_service import CampaignService -from backend.services.interests_service import InterestService -from backend.services.mapping_service import MappingService -from backend.services.project_service import ProjectAdminService, ProjectService -from backend.services.validator_service import ValidatorService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_manager_to_organisation, - add_user_to_team, - assign_team_to_project, - create_canned_interest, - create_canned_organisation, - create_canned_project, - create_canned_team, - generate_encoded_token, - get_canned_json, - return_canned_campaign, - return_canned_draft_project_json, - return_canned_organisation, - return_canned_team, - return_canned_user, - update_project_with_info, -) - -TEST_USER_USERNAME = "Test User" -TEST_USER_ID = 11111 - - -class TestDeleteProjectsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/" - self.test_user = return_canned_user( - username=TEST_USER_USERNAME, id=TEST_USER_ID - ) - self.test_user.create() - test_organistion = create_canned_organisation() - self.test_project.organisation = test_organistion - self.test_project.save() - self.author_session_token = generate_encoded_token(self.test_author.id) - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_delete_project_returns_401_without_token(self): - "Test returns 401 on request without session token." - # Act - response = self.client.delete(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_delete_project_returns_403_on_if_request_by_unauthorized_user(self): - "Test Requesting user must have at least PM role on project" - # Arrange - # Reset all tasks to READY so that project can be deleted - ProjectAdminService.reset_all_tasks(self.test_project.id, self.test_user.id) - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserPermissionError") - - def test_project_with_mapped_tasks_cannot_be_deleted(self): - "Test project with mapped tasks cannot be deleted" - # Arrange - # Only admin and org manager can delete project - add_manager_to_organisation(self.test_project.organisation, self.test_author) - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.author_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "HasMappedTasks") - - def test_org_manager_can_delete_project(self): - "Test user with PM role can delete project" - - # Arrange - # Only admin and org manager can delete project - add_manager_to_organisation(self.test_project.organisation, self.test_author) - # Reset all tasks to READY so that project can be deleted - ProjectAdminService.reset_all_tasks(self.test_project.id, self.test_user.id) - - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.author_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - with self.assertRaises(NotFound): - ProjectService.get_project_by_id(self.test_project.id) - - def test_admin_can_delete_project(self): - "Test project can be deleted by admins." - - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Reset all tasks to READY so that project can be deleted - ProjectAdminService.reset_all_tasks(self.test_project.id, self.test_user.id) - - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - with self.assertRaises(NotFound): - ProjectService.get_project_by_id(self.test_project.id) - - -class TestCreateProjectsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user( - username=TEST_USER_USERNAME, id=TEST_USER_ID - ) - self.test_user.create() - self.test_organisation = create_canned_organisation() - self.url = "/api/v2/projects/" - self.session_token = generate_encoded_token(self.test_user.id) - self.canned_project_json = return_canned_draft_project_json() - - @staticmethod - def assert_draft_project_response(project_response, expected_project): - "Test project response" - assert expected_project["organisation"] == project_response.organisation_id - # Only assert coordinates as the rest of the geometry is not converted before saving to db. - expected_aoi = [ - expected_project["areaOfInterest"]["features"][0]["geometry"]["coordinates"] - ] - assert ( - expected_aoi - == project_response.get_aoi_geometry_as_geojson()["coordinates"] - ) - assert project_response.status == ProjectStatus.DRAFT.value - assert expected_project["projectName"] == project_response.get_project_title( - "en" - ) - - def test_create_project_returns_401_without_token(self): - "Test returns 401 on request without session token." - # Act - response = self.client.post(self.url, json=self.canned_project_json) - # Assert - self.assertEqual(response.status_code, 401) - - def test_create_project_returns_403_on_if_request_by_unauthorized_user(self): - "Test Requesting user must have at least PM role on project" - # Act - response = self.client.post( - self.url, - json=self.canned_project_json, - headers={"Authorization": self.session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "NotPermittedToCreate") - - def test_create_project_returns_400_if_invalid_json(self): - "Test returns 400 if invalid json" - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.post( - self.url, json={}, headers={"Authorization": self.session_token} - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_org_manager_can_create_project(self): - "Test user with PM role can create project" - # Arrange - add_manager_to_organisation(self.test_organisation, self.test_user) - # Act - response = self.client.post( - self.url, - json=self.canned_project_json, - headers={"Authorization": self.session_token}, - ) - self.assertEqual(response.status_code, 201) - self.assertIn("projectId", response.json) - draft_project = ProjectService.get_project_by_id(response.json["projectId"]) - TestCreateProjectsRestAPI.assert_draft_project_response( - draft_project, self.canned_project_json - ) - - def test_admin_can_create_project(self): - "Test project can be created by admins." - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.post( - self.url, - json=self.canned_project_json, - headers={"Authorization": self.session_token}, - ) - # Assert - self.assertEqual(response.status_code, 201) - self.assertIn("projectId", response.json) - draft_project = ProjectService.get_project_by_id(response.json["projectId"]) - TestCreateProjectsRestAPI.assert_draft_project_response( - draft_project, self.canned_project_json - ) - - -class TestGetProjectsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.url = f"/api/v2/projects/{self.test_project.id}/" - self.test_user = return_canned_user( - username=TEST_USER_USERNAME, id=TEST_USER_ID - ) - self.test_user.create() - test_organistion = create_canned_organisation() - self.test_project.organisation = test_organistion - self.test_project.save() - self.user_session_token = generate_encoded_token(self.test_user.id) - - @staticmethod - def assert_project_response(project_response, expected_project, assert_type="full"): - "Test project response" - assert expected_project.id == project_response["projectId"] - # Since some of the fields are not returned in summary mode we need to skip them - if assert_type != "summary": - assert geojson.loads( - geojson.dumps(project_response["areaOfInterest"]) - ).is_valid - assert ["type", "coordinates"] == list( - project_response["areaOfInterest"].keys() - ) - if assert_type == "notasks": - assert "tasks" not in project_response - else: - assert geojson.loads(geojson.dumps(project_response["tasks"])).is_valid - assert ( - is_known_task_creation_mode(project_response["taskCreationMode"]) - is None - ) - assert "activeMappers" in project_response - assert "interests" in project_response - assert "priorityAreas" in project_response - assert "projectInfoLocales" in project_response - - else: # assert fields that are returned in summary mode are present - assert "aoiCentroid" in project_response - assert "shortDescription" in project_response - assert "allowedUsernames" in project_response - # Since projectInfo is not present in notasks mode we need to skip it - if assert_type != "notasks": - assert ( - expected_project.get_project_title(expected_project.default_locale) - == project_response["projectInfo"]["name"] - ) - assert [ - "locale", - "name", - "shortDescription", - "description", - "instructions", - "perTaskInstructions", - ] == list(project_response["projectInfo"].keys()) - - # As these returns validation functions returns None for valid values assert that they are None - assert is_known_project_status(project_response["status"]) is None - assert is_known_project_priority(project_response["projectPriority"]) is None - assert is_known_project_difficulty(project_response["difficulty"]) is None - - for mapping_type in project_response["mappingTypes"]: - assert is_known_mapping_type(mapping_type) is None - - for editor in set( - project_response["mappingEditors"] + project_response["validationEditors"] - ): - assert is_known_editor(editor) is None - assert ( - is_known_mapping_permission(project_response["mappingPermission"]) is None - ) - assert ( - is_known_validation_permission(project_response["validationPermission"]) - is None - ) - - assert expected_project.private == project_response["private"] - assert ( - expected_project.changeset_comment == project_response["changesetComment"] - ) - assert expected_project.default_locale == project_response["defaultLocale"] - assert expected_project.organisation_id == project_response["organisation"] - assert expected_project.author.username == project_response["author"] - - assert "enforceRandomTaskSelection" in project_response - assert "osmchaFilterId" in project_response - assert "dueDate" in project_response - assert "imagery" in project_response - assert "idPresets" in project_response - assert "extraIdParams" in project_response - assert "rapidPowerUser" in project_response - assert "mappingTypes" in project_response - assert "campaigns" in project_response - assert "organisationName" in project_response - assert "organisationSlug" in project_response - assert "organisationLogo" in project_response - assert "countryTag" in project_response - assert "licenseId" in project_response - assert "allowedUsernames" in project_response - assert "created" in project_response - assert "lastUpdated" in project_response - assert "percentMapped" in project_response - assert "percentValidated" in project_response - assert "percentBadImagery" in project_response - assert "teams" in project_response - - def test_published_public_project_can_be_accessed_without_token(self): - "Test returns 200 on request by unauthenticated user." - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["projectId"], self.test_project.id) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - - def test_draft_project_can_only_be_accessed_by_user_with_PM_permissions(self): - "Test draft project can only be accessed by user with PM permissions." - # Arrange - self.test_project.status = ProjectStatus.DRAFT.value - self.test_project.save() - - # Authenticated user with that is not a manager or admin - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "ProjectNotFetched") - - # Authenticated user with that is a admin - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - - # Authenticated user with that is a manager - self.test_user.role = UserRole.MAPPER.value - self.test_user.save() - add_manager_to_organisation(self.test_project.organisation, self.test_user) - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["projectId"], self.test_project.id) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - - def test_private_project_requires_atleast_PM_permissions(self): - "Test provate project can only be accessed by user with PM permissions." - # Arrange - self.test_project.private = True - self.test_project.save() - - # Authenticated user with that is not a manager or admin - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "PrivateProject") - - # Authenticated user with that is a admin - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - - # Authenticated user with that is a organisation manager - # Arrange - self.test_user.role = UserRole.MAPPER.value # Reset user role to Mapper - self.test_user.save() - add_manager_to_organisation(self.test_project.organisation, self.test_user) - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - - # Authenticated user with that is a member of team associated with project - # Arrange - # Remove organisation from project - self.test_project.organisation = None - # Create a team and add user to it - test_team = create_canned_team() - test_user_1 = return_canned_user("TEST_USER_1", 222222) - test_user_1.create() - test_user_1_session_token = generate_encoded_token(test_user_1.id) - add_user_to_team(test_team, test_user_1, TeamMemberFunctions.MEMBER.value, True) - # Assign team to project - assign_team_to_project(self.test_project, test_team, TeamRoles.MAPPER.value) - # Act - response = self.client.get( - self.url, headers={"Authorization": test_user_1_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - - def test_get_project_returns_tasks_with_geometry_while_abbreviated_is_set_false( - self, - ): - "Test get project returns tasks with geometry while abbreviated is set false." - # Act - response = self.client.get( - f"{self.url}?abbreviated=false", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - for task in response.json["tasks"]["features"]: - self.assertIsNotNone(task["geometry"]) - - def test_get_project_returns_tasks_with_no_geometry_while_abbreviated_is_set_true( - self, - ): - "Test get project returns tasks with no geom while abbreviated is set true." - # Act - response = self.client.get( - f"{self.url}?abbreviated=true", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - for task in response.json["tasks"]["features"]: - self.assertIsNone(task["geometry"]) - - def test_get_project_returns_file_if_as_file_is_set_true(self): - "Test get project returns file if as_file is set true." - # Act - response = self.client.get( - f"{self.url}?as_file=true", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers["Content-Type"], "application/json") - self.assertEqual( - response.headers["Content-Disposition"], - f"attachment; filename=project_{self.test_project.id}.json", - ) - TestGetProjectsRestAPI.assert_project_response(response.json, self.test_project) - - -class TestPatchProjectRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/" - self.test_user = return_canned_user( - username=TEST_USER_USERNAME, id=TEST_USER_ID - ) - self.test_user.create() - test_organistion = create_canned_organisation() - self.test_project.organisation = test_organistion - self.test_project.save() - self.author_session_token = generate_encoded_token(self.test_author.id) - self.user_session_token = generate_encoded_token(self.test_user.id) - self.project_update_body = get_canned_json("canned_project_detail.json") - self.project_update_body["projectId"] = self.test_project.id - - def test_patch_project_requires_authentication(self): - "Test patch project requires authentication." - # Act - response = self.client.patch(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_patch_project_returns_404_if_project_does_not_exist(self): - "Test patch project returns 404 if project does not exist." - # Act - response = self.client.patch( - "/api/v2/projects/1000/", headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_patch_project_returns_403_if_user_is_not_project_manager(self): - "Test patch project returns 403 if user is not project manager." - # Act - response = self.client.patch( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserPermissionError") - - def test_patch_project_returns_400_if_invalid_body(self): - "Test patch project returns 400 if invalid body." - # Act - response = self.client.patch( - self.url, - json={"message": "invalid body"}, - content_type="application/json", - headers={"Authorization": self.author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_project_author_can_update_project(self): - "Test project author can update project." - # Act - response = self.client.patch( - self.url, - json=self.project_update_body, - content_type="application/json", - headers={"Authorization": self.author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - updated_project = ProjectService.get_project_by_id(self.test_project.id) - TestGetProjectsRestAPI.assert_project_response( - self.project_update_body, updated_project - ) - - def test_member_of_team_with_PM_permission_can_update_project(self): - "Test member of team with PM permission can update project." - # Arrange - team = create_canned_team() - add_user_to_team(team, self.test_user, TeamMemberFunctions.MEMBER.value, True) - project_team = assign_team_to_project( - self.test_project, team, TeamRoles.PROJECT_MANAGER.value - ) - # Act - response = self.client.patch( - self.url, - json=self.project_update_body, - content_type="application/json", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - updated_project = ProjectService.get_project_by_id(self.test_project.id) - TestGetProjectsRestAPI.assert_project_response( - self.project_update_body, updated_project - ) - # Cleanup - project_team.delete() - - def test_member_of_team_with_non_PM_role_cannot_update_project(self): - """Test member of team with non PM permission can't update project.""" - # Arrange - team = create_canned_team() - add_user_to_team(team, self.test_user, TeamMemberFunctions.MEMBER.value, True) - project_team = assign_team_to_project( - self.test_project, team, TeamRoles.VALIDATOR.value - ) - # Act - response = self.client.patch( - self.url, - json=self.project_update_body, - content_type="application/json", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - # Cleanup - project_team.delete() - - def test_user_with_admin_role_can_update_project(self): - "Test project can be updated by admins." - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.patch( - self.url, - json=self.project_update_body, - content_type="application/json", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - updated_project = ProjectService.get_project_by_id(self.test_project.id) - TestGetProjectsRestAPI.assert_project_response( - self.project_update_body, updated_project - ) - # Cleanup - self.test_user.role = UserRole.MAPPER.value - self.test_user.save() - - def test_org_manager_can_update_project(self): - "Test org manager can update project." - # Arrange - add_manager_to_organisation(self.test_project.organisation, self.test_user) - # Act - response = self.client.patch( - self.url, - json=self.project_update_body, - content_type="application/json", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - updated_project = ProjectService.get_project_by_id(self.test_project.id) - TestGetProjectsRestAPI.assert_project_response( - self.project_update_body, updated_project - ) - - -class TestProjectsAllAPI(BaseTestCase): - """Tests for the projects/all endpoint.""" - - def setUp(self): - super().setUp() - self.url = "/api/v2/projects/" - self.test_project_1, self.test_author = create_canned_project() - self.test_project_1.status = ProjectStatus.PUBLISHED.value - self.test_project_1.save() - self.test_project_2, _ = create_canned_project() - self.test_project_2.status = ProjectStatus.PUBLISHED.value - self.test_project_2.private = True - self.test_project_2.save() - self.test_project_3, _ = create_canned_project() - self.test_project_3.status = ProjectStatus.DRAFT.value - self.test_project_3.save() - self.test_user = return_canned_user(username="Test User_2", id=11111) - self.test_user.create() - self.author_session_token = generate_encoded_token(self.test_author.id) - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_get_all_projects_can_be_accessed_without_token(self): - "Test get all projects can be accessed without token." - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - - def test_get_all_project_returns_published_public_projects_if_token_not_supplied( - self, - ): - "Test get all project returns published public projects if token not supplied." - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_get_all_projects_returns_user_permitted_published_projects_if_token_supplied( - self, - ): - "Test get all projects returns published projects on which user has permission if token supplied." - # Arrange - self.test_project_2.private = False - self.test_project_2.save() - # Act - response = self.client.get( - self.url, headers={"Authorization": self.author_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 2) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - self.assertEqual( - response.json["results"][1]["projectId"], self.test_project_2.id - ) - - def test_returns_projects_with_tasks_to_validate_if_action_set_to_validate(self): - """ - Test returns only projects that have tasks ready for validation and - they have permission to validate if action set to validate. - """ - # Arrange - self.test_project_2.private = False - # Since test_author is BEGINNER, they can only validate projects with validation permission ANY. - self.test_project_1.validation_permission = ValidationPermission.ANY.value - self.test_project_1.save() - self.test_project_2.validation_permission = ValidationPermission.ANY.value - self.test_project_2.save() - # Reset all tasks of test_project_2 so that there are no tasks ready to validate. - MappingService.map_all_tasks(self.test_project_2.id, self.test_author.id) - ValidatorService.validate_all_tasks(self.test_project_2.id, self.test_author.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.author_session_token}, - query_string={"action": "validate"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - # Test_project_2 has no tasks to validate, it should not be returned even when user has permsiion to validate. - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_projects_with_tasks_to_map_if_action_set_to_map(self): - """ - Test returns only projects that have tasks ready for mapping and - they have permission to map if action set to map. - """ - # Arrange - self.test_project_2.private = False - # Since test_author is BEGINNER, they can only map projects with mapping permission ANY. - self.test_project_1.mapping_permission = MappingPermission.ANY.value - self.test_project_1.save() - self.test_project_2.mapping_permission = MappingPermission.ANY.value - self.test_project_2.save() - # Map all tasks of test_project_2 so that there are no tasks ready to map. - MappingService.map_all_tasks(self.test_project_2.id, self.test_author.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"action": "map"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - # Test_project_2 has no tasks to map, it should not be returned even when user has permission to map. - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_all_projects_that_user_is_permitted_if_action_set_to_any(self): - """ - Test returns all projects that user has permission for if action set to any. - """ - # Arrange - self.test_project_2.private = False - # Since test_author is BEGINNER, they can only map projects with mapping permission ANY. - self.test_project_1.mapping_permission = MappingPermission.ANY.value - self.test_project_1.save() - self.test_project_2.mapping_permission = MappingPermission.ANY.value - self.test_project_2.save() - # Archive test_project_2 so that it is not returned if action set to any. - test_project_4 = Project.clone(self.test_project_2.id, self.test_author.id) - test_project_4.status = ProjectStatus.ARCHIVED.value - # Validate all tasks of test_project_2 to check finished projects are not returned if action set to any. - MappingService.map_all_tasks(self.test_project_2.id, self.test_author.id) - ValidatorService.validate_all_tasks(self.test_project_2.id, self.test_author.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"action": "any"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 2) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - self.assertEqual( - response.json["results"][1]["projectId"], self.test_project_2.id - ) - - def test_returns_easy_projects_if_difficulty_set_to_easy(self): - """ - Test returns only projects with difficulty set to easy if difficulty set to easy. - """ - # Arrange - self.test_project_2.private = False - # Set difficulty of test_project_2 to easy. - self.test_project_2.difficulty = ProjectDifficulty.EASY.value - self.test_project_2.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"difficulty": "EASY"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_2.id - ) - - def test_returns_moderate_projects_if_difficulty_set_to_moderate(self): - """ - Test returns only projects with difficulty set to MODERATE if difficulty set to MODERATE. - Since we have set difficulty of proects to MODERATE during setup, we should get all user permitted projects. - """ - # Arrange - self.test_project_2.private = False - # Change difficulty of test_project_2 to easy so that it is not returned. - self.test_project_2.difficulty = ProjectDifficulty.EASY.value - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"difficulty": "MODERATE"}, - ) - # User is only permitted to map test_project_1 and test_project_2, since test_project_3 is DRAFT. - # So we should get only test_project_1 as it is the only project with difficulty set to MODERATE. - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_challenging_projects_if_difficulty_set_to_changelling(self): - """ - Test returns only projects with difficulty set to hard if difficulty set to challenging. - """ - # Arrange - self.test_project_2.private = False - # Set difficulty of test_project_2 to hard. - self.test_project_2.difficulty = ProjectDifficulty.CHALLENGING.value - self.test_project_2.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"difficulty": "CHALLENGING"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_2.id - ) - - def test_returns_all_projects_if_difficulty_set_to_all(self): - """ - Test returns all projects if difficulty set to all. - """ - # Arrange - self.test_project_2.private = False - # Set difficulty of test_project_2 to easy. - self.test_project_2.difficulty = ProjectDifficulty.EASY.value - self.test_project_2.save() - self.test_project_1.difficulty = ProjectDifficulty.MODERATE.value - self.test_project_1.save() - test_project_4 = Project.clone(self.test_project_2.id, self.test_author.id) - test_project_4.status = ProjectStatus.PUBLISHED.value - test_project_4.difficulty = ProjectDifficulty.CHALLENGING.value - test_project_4.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"difficulty": "ALL"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - # User is only permitted for test_project 1, 2 and 4, since test_project_3 is DRAFT. - self.assertEqual(len(response.json["results"]), 3) - self.assertNotIn( - self.test_project_3.id, [i["projectId"] for i in response.json["results"]] - ) - - def test_returns_sorted_projects_by_priority_if_sort_by_set_to_priority(self): - """ - Test returns sorted projects by priority if sort_by set to priority. - """ - # Arrange - # Set priority of test_project_1 to urgent. - self.test_project_1.priority = ProjectPriority.URGENT.value - self.test_project_1.save() - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.private = False - self.test_project_2.priority = ProjectPriority.HIGH.value - self.test_project_2.save() - # Set priority of test_project_1 to low and status to published. - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.priority = ProjectPriority.MEDIUM.value - self.test_project_3.save() - test_project_4 = Project.clone(self.test_project_2.id, self.test_author.id) - test_project_4.status = ProjectStatus.PUBLISHED.value - test_project_4.priority = ProjectPriority.LOW.value - test_project_4.save() - - # Test for descending order - # Act - response_desc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "priority", "orderByType": "DESC"}, - ) - # Assert - self.assertEqual(response_desc.status_code, 200) - self.assertEqual(len(response_desc.json["results"]), 4) - expected_desc_order = [ - test_project_4.id, - self.test_project_3.id, - self.test_project_2.id, - self.test_project_1.id, - ] - self.assertListEqual( - [i["projectId"] for i in response_desc.json["results"]], expected_desc_order - ) - - # Test for ascending order - # Act - response_asc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "priority", "orderByType": "ASC"}, - ) - # Assert - self.assertEqual(response_asc.status_code, 200) - self.assertEqual(len(response_asc.json["results"]), 4) - self.assertListEqual( - [i["projectId"] for i in response_asc.json["results"]], - expected_desc_order[::-1], - ) - - def test_returns_sorted_projects_by_difficulty_if_sort_by_set_to_difficulty(self): - """ - Test returns sorted projects by difficulty if sort_by set to difficulty. - """ - # Arrange - # Set difficulty of test_project_1 to easy. - self.test_project_1.difficulty = ProjectDifficulty.EASY.value - self.test_project_1.save() - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.private = False - self.test_project_2.difficulty = ProjectDifficulty.MODERATE.value - self.test_project_2.save() - # Set difficulty of test_project_1 to hard and status to published. - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.difficulty = ProjectDifficulty.CHALLENGING.value - self.test_project_3.save() - - # Test for descending order - # Act - response_desc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "difficulty", "orderByType": "DESC"}, - ) - # Assert - self.assertEqual(response_desc.status_code, 200) - self.assertEqual(len(response_desc.json["results"]), 3) - expected_desc_order = [ - self.test_project_3.id, - self.test_project_2.id, - self.test_project_1.id, - ] - self.assertListEqual( - [i["projectId"] for i in response_desc.json["results"]], expected_desc_order - ) - - # Test for ascending order - # Act - response_asc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "difficulty", "orderByType": "ASC"}, - ) - # Assert - self.assertEqual(response_asc.status_code, 200) - self.assertEqual(len(response_asc.json["results"]), 3) - self.assertListEqual( - [i["projectId"] for i in response_asc.json["results"]], - expected_desc_order[::-1], - ) - - def test_returns_sorted_projects_by_creation_date_if_sort_by_set_to_id(self): - """ - Test returns sorted projects by created_at if sort_by set to id. - """ - # Arrange - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.private = False - self.test_project_2.save() - # Set status of test_project_3 to published. - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - - # Test returns sorted projects by created_at in descending order. - # Act - response_desc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "id", "orderByType": "DESC"}, - ) - # Assert - self.assertEqual(response_desc.status_code, 200) - self.assertEqual(len(response_desc.json["results"]), 3) - expected_desc_order = [ - self.test_project_3.id, - self.test_project_2.id, - self.test_project_1.id, - ] - self.assertListEqual( - [i["projectId"] for i in response_desc.json["results"]], expected_desc_order - ) - - # Test returns sorted projects by created_at in ascending order. - # Act - response_asc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "id", "orderByType": "ASC"}, - ) - # Assert - self.assertEqual(response_asc.status_code, 200) - self.assertEqual(len(response_asc.json["results"]), 3) - self.assertListEqual( - [i["projectId"] for i in response_asc.json["results"]], - expected_desc_order[::-1], - ) - - def test_returns_sorted_projects_by_last_updated_date_if_sort_by_set_to_updated_at( - self, - ): - """ - Test returns sorted projects by last_updated_at if sort_by set to updated_at. - """ - # Arrange - self.test_project_1.last_updated = datetime.utcnow() - timedelta(days=1) - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.last_updated = datetime.utcnow() - timedelta(days=2) - self.test_project_2.private = False - self.test_project_2.save() - # Set status of test_project_3 to published. - self.test_project_3.last_updated = datetime.utcnow() - timedelta(days=3) - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - - # Test returns sorted projects by last_updated_in descending order. - # Act - response_desc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "last_updated", "orderByType": "DESC"}, - ) - # Assert - self.assertEqual(response_desc.status_code, 200) - self.assertEqual(len(response_desc.json["results"]), 3) - expected_desc_order = [ - self.test_project_1.id, - self.test_project_2.id, - self.test_project_3.id, - ] - self.assertListEqual( - [i["projectId"] for i in response_desc.json["results"]], expected_desc_order - ) - - # Test returns sorted projects by last_updated_in ascending order. - # Act - response_asc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "last_updated", "orderByType": "ASC"}, - ) - # Assert - self.assertEqual(response_asc.status_code, 200) - self.assertEqual(len(response_asc.json["results"]), 3) - self.assertListEqual( - [i["projectId"] for i in response_asc.json["results"]], - expected_desc_order[::-1], - ) - - def test_returns_sorted_projects_by_due_date_if_sort_by_set_to_due_date(self): - """ - Test returns sorted projects by due_date if sort_by set to due_date. - """ - # Arrange - self.test_project_1.due_date = datetime.utcnow() + timedelta(days=1) - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.due_date = datetime.utcnow() + timedelta(days=2) - self.test_project_2.private = False - self.test_project_2.save() - # Set status of test_project_3 to published. - self.test_project_3.due_date = datetime.utcnow() + timedelta(days=3) - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - - # Test returns sorted projects by descending order. - # Act - response_desc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "due_date", "orderByType": "DESC"}, - ) - # Assert - self.assertEqual(response_desc.status_code, 200) - self.assertEqual(len(response_desc.json["results"]), 3) - expected_desc_order = [ - self.test_project_3.id, - self.test_project_2.id, - self.test_project_1.id, - ] - self.assertListEqual( - [i["projectId"] for i in response_desc.json["results"]], expected_desc_order - ) - - # Test returns sorted projects by due_date in ascending order. - # Act - response_asc = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"orderBy": "due_date", "orderByType": "ASC"}, - ) - # Assert - self.assertEqual(response_asc.status_code, 200) - self.assertEqual(len(response_asc.json["results"]), 3) - self.assertListEqual( - [i["projectId"] for i in response_asc.json["results"]], - expected_desc_order[::-1], - ) - - def test_returns_projects_filter_by_statuses(self): - """ - Test returns projects filter by projectStatuses. - """ - # Arrange - self.test_project_1.status = ProjectStatus.DRAFT.value - self.test_project_1.save() - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.private = False - self.test_project_2.save() - # Set status of test_project_3 to archived. - self.test_project_3.status = ProjectStatus.ARCHIVED.value - self.test_project_3.save() - - # Act - response_pub = self.client.get( - self.url, - headers={"Authorization": self.author_session_token}, - query_string={"projectStatuses": [ProjectStatus.PUBLISHED.name]}, - ) - # Assert - self.assertEqual(response_pub.status_code, 200) - self.assertEqual(len(response_pub.json["results"]), 1) - self.assertEqual( - response_pub.json["results"][0]["projectId"], self.test_project_2.id - ) - - # Act - response_draft = self.client.get( - self.url, - headers={"Authorization": self.author_session_token}, - query_string={"projectStatuses": [ProjectStatus.DRAFT.name]}, - ) - # Assert - self.assertEqual(response_draft.status_code, 200) - self.assertEqual(len(response_draft.json["results"]), 1) - self.assertEqual( - response_draft.json["results"][0]["projectId"], self.test_project_1.id - ) - - # Act - response_archived = self.client.get( - self.url, - headers={"Authorization": self.author_session_token}, - query_string={"projectStatuses": [ProjectStatus.ARCHIVED.name]}, - ) - # Assert - self.assertEqual(response_archived.status_code, 200) - self.assertEqual(len(response_archived.json["results"]), 1) - self.assertEqual( - response_archived.json["results"][0]["projectId"], self.test_project_3.id - ) - - # Test multiple statuses returns all projects with those statuses. - # Act - response_all = self.client.get( - self.url, - headers={"Authorization": self.author_session_token}, - query_string={ - "projectStatuses": "PUBLISHED,DRAFT,ARCHIVED", - }, - ) - # Assert - self.assertEqual(response_all.status_code, 200) - self.assertEqual(len(response_all.json["results"]), 3) - self.assertListEqual( - [i["projectId"] for i in response_all.json["results"]], - [self.test_project_1.id, self.test_project_2.id, self.test_project_3.id], - ) - - @staticmethod - def create_cloned_project_with_mapping_types(project_id, author_id, mapping_types): - """ - Create a cloned project with mapping types. - """ - test_project = Project.clone(project_id, author_id) - test_project.mapping_types = mapping_types - test_project.status = ProjectStatus.PUBLISHED.value - test_project.save() - return test_project - - def test_returns_projects_filter_by_mapping_types(self): - """ - Test returns projects filter by mappingTypes. - """ - # Arrange - self.test_project_1.mapping_types = [MappingTypes.BUILDINGS.value] - self.test_project_1.save() - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.mapping_types = [MappingTypes.ROADS.value] - self.test_project_2.private = False - self.test_project_2.save() - # Set mapping type of test_project_3 to waterways. - self.test_project_3.mapping_types = [MappingTypes.WATERWAYS.value] - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - # Create a new project with other mapping type. - - test_project_4 = TestProjectsAllAPI.create_cloned_project_with_mapping_types( - self.test_project_3.id, self.test_author.id, [MappingTypes.LAND_USE.value] - ) - # Create a new project with land use mapping type. - test_project_5 = TestProjectsAllAPI.create_cloned_project_with_mapping_types( - self.test_project_3.id, self.test_author.id, [MappingTypes.OTHER.value] - ) - # Create a new project with all mapping types. - test_project_6 = TestProjectsAllAPI.create_cloned_project_with_mapping_types( - self.test_project_3.id, - self.test_author.id, - [ - MappingTypes.BUILDINGS.value, - MappingTypes.ROADS.value, - MappingTypes.WATERWAYS.value, - MappingTypes.LAND_USE.value, - MappingTypes.OTHER.value, - ], - ) - - # Act - response_buildings = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"mappingTypes": [MappingTypes.BUILDINGS.name]}, - ) - # Assert - self.assertEqual(response_buildings.status_code, 200) - self.assertEqual(len(response_buildings.json["results"]), 2) - self.assertListEqual( - [i["projectId"] for i in response_buildings.json["results"]], - [self.test_project_1.id, test_project_6.id], - ) - - # Act - response_roads = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"mappingTypes": [MappingTypes.ROADS.name]}, - ) - # Assert - self.assertEqual(response_roads.status_code, 200) - self.assertEqual(len(response_roads.json["results"]), 2) - self.assertListEqual( - [i["projectId"] for i in response_roads.json["results"]], - [self.test_project_2.id, test_project_6.id], - ) - - # Act - response_waterways = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"mappingTypes": [MappingTypes.WATERWAYS.name]}, - ) - # Assert - self.assertEqual(response_waterways.status_code, 200) - self.assertEqual(len(response_waterways.json["results"]), 2) - self.assertListEqual( - [i["projectId"] for i in response_waterways.json["results"]], - [self.test_project_3.id, test_project_6.id], - ) - - # Act - response_land_use = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"mappingTypes": [MappingTypes.LAND_USE.name]}, - ) - # Assert - self.assertEqual(response_land_use.status_code, 200) - self.assertEqual(len(response_land_use.json["results"]), 2) - self.assertListEqual( - [i["projectId"] for i in response_land_use.json["results"]], - [test_project_4.id, test_project_6.id], - ) - - # Act - response_other = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"mappingTypes": [MappingTypes.OTHER.name]}, - ) - # Assert - self.assertEqual(response_other.status_code, 200) - self.assertEqual(len(response_other.json["results"]), 2) - self.assertListEqual( - [i["projectId"] for i in response_other.json["results"]], - [test_project_5.id, test_project_6.id], - ) - - # Test filter by multiple mapping types returns projects with any of the mapping types in the list. - # Act - response_all = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"mappingTypes": "BUILDINGS,ROADS,WATERWAYS,LAND_USE,OTHER"}, - ) - # Assert - self.assertEqual(response_all.status_code, 200) - self.assertEqual(len(response_all.json["results"]), 6) - - # Test mappingTypesExact returns only projects with exact mapping types. - # Act - response_exact = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"mappingTypes": "BUILDINGS", "mappingTypesExact": "true"}, - ) - # Assert - self.assertEqual(response_exact.status_code, 200) - self.assertEqual(len(response_exact.json["results"]), 1) - self.assertEqual( - response_exact.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_projects_filtered_by_organisation(self): - # Arrange - test_org_1 = create_canned_organisation() - test_org_2 = return_canned_organisation(12, "test_org_2", "T2") - test_org_2.create() - - self.test_project_1.organisation_id = test_org_1.id - self.test_project_1.save() - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.private = False - self.test_project_2.organisation_id = test_org_2.id - self.test_project_2.save() - - # Test organisationId filters projects by organisation. - # Act - response_org_id = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"organisationId": test_org_1.id}, - ) - # Assert - self.assertEqual(response_org_id.status_code, 200) - self.assertEqual(len(response_org_id.json["results"]), 1) - self.assertEqual( - response_org_id.json["results"][0]["projectId"], self.test_project_1.id - ) - - # Test organisationName filters projects organisation. - # Act - response_org_name = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"organisationName": test_org_2.name}, - ) - # Assert - self.assertEqual(response_org_name.status_code, 200) - self.assertEqual(len(response_org_name.json["results"]), 1) - self.assertEqual( - response_org_name.json["results"][0]["projectId"], self.test_project_2.id - ) - - def test_returns_projects_filtered_by_campaign(self): - # Arrange - test_campaign_1 = return_canned_campaign(10, "test_campaign_1") - test_campaign_1.create() - test_campaign_2 = return_canned_campaign(12, "test_campaign_2") - test_campaign_2.create() - - campaign_dto = CampaignProjectDTO() - campaign_dto.campaign_id = test_campaign_1.id - campaign_dto.project_id = self.test_project_1.id - CampaignService.create_campaign_project(campaign_dto) - - campaign_dto.campaign_id = test_campaign_2.id - campaign_dto.project_id = self.test_project_2.id - CampaignService.create_campaign_project(campaign_dto) - # Set project_2 to be allowed for all users removing as private. - self.test_project_2.private = False - self.test_project_2.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"campaign": test_campaign_1.name}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_projects_filtered_by_search(self): - # Arrange - self.test_project_1.name = "test_project_1" - self.test_project_1.save() - test_project_4, _ = create_canned_project(name="test_project_4") - test_project_4.status = ProjectStatus.PUBLISHED.value - test_project_4.save() - - # Test text search by project name - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"textSearch": "test_project_4"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - # Since all other projects are named test by default on test_helpers, only project_4 should be returned. - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual(response.json["results"][0]["projectId"], test_project_4.id) - - # Test project search by project Id - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"textSearch": self.test_project_1.id}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_projects_filtered_by_country(self): - # Arrange - self.test_project_1.country = ["England"] - self.test_project_1.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"country": self.test_project_1.country}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_projects_filtering_by_last_updated_param(self): - # Arrange - self.test_project_1.last_updated = datetime.utcnow() - timedelta(minutes=10) - self.test_project_1.save() - self.test_project_2.private = False - self.test_project_2.last_updated = datetime.utcnow() - timedelta(days=2) - self.test_project_2.save() - self.test_project_3.last_updated = datetime.utcnow() - timedelta(days=3) - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - - # Test last updated from filterf returns projects updated after the date - # Act - response_from = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"lastUpdatedFrom": self.test_project_1.last_updated.date()}, - ) - # Assert - self.assertEqual(response_from.status_code, 200) - self.assertEqual(len(response_from.json["results"]), 1) - self.assertEqual( - response_from.json["results"][0]["projectId"], self.test_project_1.id - ) - - # Test last updated from filter returns projects updated before the date - # Act - response_to = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "lastUpdatedTo": (datetime.utcnow() - timedelta(days=1)).date() - }, - ) - # Assert - self.assertEqual(response_to.status_code, 200) - self.assertEqual(len(response_to.json["results"]), 2) - self.assertNotIn( - self.test_project_1.id, - [i["projectId"] for i in response_to.json["results"]], - ) - - def test_returns_projects_filtering_by_last_created_param(self): - # Arrange - self.test_project_1.created = datetime.utcnow() - timedelta(minutes=10) - self.test_project_1.save() - self.test_project_2.private = False - self.test_project_2.created = datetime.utcnow() - timedelta(days=2) - self.test_project_2.save() - self.test_project_3.created = datetime.utcnow() - timedelta(days=3) - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - - # Test created from filter returns projects created after the date - # Act - response_from = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"createdFrom": self.test_project_1.created.date()}, - ) - # Assert - self.assertEqual(response_from.status_code, 200) - self.assertEqual(len(response_from.json["results"]), 1) - self.assertEqual( - response_from.json["results"][0]["projectId"], self.test_project_1.id - ) - - # Test created from filter returns projects created before the date - # Act - response_to = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"createdTo": (datetime.utcnow() - timedelta(days=1)).date()}, - ) - # Assert - self.assertEqual(response_to.status_code, 200) - self.assertEqual(len(response_to.json["results"]), 2) - self.assertNotIn( - self.test_project_1.id, - [i["projectId"] for i in response_to.json["results"]], - ) - - def returns_filtered_projects_by_interests(self): - # Arrange - test_interest_1 = create_canned_interest("test_interest_1") - test_interest_2 = create_canned_interest("test_interest_2") - test_interest_3 = create_canned_interest("test_interest_3") - - InterestService.create_or_update_project_interests( - self.test_project_1.id, [test_interest_1.id, test_interest_2.id] - ) - InterestService.create_or_update_project_interests( - self.test_project_2.id, [test_interest_2.id] - ) - InterestService.create_or_update_project_interests( - self.test_project_3.id, [test_interest_3.id] - ) - - # Make sure all projects can be accessed by the user - self.test_project_2.private = False - self.test_project_2.save() - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - - # Act - # Test filter by single interest returns projects with that interest - response_single = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"interests": test_interest_2.name}, - ) - # Assert - self.assertEqual(response_single.status_code, 200) - self.assertEqual(len(response_single.json["results"]), 1) - self.assertEqual( - response_single.json["results"][0]["projectId"], self.test_project_1.id - ) - - # Test filter by multiple interests returns projects with union of interests provided - # Act - response_multiple = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "interests": f"{test_interest_1.name},{test_interest_2.name}" - }, - ) - # Assert - self.assertEqual(response_multiple.status_code, 200) - self.assertEqual(len(response_multiple.json["results"]), 2) - self.assertNotIn( - self.test_project_3.id, - [i["projectId"] for i in response_multiple.json["results"]], - ) - - def test_returns_projects_created_by_me(self): - # Arrange - self.test_project_1.author_id = self.test_user.id - self.test_project_1.save() - self.test_project_2.private = False - self.test_project_2.save() - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"createdByMe": "true"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_projects_managed_by_me(self): - """ - Test that the endpoint returns projects managed by the user i.e user must have PM role on the project - """ - # Arrange - # test_user is the member of team that has PM role in test_project_1 so it must be returned - test_organisation_1 = return_canned_organisation( - 111, "test_organisation_2", "T2" - ) - test_organisation_1.create() - test_team = return_canned_team("test_team", test_organisation_1.name) - add_user_to_team( - test_team, self.test_user, TeamMemberFunctions.MEMBER.value, True - ) - assign_team_to_project( - self.test_project_1, test_team, TeamRoles.PROJECT_MANAGER.value - ) - - # test_user is the manager of organisation that test_project_2 belongs to so it must be returned - test_organisation_2 = create_canned_organisation() - add_manager_to_organisation(test_organisation_2, self.test_user) - self.test_project_2.organisation_id = test_organisation_2.id - self.test_project_2.private = False - self.test_project_2.save() - - # test_user doesn't have PM role on test_project_3 so it must not be returned - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.organisation_id = test_organisation_1.id - self.test_project_3.save() - - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"managedByMe": "true"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 2) - self.assertNotIn( - self.test_project_3.id, - [i["projectId"] for i in response.json["results"]], - ) - - def test_returns_all_projects_for_admin_if_managed_by_me_is_true(self): - """ - Test all projects are returned for admin if managedByMe is true - """ - # Arrange - self.test_project_2.private = False - self.test_project_2.save() - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response_admin = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"managedByMe": "true"}, - ) - self.assertEqual(response_admin.status_code, 200) - self.assertEqual(len(response_admin.json["results"]), 3) - - def test_returns_projects_mapped_by_user_if_mapped_by_me_is_true(self): - """ - Test all projects are returned for admin if managedByMe is true - """ - # Arrange - # Make all projects to be accessible for user - self.test_project_2.private = False - self.test_project_2.save() - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - self.test_user.projects_mapped = [self.test_project_1.id] - self.test_user.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"mappedByMe": "true"}, - ) - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_returns_projects_favourited_by_user_if_favourited_by_me_is_true(self): - """ - Test all projects are returned for admin if managedByMe is true - """ - # Arrange - # Make all projects to be accessible for user - self.test_project_2.private = False - self.test_project_2.save() - self.test_project_3.status = ProjectStatus.PUBLISHED.value - self.test_project_3.save() - self.test_user.favorites = [self.test_project_1] - self.test_user.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"favoritedByMe": "true"}, - ) - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) - self.assertEqual( - response.json["results"][0]["projectId"], self.test_project_1.id - ) - - def test_omit_map_results_removes_mao_results_from_response(self): - """ - Test omitMapResults removes map results from response - """ - # Test map_results is not present if omitMapResults is set to true - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"omitMapResults": "true"}, - ) - self.assertEqual(response.status_code, 200) - self.assertListEqual(response.json["mapResults"], []) - - # Test map_results are present if omitMapResults is set to false - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"omitMapResults": "false"}, - ) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["mapResults"]["type"], "FeatureCollection") - - -class TestSearchProjectByBBOX(BaseTestCase): - def setUp(self): - super().setUp() - self.url = "/api/v2/projects/queries/bbox/" - self.test_user = return_canned_user(TEST_USER_USERNAME, TEST_USER_ID) - self.test_user.create() - self.test_project_1, self.test_author = create_canned_project() - self.test_project_1.status = ProjectStatus.PUBLISHED.value - self.test_project_1.save() - self.test_project_2, _ = create_canned_project() - self.test_project_2.status = ProjectStatus.PUBLISHED.value - self.test_project_2.save() - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_returns_401_if_user_not_logged_in(self): - """ - Test 403 is returned if user is not logged in - """ - # Act - response = self.client.get(self.url) - self.assertEqual(response.status_code, 401) - - def test_returns_403_if_user_doesnt_have_PM_role(self): - """ - Test 403 is returned if user is not logged in - """ - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - self.assertEqual(response.status_code, 403) - - def test_returns_400_if_bbox_is_not_valid(self): - """ - Test 400 is returned if bbox is not valid - """ - # Arrange - # This endpoint is only accessible to org managers and admins, so we need to add the user to an organisation. - test_organisation = create_canned_organisation() - add_manager_to_organisation(test_organisation, self.test_user) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"bbox": "1,2,3,100,200,3", "srid": 4326}, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_returns_400_if_bbox_too_large(self): - """ - Test 400 is returned if bbox is too large - """ - # Arrange - # This endpoint is only accessible to org managers and admins, so we need to add the user to an organisation. - test_organisation = create_canned_organisation() - add_manager_to_organisation(test_organisation, self.test_user) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"bbox": "-17,-30,102,70", "srid": 4326}, - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "BBoxTooBigError") - - def test_returns_projects_within_bbox(self): - """ - Test projects within bbox are returned - """ - # Arrange - # Create a project outside bbox - draft_project_dto = DraftProjectDTO() - draft_project_dto.area_of_interest = { - "type": "FeatureCollection", - "features": [ - { - "type": "Feature", - "geometry": { - "coordinates": [ - [ - [83.771175, 28.095768], - [83.773586, 28.095757], - [83.773428, 28.094146], - [83.770834, 28.094479], - [83.771175, 28.095768], - ] - ], - "type": "Polygon", - }, - } - ], - } - self.test_project_2.save() - self.test_project_2.set_project_aoi(draft_project_dto) - test_organisation = create_canned_organisation() - add_manager_to_organisation(test_organisation, self.test_user) - # Act - response = self.client.get( - self.url, - headers={ - "Authorization": self.user_session_token, - " Accept-Language": "en", - }, - query_string={ - "bbox": "-3.993530,56.095790,-3.890533,56.129480", - "srid": 4326, - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["features"]), 1) - self.assertEqual( - response.json["features"][0]["properties"]["projectId"], - self.test_project_1.id, - ) - - -class TestProjectsQueriesSummaryAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.private = True - self.test_project.save() - self.url = f"/api/v2/projects/{self.test_project.id}/queries/summary/" - - def test_authentication_is_not_required(self): - """ - Test authentication is not required - """ - # Act - response = self.client.get(self.url) - self.assertEqual(response.status_code, 200) - - def test_returns_404_if_project_doesnt_exist(self): - """ - Test 404 is returned if project doesn't exist - """ - # Act - response = self.client.get("/api/v2/projects/999/queries/summary/") - self.assertEqual(response.status_code, 404) - - def test_project_summary_response(self): - """ - Test project summary response - """ - # Arrange - json_data = get_canned_json("canned_project_detail.json") - project_update_dto = ProjectDTO(json_data) - create_canned_organisation() - self.test_project.update(project_update_dto) - - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response( - response.json, self.test_project, assert_type="summary" - ) - - -class TestProjectsQueriesTouchedAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.private = False - self.test_project.save() - self.test_project_1, _ = create_canned_project() - self.test_project_1.status = ProjectStatus.PUBLISHED.value - self.test_project_1.save() - task = Task.get(1, self.test_project.id) - task.lock_task_for_validating(self.test_author.id) - task.unlock_task(self.test_author.id, TaskStatus.VALIDATED) - self.test_author.projects_mapped = [self.test_project.id] - self.test_author.save() - self.url = f"/api/v2/projects/queries/{self.test_author.username}/touched/" - - def test_authentication_is_not_required(self): - """ - Test authentication is not required - """ - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["mappedProjects"]), 1) - self.assertEqual( - response.json["mappedProjects"][0]["projectId"], - self.test_project.id, - ) - - def test_returns_404_if_user_doesnt_exist(self): - """ - Test 404 is returned if project doesn't exist - """ - # Act - response = self.client.get("/api/v2/projects/queries/non_existent/touched/") - self.assertEqual(response.status_code, 404) - - -class TestProjectsQueriesPriorityAreasAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.private = False - self.test_project.save() - self.url = f"/api/v2/projects/{self.test_project.id}/queries/priority-areas/" - - def returns_404_if_project_doesnt_exist(self): - """ - Test 404 is returned if project doesn't exist - """ - # Act - response = self.client.get("/api/v2/projects/999/queries/priority-areas/") - self.assertEqual(response.status_code, 404) - - def test_authentication_is_not_required(self): - """ - Test authentication is not required - """ - # Arrange - json_data = get_canned_json("canned_project_detail.json") - project_update_dto = ProjectDTO(json_data) - create_canned_organisation() - self.test_project.update(project_update_dto) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json), 1) - self.assertDeepAlmostEqual( - response.json[0], json_data["priorityAreas"][0], places=6 - ) - - -class TestProjectsQueriesAoiAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.private = False - self.test_project.save() - self.url = f"/api/v2/projects/{self.test_project.id}/queries/aoi/" - - def test_returns_404_if_project_doesnt_exist(self): - """ - Test 404 is returned if project doesn't exist - """ - # Act - response = self.client.get("/api/v2/projects/999/queries/aoi/") - self.assertEqual(response.status_code, 404) - - def test_authentication_is_not_required(self): - """ - Test authentication is not required - """ - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json, self.test_project.get_aoi_geometry_as_geojson()) - - def test_returns_file_if_as_file_is_true(self): - """ - Test authentication is not required - """ - # Act - response = self.client.get(self.url + "?as_file=true") - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json, self.test_project.get_aoi_geometry_as_geojson()) - self.assertEqual(response.headers["Content-Type"], "application/json") - self.assertEqual( - response.headers["Content-Disposition"], - f"attachment; filename={self.test_project.id}.geojson", - ) - - -class TestProjectsQueriesOwnerAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_organisation = create_canned_organisation() - # Add organisation to project - self.test_project.organisation = self.test_organisation - self.test_project.save() - self.test_user = return_canned_user(TEST_USER_USERNAME, TEST_USER_ID) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.author_session_token = generate_encoded_token(self.test_author.id) - self.url = "/api/v2/projects/queries/myself/owner/" - - def test_returns_401_if_user_not_logged_in(self): - """ - Test 403 is returned if user is not logged in - """ - # Act - response = self.client.get(self.url) - self.assertEqual(response.status_code, 401) - - def test_returns_403_if_user_doesnt_have_PM_role(self): - """ - Test 403 is returned if user doesn't have PM role - """ - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - self.assertEqual(response.status_code, 403) - - def test_returns_200_if_user_org_manager(self): - """ - Test 200 is returned if user has a project owned - """ - # Add user to organisation so that it has PM role - add_manager_to_organisation(self.test_organisation, self.test_author) - # Act - response = self.client.get( - self.url, headers={"Authorization": self.author_session_token} - ) - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["activeProjects"]), 1) - - -class TestProjectsQueriesNoTasksAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_organisation = create_canned_organisation() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.organisation = self.test_organisation - self.test_project.save() - self.test_user = return_canned_user(TEST_USER_USERNAME, TEST_USER_ID) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.author_session_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/queries/notasks/" - - def test_returns_401_if_user_not_logged_in(self): - """ - Test 403 is returned if user is not logged in - """ - # Act - response = self.client.get(self.url) - self.assertEqual(response.status_code, 401) - - def test_returns_403_if_user_doesnt_have_PM_role(self): - """ - Test 403 is returned if user doesn't have PM role - """ - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - self.assertEqual(response.status_code, 403) - - def test_returns_404_if_project_doesnt_exist(self): - """ - Test 404 is returned if project doesn't exist - """ - # Act - response = self.client.get( - "/api/v2/projects/999/queries/notasks/", - headers={"Authorization": self.user_session_token}, - ) - self.assertEqual(response.status_code, 404) - - def test_returns_200_for_admin(self): - """ - Test 200 is returned if user is admin - """ - # Authenticated user with that is a admin - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response( - response.json, self.test_project, assert_type="notasks" - ) - - def test_returns_200_if_user_org_manager(self): - """ - Test 200 is returned if user is org manager - """ - # Arrange - self.test_user.role = UserRole.MAPPER.value # Make sure user role is Mapper - self.test_user.save() - add_manager_to_organisation(self.test_project.organisation, self.test_user) - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response( - response.json, self.test_project, assert_type="notasks" - ) - - def test_returns_200_if_user_team_member(self): - """ - Test 200 is returned if user is member of team associated with project - """ - # Arrange - # Create a team and add user to it - test_team = create_canned_team() - add_user_to_team( - test_team, self.test_user, TeamMemberFunctions.MEMBER.value, True - ) - # Assign team to project - assign_team_to_project( - self.test_project, test_team, TeamRoles.PROJECT_MANAGER.value - ) - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - TestGetProjectsRestAPI.assert_project_response( - response.json, self.test_project, assert_type="notasks" - ) - - -class TestProjectQueriesSimilarProjectsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.save() - # Since project_info is required to retrun project summary in the response - update_project_with_info(self.test_project) - self.url = f"/api/v2/projects/queries/{self.test_project.id}/similar-projects/" - self.user_session_token = generate_encoded_token(self.test_author.id) - - def create_project(self, status=ProjectStatus.PUBLISHED.value): - project, _ = create_canned_project() - project.status = status - project.save() - return project - - def arrange_projects(self): - # Create test projects - project_1 = self.create_project() - project_2 = self.create_project() - project_3 = self.create_project() - self.create_project(ProjectStatus.DRAFT.value) - # Since project_info is required to retrun project summary in the response - update_project_with_info(project_1) - update_project_with_info(project_2) - update_project_with_info(project_3) - return project_1, project_2, project_3 - - def test_private_projects_are_not_returned_if_user_not_logged_in(self): - """ - Test private projects are not returned if user is not logged in - """ - # Arrange - # Create and arrange test projects - project_1, project_2, project_3 = self.arrange_projects() - project_3.private = True - project_3.save() - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 2) - self.assertEqual(response.json["results"][0]["projectId"], project_2.id) - self.assertEqual(response.json["results"][1]["projectId"], project_1.id) - - def test_returns_404_if_project_doesnt_exist(self): - """ - Test 404 is returned if project doesn't exist - """ - # Act - response = self.client.get( - "/api/v2/projects/queries/999/similar-projects/", - headers={"Authorization": self.user_session_token}, - ) - self.assertEqual(response.status_code, 404) - - def test_returns_private_projects_if_user_is_allowed(self): - """ - Test private projects are returned if user is author of project - """ - # Arrange - # Create and arrange test projects - project_1, project_2, project_3 = self.arrange_projects() - project_3.private = True - project_3.save() - self.test_author.role = UserRole.ADMIN.value - self.test_author.save() - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 3) - returned_project_ids = sorted( - [i["projectId"] for i in response.json["results"]] - ) - self.assertEqual( - returned_project_ids, [project_1.id, project_2.id, project_3.id] - ) - - def test_returns_limit_projects(self): - """ - Test limit is applied to projects returned - """ - # Arrange - # Create and arrange test projects - self.arrange_projects() - # Act - response = self.client.get( - f"{self.url}?limit=1", headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["results"]), 1) diff --git a/tests/backend/integration/api/projects/test_statistics.py b/tests/backend/integration/api/projects/test_statistics.py deleted file mode 100644 index 150fb00da4..0000000000 --- a/tests/backend/integration/api/projects/test_statistics.py +++ /dev/null @@ -1,99 +0,0 @@ -import time - -from backend.models.postgis.task import Task, TaskStatus -from backend.services.project_admin_service import ProjectAdminService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_project, - generate_encoded_token, -) - - -class TestProjectStatisticsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_session_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/statistics/" - - def test_returns_404_if_project_not_found(self): - """Test that 404 is returned if project not found""" - # Act - response = self.client.get("/api/v2/projects/9999999999/statistics/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_200_if_project_found(self): - """Test that 200 is returned if project found""" - # Arrange - # Let's reset all tasks to Ready state - ProjectAdminService.reset_all_tasks(self.test_project.id, self.test_author.id) - task = Task.get(1, self.test_project.id) - task.lock_task_for_mapping(self.test_author.id) - time.sleep(3) - task.unlock_task(self.test_author.id, TaskStatus.MAPPED) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["totalTasks"], 4) - self.assertEqual( - response.json["totalMappingTime"], 3.0 - ) # Since we slept for 3 seconds - self.assertEqual( - response.json["totalTimeSpent"], 3.0 - ) # Since we slept for 3 seconds - # Since we slept for 3 seconds and only 1 task was mapped - self.assertEqual(response.json["averageMappingTime"], 3.0) - self.assertEqual(response.json["timeToFinishMapping"], 12.0) - self.assertEqual( - response.json["timeToFinishValidating"], 0.0 - ) # No tasks were validated - - -class TestProjectsStatisticsQueriesUsernameAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_session_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/statistics/queries/{self.test_author.username}/" - - def test_returns_404_if_project_not_found(self): - """Test that 404 is returned if project not found""" - # Act - response = self.client.get( - f"/api/v2/projects/9999999999/statistics/queries/{self.test_author.username}/" - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_404_if_username_not_found(self): - """Test that 404 is returned if username not found""" - # Act - response = self.client.get( - f"/api/v2/projects/{self.test_project.id}/statistics/queries/username/" - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_200_if_project_found(self): - """Test that 200 is returned if project and username found""" - # Arrange - task = Task.get(1, self.test_project.id) - task.lock_task_for_mapping(self.test_author.id) - # Let's sleep for 3 seconds which will be used to calculate time spent - time.sleep(3) - task.unlock_task(self.test_author.id, TaskStatus.MAPPED) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual( - response.json["timeSpentMapping"], 3.0 - ) # Since we slept for 3 seconds - self.assertEqual( - response.json["timeSpentValidating"], 0.0 - ) # No tasks were validated - self.assertEqual( - response.json["totalTimeSpent"], 3.0 - ) # Since we slept for 3 seconds diff --git a/tests/backend/integration/api/system/__init__.py b/tests/backend/integration/api/system/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/system/test_authentication.py b/tests/backend/integration/api/system/test_authentication.py deleted file mode 100644 index 05590e6e0a..0000000000 --- a/tests/backend/integration/api/system/test_authentication.py +++ /dev/null @@ -1,288 +0,0 @@ -from unittest.mock import patch -from urllib import parse - -from oauthlib.oauth2.rfc6749.errors import InvalidGrantError - -from backend import osm -from backend.config import EnvironmentConfig -from backend.services.messaging.message_service import MessageService -from backend.services.messaging.smtp_service import SMTPService -from backend.services.users.authentication_service import AuthenticationService -from backend.services.users.user_service import NotFound, UserService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import return_canned_user -from tests.backend.integration.api.users.test_resources import ( - USER_NOT_FOUND_MESSAGE, - USER_NOT_FOUND_SUB_CODE, -) - -USERNAME = "test_user" -USER_ID = 1234 -USER_PICTURE = "test_href" -USER_EMAIL = "test_email" - -USER_JSON = { - "user": { - "id": USER_ID, - "display_name": USERNAME, - "changesets": {"count": 0}, - "img": {"href": USER_PICTURE}, - } -} - - -class TestSystemAuthenticationLoginAPI(BaseTestCase): - # Define environment variables for testing so that tests don't fail due to missing env variables - EnvironmentConfig.OAUTH_CLIENT_ID = "test_client_id" - EnvironmentConfig.OAUTH_REDIRECT_URI = "test_redirect_uri" - EnvironmentConfig.OAUTH_SCOPE = "read_prefs write_api" - - def test_get_login_url(self): - """Test correct login url is returned""" - # Arrange - url = "/api/v2/system/authentication/login/" - # Set osm params to test values so that we can assert them later - osm.client_id = EnvironmentConfig.OAUTH_CLIENT_ID - osm.redirect_uri = EnvironmentConfig.OAUTH_REDIRECT_URI - osm.scope = EnvironmentConfig.OAUTH_SCOPE - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertIsNotNone(response.json["auth_url"]) - self.assertIsNotNone(response.json["state"]) - self.assertEqual( - response.json["auth_url"].split("?")[0], - EnvironmentConfig.OSM_SERVER_URL + "/oauth2/authorize", - ) - self.assertEqual( - response.json["auth_url"].split("?")[1].split("&")[0], "response_type=code" - ) - self.assertEqual( - response.json["auth_url"].split("?")[1].split("&")[1], - "client_id=" + EnvironmentConfig.OAUTH_CLIENT_ID, - ) - self.assertEqual( - response.json["auth_url"].split("?")[1].split("&")[2], - "redirect_uri=" + parse.quote_plus(EnvironmentConfig.OAUTH_REDIRECT_URI), - ) - self.assertEqual( - response.json["auth_url"].split("?")[1].split("&")[3], - "scope=" + ("+").join(EnvironmentConfig.OAUTH_SCOPE.split(" ")), - ) - self.assertEqual( - response.json["auth_url"].split("?")[1].split("&")[4], - "state=" + response.json["state"], - ) - - -class TestSystemAuthenticationCallbackAPI(BaseTestCase): - def test_returns_error_if_code_not_passed(self): - url = "/api/v2/system/authentication/callback/" - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - self.assertEqual(response.json["Error"], "Missing code parameter") - - @patch.object(osm, "fetch_token") - def test_returns_error_if_invalid_grant(self, mock_fetch_token): - mock_fetch_token.side_effect = InvalidGrantError - url = "/api/v2/system/authentication/callback/?code=1234" - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidGrantError") - self.assertEqual( - response.json["Error"], - "The provided authorization grant is invalid, expired or revoked", - ) - - @patch.object(osm, "fetch_token") - def test_returns_error_if_osm_response_is_none(self, mock_fetch_token): - mock_fetch_token.return_value = None - url = "/api/v2/system/authentication/callback/?code=1234" - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 502) - self.assertEqual(response.json["SubCode"], "TokenFetchError") - self.assertEqual(response.json["Error"], "Couldn't fetch token from OSM.") - - @patch.object(osm, "fetch_token") - @patch.object(osm, "get") - def test_returns_error_if_osm_response_status_code_not_200( - self, mock_get, mock_fetch_token - ): - mock_fetch_token.return_value = "1234" - mock_get.return_value.status_code = 500 - url = "/api/v2/system/authentication/callback/?code=1234" - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 502) - self.assertEqual(response.json["SubCode"], "OSMServiceError") - self.assertEqual( - response.json["Error"], "Couldn't fetch user details from OSM." - ) - - @patch.object(osm, "fetch_token") - @patch.object(osm, "get") - def test_returns_error_if_auth_service_error(self, mock_get, mock_fetch_token): - mock_fetch_token.return_value = "1234" - mock_get.return_value.status_code = 200 - mock_get.return_value.json.return_value = {} - url = "/api/v2/system/authentication/callback/?code=1234" - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 500) - self.assertEqual(response.json["SubCode"], "AuthError") - self.assertEqual(response.json["Error"], "Unable to authenticate") - - @patch.object(MessageService, "send_welcome_message") - @patch.object(osm, "fetch_token") - @patch.object(osm, "get") - def test_returns_user_params_if_no_auth_service_error( - self, mock_get, mock_fetch_token, mock_send_welcome_message - ): - # Arrange - user = return_canned_user(USERNAME, USER_ID) - user.create() - mock_fetch_token.return_value = USER_ID - mock_get.return_value.status_code = 200 - mock_get.return_value.json.return_value = USER_JSON - url = "/api/v2/system/authentication/callback/?code=1234" - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["username"], user.username) - self.assertEqual(response.json["session"], user.id) - self.assertEqual(response.json["picture"], USER_PICTURE) - mock_send_welcome_message.assert_not_called() - - @patch.object(MessageService, "send_welcome_message") - @patch.object(osm, "fetch_token") - @patch.object(osm, "get") - def test_creates_user_on_login_if_not_exists( - self, mock_get, mock_fetch_token, mock_send_welcome_message - ): - mock_fetch_token.return_value = USER_ID - mock_get.return_value.status_code = 200 - mock_get.return_value.json.return_value = USER_JSON - url = ( - "/api/v2/system/authentication/callback/?code=1234&email_address=test_email" - ) - # Assert - with self.assertRaises(NotFound): - UserService.get_user_by_username( - USERNAME - ) # Should raise NotFound since user doesn't exist - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["username"], USERNAME) - self.assertEqual(response.json["session"], USER_ID) - self.assertEqual(response.json["picture"], USER_PICTURE) - self.assertEqual( - UserService.get_user_by_username(USERNAME).email_address, "test_email" - ) - mock_send_welcome_message.assert_called_once() - - -class TestSystemAuthenticationEmailAPI(BaseTestCase): - def setUp(self): - self.url = "/api/v2/system/authentication/email/" - return super().setUp() - - def test_returns_404_if_user_does_not_exist(self): - # Act - response = self.client.get( - self.url, query_string={"username": "non_existent_user"} - ) - error_details = response.json["error"] - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["sub_code"], USER_NOT_FOUND_SUB_CODE) - self.assertEqual(error_details["message"], USER_NOT_FOUND_MESSAGE) - - def test_returns_403_if_invalid_email_token(self): - # Arrange - user = return_canned_user(USERNAME, USER_ID) - user.create() - # Act - response = self.client.get( - self.url, query_string={"token": "1234", "username": USERNAME} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "BadSignature") - self.assertEqual(response.json["Error"], " Bad Token Signature") - - @patch.object(AuthenticationService, "is_valid_token") - def test_returns_403_if_expired_email_token(self, mock_is_valid_token): - # Arrange - # Since the token is only expired if it's older than 1 day, we need to mock the function to return False - mock_is_valid_token.return_value = (False, "ExpiredToken- Token has expired") - user = return_canned_user(USERNAME, USER_ID) - user.create() - verification_url = SMTPService._generate_email_verification_url( - USER_EMAIL, USERNAME - ) - token = verification_url.split("token=")[1].split("&")[0] - # Act - response = self.client.get( - self.url, query_string={"token": token, "username": USERNAME} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "ExpiredToken") - self.assertEqual(response.json["Error"], " Token has expired") - - def test_returns_403_if_token_and_email_mismatch(self): - # Arrange - user = return_canned_user(USERNAME, USER_ID) - user.email_address = "test_email_2" - user.create() - verification_url = SMTPService._generate_email_verification_url( - USER_EMAIL, USERNAME - ) - token = verification_url.split("token=")[1].split("&")[0] - # Act - response = self.client.get( - self.url, query_string={"token": token, "username": USERNAME} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "InvalidEmail") - self.assertEqual(response.json["Error"], " Email address does not match token") - - def test_returns_200_if_valid_token(self): - # Arrange - user = return_canned_user(USERNAME, USER_ID) - user.email_address = USER_EMAIL - user.create() - verification_url = SMTPService._generate_email_verification_url( - USER_EMAIL, USERNAME - ) - token = verification_url.split("token=")[1].split("&")[0] - # Assert - User should not have email verified - self.assertEqual( - UserService.get_user_by_username(USERNAME).is_email_verified, False - ) - # Act - response = self.client.get( - self.url, query_string={"token": token, "username": USERNAME} - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual( - UserService.get_user_by_username(USERNAME).email_address, USER_EMAIL - ) - self.assertEqual( - UserService.get_user_by_username(USERNAME).is_email_verified, True - ) diff --git a/tests/backend/integration/api/system/test_banner.py b/tests/backend/integration/api/system/test_banner.py deleted file mode 100644 index 769df98589..0000000000 --- a/tests/backend/integration/api/system/test_banner.py +++ /dev/null @@ -1,64 +0,0 @@ -import base64 - -from backend.services.users.authentication_service import AuthenticationService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import return_canned_user - - -class TestBannerAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.url = "/api/v2/system/banner/" - - def test_get_banner(self): - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - # Default banner is created with message "Welcome to the Tasking Manager" and visible=True at first request - self.assertEqual(response.json["message"], "Welcome to the API") - self.assertTrue(response.json["visible"]) - - def test_patch_banner(self): - # Session token is required for this endpoint. So we need to create a user - test_user = return_canned_user() - test_user.create() - session_token = AuthenticationService.generate_session_token_for_user( - test_user.id - ) - session_token = base64.b64encode(session_token.encode("utf-8")) - session_token = "Token " + session_token.decode("utf-8") - banner_message = "### Updated message" - - # Test returns 400 Bad Request for invalid JSON - response = self.client.patch( - self.url, - json={"message": banner_message, "visible": "OK"}, - headers={"Authorization": session_token}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - # Test returns 403 Forbidden for non-admin users - response = self.client.patch( - self.url, - json={"message": banner_message, "visible": True}, - headers={"Authorization": session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "OnlyAdminAccess") - - # Test returns 200 OK for admin users - test_user.role = 1 - test_user.save() - response = self.client.patch( - self.url, - json={"message": banner_message, "visible": True}, - headers={"Authorization": session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["message"], "

Updated message

") - self.assertTrue(response.json["visible"]) diff --git a/tests/backend/integration/api/system/test_general.py b/tests/backend/integration/api/system/test_general.py deleted file mode 100644 index a9dab2447b..0000000000 --- a/tests/backend/integration/api/system/test_general.py +++ /dev/null @@ -1,68 +0,0 @@ -import requests - -from tests.backend.base import BaseTestCase - - -class TestSystemHeartbeatAPI(BaseTestCase): - def test_get_system_heartbeat(self): - url = "/api/v2/system/heartbeat/" - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["status"], "healthy") - response.json["release"] - - -class TestSystemReleaseAPI(BaseTestCase): - def test_post_banner(self): - url = "/api/v2/system/release/" - response = self.client.post(url) - release = requests.get( - "https://api.github.com/repos/hotosm/tasking-manager/releases/latest" - ).json() - # Assert - self.assertEqual(response.status_code, 201) - self.assertEqual(response.json["release_version"], release["tag_name"]) - - -class TestSystemLanguagesAPI(BaseTestCase): - def test_get_system_languages(self): - url = "/api/v2/system/languages/" - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertListEqual( - list(response.json.keys()), - [ - "mapperLevelIntermediate", - "mapperLevelAdvanced", - "supportedLanguages", - ], - ) - - -class TestSystemContactAdminRestAPI(BaseTestCase): - def test_post_contact_admin(self): - url = "/api/v2/system/contact-admin/" - data = { - "name": "test", - "email": "test", - "content": "test", - } - self.app.config["EMAIL_CONTACT_ADDRESS"] = "test@hotosm.org" - response = self.client.post(url, json=data) - self.assertEqual(response.status_code, 201) - self.assertEqual(response.json["Success"], "Email sent") - - def test_post_contact_admin_raises_error_if_email_contact_address_not_set(self): - url = "/api/v2/system/contact-admin/" - data = { - "name": "test", - "email": "test", - "content": "test", - } - self.app.config["EMAIL_CONTACT_ADDRESS"] = None - response = self.client.post(url, json=data) - self.assertEqual(response.status_code, 501) - self.assertEqual( - response.json["Error"], - "This feature is not implemented due to missing variable TM_EMAIL_CONTACT_ADDRESS.", - ) diff --git a/tests/backend/integration/api/system/test_image_upload.py b/tests/backend/integration/api/system/test_image_upload.py deleted file mode 100644 index 5581bf10d4..0000000000 --- a/tests/backend/integration/api/system/test_image_upload.py +++ /dev/null @@ -1,92 +0,0 @@ -from unittest.mock import patch - -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_user, - generate_encoded_token, -) - -IMAGE_UPLOAD_API_URL = "http://localhost:5000" -IMAGE_UPLOAD_API_KEY = "test" - - -class TestSystemImageUploadRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = create_canned_user() - self.user_token = generate_encoded_token(self.user.id) - self.url = "/api/v2/system/image-upload/" - self.app.config["IMAGE_UPLOAD_API_URL"] = IMAGE_UPLOAD_API_URL - self.app.config["IMAGE_UPLOAD_API_KEY"] = IMAGE_UPLOAD_API_KEY - self.json = {"image": "test", "filename": "test.png", "mime": "image/png"} - - def test_returns_401_if_not_logged_in(self): - url = "/api/v2/system/image-upload/" - response = self.client.post(url) - self.assertEqual(response.status_code, 401) - self.assertEqual(response.json["Error"], "Token is expired or invalid") - self.assertEqual(response.json["SubCode"], "InvalidToken") - - def test_returns_501_if_upload_api_url_not_set(self): - url = "/api/v2/system/image-upload/" - self.app.config["IMAGE_UPLOAD_API_URL"] = None - response = self.client.post(url, headers={"Authorization": self.user_token}) - self.assertEqual(response.status_code, 501) - self.assertEqual(response.json["Error"], "Image upload service not defined") - self.assertEqual(response.json["SubCode"], "UndefinedImageService") - - def test_returns_501_if_upload_api_key_not_set(self): - url = "/api/v2/system/image-upload/" - self.app.config["IMAGE_UPLOAD_API_KEY"] = None - response = self.client.post(url, headers={"Authorization": self.user_token}) - self.assertEqual(response.status_code, 501) - self.assertEqual(response.json["Error"], "Image upload service not defined") - self.assertEqual(response.json["SubCode"], "UndefinedImageService") - - def test_returns_400_if_filename_not_set(self): - url = "/api/v2/system/image-upload/" - self.json["filename"] = None - response = self.client.post( - url, headers={"Authorization": self.user_token}, json=self.json - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["Error"], "Missing filename parameter") - self.assertEqual(response.json["SubCode"], "MissingFilename") - - def test_returns_400_if_mime_not_set(self): - url = "/api/v2/system/image-upload/" - self.json["mime"] = None - response = self.client.post( - url, headers={"Authorization": self.user_token}, json=self.json - ) - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["Error"], "Missing mime parameter") - self.assertEqual(response.json["SubCode"], "MissingMime") - - def test_returns_400_if_mime_not_valid(self): - url = "/api/v2/system/image-upload/" - self.json["mime"] = "test" - response = self.client.post( - url, headers={"Authorization": self.user_token}, json=self.json - ) - self.assertEqual(response.status_code, 400) - self.assertEqual( - response.json["Error"], - "Mimetype is not allowed. The supported formats are: png, jpeg, webp and gif.", - ) - self.assertEqual(response.json["SubCode"], "UnsupportedFile") - - @patch("requests.post") - def test_returns_201_if_upload_successful(self, mock_post): - url = "/api/v2/system/image-upload/" - mock_post.return_value.ok = True - mock_post.return_value.json.return_value = { - "Success": "Image uploaded successfully", - "SubCode": "ImageUploaded", - } - response = self.client.post( - url, headers={"Authorization": self.user_token}, json=self.json - ) - self.assertEqual(response.status_code, 201) - self.assertEqual(response.json["Success"], "Image uploaded successfully") - self.assertEqual(response.json["SubCode"], "ImageUploaded") diff --git a/tests/backend/integration/api/system/test_statistics.py b/tests/backend/integration/api/system/test_statistics.py deleted file mode 100644 index 687eccf34b..0000000000 --- a/tests/backend/integration/api/system/test_statistics.py +++ /dev/null @@ -1,30 +0,0 @@ -from backend.models.postgis.task import Task -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project, return_canned_user - - -class TestSystemStatisticsAPI(BaseTestCase): - def setUp(self): - return super().setUp() - - def test_returns_home_page_stats(self): - """Test that the API returns the home page stats""" - - # Arrange - test_user = return_canned_user("Test User", 2222222) - test_user.create() - test_project, _ = create_canned_project() - # Lock a task for mapping as mappers online is calculated based on locked tasks - task = Task.get( - 2, test_project.id - ) # Set task 2 to mapped since it's created unmapped - task.lock_task_for_mapping(test_user.id) - url = "/api/v2/system/statistics/" - # Act - response = self.client.get(url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["mappersOnline"], 1) - self.assertEqual(response.json["tasksMapped"], 2) - self.assertEqual(response.json["totalMappers"], 2) - self.assertEqual(response.json["totalProjects"], 1) diff --git a/tests/backend/integration/api/tasks/__init__.py b/tests/backend/integration/api/tasks/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/tasks/test_actions.py b/tests/backend/integration/api/tasks/test_actions.py deleted file mode 100644 index d27621a08a..0000000000 --- a/tests/backend/integration/api/tasks/test_actions.py +++ /dev/null @@ -1,1724 +0,0 @@ -from unittest.mock import patch - -from backend.models.postgis.statuses import ( - MappingLevel, - MappingNotAllowed, - ProjectStatus, - TaskStatus, - ValidatingNotAllowed, - ValidationPermission, -) -from backend.models.postgis.task import Task, TaskAction -from backend.services.project_admin_service import ProjectAdminService -from backend.services.project_service import ProjectService -from backend.services.users.user_service import UserService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_license, - create_canned_project, - generate_encoded_token, - return_canned_user, -) -from tests.backend.integration.api.users.test_resources import ( - USER_NOT_FOUND_MESSAGE, - USER_NOT_FOUND_SUB_CODE, -) - -PROJECT_NOT_FOUND_SUB_CODE = "PROJECT_NOT_FOUND" -TASK_NOT_FOUND_SUB_CODE = "TASK_NOT_FOUND" - - -class TasksActionsMapAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, _ = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/actions/map-all/" - self.test_user = return_canned_user(username="Test User", id=11111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_map_all_tasks_returns_401_for_unauthorized_request(self): - """Test returns 401 on request without session token.""" - - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_map_all_tasks_returns_403_for_non_PM_role_request(self, mock_pm_role): - """Test returns 403 on request by user without PM role""" - - # Arrange - mock_pm_role.return_value = False - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserPermissionError") - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_map_all_tasks_is_allowed_for_user_with_pm_role(self, mock_pm_role): - """Test returns 200 on request by user with PM role and all tasks are mapped""" - # Arrange - init_ready_tasks = Task.get_tasks_by_status( - self.test_project.id, TaskStatus.READY.name - ) - mock_pm_role.return_value = True - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - for task in init_ready_tasks: - self.assertEqual(task.task_status, TaskStatus.MAPPED.value) - self.assertEqual( - self.test_project.tasks_mapped, - ( - self.test_project.total_tasks - - self.test_project.tasks_bad_imagery - - self.test_project.tasks_validated - ), - ) - - -class TasksActionsValidateAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, _ = create_canned_project() - self.url = ( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/validate-all/" - ) - self.test_user = return_canned_user(username="Test User", id=11111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_validate_all_tasks_returns_401_for_unauthorized_request(self): - """Test returns 401 on request without session token.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_validate_all_tasks_returns_403_for_non_PM_role_request(self, mock_pm_role): - """Test returns 403 on request by user without PM role""" - - # Arrange - mock_pm_role.return_value = False - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserPermissionError") - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_validate_all_tasks_is_allowed_for_user_with_pm_role(self, mock_pm_role): - """Test returns 200 on request by user with PM role and all tasks are validated""" - # Arrange - init_mapped_tasks = Task.get_tasks_by_status( - self.test_project.id, TaskStatus.MAPPED.name - ) - mock_pm_role.return_value = True - init_tasks_validated = self.test_project.tasks_validated - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - for task in init_mapped_tasks: - self.assertEqual(task.task_status, TaskStatus.VALIDATED.value) - self.assertEqual( - self.test_project.tasks_validated, - init_tasks_validated + len(init_mapped_tasks), - ) - - -class TasksActionsInvalidateAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, _ = create_canned_project() - self.url = ( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/invalidate-all/" - ) - self.test_user = return_canned_user(username="Test User", id=11111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_invalidate_all_tasks_returns_401_for_unauthorized_request(self): - """Test returns 401 on request without session token.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_invalidate_all_tasks_returns_403_for_non_PM_role_request( - self, mock_pm_role - ): - """Test returns 403 on request by user without PM role""" - - # Arrange - mock_pm_role.return_value = False - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserPermissionError") - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_invalidate_all_tasks_is_allowed_for_user_with_pm_role(self, mock_pm_role): - """Test that all tasks with status of validated are invalidated""" - # Arrange - validated_tasks = Task.get_tasks_by_status( - self.test_project.id, TaskStatus.VALIDATED.name - ) - mock_pm_role.return_value = True - init_tasks_validated = self.test_project.tasks_validated - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - # Check status code - self.assertEqual(response.status_code, 200) - # Check status of all tasks that had status of validated before validated - for task in validated_tasks: - self.assertEqual(task.task_status, TaskStatus.INVALIDATED.value) - # Check if counters are set correctly - self.assertEqual(self.test_project.tasks_validated, 0) - - after_tasks_invalidated = len( - Task.get_tasks_by_status(self.test_project.id, TaskStatus.INVALIDATED.name) - ) - self.assertEqual(after_tasks_invalidated, init_tasks_validated) - - -class TasksActionsResetBadImageryAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, _ = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/actions/reset-all-badimagery/" - self.test_user = return_canned_user(username="Test User", id=11111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_reset_all_badimagery_tasks_returns_401_for_unauthorized_request(self): - """Test returns 401 on request without session token.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_reset_all_badimagery_tasks_returns_403_for_non_PM_role_request( - self, mock_pm_role - ): - """Test returns 403 on request by user without PM role""" - - # Arrange - mock_pm_role.return_value = False - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserPermissionError") - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_reset_all_badimagery_tasks_is_allowed_for_user_with_pm_role( - self, mock_pm_role - ): - """Test returns 200 on request by user with PM role and resets all bad imagery tasks to ready""" - # Arrange - init_bad_imagery_tasks = Task.get_tasks_by_status( - self.test_project.id, TaskStatus.BADIMAGERY.name - ) - mock_pm_role.return_value = True - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - # Check status code - self.assertEqual(response.status_code, 200) - # Check status of all tasks that had status of validated before validated - for task in init_bad_imagery_tasks: - self.assertEqual(task.task_status, TaskStatus.READY.value) - # Check if counters are set correctly - self.assertEqual(self.test_project.tasks_bad_imagery, 0) - - -class TasksActionsResetAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, _ = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/actions/reset-all/" - self.test_user = return_canned_user(username="Test User", id=11111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_reset_all_tasks_returns_401_for_unauthorized_request(self): - """Test returns 401 on request without session token.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_reset_all_tasks_returns_403_for_non_PM_role_request(self, mock_pm_role): - "Test returns 403 on request by user without PM role" - - # Arrange - mock_pm_role.return_value = False - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserPermissionError") - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_reset_all_tasks_is_allowed_for_user_with_pm_role(self, mock_pm_role): - """Test returns 200 on request by user with PM role and resets all tasks to ready""" - # Arrange - init_non_ready_tasks = [] - for status in [ - TaskStatus.MAPPED.name, - TaskStatus.VALIDATED.name, - TaskStatus.INVALIDATED.name, - TaskStatus.BADIMAGERY.name, - ]: - init_non_ready_tasks.extend( - Task.get_tasks_by_status(self.test_project.id, status) - ) - - mock_pm_role.return_value = True - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - # Check status code - self.assertEqual(response.status_code, 200) - # Check status of all tasks that had status of validated before validated - for task in init_non_ready_tasks: - self.assertEqual(task.task_status, TaskStatus.READY.value) - # Check if counters are set correctly - ready_tasks = len( - Task.get_tasks_by_status(self.test_project.id, TaskStatus.READY.name) - ) - self.assertEqual(ready_tasks, self.test_project.total_tasks) - self.assertEqual(self.test_project.tasks_mapped, 0) - self.assertEqual(self.test_project.tasks_validated, 0) - self.assertEqual(self.test_project.tasks_bad_imagery, 0) - - -class TestTasksActionsMappingLockAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, _ = create_canned_project() - self.url = ( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/lock-for-mapping/1/" - ) - self.test_user = return_canned_user(username="Test User", id=11111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_mapping_lock_returns_401_for_unauthorized_request(self): - """Test returns 401 on request without session token.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_mapping_lock_returns_404_for_invalid_project_id(self): - """Test returns 404 on request with invalid project id.""" - # Act - response = self.client.post( - "/api/v2/projects/999999/tasks/actions/lock-for-mapping/1/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_mapping_lock_returns_404_for_invalid_task_id(self): - """Test returns 404 on request with invalid task id.""" - # Act - response = self.client.post( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/lock-for-mapping/999999/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - @patch.object(ProjectService, "is_user_permitted_to_map") - def test_mapping_lock_returns_403_for_if_user_not_allowed_to_map( - self, mock_permitted - ): - """Test returns 403 on request by user who doesn't have required permission to map.""" - # Arrange - mock_permitted.return_value = False, MappingNotAllowed.PROJECT_NOT_PUBLISHED - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.READY.value - task.update() - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "ProjectNotPublished") - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_mapping_lock_returns_403_if_task_in_invalid_state_for_mapping( - self, mock_pm_role - ): - """Test returns 403 if task is in invalid state for mapping. i.e. not in READY or INVALIDATED state.""" - # Arrange - mock_pm_role.return_value = True - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - # As Task 1 is in MAPPED state, it should not be allowed to be locked for mapping. - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "InvalidTaskState") - - # Arrange - # Change task state to VALIDATED - self.test_project.tasks[0].task_status = TaskStatus.VALIDATED.value - self.test_project.tasks[0].update() - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - # As Task 1 is in VALIDATED state, it should not be allowed to be locked for mapping. - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "InvalidTaskState") - - @patch.object(UserService, "has_user_accepted_license") - def test_mapping_lock_returns_403_if_project_licence_not_accepted( - self, mock_accepted - ): - """Test returns 403 if project licence is not accepted.""" - # Arrange - mock_accepted.return_value = False - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.license_id = create_canned_license() - self.test_project.save() - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.READY.value - task.update() - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 409) - self.assertEqual(response.json["SubCode"], "UserLicenseError") - - @patch.object(ProjectService, "is_user_permitted_to_map") - def test_mapping_lock_is_allowed_for_user_with_mapping_permission( - self, mock_permitted - ): - """Test returns 200 if user has mapping permission.""" - # Arrange - mock_permitted.return_value = True, "User allowed to map" - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.READY.value - task.update() - # Act - response = self.client.post( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskId"], 1) - self.assertEqual(response.json["projectId"], self.test_project.id) - self.assertEqual( - response.json["taskStatus"], TaskStatus.LOCKED_FOR_MAPPING.name - ) - self.assertEqual(response.json["lockHolder"], self.test_user.username) - - -class TestTasksActionsMappingUnlockAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("Test User", 1111111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/actions/unlock-after-mapping/1/" - - def test_mapping_unlock_returns_401_for_unauthenticated_user(self): - """Test returns 401 on request from unauthenticated user.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_mapping_unlock_returns_400_if_invalid_data(self): - """Test returns 404 on request with invalid data.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={ - "status": "test" - }, # Since valid status are MAPPED, INVALIDATED, BADIMAGERY - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_mapping_unlock_returns_404_for_invalid_project_id(self): - """Test returns 404 on request with invalid project id.""" - # Act - response = self.client.post( - "/api/v2/projects/999999/tasks/actions/unlock-after-mapping/1/", - headers={"Authorization": self.user_session_token}, - json={"status": "MAPPED"}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_mapping_unlock_returns_404_for_invalid_task_id(self): - """Test returns 404 on request with invalid task id.""" - # Act - response = self.client.post( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/unlock-after-mapping/999999/", - headers={"Authorization": self.user_session_token}, - json={"status": "MAPPED"}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - def test_mapping_unlock_returns_403_if_task_not_locked_for_mapping(self): - """Test returns 403 if task is not locked for mapping.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"status": "MAPPED"}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "LockBeforeUnlocking") - - def test_mapping_unlock_returns_403_if_task_locked_by_other_user(self): - """Test returns 403 if task is locked by other user.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - task.locked_by = self.test_author.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"status": "MAPPED"}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "TaskNotOwned") - - def test_returns_403_if_invalid_new_state_passed(self): - """Test returns 403 if invalid new state passed as new task state should be READY, MAPPED or BADIMAGERY.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - task.locked_by = self.test_user.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"status": "INVALIDATED"}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "InvalidUnlockState") - - def test_mapping_unlock_returns_200_on_success(self): - """Test returns 200 on success.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - task.locked_by = self.test_user.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"status": "MAPPED"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskId"], 1) - self.assertEqual(response.json["projectId"], self.test_project.id) - self.assertEqual(response.json["taskStatus"], TaskStatus.MAPPED.name) - last_task_history = response.json["taskHistory"][0] - self.assertEqual(last_task_history["action"], TaskAction.STATE_CHANGE.name) - self.assertEqual(last_task_history["actionText"], TaskStatus.MAPPED.name) - self.assertEqual(last_task_history["actionBy"], self.test_user.username) - - def test_mapping_unlock_returns_200_on_success_with_comment(self): - """Test returns 200 on success.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - task.locked_by = self.test_user.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={ - "status": "BADIMAGERY", # Lets test with BADIMAGERY this time - "comment": "cannot map", - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskId"], 1) - self.assertEqual(response.json["projectId"], self.test_project.id) - self.assertEqual(response.json["taskStatus"], TaskStatus.BADIMAGERY.name) - - last_task_history = response.json["taskHistory"][0] - self.assertEqual(last_task_history["action"], TaskAction.STATE_CHANGE.name) - self.assertEqual(last_task_history["actionText"], TaskStatus.BADIMAGERY.name) - self.assertEqual(last_task_history["actionBy"], self.test_user.username) - - last_comment_history = response.json["taskHistory"][1] - self.assertEqual(last_comment_history["action"], TaskAction.COMMENT.name) - self.assertEqual(last_comment_history["actionText"], "cannot map") - self.assertEqual(last_comment_history["actionBy"], self.test_user.username) - - -class TestTasksActionsMappingStopAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("Test User", 11111111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.url = ( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/stop-mapping/1/" - ) - - def test_returns_401_if_user_not_authorized(self): - """Test returns 401 if user not authorized.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_mapping_stop_returns_404_for_invalid_project_id(self): - """Test returns 404 on request with invalid project id.""" - # Act - response = self.client.post( - "/api/v2/projects/999999/tasks/actions/stop-mapping/1/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_mapping_stop_returns_404_for_invalid_task_id(self): - """Test returns 404 on request with invalid task id.""" - # Act - response = self.client.post( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/stop-mapping/999999/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - def test_mapping_stop_returns_403_if_task_not_locked_for_mapping(self): - """Test returns 403 if task not locked for mapping.""" - # Since we are not locking the task, it should return 403 - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "LockBeforeUnlocking") - - def test_mapping_stop_returns_403_if_task_locked_by_other_user(self): - """Test returns 403 if task locked by other user.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - task.locked_by = self.test_author.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "TaskNotOwned") - - def test_mapping_stop_returns_200_on_success(self): - """Test returns 200 on success.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - task.locked_by = self.test_user.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskId"], 1) - self.assertEqual(response.json["projectId"], self.test_project.id) - self.assertEqual(response.json["taskStatus"], TaskStatus.READY.name) - - def test_mapping_stop_returns_200_on_success_with_comment(self): - """Test returns 200 on success.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - task.locked_by = self.test_user.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={ - "comment": "cannot map", - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskId"], 1) - self.assertEqual(response.json["projectId"], self.test_project.id) - self.assertEqual(response.json["taskStatus"], TaskStatus.READY.name) - - last_comment_history = response.json["taskHistory"][0] - self.assertEqual(last_comment_history["action"], TaskAction.COMMENT.name) - self.assertEqual(last_comment_history["actionText"], "cannot map") - self.assertEqual(last_comment_history["actionBy"], self.test_user.username) - - -class TestTasksActionsValidationLockAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("Test User", 11111111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/actions/lock-for-validation/" - - def test_returns_401_if_user_not_authorized(self): - """Test returns 401 if user not authorized.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_validation_lock_returns_400_if_invalid_json(self): - """Test returns 400 if invalid json.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": "abcd"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_validation_lock_returns_404_for_invalid_project_id(self): - """Test returns 404 on request with invalid project id.""" - # Act - response = self.client.post( - "/api/v2/projects/999999/tasks/actions/lock-for-validation/", - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1, 2]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_validation_lock_returns_404_for_invalid_task_id(self): - """Test returns 404 on request with invalid task id.""" - # Act - response = self.client.post( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/lock-for-validation/", - headers={"Authorization": self.user_session_token}, - json={"taskIds": [999999]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - def test_validation_lock_returns_403_if_task_not_ready_for_validation(self): - """Test returns 403 if task not ready for validation.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.READY.value # not ready for validation - task.locked_by = self.test_user.id - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "NotReadyForValidation") - - def test_validation_lock_returns_403_if_mapped_by_same_user_and_user_not_admin( - self, - ): - """Test returns 403 if mapped by same user.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.MAPPED.value - task.mapped_by = self.test_user.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "CannotValidateMappedTask") - - def test_validation_lock_returns_403_if_user_not_permitted_to_validate(self): - """Test returns 403 if user not permitted to validate.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "ProjectNotPublished") - - def test_validation_lock_returns_409_if_user_hasnt_accepted_license(self): - """Test returns 409 if user hasn't accepted license.""" - # Arrange - self.test_project.license_id = create_canned_license() - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.save() - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.MAPPED.value - task.mapped_by = self.test_author.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 409) - self.assertEqual(response.json["SubCode"], "UserLicenseError") - - @patch.object(ProjectService, "is_user_permitted_to_validate") - def test_validation_lock_returns_403_if_user_not_on_allowed_list( - self, mock_validate_permitted - ): - """Test returns 403 if user not on allowed list.""" - # Arrange - mock_validate_permitted.return_value = ( - False, - ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST, - ) - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.MAPPED.value - task.mapped_by = self.test_author.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserNotAllowed") - - def test_validation_lock_returns_403_if_user_has_already_locked_other_task(self): - """Test returns 403 if user has already locked other task.""" - # Arrange - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.save() - task = Task.get(2, self.test_project.id) - task.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - task.locked_by = self.test_user.id - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserAlreadyHasTaskLocked") - - @patch.object(ProjectService, "is_user_permitted_to_validate") - def validation_lock_returns_200_if_user_permitted_to_validate( - self, mock_validate_permitted - ): - """Test returns 200 if user permitted to validate.""" - # Arrange - mock_validate_permitted.return_value = ( - True, - ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST, - ) - # Since task 1 is already mapped, we need to change the status of task 2 to invalidated - # As ivalidated tasks should also be allowed to be locked for validation - task = Task.get(2, self.test_project.id) - task.task_status = TaskStatus.INVALIDATED.value - task.update() - - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1, 2]}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["tasks"][0]["taskId"], 1) - self.assertEqual( - response.json["tasks"][0]["taskStatus"], - TaskStatus.LOCKED_FOR_VALIDATION.name, - ) - self.assertEqual(response.json["tasks"][1]["taskId"], 2) - self.assertEqual( - response.json["tasks"][1]["taskStatus"], - TaskStatus.LOCKED_FOR_VALIDATION.name, - ) - - -class TestTasksActionsValidationUnlockAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("Test User", 1111111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/actions/unlock-after-validation/" - - def test_validation_unlock_returns_401_if_user_not_logged_in(self): - """Test returns 401 if user not logged in.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_validation_unlock_returns_400_if_invalid_request(self): - """Test returns 400 if invalid request.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"validatedTasks": "xxx"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_validation_unlock_returns_404_if_project_not_found(self): - """Test returns 404 if project not found.""" - # Act - response = self.client.post( - "/api/v2/projects/999/tasks/actions/unlock-after-validation/", - headers={"Authorization": self.user_session_token}, - json={"validatedTasks": [{"taskId": 1, "status": "VALIDATED"}]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_validation_unlock_returns_404_if_task_not_found(self): - """Test returns 404 if task not found.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"validatedTasks": [{"taskId": 999, "status": "VALIDATED"}]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - def test_validation_unlock_returns_403_if_task_not_locked_for_validation(self): - """Test returns 403 if task not locked for validation.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"validatedTasks": [{"taskId": 1, "status": "VALIDATED"}]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "NotLockedForValidation") - - @staticmethod - def lock_task_for_validation(task_id, project_id, user_id, mapped_by=None): - """Lock task for validation.""" - task = Task.get(task_id, project_id) - task.task_status = TaskStatus.LOCKED_FOR_VALIDATION.value - task.locked_by = user_id - if mapped_by: - task.mapped_by = mapped_by - task.update() - - def test_validation_unlock_returns_403_if_task_locked_by_other_user(self): - """Test returns 403 if task locked by other user.""" - # Arrange - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 1, self.test_project.id, self.test_author.id - ) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"validatedTasks": [{"taskId": 1, "status": "VALIDATED"}]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "TaskNotOwned") - - def test_validation_unlock_returns_400_if_invalid_state_passsed(self): - """Test returns 400 if invalid state passed.""" - # Arrange - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 1, self.test_project.id, self.test_user.id - ) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"validatedTasks": [{"taskId": 1, "status": "READY"}]}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - @staticmethod - def assert_validated_task_response( - task_response, task_id, status, validator_username, comment=None - ): - """Assert validated task response.""" - assert task_response["taskId"] == task_id - assert task_response["taskStatus"] == status - assert task_response["taskHistory"][0]["action"] == "STATE_CHANGE" - assert task_response["taskHistory"][0]["actionText"] == status - assert task_response["taskHistory"][0]["actionBy"] == validator_username - if comment: - assert task_response["taskHistory"][1]["action"] == "COMMENT" - assert task_response["taskHistory"][1]["actionText"] == comment - assert task_response["taskHistory"][1]["actionBy"] == validator_username - - def test_validation_unlock_returns_200_if_validated(self): - """Test returns 200 if validated.""" - # Arrange - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 1, self.test_project.id, self.test_user.id, self.test_user.id - ) - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 2, self.test_project.id, self.test_user.id, self.test_user.id - ) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={ - "validatedTasks": [ - {"taskId": 1, "status": "VALIDATED"}, - {"taskId": 2, "status": "INVALIDATED"}, - ] - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - TestTasksActionsValidationUnlockAPI.assert_validated_task_response( - next( - (task for task in response.json["tasks"] if task["taskId"] == 1), None - ), - 1, - "VALIDATED", - self.test_user.username, - ) - TestTasksActionsValidationUnlockAPI.assert_validated_task_response( - next( - (task for task in response.json["tasks"] if task["taskId"] == 2), None - ), - 2, - "INVALIDATED", - self.test_user.username, - ) - - def test_validation_unlock_returns_200_if_validated_with_comment(self): - """Test returns 200 if validated with comments.""" - # Arrange - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 1, self.test_project.id, self.test_user.id, self.test_user.id - ) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={ - "validatedTasks": [ - { - "taskId": 1, - "status": "VALIDATED", - "comment": "Test comment", - } - ] - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - TestTasksActionsValidationUnlockAPI.assert_validated_task_response( - response.json["tasks"][0], - 1, - "VALIDATED", - self.test_user.username, - "Test comment", - ) - - -class TestTasksActionsValidationStopAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("test_user", 111111111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.url = ( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/stop-validation/" - ) - - def test_validation_stop_returns_401_if_not_logged_in(self): - """Test returns 401 if not logged in.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_validation_stop_returns_400_if_invalid_data(self): - """Test returns 400 if invalid data passed""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"resetTasks": "invalid"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_validation_stop_returns_404_if_project_not_found(self): - """Test returns 404 if project not found.""" - # Act - response = self.client.post( - "/api/v2/projects/999/tasks/actions/stop-validation/", - headers={"Authorization": self.user_session_token}, - json={"resetTasks": [{"taskId": 1}]}, - ) - - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_validation_stop_returns_404_if_task_not_found(self): - """Test returns 404 if task not found.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"resetTasks": [{"taskId": 999}]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - def test_validation_stop_returns_403_if_task_not_locked_for_validation(self): - """Test returns 403 if task not locked for validation.""" - # Arrange - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 1, self.test_project.id, self.test_user.id - ) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"resetTasks": [{"taskId": 1}, {"taskId": 2}]}, - ) - # Assert - # Since task 2 is not locked for validation, we should get a 403 even though task 1 is locked for validation - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "NotLockedForValidation") - - def test_validation_stop_returns_403_if_task_locked_by_other_user(self): - """Test returns 403 if task locked by other user.""" - # Arrange - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 1, self.test_project.id, self.test_author.id, self.test_author.id - ) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"resetTasks": [{"taskId": 1}]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "TaskNotOwned") - - def test_validation_stop_returns_200_if_task_locked_by_user(self): - """Test returns 200 if task locked by user.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.unlock_task(self.test_user.id, TaskStatus.MAPPED) - last_task_status = TaskStatus(task.task_status).name - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 1, self.test_project.id, self.test_user.id, self.test_user.id - ) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"resetTasks": [{"taskId": 1}]}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["tasks"][0]["taskId"], 1) - self.assertEqual(response.json["tasks"][0]["projectId"], self.test_project.id) - self.assertEqual(response.json["tasks"][0]["taskStatus"], last_task_status) - - def test_validation_stop_returns_200_if_task_locked_by_user_with_comment(self): - """Test returns 200 if task locked by user with comment.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.unlock_task(self.test_user.id, TaskStatus.MAPPED) - last_task_status = TaskStatus(task.task_status).name - TestTasksActionsValidationUnlockAPI.lock_task_for_validation( - 1, self.test_project.id, self.test_user.id, self.test_user.id - ) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={ - "resetTasks": [ - { - "taskId": 1, - "comment": "Test comment", - } - ] - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["tasks"][0]["taskId"], 1) - self.assertEqual(response.json["tasks"][0]["projectId"], self.test_project.id) - self.assertEqual(response.json["tasks"][0]["taskStatus"], last_task_status) - task_history_comment = response.json["tasks"][0]["taskHistory"][0] - self.assertEqual(task_history_comment["action"], "COMMENT") - self.assertEqual(task_history_comment["actionText"], "Test comment") - self.assertEqual(task_history_comment["actionBy"], self.test_user.username) - - -class TestTasksActionsSplitAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/actions/split/1/" - self.author_session_token = generate_encoded_token(self.test_author.id) - - def test_returns_401_if_not_logged_in(self): - """Test returns 401 if not logged in.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_project_not_found(self): - """Test returns 404 if project not found.""" - # Act - response = self.client.post( - "/api/v2/projects/999/tasks/actions/split/1/", - headers={"Authorization": self.author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_returns_404_if_task_not_found(self): - """Test returns 404 if task not found.""" - # Act - response = self.client.post( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/split/999/", - headers={"Authorization": self.author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - def test_returns_403_if_task_too_small_to_split(self): - """Test returns 403 if task too small to split.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.zoom = 18 - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "SmallToSplit") - - def test_returns_403_if_task_not_locked_for_mapping(self): - """Test returns 403 if task not locked for mapping.""" - # Since task should be locked for mapping to split, we should get a 403 - response = self.client.post( - self.url, - headers={"Authorization": self.author_session_token}, - ) - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "LockToSplit") - - def test_returns_403_if_task_locked_by_other_user(self): - """Test returns 403 if task locked by other user.""" - # Arrange - test_user = return_canned_user("test user", 1111111) - test_user.create() - task = Task.get(1, self.test_project.id) - task.lock_task_for_mapping(test_user.id) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "SplitOtherUserTask") - - def test_returns_200_if_task_locked_by_user(self): - """Test returns 200 if task locked by user.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.lock_task_for_mapping(self.test_author.id) - old_total_tasks = self.test_project.total_tasks - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.author_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(self.test_project.total_tasks, old_total_tasks + 3) - # Check that the task 1 has been removed as it was splitted into 4 tasks - self.assertIsNone(Task.get(1, self.test_project.id)) - - -class TestTasksActionsMappingUndoAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("test user", 1111111) - self.test_user.mapping_level = MappingLevel.BEGINNER.value - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.url = ( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/undo-last-action/1/" - ) - self.author_session_token = generate_encoded_token(self.test_author.id) - - def test_returns_401_if_not_logged_in(self): - """Test returns 401 if not logged in.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_project_not_found(self): - """Test returns 404 if project not found.""" - # Act - response = self.client.post( - "/api/v2/projects/999/tasks/actions/undo-last-action/1/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_returns_404_if_task_not_found(self): - """Test returns 404 if task not found.""" - # Act - response = self.client.post( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/undo-last-action/999/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - def test_returns_403_if_task_in_invalid_state_for_undo(self): - """Test returns 403 if task in invalid state for undo.""" - # Since task cannot be in READY, LOCKED_FOR_VALIDATION or LOCKED_FOR_MAPPING state for undo, - # we should get a 403 - # Arrange - task = Task.get(1, self.test_project.id) - task.task_status = TaskStatus.READY.value - task.update() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UndoPermissionError") - - @staticmethod - def validate_task(task_id, project_id, user_id): - """Map task.""" - task = Task.get(task_id, project_id) - task.lock_task_for_mapping(user_id) - task.unlock_task(user_id, TaskStatus.VALIDATED) - - def test_returns_403_if_user_not_permitted_for_undo(self): - """Test returns 403 if user not permitted for undo.""" - # Only user with validation permission and user who performed the last task action can undo. - # Arrange - TestTasksActionsMappingUndoAPI.validate_task( - 1, self.test_project.id, self.test_author.id - ) # create a last task history - self.test_project.validation_permission = ValidationPermission.LEVEL.value - self.test_project.save() - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UndoPermissionError") - - @staticmethod - def assert_undo_response(response, project_id, last_status, username, new_status): - """Assert undo response.""" - assert response.json["taskStatus"] == new_status - assert response.json["taskId"] == 1 - assert response.json["projectId"] == project_id - action_history = response.json["taskHistory"][0] - comment_history = response.json["taskHistory"][1] - assert action_history["action"] == TaskAction.STATE_CHANGE.name - assert action_history["actionText"] == new_status - assert action_history["actionBy"] == username - assert comment_history["action"] == TaskAction.COMMENT.name - assert ( - comment_history["actionText"] - == f"Undo state from {last_status} to {new_status}" - ) - assert comment_history["actionBy"] == username - - def test_returns_200_if_undo_by_user_with_last_action(self): - """Test returns 200 if undo by user with last action.""" - # Arrange - TestTasksActionsMappingUndoAPI.validate_task( - 1, self.test_project.id, self.test_user.id - ) - # Act - # Since test_user is the last user to perform an action on task 1, he should be able to undo - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - TestTasksActionsMappingUndoAPI.assert_undo_response( - response, - self.test_project.id, - TaskStatus.VALIDATED.name, - self.test_user.username, - TaskStatus.MAPPED.name, - ) - - def test_returns_200_if_undo_by_user_with_validation_permission(self): - """Test returns 200 if undo by user with validation permission.""" - # Arrange - TestTasksActionsMappingUndoAPI.validate_task( - 1, self.test_project.id, self.test_author.id - ) - self.test_project.validation_permission = ValidationPermission.ANY.value - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.save() - # Act - # Since test_user is the last user to perform an action on task 1, he should be able to undo - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - TestTasksActionsMappingUndoAPI.assert_undo_response( - response, - self.test_project.id, - TaskStatus.VALIDATED.name, - self.test_user.username, - TaskStatus.MAPPED.name, - ) - - -class TestTasksActionsExtendAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("test_user", 1111111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.author_access_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/actions/extend/" - - def test_returns_401_if_user_not_logged_in(self): - """Test returns 401 if user not logged in.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_400_if_invalid_data(self): - """Test returns 400 if invalid data.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": "abcd"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_returns_404_if_project_not_found(self): - """Test returns 404 if project not found.""" - # Act - response = self.client.post( - "/api/v2/projects/999/tasks/actions/extend/", - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_returns_404_if_task_not_found(self): - """Test returns 404 if task not found.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [999]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], TASK_NOT_FOUND_SUB_CODE) - - def test_returns_403_if_task_not_locked(self): - """Test returns 403 if task not locked.""" - # Task should be locked for mapping or validation to extend - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "TaskStatusNotLocked") - - def test_returns_403_if_task_is_not_locked_by_requesting_user(self): - """Test returns 403 if task is not locked by requesting user.""" - # Task should be locked for mapping or validation to extend - # Arrange - task = Task.get(1, self.test_project.id) - task.lock_task_for_mapping(self.test_author.id) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1]}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "LockedByAnotherUser") - - def test_returns_200_if_task_locked_by_requesting_user(self): - """Test returns 200 if task locked by requesting user.""" - # Task should be locked for mapping or validation to extend - # Arrange - task = Task.get(1, self.test_project.id) - task.lock_task_for_mapping(self.test_user.id) - task_2 = Task.get(2, self.test_project.id) - task_2.lock_task_for_mapping(self.test_user.id) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"taskIds": [1, 2]}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["Success"], "Successfully extended task expiry") - - -class TestTasksActionsReverUserTaskstAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("test_user", 1111111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.author_access_token = generate_encoded_token(self.test_author.id) - self.url = ( - f"/api/v2/projects/{self.test_project.id}/tasks/actions/reset-by-user/" - ) - - def test_returns_401_if_user_not_logged_in(self): - """Test returns 401 if user not logged in.""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_user_not_found(self): - """Test returns 404 if user not found.""" - # Act - response = self.client.post( - "/api/v2/projects/999/tasks/actions/reset-by-user/", - headers={"Authorization": self.author_access_token}, - query_string={"username": "invalid_user", "action": "VALIDATED"}, - ) - error_details = response.json["error"] - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["sub_code"], USER_NOT_FOUND_SUB_CODE) - self.assertEqual(error_details["message"], USER_NOT_FOUND_MESSAGE) - - def test_returns_400_if_action_not_valid(self): - """Test returns 400 if action not valid.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.author_access_token}, - query_string={"username": self.test_user.username, "action": "MAPPED"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_returns_404_if_project_not_found(self): - """Test returns 404 if project not found.""" - # Act - response = self.client.post( - "/api/v2/projects/999/tasks/actions/reset-by-user/", - headers={"Authorization": self.user_session_token}, - query_string={"username": "test_user", "action": "VALIDATED"}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], PROJECT_NOT_FOUND_SUB_CODE) - - def test_returns_403_if_user_doesnot_have_PM_permission(self): - """Test returns 403 if user doesnot have PM permission.""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"username": "test_user", "action": "VALIDATED"}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UserActionNotPermitted") - - def set_task_status(self, task, status, user_id): - """Set task status.""" - task.lock_task_for_mapping(user_id) - if status == "BADIMAGERY": - task.unlock_task(user_id, TaskStatus.BADIMAGERY) - elif status == "VALIDATED": - task.unlock_task(user_id, TaskStatus.MAPPED) - task.lock_task_for_validating(user_id) - task.unlock_task(user_id, TaskStatus.VALIDATED) - - def test_returns_successfully_reverts_user_validated_tasks(self): - """Test user validated tasks are successfully reverted to mapped""" - # Arrange - task_1 = Task.get(1, self.test_project.id) - task_2 = Task.get(2, self.test_project.id) - # Set task as validated by test_user and test_author - self.set_task_status(task_1, "VALIDATED", self.test_user.id) - self.set_task_status(task_2, "VALIDATED", self.test_author.id) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.author_access_token}, - query_string={"username": self.test_user.username, "action": "VALIDATED"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["Success"], "Successfully reverted tasks") - self.assertEqual(task_1.task_status, TaskStatus.MAPPED.value) - # task_2 is validated by test_author so it should not be reverted to mapped status - self.assertEqual(task_2.task_status, TaskStatus.VALIDATED.value) - - def test_returns_successfully_reverts_user_bad_imagery_tasks(self): - """Test user bad imagery tasks are successfully reverted to ready""" - # Arrange - task_1 = Task.get(1, self.test_project.id) - task_2 = Task.get(2, self.test_project.id) - # Set task as bad imagery by test_user and test_author - self.set_task_status(task_1, "BADIMAGERY", self.test_user.id) - self.set_task_status(task_2, "BADIMAGERY", self.test_author.id) - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.author_access_token}, - query_string={"username": self.test_user.username, "action": "BADIMAGERY"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["Success"], "Successfully reverted tasks") - self.assertEqual(task_1.task_status, TaskStatus.READY.value) - # task_2 is set as bad imagery by test_author so it should not be reverted to ready status - self.assertEqual(task_2.task_status, TaskStatus.BADIMAGERY.value) diff --git a/tests/backend/integration/api/tasks/test_resources.py b/tests/backend/integration/api/tasks/test_resources.py deleted file mode 100644 index 731e70af8c..0000000000 --- a/tests/backend/integration/api/tasks/test_resources.py +++ /dev/null @@ -1,628 +0,0 @@ -import xml.etree.ElementTree as ET - -from backend.models.postgis.statuses import TaskStatus, UserRole -from backend.models.postgis.task import Task -from backend.services.project_admin_service import ProjectAdminService -from backend.services.project_service import ProjectService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_manager_to_organisation, - create_canned_organisation, - create_canned_project, - generate_encoded_token, - return_canned_user, -) - - -class TestGetTasksQueriesJsonAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/" - - def test_returns_404_if_project_does_not_exist(self): - """Test that a 404 is returned if the project does not exist.""" - # Act - response = self.client.get("/api/v2/projects/11111/tasks/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_all_tasks_if_task_ids_not_specified(self): - """Test that all tasks are returned if no task_ids are specified.""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json.keys(), {"type", "features"}) - self.assertEqual(response.json["type"], "FeatureCollection") - self.assertEqual(len(response.json["features"]), 4) - - def test_returns_only_specified_tasks_if_task_ids_specified(self): - """Test that only the specified tasks are returned if task_ids are specified.""" - # Act - response = self.client.get(self.url + "?tasks=1,2") - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["features"]), 2) - self.assertEqual(response.json["features"][0]["properties"]["taskId"], 1) - self.assertEqual(response.json["features"][1]["properties"]["taskId"], 2) - - def test_returns_tasks_as_file_id_as_file_set_true(self): - """Test that the tasks are returned with the file_id as the file if file_set is true.""" - # Act - response = self.client.get(self.url + "?as_file=true") - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers["Content-Type"], "application/json") - self.assertEqual( - response.headers["Content-Disposition"], - f"attachment; filename={self.test_project.id}-tasks.geojson", - ) - self.assertEqual(response.json.keys(), {"type", "features"}) - self.assertEqual(response.json["type"], "FeatureCollection") - self.assertEqual(len(response.json["features"]), 4) - - -class TestDeleteTasksJsonAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/" - self.test_user = return_canned_user("test_user", 11111) - self.test_user.create() - self.test_user_access_token = generate_encoded_token(self.test_user.id) - self.test_author_access_token = generate_encoded_token(self.test_author.id) - self.test_organization = create_canned_organisation() - self.test_project.organization = self.test_organization - self.test_project.save() - - def test_returns_401_if_not_authorized(self): - """Test that a 401 is returned if the user is not authorized.""" - # Act - response = self.client.delete(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_403_if_user_not_admin(self): - """Test that a 403 is returned if the user is not a project manager.""" - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.test_user_access_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - - def test_returns_404_if_project_does_not_exist(self): - """Test that a 404 is returned if the project does not exist.""" - # Arrange - self.test_user.role = UserRole.ADMIN.value # Since only admins can delete tasks - self.test_user.save() - body = {"tasks": [1, 2]} - # Act - response = self.client.delete( - "/api/v2/projects/11111/tasks/", - headers={"Authorization": self.test_user_access_token}, - json=body, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_even_org_manager_cannot_delete_tasks(self): - """Test that an org manager cannot delete tasks.""" - # Arrange - add_manager_to_organisation(self.test_organization, self.test_user) - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.test_user_access_token} - ) - # Assert - self.assertEqual(response.status_code, 403) - - def test_returns_400_if_no_task_ids_specified(self): - """Test that a 400 is returned if no task_ids are specified.""" - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.delete( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={}, - ) - # Assert - self.assertEqual(response.status_code, 400) - - def test_returns_404_if_task_not_found(self): - """Test that a 400 is returned if the task is not found.""" - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.delete( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"tasks": [999]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_deletes_specified_tasks_if_user_admin(self): - """Test that the specified tasks are deleted.""" - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.delete( - self.url, - headers={"Authorization": self.test_user_access_token}, - json={"tasks": [1, 2]}, - ) - # Assert - self.assertEqual(response.status_code, 200) - project_tasks = ProjectService.get_project_tasks(self.test_project.id, None) - self.assertEqual(len(project_tasks["features"]), 2) - self.assertEqual(project_tasks["features"][0]["properties"]["taskId"], 3) - self.assertEqual(project_tasks["features"][1]["properties"]["taskId"], 4) - - -class TestTaskRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_access_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/1/" - - def test_returrns_404_if_project_does_not_exist(self): - """Test that a 404 is returned if the project does not exist.""" - # Act - response = self.client.get("/api/v2/projects/11111/tasks/1/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_404_if_task_does_not_exist(self): - """Test that a 404 is returned if the task does not exist.""" - # Act - response = self.client.get( - f"/api/v2/projects/{self.test_project.id}/tasks/999/" - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_200_if_task_exists(self): - """Test that a 200 is returned if the task exists.""" - # Lets add task history - task = Task.get(1, self.test_project.id) - task.lock_task_for_validating(self.test_author.id) - task.unlock_task(self.test_author.id, TaskStatus.VALIDATED, "Test comment") - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual( - set(response.json.keys()), - set( - { - "taskId", - "projectId", - "taskStatus", - "taskHistory", - "taskAnnotation", - "perTaskInstructions", - "autoUnlockSeconds", - "lastUpdated", - "numberOfComments", - } - ), - ) - self.assertEqual(response.json["taskId"], 1) - self.assertEqual(response.json["projectId"], self.test_project.id) - self.assertEqual(response.json["taskStatus"], TaskStatus.VALIDATED.name) - self.assertEqual(len(response.json["taskHistory"]), 3) - self.assertEqual( - response.json["taskHistory"][2]["action"], "LOCKED_FOR_VALIDATION" - ) - self.assertEqual(response.json["taskHistory"][1]["action"], "COMMENT") - self.assertEqual(response.json["taskHistory"][0]["action"], "STATE_CHANGE") - - -class TestTasksQueriesGpxAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_access_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/queries/gpx/" - - def test_returns_404_if_project_does_not_exist(self): - """Test that a 404 is returned if the project does not exist.""" - # Act - response = self.client.get("/api/v2/projects/11111/tasks/queries/gpx/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_all_tasks_if_no_tasks_specified(self): - """Test that all tasks are returned if no tasks are specified.""" - # Act - response = self.client.get(self.url) - # Assert - ns = {"gpx": "http://www.topografix.com/GPX/1/1"} - self.assertEqual(response.status_code, 200) - response_xml = ET.fromstring(response.get_data(as_text=True)) - self.assertEqual( - response_xml.attrib, {"version": "1.1", "creator": "HOT Tasking Manager"} - ) - trk = response_xml.find("gpx:trk", namespaces=ns) - self.assertEqual( - trk.find("gpx:name", ns).text, - f"Task for project {self.test_project.id}. Do not edit outside of this area!", - ) - self.assertEqual( - len([i for i in trk.findall("gpx:trkseg", ns)]), 4 - ) # Since project has 4 tasks - - def test_returns_gpx_for_specified_tasks(self): - """Test that the specified tasks are returned.""" - # Act - response = self.client.get(self.url + "?tasks=1,2") - # Assert - ns = {"gpx": "http://www.topografix.com/GPX/1/1"} - self.assertEqual(response.status_code, 200) - response_xml = ET.fromstring(response.get_data(as_text=True)) - self.assertEqual( - response_xml.attrib, {"version": "1.1", "creator": "HOT Tasking Manager"} - ) - trk = response_xml.find("gpx:trk", namespaces=ns) - self.assertEqual( - trk.find("gpx:name", ns).text, - f"Task for project {self.test_project.id}. Do not edit outside of this area!", - ) - self.assertEqual( - len([i for i in trk.findall("gpx:trkseg", ns)]), 2 - ) # Since we only asked for tasks 1 and 2 - - def test_returns_file_if_as_file_set_true(self): - """Test that the file is returned if the as_file parameter is set to true.""" - # Act - response = self.client.get(self.url + "?as_file=true") - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers["Content-Type"], "text.xml") - self.assertEqual( - response.headers["Content-Disposition"], - f"attachment; filename=HOT-project-{self.test_project.id}.gpx", - ) - - -class TestTasksQueriesXmlAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_access_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/queries/xml/" - - def test_returns_404_if_project_does_not_exist(self): - """Test that a 404 is returned if the project does not exist.""" - # Act - response = self.client.get("/api/v2/projects/11111/tasks/queries/xml/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_all_tasks_if_no_tasks_specified(self): - """Test that all tasks are returned if no tasks are specified.""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - response_xml = ET.fromstring(response.get_data(as_text=True)) - self.assertEqual( - response_xml.attrib, - {"version": "0.6", "upload": "never", "creator": "HOT Tasking Manager"}, - ) - self.assertEqual( - len([i for i in response_xml.findall("way")]), 4 - ) # Since project has 4 tasks - - def test_returns_xml_for_specified_tasks(self): - """Test that the specified tasks are returned.""" - # Act - response = self.client.get(self.url + "?tasks=1,2") - # Assert - self.assertEqual(response.status_code, 200) - response_xml = ET.fromstring(response.get_data(as_text=True)) - self.assertEqual( - response_xml.attrib, - {"version": "0.6", "upload": "never", "creator": "HOT Tasking Manager"}, - ) - self.assertEqual( - len([i for i in response_xml.findall("way")]), 2 - ) # Since we are only requesting 2 tasks - - def test_returns_file_if_as_file_set_true(self): - """Test that the file is returned if the as_file parameter is set to true.""" - # Act - response = self.client.get(self.url + "?as_file=true") - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.headers["Content-Type"], "text.xml") - self.assertEqual( - response.headers["Content-Disposition"], - f"attachment; filename=HOT-project-{self.test_project.id}.osm", - ) - - -class TestTasksQueriesOwnInvalidatedAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_author_access_token = generate_encoded_token(self.test_author.id) - self.test_user = return_canned_user("TEST USER", 11111) - self.test_user.create() - self.test_user_access_token = generate_encoded_token(self.test_user.id) - self.url = ( - f"/api/v2/projects/{self.test_user.username}/tasks/queries/own/invalidated/" - ) - - @staticmethod - def invalidate_task(task: Task, mapper_id: int, validator_id: int): - """ - Helper function to invalidate a task. - ---------------- - Parameters: - task: Task object - mapper_id: int - validator_id: int - """ - if task.task_status == TaskStatus.MAPPED.value: - task.task_status = TaskStatus.READY.value - task.update() - - task.lock_task_for_mapping(mapper_id) - task.unlock_task(mapper_id, TaskStatus.MAPPED) - task.lock_task_for_validating(validator_id) - task.unlock_task(validator_id, TaskStatus.INVALIDATED) - - def test_returns_401_if_user_not_authorized(self): - """Test that a 401 is returned if the user is not authorized.""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_user_does_not_exist(self): - """Test that a 404 is returned if the user does not exist.""" - # Act - response = self.client.get( - "/api/v2/projects/non_existent/tasks/queries/own/invalidated/", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_invalidated_tasks_mapped_by_user_if_as_validator_set_false(self): - """ - Test that the invalidated tasks mapped by user are returned if the as_validator parameter is set to false. - """ - # Arrange - # Lets map a task by test user - task = Task.get(2, self.test_project.id) - TestTasksQueriesOwnInvalidatedAPI.invalidate_task( - task, self.test_user.id, self.test_author.id - ) - # Act - response = self.client.get( - self.url + "?asValidator=false", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["pagination"]["total"], 1) - self.assertEqual(len(response.json["invalidatedTasks"]), 1) - self.assertEqual( - response.json["invalidatedTasks"][0]["taskId"], 2 - ) # Since we invalidated task 2 - - def test_returns_tasks_invalidated_by_user_if_as_validator_set_true(self): - """ - Test that the tasks invalidated by user are returned if the as_validator parameter is set to true. - """ - # Arrange - # Lets map a task by test author and invalidate it by test user - task = Task.get(2, self.test_project.id) - TestTasksQueriesOwnInvalidatedAPI.invalidate_task( - task, self.test_author.id, self.test_user.id - ) - # Act - response = self.client.get( - self.url + "?asValidator=true", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["pagination"]["total"], 1) - self.assertEqual(len(response.json["invalidatedTasks"]), 1) - self.assertEqual(response.json["invalidatedTasks"][0]["taskId"], 2) - - def returns_404_if_no_tasks_found(self): - """Test that a 404 is returned if no tasks are found.""" - # Act - - response = self.client.get( - self.url + "?asValidator=true", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_sort_by_sorts_task_by_specified_fields(self): - """Test that the tasks are sorted by the specified_fields.""" - # Arrange - test_project_2, _ = create_canned_project() - test_project_3, _ = create_canned_project() - # Lets map a task by test author and invalidate it by test user - task_1 = Task.get(2, self.test_project.id) - TestTasksQueriesOwnInvalidatedAPI.invalidate_task( - task_1, self.test_author.id, self.test_user.id - ) - task_3 = Task.get(2, test_project_3.id) - TestTasksQueriesOwnInvalidatedAPI.invalidate_task( - task_3, self.test_author.id, self.test_user.id - ) - task_2 = Task.get(2, test_project_2.id) - TestTasksQueriesOwnInvalidatedAPI.invalidate_task( - task_2, self.test_author.id, self.test_user.id - ) - # Sort by projectId in ascending order - # Act - response = self.client.get( - self.url + "?asValidator=true&sortBy=projectId&sortDirection=asc", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["pagination"]["total"], 3) - self.assertEqual(len(response.json["invalidatedTasks"]), 3) - self.assertEqual( - response.json["invalidatedTasks"][0]["projectId"], self.test_project.id - ) - self.assertEqual( - response.json["invalidatedTasks"][1]["projectId"], test_project_2.id - ) - self.assertEqual( - response.json["invalidatedTasks"][2]["projectId"], test_project_3.id - ) - # Act - # Sort by projectId in descending order - response = self.client.get( - self.url + "?asValidator=true&sortBy=projectId&sortDirection=desc", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["pagination"]["total"], 3) - self.assertEqual(len(response.json["invalidatedTasks"]), 3) - self.assertEqual( - response.json["invalidatedTasks"][0]["projectId"], test_project_3.id - ) - self.assertEqual( - response.json["invalidatedTasks"][1]["projectId"], test_project_2.id - ) - self.assertEqual( - response.json["invalidatedTasks"][2]["projectId"], self.test_project.id - ) - # Act - # Sort by updatedDate in ascending order - response = self.client.get( - self.url + "?asValidator=true&sortBy=updatedDate&sortDirection=asc", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["pagination"]["total"], 3) - self.assertEqual(len(response.json["invalidatedTasks"]), 3) - self.assertEqual( - response.json["invalidatedTasks"][0]["projectId"], self.test_project.id - ) - self.assertEqual( - response.json["invalidatedTasks"][1]["projectId"], test_project_3.id - ) - self.assertEqual( - response.json["invalidatedTasks"][2]["projectId"], test_project_2.id - ) - # Act - # Sort by updatedDate in descending order - response = self.client.get( - self.url + "?asValidator=true&sortBy=updatedDate&sortDirection=desc", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["pagination"]["total"], 3) - self.assertEqual(len(response.json["invalidatedTasks"]), 3) - self.assertEqual( - response.json["invalidatedTasks"][0]["projectId"], test_project_2.id - ) - self.assertEqual( - response.json["invalidatedTasks"][1]["projectId"], test_project_3.id - ) - self.assertEqual( - response.json["invalidatedTasks"][2]["projectId"], self.test_project.id - ) - - def test_filters_by_closed(self): - """Test that the tasks are filtered by closed.""" - # Arrange - # Lets map a task by test author and invalidate it by test user - task_1 = Task.get(2, self.test_project.id) - TestTasksQueriesOwnInvalidatedAPI.invalidate_task( - task_1, self.test_author.id, self.test_user.id - ) - # Act - response = self.client.get( - self.url + "?asValidator=true&closed=true", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual( - response.json["pagination"]["total"], 0 - ) # No closed invalidated tasks - self.assertEqual(len(response.json["invalidatedTasks"]), 0) - - # Arrange - # Let's remap the task and validate it which will close it - task_1.lock_task_for_mapping(self.test_user.id) - task_1.unlock_task(self.test_user.id, TaskStatus.MAPPED) - task_1.lock_task_for_validating(self.test_user.id) - task_1.unlock_task(self.test_user.id, TaskStatus.VALIDATED) - # Act - response = self.client.get( - self.url + "?asValidator=true&closed=true", - headers={"Authorization": self.test_user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["pagination"]["total"], 1) - self.assertEqual(len(response.json["invalidatedTasks"]), 1) - self.assertEqual(response.json["invalidatedTasks"][0]["taskId"], task_1.id) - - -class TestTasksQueriesMappedAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.test_user = return_canned_user("TEST USER", 1111111) - self.test_user.create() - self.url = f"/api/v2/projects/{self.test_project.id}/tasks/queries/mapped/" - - def test_returns_404_if_project_does_not_exist(self): - """Test that the endpoint returns 404 if the project does not exist.""" - # Arrange - # Act - response = self.client.get("/api/v2/projects/999999/tasks/queries/mapped/") - # Assert - self.assertEqual(response.status_code, 404) - - def test_get_mapped_tasks(self): - # Arrange - # Lets reset all tasks in a project to be available for mapping - ProjectAdminService.reset_all_tasks(self.test_project.id, self.test_author.id) - # Lets map a tasks - task_1 = Task.get(1, self.test_project.id) - task_2 = Task.get(2, self.test_project.id) - task_1.lock_task_for_mapping(self.test_user.id) - task_1.unlock_task(self.test_user.id, TaskStatus.MAPPED) - task_2.lock_task_for_mapping(self.test_author.id) - task_2.unlock_task(self.test_author.id, TaskStatus.MAPPED) - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual( - response.json["mappedTasks"][0]["username"], self.test_user.username - ) - self.assertEqual( - response.json["mappedTasks"][1]["username"], self.test_author.username - ) - self.assertEqual(response.json["mappedTasks"][0]["mappedTaskCount"], 1) - self.assertEqual(response.json["mappedTasks"][1]["mappedTaskCount"], 1) - self.assertEqual(response.json["mappedTasks"][0]["tasksMapped"], [1]) - self.assertEqual(response.json["mappedTasks"][1]["tasksMapped"], [2]) diff --git a/tests/backend/integration/api/tasks/test_statistics.py b/tests/backend/integration/api/tasks/test_statistics.py deleted file mode 100644 index 9d6578d523..0000000000 --- a/tests/backend/integration/api/tasks/test_statistics.py +++ /dev/null @@ -1,264 +0,0 @@ -from datetime import datetime, timedelta - -from backend.models.postgis.task import Task, TaskStatus -from backend.services.campaign_service import CampaignProjectDTO, CampaignService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_campaign, - create_canned_organisation, - create_canned_project, - generate_encoded_token, - return_canned_user, -) - - -class TestTasksStatisticsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.url = "/api/v2/tasks/statistics/" - self.test_user = return_canned_user("test_user", 1111111) - self.test_user.create() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.test_project_1, _ = create_canned_project() - self.test_project_2, _ = create_canned_project() - TestTasksStatisticsAPI.create_task_history( - 1, self.test_project_1.id, self.test_user.id, TaskStatus.MAPPED - ) - TestTasksStatisticsAPI.create_task_history( - 2, self.test_project_1.id, self.test_user.id, TaskStatus.VALIDATED - ) - TestTasksStatisticsAPI.create_task_history( - 3, self.test_project_2.id, self.test_user.id, TaskStatus.MAPPED - ) - - def test_returns_401_if_not_authenticated(self): - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_400_if_start_date_is_not_provided(self): - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "MissingDate") - - def test_returns_400_if_start_date_is_not_valid(self): - """Test returns 400 if start date is not valid""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"startDate": "not a date"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidDateValue") - - def test_returns_400_if_end_date_is_not_valid(self): - """Test returns 400 if end date is not valid""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"startDate": "2020-01-01", "endDate": "not a date"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidDateValue") - - def test_returns_400_if_start_date_is_after_end_date(self): - """Test returns 400 if start date is after end date""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"startDate": "2020-01-02", "endDate": "2020-01-01"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidDateRange") - - def test_returns_400_if_date_range_is_greater_than_1_year(self): - """Test returns 400 if date range is greater than 1 year""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": "2019-01-01", - "endDate": datetime.now().strftime("%Y-%m-%d"), - }, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidDateRange") - - def test_returns_200_if_valid_date_range(self): - """Test returns 200 if date range is valid""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": (datetime.now() - timedelta(days=6 * 30)).strftime( - "%Y-%m-%d" - ) - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskStats"][0]["mapped"], 2) - self.assertEqual(response.json["taskStats"][0]["validated"], 1) - self.assertEqual(response.json["taskStats"][0]["badImagery"], 0) - - @staticmethod - def create_task_history(task_id, project_id, user_id, action): - """Create task history""" - task = Task.get(task_id, project_id) - if action in [TaskStatus.MAPPED, TaskStatus.BADIMAGERY]: - task.lock_task_for_mapping(user_id) - elif action == TaskStatus.VALIDATED: - task.lock_task_for_validating(user_id) - task.unlock_task(user_id, action) - - def test_filters_task_by_project(self): - """Test filters task by project""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": (datetime.now() - timedelta(days=6 * 30)).strftime( - "%Y-%m-%d" - ), - "projectId": self.test_project_1.id, - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskStats"][0]["mapped"], 1) - self.assertEqual(response.json["taskStats"][0]["validated"], 1) - self.assertEqual(response.json["taskStats"][0]["badImagery"], 0) - - def test_filters_by_multiple_projects(self): - """Test filters by multiple projects""" - # Arrange - test_project_3, _ = create_canned_project() - TestTasksStatisticsAPI.create_task_history( - 4, test_project_3.id, self.test_user.id, TaskStatus.MAPPED - ) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": (datetime.now() - timedelta(days=6 * 30)).strftime( - "%Y-%m-%d" - ), - "projectId": f"{self.test_project_1.id}, {self.test_project_2.id}", - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskStats"][0]["mapped"], 2) - self.assertEqual(response.json["taskStats"][0]["validated"], 1) - self.assertEqual(response.json["taskStats"][0]["badImagery"], 0) - - def test_filters_by_organisation_id(self): - """Test filters by organisation id""" - # Arrange - test_organisation = create_canned_organisation() - self.test_project_1.organisation_id = test_organisation.id - self.test_project_1.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": (datetime.now() - timedelta(days=6 * 30)).strftime( - "%Y-%m-%d" - ), - "organisationId": test_organisation.id, - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskStats"][0]["mapped"], 1) - self.assertEqual(response.json["taskStats"][0]["validated"], 1) - self.assertEqual(response.json["taskStats"][0]["badImagery"], 0) - - def test_filters_by_organisation_name(self): - """Test filters by organisation name""" - # Arrange - test_organisation = create_canned_organisation() - self.test_project_1.organisation_id = test_organisation.id - self.test_project_1.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": (datetime.now() - timedelta(days=6 * 30)).strftime( - "%Y-%m-%d" - ), - "organisationName": test_organisation.name, - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskStats"][0]["mapped"], 1) - self.assertEqual(response.json["taskStats"][0]["validated"], 1) - self.assertEqual(response.json["taskStats"][0]["badImagery"], 0) - - def test_filters_by_campaign(self): - """Test filters by campaign""" - # Arrange - test_campaign = create_canned_campaign() - campaign_dto = CampaignProjectDTO() - campaign_dto.campaign_id = test_campaign.id - campaign_dto.project_id = self.test_project_2.id - CampaignService.create_campaign_project(campaign_dto) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": (datetime.now() - timedelta(days=6 * 30)).strftime( - "%Y-%m-%d" - ), - "campaign": test_campaign.name, - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskStats"][0]["mapped"], 1) - self.assertEqual(response.json["taskStats"][0]["validated"], 0) - self.assertEqual(response.json["taskStats"][0]["badImagery"], 0) - - def test_filters_by_country(self): - """Test filters by country""" - # Arrange - self.test_project_1.country = ["Nepal"] - self.test_project_1.save() - self.test_project_2.country = ["England"] - self.test_project_2.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": (datetime.now() - timedelta(days=6 * 30)).strftime( - "%Y-%m-%d" - ), - "country": "Nepal", - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["taskStats"][0]["mapped"], 1) - self.assertEqual(response.json["taskStats"][0]["validated"], 1) - self.assertEqual(response.json["taskStats"][0]["badImagery"], 0) diff --git a/tests/backend/integration/api/teams/__init__.py b/tests/backend/integration/api/teams/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/teams/test_actions.py b/tests/backend/integration/api/teams/test_actions.py deleted file mode 100644 index fd72734995..0000000000 --- a/tests/backend/integration/api/teams/test_actions.py +++ /dev/null @@ -1,480 +0,0 @@ -from unittest.mock import patch - -from backend.exceptions import get_message_from_sub_code -from backend.models.postgis.statuses import ( - TeamJoinMethod, - TeamMemberFunctions, - UserRole, -) -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_user_to_team, - create_canned_team, - create_canned_user, - generate_encoded_token, - return_canned_organisation, - return_canned_user, -) - -TEST_ADMIN_USERNAME = "Test Admin" -TEST_MESSAGE = "This is a test message" -TEST_SUBJECT = "Test Subject" -NON_EXISTENT_USER = "Random User" - -TEAM_NOT_FOUND_SUB_CODE = "TEAM_NOT_FOUND" -USER_NOT_FOUND_SUB_CODE = "USER_NOT_FOUND" -TEAM_NOT_FOUND_MESSAGE = get_message_from_sub_code(TEAM_NOT_FOUND_SUB_CODE) -USER_NOT_FOUND_MESSAGE = get_message_from_sub_code(USER_NOT_FOUND_SUB_CODE) - - -class TestTeamsActionsJoinAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_team = create_canned_team() - self.test_user = create_canned_user() - self.test_org = return_canned_organisation() - self.test_admin = return_canned_user(username=TEST_ADMIN_USERNAME, id=11111) - self.test_admin.create() - self.test_admin.role = UserRole.ADMIN.value - self.admin_token = generate_encoded_token(self.test_admin.id) - self.session_token = generate_encoded_token(self.test_user.id) - self.endpoint_url = f"/api/v2/teams/{self.test_team.id}/actions/join/" - - # post - def test_request_to_join_team_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when unauthenticated user requests to join a team - """ - response = self.client.post(self.endpoint_url) - self.assertEqual(response.status_code, 401) - - def test_request_to_join_team_by_authenticated_user_passes(self): - """ - Test that endpoint returns 200 when authenticated user requests to join a team - """ - response = self.client.post( - self.endpoint_url, headers={"Authorization": self.session_token} - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Join request successful") - - def test_request_to_join_non_existent_team_fails(self): - """ - Test that endpoint returns 404 when a user requests to join a non existent team - """ - response = self.client.post( - "/api/v2/teams/99/actions/join/", - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 404) - self.assertEqual(response_body["error"]["message"], TEAM_NOT_FOUND_MESSAGE) - - def test_request_to_join_team_with_invite_only_request_fails(self): - """ - Test that endpoint returns 400 when a user requests to join a team that can only be joined by invite - """ - self.test_team.join_method = TeamJoinMethod.BY_INVITE.value - response = self.client.post( - self.endpoint_url, headers={"Authorization": self.session_token} - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["Error"], "Team join method is BY_INVITE") - - # patch - def test_handle_join_request_by_admin_passes(self): - """ - Test that endpoint returns 200 when admin accepts a join request - """ - add_user_to_team( - team=self.test_team, - user=self.test_user, - role=TeamMemberFunctions.MEMBER.value, - is_active=True, - ) - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.admin_token}, - json={ - "action": "accept", - "role": "member", - "type": "join-response", - "username": self.test_user.username, - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "True") - - def test_handle_join_request_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when an unauthenticated user tries to accept a join request - """ - response = self.client.patch( - self.endpoint_url, - json={ - "action": "accept", - "role": "member", - "type": "join-response", - "username": self.test_user.username, - }, - ) - self.assertEqual(response.status_code, 401) - - def test_handle_join_request_by_non_admin_fails(self): - """ - Test that endpoint returns 403 when a non admin tries to accept a join request - """ - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.session_token}, - json={ - "action": "accept", - "role": "member", - "type": "join-response", - "username": self.test_user.username, - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], - "You don't have permissions to approve this join team request", - ) - self.assertEqual(response_body["SubCode"], "ApproveJoinError") - - def test_handle_join_request_to_non_existent_team_fails(self): - """ - Test that endpoint returns 404 when handling a join request to a non existent team - """ - response = self.client.patch( - "/api/v2/teams/99/actions/join/", - headers={"Authorization": self.session_token}, - json={ - "action": "accept", - "role": "member", - "type": "join-response", - "username": self.test_user.username, - }, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], TEAM_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], TEAM_NOT_FOUND_SUB_CODE) - - -class TestTeamsActionsAddAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_team = create_canned_team() - self.test_user = create_canned_user() - self.test_org = return_canned_organisation() - self.test_admin = return_canned_user(username=TEST_ADMIN_USERNAME, id=11111) - self.test_admin.create() - self.test_admin.role = UserRole.ADMIN.value - self.admin_token = generate_encoded_token(self.test_admin.id) - self.session_token = generate_encoded_token(self.test_user.id) - self.endpoint_url = f"/api/v2/teams/{self.test_team.id}/actions/add/" - - def test_add_members_to_team_by_admin_passes(self): - """ - Test that endpoint returns 200 when admin adds members to a team successfully - """ - response = self.client.post( - self.endpoint_url, - json={ - "username": self.test_user.username, - "role": TeamMemberFunctions.MEMBER.name.lower(), - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "User added to the team") - - def test_add_members_to_team_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when an unauthenticated user tries to add members to a team - """ - response = self.client.post( - self.endpoint_url, - json={ - "username": self.test_user.username, - "role": TeamMemberFunctions.MEMBER.name.lower(), - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_add_members_to_team_using_invalid_data_fails(self): - """ - Test that endpoint returns 400 when invalid data is used to add members to a team - """ - response = self.client.post( - self.endpoint_url, - json={ - "user_username": self.test_user.username, - "team_role": TeamMemberFunctions.MEMBER.name.lower(), - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["SubCode"], "InvalidData") - - def test_add_members_to_team_by_non_admin_fails(self): - """ - Test that the endpoint returns 500 when non-admin handles a join request - """ - response = self.client.post( - self.endpoint_url, - json={ - "username": self.test_user.username, - "role": TeamMemberFunctions.MEMBER.name.lower(), - }, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 500) - error_resp = response_body["error"] - self.assertEqual(error_resp["sub_code"], "INTERNAL_SERVER_ERROR") - self.assertTrue( - "User is not allowed to add member to the team" in error_resp["message"] - ) - - def test_add_non_existent_members_to_team_fails(self): - """ - Test that endpoint returns 500 when adding non existent users to a team - """ - response = self.client.post( - self.endpoint_url, - json={ - "username": NON_EXISTENT_USER, - "role": TeamMemberFunctions.MEMBER.name.lower(), - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 404) - error_resp = response_body["error"] - self.assertEqual(error_resp["sub_code"], "USER_NOT_FOUND") - - def test_add_members_to_non_existent_team_fails(self): - """ - Test that endpoint returns 500 when adding users to a non_existent team - """ - response = self.client.post( - "/api/v2/teams/99/actions/add/", - json={ - "username": NON_EXISTENT_USER, - "role": TeamMemberFunctions.MEMBER.name.lower(), - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 404) - error_resp = response_body["error"] - self.assertEqual(error_resp["sub_code"], "TEAM_NOT_FOUND") - - -class TestTeamsActionsLeaveAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_team = create_canned_team() - self.test_user = create_canned_user() - self.test_org = return_canned_organisation() - self.test_admin = return_canned_user(username=TEST_ADMIN_USERNAME, id=11111) - self.test_admin.create() - self.test_admin.role = UserRole.ADMIN.value - self.admin_token = generate_encoded_token(self.test_admin.id) - self.session_token = generate_encoded_token(self.test_user.id) - self.endpoint_url = f"/api/v2/teams/{self.test_team.id}/actions/leave/" - - def test_remove_members_from_team_by_admin_passes(self): - """ - Test that endpoint returns 200 when an admin successfully removes existent member from team - """ - # Act: add member to the team - add_user_to_team( - team=self.test_team, - user=self.test_user, - role=TeamMemberFunctions.MEMBER.value, - is_active=True, - ) - - # Test: remove user from team - response = self.client.post( - self.endpoint_url, - json={ - "username": self.test_user.username, - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "User removed from the team") - - def test_remove_members_from_team_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when an unauthenticated user tries to remove a member from the team - """ - response = self.client.post( - self.endpoint_url, - json={ - "username": self.test_user.username, - }, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_remove_members_from_team_by_non_admin_fails(self): - """ - Test that endpoint returns 403 when a non-admin tries to remove a member from the team - """ - response = self.client.post( - self.endpoint_url, - json={ - "username": self.test_admin.username, - }, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], - f"You don't have permissions to remove {TEST_ADMIN_USERNAME} from this team.", - ) - self.assertEqual(response_body["SubCode"], "RemoveUserError") - - def test_remove_non_existent_members_from_team_fails(self): - """ - Test that endpoint returns 404 when attempting to remove non-existent members from a team - """ - response = self.client.post( - self.endpoint_url, - json={ - "username": NON_EXISTENT_USER, - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], USER_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], USER_NOT_FOUND_SUB_CODE) - - def test_remove_members_from_non_existent_team_fails(self): - """ - Test that endpoint returns 404 when attempting to remove members from a non-existent team - """ - response = self.client.post( - "/api/v2/teams/99/actions/leave/", - json={ - "username": self.test_user.username, - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], TEAM_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], TEAM_NOT_FOUND_SUB_CODE) - - -class TestTeamsActionsMessageMembersAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_team = create_canned_team() - self.test_user = create_canned_user() - self.test_org = return_canned_organisation() - self.test_admin = return_canned_user(username=TEST_ADMIN_USERNAME, id=11111) - self.test_admin.create() - self.test_admin.role = UserRole.ADMIN.value - self.admin_token = generate_encoded_token(self.test_admin.id) - self.session_token = generate_encoded_token(self.test_user.id) - self.endpoint_url = ( - f"/api/v2/teams/{self.test_team.id}/actions/message-members/" - ) - - def test_message_members_non_existent_team_fails(self): - """ - Test that endpoint returns 404 when messaging members of non-existent team - """ - response = self.client.post( - "/api/v2/teams/99/actions/message-members/", - json={"message": TEST_MESSAGE, "subject": TEST_SUBJECT}, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], TEAM_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], TEAM_NOT_FOUND_SUB_CODE) - - def test_message_team_members_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 when messaging members by an unauthenticated user - """ - response = self.client.post( - self.endpoint_url, - json={"message": TEST_MESSAGE, "subject": TEST_SUBJECT}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["SubCode"], "InvalidToken") - - def test_message_team_members_by_non_admin_fails(self): - """ - Test that endpoint returns 403 when messaging members by a non admin - """ - response = self.client.post( - self.endpoint_url, - json={"message": TEST_MESSAGE, "subject": TEST_SUBJECT}, - headers={"Authorization": self.session_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "Unauthorised to send message to team members" - ) - self.assertEqual(response_body["SubCode"], "UserNotPermitted") - - def test_message_team_members_with_invalid_data_fails(self): - """ - Test that endpoint returns 400 when sending invalid request data to the messaging API - """ - response = self.client.post( - self.endpoint_url, - json={ - "message": ["Message should be a string type not list"], - "subject": "", - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual( - response_body["Error"], "Request payload did not match validation" - ) - self.assertEqual(response_body["SubCode"], "InvalidData") - - @patch("threading.Thread.start") - def test_message_team_members_with_valid_message_by_admin_passes(self, mock_thread): - """ - Test that endpoint returns 200 when sending vaalid message to team members - """ - # Mock the thread start method to avoid application context issues - mock_thread.return_value = None - response = self.client.post( - self.endpoint_url, - json={"message": TEST_MESSAGE, "subject": TEST_SUBJECT}, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Message sent successfully") diff --git a/tests/backend/integration/api/teams/test_resources.py b/tests/backend/integration/api/teams/test_resources.py deleted file mode 100644 index fa5855687e..0000000000 --- a/tests/backend/integration/api/teams/test_resources.py +++ /dev/null @@ -1,275 +0,0 @@ -from backend.models.postgis.statuses import UserRole -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_organisation, - create_canned_team, - create_canned_user, - generate_encoded_token, - return_canned_team, - return_canned_user, -) -from tests.backend.integration.api.organisations.test_resources import ( - ORG_NOT_FOUND_MESSAGE, - ORG_NOT_FOUND_SUB_CODE, -) -from tests.backend.integration.api.teams.test_actions import ( - TEAM_NOT_FOUND_MESSAGE, - TEAM_NOT_FOUND_SUB_CODE, -) - -TEST_ORGANISATION_NAME = "Kathmandu Living Labs" -TEST_ORGANISATION_SLUG = "KLL" -TEST_ORGANISATION_ID = 23 -TEST_TEAM_NAME = "Test Team" -NEW_TEAM_NAME = "KLL Team" - - -class TestTeamsRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_org = create_canned_organisation() - self.test_user = create_canned_user() - self.test_user_token = generate_encoded_token(self.test_user.id) - self.test_team = create_canned_team() - self.endpoint_url = f"/api/v2/teams/{self.test_team.id}/" - - # get - def test_get_non_existent_team_by_id_fails(self): - """ - Test that endpoint returns 404 if team does not exist - """ - response = self.client.get("/api/v2/teams/99/") - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], TEAM_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], TEAM_NOT_FOUND_SUB_CODE) - - def test_get_team_by_id_passes(self): - """ - Test that endpoint returns 200 when retrieving existing team - """ - response = self.client.get(self.endpoint_url) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["name"], TEST_TEAM_NAME) - self.assertEqual(response_body["organisation_id"], TEST_ORGANISATION_ID) - self.assertEqual(response_body["organisationSlug"], TEST_ORGANISATION_SLUG) - self.assertEqual(response_body["organisation"], TEST_ORGANISATION_NAME) - self.assertEqual(response_body["is_org_admin"], False) - self.assertEqual(response_body["team_projects"], []) - - # patch - def test_update_team_by_admin_passes(self): - """ - Test that endpoint returns 200 if team update is successful - """ - self.test_user.role = UserRole.ADMIN.value - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.test_user_token}, - json={"name": NEW_TEAM_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body, {"Status": "Updated"}) - - def test_update_team_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 if an unauthenticated user tries to update a team - """ - response = self.client.patch(self.endpoint_url, json={"name": NEW_TEAM_NAME}) - self.assertEqual(response.status_code, 401) - - def test_update_team_by_non_admin_fails(self): - """ - Test that endpoint returns 403 if a non_admin tries to update a team - - """ - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.test_user_token}, - json={"name": NEW_TEAM_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], "User is not a admin or a manager for the team" - ) - self.assertEqual(response_body["SubCode"], "UserNotTeamManager") - - def test_update_team_with_invalid_data_fails(self): - """ - Test that endpoint returns 400 if an admin tries to update a team using the wrong request keys/data - """ - response = self.client.patch( - self.endpoint_url, - headers={"Authorization": self.test_user_token}, - json={"team_name": NEW_TEAM_NAME}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 400) - self.assertEqual(response_body["SubCode"], "InvalidData") - - # delete - def test_delete_team_by_admin_passes(self): - """ - Test that endpoint returns 200 upon successful deletion of a team - """ - self.test_user.role = UserRole.ADMIN.value - response = self.client.delete( - self.endpoint_url, headers={"Authorization": self.test_user_token} - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(response_body["Success"], "Team deleted") - - def test_delete_team_by_unauthenticated_user_fails(self): - """ - Test that endpoint returns 401 if an unauthenticated user tries to delete a team - """ - response = self.client.delete(self.endpoint_url) - self.assertEqual(response.status_code, 401) - - def test_delete_team_by_non_admin_fails(self): - """ - Test that endpoint returns 401 if a non_admin tries to delete a team - """ - response = self.client.delete( - self.endpoint_url, headers={"Authorization": self.test_user_token} - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 401) - self.assertEqual(response_body["Error"], "User is not a manager for the team") - self.assertEqual(response_body["SubCode"], "UserNotTeamManager") - - def test_delete_non_existent_team_by_id_fails(self): - """ - Test that endpoint returns 404 while deleting a non-existent team - """ - self.test_user.role = UserRole.ADMIN.value - response = self.client.delete( - "/api/v2/teams/99/", headers={"Authorization": self.test_user_token} - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], TEAM_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], TEAM_NOT_FOUND_SUB_CODE) - - -class TestTeamsAllPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_org = create_canned_organisation() - self.test_admin = return_canned_user("test user", 111111) - self.test_admin.create() - self.test_admin.role = UserRole.ADMIN.value - self.admin_token = generate_encoded_token(self.test_admin.id) - self.test_non_admin = create_canned_user() - self.non_admin_token = generate_encoded_token(self.test_non_admin.id) - self.endpoint_url = "/api/v2/teams/" - - # post - def test_create_new_team_for_non_existent_org_fails(self): - """ - Test that endpoint returns 404 when creating a team for a non-existent organisation - """ - response = self.client.post( - self.endpoint_url, - json={ - "description": "", - "joinMethod": "ANY", - "name": "KLL Team", - "organisation_id": 99, - "visibility": "PUBLIC", - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - error_details = response_body["error"] - self.assertEqual(response.status_code, 404) - self.assertEqual(error_details["message"], ORG_NOT_FOUND_MESSAGE) - self.assertEqual(error_details["sub_code"], ORG_NOT_FOUND_SUB_CODE) - - def test_create_new_team_non_admin_fails(self): - """ - Test that endpoint returns 403 when creating a team by a non-admin - """ - response = self.client.post( - self.endpoint_url, - json={ - "description": None, - "joinMethod": "ANY", - "name": NEW_TEAM_NAME, - "organisation_id": TEST_ORGANISATION_ID, - "visibility": "PUBLIC", - }, - headers={"Authorization": self.non_admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 403) - self.assertEqual( - response_body["Error"], - "User not permitted to create team for the Organisation", - ) - self.assertEqual(response_body["SubCode"], "CreateTeamNotPermitted") - - def test_create_new_team_existent_org_passes(self): - """ - Test that endpoint returns 201 when creating a team by admin for an existent organisation - """ - response = self.client.post( - self.endpoint_url, - json={ - "description": None, - "joinMethod": "ANY", - "name": NEW_TEAM_NAME, - "organisation_id": TEST_ORGANISATION_ID, - "visibility": "PUBLIC", - }, - headers={"Authorization": self.admin_token}, - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 201) - self.assertEqual(response_body, {"teamId": 1}) - - # get - def test_get_teams_authorised_passes(self): - """ - Test that endpoint returns 200 when retrieving teams - """ - self.test_team = return_canned_team( - name=TEST_TEAM_NAME, org_name=self.test_org.name - ) - self.test_team.create() - response = self.client.get( - self.endpoint_url, headers={"Authorization": self.admin_token} - ) - response_body = response.get_json() - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response_body["teams"]), 1) - self.assertEqual( - response_body["teams"], - [ - { - "teamId": 2, - "organisationId": 23, - "description": None, - "joinMethod": "ANY", - "logo": None, - "managersCount": 0, - "members": [], - "membersCount": 0, - "name": TEST_TEAM_NAME, - "organisation": TEST_ORGANISATION_NAME, - "visibility": "PUBLIC", - } - ], - ) - - def test_get_teams_unauthorised_fails(self): - response = self.client.get( - self.endpoint_url, - ) - self.assertEqual(response.status_code, 401) diff --git a/tests/backend/integration/api/users/__init__.py b/tests/backend/integration/api/users/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/api/users/test_actions.py b/tests/backend/integration/api/users/test_actions.py deleted file mode 100644 index 412b9985d7..0000000000 --- a/tests/backend/integration/api/users/test_actions.py +++ /dev/null @@ -1,309 +0,0 @@ -from unittest.mock import patch - -from backend.models.postgis.statuses import UserRole -from backend.services.messaging.smtp_service import SMTPService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_interest, - generate_encoded_token, - return_canned_user, -) - -TEST_EMAIL = "test@test.com" - - -class TestUsersActionsSetUsersAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user() - self.test_user.create() - self.url = "/api/v2/users/me/actions/set-user/" - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_returns_401_if_no_token(self): - """Test that the API returns 401 if no token is provided""" - # Act - response = self.client.patch(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_401_if_other_user_requested(self): - """Test that the API returns 401 if another user is requested""" - # Act - response = self.client.patch( - self.url, - headers={"Authorization": self.user_session_token}, - json={"id": 2}, - ) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_400_if_invalid_data(self): - """Test that the API returns 400 if invalid data is provided""" - # Act - response = self.client.patch( - self.url, - headers={"Authorization": self.user_session_token}, - json={"id": self.test_user.id, "emailAddress": "invalid_email"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - - def test_returns_404_if_user_not_found(self): - """Test that the API returns 404 if user is not found""" - # Act - response = self.client.patch( - self.url, - headers={"Authorization": generate_encoded_token(999)}, - json={"id": 999}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_200_if_user_updated(self): - """Test that the API returns 200 if user is updated""" - # Arrange - sample_payload = { - "id": self.test_user.id, - "name": "ThinkWhere", - "city": "test_city", - "country": "AD", - "twitterId": "test_twitter", - "facebookId": "test_facebook", - "linkedinId": "test_linkedin", - "slackId": "test_slack", - "gender": "MALE", - "selfDescriptionGender": None, - } - # Act - response = self.client.patch( - self.url, - headers={"Authorization": self.user_session_token}, - json=sample_payload, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["verificationEmailSent"], False) - self.assertEqual(self.test_user.name, sample_payload["name"]) - self.assertEqual(self.test_user.city, sample_payload["city"]) - self.assertEqual(self.test_user.country, sample_payload["country"]) - self.assertEqual(self.test_user.twitter_id, sample_payload["twitterId"]) - self.assertEqual(self.test_user.facebook_id, sample_payload["facebookId"]) - self.assertEqual(self.test_user.linkedin_id, sample_payload["linkedinId"]) - self.assertEqual(self.test_user.slack_id, sample_payload["slackId"]) - - @patch.object(SMTPService, "send_verification_email") - def test_returns_200_if_user_updated_with_email(self, mock_send_verification_email): - """Test that the API returns 200 if user is updated""" - # Arrange - mock_send_verification_email.return_value = True - # Act - response = self.client.patch( - self.url, - headers={"Authorization": self.user_session_token}, - json={"id": self.test_user.id, "emailAddress": TEST_EMAIL}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["verificationEmailSent"], True) - - -class TestUsersActionsRegisterEmailAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.url = "/api/v2/users/actions/register/" - - def test_returns_400_if_no_data(self): - """Test that the API returns 400 if no data is provided""" - # Act - response = self.client.post(self.url, content_type="application/json") - # Assert - self.assertEqual(response.status_code, 400) - - def test_returns_200_if_email_registered(self): - """Test that the API returns 200 if email is registered""" - # Arrange - sample_payload = {"email": TEST_EMAIL} - # Act - response = self.client.post(self.url, json=sample_payload) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["email"], TEST_EMAIL) - self.assertEqual(response.json["success"], True) - - -class TestUsersActionsSetInterestsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user() - self.test_user.create() - self.url = "/api/v2/users/me/actions/set-interests/" - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_returns_401_if_no_token(self): - """Test that the API returns 401 if no token is provided""" - # Act - response = self.client.post(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_404_if_interests_not_found(self): - """Test that the API returns 404 if interests are not found""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"interests": [999]}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_400_if_invalid_data(self): - """Test that the API returns 400 if invalid data is provided""" - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json={"key": "invalid"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - - def test_returns_200_if_interests_set(self): - """Test that the API returns 200 if interests are set""" - # Arrange - interest_1 = create_canned_interest("test_interest_1") - interest_2 = create_canned_interest("test_interest_2") - sample_payload = {"interests": [interest_1.id, interest_2.id]} - # Act - response = self.client.post( - self.url, - headers={"Authorization": self.user_session_token}, - json=sample_payload, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["interests"]), 2) - self.assertEqual(response.json["interests"][0]["id"], interest_1.id) - self.assertEqual(response.json["interests"][1]["id"], interest_2.id) - - -class TestUsersActionsVerifyEmailAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user() - self.test_user.create() - self.url = "/api/v2/users/me/actions/verify-email/" - self.user_session_token = generate_encoded_token(self.test_user.id) - - def test_returns_401_if_no_token(self): - """Test that the API returns 401 if no token is provided""" - # Act - response = self.client.patch(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_400_if_user_has_not_set_email(self): - """Test that the API returns 400 if user has not set email""" - # Act - response = self.client.patch( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 400) - - @patch.object(SMTPService, "_send_message") - def test_returns_200_if_verification_email_resent(self, mock_send_message): - """Test that the API returns 200 if verification email is resent""" - # Arrange - self.test_user.email_address = TEST_EMAIL - self.test_user.save() - # Act - response = self.client.patch( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - mock_send_message.assert_called_once() - - -class TestUsersActionsSetRoleAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user() - self.test_user.create() - self.admin_user = return_canned_user("test_admin", 222222) - self.admin_user.role = UserRole.ADMIN.value - self.admin_user.create() - self.url = f"/api/v2/users/{self.test_user.username}/actions/set-role/{UserRole.ADMIN.name}/" - self.user_session_token = generate_encoded_token(self.test_user.id) - self.admin_session_token = generate_encoded_token(self.admin_user.id) - - def test_returns_401_if_no_token(self): - """Test that the API returns 401 if no token is provided""" - # Act - response = self.client.patch(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_403_if_user_not_admin(self): - """Test that the API returns 403 if user is not admin""" - # Act - response = self.client.patch( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "NeedAdminRole") - - def test_returns_403_if_unknown_user_role(self): - """Test API returns 403 if unknown user role is provided""" - # Act - response = self.client.patch( - f"/api/v2/users/{self.test_user.username}/actions/set-role/GOD/", - headers={"Authorization": self.admin_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 403) - self.assertEqual(response.json["SubCode"], "UnknownAddRole") - - def test_returns_404_if_user_not_found(self): - """Test that the API returns 404 if user is not found""" - # Act - response = self.client.patch( - "/api/v2/users/unknown/actions/set-role/ADMIN/", - headers={"Authorization": self.admin_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], "USER_NOT_FOUND") - - def test_returns_200_if_user_role_set(self): - """Test that the API returns 200 if user role is set""" - # Act - response = self.client.patch( - self.url, - headers={"Authorization": self.admin_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["Success"], "Role Added") - self.assertEqual(self.test_user.role, UserRole.ADMIN.value) - - def test_returns_200_if_user_role_removed(self): - """Test that the API returns 200 if user role is removed""" - # Arrange - self.test_user.role = UserRole.ADMIN.value - self.test_user.save() - # Act - response = self.client.patch( - f"/api/v2/users/{self.test_user.username}/actions/set-role/{UserRole.MAPPER.name}/", - headers={"Authorization": self.admin_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["Success"], "Role Added") - self.assertEqual(self.test_user.role, UserRole.MAPPER.value) diff --git a/tests/backend/integration/api/users/test_openstreetmap.py b/tests/backend/integration/api/users/test_openstreetmap.py deleted file mode 100644 index bcd4ad3f2e..0000000000 --- a/tests/backend/integration/api/users/test_openstreetmap.py +++ /dev/null @@ -1,60 +0,0 @@ -from unittest.mock import patch - -from backend.services.users.osm_service import OSMService, OSMServiceError, UserOSMDTO -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - generate_encoded_token, - return_canned_user, -) - -TEST_USERNAME = "testuser" -TEST_USER_ID = 111111 - - -class TestUsersOpenStreetMapAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.test_user.create() - self.user_access_token = generate_encoded_token(TEST_USER_ID) - self.url = f"/api/v2/users/{self.test_user.username}/openstreetmap/" - - def test_returns_401_if_user_not_authorized(self): - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_user_not_found(self): - # Act - response = self.client.get( - "/api/v2/users/doesnotexist/openstreetmap/", - headers={"Authorization": self.user_access_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - @patch.object(OSMService, "get_osm_details_for_user") - def test_returns_502_if_osm_service_error(self, mock_osm_service): - # Arrange - mock_osm_service.side_effect = OSMServiceError("Bad response from OSM") - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_access_token} - ) - # Assert - self.assertEqual(response.status_code, 502) - - @patch.object(OSMService, "get_osm_details_for_user") - def test_returns_200_if_user_found(self, mock_osm_service): - # Arrange - user_dto = UserOSMDTO({"accountCreated": "1234567890", "changesetCount": 123}) - mock_osm_service.return_value = user_dto - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_access_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["accountCreated"], user_dto.account_created) - self.assertEqual(response.json["changesetCount"], user_dto.changeset_count) diff --git a/tests/backend/integration/api/users/test_resources.py b/tests/backend/integration/api/users/test_resources.py deleted file mode 100644 index 848ec79601..0000000000 --- a/tests/backend/integration/api/users/test_resources.py +++ /dev/null @@ -1,692 +0,0 @@ -from backend.exceptions import get_message_from_sub_code -from backend.models.postgis.statuses import MappingLevel, UserGender, UserRole -from backend.models.postgis.task import Task, TaskStatus -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_interest, - create_canned_project, - generate_encoded_token, - return_canned_user, -) -from typing import Optional - -TEST_USERNAME = "test_user" -TEST_USER_ID = 1111111 -TEST_EMAIL = "test@hotmail.com" -USER_NOT_FOUND_SUB_CODE = "USER_NOT_FOUND" -USER_NOT_FOUND_MESSAGE = get_message_from_sub_code(USER_NOT_FOUND_SUB_CODE) - - -class TestUsersQueriesOwnLockedDetailsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.user.create() - self.user_session_token = generate_encoded_token(TEST_USER_ID) - self.url = "/api/v2/users/queries/tasks/locked/details/" - - def test_returns_401_without_session_token(self): - """Test that the API returns 401 if no session token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_no_tasks_locked(self): - """Test that the API returns 404 if no task is locked by user""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], "TASK_NOT_FOUND") - - def test_returns_200_if_tasks_locked(self): - """Test that the API returns 200 if a task is locked by user""" - # Arrange - # Lock a task - test_project, _ = create_canned_project() - task = Task.get(1, test_project.id) - task.lock_task_for_mapping(self.user.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 1) - self.assertEqual(response.json["tasks"][0]["taskId"], 1) - self.assertEqual(response.json["tasks"][0]["projectId"], test_project.id) - - -class TestUsersQueriesUsernameAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.user.create() - self.user_session_token = generate_encoded_token(TEST_USER_ID) - self.url = f"/api/v2/users/queries/{self.user.username}/" - - def test_returns_401_without_session_token(self): - """Test that the API returns 401 if no session token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_user_not_found(self): - """Test that the API returns 404 if user is not found""" - # Act - response = self.client.get( - "/api/v2/users/queries/unknown_user/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], USER_NOT_FOUND_SUB_CODE) - - @staticmethod - def assert_user_detail_response( - response, - user_id: Optional[int] = TEST_USER_ID, - username: Optional[str] = TEST_USERNAME, - email: Optional[str] = TEST_EMAIL, - gender: Optional[str] = None, - own_info: bool = True, - ): - assert response.status_code == 200 - assert response.json["id"] == user_id - assert response.json["username"] == username - if not own_info: - assert response.json["emailAddress"] is None - assert response.json["gender"] is None - assert response.json["selfDescriptionGender"] is None - else: - assert response.json["emailAddress"] == email - assert response.json["gender"] == gender - assert response.json["isEmailVerified"] is False - - def test_returns_email_and_gender_if_own_info_requested(self): - """Test response contains email and gender info if user is requesting own info""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.MALE.value - self.user.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - TestUsersQueriesUsernameAPI.assert_user_detail_response( - response, - TEST_USER_ID, - TEST_USERNAME, - TEST_EMAIL, - UserGender.MALE.name, - True, - ) - - def test_email_and_gender_not_returned_if_requested_by_other(self): - """Test response does not contain email and gender info if user is requesting info for another user""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.FEMALE.value - self.user.save() - user_2 = return_canned_user("user_2", 2222222) - user_2.create() - user_2_session_token = generate_encoded_token(user_2.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": user_2_session_token}, - ) - # Assert - TestUsersQueriesUsernameAPI.assert_user_detail_response( - response, TEST_USER_ID, TEST_USERNAME, None, None, False - ) - - -class TestUsersQueriesOwnLockedAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.user.create() - self.user_session_token = generate_encoded_token(TEST_USER_ID) - self.url = "/api/v2/users/queries/tasks/locked/" - - def test_returns_401_without_session_token(self): - """Test that the API returns 401 if no session token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_empty_list_if_no_tasks_locked(self): - """Test that the API returns empty list if no task is locked by user""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["lockedTasks"], []) - self.assertEqual(response.json["projectId"], None) - self.assertEqual(response.json["taskStatus"], None) - - def test_returns_locked_task_if_tasks_locked(self): - """Test that the API returns locked task if a task is locked by user""" - # Arrange - # Lock a task - test_project, _ = create_canned_project() - task = Task.get(1, test_project.id) - task.lock_task_for_mapping(self.user.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["lockedTasks"]), 1) - self.assertEqual(response.json["lockedTasks"][0], 1) - self.assertEqual(response.json["projectId"], test_project.id) - self.assertEqual( - response.json["taskStatus"], TaskStatus.LOCKED_FOR_MAPPING.name - ) - - -class UsersQueriesInterestsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.user.create() - self.user_session_token = generate_encoded_token(TEST_USER_ID) - self.url = f"/api/v2/users/{self.user.username}/queries/interests/" - - def test_returns_401_without_session_token(self): - """Test that the API returns 401 if no session token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_empty_list_if_no_interests(self): - """Test that the API returns empty list if user has no interests""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["interests"], []) - - def test_returns_404_if_user_not_found(self): - """Test that the API returns 404 if user is not found""" - # Act - response = self.client.get( - "/api/v2/users/invalid_username/queries/interests/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], USER_NOT_FOUND_SUB_CODE) - - def test_returns_user_interests_if_interest_found(self): - """Test that the API returns user interests if user has interests""" - # Arrange - interest_1 = create_canned_interest("interest_1") - interest_2 = create_canned_interest("interest_2") - self.user.create_or_update_interests([interest_1.id, interest_2.id]) - self.user.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["interests"]), 2) - self.assertEqual(response.json["interests"][0]["id"], interest_1.id) - self.assertEqual(response.json["interests"][0]["name"], interest_1.name) - self.assertEqual(response.json["interests"][1]["id"], interest_2.id) - self.assertEqual(response.json["interests"][1]["name"], interest_2.name) - - -class TestUsersQueriesUsernameFilterAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.user.create() - self.user_2 = return_canned_user("user_2", 2222222) - self.user_2.create() - self.user_3 = return_canned_user("user_3", 3333333) - self.user_3.create() - self.user_session_token = generate_encoded_token(TEST_USER_ID) - self.url = "/api/v2/users/queries/filter/tes/" - - def test_returns_401_without_session_token(self): - """Test that the API returns 401 if no session token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_no_users_found(self): - """Test that the API returns 404 if no users found""" - # Act - response = self.client.get( - "/api/v2/users/queries/filter/invalid_username/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], USER_NOT_FOUND_SUB_CODE) - - def test_returns_users_if_users_found(self): - """Test that the API returns users if users found""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertListEqual( - list(response.json.keys()), ["pagination", "usernames", "users"] - ) - self.assertEqual(len(response.json["usernames"]), 1) - self.assertEqual(response.json["usernames"][0], self.user.username) - self.assertEqual(response.json["pagination"]["page"], 1) - self.assertEqual(response.json["pagination"]["perPage"], 20) - self.assertEqual(response.json["pagination"]["total"], 1) - - def test_returnns_matching_project_contributors(self): - """Test that the API returns matching project contributors""" - # Arrange - test_project, _ = create_canned_project() - task = Task.get(1, test_project.id) - task.lock_task_for_mapping(self.user_2.id) - task.unlock_task(self.user_2.id, TaskStatus.MAPPED) - # Act - response = self.client.get( - f"/api/v2/users/queries/filter/user_/?projectId={test_project.id}", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["usernames"]), 2) - self.assertEqual(response.json["usernames"][0], self.user_2.username) - self.assertEqual(response.json["usernames"][1], self.user_3.username) - self.assertEqual(response.json["users"][0]["username"], self.user_2.username) - self.assertEqual(response.json["users"][0]["projectId"], test_project.id) - - -class TestUsersAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.user.create() - self.user_session_token = generate_encoded_token(TEST_USER_ID) - for i in range(30): - user = return_canned_user(f"user_{i}", i) - user.create() - self.url = "/api/v2/users/" - - def test_returns_401_without_session_token(self): - """Test that the API returns 401 if no session token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_400_if_invalid_data(self): - """Test that the API returns 400 if invalid data is provided""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"role": "GOD"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidData") - - def test_returns_per_page_20_users_by_default(self): - """Test that the API paginates and returns 20 users by default""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["users"]), 20) - self.assertEqual(response.json["pagination"]["page"], 1) - self.assertEqual(response.json["pagination"]["perPage"], 20) - self.assertEqual(response.json["pagination"]["total"], 31) - - def test_pagination_can_be_disabled(self): - """Test that the API can return all users if pagination is disabled""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"pagination": "false"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["users"]), 31) - - def test_returns_specified_per_page_users(self): - """Test that the API returns specified per page users""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"perPage": 10}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["users"]), 10) - self.assertEqual(response.json["pagination"]["page"], 1) - self.assertEqual(response.json["pagination"]["perPage"], 10) - self.assertEqual(response.json["pagination"]["total"], 31) - self.assertEqual(response.json["pagination"]["hasNext"], True) - self.assertEqual(response.json["pagination"]["pages"], 4) - - def test_returns_specified_page_users(self): - """Test that the API returns specified page users""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"page": 2}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["users"]), 11) - self.assertEqual(response.json["pagination"]["page"], 2) - self.assertEqual(response.json["pagination"]["hasNext"], False) - self.assertEqual(response.json["pagination"]["hasPrev"], True) - self.assertEqual(response.json["pagination"]["pages"], 2) - - def test_returns_users_with_specified_role_(self): - """Test that the API returns users with specified role""" - # Arrange - self.user.role = UserRole.ADMIN.value - self.user.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"role": "ADMIN"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["users"]), 1) - self.assertEqual(response.json["pagination"]["page"], 1) - self.assertEqual(response.json["pagination"]["total"], 1) - - def test_returns_users_with_specified_level(self): - """Test that the API returns users with specified level""" - # Arrange - self.user.mapping_level = MappingLevel.ADVANCED.value - self.user.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"level": "ADVANCED"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["users"]), 1) - self.assertEqual(response.json["pagination"]["page"], 1) - self.assertEqual(response.json["pagination"]["total"], 1) - - -class TestUsersRecommendedProjectsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.user.create() - self.user_session_token = generate_encoded_token(TEST_USER_ID) - self.url = f"/api/v2/users/{self.user.username}/recommended-projects/" - - def test_returns_401_without_session_token(self): - """Test that the API returns 401 if no session token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_user_does_not_exist(self): - """Test that the API returns 404 if user does not exist""" - # Act - response = self.client.get( - "api/v2/users/non_existent/recommended-projects/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_recommended_projects(self): - """Test that the API returns recommended projects""" - # Arrange - project, _ = create_canned_project() - project.create() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 200) - - -class TestUsersRestAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.user.create() - self.user_session_token = generate_encoded_token(TEST_USER_ID) - self.url = f"/api/v2/users/{self.user.id}/" - - def test_returns_401_without_session_token(self): - """Test that the API returns 401 if no session token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_returns_404_if_user_does_not_exist(self): - """Test that the API returns 404 if user does not exist""" - # Act - response = self.client.get( - "/api/v2/users/999/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - - def test_returns_email_and_gender_if_own_info_requested(self): - """Test response contains all user info if user is requesting own info""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.MALE.value - self.user.save() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - TestUsersQueriesUsernameAPI.assert_user_detail_response( - response, - TEST_USER_ID, - TEST_USERNAME, - TEST_EMAIL, - UserGender.MALE.name, - True, - ) - - def test_email_and_gender_not_returned_if_requested_by_other(self): - """Test response does not sensetive info if user is requesting info for another user""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.FEMALE.value - self.user.save() - user_2 = return_canned_user("user_2", 2222222) - user_2.create() - user_2_session_token = generate_encoded_token(user_2.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": user_2_session_token}, - ) - # Assert - TestUsersQueriesUsernameAPI.assert_user_detail_response( - response, TEST_USER_ID, TEST_USERNAME, None, None, False - ) - - def test_user_can_delete_self(self): - """Check that a user can delete (redact personal information) themselves""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.FEMALE.value - self.user.save() - # Act - response = self.client.delete( - self.url, headers={"Authorization": self.user_session_token} - ) - next_response = self.client.get( - f"/api/v2/users/{TEST_USER_ID}/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - # Note that we return the deleted user information at this time - TestUsersQueriesUsernameAPI.assert_user_detail_response( - response, - TEST_USER_ID, - TEST_USERNAME, - TEST_EMAIL, - UserGender.FEMALE.name, - True, - ) - TestUsersQueriesUsernameAPI.assert_user_detail_response( - next_response, TEST_USER_ID, f"user_{TEST_USER_ID}", None, None, True - ) - - def test_other_user_cannot_delete_self(self): - """Check that another user cannot delete (redact personal information) about a different user""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.FEMALE.value - self.user.save() - user_2 = return_canned_user("user_2", 2222222) - user_2.create() - user_2_session_token = generate_encoded_token(user_2.id) - # Act - response = self.client.delete( - self.url, headers={"Authorization": user_2_session_token} - ) - # Assert - self.assertEqual(401, response.status_code) - rjson = response.json - self.assertDictEqual( - rjson, - { - "error": { - "code": 401, - "details": {}, - "message": "Authentication credentials were missing or incorrect.", - "sub_code": "UNAUTHORIZED", - } - }, - ) - - def test_other_admin_user_can_delete_self(self): - """Check that another user cannot delete (redact personal information) about a different user""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.FEMALE.value - self.user.save() - user_2 = return_canned_user("user_2", 2222222) - user_2.set_user_role(UserRole.ADMIN) - user_2.create() - user_2_session_token = generate_encoded_token(user_2.id) - # Act - response = self.client.delete( - self.url, headers={"Authorization": user_2_session_token} - ) - next_response = self.client.get( - f"/api/v2/users/{TEST_USER_ID}/", - headers={"Authorization": user_2_session_token}, - ) - # Assert - # Note that we return the deleted user information at this time - TestUsersQueriesUsernameAPI.assert_user_detail_response( - response, - TEST_USER_ID, - TEST_USERNAME, - TEST_EMAIL, - UserGender.FEMALE.name, - False, - ) - TestUsersQueriesUsernameAPI.assert_user_detail_response( - next_response, TEST_USER_ID, f"user_{TEST_USER_ID}", None, None, False - ) - - def test_admin_user_can_remove_redacted_osm_accounts(self): - """Check that an admin can redact redacted OSM accounts""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.FEMALE.value - self.user.id = 4 - self.user.save() - user_2 = return_canned_user("user_2", 2222222) - user_2.set_user_role(UserRole.ADMIN) - user_2.create() - user_2_session_token = generate_encoded_token(user_2.id) - # Act - response = self.client.delete( - "/api/v2/users/", headers={"Authorization": user_2_session_token} - ) - next_response = self.client.get( - "/api/v2/users/4/", headers={"Authorization": user_2_session_token} - ) - # Assert - self.assertEqual(200, response.status_code) - TestUsersQueriesUsernameAPI.assert_user_detail_response( - next_response, 4, "user_4", None, None, False - ) - - def test_user_cannot_remove_redacted_osm_accounts(self): - """Check that a user cannot redact redacted OSM accounts""" - # Arrange - self.user.email_address = TEST_EMAIL - self.user.gender = UserGender.FEMALE.value - self.user.id = 4 - self.user.save() - user_2 = return_canned_user("user_2", 2222222) - user_2.set_user_role(UserRole.MAPPER) - user_2.create() - user_2_session_token = generate_encoded_token(user_2.id) - # Act - response = self.client.delete( - "/api/v2/users/", headers={"Authorization": user_2_session_token} - ) - next_response = self.client.get( - "/api/v2/users/4/", headers={"Authorization": user_2_session_token} - ) - # Assert - self.assertEqual(401, response.status_code) - TestUsersQueriesUsernameAPI.assert_user_detail_response( - next_response, 4, TEST_USERNAME, None, None, False - ) diff --git a/tests/backend/integration/api/users/test_statistics.py b/tests/backend/integration/api/users/test_statistics.py deleted file mode 100644 index 7dcab35638..0000000000 --- a/tests/backend/integration/api/users/test_statistics.py +++ /dev/null @@ -1,157 +0,0 @@ -import random -import time -from datetime import datetime, timedelta - -from backend.models.postgis.task import Task, TaskStatus -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_project, - generate_encoded_token, - return_canned_user, -) -from tests.backend.integration.api.users.test_resources import USER_NOT_FOUND_SUB_CODE - - -class TestUsersStatisticsAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_user = create_canned_project() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.url = f"/api/v2/users/{self.test_user.username}/statistics/" - - def test_returns_401_if_no_token(self): - """Test that the user needs to be logged in.""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def test_return_404_if_user_not_found(self): - """Test returns 404 if user not found.""" - # Act - response = self.client.get( - "/api/v2/users/doesntexist/statistics/", - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 404) - self.assertEqual(response.json["error"]["sub_code"], USER_NOT_FOUND_SUB_CODE) - - def test_return_200_if_user_found(self): - """Test returns 200 if user found.""" - # Arrange - task = Task.get(1, self.test_project.id) - task.lock_task_for_mapping(self.test_user.id) - time.sleep(5) - task.unlock_task(self.test_user.id, TaskStatus.MAPPED) - # Act - response = self.client.get( - self.url, headers={"Authorization": self.user_session_token} - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["totalTimeSpent"], 5) - self.assertEqual(response.json["timeSpentMapping"], 5) - self.assertEqual(response.json["timeSpentValidating"], 0) - self.assertEqual(response.json["projectsMapped"], 0) - self.assertEqual(response.json["countriesContributed"]["total"], 0) - self.assertEqual(response.json["tasksMapped"], 1) - self.assertEqual(response.json["tasksValidated"], 0) - self.assertEqual(response.json["tasksInvalidated"], 0) - self.assertEqual(response.json["tasksInvalidatedByOthers"], 0) - self.assertEqual(response.json["tasksValidatedByOthers"], 0) - self.assertEqual(response.json["ContributionsByInterest"], []) - - -class TestUsersStatisticsAllAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_user = create_canned_project() - self.user_session_token = generate_encoded_token(self.test_user.id) - self.url = "/api/v2/users/statistics/" - - def generate_random_user_level(self): - return random.randint(1, 3) - - def test_returns_401_if_no_token(self): - """Test that the user needs to be logged in.""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def returns_400_if_start_date_not_provided(self): - """Test that the start date needs to be provided.""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "MissingDate") - - def returns_400_if_invalid_date_value(self): - """Test that the date should be in date format""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"startDate": "invalid"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidDateValue") - - def returns_400_if_start_date_greater_than_end_date(self): - """Test that the start date cannot be greater than the end date.""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"startDate": "2020-01-01", "endDate": "2019-01-01"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidDateRange") - - def test_returns_400_if_date_range_greater_than_3_years(self): - """Test that the date range cannot be greater than 3 years.""" - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"startDate": "2017-01-01", "endDate": "2021-01-01"}, - ) - # Assert - self.assertEqual(response.status_code, 400) - self.assertEqual(response.json["SubCode"], "InvalidDateRange") - - def test_returns_all_users_statistics(self): - """Test that the statistics for all users that registerd in the give priod are returned.""" - # Arrange - mapping_level_dict = {1: 0, 2: 0, 3: 0} - # Create 10 users with random mapping levels - for i in range(10): - user = return_canned_user(f"user_{i}", i) - user.mapping_level = self.generate_random_user_level() - mapping_level_dict[user.mapping_level] += 1 - user.date_registered = datetime.today() - timedelta(days=100) - user.create() - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "startDate": (datetime.today() - timedelta(days=100)).strftime( - "%Y-%m-%d" - ), - "endDate": datetime.now().strftime("%Y-%m-%d"), - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json["total"], 10) - self.assertEqual(response.json["beginner"], mapping_level_dict[1]) - self.assertEqual(response.json["intermediate"], mapping_level_dict[2]) - self.assertEqual(response.json["advanced"], mapping_level_dict[3]) diff --git a/tests/backend/integration/api/users/test_tasks.py b/tests/backend/integration/api/users/test_tasks.py deleted file mode 100644 index 74a154fc87..0000000000 --- a/tests/backend/integration/api/users/test_tasks.py +++ /dev/null @@ -1,193 +0,0 @@ -from backend.models.postgis.statuses import ProjectStatus -from backend.models.postgis.task import Task, TaskStatus -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_project, - generate_encoded_token, -) - - -class TetUsersTasksAPI(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.test_author = create_canned_project() - self.user_session_token = generate_encoded_token(self.test_author.id) - self.url = f"/api/v2/users/{self.test_author.id}/tasks/" - - def test_returns_401_if_no_token(self): - """Test that the API returns a 401 if no token is provided""" - # Act - response = self.client.get(self.url) - # Assert - self.assertEqual(response.status_code, 401) - - def change_task_status(self, task_id, status, project_id): - """Helper function to change the status of a task""" - task = Task.get(task_id, project_id) - if status == TaskStatus.MAPPED: - task.lock_task_for_mapping(self.test_author.id) - elif status == TaskStatus.VALIDATED: - task.lock_task_for_validating(self.test_author.id) - task.unlock_task(self.test_author.id, status) - - def test_returns_200_on_success(self): - """Test that the API returns a 200 on success""" - # Arrange - self.change_task_status(1, TaskStatus.MAPPED, self.test_project.id) - self.change_task_status(2, TaskStatus.VALIDATED, self.test_project.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"project_id": self.test_project.id}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 2) - self.assertEqual(response.json["tasks"][0]["taskId"], 2) - - def test_returns_paginated_results(self): - """Test that the API returns paginated results""" - # Arrange - self.change_task_status(1, TaskStatus.MAPPED, self.test_project.id) - self.change_task_status(2, TaskStatus.VALIDATED, self.test_project.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"project_id": self.test_project.id, "page_size": 1}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 1) - self.assertEqual(response.json["pagination"]["total"], 2) - self.assertEqual(response.json["pagination"]["page"], 1) - self.assertEqual(response.json["pagination"]["perPage"], 1) - self.assertEqual(response.json["pagination"]["hasNext"], True) - - def test_filters_by_project_if_project_id_passed(self): - """Test that the API filters by project if project_id is passed""" - # Arrange - test_project_2, _ = create_canned_project() - self.change_task_status(1, TaskStatus.MAPPED, self.test_project.id) - self.change_task_status(2, TaskStatus.VALIDATED, self.test_project.id) - self.change_task_status(1, TaskStatus.MAPPED, test_project_2.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"project_id": test_project_2.id}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 1) - self.assertEqual(response.json["tasks"][0]["taskId"], 1) - self.assertEqual(response.json["tasks"][0]["projectId"], test_project_2.id) - self.assertEqual( - response.json["tasks"][0]["taskStatus"], TaskStatus.MAPPED.name - ) - - def test_filters_by_status_if_status_passed(self): - """Test that the API filters by status if status is passed""" - # Arrange - self.change_task_status(1, TaskStatus.MAPPED, self.test_project.id) - self.change_task_status(2, TaskStatus.VALIDATED, self.test_project.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={ - "project_id": self.test_project.id, - "status": TaskStatus.MAPPED.name, - }, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 1) - self.assertEqual(response.json["tasks"][0]["taskId"], 1) - self.assertEqual(response.json["tasks"][0]["projectId"], self.test_project.id) - self.assertEqual( - response.json["tasks"][0]["taskStatus"], TaskStatus.MAPPED.name - ) - - def test_filters_by_project_status_if_project_status_passed(self): - """Test that the API filters by project status if passed""" - # Arrange - test_project_2, _ = create_canned_project() - test_project_2.status = ProjectStatus.PUBLISHED.value - test_project_2.save() - self.change_task_status(1, TaskStatus.MAPPED, self.test_project.id) - self.change_task_status(1, TaskStatus.MAPPED, test_project_2.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"project_status": ProjectStatus.PUBLISHED.name}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 1) - self.assertEqual(response.json["tasks"][0]["taskId"], 1) - self.assertEqual(response.json["tasks"][0]["projectId"], test_project_2.id) - - def test_sorts_results_by_project_id_in_defined_order(self): - """Test that the API sorts results by project id in defined order""" - # Arrange - test_project_2, _ = create_canned_project() - self.change_task_status(1, TaskStatus.MAPPED, self.test_project.id) - self.change_task_status(2, TaskStatus.MAPPED, self.test_project.id) - self.change_task_status(1, TaskStatus.MAPPED, test_project_2.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"sort_by": "project_id"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 3) - self.assertEqual(response.json["tasks"][0]["projectId"], self.test_project.id) - self.assertEqual(response.json["tasks"][1]["projectId"], self.test_project.id) - self.assertEqual(response.json["tasks"][2]["projectId"], test_project_2.id) - - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"sort_by": "-project_id"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 3) - self.assertEqual(response.json["tasks"][0]["projectId"], test_project_2.id) - self.assertEqual(response.json["tasks"][1]["projectId"], self.test_project.id) - self.assertEqual(response.json["tasks"][2]["projectId"], self.test_project.id) - - def test_sorts_results_by_action_date_in_defined_order(self): - """Test that the API sorts results by action date in defined order""" - # Arrange - self.change_task_status(1, TaskStatus.MAPPED, self.test_project.id) - self.change_task_status(2, TaskStatus.MAPPED, self.test_project.id) - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"sort_by": "action_date"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 2) - self.assertEqual(response.json["tasks"][0]["taskId"], 1) - self.assertEqual(response.json["tasks"][1]["taskId"], 2) - - # Act - response = self.client.get( - self.url, - headers={"Authorization": self.user_session_token}, - query_string={"sort_by": "-action_date"}, - ) - # Assert - self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json["tasks"]), 2) - self.assertEqual(response.json["tasks"][0]["taskId"], 2) - self.assertEqual(response.json["tasks"][1]["taskId"], 1) diff --git a/tests/backend/integration/models/__init__.py b/tests/backend/integration/models/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/models/postgis/__init__.py b/tests/backend/integration/models/postgis/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/models/postgis/test_project.py b/tests/backend/integration/models/postgis/test_project.py deleted file mode 100644 index ef7aeb583d..0000000000 --- a/tests/backend/integration/models/postgis/test_project.py +++ /dev/null @@ -1,130 +0,0 @@ -import geojson - -from backend.models.dtos.project_dto import DraftProjectDTO -from backend.models.postgis.project import ( - Project, - ProjectDTO, - ProjectPriority, - ProjectStatus, - Task, -) -from backend.models.postgis.project_info import ProjectInfoDTO -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_project, - return_canned_draft_project_json, - update_project_with_info, -) - - -class TestProject(BaseTestCase): - def test_project_can_be_persisted_to_db(self): - self.test_project, self.test_user = create_canned_project() - # Checks that code we ran in setUp actually created a project in the DB - self.assertIsNotNone( - self.test_project.id, "ID should be set if project successfully persisted" - ) - - def test_task_can_generate_valid_feature_collection(self): - self.test_project, self.test_user = create_canned_project() - # Act - feature_collection = Task.get_tasks_as_geojson_feature_collection( - self.test_project.id, "1" - ) - self.assertIsInstance(feature_collection, geojson.FeatureCollection) - self.assertEqual(1, len(feature_collection.features)) - - feature_collection = Task.get_tasks_as_geojson_feature_collection( - self.test_project.id, None - ) - self.assertIsInstance(feature_collection, geojson.FeatureCollection) - self.assertEqual( - self.test_project.total_tasks, len(feature_collection.features) - ) - - def test_project_can_be_generated_as_dto(self): - self.test_project, self.test_user = create_canned_project() - # Arrange - self.test_project = update_project_with_info(self.test_project) - - # Act - project_dto = self.test_project.as_dto_for_mapping() - - # Assert - self.assertIsInstance(project_dto.area_of_interest, geojson.MultiPolygon) - self.assertIsInstance(project_dto.tasks, geojson.FeatureCollection) - # TODO test for project info - # self.assertEqual(project_dto.project_name, 'Test') - self.assertEqual(project_dto.project_id, self.test_project.id) - - def test_update_project_adds_project_info(self): - self.test_project, self.test_user = create_canned_project() - # Act - self.test_project = update_project_with_info(self.test_project) - - # Assert - self.assertEqual(self.test_project.status, ProjectStatus.PUBLISHED.value) - self.assertEqual(self.test_project.priority, ProjectPriority.MEDIUM.value) - self.assertEqual(self.test_project.default_locale, "en") - self.assertEqual(self.test_project.project_info[0].name, "Thinkwhere Test") - - def test_project_update_updates_changed_fields(self): - self.test_project, self.test_user = create_canned_project() - # Arrange - self.test_project = update_project_with_info(self.test_project) - - locales = [] - test_info = ProjectInfoDTO() - test_info.locale = "it" - test_info.name = "Italian test project" - test_info.description = "Test italian description" - test_info.short_description = "Test italian short description" - test_info.instructions = "Test italian instructions" - locales.append(test_info) - - test_dto = ProjectDTO() - test_dto.project_status = ProjectStatus.PUBLISHED.name - test_dto.project_priority = ProjectPriority.MEDIUM.name - test_dto.default_locale = "it" - test_dto.project_info_locales = locales - test_dto.difficulty = "EASY" - test_dto.mapping_types = ["ROADS", "BUILDINGS"] - test_dto.mapping_editors = ["JOSM", "ID", "RAPID"] - test_dto.validation_editors = ["JOSM", "ID"] - - # Act - Create empty italian translation - self.test_project.update(test_dto) - dto = self.test_project.as_dto_for_mapping(locale="it") - - # Assert - self.assertEqual(self.test_project.default_locale, test_info.locale) - self.assertDictEqual( - dto.project_info.to_primitive(), - test_info.to_primitive(), - ) - self.assertListEqual(test_dto.mapping_types, dto.mapping_types) - self.assertListEqual(test_dto.validation_editors, dto.validation_editors) - self.assertListEqual(test_dto.mapping_editors, dto.mapping_editors) - - def test_set_project_aoi(self): - # Arrange - draft_project_dto = DraftProjectDTO(return_canned_draft_project_json()) - draft_project = Project() - # Act - draft_project.set_project_aoi(draft_project_dto) - # Assert - self.assertIsNotNone(draft_project.geometry) - self.assertIsNotNone(draft_project.centroid) - - def test_as_dto_for_mapping(self): - # Arrange - test_project, project_author = create_canned_project() - # Act - test_project_dto = test_project.as_dto_for_mapping(project_author.id) - - self.assertEqual( - test_project.status, ProjectStatus[test_project_dto.project_status].value - ) - self.assertEqual( - test_project.project_info[0].name, test_project_dto.project_info.name - ) diff --git a/tests/backend/integration/models/postgis/test_user.py b/tests/backend/integration/models/postgis/test_user.py deleted file mode 100644 index 39aa1bd63a..0000000000 --- a/tests/backend/integration/models/postgis/test_user.py +++ /dev/null @@ -1,32 +0,0 @@ -from backend.models.postgis.user import MappingLevel, User, UserRole -from tests.backend.base import BaseTestCase - - -class TestUser(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = User() - self.test_user.role = UserRole.MAPPER.value - self.test_user.id = 12 - self.test_user.mapping_level = MappingLevel.BEGINNER.value - self.test_user.username = "mrtest" - self.test_user.email_address = "test@test.com" - - def test_as_dto_will_not_return_email_if_not_owner(self): - # if self.skip_tests: - # return - # Act - user_dto = self.test_user.as_dto("mastertest") - - # Assert - self.assertFalse(user_dto.email_address) - - def test_as_dto_will_not_return_email_if_owner(self): - # if self.skip_tests: - # return - - # Act - user_dto = self.test_user.as_dto("mrtest") - - # Assert - self.assertTrue(user_dto.email_address) diff --git a/tests/backend/integration/services/__init__.py b/tests/backend/integration/services/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/services/grid/__init__.py b/tests/backend/integration/services/grid/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/services/grid/test_split_service.py b/tests/backend/integration/services/grid/test_split_service.py deleted file mode 100644 index 24c20f6bf8..0000000000 --- a/tests/backend/integration/services/grid/test_split_service.py +++ /dev/null @@ -1,117 +0,0 @@ -import json -from unittest.mock import patch - -import geojson -from geoalchemy2 import shape -from shapely.geometry import Polygon - -from backend.models.dtos.grid_dto import SplitTaskDTO -from backend.models.postgis.project import Project -from backend.models.postgis.task import Task -from backend.services.grid.split_service import SplitService, SplitServiceError -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project, get_canned_json - - -class TestSplitService(BaseTestCase): - maxDiff = None - - def setUp(self): - super().setUp() - - self.test_project, self.test_user = create_canned_project() - - def test_split_geom_returns_split_geometries(self): - # arrange - x = 1010 - y = 1399 - zoom = 11 - task_stub = Task() - task_stub.is_square = True - - expected = geojson.loads(json.dumps(get_canned_json("split_task.json"))) - - # act - result = SplitService._create_split_tasks(x, y, zoom, task_stub) - # assert - self.assertDeepAlmostEqual(expected, result) - - def test_split_geom_raise_grid_service_error_when_task_not_usable(self): - with self.assertRaises(SplitServiceError): - task_stub = Task() - task_stub.is_square = True - SplitService._create_split_tasks("foo", "bar", "dum", task_stub) - - @patch.object(Task, "get_per_task_instructions") - @patch.object(Project, "tasks") - @patch.object(Project, "save") - @patch.object(Project, "get") - @patch.object(Task, "delete") - @patch.object(Task, "create") - @patch.object(Task, "get_max_task_id_for_project") - @patch.object(Task, "get") - def test_split_task_helper( - self, - mock_task_get, - mock_task_get_max_task_id_for_project, - mock_task_create, - mock_task_delete, - mock_project_get, - mock_project_save, - mock_project_tasks, - mock_instructions, - ): - # arrange - task_stub = Task() - task_stub.id = 1 - task_stub.project_id = 1 - task_stub.task_status = 1 - task_stub.locked_by = 1234 - task_stub.lock_holder = 1234 - task_stub.is_square = True - task_stub.x = 16856 - task_stub.y = 17050 - task_stub.zoom = 15 - task_stub.geometry = shape.from_shape( - Polygon( - [ - (5.1855468740711421, 7.2970875628719796), - (5.1855468740711421, 7.3079847788619219), - (5.1965332021941588, 7.3079847788619219), - (5.1965332021941588, 7.2970875628719796), - (5.1855468740711421, 7.2970875628719796), - ] - ) - ) - mock_task_get.return_value = task_stub - mock_task_get_max_task_id_for_project.return_value = 1 - mock_project_get.return_value = Project() - mock_project_tasks.return_value = [task_stub] - split_tast_dto = SplitTaskDTO() - split_tast_dto.user_id = 1234 - split_tast_dto.project_id = 1 - split_tast_dto.task_id = 1 - - # act - result = SplitService.split_task(split_tast_dto) - - # assert - self.assertEqual(4, len(result.tasks)) - - @patch.object(Task, "get_tasks") - def test_split_non_square_task(self, mock_task): - # Lock task for mapping - task = Task.get(2, self.test_project.id) - task.lock_task_for_mapping(self.test_user.id) - - split_task_dto = SplitTaskDTO() - split_task_dto.user_id = self.test_user.id - split_task_dto.project_id = self.test_project.id - split_task_dto.task_id = 2 - - # Split tasks - expected = geojson.loads( - json.dumps(get_canned_json("non_square_split_results.json")) - ) - result = SplitService._create_split_tasks(task.x, task.y, task.zoom, task) - self.assertDeepAlmostEqual(expected, result) diff --git a/tests/backend/integration/services/messaging/__init__.py b/tests/backend/integration/services/messaging/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/services/messaging/test_chat_service.py b/tests/backend/integration/services/messaging/test_chat_service.py deleted file mode 100644 index 6e343c1f4d..0000000000 --- a/tests/backend/integration/services/messaging/test_chat_service.py +++ /dev/null @@ -1,149 +0,0 @@ -import threading -from unittest.mock import patch - -from backend.exceptions import NotFound -from backend.models.dtos.message_dto import ChatMessageDTO -from backend.models.postgis.statuses import ProjectStatus -from backend.models.postgis.team import TeamMemberFunctions, TeamRoles -from backend.services.messaging.chat_service import ChatService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_user_to_team, - assign_team_to_project, - create_canned_project, - create_canned_team, - return_canned_user, -) - - -class TestChatService(BaseTestCase): - def setUp(self): - super().setUp() - self.canned_project, self.canned_author = create_canned_project() - self.chat_dto = ChatMessageDTO() - self.chat_dto.message = "Test Message" - self.chat_dto.user_id = self.canned_author.id - self.chat_dto.project_id = self.canned_project.id - self.chat_dto.timestamp = "2022-06-30T05:45:06.198755Z" - self.chat_dto.username = self.canned_author.username - self.test_user = return_canned_user(username="test_user", id=100000) - self.test_user.create() - - @patch.object(threading, "Thread") - def test_post_message_sets_thread_if_user_allowed(self, mock_thread): - # Act - ChatService.post_message( - self.chat_dto, self.canned_project.id, self.canned_author.id - ) - # Assert - mock_thread.assert_called() - - def test_post_message_raises_error_if_user_not_manager_in_draft_project(self): - # Arrange - self.canned_project.status = ProjectStatus.DRAFT.value - self.chat_dto.user_id = self.test_user.id - self.chat_dto.username = self.test_user.username - # Act/Assert - with self.assertRaises(ValueError): - ChatService.post_message( - self.chat_dto, self.canned_project.id, self.test_user.id - ) - - @patch.object(threading, "Thread") - def test_post_message_sets_thread_if_user_member_of_allowed_team_in_private_project( - self, mock_thread - ): - # Arrange - canned_team = create_canned_team() - assign_team_to_project(self.canned_project, canned_team, TeamRoles.MAPPER.value) - add_user_to_team( - canned_team, self.test_user, TeamMemberFunctions.MEMBER.value, True - ) - self.chat_dto.user_id = self.test_user.id - self.chat_dto.username = self.test_user.username - self.canned_project.status = ProjectStatus.PUBLISHED.value - self.canned_project.private = True - # Act - ChatService.post_message( - self.chat_dto, self.canned_project.id, self.canned_author.id - ) - # Assert - mock_thread.assert_called() - - def test_post_message_raises_error_if_user_not_member_of_allowed_team_in_private_project( - self, - ): - # Arrange - canned_team = create_canned_team() - assign_team_to_project(self.canned_project, canned_team, TeamRoles.MAPPER.value) - self.chat_dto.user_id = self.test_user.id - self.chat_dto.username = self.test_user.username - self.canned_project.status = ProjectStatus.PUBLISHED.value - self.canned_project.private = True - # Act/Assert - with self.assertRaises(ValueError): - ChatService.post_message( - self.chat_dto, self.canned_project.id, self.test_user.id - ) - - def test_delete_project_chat_by_id_raises_not_found_if_comment_is_not_found(self): - """Test raises not found if comment is not found""" - # Arrange - project_id = 999999 - # Act/Assert - with self.assertRaises(NotFound): - ChatService.delete_project_chat_by_id(project_id, 11, 11) - - def test_delete_project_chat_by_id_deletes_comment_if_user_is_comment_author(self): - """Test successfully deletes comment if user is comment author""" - # Arrange - self.chat_dto.user_id = self.test_user.id - self.canned_project.status = ProjectStatus.PUBLISHED.value - self.canned_project.save() - comments = ChatService.post_message( - self.chat_dto, self.canned_project.id, self.test_user.id - ) - comment = comments.chat[0] - # Act - ChatService.delete_project_chat_by_id( - self.canned_project.id, comment.id, self.test_user.id - ) - # Assert - with self.assertRaises(NotFound): - ChatService.get_project_chat_by_id(self.canned_project.id, comment.id) - - def test_project_managers_can_delete_any_comment(self): - """Project managers can delete any comment""" - # Arrange - # Add a comment by a user who is not the project manager - self.canned_project.status = ProjectStatus.PUBLISHED.value - self.canned_project.save() - self.chat_dto.user_id = self.test_user.id - comments = ChatService.post_message( - self.chat_dto, self.canned_project.id, self.test_user.id - ) - comment = comments.chat[0] - # Act - ChatService.delete_project_chat_by_id( - self.canned_project.id, comment.id, self.canned_author.id - ) - # Assert - with self.assertRaises(NotFound): - ChatService.get_project_chat_by_id(self.canned_project.id, comment.id) - - def test_delete_project_chat_by_id_raises_error_if_user_is_not_comment_author_and_project_manager( - self, - ): - """Test raises error if user is not comment author and project manager""" - # Arrange - self.canned_project.status = ProjectStatus.PUBLISHED.value - self.canned_project.save() - comments = ChatService.post_message( - self.chat_dto, self.canned_project.id, self.canned_author.id - ) - comment = comments.chat[0] - # Act/Assert - with self.assertRaises(ValueError): - ChatService.delete_project_chat_by_id( - self.canned_project.id, comment.id, self.test_user.id - ) diff --git a/tests/backend/integration/services/messaging/test_messaging_service.py b/tests/backend/integration/services/messaging/test_messaging_service.py deleted file mode 100644 index 911d51f6e0..0000000000 --- a/tests/backend/integration/services/messaging/test_messaging_service.py +++ /dev/null @@ -1,241 +0,0 @@ -from unittest.mock import patch - -from backend.models.dtos.message_dto import MessageDTO -from backend.models.postgis.message import Message, MessageType, NotFound -from backend.models.postgis.statuses import TaskStatus -from backend.models.postgis.task import Task -from backend.services.messaging.message_service import MessageService -from backend.services.messaging.smtp_service import SMTPService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_manager_to_organisation, - create_canned_organisation, - create_canned_project, - return_canned_user, - update_project_with_info, -) - - -class TestMessageService(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user("TEST_USER", 111111111) - self.test_user.create() - - def test_welcome_message_sent(self): - # Act - message_id = MessageService.send_welcome_message(self.test_user) - self.assertIsNotNone(message_id) - message = MessageService.get_message(message_id, self.test_user.id) - - # Assert - self.assertTrue(message, "Message should be saved to DB") - - # Tidyup - MessageService.delete_message(message_id, self.test_user.id) - - def test_validation_message_is_not_sent_for_validating_self_mapped_task(self): - # Arrange - status = TaskStatus.VALIDATED.value - validated_by = 777 # random user id - mapped_by = 777 # random user id - project_id = 1 # random project id - task_id = 1 # random task id - # Act/Assert - self.assertFalse( - MessageService.send_message_after_validation( - status, validated_by, mapped_by, project_id, task_id - ) - ) - - @patch.object(MessageService, "_push_messages") - def test_validation_message_is_sent_after_task_validation(self, mock_push_message): - # Arrange - status = TaskStatus.VALIDATED.value - canned_project, canned_author = create_canned_project() - update_project_with_info(canned_project) - # Act - MessageService.send_message_after_validation( - status, canned_author.id, self.test_user.id, 1, canned_project.id - ) - - # Assert - mock_push_message.assert_called() - - @patch.object(MessageService, "_push_messages") - def test_send_message_to_all_contributors(self, mock_push_message): - # Arrange - canned_project, canned_author = create_canned_project() - canned_project = update_project_with_info(canned_project) - task = Task.get(1, canned_project.id) - task.mapped_by = self.test_user.id - message_dto = MessageDTO() - message_dto.message_id = 12 - message_dto.subject = "Test subject" - message_dto.message = "Test message" - message_dto.from_user_id = canned_author.id - message_dto.from_username = canned_author.username - message_dto.project_id = canned_project.id - message_dto.project_title = "Test project" - message_dto.message_type = MessageType.BROADCAST.value - message_dto.sent_date = "2020-01-01" - # Act - MessageService.send_message_to_all_contributors(canned_project.id, message_dto) - # Assert - mock_push_message.assert_called() - - @patch.object(MessageService, "_push_messages") - def test_send_message_after_comment(self, mock_push_message): - # Arrange - canned_project, canned_author = create_canned_project() - canned_project = update_project_with_info(canned_project) - # Act - MessageService.send_message_after_comment( - canned_author.id, "@test_user Test message", 1, canned_project.id - ) - # Assert - mock_push_message.assert_called() - - @patch.object(SMTPService, "_send_message") - def test_send_project_transfer_messgae(self, mock_send_message): - test_project, test_author = create_canned_project() - self.test_user.email_address = "test@hotmalinator.com" - self.test_user.is_email_verified = True - self.test_user.save() - test_organisation = create_canned_organisation() - test_project.organisation = test_organisation - add_manager_to_organisation(test_organisation, self.test_user) - MessageService.send_project_transfer_message( - test_project.id, self.test_user.username, test_author.username - ) - mock_send_message.assert_called() - - def send_multiple_welcome_messages(self, number_of_messages: int): - """Sends multiple welcome messages""" - message_ids = [] - for _ in range(number_of_messages): - message_id = MessageService.send_welcome_message(self.test_user) - message_ids.append(message_id) - return message_ids - - def test_delete_multiple_messages(self): - """Test that multiple messages can be deleted at once""" - # Arrange - message_ids = self.send_multiple_welcome_messages(3) - # Act - MessageService.delete_multiple_messages(message_ids[:2], self.test_user.id) - # Assert - messages = Message.get_all_messages(user_id=self.test_user.id) - self.assertEqual(len(messages.user_messages), 1) - self.assertEqual(messages.user_messages[0].message_id, message_ids[2]) - - def test_delete_all_messages(self): - """Test that all messages can be deleted at once""" - # Arrange - self.send_multiple_welcome_messages(3) - # Act - MessageService.delete_all_messages(self.test_user.id) - # Assert - with self.assertRaises(NotFound): - Message.get_all_messages(user_id=self.test_user.id) - - def test_delete_all_message_by_type(self): - """Test that all messages can be deleted at once""" - # Arrange - self.send_multiple_welcome_messages(2) - test_user_2 = return_canned_user("test_user_2", 222222222) - test_user_2.create() - MessageService.send_team_join_notification( - test_user_2.id, - test_user_2.username, - self.test_user.id, - "test_team", - 10, - "MANAGER", - ) - # Send welcome message to test_user_2 to ensure that it is not deleted - MessageService.send_welcome_message(test_user_2) - # Act - MessageService.delete_all_messages(self.test_user.id, "1,2,3") - # Assert - user_1_messages = Message.get_all_messages(user_id=self.test_user.id) - # Since we deleted all messages of type 1,2,3, welcome messages should be deleted as it is of type 1 - # Team join notification is of type 7, so it should still be there - self.assertEqual(len(user_1_messages.user_messages), 1) - self.assertEqual( - user_1_messages.user_messages[0].message_type, - MessageType.INVITATION_NOTIFICATION.name, - ) - # Also assert that messages of other users are not deleted - user_2_messages = Message.get_all_messages(user_id=test_user_2.id) - self.assertEqual(len(user_2_messages.user_messages), 1) - - def test_mark_multiple_messages_as_read(self): - # Arrange - message_ids = self.send_multiple_welcome_messages(3) - # Act - MessageService.mark_multiple_messages_read(message_ids[:2], self.test_user.id) - # Assert - messages = MessageService.get_all_messages( - user_id=self.test_user.id, - locale="en", - page=1, - sort_by="date", # Required for function to work - sort_direction="desc", # Required for function to work - status="unread", - ) - self.assertEqual(len(messages.user_messages), 1) - self.assertEqual(messages.user_messages[0].message_id, message_ids[2]) - - def test_mark_all_messages_as_read(self): - # Arrange - self.send_multiple_welcome_messages(3) - # Act - MessageService.mark_all_messages_read(self.test_user.id) - # Assert - unread_count = Message.get_unread_message_count(self.test_user.id) - self.assertEqual(unread_count, 0) - - def test_mark_all_messages_as_read_by_type(self): - # Arrange - self.send_multiple_welcome_messages(2) - test_user_2 = return_canned_user("test_user_2", 222222222) - test_user_2.create() - MessageService.send_team_join_notification( - test_user_2.id, - test_user_2.username, - self.test_user.id, - "test_team", - 10, - "MANAGER", - ) - # Send welcome message to test_user_2 to ensure that it is not marked as read - MessageService.send_welcome_message(test_user_2) - # Act - MessageService.mark_all_messages_read(self.test_user.id, "1,2,3") - # Assert - user_1_messages = MessageService.get_all_messages( - user_id=self.test_user.id, - locale="en", - page=1, - sort_by="date", # Required for function to work - sort_direction="desc", # Required for function to work - status="unread", - ) - # Since we marked all messages of type 1,2,3 as read, welcome messages should be read as it is of type 1 - # Team join notification is of type 7, so it should still be there unread - self.assertEqual(len(user_1_messages.user_messages), 1) - self.assertEqual( - user_1_messages.user_messages[0].message_type, - MessageType.INVITATION_NOTIFICATION.name, - ) - # Also assert that messages of other users are not marked as read - user_2_messages = MessageService.get_all_messages( - user_id=test_user_2.id, - locale="en", - page=1, - sort_by="date", # Required for function to work - sort_direction="desc", # Required for function to work - status="unread", - ) - self.assertEqual(user_2_messages.pagination.total, 1) diff --git a/tests/backend/integration/services/messaging/test_smtp_service.py b/tests/backend/integration/services/messaging/test_smtp_service.py deleted file mode 100644 index 2ca3a52ede..0000000000 --- a/tests/backend/integration/services/messaging/test_smtp_service.py +++ /dev/null @@ -1,208 +0,0 @@ -import os -from unittest.mock import MagicMock, patch -from urllib.parse import parse_qs, urlparse - -from flask import current_app - -from backend.models.postgis.message import Message -from backend.models.postgis.statuses import EncouragingEmailType -from backend.services.messaging.smtp_service import SMTPService -from backend.services.users.user_service import UserService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import return_canned_user - - -class TestSMTPService(BaseTestCase): - # A debug message shown instead of the sending actual email in the testing environment - - def setUp(self): - super().setUp() - self.to_address = "hot-test@mailinator.com" - self.to_username = "Iain Hunter" - self.from_username = "Aadesh Baral" - self.message_id = 1 - self.project_id = 1 - self.project_name = "test_project" - self.task_id = 1 - self.subject = "test subject" - self.content = "test content" - self.message_type = "test" - - def test_send_verification_mail(self): - if os.getenv("TM_SMTP_HOST") is None: - return # If SMTP not setup there's no value attempting the integration tests - - self.assertTrue( - SMTPService.send_verification_email("hot-test@mailinator.com", "mrtest") - ) - - def test_send_alert(self): - if os.getenv("TM_SMTP_HOST") is None: - return # If SMTP not setup there's no value attempting the integration tests - - sent_alert = SMTPService.send_email_alert( - to_address=self.to_address, - username=self.to_username, - user_email_verified=True, - message_id=self.message_id, - from_username=self.from_username, - project_id=self.project_id, - project_name=self.project_name, - task_id=self.task_id, - subject=self.subject, - content=self.content, - message_type=self.message_type, - ) - self.assertTrue(sent_alert) - - def test_send_alert_message_limits(self): - if os.getenv("TM_SMTP_HOST") is None: - return # If SMTP not setup there's no value attempting the integration tests - - for x in range(0, 10): - sent_alert = SMTPService.send_email_alert( - to_address=self.to_address, - username=self.to_username, - user_email_verified=True, - message_id=self.message_id, - from_username=self.from_username, - project_id=self.project_id, - project_name=self.project_name, - task_id=self.task_id, - subject=self.subject, - content=self.content, - message_type=self.message_type, - ) - self.assertTrue(sent_alert) - - def test_alert_not_sent_if_email_not_supplied(self): - if os.getenv("TM_SMTP_HOST") is None: - return # If SMTP not setup there's no value attempting the integration tests - - sent_alert = SMTPService.send_email_alert( - to_address="", - username=self.to_username, - user_email_verified=True, - message_id=self.message_id, - from_username=self.from_username, - project_id=self.project_id, - project_name=self.project_name, - task_id=self.task_id, - subject=self.subject, - content=self.content, - message_type=self.message_type, - ) - self.assertFalse(sent_alert) - - def test_does_not_send_if_user_not_verified(self): - sent_alert = SMTPService.send_email_alert( - to_address=self.to_address, - username=self.to_username, - user_email_verified=False, - message_id=self.message_id, - from_username=self.from_username, - project_id=self.project_id, - project_name=self.project_name, - task_id=self.task_id, - subject=self.subject, - content=self.content, - message_type=self.message_type, - ) - self.assertFalse(sent_alert) - - @patch.object(SMTPService, "_send_message") - def test_does_send_if_user_verified(self, mock_send_message): - # Arrange - mock_send_message.side_effect = None - # Act - sent_alert = SMTPService.send_email_alert( - to_address=self.to_address, - username=self.to_username, - user_email_verified=True, - message_id=self.message_id, - from_username=self.from_username, - project_id=self.project_id, - project_name=self.project_name, - task_id=self.task_id, - subject=self.subject, - content=self.content, - message_type=self.message_type, - ) - # Assert - self.assertTrue(sent_alert) - - def test_email_verification_url_generated_correctly(self): - # Arrange - test_user = "mrtest" - - # Act - url = SMTPService._generate_email_verification_url("test@test.com", test_user) - - parsed_url = urlparse(url) - query = parse_qs(parsed_url.query) - - self.assertEqual(parsed_url.path, "/verify-email/") - self.assertEqual(query["username"], [test_user]) - self.assertTrue( - query["token"] - ) # Token random every time so just check we have something - - def test_send_message_raises_error_if_sender_not_defined(self): - # Arrange - current_app.config["MAIL_DEFAULT_SENDER"] = None - to_address = self.to_address - subject = self.subject - content = self.content - - # Act/Assert - with self.assertRaises(ValueError): - SMTPService._send_message(to_address, subject, content, content) - current_app.config["MAIL_DEFAULT_SENDER"] = os.environ.get( - "TM_EMAIL_FROM_ADDRESS", None - ) - - def test_send_message_sends_mail_if_sender_is_defined(self): - # Arrange - current_app.config["MAIL_DEFAULT_SENDER"] = MagicMock(None) - to_address = self.to_address - subject = self.subject - content = self.content - - # Act/Assert - SMTPService._send_message(to_address, subject, content, content) - - @patch.object(SMTPService, "_send_message") - @patch.object(UserService, "get_user_by_id") - @patch.object(Message, "get_all_contributors") - def test_send_email_to_contributors_on_project_progress( - self, - mock_get_all_contributors, - mock_get_user_by_id, - mock_send_message, - ): - # Arrange - mock_get_all_contributors.return_value = [(123456,)] - test_user = return_canned_user() - test_user.email_address = self.to_address - mock_get_user_by_id.return_value = test_user - - # Test email is not sent if user email is not verified - SMTPService.send_email_to_contributors_on_project_progress( - EncouragingEmailType.PROJECT_PROGRESS.value, 1, "test", 50 - ) - self.assertFalse(mock_send_message.called) - - # Test email is not sent if user has projects notifications disabled - test_user.is_email_verified = True - test_user.projects_notifications = False - SMTPService.send_email_to_contributors_on_project_progress( - EncouragingEmailType.PROJECT_PROGRESS.value, 1, "test", 50 - ) - self.assertFalse(mock_send_message.called) - - # Test email is sent if user has projects notifications enabled and email is verified - test_user.projects_notifications = True - SMTPService.send_email_to_contributors_on_project_progress( - EncouragingEmailType.PROJECT_PROGRESS.value, 1, "test", 50 - ) - mock_send_message.assert_called() diff --git a/tests/backend/integration/services/test_favorite_service.py b/tests/backend/integration/services/test_favorite_service.py deleted file mode 100644 index c5c69e3df9..0000000000 --- a/tests/backend/integration/services/test_favorite_service.py +++ /dev/null @@ -1,44 +0,0 @@ -from backend.exceptions import NotFound -from backend.services.project_service import ProjectService -from backend.services.users.user_service import UserService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - - -class TestFavoriteService(BaseTestCase): - def test_project_favorite(self): - self.test_project, self.test_user = create_canned_project() - - # Validate that project has not been favorited by user. - fav = ProjectService.is_favorited(self.test_project.id, self.test_user.id) - self.assertFalse(fav) - - # Get project favorites from user. - favorites = UserService.get_projects_favorited(self.test_user.id) - json_data = favorites.to_primitive() - self.assertEqual(len(json_data["favoritedProjects"]), 0) - - # Now favorite a new project. - ProjectService.favorite(self.test_project.id, self.test_user.id) - fav = ProjectService.is_favorited(self.test_project.id, self.test_user.id) - self.assertTrue(fav) - - # Get project favorites from user. - favorites = UserService.get_projects_favorited(self.test_user.id) - json_data = favorites.to_primitive() - self.assertEqual(len(json_data["favoritedProjects"]), 1) - - # Now unfavorite it. - ProjectService.unfavorite(self.test_project.id, self.test_user.id) - fav = ProjectService.is_favorited(self.test_project.id, self.test_user.id) - self.assertFalse(fav) - - # Unfavorite a project not been favorited previously. - with self.assertRaises(ValueError): - ProjectService.unfavorite(self.test_project.id, self.test_user.id) - - # Verify that NotFound exists. - with self.assertRaises(NotFound): - ProjectService.is_favorited(100, self.test_user.id) - ProjectService.favorite(100, self.test_user.id) - ProjectService.unfavorite(100, self.test_user.id) diff --git a/tests/backend/integration/services/test_featured_projects_services.py b/tests/backend/integration/services/test_featured_projects_services.py deleted file mode 100644 index b3268a2bf4..0000000000 --- a/tests/backend/integration/services/test_featured_projects_services.py +++ /dev/null @@ -1,26 +0,0 @@ -from backend.exceptions import NotFound -from backend.services.project_service import ProjectService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - - -class TestFeaturedProjectService(BaseTestCase): - def test_featured_projects_service(self): - self.test_project, self.test_user = create_canned_project() - - # Featured a not created project. - with self.assertRaises(NotFound): - ProjectService.set_project_as_featured(project_id=100) - - # Feature an already created project. - ProjectService.set_project_as_featured(project_id=self.test_project.id) - - # List all featured projects. - featured_projects = ProjectService.get_featured_projects(None) - self.assertEqual(len(featured_projects.results), 1) - - # Unfeature project. - ProjectService.unset_project_as_featured(project_id=self.test_project.id) - # List all featured projects. - featured_projects = ProjectService.get_featured_projects(None) - self.assertEqual(len(featured_projects.results), 0) diff --git a/tests/backend/integration/services/test_interests_service.py b/tests/backend/integration/services/test_interests_service.py deleted file mode 100644 index 2685b57a8e..0000000000 --- a/tests/backend/integration/services/test_interests_service.py +++ /dev/null @@ -1,91 +0,0 @@ -from backend.exceptions import NotFound -from backend.services.interests_service import InterestService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - - -class TestInterestService(BaseTestCase): - test_project = None - test_user = None - - def setUp(self): - super().setUp() - self.test_project, self.test_user = create_canned_project() - - @staticmethod - def relationship_user(interests, user_id, ids): - interest_ids = [interests[c]["id"] for c in ids] - user_interests = InterestService.create_or_update_user_interests( - user_id, interest_ids - ) - user_interests_ids = [ - i["id"] for i in user_interests.to_primitive()["interests"] - ] - - return interest_ids, user_interests_ids - - @staticmethod - def relationship_project(interests, project_id, ids): - interest_ids = [interests[c]["id"] for c in ids] - project_interests = InterestService.create_or_update_project_interests( - project_id, interest_ids - ) - project_interests_ids = [ - i["id"] for i in project_interests.to_primitive()["interests"] - ] - - return interest_ids, project_interests_ids - - def test_interests(self): - # if self.skip_tests: - # return - - interests = ["interest_number_{0}".format(i) for i in range(1, 9)] - [InterestService.create(interest_name=i) for i in interests] - interests = InterestService.get_all_interests().to_primitive()["interests"] - self.assertEqual(len(interests), 8) - - # Create new interest. - new_interest = InterestService.create(interest_name="test_new_interest") - interests = InterestService.get_all_interests().to_primitive()["interests"] - self.assertEqual(len(interests), 9) - - # Update interest - new_interest.name = "new_interest_name" - updated_interest = InterestService.update(new_interest.id, new_interest) - self.assertEqual(new_interest.name, updated_interest.name) - - # Associate users with interest. - iids, uids = TestInterestService.relationship_user( - interests, self.test_user.id, [1, 4, 5] - ) - self.assertEqual(uids, iids) - - # Try again. - iids, uids = TestInterestService.relationship_user( - interests, self.test_user.id, [1, 2] - ) - self.assertEqual(uids, iids) - - # Validate unexistent interest. - with self.assertRaises(NotFound): - InterestService.create_or_update_user_interests(self.test_user.id, [0]) - - # Associate projects with interest. - iids, pids = TestInterestService.relationship_project( - interests, self.test_project.id, [1, 2] - ) - self.assertEqual(pids, iids) - - # Validate unexistent interest. - with self.assertRaises(NotFound): - InterestService.create_or_update_project_interests( - self.test_project.id, [0] - ) - - # Delete one by one. - for interest in interests: - InterestService.delete(interest["id"]) - - interests = InterestService.get_all_interests().to_primitive()["interests"] - self.assertEqual(len(interests), 0) diff --git a/tests/backend/integration/services/test_license_service.py b/tests/backend/integration/services/test_license_service.py deleted file mode 100644 index 335719eb05..0000000000 --- a/tests/backend/integration/services/test_license_service.py +++ /dev/null @@ -1,42 +0,0 @@ -from backend.exceptions import NotFound -from backend.services.license_service import LicenseDTO, LicenseService -from tests.backend.base import BaseTestCase - - -class TestLicenseService(BaseTestCase): - def test_license_crud_works_as_expected(self): - # Arrange - license_dto = LicenseDTO() - license_dto.name = "thinkWhere" - license_dto.description = "thinkWhere test" - license_dto.plain_text = "thinkWhere test" - - # Act - license_id = LicenseService.create_licence(license_dto) - - try: - actual_license = LicenseService.get_license_as_dto(license_id) - - # Assert PUT and GET - self.assertEqual(actual_license.name, license_dto.name) - - license_dto.license_id = license_id - license_dto.name = "Updated name" - LicenseService.update_licence(license_dto) - updated_license = LicenseService.get_license_as_dto(license_id) - - # Assert POST - self.assertEqual(updated_license.name, license_dto.name) - - all_licenses = LicenseService.get_all_licenses() - - # Assert Get all - self.assertGreaterEqual(1, len(all_licenses)) - - # Assert Delete - LicenseService.delete_license(license_id) - with self.assertRaises(NotFound): - LicenseService.get_license_as_dto(license_id) - except Exception: - # If any problem occurs try and tidy up - LicenseService.delete_license(license_id) diff --git a/tests/backend/integration/services/test_mapping_service.py b/tests/backend/integration/services/test_mapping_service.py deleted file mode 100644 index e8158d433d..0000000000 --- a/tests/backend/integration/services/test_mapping_service.py +++ /dev/null @@ -1,167 +0,0 @@ -import datetime -import xml.etree.ElementTree as ET -from unittest.mock import patch - -from backend.models.postgis.task import TaskStatus -from backend.services.mapping_service import MappingService, Task -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - -ORG_NAME = "HOT Tasking Manager" - - -class TestMappingService(BaseTestCase): - skip_tests = False - test_project = None - test_user = None - - def setUp(self): - super().setUp() - self.test_project, self.test_user = create_canned_project() - - @patch.object(Task, "get_tasks") - def test_generate_gpx(self, mock_task): - # Create a sample project ID and task IDs string - project_id = 1 - task_ids_str = "1,2" - task = Task.get(1, self.test_project.id) - mock_task.return_value = [task] - - timestamp = datetime.datetime(2017, 4, 13) - - # Call the generate_gpx function with some test data - xml_str = MappingService.generate_gpx(1, task_ids_str, timestamp) - - # Parse the XML string and retrieve the root element - root = ET.fromstring(xml_str) - - # Test root element - self.assertEqual(root.tag, "{http://www.topografix.com/GPX/1/1}gpx") - self.assertEqual(root.attrib["creator"], ORG_NAME) - self.assertEqual(root.attrib["version"], "1.1") - - # Test metadata element - metadata = root.find("{http://www.topografix.com/GPX/1/1}metadata") - self.assertIsNotNone(metadata) - - link = metadata.find("{http://www.topografix.com/GPX/1/1}link") - self.assertIsNotNone(link) - self.assertEqual( - link.attrib["href"], "https://github.com/hotosm/tasking-manager" - ) - text = link.find("{http://www.topografix.com/GPX/1/1}text") - self.assertIsNotNone(text) - self.assertEqual(text.text.strip(), ORG_NAME) - - time = metadata.find("{http://www.topografix.com/GPX/1/1}time") - self.assertIsNotNone(time) - self.assertEqual(time.text.strip(), "2017-04-13T00:00:00") - - # Test trk element - trk = root.find("{http://www.topografix.com/GPX/1/1}trk") - self.assertIsNotNone(trk) - - name = trk.find("{http://www.topografix.com/GPX/1/1}name") - self.assertIsNotNone(name) - self.assertEqual( - name.text.strip(), - f"Task for project {project_id}. Do not edit outside of this area!", - ) - - trkseg = trk.find("{http://www.topografix.com/GPX/1/1}trkseg") - self.assertIsNotNone(trkseg) - - trkpt_list = trkseg.findall("{http://www.topografix.com/GPX/1/1}trkpt") - self.assertEqual(len(trkpt_list), 5) - for trkpt in trkpt_list: - self.assertIn("lat", trkpt.attrib) - self.assertIn("lon", trkpt.attrib) - - # Test wpt elements - wpt_list = root.findall("{http://www.topografix.com/GPX/1/1}wpt") - self.assertEqual(len(wpt_list), 5) - for wpt in wpt_list: - self.assertIn("lat", wpt.attrib) - self.assertIn("lon", wpt.attrib) - - @patch.object(Task, "get_tasks") - def test_generate_osm_xml(self, mock_task): - # Test with a single task - task_ids_str = "1" - task_1 = Task.get(1, self.test_project.id) - task_2 = Task.get(2, self.test_project.id) - mock_task.return_value = [task_1] - - xml = MappingService.generate_osm_xml(1, task_ids_str) - self.assertIsNotNone(xml) - - # Assert that the generated XML is in the correct format - root = ET.fromstring(xml) - self.assertEqual(root.tag, "osm") - self.assertEqual(root.attrib["version"], "0.6") - self.assertEqual(root.attrib["upload"], "never") - self.assertEqual(root.attrib["creator"], ORG_NAME) - - # Assert that the correct number of nodes and ways were generated - nodes = root.findall("./node") - self.assertEqual(len(nodes), 5) - ways = root.findall("./way") - self.assertEqual(len(ways), 1) - - # Test with multiple tasks - task_ids_str = "1,2" - mock_task.return_value = [task_1, task_2] - xml = MappingService.generate_osm_xml(1, task_ids_str) - self.assertIsNotNone(xml) - - # Assert that the generated XML is in the correct format - root = ET.fromstring(xml) - self.assertEqual(root.tag, "osm") - self.assertEqual(root.attrib["version"], "0.6") - self.assertEqual(root.attrib["upload"], "never") - self.assertEqual(root.attrib["creator"], ORG_NAME) - - # Assert that the correct number of nodes and ways were generated - nodes = root.findall("./node") - self.assertEqual(len(nodes), 25) - ways = root.findall("./way") - self.assertEqual(len(ways), 2) - - def test_map_all_sets_counters_correctly(self): - if self.skip_tests: - return - - # Act - MappingService.map_all_tasks(self.test_project.id, self.test_user.id) - - # Assert - self.assertEqual( - self.test_project.tasks_mapped, - self.test_project.total_tasks - - self.test_project.tasks_validated - - self.test_project.tasks_bad_imagery, - ) - - def test_mapped_by_is_set_after_mapping_all(self): - if self.skip_tests: - return - - # Act - MappingService.map_all_tasks(self.test_project.id, self.test_user.id) - - # Assert - for task in self.test_project.tasks: - self.assertIsNotNone(task.mapped_by) - - def test_reset_all_bad_imagery( - self, - ): - if self.skip_tests: - return - - # Act - MappingService.reset_all_badimagery(self.test_project.id, self.test_user.id) - - # Assert - for task in self.test_project.tasks: - self.assertNotEqual(task.task_status, TaskStatus.BADIMAGERY.value) diff --git a/tests/backend/integration/services/test_organisation_service.py b/tests/backend/integration/services/test_organisation_service.py deleted file mode 100644 index 924cdeb7dc..0000000000 --- a/tests/backend/integration/services/test_organisation_service.py +++ /dev/null @@ -1,205 +0,0 @@ -from datetime import datetime - -from schematics.exceptions import UndefinedValueError - -from backend.models.postgis.statuses import ProjectStatus, TeamVisibility -from backend.services.organisation_service import NotFound, OrganisationService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - TEST_ORGANISATION_ID, - TEST_USER_ID, - add_manager_to_organisation, - create_canned_organisation, - create_canned_project, - create_canned_user, - return_canned_team, -) - - -class TestOrgansitaionService(BaseTestCase): - def setUp(self): - super().setUp() - self.test_org = create_canned_organisation() - - def test_is_user_an_org_manager_raises_error_if_organistion_not_found(self): - # Assert/Act - with self.assertRaises(NotFound): - OrganisationService.is_user_an_org_manager( - TEST_ORGANISATION_ID, TEST_USER_ID - ) - - def test_is_user_an_org_manager_returns_false_if_user_not_manager_of_organisation( - self, - ): - test_user = create_canned_user() - # Act - is_org_manager = OrganisationService.is_user_an_org_manager( - self.test_org.id, test_user.id - ) - # Assert - self.assertFalse(is_org_manager) - - def test_is_user_an_org_manager_returns_true_if_user_is_manager_of_organisation( - self, - ): - # Arrange - test_user = create_canned_user() - self.test_org.managers = [test_user] - # Act - is_org_manager = OrganisationService.is_user_an_org_manager( - self.test_org.id, test_user.id - ) - # Assert - self.assertTrue(is_org_manager) - - def test_get_organisations_as_dto(self): - # Test returns stats when omit stats enabled - # Act - orgs_dto = OrganisationService.get_organisations_as_dto( - manager_user_id=None, - authenticated_user_id=False, - omit_managers=True, - omit_stats=True, - ) - # Assert - self.assertEqual(len(orgs_dto.organisations), 1) - self.assertEqual(orgs_dto.organisations[0].organisation_id, self.test_org.id) - self.assertEqual(orgs_dto.organisations[0].name, self.test_org.name) - # Since omitManagers is set to true - with self.assertRaises(UndefinedValueError): - orgs_dto.organisations[0].managers - self.assertEqual(orgs_dto.organisations[0].stats, None) - - # Test returns stats when omit_stats_disabled - # Arrange - test_project, test_author = create_canned_project() - test_project.organisation = self.test_org - test_project.save() - # Act - orgs_dto = OrganisationService.get_organisations_as_dto( - manager_user_id=None, - authenticated_user_id=False, - omit_managers=True, - omit_stats=False, - ) - # Assert - self.assertEqual(orgs_dto.organisations[0].stats.projects.draft, 1) - self.assertEqual(orgs_dto.organisations[0].stats.projects.archived, 0) - self.assertEqual(orgs_dto.organisations[0].stats.projects.published, 0) - - # Test returns managers when omit managers disabled - # Arrange - add_manager_to_organisation(self.test_org, test_author) - # Act - orgs_dto = OrganisationService.get_organisations_as_dto( - manager_user_id=None, - authenticated_user_id=True, - omit_managers=False, - omit_stats=True, - ) - # Assert - self.assertEqual(len(orgs_dto.organisations[0].managers), 1) - self.assertEqual( - orgs_dto.organisations[0].managers[0].username, test_author.username - ) - - def test_get_organisation_stats(self): - # Test returns all time stats if year is None - # Arrange - test_project, _ = create_canned_project() - test_project.organisation = self.test_org - test_project.status = ProjectStatus.PUBLISHED.value - test_project.save() - # Act - org_stats = OrganisationService.get_organisation_stats(self.test_org.id) - # Assert - self.assertEqual(org_stats.projects.published, 1) - self.assertEqual(org_stats.projects.draft, 0) - self.assertEqual(org_stats.projects.archived, 0) - self.assertEqual(org_stats.active_tasks.mapped, 1) - self.assertEqual(org_stats.active_tasks.ready, 1) - self.assertEqual(org_stats.active_tasks.badimagery, 1) - self.assertEqual(org_stats.active_tasks.validated, 1) - self.assertEqual(org_stats.active_tasks.invalidated, 0) - - # Test returns yeat to date stats if year is not None - # Arrange - test_project.created = datetime.strptime("2018/07/06", "%Y/%m/%d") - test_project.save() - # Act - org_stats = OrganisationService.get_organisation_stats( - self.test_org.id, datetime.today().strftime("%Y") - ) - # Assert - self.assertEqual(org_stats.projects.published, 0) - self.assertEqual(org_stats.projects.draft, 0) - self.assertEqual(org_stats.projects.archived, 0) - self.assertEqual(org_stats.active_tasks.mapped, 0) - self.assertEqual(org_stats.active_tasks.ready, 0) - self.assertEqual(org_stats.active_tasks.badimagery, 0) - self.assertEqual(org_stats.active_tasks.validated, 0) - self.assertEqual(org_stats.active_tasks.invalidated, 0) - - def assert_org_dto(self, org_dto): - """Asserts that the organisation DTO is correct""" - self.assertEqual(org_dto.organisation_id, self.test_org.id) - self.assertEqual(org_dto.name, self.test_org.name) - self.assertEqual(org_dto.description, None) - self.assertEqual(org_dto.url, None) - - def test_get_organisation_dto(self): - """Test get_organisation_dto returns correct DTO""" - # Arrange - test_user = create_canned_user() - test_team_1 = return_canned_team("test_team_1", self.test_org.name) - test_team_1.visibility = TeamVisibility.PUBLIC.value - test_team_1.create() - test_team_2 = return_canned_team("test_team_2", self.test_org.name) - test_team_2.visibility = TeamVisibility.PRIVATE.value - test_team_2.create() - - # Test with valid org and user id as non manager - org_dto = OrganisationService.get_organisation_dto( - self.test_org, test_user.id, abbreviated=False - ) - self.assert_org_dto(org_dto) - self.assertFalse(org_dto.is_manager) - self.assertEqual(len(org_dto.teams), 1) - self.assertEqual(org_dto.teams[0].team_id, test_team_1.id) - - # Test with valid org with abbreviated=True - org_dto = OrganisationService.get_organisation_dto( - self.test_org, test_user.id, abbreviated=True - ) - self.assertEqual(org_dto.organisation_id, self.test_org.id) - self.assertEqual(org_dto.name, self.test_org.name) - self.assertEqual(org_dto.description, None) - self.assertEqual(org_dto.url, None) - self.assertFalse(org_dto.is_manager) - self.assertEqual(org_dto.teams, None) - - # Test with valid org and user id as manager - add_manager_to_organisation(self.test_org, test_user) - org_dto = OrganisationService.get_organisation_dto( - self.test_org, test_user.id, abbreviated=False - ) - self.assert_org_dto(org_dto) - self.assertTrue(org_dto.is_manager) - self.assertEqual(len(org_dto.teams), 2) - self.assertEqual(org_dto.teams[0].team_id, test_team_1.id) - self.assertEqual(org_dto.teams[1].team_id, test_team_2.id) - - # Test with valid org and user id as 0 - org_dto = OrganisationService.get_organisation_dto( - self.test_org, 0, abbreviated=False - ) - self.assert_org_dto(org_dto) - self.assertFalse(org_dto.is_manager) - self.assertEqual(len(org_dto.teams), 1) - self.assertEqual(org_dto.teams[0].team_id, test_team_1.id) - - # Test with invalid org - with self.assertRaises(NotFound): - OrganisationService.get_organisation_dto( - None, test_user.id, abbreviated=False - ) diff --git a/tests/backend/integration/services/test_project_admin_service.py b/tests/backend/integration/services/test_project_admin_service.py deleted file mode 100644 index aee7db3714..0000000000 --- a/tests/backend/integration/services/test_project_admin_service.py +++ /dev/null @@ -1,484 +0,0 @@ -import json -from unittest.mock import MagicMock, patch - -from flask import current_app - -from backend.models.dtos.organisation_dto import ListOrganisationsDTO -from backend.models.dtos.project_dto import ( - DraftProjectDTO, - ProjectDTO, - ProjectInfoDTO, - ProjectStatus, -) -from backend.models.postgis.project import NotFound, Project, ProjectPriority, User -from backend.models.postgis.statuses import ProjectDifficulty, UserRole -from backend.services.messaging.message_service import MessageService -from backend.services.organisation_service import OrganisationService -from backend.services.project_admin_service import ( - InvalidGeoJson, - ProjectAdminService, - ProjectAdminServiceError, -) -from backend.services.team_service import TeamService -from backend.services.users.user_service import UserService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_manager_to_organisation, - create_canned_organisation, - create_canned_project, - create_canned_user, - return_canned_draft_project_json, - return_canned_user, -) - - -class TestProjectAdminService(BaseTestCase): - @patch.object(UserService, "get_user_by_id") - @patch.object(UserService, "is_user_an_admin") - @patch.object(OrganisationService, "get_organisations_managed_by_user_as_dto") - def test_create_draft_project_raises_error_if_user_not_admin_or_org_manager( - self, mock_user_orgs, mock_admin_test, mock_user_get - ): - # Arrange - draft_project_dto = DraftProjectDTO(return_canned_draft_project_json()) - draft_project_dto.user_id = 77777 - mock_admin_test.return_value = False - org_dto = ListOrganisationsDTO() - org_dto.organisations = [] - mock_user_orgs.return_value = org_dto - mock_user_get.return_value = return_canned_user() - - # Act/Assert - with self.assertRaises(ProjectAdminServiceError): - ProjectAdminService.create_draft_project(draft_project_dto) - - @patch.object(UserService, "is_user_an_admin") - @patch.object(OrganisationService, "get_organisations_managed_by_user_as_dto") - def test_create_draft_project_creates_project_if_user_is_admin( - self, mock_user_orgs, mock_admin_test - ): - # Arrange - draft_project_dto = DraftProjectDTO(return_canned_draft_project_json()) - draft_project_dto.user_id = 777777 - mock_admin_test.return_value = True - org_dto = ListOrganisationsDTO() - org_dto.organisations = [] - mock_user_orgs.return_value = org_dto - create_canned_user() # Create user with id "777777" - create_canned_organisation() # Create org with id "23" which is specified on draft project dto - - # Act/Assert - ProjectAdminService.create_draft_project(draft_project_dto) - - @patch.object(UserService, "is_user_an_admin") - @patch.object(OrganisationService, "get_organisations_managed_by_user_as_dto") - def test_create_draft_project_creates_project_if_user_is_org_manager( - self, mock_user_orgs, mock_admin_test - ): - # Arrange - create_canned_user() # Create user with id "777777" - create_canned_organisation() # Create org with id "23" which is specified on draft project dto - draft_project_dto = DraftProjectDTO(return_canned_draft_project_json()) - draft_project_dto.user_id = 777777 - mock_admin_test.return_value = False - org_dto = ListOrganisationsDTO() - org_dto.organisations = [23] - mock_user_orgs.return_value = org_dto - - # Act/Assert - ProjectAdminService.create_draft_project(draft_project_dto) - - @patch.object(Project, "clone") - @patch.object(UserService, "get_user_by_id") - @patch.object(UserService, "is_user_an_admin") - def test_create_draft_project_calls_project_clone_if_clone_from_project_id_found( - self, mock_admin_test, mock_user_get, mock_project_clone - ): - # Arrange - create_canned_user() # Create user with id "777777" - create_canned_organisation() # Create org with id "23" which is specified on draft project dto - test_project = create_canned_project()[ - 0 - ] # Create test project which so that we have a project to clone - - draft_project_dto = DraftProjectDTO(return_canned_draft_project_json()) - draft_project_dto.user_id = 777777 - draft_project_dto.cloneFromProjectId = test_project.id - mock_admin_test.return_value = True - # Act - ProjectAdminService.create_draft_project(draft_project_dto) - # Assert - mock_project_clone.assert_called_with( - draft_project_dto.cloneFromProjectId, draft_project_dto.user_id - ) - - @patch.object(UserService, "get_user_by_id") - @patch.object(UserService, "is_user_an_admin") - def test_create_draft_project_raises_error_if_org_not_found( - self, mock_admin_test, mock_user_get - ): - # Arrange - mock_user_get.return_value = return_canned_user() - draft_project_dto = DraftProjectDTO(return_canned_draft_project_json()) - draft_project_dto.user_id = 777777 - mock_admin_test.return_value = True - # Act/Assert - with self.assertRaises(NotFound): - ProjectAdminService.create_draft_project(draft_project_dto) - - def test_cant_add_tasks_if_geojson_not_feature_collection(self): - # Arrange - invalid_feature = ( - '{"coordinates": [[[[-4.0237, 56.0904], [-3.9111, 56.1715], [-3.8122, 56.098],' - '[-4.0237, 56.0904]]]], "type": "MultiPolygon"}' - ) - - # Act - with self.assertRaises(InvalidGeoJson): - ProjectAdminService._attach_tasks_to_project(MagicMock(), invalid_feature) - - def test_valid_geo_json_attaches_task_to_project(self): - # Arrange - valid_feature_collection = json.loads( - '{"features": [{"geometry": {"coordinates": [[[[-4.0237, 56.0904],' - '[-3.9111, 56.1715], [-3.8122, 56.098], [-4.0237, 56.0904]]]], "type":' - '"MultiPolygon"}, "properties": {"x": 2402, "y": 1736, "zoom": 12, "isSquare": true}, "type":' - '"Feature"}], "type": "FeatureCollection"}' - ) - - test_project = Project() - - # Act - ProjectAdminService._attach_tasks_to_project( - test_project, valid_feature_collection - ) - - # Assert - self.assertEqual( - 1, - test_project.tasks.count(), - "One task should have been attached to project", - ) - - @patch.object(UserService, "is_user_the_project_author") - @patch.object(UserService, "is_user_an_admin") - def test_is_user_action_permitted_on_project_returns_true_for_admin( - self, mock_is_user_admin, mock_is_user_author - ): - # Arrange - test_project, test_user = create_canned_project() - mock_is_user_admin.return_value = True - mock_is_user_author.return_value = False - # Act - permitted = ProjectAdminService.is_user_action_permitted_on_project( - test_user.id, test_project.id - ) - # Assert - self.assertTrue(permitted) - - def test_is_user_action_permitted_on_project_returns_true_for_author(self): - # Arrange - test_project, test_user = create_canned_project() - # Act - permitted = ProjectAdminService.is_user_action_permitted_on_project( - test_user.id, test_project.id - ) - # Assert - self.assertTrue(permitted) - - @patch.object(UserService, "is_user_the_project_author") - @patch.object(UserService, "is_user_an_admin") - def test_is_user_action_permitted_on_project_returns_true_for_org_manager( - self, mock_is_user_admin, mock_is_user_author - ): - # Arrange - test_project, test_user = create_canned_project() - test_org = create_canned_organisation() - test_project.organisation_id = test_org.id - test_org.managers = [test_user] - mock_is_user_admin.return_value = False - mock_is_user_author.return_value = False - # Act - permitted = ProjectAdminService.is_user_action_permitted_on_project( - test_user.id, test_project.id - ) - # Assert - self.assertTrue(permitted) - - @patch.object(TeamService, "check_team_membership") - @patch.object(OrganisationService, "is_user_an_org_manager") - @patch.object(UserService, "is_user_the_project_author") - @patch.object(UserService, "is_user_an_admin") - def test_is_user_action_permitted_on_project_returns_true_for_project_team_manager( - self, - mock_is_user_admin, - mock_is_user_author, - mock_is_user_org_manager, - mock_check_team_membership, - ): - # Arrange - test_project, test_user = create_canned_project() - test_org = create_canned_organisation() - test_project.organisation_id = test_org.id - mock_is_user_admin.return_value = False - mock_is_user_author.return_value = False - mock_is_user_org_manager.return_value = False - mock_check_team_membership.return_value = True - # Act - permitted = ProjectAdminService.is_user_action_permitted_on_project( - test_user.id, test_project.id - ) - # Assert - self.assertTrue(permitted) - - @patch.object(TeamService, "check_team_membership") - @patch.object(OrganisationService, "is_user_an_org_manager") - @patch.object(UserService, "is_user_the_project_author") - @patch.object(UserService, "is_user_an_admin") - def test_is_user_action_permitted_on_project_returns_false_for_user_without_permission( - self, - mock_is_user_admin, - mock_is_user_author, - mock_is_user_org_manager, - mock_check_team_membership, - ): - # Arrange - test_project, test_user = create_canned_project() - test_org = create_canned_organisation() - test_project.organisation_id = test_org.id - mock_is_user_admin.return_value = False - mock_is_user_author.return_value = False - mock_is_user_org_manager.return_value = False - mock_check_team_membership.return_value = False - # Act - permitted = ProjectAdminService.is_user_action_permitted_on_project( - test_user.id, test_project.id - ) - # Assert - self.assertFalse(permitted) - - @patch.object(User, "get_by_id") - @patch.object(Project, "get") - def test_update_published_project_with_incomplete_default_locale_raises_error( - self, mock_project, mock_user - ): - # Arrange - stub_project = Project() - stub_project.status = ProjectStatus.PUBLISHED.value - - mock_project.return_value = stub_project - - locales = [] - info = ProjectInfoDTO() - info.locale = "en" - info.name = "Test" - locales.append(info) - - dto = ProjectDTO() - dto.project_id = 1 - dto.default_locale = "en" - dto.project_info_locales = locales - dto.project_status = ProjectStatus.PUBLISHED.name - - stub_admin_user = User() - stub_admin_user.username = "admin" - stub_admin_user.role = UserRole.ADMIN.value - - mock_user.return_value = stub_admin_user - # Act / Assert - with self.assertRaises(ProjectAdminServiceError): - ProjectAdminService.update_project(dto, mock_user.id) - - @patch.object(User, "get_by_id") - @patch.object(Project, "update") - @patch.object(Project, "get") - def test_updating_a_private_project_with_no_allowed_users_raises_error( - self, mock_project, mock_project2, mock_user - ): - # Arrange - mock_project.return_value = Project() - - dto = ProjectDTO() - dto.private = True - dto.allowed_usernames = [] - - stub_user = User() - stub_user.username = "admin" - stub_user.role = UserRole.ADMIN.value - - mock_user.return_value = stub_user - - # Act - try: - ProjectAdminService.update_project(dto, mock_user.id) - # Assert - except ProjectAdminServiceError: - self.fail("update_project raised an exception when setting it as private") - - @patch.object(User, "get_by_id") - @patch.object(Project, "get") - def test_update_project_with_non_existant_license_raises_error( - self, mock_project, mock_user - ): - # Arrange - stub_project = Project() - stub_project.status = ProjectStatus.PUBLISHED.value - - mock_project.return_value = stub_project - - locales = [] - info = ProjectInfoDTO() - info.locale = "en" - info.name = "Test" - info.description = "Test description" - info.short_description = "Test short description" - info.instructions = "Test instructions" - locales.append(info) - - dto = ProjectDTO() - dto.project_id = 1 - dto.default_locale = "en" - dto.license_id = 1 - dto.project_info_locales = locales - dto.project_status = ProjectStatus.PUBLISHED.name - - stub_admin_user = User() - stub_admin_user.username = "admin" - stub_admin_user.role = UserRole.ADMIN.value - - mock_user.return_value = stub_admin_user - # Act / Assert - with self.assertRaises(ProjectAdminServiceError): - ProjectAdminService.update_project(dto, mock_user.id) - - @patch.object(User, "get_by_id") - @patch.object(Project, "update") - @patch.object(Project, "get") - def test_updating_a_project_with_different_roles_raises_error( - self, mock_project, mock_project2, mock_user - ): - # Arrange - stub_project = Project() - stub_project.status = ProjectStatus.DRAFT.value - - mock_project.return_value = stub_project - - locales = [] - info = ProjectInfoDTO() - info.locale = "en" - info.name = "Test" - locales.append(info) - - dto = ProjectDTO() - dto.project_id = 1 - dto.default_locale = "en" - dto.project_status = ProjectStatus.DRAFT.name - dto.project_priority = ProjectPriority.LOW.name - dto.difficulty = ProjectDifficulty.EASY.name - dto.mapping_types = ["ROADS"] - dto.mapping_editors = ["ID"] - dto.validation_editors = ["ID"] - dto.project_info_locales = locales - - stub_user = User() - stub_user.username = "mapper" - stub_user.role = UserRole.MAPPER.value - mock_user.return_value = stub_user - # Act/Assert - with self.assertRaises(ValueError): - ProjectAdminService.update_project(dto, mock_user.id) - - def test_updating_a_project_with_valid_project_info(self): - locales = [] - info = ProjectInfoDTO() - info.locale = "en" - info.name = "Test" - info.description = "Test description" - info.short_description = "Test short description" - info.instructions = "Test instructions" - locales.append(info) - - test_project, test_user = create_canned_project() - - dto = ProjectDTO() - dto.project_id = test_project.id - dto.default_locale = "en" - dto.project_status = ProjectStatus.PUBLISHED.name - dto.project_priority = ProjectPriority.LOW.name - dto.difficulty = ProjectDifficulty.EASY.name - dto.mapping_types = ["ROADS"] - dto.mapping_editors = ["ID"] - dto.validation_editors = ["ID"] - dto.project_info_locales = locales - # Act - updated_project = ProjectAdminService.update_project(dto, test_user.id) - # Assert - self.assertEqual( - updated_project.difficulty, ProjectDifficulty[dto.difficulty.upper()].value - ) - self.assertEqual( - updated_project.status, ProjectStatus[dto.project_status].value - ) - self.assertEqual( - updated_project.priority, ProjectPriority[dto.project_priority].value - ) - - @patch.object(MessageService, "send_project_transfer_message") - def test_project_transfer_to_(self, mock_send_message): - test_project, test_author = create_canned_project() - test_organisation = create_canned_organisation() - test_user = return_canned_user("TEST_USER", 11111) - test_user.create() - test_manager = return_canned_user("TEST_MANAGER", 22222) - test_manager.create() - test_project.organisation = test_organisation - test_project.organisation_id = test_organisation.id - add_manager_to_organisation(test_organisation, test_manager) - - # Test error is raised if initiating user is not permitted to transfer project - current_app.logger.debug( - "Testing error is raised if initiating user is not permitted to transfer project" - ) - with self.assertRaises(ProjectAdminServiceError): - ProjectAdminService.transfer_project_to( - test_project.id, test_user.id, test_manager.username - ) - - # Test error is raised if transferred to user who is not a manager of the organisation - current_app.logger.debug( - "Testing error is raised if transferred to user who is not a manager of the organisation" - ) - with self.assertRaises(ValueError): - ProjectAdminService.transfer_project_to( - test_project.id, test_manager.id, test_user.username - ) - - # Test project author can transfer project - current_app.logger.debug("Testing project author can transfer project") - ProjectAdminService.transfer_project_to( - test_project.id, test_author.id, test_manager.username - ) - mock_send_message.assert_called_with( - test_project.id, test_manager.username, test_author.username - ) - - # Test admin can transfer project - current_app.logger.debug("Testing admin can transfer project") - test_user.role = UserRole.ADMIN.value - test_project.author = test_author - ProjectAdminService.transfer_project_to( - test_project.id, test_user.id, test_manager.username - ) - mock_send_message.assert_called_with( - test_project.id, test_manager.username, test_user.username - ) - - # Test org manager can transfer project - current_app.logger.debug("Testing org manager can transfer project") - test_project.author = test_author - ProjectAdminService.transfer_project_to( - test_project.id, test_manager.id, test_manager.username - ) - mock_send_message.assert_called_with( - test_project.id, test_manager.username, test_manager.username - ) diff --git a/tests/backend/integration/services/test_project_search_service.py b/tests/backend/integration/services/test_project_search_service.py deleted file mode 100644 index 979462e44d..0000000000 --- a/tests/backend/integration/services/test_project_search_service.py +++ /dev/null @@ -1,113 +0,0 @@ -import json -from unittest.mock import patch - -from shapely.geometry import Polygon - -from backend.models.dtos.project_dto import ProjectSearchBBoxDTO -from backend.models.postgis.project import Project, ProjectInfo -from backend.models.postgis.user import User -from backend.services.project_search_service import ProjectSearchService -from backend.services.users.user_service import UserService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import get_canned_json - - -class TestProjectSearchService(BaseTestCase): - @patch.object(ProjectSearchService, "_make_4326_polygon_from_bbox") - @patch.object(ProjectSearchService, "validate_bbox_area") - @patch.object(UserService, "get_user_by_username") - @patch.object(ProjectSearchService, "_get_intersecting_projects") - @patch.object(ProjectInfo, "get_dto_for_locale") - def test_get_intersecting_projects( - self, - get_dto_for_locale, - _get_intersecting_projects, - get_user_by_username, - validate_bbox_area, - _make_4326_polygon_from_bbox, - ): - # arrange _make_4326_polygon_from_bbox mock - _make_4326_polygon_from_bbox.return_value = Polygon( - [ - (34.68826225820438, -12.59912449955007), - (34.68826225820438, -11.57858317689196), - (32.50198296132938, -11.57858317689196), - (32.50198296132938, -12.59912449955007), - (34.68826225820438, -12.59912449955007), - ] - ) - - # arrange validate_bbox_area mock - validate_bbox_area.return_value = True - - # arrange get_user_by_username mock - get_user_by_username.return_value = User(id=3488526) - - # arrange _get_intersecting_projects mock - polygon = json.dumps(get_canned_json("search_bbox_feature.json")) - project = Project(id=2274, status=0, default_locale="en", geometry=polygon) - projects = [project] - _get_intersecting_projects.return_value = projects - - # arrange get_dto_for_locale mock - get_dto_for_locale.return_value = ProjectInfo(name="PEPFAR Kenya: Homa Bay") - - # arrange dto - dto = ProjectSearchBBoxDTO() - dto.bbox = map(float, "34.404,-1.034, 34.717,-0.624".split(",")) - dto.preferred_locale = "en" - dto.input_srid = 4326 - dto.project_author = 3488526 - dto.validate() - - # arrange expected result - expected = json.dumps(get_canned_json("search_bbox_result.json")) - - # act - # result = ProjectSearchService.get_projects_geojson(dto) - - # assert - self.assertEqual(str(expected), str(expected)) - - def test_make_polygon_from_3857_bbox(self): - # arrange - expected = ( - 32.50198296132938, - -12.59912449955007, - 34.68826225820438, - -11.578583176891955, - ) - - # act - polygon = ProjectSearchService._make_4326_polygon_from_bbox( - [ - 3618104.193026841, - -1413969.7644834695, - 3861479.691086842, - -1297785.4814900015, - ], - 3857, - ) - - # assert - for expected_val, actual_val in zip(expected, polygon.bounds): - self.assertAlmostEqual(expected_val, actual_val, places=10) - - def test_get_area_from_3857_bbox(self): - # polygon = ProjectSearchService._make_4326_polygon_from_bbox( - # [3618104.193026841, -1413969.7644834695, 3861479.691086842, -1297785.4814900015], 3857) - polygon = Polygon( - [ - (34.68826225820438, -12.59912449955007), - (34.68826225820438, -11.57858317689196), - (32.50198296132938, -11.57858317689196), - (32.50198296132938, -12.59912449955007), - (34.68826225820438, -12.59912449955007), - ] - ) - - # act - expected = ProjectSearchService._get_area_sqm(polygon) - - # assert - self.assertAlmostEqual(expected, 28276407740.2797, places=3) diff --git a/tests/backend/integration/services/test_project_service.py b/tests/backend/integration/services/test_project_service.py deleted file mode 100644 index 615b532d5c..0000000000 --- a/tests/backend/integration/services/test_project_service.py +++ /dev/null @@ -1,92 +0,0 @@ -from unittest.mock import patch - -from backend.models.postgis.statuses import ProjectStatus, UserRole -from backend.services.project_admin_service import ProjectAdminService -from backend.services.project_service import ProjectService, ProjectServiceError -from backend.services.team_service import TeamService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project, return_canned_user - - -class TestProjectService(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.project_author = create_canned_project() - self.test_mapper = return_canned_user() - self.test_mapper.username = "Test Mapper" - self.test_mapper.id = 11111 - self.test_mapper.create() - - def test_get_project_dto_for_mapper_returns_project_dto(self): - # Arrange - # We need to change project status to published as it's set to draft while creating test project - self.test_project.status = ProjectStatus.PUBLISHED.value - # Act - project_dto = ProjectService.get_project_dto_for_mapper( - self.test_project.id, self.test_mapper.id - ) - # Assert - self.assertIsNotNone(project_dto) - - def test_get_project_dto_for_mapper_raises_error_if_draft_project(self): - # Project status is already set as draft while creating test project so no need to change it's status - # Act/Assert - with self.assertRaises(ProjectServiceError): - ProjectService.get_project_dto_for_mapper( - self.test_project.id, self.test_mapper.id - ) - - def test_get_project_dto_for_mapper_returns_none_if_private_project(self): - # Arrange - # We need to change project status to published as it's set to draft while creating test project - self.test_project.status = ProjectStatus.PUBLISHED.value - self.test_project.private = True - # Act - project_dto = ProjectService.get_project_dto_for_mapper( - self.test_project.id, self.test_mapper.id - ) - # Assert - self.assertIsNone(project_dto) - - def test_get_project_dto_for_mapper_returns_private_and_draft_project_dto_for_adimn( - self, - ): - # Arrange - self.test_mapper.role = UserRole.ADMIN.value - self.test_project.private = True - - # Act - project_dto = ProjectService.get_project_dto_for_mapper( - self.test_project.id, self.test_mapper.id - ) - # Assert - self.assertIsNotNone(project_dto) - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - def test_get_project_dto_for_mapper_returns_private_and_draft_project_dto_for_managers( - self, mock_is_user_manager - ): - # Arrange - self.test_project.private = True - mock_is_user_manager.return_value = True - # Act - project_dto = ProjectService.get_project_dto_for_mapper( - self.test_project.id, self.test_mapper.id - ) - # Assert - self.assertIsNotNone(project_dto) - - @patch.object(TeamService, "check_team_membership") - def test_get_project_dto_for_mapper_returns_private_project_dto_for_project_team_member( - self, mock_is_team_member - ): - # Arrange - self.test_project.private = True - self.test_project.status = ProjectStatus.PUBLISHED.value - mock_is_team_member.return_value = True - # Act - project_dto = ProjectService.get_project_dto_for_mapper( - self.test_project.id, self.test_mapper.id - ) - # Assert - self.assertIsNotNone(project_dto) diff --git a/tests/backend/integration/services/test_recommendation_service.py b/tests/backend/integration/services/test_recommendation_service.py deleted file mode 100644 index 230d3e6ce8..0000000000 --- a/tests/backend/integration/services/test_recommendation_service.py +++ /dev/null @@ -1,207 +0,0 @@ -from unittest.mock import patch - -import pandas as pd - -from backend.models.postgis.project import ProjectStatus -from backend.services.recommendation_service import ProjectRecommendationService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_interest, - create_canned_project, - update_project_with_info, -) - - -class TestProjectRecommendationService(BaseTestCase): - def setUp(self): - super().setUp() - self.service = ProjectRecommendationService() - - def create_project(self, is_published=True): - """Create a canned project""" - project, _ = create_canned_project() - project.status = ( - ProjectStatus.PUBLISHED.value if is_published else ProjectStatus.DRAFT.value - ) - project.save() - return project - - def test_build_encoded_data_frame_returns_encoded_data_frame(self): - """Test that build_encoded_data_frame returns encoded data frame""" - # Arrange - df = pd.DataFrame( - { - "id": [1, 2], - "default_locale": ["en", "ne"], - "difficulty": [1, 2], - "country": [["England"], ["Nepal"]], - "mapping_types": [[1, 2], [2, 3]], - "categories": [[1, 2], [2, 3]], - } - ) - # Since default_locale, difficulty, and country are one-hot encoded with each having 2 unique values, - # and mapping_types and categories are multi-hot encoded with each having 3 unique values, - # the resulting data frame should have 13 columns (2 + 2 + 2 + 3 + 3) + 1 -> the id column - # Act - df = self.service.build_encoded_data_frame(df) - # Assert - self.assertEqual(df.shape, (2, 13)) - self.assertEqual(df["id"].tolist(), [1, 2]) - self.assertEqual(df["default_locale_en"].tolist(), [1, 0]) - self.assertEqual(df["default_locale_ne"].tolist(), [0, 1]) - self.assertEqual(df["difficulty_1"].tolist(), [1, 0]) - self.assertEqual(df["difficulty_2"].tolist(), [0, 1]) - self.assertEqual(df["country_England"].tolist(), [1, 0]) - self.assertEqual(df["country_Nepal"].tolist(), [0, 1]) - self.assertEqual(df["mapping_types_1"].tolist(), [1, 0]) - self.assertEqual(df["mapping_types_2"].tolist(), [1, 1]) - self.assertEqual(df["mapping_types_3"].tolist(), [0, 1]) - self.assertEqual(df["categories_1"].tolist(), [1, 0]) - self.assertEqual(df["categories_2"].tolist(), [1, 1]) - self.assertEqual(df["categories_3"].tolist(), [0, 1]) - - def test_get_similar_project_ids_returns_similar_project_ids(self): - """Test that get_similar_project_ids returns similar project ids""" - # Arrange - df = pd.DataFrame( - { - "id": [1, 2, 3, 4, 5], - "default_locale": ["en", "en", "ne", "ne", "ne"], - "difficulty": [1, 1, 1, 2, 2], - "country": [ - ["England"], - ["England"], - ["Nepal"], - ["Nepal"], - ["England"], - ], - "mapping_types": [[1, 2], [1, 2], [1, 2], [2, 3], [2, 3]], - "categories": [[1, 2], [1, 2], [2, 3], [2, 3], [2, 3]], - } - ) - df = self.service.build_encoded_data_frame(df) - # Act - similar_project_ids = self.service.get_similar_project_ids( - df, df[df["id"] == 1] - ) - # Assert - self.assertEqual( - similar_project_ids[0], 2 - ) # project id 2 is the most similar to project id 1 - self.assertEqual( - similar_project_ids[1], 3 - ) # project id 1 is the second most similar to project id 1 - self.assertEqual( - similar_project_ids[2], 5 - ) # project id 5 is the third most similar to project id 1 - - @staticmethod - def set_project_columns(project, **kwargs): - """Set project columns""" - for key, value in kwargs.items(): - setattr(project, key, value) - project.save() - - def test_create_project_matrix_returns_project_matrix(self): - """Test that create_project_matrix returns project matrix""" - # Arrange - test_interest_1 = create_canned_interest("test-interest-1") - test_interest_2 = create_canned_interest("test-interest-2") - - project_1 = self.create_project() - project_2 = self.create_project() - self.create_project(is_published=False) # project_3 - TestProjectRecommendationService.set_project_columns( - project_1, - default_locale="en", - difficulty=1, - country=["England"], - mapping_types=[1, 2], - interests=[test_interest_1, test_interest_2], - ) - TestProjectRecommendationService.set_project_columns( - project_2, - default_locale="ne", - difficulty=2, - country=["Nepal"], - mapping_types=[2], - interests=[test_interest_2], - ) - # Act - project_matrix = self.service.create_project_matrix(project_1.id) - # Assert - # Since default_locale, difficulty, and country are one-hot encoded with each having 2 unique values, - # and mapping_types and categories are multi-hot encoded with each having 2 unique values, - # the resulting data frame should have 11 columns (2 + 2 + 2 + 2 + 2) + 1 -> the id column - self.assertEqual(project_matrix.shape, (2, 11)) - # Since project_3 is not published, it should not be included in the project matrix - self.assertEqual(project_matrix["id"].tolist(), [project_1.id, project_2.id]) - self.assertEqual(project_matrix["default_locale_en"].tolist(), [1, 0]) - self.assertEqual(project_matrix["default_locale_ne"].tolist(), [0, 1]) - self.assertEqual(project_matrix["difficulty_1"].tolist(), [1, 0]) - self.assertEqual(project_matrix["difficulty_2"].tolist(), [0, 1]) - self.assertEqual(project_matrix["country_England"].tolist(), [1, 0]) - self.assertEqual(project_matrix["country_Nepal"].tolist(), [0, 1]) - self.assertEqual(project_matrix["mapping_types_1"].tolist(), [1, 0]) - self.assertEqual(project_matrix["mapping_types_2"].tolist(), [1, 1]) - self.assertEqual(project_matrix["categories_1"].tolist(), [1, 0]) - self.assertEqual(project_matrix["categories_2"].tolist(), [1, 1]) - - @patch.object(ProjectRecommendationService, "get_similar_project_ids") - def test_get_similar_projects_returns_similar_projects( - self, mock_get_similar_project_ids - ): - """Test that get_similar_projects returns similar projects""" - # Arrange - # Create test interests - test_interest_1 = create_canned_interest("test-interest-1") - test_interest_2 = create_canned_interest("test-interest-2") - # Create test projects - project_1 = self.create_project() - project_2 = self.create_project() - project_3 = self.create_project() - # Create draft project so that it is not included in the similar projects - self.create_project(is_published=False) - - # Since project_info is required to retrun project summary in the response - update_project_with_info(project_1) - update_project_with_info(project_2) - update_project_with_info(project_3) - - # Set mock return value for get_similar_project_ids - mock_get_similar_project_ids.return_value = [project_2.id, project_3.id] - - # Set different values for columns to be used in the project matrix for similarity calculation - TestProjectRecommendationService.set_project_columns( - project_1, - default_locale="en", - difficulty=1, - country=["England"], - mapping_types=[1, 2], - interests=[test_interest_1, test_interest_2], - ) - TestProjectRecommendationService.set_project_columns( - project_2, - default_locale="en", - difficulty=1, - country=["Nepal"], - mapping_types=[2], - interests=[test_interest_2], - ) - TestProjectRecommendationService.set_project_columns( - project_3, - default_locale="en", - difficulty=2, - country=["Nepal"], - mapping_types=[2], - interests=[test_interest_2], - ) - - # Act - similar_projects = self.service.get_similar_projects(project_1.id) - # Assert - self.assertEqual(len(similar_projects.results), 2) - self.assertEqual( - similar_projects.results[0].project_id, project_2.id - ) # project_2 is the most similar to project_1 - self.assertEqual(similar_projects.results[1].project_id, project_3.id) diff --git a/tests/backend/integration/services/test_stats_service.py b/tests/backend/integration/services/test_stats_service.py deleted file mode 100644 index 3fda3ee80b..0000000000 --- a/tests/backend/integration/services/test_stats_service.py +++ /dev/null @@ -1,19 +0,0 @@ -from backend.services.stats_service import StatsService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - - -class TestStatsService(BaseTestCase): - def setUp(self): - super().setUp() - - self.test_project, self.test_user = create_canned_project() - - def test_homepage_stats_returns_results(self): - # Act - stats = StatsService.get_homepage_stats() - - # Assert - self.assertGreaterEqual(stats.mappers_online, 0) - self.assertGreater(stats.tasks_mapped, 0) - self.assertGreater(stats.total_mappers, 0) diff --git a/tests/backend/integration/services/test_team_service.py b/tests/backend/integration/services/test_team_service.py deleted file mode 100644 index 765cc1fad7..0000000000 --- a/tests/backend/integration/services/test_team_service.py +++ /dev/null @@ -1,144 +0,0 @@ -from unittest.mock import patch - -from backend.models.postgis.statuses import ( - TeamJoinMethod, - TeamMemberFunctions, - TeamRoles, -) -from backend.services.team_service import MessageService, TeamService, TeamServiceError -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - add_user_to_team, - assign_team_to_project, - create_canned_project, - create_canned_team, - create_canned_user, - return_canned_user, -) - - -class TestTeamService(BaseTestCase): - def setUp(self): - super().setUp() - self.test_team = create_canned_team() - - def test_check_team_membership_returns_true_if_user_member_of_team_with_allowed_role( - self, - ): - # Arrange - test_project, test_user = create_canned_project() - allowed_roles = [TeamRoles.PROJECT_MANAGER.value] - assign_team_to_project(test_project, self.test_team, allowed_roles[0]) - add_user_to_team( - self.test_team, test_user, TeamMemberFunctions.MEMBER.value, is_active=True - ) - # Act - is_team_member = TeamService.check_team_membership( - test_project.id, allowed_roles, test_user.id - ) - # Assert - self.assertTrue(is_team_member) - - def test_check_team_membership_returns_false_if_user_member_of_team_with_unallowed_role( - self, - ): - # Arrange - test_project, test_user = create_canned_project() - allowed_roles = [TeamRoles.PROJECT_MANAGER.value] - assign_team_to_project(test_project, self.test_team, TeamRoles.MAPPER.value) - # Act - is_team_member = TeamService.check_team_membership( - test_project.id, allowed_roles, test_user.id - ) - # Assert - self.assertFalse(is_team_member) - - def test_check_team_membership_returns_false_if_user_member_of_team_not_assigned_to_project( - self, - ): - # Arrange - test_project, test_user = create_canned_project() - allowed_roles = [TeamRoles.PROJECT_MANAGER.value] - add_user_to_team( - self.test_team, test_user, TeamMemberFunctions.MEMBER.value, is_active=True - ) - # Act - is_team_member = TeamService.check_team_membership( - test_project.id, allowed_roles, test_user.id - ) - # Assert - self.assertFalse(is_team_member) - - def test_check_team_membership_returns_false_if_user_not_active_team_member(self): - # Arrange - test_project, test_user = create_canned_project() - allowed_roles = [TeamRoles.PROJECT_MANAGER.value] - add_user_to_team( - self.test_team, test_user, TeamMemberFunctions.MEMBER.value, is_active=False - ) - assign_team_to_project(test_project, self.test_team, TeamRoles.MAPPER.value) - # Act - is_team_member = TeamService.check_team_membership( - test_project.id, allowed_roles, test_user.id - ) - # Assert - self.assertFalse(is_team_member) - - def test_get_project_teams_as_dto(self): - # Arrange - test_project, _test_user = create_canned_project() - assign_team_to_project(test_project, self.test_team, TeamRoles.MAPPER.value) - # Act - teams_dto = TeamService.get_project_teams_as_dto(test_project.id) - # Assert - self.assertIn("teams", teams_dto) - self.assertNotEqual(len(teams_dto["teams"]), 0) - - @patch.object(TeamService, "is_user_team_member") - def test_request_to_join_team_raises_error_if_user_already_team_member( - self, mock_is_team_member - ): - # Arrange - test_user = create_canned_user() - add_user_to_team( - self.test_team, test_user, TeamMemberFunctions.MEMBER.value, True - ) - mock_is_team_member.return_value = True - # Act/Assert - with self.assertRaises(TeamServiceError): - TeamService.request_to_join_team(self.test_team.id, test_user.id) - - @patch.object(TeamService, "is_user_team_member") - @patch.object(MessageService, "_push_messages") - def test_request_to_join_team_sends_notification_if_team_is_by_request_and_manager_has_allowed_notification( - self, mock_send_notification, mock_is_team_member - ): - # Arrange - self.test_team.join_method = TeamJoinMethod.BY_REQUEST.value - test_user = create_canned_user() - mock_is_team_member.return_value = False - test_manager = return_canned_user("test manager", 1234) - test_manager = add_user_to_team(self.test_team, test_manager, 1, True) - test_manager.join_request_notifications = True - - # Act - TeamService.request_to_join_team(self.test_team.id, test_user.id) - # Assert - mock_send_notification.assert_called() - - @patch.object(TeamService, "is_user_team_member") - @patch.object(MessageService, "_push_messages") - def test_request_to_join_team_doesnt_send_notification_if_manager_has_disallowed_notification( - self, mock_send_notification, mock_is_team_member - ): - # Arrange - self.test_team.join_method = TeamJoinMethod.BY_REQUEST.value - test_user = create_canned_user() - mock_is_team_member.return_value = False - test_manager = return_canned_user("test manager", 1234) - test_manager = add_user_to_team(self.test_team, test_manager, 1, True) - test_manager.join_request_notifications = False - # Act - TeamService.request_to_join_team(self.test_team.id, test_user.id) - # Assert - mock_send_notification.assert_not_called() diff --git a/tests/backend/integration/services/test_validation_service.py b/tests/backend/integration/services/test_validation_service.py deleted file mode 100644 index 9bc0a81533..0000000000 --- a/tests/backend/integration/services/test_validation_service.py +++ /dev/null @@ -1,138 +0,0 @@ -from backend.models.dtos.validator_dto import RevertUserTasksDTO -from backend.services.validator_service import ( - Task, - TaskStatus, - ValidatorService, - ValidatorServiceError, -) -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project, return_canned_user - - -class TestValidationService(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user(username="test_user", id=123456789) - self.test_user.create() - self.test_project, self.test_author = create_canned_project() - - def test_validate_all_sets_counters_correctly(self): - # Arrange - total_mapped_tasks = self.test_project.tasks_mapped - total_validated_tasks = self.test_project.tasks_validated - # Act - ValidatorService.validate_all_tasks(self.test_project.id, self.test_user.id) - # Assert - self.assertEqual( - self.test_project.tasks_validated, - total_mapped_tasks + total_validated_tasks, - ) - self.assertEqual(self.test_project.tasks_mapped, 0) - - def test_invalidate_all_sets_counters_correctly(self): - # Arrange - mapped_tasks = self.test_project.tasks_mapped - - # Act - ValidatorService.invalidate_all_tasks(self.test_project.id, self.test_user.id) - - # Assert - self.assertEqual(mapped_tasks, self.test_project.tasks_mapped) - self.assertEqual(0, self.test_project.tasks_validated) - - def test_mapped_by_and_validated_by_are_null_after_invalidating_all(self): - ValidatorService.validate_all_tasks(self.test_project.id, self.test_user.id) - ValidatorService.invalidate_all_tasks(self.test_project.id, self.test_user.id) - - for task in self.test_project.tasks: - # Only check for validated tasks as there is one task is set as bad imagery while creating test_project - if task.task_status == TaskStatus.VALIDATED.value: - self.assertIsNone(task.mapped_by) - self.assertIsNone(task.validated_by) - - def test_mapped_by_and_validated_by_is_set_after_validating_all(self): - tasks_to_validate = Task.query.filter( - Task.project_id == self.test_project.id, - Task.task_status == TaskStatus.MAPPED.value, - ).all() - ValidatorService.validate_all_tasks(self.test_project.id, self.test_user.id) - for task in tasks_to_validate: - self.assertIsNotNone(task.mapped_by) - self.assertEqual(task.validated_by, self.test_user.id) - - def test_revert_user_tasks_requires_user_with_PM_permission_for_successful_operation( - self, - ): - # Arrange - revert_dto = RevertUserTasksDTO() - revert_dto.project_id = self.test_project.id - revert_dto.user_id = self.test_user.id - revert_dto.action_by = self.test_user.id - revert_dto.action = "VALIDATED" - # Act/Assert - with self.assertRaises(ValidatorServiceError): - ValidatorService.revert_user_tasks(revert_dto) - - def test_revert_user_tasks_revert_validated_task_to_mapped_status(self): - """ - Lets test this funtion for two tasks one by test_user and other by test_author. - so that we can test if the task validated by test_user is reverted to mapped status - and task validated by test_author is not reverted to mapped status - """ - # Arrange - task_1 = Task.get(1, self.test_project.id) - task_2 = Task.get(2, self.test_project.id) - # Lock the task for mapping - task_1.lock_task_for_mapping(self.test_user.id) - task_2.lock_task_for_mapping(self.test_author.id) - # Unlock the task - task_1.unlock_task(self.test_user.id, new_state=TaskStatus.MAPPED) - task_2.unlock_task(self.test_author.id, new_state=TaskStatus.MAPPED) - # Lock the task for validation - task_1.lock_task_for_validating(self.test_user.id) - task_2.lock_task_for_validating(self.test_author.id) - # Unlock the task - task_1.unlock_task(self.test_user.id, new_state=TaskStatus.VALIDATED) - task_2.unlock_task(self.test_author.id, new_state=TaskStatus.VALIDATED) - # Create DTO - revert_dto = RevertUserTasksDTO() - revert_dto.project_id = self.test_project.id - revert_dto.user_id = self.test_user.id - revert_dto.action_by = self.test_author.id - revert_dto.action = "VALIDATED" - # Act - ValidatorService.revert_user_tasks(revert_dto) - # Assert - # Check that the task is now mapped - self.assertEqual(task_1.task_status, TaskStatus.MAPPED.value) - # task_2 is validated by test_author so it should not be reverted to mapped status - self.assertEqual(task_2.task_status, TaskStatus.VALIDATED.value) - - def test_revert_user_tasks_reverts_bad_imagery_tasks_to_ready(self): - """ - Lets test this funtion for two tasks one by test_user and other by test_author. - so that we can test if the task set as bad imagery by test_user is reverted to ready status - and task set as bad imagery by test_author is not reverted to ready status - """ - # Arrange - task_1 = Task.get(1, self.test_project.id) - task_2 = Task.get(2, self.test_project.id) - # Lock the task for mapping - task_1.lock_task_for_mapping(self.test_user.id) - task_2.lock_task_for_mapping(self.test_author.id) - # Unlock the task - task_1.unlock_task(self.test_user.id, new_state=TaskStatus.BADIMAGERY) - task_2.unlock_task(self.test_author.id, new_state=TaskStatus.BADIMAGERY) - # Create DTO - revert_dto = RevertUserTasksDTO() - revert_dto.project_id = self.test_project.id - revert_dto.user_id = self.test_user.id - revert_dto.action_by = self.test_author.id - revert_dto.action = "BADIMAGERY" - # Act - ValidatorService.revert_user_tasks(revert_dto) - # Assert - # Check that the task is now ready - self.assertEqual(task_1.task_status, TaskStatus.READY.value) - # task_2 is set as bad imagery by test_author so it should not be reverted to ready status - self.assertEqual(task_2.task_status, TaskStatus.BADIMAGERY.value) diff --git a/tests/backend/integration/services/users/__init__.py b/tests/backend/integration/services/users/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/integration/services/users/test_authentication_service.py b/tests/backend/integration/services/users/test_authentication_service.py deleted file mode 100644 index 9ddff09914..0000000000 --- a/tests/backend/integration/services/users/test_authentication_service.py +++ /dev/null @@ -1,172 +0,0 @@ -import base64 -from unittest.mock import patch -from urllib.parse import parse_qs, urlparse - -from flask import current_app -from itsdangerous import URLSafeTimedSerializer - -from backend.services.messaging.smtp_service import SMTPService -from backend.services.users.authentication_service import ( - AuthenticationService, - AuthServiceError, - MessageService, - NotFound, - UserService, - verify_token, -) -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - TEST_USERNAME, - get_canned_osm_user_details, - return_canned_user, -) - -TEST_USER_EMAIL = "thinkwheretest@test.com" - - -class TestAuthenticationService(BaseTestCase): - def test_verify_token_verifies_user_session_token(self): - # Arrange - token = AuthenticationService.generate_session_token_for_user(12345678) - token = base64.b64encode(token.encode("utf-8")) - token = token.decode("utf-8") - - # Act/Assert - self.assertEqual(12345678, verify_token(token)) - self.assertFalse(verify_token(None)) - - def test_unable_to_find_user_in_osm_response_raises_error(self): - # Arrange - osm_response = get_canned_osm_user_details() - - # Act / Assert - with self.assertRaises(AuthServiceError): - AuthenticationService().login_user(osm_response, None, "wont-find") - - @patch.object(MessageService, "send_welcome_message") - @patch.object(UserService, "register_user") - @patch.object(UserService, "get_user_by_id") - def test_if_login_user_calls_user_create_if_user_not_found( - self, mock_user_get, mock_user_register, mock_message - ): - # Arrange - osm_response = get_canned_osm_user_details() - mock_user_get.side_effect = NotFound() - - # Act - AuthenticationService.login_user(osm_response, None) - - # Assert - mock_user_register.assert_called_with(7777777, TEST_USERNAME, 16, None, None) - - @patch.object(MessageService, "send_welcome_message") - @patch.object(UserService, "register_user") - @patch.object(UserService, "get_user_by_id") - def test_if_login_user_calls_send_welcome_if_user_not_found( - self, mock_user_get, mock_user_register, mock_message - ): - # Arrange - osm_response = get_canned_osm_user_details() - mock_user_get.side_effect = NotFound() - new_user = return_canned_user() - mock_user_register.return_value = new_user - - # Act - AuthenticationService.login_user(osm_response, None) - - # Assert - mock_message.assert_called_with(new_user) - - @patch.object(UserService, "update_user") - @patch.object(UserService, "get_user_by_id") - def test_if_login_user_calls_user_update_if_user_found( - self, mock_user_get, mock_user_update - ): - # Arrange - osm_response = get_canned_osm_user_details() - osm_response["user"]["id"] = 12345678 - osm_response["user"]["display_name"] = "Thinkwhere Test2" - - # Act - AuthenticationService.login_user(osm_response, None) - - # Assert - mock_user_update.assert_called_with(12345678, "Thinkwhere Test2", None) - - @patch.object(UserService, "get_user_by_id") - def test_if_login_user_returns_all_required_params(self, mock_user_get): - # Arrange - osm_response = get_canned_osm_user_details() - - # Act - user_params = AuthenticationService.login_user(osm_response, None) - - # Assert - self.assertIsNotNone(user_params.get("username")) - self.assertIsNotNone(user_params.get("session_token")) - self.assertIn("picture", user_params) - - @patch.object(UserService, "get_user_by_username") - def test_authenticate_email_token_raises_error_when_unable_to_find_user( - self, mock_user_get - ): - # Arrange - mock_user_get.side_effect = NotFound - email_auth_url = SMTPService._generate_email_verification_url( - TEST_USER_EMAIL, TEST_USERNAME - ) - parsed_url = urlparse(email_auth_url) - token = parse_qs(parsed_url.query)["token"][0] - # Act/Assert - with self.assertRaises(NotFound): - AuthenticationService().authenticate_email_token( - username=TEST_USERNAME, - token=token, - ) - - def test_authenticate_email_token_raises_error_when_invalid_token_supplied(self): - # Arrange - test_user = return_canned_user(TEST_USERNAME) - test_user.create() - # Act/Assert - with self.assertRaises(AuthServiceError): - AuthenticationService().authenticate_email_token( - username=TEST_USERNAME, - # Invalid Token - token="XnRoaW5rd2hlcmV0ZXN0QHRlc3QuY29tIg.YnIWEw.9yg8kxVJXDD6dxxIktYGgnCrZNE", - ) - - @patch.object(UserService, "get_user_by_username") - def test_authenticate_email_token_returns_email_validated_url(self, mock_user_get): - # Arrange - mock_user_get.return_value = return_canned_user() - mock_user_get.return_value.email_address = TEST_USER_EMAIL - entropy = current_app.secret_key if current_app.secret_key else "un1testingmode" - - serializer = URLSafeTimedSerializer(entropy) - - # Act/Assert - self.assertIsNotNone( - AuthenticationService().authenticate_email_token( - username=TEST_USERNAME, - token=serializer.dumps(TEST_USER_EMAIL), - ) - ) - - @patch.object(UserService, "get_user_by_username") - def test_authenticate_email_token_raises_error_if_email_not_matched( - self, mock_user_get - ): - # Arrange - mock_user_get.return_value = return_canned_user() - mock_user_get.return_value.email_address = "thinkwheretest2@test.com" - entropy = current_app.secret_key if current_app.secret_key else "un1testingmode" - - serializer = URLSafeTimedSerializer(entropy) - - # Act/Assert - with self.assertRaises(AuthServiceError): - AuthenticationService().authenticate_email_token( - username=TEST_USERNAME, - token=serializer.dumps(TEST_USER_EMAIL), - ) diff --git a/tests/backend/integration/services/users/test_osm_service.py b/tests/backend/integration/services/users/test_osm_service.py deleted file mode 100644 index 17aa93e64a..0000000000 --- a/tests/backend/integration/services/users/test_osm_service.py +++ /dev/null @@ -1,31 +0,0 @@ -from backend.services.users.osm_service import OSMService, OSMServiceError -from tests.backend.base import BaseTestCase - - -class TestOsmService(BaseTestCase): - def test_get_osm_details_for_user_raises_error_if_invalid_user_id(self): - # Act/Assert - with self.assertRaises(OSMServiceError): - OSMService.get_osm_details_for_user("1xcf") - - def test_get_osm_details_for_user_returns_user_details_if_valid_user_id(self): - # Act - dto = OSMService.get_osm_details_for_user(13526430) - # Assert - self.assertEqual(dto.account_created, "2021-06-10T01:27:18Z") - - def test_is_user_deleted(self): - self.assertTrue(OSMService.is_osm_user_gone(535043)) - self.assertFalse(OSMService.is_osm_user_gone(2078753)) - - def test_get_deleted_users(self): - # These are the first 10 deleted users on 2024-04-16. This should ensure that the test finishes quickly. - # Otherwise, it can take 6s+ (dependent upon network speed) - deleted_users = [4, 142, 593, 601, 1769, 2161, 2238, 2782, 2868] - generator = OSMService.get_deleted_users() - for deleted_user in generator: - if deleted_user in deleted_users: - deleted_users.remove(deleted_user) - if len(deleted_users) == 0: - break - self.assertEquals(0, len(deleted_users)) diff --git a/tests/backend/integration/services/users/test_user_service.py b/tests/backend/integration/services/users/test_user_service.py deleted file mode 100644 index f194b87d15..0000000000 --- a/tests/backend/integration/services/users/test_user_service.py +++ /dev/null @@ -1,164 +0,0 @@ -from unittest.mock import patch - -from backend.models.postgis.message import Message -from backend.models.postgis.statuses import UserRole, UserGender -from backend.services.users.user_service import ( - MappingLevel, - OSMService, - User, - UserOSMDTO, - UserService, -) -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_project, - create_canned_user, - get_canned_user, - return_canned_user, -) - - -class TestUserService(BaseTestCase): - def test_upsert_inserts_project_if_not_exists(self): - self.test_project, self.test_user = create_canned_project() - # Arrange - UserService.upsert_mapped_projects(self.test_user.id, self.test_project.id) - - # Act - projects = UserService.get_mapped_projects(self.test_user.username, "en") - - # Assert - mapped_project = projects.mapped_projects[0] - self.assertEqual( - mapped_project.project_id, self.test_project.id - ) # We should find we've mapped the test project - - def test_set_level_adds_level_to_user(self): - self.test_user = get_canned_user("Thinkwhere TEST") - if self.test_user is None: - self.test_user = create_canned_user() - - # Act - user = UserService.set_user_mapping_level( - self.test_user.username, MappingLevel.ADVANCED.name - ) - - # Assert - self.assertEqual(MappingLevel(user.mapping_level), MappingLevel.ADVANCED) - - @patch.object(User, "create") - def test_user_can_register_with_correct_mapping_level(self, mock_user): - # Act - test_user = UserService().register_user( - 12, "Thinkwhere", 300, "some_picture_url", None - ) - - # Assert - self.assertEqual(test_user.mapping_level, MappingLevel.INTERMEDIATE.value) - - @patch.object(Message, "save") - @patch.object(User, "save") - @patch.object(OSMService, "get_osm_details_for_user") - @patch.object(UserService, "get_user_by_id") - def test_mapper_level_updates_correctly( - self, mock_user, mock_osm, mock_save, mock_message - ): - # Arrange - test_user = User() - test_user.username = "Test User" - test_user.mapping_level = MappingLevel.BEGINNER.value - mock_user.return_value = test_user - - test_osm = UserOSMDTO() - test_osm.changeset_count = 350 - mock_osm.return_value = test_osm - - # Act - UserService.check_and_update_mapper_level(12) - - # Assert - self.assertTrue(test_user.mapping_level, MappingLevel.INTERMEDIATE.value) - - def test_update_user_updates_user_details(self): - # Arrange - create_canned_user() - # Act - UserService.update_user(777777, "Thinkwhere", None) - # Assert - user = UserService.get_user_by_id(777777) - self.assertEqual(user.username, "Thinkwhere") - - def test_register_user_creates_new_user(self): - # Arrange - test_user = return_canned_user() - # Act - UserService.register_user(test_user.id, test_user.username, 251, None, None) - # Arrange - expected_user = UserService.get_user_by_id(777777) - # Assert - self.assertEqual(expected_user.username, test_user.username) - self.assertEqual(expected_user.mapping_level, MappingLevel.INTERMEDIATE.value) - - @staticmethod - def add_user_identifying_information(user: User) -> User: - user.username = "Test User" - user.email_address = "test@example.com" - user.twitter_id = "@Test" - user.facebook_id = "@FBTest" - user.linkedin_id = "@LinkedIn" - user.slack_id = "@Slack" - user.skype_id = "@Skype" - user.irc_id = "IRC" - user.name = "Some name here" - user.city = "Some city" - user.country = "Some country" - user.picture_url = "https://test.com/path/to/picture.png" - user.gender = UserGender.MALE.value - user.self_description_gender = "I am male" - user.default_editor = "ID" - user.save() - return user - - def check_user_details_deleted(self, user: User, deleted: bool): - if deleted: - check = self.assertIsNone - self.assertNotEquals(UserRole.ADMIN.value, user.role) - self.assertEqual(f"user_{user.id}", user.username) - else: - self.assertNotEquals(f"user_{user.id}", user.username) - check = self.assertIsNotNone - check(user.email_address) - check(user.twitter_id) - check(user.facebook_id) - check(user.linkedin_id) - check(user.slack_id) - check(user.skype_id) - check(user.irc_id) - check(user.name) - check(user.city) - check(user.country) - check(user.picture_url) - check(user.gender) - check(user.self_description_gender) - self.assertEqual([], user.accepted_licenses) - self.assertEqual([], user.interests) - - def test_delete_user_same_user(self): - test_user = self.add_user_identifying_information(create_canned_user()) - UserService.delete_user_by_id(test_user.id, test_user.id) - self.check_user_details_deleted(User().get_by_id(test_user.id), deleted=True) - - def test_delete_user_different_user(self): - test_user = self.add_user_identifying_information(create_canned_user()) - other_user = return_canned_user("someone", test_user.id + 1) - other_user.create() - UserService.delete_user_by_id(test_user.id, other_user.id) - self.check_user_details_deleted(User().get_by_id(test_user.id), deleted=False) - - def test_delete_user_different_admin_user(self): - test_user = self.add_user_identifying_information(create_canned_user()) - other_user = return_canned_user("someone", test_user.id + 1) - other_user.set_user_role(UserRole.ADMIN) - other_user.create() - UserService.delete_user_by_id(test_user.id, other_user.id) - self.check_user_details_deleted(User().get_by_id(test_user.id), deleted=True) diff --git a/tests/backend/unit/__init__.py b/tests/backend/unit/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/unit/models/__init__.py b/tests/backend/unit/models/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/unit/models/dtos/__init__.py b/tests/backend/unit/models/dtos/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/unit/models/dtos/test_mapping_dto.py b/tests/backend/unit/models/dtos/test_mapping_dto.py deleted file mode 100644 index 0df920e66f..0000000000 --- a/tests/backend/unit/models/dtos/test_mapping_dto.py +++ /dev/null @@ -1,28 +0,0 @@ -from schematics.exceptions import DataError - -from backend.models.dtos.mapping_dto import MappedTaskDTO -from backend.models.postgis.statuses import TaskStatus -from tests.backend.base import BaseTestCase - - -class TestMappingDTO(BaseTestCase): - def test_mapped_task_with_validated_status_is_invalid(self): - mapped_task = MappedTaskDTO() - mapped_task.task_id = 1 - mapped_task.project_id = 1 - mapped_task.status = TaskStatus.VALIDATED.name - - # Act / Assert - with self.assertRaises(DataError): - mapped_task.validate() - - def test_mapped_task_with_unknown_status_raises_error(self): - # Arrange - mapped_task = MappedTaskDTO() - mapped_task.task_id = 1 - mapped_task.project_id = 1 - mapped_task.status = "IAIN" - - # Act / Assert - with self.assertRaises(DataError): - mapped_task.validate() diff --git a/tests/backend/unit/models/dtos/test_project_dto.py b/tests/backend/unit/models/dtos/test_project_dto.py deleted file mode 100644 index d859359144..0000000000 --- a/tests/backend/unit/models/dtos/test_project_dto.py +++ /dev/null @@ -1,14 +0,0 @@ -from schematics.exceptions import DataError - -from backend.models.dtos.project_dto import ProjectDTO -from tests.backend.base import BaseTestCase - - -class TestProjectDTO(BaseTestCase): - def test_project_with_unknown_mapping_type_is_invalid(self): - project_dto = ProjectDTO() - project_dto.mapping_types = ["BAD", "DATA"] - - # Act / Assert - with self.assertRaises(DataError): - project_dto.validate() diff --git a/tests/backend/unit/models/postgis/__init__.py b/tests/backend/unit/models/postgis/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/unit/models/postgis/test_banner.py b/tests/backend/unit/models/postgis/test_banner.py deleted file mode 100644 index 1278b86af5..0000000000 --- a/tests/backend/unit/models/postgis/test_banner.py +++ /dev/null @@ -1,85 +0,0 @@ -from unittest.mock import patch - -from backend.models.dtos.banner_dto import BannerDTO -from backend.models.postgis.banner import Banner -from tests.backend.base import BaseTestCase - - -class TestBanner(BaseTestCase): - def setUp(self): - super().setUp() - self.message = "Test message" - self.visible = True - - def create_banner(self): - banner = Banner() - banner.message = self.message - banner.visible = self.visible - - banner.create() - - def test_create_banner(self): - # Arrange - self.create_banner() - # Act - banner = Banner.get() - # Assert - self.assertIsNotNone(banner) - self.assertEqual(banner.message, self.message) - self.assertTrue(banner.visible) - - @patch.object(Banner, "query") - def test_get_banner_creates_one_if_none(self, mock_query): - # Arrange - mock_query.first.return_value = None - # Act - banner = Banner.get() - # Assert - self.assertIsNotNone(banner) - self.assertEqual(banner.message, "Welcome to the API") - self.assertTrue(banner.visible) - - def test_update_banner(self): - # Arrange - self.create_banner() - - banner_1 = Banner.get() - banner_1.message = "Updated message" - # Act - banner_1.update() - # Assert - banner_2 = Banner.get() - self.assertEqual(banner_1.message, banner_2.message) - - def test_update_banner_from_dto(self): - # Arrange - self.create_banner() - # Act - banner = Banner.get() - banner_dto = BannerDTO() - banner_dto.message = "Updated message" - banner_dto.visible = False - banner.update_from_dto(banner_dto) - # Assert - banner = Banner.get() - self.assertEqual(banner.message, banner_dto.message) - self.assertFalse(banner.visible) - - def test_as_dto(self): - # Arrange - self.create_banner() - # Act - banner = Banner.get() - banner_dto = banner.as_dto() - # Assert - self.assertEqual(banner_dto.message, self.message) - self.assertTrue(banner_dto.visible) - - def test_to_html(self): - # Arrange - self.create_banner() - # Act - banner = Banner.get() - html = banner.to_html(f"### {self.message}") - # Assert - self.assertEqual(html, f"

{self.message}

") diff --git a/tests/backend/unit/models/postgis/test_custom_editor.py b/tests/backend/unit/models/postgis/test_custom_editor.py deleted file mode 100644 index 1ef317a334..0000000000 --- a/tests/backend/unit/models/postgis/test_custom_editor.py +++ /dev/null @@ -1,93 +0,0 @@ -from backend.models.postgis.custom_editors import CustomEditor, CustomEditorDTO -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - - -class TestCustomEditor(BaseTestCase): - def setUp(self): - super().setUp() - self.test_project, self.author_id = create_canned_project() - self.custom_editor = CustomEditor() - self.custom_editor.name = "Test custom editor" - self.custom_editor.description = "Test descrption" - self.custom_editor.url = "Test URL" - self.test_project.custom_editor = self.custom_editor - self.custom_editor.create() - - def test_get_by_project_id(self): - # Act - custom_editor = CustomEditor.get_by_project_id(self.test_project.id) - - # Assert - self.assertEqual(custom_editor.project_id, self.test_project.id) - self.assertEqual(custom_editor.name, self.custom_editor.name) - self.assertEqual(custom_editor.description, self.custom_editor.description) - self.assertEqual(custom_editor.url, self.custom_editor.url) - - def test_create_from_dto(self): - # Arrange - self.custom_editor.delete() - custom_editor_dto = CustomEditorDTO() - custom_editor_dto.name = self.custom_editor.name - custom_editor_dto.description = self.custom_editor.description - custom_editor_dto.url = self.custom_editor.url - - # Act - custom_editor = CustomEditor.create_from_dto( - self.test_project.id, custom_editor_dto - ) - - # Assert - self.assertEqual(custom_editor.project_id, self.test_project.id) - self.assertEqual(custom_editor.name, self.custom_editor.name) - self.assertEqual(custom_editor.description, self.custom_editor.description) - self.assertEqual(custom_editor.url, self.custom_editor.url) - - def test_update_editor(self): - # Arrange - self.test_project.custom_editor = self.custom_editor - custom_editor_dto = CustomEditorDTO() - custom_editor_dto.name = "Updated Name" - custom_editor_dto.description = "Updated Description" - custom_editor_dto.url = "Updated URL" - - # Act - self.custom_editor.update_editor(custom_editor_dto) - - # Assert - self.assertEqual(self.custom_editor.project_id, self.test_project.id) - self.assertEqual(self.custom_editor.name, custom_editor_dto.name) - self.assertEqual(self.custom_editor.description, custom_editor_dto.description) - self.assertEqual(self.custom_editor.url, custom_editor_dto.url) - - def test_delete(self): - # Act - self.custom_editor.delete() - - # Assert - custom_editor = CustomEditor.get_by_project_id(self.test_project.id) - self.assertIsNone(custom_editor) - - def test_as_dto(self): - # Act - custom_editor_dto = self.custom_editor.as_dto() - - # Assert - self.assertIsInstance(custom_editor_dto, CustomEditorDTO) - self.assertEqual(self.custom_editor.project_id, self.test_project.id) - self.assertEqual(self.custom_editor.name, custom_editor_dto.name) - self.assertEqual(self.custom_editor.description, custom_editor_dto.description) - self.assertEqual(self.custom_editor.url, custom_editor_dto.url) - - def test_clone_to_project(self): - # Act - test_new_project_id = 123456 - cloned_custom_editor = self.custom_editor.clone_to_project(test_new_project_id) - - # Assert - self.assertEqual(test_new_project_id, cloned_custom_editor.project_id) - self.assertEqual(self.custom_editor.name, cloned_custom_editor.name) - self.assertEqual( - self.custom_editor.description, cloned_custom_editor.description - ) - self.assertEqual(self.custom_editor.url, cloned_custom_editor.url) diff --git a/tests/backend/unit/models/postgis/test_message.py b/tests/backend/unit/models/postgis/test_message.py deleted file mode 100644 index 508bc6c0b9..0000000000 --- a/tests/backend/unit/models/postgis/test_message.py +++ /dev/null @@ -1,127 +0,0 @@ -from backend.models.postgis.message import Message, MessageType, NotFound -from backend.services.messaging.message_service import MessageService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import return_canned_user - -TEST_USERNAME = "test_user" -TEST_USER_ID = 1 - - -class TestMessage(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = return_canned_user(TEST_USERNAME, TEST_USER_ID) - self.test_user.create() - - def send_multiple_welcome_messages(self, number_of_messages: int): - """Sends multiple welcome messages""" - message_ids = [] - for _ in range(number_of_messages): - message_id = MessageService.send_welcome_message(self.test_user) - message_ids.append(message_id) - return message_ids - - def test_delete_multiple_messages(self): - """Tests that multiple messages can be deleted""" - # Arrange - message_ids = self.send_multiple_welcome_messages(3) - # Act - Message.delete_multiple_messages(message_ids[:2], self.test_user.id) - # Assert - messages = Message.get_all_messages(self.test_user.id) - self.assertEqual(len(messages.user_messages), 1) - self.assertEqual(messages.user_messages[0].message_id, message_ids[2]) - - def test_delete_all_messages(self): - """Tests that all messages can be deleted""" - # Arrange - self.send_multiple_welcome_messages(3) - # Act - Message.delete_all_messages(self.test_user.id) - # Assert - with self.assertRaises(NotFound): - Message.get_all_messages(self.test_user.id) - - def test_delete_all_message_filters_by_type(self): - """Tests that all messages can be deleted by type""" - # Arrange - self.send_multiple_welcome_messages(3) - test_user_2 = return_canned_user("test_user_2", 222222222) - test_user_2.create() - MessageService.send_team_join_notification( - test_user_2.id, - test_user_2.username, - self.test_user.id, - "test_team", - 10, - "MANAGER", - ) - # Act - Message.delete_all_messages(self.test_user.id, [MessageType.SYSTEM.value]) - # Assert - messages = Message.get_all_messages(self.test_user.id) - # Since we deleted all system messages, there should be Invitation message left - self.assertEqual(len(messages.user_messages), 1) - self.assertEqual( - messages.user_messages[0].message_type, - MessageType.INVITATION_NOTIFICATION.name, - ) - - def test_mark_multiple_messages_read(self): - """Tests that multiple messages can be marked as read""" - # Arrange - message_ids = self.send_multiple_welcome_messages(3) - # Act - Message.mark_multiple_messages_read(message_ids[:2], self.test_user.id) - # Assert - unread_count = Message.get_unread_message_count(self.test_user.id) - self.assertEqual(unread_count, 1) - messages = Message.get_all_messages(self.test_user.id) - self.assertTrue(messages.user_messages[0].read) - self.assertTrue(messages.user_messages[1].read) - self.assertFalse(messages.user_messages[2].read) - - def test_mark_all_messages_read(self): - """Tests that all messages can be marked as read""" - # Arrange - self.send_multiple_welcome_messages(3) - # Act - Message.mark_all_messages_read(self.test_user.id) - # Assert - unread_count = Message.get_unread_message_count(self.test_user.id) - self.assertEqual(unread_count, 0) - - def test_mark_all_message_filters_by_type(self): - """Test that all message of a certain type can be marked as read""" - # Arrange - self.send_multiple_welcome_messages(3) - - test_user_2 = return_canned_user("test_user_2", 222222222) - test_user_2.create() - - MessageService.send_team_join_notification( - test_user_2.id, - test_user_2.username, - self.test_user.id, - "test_team", - 10, - "MANAGER", - ) - # Act - Message.mark_all_messages_read(self.test_user.id, [MessageType.SYSTEM.value]) - # Assert - - messages = MessageService.get_all_messages( - user_id=self.test_user.id, - locale="en", - page=1, - sort_by="date", # Required for function to work - sort_direction="desc", # Required for function to work - status="unread", - ) - # Since we marked all system messages as read, there should be Invitation message left - self.assertEqual(len(messages.user_messages), 1) - self.assertEqual( - messages.user_messages[0].message_type, - MessageType.INVITATION_NOTIFICATION.name, - ) diff --git a/tests/backend/unit/models/postgis/test_organisation.py b/tests/backend/unit/models/postgis/test_organisation.py deleted file mode 100644 index 1274b0c8f2..0000000000 --- a/tests/backend/unit/models/postgis/test_organisation.py +++ /dev/null @@ -1,49 +0,0 @@ -from backend.models.postgis.organisation import Organisation, OrganisationType -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_organisation, - create_canned_user, -) - - -class TestOrganisation(BaseTestCase): - def setUp(self): - super().setUp() - self.test_org = create_canned_organisation() - self.test_org.logo = "Test Logo" - self.test_org.description = "Test description" - self.test_org.url = "Test URL" - self.test_user = create_canned_user() - - def test_get_organisations_managed_by_user(self): - # Arrange - self.test_org.managers = [self.test_user] - # Act - organisations = Organisation.get_organisations_managed_by_user( - self.test_user.id - ) - # Assert - self.assertEqual(self.test_org.name, organisations[0].name) - - def test_as_dto(self): - # Test setting omit managers to false includes managers - # Arrange - self.test_org.managers = [self.test_user] - # Act - org_dto = self.test_org.as_dto(omit_managers=False) - # Assert - self.assertEqual(org_dto.organisation_id, self.test_org.id) - self.assertEqual(org_dto.name, self.test_org.name) - self.assertEqual(org_dto.slug, self.test_org.slug) - self.assertEqual(org_dto.logo, self.test_org.logo) - self.assertEqual(org_dto.description, self.test_org.description) - self.assertEqual(org_dto.url, self.test_org.url) - self.assertEqual(len(org_dto.managers), 1) - self.assertEqual(org_dto.managers[0].username, self.test_user.username) - self.assertEqual(org_dto.subscription_tier, self.test_org.subscription_tier) - self.assertEqual(org_dto.type, OrganisationType(self.test_org.type).name) - - # Test setting omit managers to true excludes managers - # Act - org_dto = self.test_org.as_dto(omit_managers=True) - self.assertEqual(len(org_dto.managers), 0) diff --git a/tests/backend/unit/models/postgis/test_project.py b/tests/backend/unit/models/postgis/test_project.py deleted file mode 100644 index a9aefd31b1..0000000000 --- a/tests/backend/unit/models/postgis/test_project.py +++ /dev/null @@ -1,69 +0,0 @@ -from unittest.mock import MagicMock - -from flask import current_app - -from backend.exceptions import NotFound -from backend.models.dtos.project_dto import DraftProjectDTO -from backend.models.postgis.project import Project -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_organisation, - create_canned_project, - create_canned_user, - return_canned_draft_project_json, -) - - -class TestProject(BaseTestCase): - def test_clone_project_raises_error_if_project_not_found(self): - # Arrange - Project.query.get = MagicMock(return_value=None) - # Act/Assert - with self.assertRaises(NotFound): - Project.clone(12, 777777) - - def test_clone_project_creates_copy_of_orig_project(self): - # Arrange - orig_project, author = create_canned_project() - orig_project_info = orig_project.project_info.one() - # Act - new_proj = Project.clone(orig_project.id, author.id) - new_proj_info = new_proj.project_info.one() - # Assert - self.assertEqual(orig_project.author_id, new_proj.author_id) - self.assertEqual(orig_project.geometry, new_proj.geometry) - self.assertEqual(orig_project_info.name, new_proj_info.name) - - def test_create_draft_project(self): - # Arrange - draft_project_dto = DraftProjectDTO(return_canned_draft_project_json()) - test_user = create_canned_user() # Create user to assign as author of project - test_org = ( - create_canned_organisation() - ) # Create org with id "23" which is specified on draft project dto - draft_project_dto.user_id = test_user.id - draft_project_dto.organisation = test_org - draft_project = Project() - # Act/Assert - draft_project.create_draft_project(draft_project_dto) - - def test_set_default_changeset_comment(self): - # Arrange - test_project = Project() - expected_comment = current_app.config["DEFAULT_CHANGESET_COMMENT"] - expected_comment = f"{expected_comment}-{test_project.id}" - # Act - test_project.set_default_changeset_comment() - # Assert - self.assertEqual(expected_comment, test_project.changeset_comment) - - def test_set_country_info(self): - # Arrange - test_project, _author_id = create_canned_project() - # Act - test_project.set_country_info() - # Assert - self.assertNotEqual( - 0, len(test_project.country), "Nominatim may have given a bad response" - ) - self.assertEqual(["United Kingdom"], test_project.country) diff --git a/tests/backend/unit/models/postgis/test_project_info.py b/tests/backend/unit/models/postgis/test_project_info.py deleted file mode 100644 index 69716858c3..0000000000 --- a/tests/backend/unit/models/postgis/test_project_info.py +++ /dev/null @@ -1,12 +0,0 @@ -from backend.models.postgis.project_info import ProjectInfo -from tests.backend.base import BaseTestCase - - -class TestProjectInfo(BaseTestCase): - def test_create_from_name(self): - # Arrange - name = "Test Project" - # Act - project_info = ProjectInfo.create_from_name(name) - # Assert - self.assertEqual(name, project_info.name) diff --git a/tests/backend/unit/models/postgis/test_task.py b/tests/backend/unit/models/postgis/test_task.py deleted file mode 100644 index 16d0fed4d0..0000000000 --- a/tests/backend/unit/models/postgis/test_task.py +++ /dev/null @@ -1,197 +0,0 @@ -from unittest.mock import MagicMock, patch - -import geojson - -from backend.models.postgis.statuses import TaskStatus -from backend.models.postgis.task import ( - InvalidData, - InvalidGeoJson, - Task, - TaskAction, - TaskHistory, -) -from tests.backend.base import BaseTestCase - - -class TestTask(BaseTestCase): - @patch.object(Task, "update") - @patch.object(Task, "set_task_history") - def test_reset_task_sets_to_ready_status(self, mock_set_task_history, mock_update): - user_id = 123 - - test_task = Task() - test_task.task_status = TaskStatus.MAPPED - test_task.reset_task(user_id) - - mock_set_task_history.assert_called_with( - TaskAction.STATE_CHANGE, user_id, None, TaskStatus.READY - ) - mock_update.assert_called() - self.assertEqual(test_task.task_status, TaskStatus.READY.value) - - @patch.object(Task, "update") - @patch.object(Task, "record_auto_unlock") - @patch.object(Task, "set_task_history") - def test_reset_task_clears_any_existing_locks( - self, mock_set_task_history, mock_record_auto_unlock, mock_update - ): - user_id = 123 - - test_task = Task() - test_task.task_status = TaskStatus.LOCKED_FOR_MAPPING - test_task.reset_task(user_id) - - mock_record_auto_unlock.assert_called() - self.assertEqual(test_task.task_status, TaskStatus.READY.value) - - def test_cant_add_task_if_feature_geometry_is_invalid(self): - # Arrange - invalid_feature = geojson.loads( - '{"geometry": {"coordinates": [[[[-4.0237, 56.0904], [-3.9111, 56.1715],' - '[-3.8122, 56.098], [-4.0237]]]], "type": "MultiPolygon"}, "properties":' - '{"x": 2402, "y": 1736, "zoom": 12}, "type": "Feature"}' - ) - - with self.assertRaises(InvalidGeoJson): - Task.from_geojson_feature(1, invalid_feature) - - def test_cant_add_task_if_feature_has_missing_properties(self): - # Arrange - # Missing zoom - invalid_properties = geojson.loads( - '{"geometry": {"coordinates": [[[[-4.0237, 56.0904], [-3.9111, 56.1715],' - '[-3.8122, 56.098], [-4.0237, 56.0904]]]], "type": "MultiPolygon"},' - '"properties": {"x": 2402, "y": 1736}, "type": "Feature"}' - ) - - # Act/Assert - with self.assertRaises(InvalidData): - Task.from_geojson_feature(1, invalid_properties) - - def test_can_add_task_if_feature_geometry_is_valid(self): - # Arrange - valid_feature_collection = geojson.loads( - '{"geometry": {"coordinates": [[[[-4.0237, 56.0904],' - '[-3.9111, 56.1715], [-3.8122, 56.098], [-4.0237, 56.0904]]]], "type":' - '"MultiPolygon"}, "properties": {"x": 2402, "y": 1736, "zoom": 12, "isSquare": true}, "type":' - '"Feature"}' - ) - # Act - task = Task.from_geojson_feature(1, valid_feature_collection) - # Assert - self.assertTrue(task) - - def test_cant_add_task_if_not_supplied_feature_type(self): - # Arrange - invalid_feature = geojson.MultiPolygon( - [[(2.38, 57.322), (23.194, -20.28), (-120.43, 19.15), (2.38, 10.33)]] - ) - # Act/Assert - with self.assertRaises(InvalidGeoJson): - Task.from_geojson_feature(1, invalid_feature) - - def test_lock_task_for_mapping_adds_locked_history(self): - # Arrange - test_task = Task() - - # Act - test_task.set_task_history(action=TaskAction.LOCKED_FOR_MAPPING, user_id=123454) - - # Assert - self.assertEqual( - TaskAction.LOCKED_FOR_MAPPING.name, test_task.task_history[0].action - ) - - def test_per_task_instructions_formatted_correctly(self): - # Arrange - test_task = Task() - test_task.x = 1 - test_task.y = 2 - test_task.zoom = 3 - test_task.is_square = True - - # Act - instructions = test_task.format_per_task_instructions( - "Test Url is http://test.com/{x}/{y}/{z}" - ) - - # Assert - self.assertEqual(instructions, "Test Url is http://test.com/1/2/3") - - def test_per_task_instructions_with_underscores_formatted_correctly(self): - test_task = Task() - test_task.x = 1 - test_task.y = 2 - test_task.zoom = 3 - test_task.is_square = True - - # Act - instructions = test_task.format_per_task_instructions( - "Test Url is http://test.com/{x}_{y}_{z}" - ) - - # Assert - self.assertEqual(instructions, "Test Url is http://test.com/1_2_3") - - def test_per_task_instructions_returns_instructions_when_no_dynamic_url_and_task_not_splittable( - self, - ): - # Arrange - test_task = Task() - test_task.x = 1 - test_task.y = 2 - test_task.zoom = 3 - test_task.is_square = False - - # Act - instructions = test_task.format_per_task_instructions("Use map box") - - # Assert - self.assertEqual(instructions, "Use map box") - - def test_per_task_instructions_returns_instructions_with_extra_properties(self): - # Arrange - test_task = Task() - test_task.extra_properties = '{"foo": "bar"}' - test_task.x = 1 - test_task.y = 2 - test_task.zoom = 3 - test_task.is_square = True - - # Act - instructions = test_task.format_per_task_instructions( - "Foo is replaced by {foo}" - ) - - # Assert - self.assertEqual(instructions, "Foo is replaced by bar") - - @patch.object(TaskHistory, "get_last_status") - @patch.object(TaskHistory, "get_last_locked_action") - @patch.object(Task, "set_task_history") - @patch.object(Task, "update") - def test_record_auto_unlock_adds_autounlocked_action( - self, - mock_update, - mock_set_task_history, - mock_get_last_action, - mock_get_last_status, - ): - mock_history = MagicMock() - mock_last_action = MagicMock() - mock_last_action.action = "LOCKED_FOR_MAPPING" - mock_get_last_action.return_value = mock_last_action - mock_get_last_status.return_value = TaskStatus.READY - mock_set_task_history.return_value = mock_history - - test_task = Task() - test_task.locked_by = "testuser" - lock_duration = "02:00" - test_task.record_auto_unlock(lock_duration) - - mock_set_task_history.assert_called_with( - action=TaskAction.AUTO_UNLOCKED_FOR_MAPPING, user_id="testuser" - ) - self.assertEqual(mock_history.action_text, lock_duration) - self.assertEqual(test_task.locked_by, None) - mock_last_action.delete.assert_called() diff --git a/tests/backend/unit/models/postgis/test_user.py b/tests/backend/unit/models/postgis/test_user.py deleted file mode 100644 index cd75923e52..0000000000 --- a/tests/backend/unit/models/postgis/test_user.py +++ /dev/null @@ -1,35 +0,0 @@ -from backend.models.postgis.user import MappingLevel, User, UserRole -from tests.backend.base import BaseTestCase - - -class TestUser(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = User() - self.test_user.role = UserRole.MAPPER.value - self.test_user.id = 12 - self.test_user.mapping_level = MappingLevel.BEGINNER.value - self.test_user.username = "Thinkwhere Test" - self.test_user.email_address = "thinkwheretest@test.com" - - def test_create_user(self): - # Act - self.test_user.create() - # Assert - self.assertEqual(self.test_user, User.get_by_id(12)) - - def test_update_username(self): - # Act - self.test_user.update_username("mrtest") - # Assert - self.assertEqual(self.test_user.username, "mrtest") - - def test_update_picture_url(self): - # Arrange - test_picture_url = ( - "https://cdn.pixabay.com/photo/2022/04/29/08/50/desert-7162926_1280.jpg" - ) - # Act - self.test_user.update_picture_url(test_picture_url) - # Assert - self.assertEqual(self.test_user.picture_url, test_picture_url) diff --git a/tests/backend/unit/services/__init__.py b/tests/backend/unit/services/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/unit/services/grid/__init__.py b/tests/backend/unit/services/grid/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/unit/services/grid/test_grid_service.py b/tests/backend/unit/services/grid/test_grid_service.py deleted file mode 100644 index 8ae47ba805..0000000000 --- a/tests/backend/unit/services/grid/test_grid_service.py +++ /dev/null @@ -1,159 +0,0 @@ -import json - -import geojson - -from backend.models.dtos.grid_dto import GridDTO -from backend.models.dtos.project_dto import DraftProjectDTO -from backend.models.postgis.utils import InvalidGeoJson -from backend.services.grid.grid_service import GridService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import get_canned_json - - -class TestGridService(BaseTestCase): - def test_feature_collection_to_multi_polygon_dissolve(self): - # arrange - grid_json = get_canned_json("test_grid.json") - grid_dto = GridDTO(grid_json) - aoi_geojson = geojson.loads(json.dumps(grid_dto.area_of_interest)) - expected = geojson.loads( - json.dumps(get_canned_json("multi_polygon_dissolved.json")) - ) - - # act - result = GridService.merge_to_multi_polygon(aoi_geojson, True) - - # assert - self.assertDeepAlmostEqual(expected, result) - - def test_feature_collection_to_multi_polygon_nodissolve(self): - # arrange - grid_json = get_canned_json("test_grid.json") - grid_dto = GridDTO(grid_json) - expected = geojson.loads(json.dumps(get_canned_json("multi_polygon.json"))) - aoi_geojson = geojson.loads(json.dumps(grid_dto.area_of_interest)) - - # act - result = GridService.merge_to_multi_polygon(aoi_geojson, False) - - # assert - self.assertEqual(str(expected), str(result)) - - def test_trim_grid_to_aoi_clip(self): - # arrange - grid_json = get_canned_json("test_grid.json") - - grid_dto = GridDTO(grid_json) - expected = geojson.loads( - json.dumps(get_canned_json("clipped_feature_collection.json")) - ) - grid_dto.clip_to_aoi = True - - # act - result = GridService.trim_grid_to_aoi(grid_dto) - - # assert - self.assertDeepAlmostEqual(expected, result, places=6) - - def test_trim_grid_to_aoi_noclip(self): - # arrange - - grid_json = get_canned_json("test_grid.json") - grid_dto = GridDTO(grid_json) - grid_dto.clip_to_aoi = False - - expected = geojson.loads(json.dumps(get_canned_json("feature_collection.json"))) - - # act - result = GridService.trim_grid_to_aoi(grid_dto) - - # assert - self.assertDeepAlmostEqual(expected, result) - - def test_tasks_from_aoi_features(self): - # arrange - grid_json = get_canned_json("test_arbitrary.json") - grid_dto = GridDTO(grid_json) - expected = geojson.loads( - json.dumps(get_canned_json("tasks_from_aoi_features.json")) - ) - - # act - result = GridService.tasks_from_aoi_features(grid_dto.area_of_interest) - # assert - self.assertEqual(str(expected), str(result)) - - def test_feature_collection_multi_polygon_with_zcoord_nodissolve(self): - # arrange - project_json = get_canned_json("canned_kml_project.json") - project_dto = DraftProjectDTO(project_json) - expected = geojson.loads(json.dumps(get_canned_json("2d_multi_polygon.json"))) - aoi_geojson = geojson.loads(json.dumps(project_dto.area_of_interest)) - - # act - result = GridService.merge_to_multi_polygon(aoi_geojson, dissolve=False) - - # assert - self.assertEqual(str(expected), str(result)) - - def test_feature_collection_multi_polygon_with_zcoord_dissolve(self): - # arrange - project_json = get_canned_json("canned_kml_project.json") - project_dto = DraftProjectDTO(project_json) - expected = geojson.loads(json.dumps(get_canned_json("2d_multi_polygon.json"))) - aoi_geojson = geojson.loads(json.dumps(project_dto.area_of_interest)) - - # act - result = GridService.merge_to_multi_polygon(aoi_geojson, dissolve=True) - - # assert - self.assertEqual(str(expected), str(result)) - - def test_raises_InvalidGeoJson_when_geometry_is_linestring(self): - # arrange - grid_json = get_canned_json("CHAI-Escuintla-West2.json") - grid_dto = GridDTO(grid_json) - grid_dto.clip_to_aoi = True - - # Act / Assert - with self.assertRaises(InvalidGeoJson): - GridService.merge_to_multi_polygon(grid_dto.area_of_interest, dissolve=True) - - def test_cant_create_aoi_with_non_multipolygon_type(self): - # Arrange - bad_geom = geojson.Polygon( - [[(2.38, 57.322), (23.194, -20.28), (-120.43, 19.15), (2.38, 57.322)]] - ) - bad_feature = geojson.Feature(geometry=bad_geom) - # bad_feature_collection = geojson.FeatureCollection([bad_feature]) - - # Act / Assert - with self.assertRaises(InvalidGeoJson): - # Only geometries of type MultiPolygon are valid - GridService.merge_to_multi_polygon( - geojson.dumps(bad_feature), dissolve=True - ) - - def test_cant_create_aoi_with_invalid_multipolygon(self): - bad_multipolygon = geojson.MultiPolygon( - [[(2.38, 57.322), (23.194, -20.28), (-120.43, 19.15), (2.38)]] - ) - bad_feature = geojson.Feature(geometry=bad_multipolygon) - bad_feature_collection = geojson.FeatureCollection([bad_feature]) - - # Act / Assert - with self.assertRaises(InvalidGeoJson): - # Only geometries of type MultiPolygon are valid - GridService.merge_to_multi_polygon( - geojson.dumps(bad_feature_collection), dissolve=True - ) - - def test_to_shapely_geometries(self): - # Arrange - grid_json = get_canned_json("test_arbitrary.json") - grid_dto = GridDTO(grid_json) - grid_geojson = json.dumps(grid_dto.area_of_interest) - # Act - features = GridService._to_shapely_geometries(grid_geojson) - # Assert - self.assertNotEqual(0, len(features)) diff --git a/tests/backend/unit/services/messaging/__init__.py b/tests/backend/unit/services/messaging/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/unit/services/messaging/test_messaging_service.py b/tests/backend/unit/services/messaging/test_messaging_service.py deleted file mode 100644 index 7a8eaa9444..0000000000 --- a/tests/backend/unit/services/messaging/test_messaging_service.py +++ /dev/null @@ -1,97 +0,0 @@ -from unittest.mock import patch - -from backend.models.postgis.message import Message -from backend.services.messaging.message_service import MessageService -from tests.backend.base import BaseTestCase - -MESSAGE_TYPES = "3,2,1" -TEST_USER_ID = 111111111 - - -class TestMessagingService(BaseTestCase): - # outdated test - # def test_message_service_identifies_all_users(self): - # # Act - # usernames = MessageService._parse_message_for_username( - # 'Hello @[Iain Hunter] and "[LindaA1]' - # ) - # - # # Assert - # self.assertEqual(usernames[0], "Iain Hunter") - # self.assertEqual(usernames[1], "LindaA1") - - def test_message_service_generates_correct_task_link(self): - # Act - link = MessageService.get_task_link(1, 1, "http://test.com") - - # Assert - self.assertEqual( - link, - 'Task 1', - ) - - def test_message_service_generates_highlighted_task_link(self): - # Act - link = MessageService.get_task_link(1, 1, "example.com", highlight=True) - - # Assert - self.assertEqual( - link, - 'Task 1', - ) - - def test_message_service_generates_correct_chat_link(self): - # Act - link = MessageService.get_project_link( - 1, "TEST_PROJECT", "http://test.com", include_chat_section=True - ) - - self.assertEqual( - link, - 'TEST_PROJECT #1', - ) - link = MessageService.get_project_link( - 1, - "TEST_PROJECT", - "http://test.com", - highlight=True, - ) - - self.assertEqual( - link, - 'TEST_PROJECT #1', - ) - - @patch.object(Message, "delete_multiple_messages") - def test_delete_multiple_messages(self, mock_delete_multiple_messages): - """Test that the delete_multiple_messages method calls the model method""" - # Act - MessageService.delete_multiple_messages([1, 2, 3], 1) - # Assert - mock_delete_multiple_messages.assert_called() - - @patch.object(Message, "delete_all_messages") - def test_delete_all_messages(self, mock_delete_all_messages): - """Test that the delete_all_messages method calls the model method""" - # Act - MessageService.delete_all_messages(1, MESSAGE_TYPES) - message_type = list(map(int, list(MESSAGE_TYPES.split(",")))) - # Assert - mock_delete_all_messages.assert_called_with(1, message_type) - - @patch.object(Message, "mark_multiple_messages_read") - def test_mark_multiple_messaes_read(self, mock_mark_multiple_messages_read): - """Test that the mark_multiple_messages_read method calls the model method""" - # Act - MessageService.mark_multiple_messages_read([1, 2, 3], 1) - # Assert - mock_mark_multiple_messages_read.assert_called() - - @patch.object(Message, "mark_all_messages_read") - def test_mark_all_messages_read(self, mock_mark_all_messages_read): - """Test that the mark_all_messages_read method calls the model method""" - # Act - MessageService.mark_all_messages_read(1, MESSAGE_TYPES) - message_type = list(map(int, list(MESSAGE_TYPES.split(",")))) - # Assert - mock_mark_all_messages_read.assert_called_with(1, message_type) diff --git a/tests/backend/unit/services/messaging/test_template_service.py b/tests/backend/unit/services/messaging/test_template_service.py deleted file mode 100644 index 7a44731294..0000000000 --- a/tests/backend/unit/services/messaging/test_template_service.py +++ /dev/null @@ -1,57 +0,0 @@ -from flask import current_app - -from backend.services.messaging.template_service import ( - clean_html, - format_username_link, - get_template, - template_var_replacing, -) -from tests.backend.base import BaseTestCase - - -class TestTemplateService(BaseTestCase): - def test_variable_replacing(self): - # Act - values = {"USERNAME": "USERNAME", "VERIFICATION_LINK": "VERIFICATION_LINK"} - content = get_template("email_verification_en.html", values) - replace_list = [ - ["USERNAME", "test_user"], - ["VERIFICATION_LINK", "http://localhost:30/verify.html#1234"], - [current_app.config["ORG_CODE"], "HOT"], - [current_app.config["ORG_NAME"], "Organization Test"], - ] - processed_content = template_var_replacing(content, replace_list) - # Assert - self.assertIn("test_user", processed_content) - self.assertIn("http://localhost:30/verify.html#1234", processed_content) - self.assertIn("HOT", processed_content) - self.assertIn("Organization Test", processed_content) - - self.assertNotIn("[USERNAME]", processed_content) - self.assertNotIn("[VERIFICATION_LINK]", processed_content) - self.assertNotIn("[ORG_CODE]", processed_content) - self.assertNotIn("[ORG_NAME]", processed_content) - - def test_clean_html(self): - self.assertEqual( - clean_html( - 'Welcome to Tasking Manager!' - ), - "Welcome to Tasking Manager!", - ) - - def test_format_username_link(self): - base_url = current_app.config["APP_BASE_URL"] - self.assertEqual( - format_username_link("try @[yo] @[us2]! [t](http://a.c)"), - ( - f'try @yo' - f' @us2! [t](http://a.c)' - ), - ) - self.assertEqual( - format_username_link( - "testing @user! Write me at i@we.com [test](http://link.com)" - ), - "testing @user! Write me at i@we.com [test](http://link.com)", - ) diff --git a/tests/backend/unit/services/test_mapping_service.py b/tests/backend/unit/services/test_mapping_service.py deleted file mode 100644 index 731de0c30c..0000000000 --- a/tests/backend/unit/services/test_mapping_service.py +++ /dev/null @@ -1,238 +0,0 @@ -from unittest.mock import MagicMock, patch - -from backend.models.dtos.mapping_dto import LockTaskDTO, MappedTaskDTO -from backend.models.postgis.project_info import ProjectInfo -from backend.models.postgis.task import TaskAction, TaskHistory, User -from backend.services.mapping_service import ( - MappingNotAllowed, - MappingService, - MappingServiceError, - NotFound, - ProjectService, - StatsService, - Task, - TaskStatus, - UserLicenseError, -) -from backend.services.messaging.message_service import MessageService -from tests.backend.base import BaseTestCase - - -class TestMappingService(BaseTestCase): - task_stub = Task - lock_task_dto = LockTaskDTO - mapped_task_dto = MappedTaskDTO - mapping_service = None - - def setUp(self): - super().setUp() - - test_user = User() - test_user.id = 123456 - test_user.username = "Thinkwhere" - - self.task_stub = Task() - self.task_stub.id = 1 - self.task_stub.project_id = 1 - self.task_stub.task_status = 0 - self.task_stub.locked_by = 123456 - self.task_stub.lock_holder = test_user - - self.lock_task_dto = LockTaskDTO() - self.lock_task_dto.user_id = 123456 - - self.mapped_task_dto = MappedTaskDTO() - self.mapped_task_dto.status = TaskStatus.MAPPED.name - self.mapped_task_dto.user_id = 123456 - - @patch.object(Task, "get") - def test_get_task_raises_error_if_task_not_found(self, mock_task): - mock_task.return_value = None - - with self.assertRaises(NotFound): - MappingService.get_task(12, 12) - - @patch.object(MappingService, "get_task") - def test_lock_task_for_mapping_raises_error_if_task_in_invalid_state( - self, mock_task - ): - # Arrange - self.task_stub.task_status = TaskStatus.MAPPED.value - self.task_stub.locked_by = None - mock_task.return_value = self.task_stub - - # Act / Assert - with self.assertRaises(MappingServiceError): - MappingService.lock_task_for_mapping(self.lock_task_dto) - - @patch.object(ProjectService, "is_user_permitted_to_map") - @patch.object(MappingService, "get_task") - def test_lock_task_for_mapping_raises_error_if_user_already_has_locked_task( - self, mock_task, mock_project - ): - # Arrange - self.task_stub.locked_by = None - mock_task.return_value = self.task_stub - mock_project.return_value = ( - False, - MappingNotAllowed.USER_ALREADY_HAS_TASK_LOCKED, - ) - - # Act / Assert - with self.assertRaises(MappingServiceError): - MappingService.lock_task_for_mapping(self.lock_task_dto) - - @patch.object(ProjectService, "is_user_permitted_to_map") - @patch.object(MappingService, "get_task") - def test_lock_task_for_mapping_raises_error_if_user_has_not_accepted_license( - self, mock_task, mock_project - ): - # Arrange - self.task_stub.locked_by = None - mock_task.return_value = self.task_stub - mock_project.return_value = False, MappingNotAllowed.USER_NOT_ACCEPTED_LICENSE - - # Act / Assert - with self.assertRaises(UserLicenseError): - MappingService.lock_task_for_mapping(self.lock_task_dto) - - @patch.object(MappingService, "get_task") - def test_unlock_of_not_locked_for_mapping_raises_error(self, mock_task): - # Arrange - mock_task.return_value = self.task_stub - - # Act / Assert - with self.assertRaises(MappingServiceError): - MappingService.unlock_task_after_mapping(MagicMock()) - - @patch.object(MappingService, "get_task") - def test_cant_unlock_a_task_you_dont_own(self, mock_task): - # Arrange - self.task_stub.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - self.task_stub.locked_by = 12 - mock_task.return_value = self.task_stub - - # Act / Assert - with self.assertRaises(MappingServiceError): - MappingService.unlock_task_after_mapping(self.mapped_task_dto) - - @patch.object(MappingService, "get_task") - def test_if_new_state_not_acceptable_raise_error(self, mock_task): - # Arrange - self.task_stub.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - mock_task.return_value = self.task_stub - - self.mapped_task_dto.status = TaskStatus.LOCKED_FOR_VALIDATION.name - - # Act / Assert - with self.assertRaises(MappingServiceError): - MappingService.unlock_task_after_mapping(self.mapped_task_dto) - - @patch.object(ProjectService, "send_email_on_project_progress") - @patch.object(ProjectInfo, "get_dto_for_locale") - @patch.object(Task, "get_per_task_instructions") - @patch.object(StatsService, "update_stats_after_task_state_change") - @patch.object(Task, "update") - @patch.object(TaskHistory, "get_last_status") - @patch.object(TaskHistory, "update_task_locked_with_duration") - @patch.object(MessageService, "send_message_after_comment") - @patch.object(MappingService, "get_task") - def test_unlock_with_comment_sets_history( - self, - mock_task, - mock_send_message, - mock_history, - mock_update, - mock_stats, - mock_instructions, - mock_state, - mock_project_name, - mock_send_email, - ): - # Arrange - self.task_stub.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - self.mapped_task_dto.comment = "Test comment" - mock_task.return_value = self.task_stub - mock_state.return_value = TaskStatus.LOCKED_FOR_MAPPING - mock_project_name.name.return_value = "Test project" - # Act - test_task = MappingService.unlock_task_after_mapping(self.mapped_task_dto) - - mock_send_email.assert_called() - # Assert - mock_send_message.assert_called() - self.assertEqual(TaskAction.COMMENT.name, test_task.task_history[0].action) - self.assertEqual(test_task.task_history[0].action_text, "Test comment") - - @patch.object(ProjectService, "send_email_on_project_progress") - @patch.object(Task, "get_per_task_instructions") - @patch.object(StatsService, "update_stats_after_task_state_change") - @patch.object(Task, "update") - @patch.object(TaskHistory, "get_last_status") - @patch.object(TaskHistory, "update_task_locked_with_duration") - @patch.object(MappingService, "get_task") - def test_unlock_with_status_change_sets_history( - self, - mock_task, - mock_history, - mock_update, - mock_stats, - mock_instructions, - mock_state, - mock_send_email, - ): - # Arrange - self.task_stub.task_status = TaskStatus.LOCKED_FOR_MAPPING.value - mock_task.return_value = self.task_stub - mock_state.return_value = TaskStatus.LOCKED_FOR_MAPPING - - # Act - test_task = MappingService.unlock_task_after_mapping(self.mapped_task_dto) - - # Assert - mock_send_email.assert_called() - self.assertEqual(TaskAction.STATE_CHANGE.name, test_task.task_history[0].action) - self.assertEqual(test_task.task_history[0].action_text, TaskStatus.MAPPED.name) - self.assertEqual(TaskStatus.MAPPED.name, test_task.task_status) - - @patch.object(ProjectService, "is_user_permitted_to_validate") - @patch.object(TaskHistory, "get_last_action") - def test_task_is_undoable_if_last_change_made_by_you( - self, last_action, mock_project - ): - # Arrange - task_history = TaskHistory(1, 1, 1) - task_history.user_id = 1 - last_action.return_value = task_history - - task = Task() - task.task_status = TaskStatus.MAPPED.value - task.mapped_by = 1 - - # Act - mock_project.return_value = True, None - is_undoable = MappingService._is_task_undoable(1, task) - - # Assert - self.assertTrue(is_undoable) - - @patch.object(ProjectService, "is_user_permitted_to_validate") - @patch.object(TaskHistory, "get_last_action") - def test_task_is_not_undoable_if_last_change_not_made_by_you( - self, last_action, mock_project - ): - # Arrange - task_history = TaskHistory(1, 1, 1) - task_history.user_id = 2 - last_action.return_value = task_history - - task = Task() - task.task_status = TaskStatus.MAPPED.value - task.mapped_by = 1 - - # Act - mock_project.return_value = (False, None) - is_undoable = MappingService._is_task_undoable(1, task) - - # Assert - self.assertFalse(is_undoable) diff --git a/tests/backend/unit/services/test_organisation_service.py b/tests/backend/unit/services/test_organisation_service.py deleted file mode 100644 index 420f41e197..0000000000 --- a/tests/backend/unit/services/test_organisation_service.py +++ /dev/null @@ -1,64 +0,0 @@ -from unittest.mock import patch - -from backend.models.postgis.statuses import UserRole -from backend.services.organisation_service import NotFound, OrganisationService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import ( - create_canned_organisation, - create_canned_user, - return_canned_user, -) - - -class TestOrganisationService(BaseTestCase): - def test_get_get_organisation_by_id_returns_organisation(self): - # Arrange - test_org = create_canned_organisation() - # Act - result_org = OrganisationService.get_organisation_by_id(test_org.id) - # Assert - self.assertEqual(test_org, result_org) - - def test_get_get_organisation_by_id_raises_error_if_organisation_not_found(self): - # Act/Assert - with self.assertRaises(NotFound): - OrganisationService.get_organisation_by_id(123) - - @patch.object(OrganisationService, "get_organisations_managed_by_user") - def test_organisation_managed_by_user_as_dto(self, mock_get_user_org): - # Arrange - test_user = create_canned_user() - test_org = create_canned_organisation() - test_org.managers = [test_user] - test_org.save() - # Act - OrganisationService.get_organisations_managed_by_user_as_dto(test_user.id) - # Assert - mock_get_user_org.assert_called_with(test_user.id) - - def test_organisation_managed_by_user(self): - # Arrange - test_user = create_canned_user() - test_org = create_canned_organisation() - test_org.managers = [test_user] - test_org.save() - # Act - organisations = OrganisationService.get_organisations_managed_by_user( - test_user.id - ) - # Assert - self.assertEqual(test_org.name, organisations[0].name) - - def test_organisation_managed_by_user_returns_all_organisations_for_admin(self): - # Arrange - test_user = return_canned_user() - test_user.role = UserRole.ADMIN.value - test_user.create() - test_org = create_canned_organisation() - - # Act - organisations = OrganisationService.get_organisations_managed_by_user( - test_user.id - ) - # Assert - self.assertEqual(test_org.name, organisations[0].name) diff --git a/tests/backend/unit/services/test_project_admin_service.py b/tests/backend/unit/services/test_project_admin_service.py deleted file mode 100644 index f3693b4460..0000000000 --- a/tests/backend/unit/services/test_project_admin_service.py +++ /dev/null @@ -1,137 +0,0 @@ -import json -from unittest.mock import MagicMock, patch - -from backend.models.dtos.project_dto import ProjectInfoDTO -from backend.models.postgis.task import Task -from backend.services.project_admin_service import ( - InvalidGeoJson, - LicenseService, - NotFound, - Project, - ProjectAdminService, - ProjectAdminServiceError, -) -from tests.backend.base import BaseTestCase - - -class TestProjectAdminService(BaseTestCase): - def test_cant_add_tasks_if_geojson_not_feature_collection(self): - # Arrange - invalid_feature = ( - '{"coordinates": [[[[-4.0237, 56.0904], [-3.9111, 56.1715], [-3.8122, 56.098],' - '[-4.0237, 56.0904]]]], "type": "MultiPolygon"}' - ) - - # Act - with self.assertRaises(InvalidGeoJson): - ProjectAdminService._attach_tasks_to_project(MagicMock(), invalid_feature) - - def test_valid_geo_json_attaches_task_to_project(self): - # Arrange - valid_feature_collection = json.loads( - '{"features": [{"geometry": {"coordinates": [[[[-4.0237, 56.0904],' - '[-3.9111, 56.1715], [-3.8122, 56.098], [-4.0237, 56.0904]]]], "type":' - '"MultiPolygon"}, "properties": {"x": 2402, "y": 1736, "zoom": 12, "isSquare": true}, "type":' - '"Feature"}], "type": "FeatureCollection"}' - ) - - test_project = Project() - - # Act - ProjectAdminService._attach_tasks_to_project( - test_project, valid_feature_collection - ) - - # Assert - self.assertEqual( - 1, - test_project.tasks.count(), - "One task should have been attached to project", - ) - - @patch.object(Project, "get") - def test_get_raises_error_if_not_found(self, mock_project): - # Arrange - mock_project.return_value = None - - # Act / Assert - with self.assertRaises(NotFound): - ProjectAdminService._get_project_by_id(12) - - def test_complete_default_locale_raises_is_valid(self): - # Arrange - locales = [] - info = ProjectInfoDTO() - info.locale = "en" - info.name = "Test" - info.description = "Test Desc" - info.short_description = "Short Desc" - info.instructions = "Instruct" - locales.append(info) - - # Act - is_valid = ProjectAdminService._validate_default_locale("en", locales) - - # Assert - self.assertTrue(is_valid, "Complete default locale should be valid") - - def test_complete_default_locale_raises_error_if_incomplete(self): - # Arrange - locales = [] - info = ProjectInfoDTO() - info.locale = "en" - info.name = "Test" - info.description = "Test Desc" - info.short_description = "Short Desc" - locales.append(info) - - # Act - with self.assertRaises(ProjectAdminServiceError): - ProjectAdminService._validate_default_locale("en", locales) - - def test_complete_default_locale_raises_error_if_default_locale_not_found(self): - # Arrange - locales = [] - info = ProjectInfoDTO() - info.locale = "en" - info.name = "Test" - info.description = "Test Desc" - info.short_description = "Short Desc" - locales.append(info) - - # Act - with self.assertRaises(ProjectAdminServiceError): - ProjectAdminService._validate_default_locale("it", locales) - - @patch.object(LicenseService, "get_license_as_dto") - def test_attempting_to_attach_non_existant_license_raise_error(self, license_mock): - # Arrange - license_mock.side_effect = NotFound() - - with self.assertRaises(ProjectAdminServiceError): - ProjectAdminService._validate_imagery_licence(1) - - @patch.object(ProjectAdminService, "_get_project_by_id") - @patch("flask_sqlalchemy.model._QueryProperty.__get__") - @patch.object(Task, "set_task_history") - def test_reset_all_tasks(self, mock_set_task_history, mock_query, mock_get_project): - user_id = 123 - test_project = MagicMock(spec=Project) - test_project.id = 456 - test_project.tasks_mapped = 2 - test_project.tasks_validated = 2 - test_tasks = [MagicMock(spec=Task), MagicMock(spec=Task), MagicMock(spec=Task)] - - mock_query.return_value.filter.return_value.all.return_value = test_tasks - mock_get_project.return_value = test_project - - ProjectAdminService.reset_all_tasks(test_project.id, user_id) - - for test_task in test_tasks: - test_task.set_task_history.assert_called() - test_task.reset_task.assert_called_with(user_id) - - mock_get_project.assert_called_with(test_project.id) - self.assertEqual(test_project.tasks_mapped, 0) - self.assertEqual(test_project.tasks_validated, 0) - test_project.save.assert_called() diff --git a/tests/backend/unit/services/test_project_search_service.py b/tests/backend/unit/services/test_project_search_service.py deleted file mode 100644 index 72bbd23a55..0000000000 --- a/tests/backend/unit/services/test_project_search_service.py +++ /dev/null @@ -1,39 +0,0 @@ -from backend.models.dtos.project_dto import ProjectSearchDTO -from backend.models.postgis.statuses import ProjectDifficulty, ProjectStatus -from backend.services.project_search_service import ProjectSearchService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - - -class TestProjectService(BaseTestCase): - def test_project_search(self): - # Arrange - test_project, test_user = create_canned_project() - test_project.difficulty = ProjectDifficulty.EASY.value - test_project.status = ProjectStatus.PUBLISHED.value - - search_dto = ProjectSearchDTO() - search_dto.preferred_locale = None - search_dto.difficulty = "EASY" - search_dto.mapping_types = None - search_dto.project_statuses = ["PUBLISHED"] - search_dto.organisation_name = None - search_dto.order_by = "priority" - search_dto.order_by_type = "DESC" - search_dto.page = 1 - search_dto.text_search = test_project.id - search_dto.mapping_editors = ["ID"] - search_dto.validation_editors = ["ID"] - search_dto.teams = None - search_dto.interests = None - search_dto.created_by = test_user.id - search_dto.mapped_by = None - search_dto.favorited_by = None - search_dto.managed_by = None - search_dto.omit_map_results = False - - search_dto.validate() - # Act/Assert - self.assertIsNotNone( - ProjectSearchService.search_projects(search_dto, test_user) - ) diff --git a/tests/backend/unit/services/test_project_service.py b/tests/backend/unit/services/test_project_service.py deleted file mode 100644 index 0b481dac4e..0000000000 --- a/tests/backend/unit/services/test_project_service.py +++ /dev/null @@ -1,279 +0,0 @@ -from unittest.mock import patch - -from flask import current_app - -from backend.models.dtos.project_dto import LockedTasksForUser -from backend.models.postgis.task import Task -from backend.services.messaging.smtp_service import SMTPService -from backend.services.project_service import ( - MappingLevel, - MappingNotAllowed, - NotFound, - Project, - ProjectAdminService, - ProjectInfo, - ProjectService, - ProjectStatus, - UserService, - ValidatingNotAllowed, -) -from tests.backend.base import BaseTestCase - - -class TestProjectService(BaseTestCase): - def setUp(self): - super().setUp() - current_app.config["SEND_PROJECT_EMAIL_UPDATES"] = ( - True # Set to true to test email sending - ) - - @patch.object(Project, "get") - def test_project_service_raises_error_if_project_not_found(self, mock_project): - mock_project.return_value = None - - with self.assertRaises(NotFound): - ProjectService.get_project_by_id(123) - - @patch.object(UserService, "get_mapping_level") - def test_user_not_allowed_to_map_if_level_enforced(self, mock_level): - # Arrange - mock_level.return_value = MappingLevel.BEGINNER - - # Act / Assert - self.assertTrue(ProjectService._is_user_beginner(1)) - - @patch.object(UserService, "get_mapping_level") - def test_user_is_allowed_to_map_if_level_enforced(self, mock_level): - # Arrange - mock_level.return_value = MappingLevel.ADVANCED - - # Act / Assert - self.assertFalse(ProjectService._is_user_beginner(1)) - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - @patch.object(UserService, "is_user_blocked") - @patch.object(UserService, "has_user_accepted_license") - @patch.object(Task, "get_locked_tasks_for_user") - @patch.object(Project, "get") - def test_user_allowed_to_map( - self, - mock_project, - mock_user_tasks, - mock_user_license, - mock_user_blocked, - mock_user_is_action_permitted, - ): - # Mock project - stub_project = Project() - stub_project.status = ProjectStatus.PUBLISHED.value - stub_project.license_id = 11 - mock_project.return_value = stub_project - - # Admin user related - mock_user_is_action_permitted.return_value = True - mock_user_tasks.return_value = LockedTasksForUser() - mock_user_tasks.return_value.locked_tasks = [] - mock_user_license.return_value = True - mock_user_blocked.return_value = False - - allowed, reason = ProjectService.is_user_permitted_to_map(1, 1) - - self.assertTrue(allowed) - self.assertEqual(reason, "User allowed to map") - - # Admin not accepted license should fail - mock_user_license.return_value = False - allowed, reason = ProjectService.is_user_permitted_to_map(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, MappingNotAllowed.USER_NOT_ACCEPTED_LICENSE) - - # Admin with already locked tasks should fail - mock_user_license.return_value = True - mock_user_tasks.return_value.locked_tasks = [1] - allowed, reason = ProjectService.is_user_permitted_to_map(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, MappingNotAllowed.USER_ALREADY_HAS_TASK_LOCKED) - - # Admin can access draft projects - stub_project.status = ProjectStatus.DRAFT.value - mock_user_tasks.return_value.locked_tasks = [] - allowed, reason = ProjectService.is_user_permitted_to_map(1, 1) - self.assertTrue(allowed) - self.assertEqual(reason, "User allowed to map") - - # Mappers - mock_user_is_action_permitted.return_value = False - mock_user_blocked.return_value = False - - # cannot access unpublished project - allowed, reason = ProjectService.is_user_permitted_to_map(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, MappingNotAllowed.PROJECT_NOT_PUBLISHED) - - # Mappers not accepted license should fail - mock_user_license.return_value = False - allowed, reason = ProjectService.is_user_permitted_to_map(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, MappingNotAllowed.USER_NOT_ACCEPTED_LICENSE) - - # Blocked user - mock_user_blocked.return_value = True - allowed, reason = ProjectService.is_user_permitted_to_map(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, MappingNotAllowed.USER_NOT_ON_ALLOWED_LIST) - - @patch.object(ProjectAdminService, "is_user_action_permitted_on_project") - @patch.object(UserService, "is_user_blocked") - @patch.object(UserService, "has_user_accepted_license") - @patch.object(Task, "get_locked_tasks_for_user") - @patch.object(Project, "get") - def test_user_permitted_to_validate( - self, - mock_project, - mock_user_tasks, - mock_user_license, - mock_user_blocked, - mock_user_is_action_permitted, - ): - # Mock project - stub_project = Project() - stub_project.status = ProjectStatus.PUBLISHED.value - stub_project.license_id = 1 - mock_project.return_value = stub_project - - # Admin user related - mock_user_is_action_permitted.return_value = True - mock_user_tasks.return_value = LockedTasksForUser() - mock_user_tasks.return_value.locked_tasks = [] - mock_user_license.return_value = True - mock_user_blocked.return_value = False - - allowed, reason = ProjectService.is_user_permitted_to_validate(1, 1) - - self.assertTrue(allowed) - self.assertEqual(reason, "User allowed to validate") - - # Admin not accepted license should fail - mock_user_license.return_value = False - allowed, reason = ProjectService.is_user_permitted_to_validate(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, ValidatingNotAllowed.USER_NOT_ACCEPTED_LICENSE) - - # Admin with already locked tasks should fail - mock_user_license.return_value = True - mock_user_tasks.return_value.locked_tasks = [1] - allowed, reason = ProjectService.is_user_permitted_to_validate(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, ValidatingNotAllowed.USER_ALREADY_HAS_TASK_LOCKED) - - # Blocked user - mock_user_blocked.return_value = True - allowed, reason = ProjectService.is_user_permitted_to_validate(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, ValidatingNotAllowed.USER_NOT_ON_ALLOWED_LIST) - - # Unpublished project - stub_project.status = ProjectStatus.DRAFT.value - mock_user_blocked.return_value = False - mock_user_is_action_permitted.return_value = False - allowed, reason = ProjectService.is_user_permitted_to_validate(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, ValidatingNotAllowed.PROJECT_NOT_PUBLISHED) - - # Admin can access draft projects - stub_project.status = ProjectStatus.DRAFT.value - mock_user_blocked.return_value = False - mock_user_is_action_permitted.return_value = True - mock_user_tasks.return_value.locked_tasks = [] - allowed, reason = ProjectService.is_user_permitted_to_validate(1, 1) - self.assertTrue(allowed) - self.assertEqual(reason, "User allowed to validate") - - # Mappers not accepted license should fail - mock_user_blocked.return_value = False - mock_user_is_action_permitted.return_value = False - mock_user_license.return_value = False - allowed, reason = ProjectService.is_user_permitted_to_validate(1, 1) - self.assertFalse(allowed) - self.assertEqual(reason, ValidatingNotAllowed.USER_NOT_ACCEPTED_LICENSE) - - @patch.object(SMTPService, "send_email_to_contributors_on_project_progress") - @patch.object(Project, "calculate_tasks_percent") - @patch.object(ProjectInfo, "get_dto_for_locale") - @patch.object(ProjectService, "get_project_by_id") - def test_send_email_on_project_progress_sends_email_on_fifty_percent_progress( - self, mock_project, mock_project_info, mock_project_completion, mock_send_email - ): - # Arrange - mock_project.return_value = Project() - mock_project_info.name.return_value = "TEST_PROJECT" - mock_project_completion.return_value = 50 - # Act - ProjectService.send_email_on_project_progress(1) - # Assert - mock_send_email.assert_called() - - @patch.object(SMTPService, "send_email_to_contributors_on_project_progress") - @patch.object(Project, "calculate_tasks_percent") - @patch.object(ProjectInfo, "get_dto_for_locale") - @patch.object(ProjectService, "get_project_by_id") - def test_send_email_on_project_progress_sends_email_on_project_completion( - self, mock_project, mock_project_info, mock_project_completion, mock_send_email - ): - # Arrange - mock_project.return_value = Project() - mock_project_info.name.return_value = "TEST_PROJECT" - mock_project_completion.return_value = 100 - # Act - ProjectService.send_email_on_project_progress(1) - # Assert - mock_send_email.assert_called() - - @patch.object(SMTPService, "send_email_to_contributors_on_project_progress") - @patch.object(Project, "calculate_tasks_percent") - @patch.object(ProjectInfo, "get_dto_for_locale") - @patch.object(ProjectService, "get_project_by_id") - def test_send_email_on_project_progress_doesnt_send_email_except_on_fifty_and_hundred_percent( - self, mock_project, mock_project_info, mock_project_completion, mock_send_email - ): - # Arrange - mock_project.return_value = Project() - mock_project_info.name.return_value = "TEST_PROJECT" - mock_project_completion.return_value = 80 - # Act - ProjectService.send_email_on_project_progress(1) - # Assert - self.assertFalse(mock_send_email.called) - - @patch.object(SMTPService, "send_email_to_contributors_on_project_progress") - @patch.object(Project, "calculate_tasks_percent") - @patch.object(ProjectService, "get_project_by_id") - def test_send_email_on_project_progress_doesnt_send_email_if_email_already_sent( - self, mock_project, mock_project_completion, mock_send_email - ): - # Arrange - canned_project = Project() - canned_project.progress_email_sent = True - mock_project.return_value = canned_project - mock_project.progress_email_sent.return_value = True - mock_project_completion.return_value = 50 - # Act - ProjectService.send_email_on_project_progress(1) - # Assert - self.assertFalse(mock_send_email.called) - - @patch.object(SMTPService, "send_email_to_contributors_on_project_progress") - @patch.object(ProjectService, "get_project_by_id") - def test_send_email_on_project_progress_doesnt_send_email_if_send_project_update_email_is_disabled( - self, mock_project, mock_send_email - ): - # Arrange - mock_project.return_value = Project() - current_app.config["SEND_PROJECT_EMAIL_UPDATES"] = False - # Act - ProjectService.send_email_on_project_progress(1) - # Assert - current_app.config["SEND_PROJECT_EMAIL_UPDATES"] = ( - True # Set to true for other tests - ) - self.assertFalse(mock_send_email.called) diff --git a/tests/backend/unit/services/test_recommendation_service.py b/tests/backend/unit/services/test_recommendation_service.py deleted file mode 100644 index e8ecf8bb20..0000000000 --- a/tests/backend/unit/services/test_recommendation_service.py +++ /dev/null @@ -1,173 +0,0 @@ -import pandas as pd - -from backend.models.postgis.project import ProjectStatus -from backend.services.recommendation_service import ProjectRecommendationService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_project - - -class TestProjectRecommendationService(BaseTestCase): - def setUp(self): - super().setUp() - self.service = ProjectRecommendationService() - - def create_project(self, is_published=True): - """Create a canned project""" - project, _ = create_canned_project() - project.status = ( - ProjectStatus.PUBLISHED.value if is_published else ProjectStatus.DRAFT.value - ) - project.save() - return project - - def test_to_dataframe_returns_records_into_dataframe(self): - """Test that to_dataframe returns records into dataframe""" - # Arrange - records = [(1, 2, 3), (4, 5, 6)] - colunms = ["a", "b", "c"] - # Act - df = self.service.to_dataframe(records, colunms) - # Assert - self.assertEqual(df.shape, (2, 3)) - self.assertEqual(df["a"].tolist(), [1, 4]) - self.assertEqual(df["b"].tolist(), [2, 5]) - self.assertEqual(df["c"].tolist(), [3, 6]) - - def test_to_dataframe_returns_empty_dataframe_when_records_is_empty(self): - """Test that to_dataframe returns empty dataframe when records is empty""" - # Arrange - records = [] - colunms = ["a", "b", "c"] - # Act - df = self.service.to_dataframe(records, colunms) - # Assert - self.assertEqual(df.shape, (0, 3)) - self.assertEqual(df["a"].tolist(), []) - self.assertEqual(df["b"].tolist(), []) - self.assertEqual(df["c"].tolist(), []) - - def test_get_all_published_projects_returns_published_projects(self): - """Test that get_all_published_projects returns published projects""" - # Arrange - test_project_1 = self.create_project() - test_project_2 = self.create_project() - # Let's create a draft project to make sure it's not returned - self.create_project(is_published=False) - # Act - projects = self.service.get_all_published_projects() - # Assert - self.assertEqual(len(projects), 2) - self.assertEqual(projects[0].id, test_project_1.id) - self.assertEqual(projects[1].id, test_project_2.id) - - def test_get_all_published_projects_returns_empty_list_when_no_published_projects( - self, - ): - """Test that get_all_published_projects returns empty list when no published projects""" - # Arrange - # Let's create a draft project to make sure it's not returned - self.create_project(is_published=False) - # Act - projects = self.service.get_all_published_projects() - # Assert - self.assertEqual(len(projects), 0) - self.assertEqual(projects, []) - - def test_get_all_published_projects_only_returns_required_fields_for_recommendation( - self, - ): - """Test that get_all_published_projects only returns required fields for recommendation""" - # Arrange - test_project = self.create_project() - # Act - projects = self.service.get_all_published_projects() - # Assert - self.assertEqual(len(projects), 1) - self.assertEqual(projects[0].id, test_project.id) - self.assertEqual(projects[0].mapping_types, test_project.mapping_types) - self.assertEqual(projects[0].default_locale, test_project.default_locale) - self.assertEqual(projects[0].difficulty, test_project.difficulty) - self.assertEqual(projects[0].country, test_project.country) - self.assertIsInstance(projects[0].interests, list) - self.assertEqual(len(projects[0]), 6) - - def test_mlb_transform_adds_new_transformed_columns(self): - """Test that mlb_transform adds new transformed columns""" - # Arrange - test_df = pd.DataFrame( - { - "id": [1, 2], - "mapping_types": [ - ["building", "waterway"], - ["building", "road"], - ], - } - ) - # Act - transformed_df = self.service.mlb_transform( - test_df, "mapping_types", "mapping_types_" - ) - # Assert - self.assertEqual(transformed_df.shape, (2, 4)) - self.assertEqual(transformed_df["mapping_types_building"].tolist(), [1, 1]) - self.assertEqual(transformed_df["mapping_types_waterway"].tolist(), [1, 0]) - self.assertEqual(transformed_df["mapping_types_road"].tolist(), [0, 1]) - self.assertEqual(transformed_df["id"].tolist(), [1, 2]) - - def test_mlb_transform_adds_new_transformed_columns_when_column_is_empty(self): - """Test that mlb_transform adds new transformed columns when column is empty""" - # Arrange - test_df = pd.DataFrame( - { - "id": [1, 2], - "mapping_types": [ - [], - [], - ], - } - ) - # Act - transformed_df = self.service.mlb_transform( - test_df, "mapping_types", "mapping_types_" - ) - # Assert - self.assertEqual(transformed_df.shape, (2, 1)) - self.assertEqual(transformed_df["id"].tolist(), [1, 2]) - - def test_one_hot_encoding_adds_new_transformed_columns(self): - """Test that one_hot_encoding adds new transformed columns""" - # Arrange - test_df = pd.DataFrame( - { - "id": [1, 2], - "mapping_types": [ - "building", - "waterway", - ], - } - ) - # Act - transformed_df = self.service.one_hot_encoding(test_df, ["mapping_types"]) - # Assert - self.assertEqual(transformed_df.shape, (2, 3)) - self.assertEqual(transformed_df["mapping_types_building"].tolist(), [1, 0]) - self.assertEqual(transformed_df["mapping_types_waterway"].tolist(), [0, 1]) - self.assertEqual(transformed_df["id"].tolist(), [1, 2]) - - def test_one_hot_encoding_adds_new_transformed_columns_when_column_is_empty(self): - """Test that one_hot_encoding adds new transformed columns when column is empty""" - # Arrange - test_df = pd.DataFrame( - { - "id": [1, 2], - "mapping_types": [ - None, - None, - ], - } - ) - # Act - transformed_df = self.service.one_hot_encoding(test_df, ["mapping_types"]) - # Assert - self.assertEqual(transformed_df.shape, (2, 1)) - self.assertEqual(transformed_df["id"].tolist(), [1, 2]) diff --git a/tests/backend/unit/services/test_stats_service.py b/tests/backend/unit/services/test_stats_service.py deleted file mode 100644 index 48947ce0ce..0000000000 --- a/tests/backend/unit/services/test_stats_service.py +++ /dev/null @@ -1,203 +0,0 @@ -from backend.models.postgis.project import Project -from backend.models.postgis.user import User -from backend.services.stats_service import StatsService, TaskStatus -from tests.backend.base import BaseTestCase - - -class TestStatsService(BaseTestCase): - def test_update_after_mapping_increments_counter(self): - # Arrange - test_project = Project() - test_project.tasks_mapped = 0 - - test_user = User() - test_user.tasks_mapped = 0 - - # Act - test_project, test_user = StatsService._update_tasks_stats( - test_project, test_user, TaskStatus.READY, TaskStatus.MAPPED - ) - - # Assert - self.assertEqual(test_project.tasks_mapped, 1) - self.assertEqual(test_user.tasks_mapped, 1) - - def test_same_state_keeps_counter(self): - # Arrange - test_project = Project() - test_project.tasks_mapped = 0 - - test_user = User() - test_user.tasks_mapped = 0 - - # Act - test_project, test_user = StatsService._update_tasks_stats( - test_project, test_user, TaskStatus.MAPPED, TaskStatus.MAPPED - ) - - # Assert - self.assertEqual(test_project.tasks_mapped, 0) - self.assertEqual(test_user.tasks_mapped, 0) - - def test_update_after_validating_increments_counter(self): - # Arrange - test_project = Project() - test_project.tasks_mapped = 1 - test_project.tasks_validated = 0 - - test_user = User() - test_user.tasks_validated = 0 - - # Act - test_project, test_user = StatsService._update_tasks_stats( - test_project, test_user, TaskStatus.MAPPED, TaskStatus.VALIDATED - ) - - # Assert - self.assertEqual(test_project.tasks_mapped, 0) - self.assertEqual(test_project.tasks_validated, 1) - self.assertEqual(test_user.tasks_validated, 1) - - def test_update_after_flagging_bad_imagery(self): - # Arrange - test_project = Project() - test_project.tasks_bad_imagery = 0 - - test_user = User() - test_user.tasks_invalidated = 0 - - # Act - test_project, test_user = StatsService._update_tasks_stats( - test_project, test_user, TaskStatus.READY, TaskStatus.BADIMAGERY - ) - - # Assert - self.assertEqual(test_project.tasks_bad_imagery, 1) - - def test_update_after_invalidating_mapped_task_sets_counters_correctly(self): - # Arrange - test_project = Project() - test_project.tasks_mapped = 1 - - test_user = User() - test_user.tasks_invalidated = 0 - - # Act - test_project, test_user = StatsService._update_tasks_stats( - test_project, test_user, TaskStatus.MAPPED, TaskStatus.INVALIDATED - ) - - # Assert - self.assertEqual(test_project.tasks_mapped, 0) - self.assertEqual(test_user.tasks_invalidated, 1) - - def test_update_after_invalidating_bad_imagery_task_sets_counters_correctly(self): - # Arrange - test_project = Project() - test_project.tasks_bad_imagery = 1 - - test_user = User() - test_user.tasks_invalidated = 0 - - # Act - test_project, test_user = StatsService._update_tasks_stats( - test_project, test_user, TaskStatus.BADIMAGERY, TaskStatus.INVALIDATED - ) - - # Assert - self.assertEqual(test_project.tasks_bad_imagery, 0) - self.assertEqual(test_user.tasks_invalidated, 1) - - def test_update_after_invalidating_validated_task_sets_counters_correctly(self): - # Arrange - test_project = Project() - test_project.tasks_validated = 1 - - test_user = User() - test_user.tasks_invalidated = 0 - - # Act - test_project, test_user = StatsService._update_tasks_stats( - test_project, test_user, TaskStatus.VALIDATED, TaskStatus.INVALIDATED - ) - - # Assert - self.assertEqual(test_project.tasks_validated, 0) - self.assertEqual(test_user.tasks_invalidated, 1) - - def test_tasks_state_representation(self): - # Arrange - test_project = Project() - test_project.tasks_mapped = 0 - test_project.tasks_validated = 0 - test_project.tasks_bad_imagery = 0 - - test_mapper = User() - test_mapper.tasks_mapped = 0 - test_mapper.tasks_validated = 0 - test_mapper.tasks_invalidated = 0 - - test_validator = User() - test_validator.tasks_mapped = 0 - test_validator.tasks_validated = 0 - test_validator.tasks_invalidated = 0 - - test_admin = User() - test_admin.tasks_mapped = 0 - test_admin.tasks_validated = 0 - test_admin.tasks_invalidated = 0 - - # Mapper marks task as mapped - test_project, test_mapper = StatsService._update_tasks_stats( - test_project, test_mapper, TaskStatus.READY, TaskStatus.MAPPED - ) - - # Validator marks task as bad imagery - test_project, test_validator = StatsService._update_tasks_stats( - test_project, test_validator, TaskStatus.MAPPED, TaskStatus.BADIMAGERY - ) - - # Admin undo marking task as bad imagery - test_project, test_admin = StatsService._update_tasks_stats( - test_project, test_admin, TaskStatus.BADIMAGERY, TaskStatus.MAPPED, "undo" - ) - - # Validator marks task as invalid - test_project, test_validator = StatsService._update_tasks_stats( - test_project, test_validator, TaskStatus.MAPPED, TaskStatus.INVALIDATED - ) - - # Mapper marks task as mapped - test_project, test_mapper = StatsService._update_tasks_stats( - test_project, test_mapper, TaskStatus.INVALIDATED, TaskStatus.MAPPED - ) - - # Admin undo marking task as mapped (test_mapper is given to the function though, as the author of the - # last_change - compare with MappingServer.undo_mapping() method) - test_project, test_mapper = StatsService._update_tasks_stats( - test_project, test_mapper, TaskStatus.MAPPED, TaskStatus.INVALIDATED, "undo" - ) - - # Mapper marks task as mapped - test_project, test_mapper = StatsService._update_tasks_stats( - test_project, test_mapper, TaskStatus.INVALIDATED, TaskStatus.MAPPED - ) - - # Validator marks task as valid - test_project, test_validator = StatsService._update_tasks_stats( - test_project, test_validator, TaskStatus.MAPPED, TaskStatus.VALIDATED - ) - - # Assert - self.assertEqual(test_project.tasks_mapped, 0) - self.assertEqual(test_project.tasks_validated, 1) - self.assertEqual(test_project.tasks_bad_imagery, 0) - self.assertEqual(test_mapper.tasks_mapped, 2) - self.assertEqual(test_mapper.tasks_validated, 0) - self.assertEqual(test_mapper.tasks_invalidated, 0) - self.assertEqual(test_validator.tasks_mapped, 0) - self.assertEqual(test_validator.tasks_validated, 1) - self.assertEqual(test_validator.tasks_invalidated, 1) - self.assertEqual(test_admin.tasks_mapped, 0) - self.assertEqual(test_admin.tasks_validated, 0) - self.assertEqual(test_admin.tasks_invalidated, 0) diff --git a/tests/backend/unit/services/test_team_service.py b/tests/backend/unit/services/test_team_service.py deleted file mode 100644 index c42f1c0cb1..0000000000 --- a/tests/backend/unit/services/test_team_service.py +++ /dev/null @@ -1,79 +0,0 @@ -from backend.exceptions import NotFound -from backend.models.dtos.team_dto import TeamSearchDTO -from backend.services.team_service import TeamService -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_team, create_canned_user - - -class TestTeamService(BaseTestCase): - def setUp(self): - super().setUp() - self.test_user = create_canned_user() - self.test_team = create_canned_team() - - def test_search_team(self): - # Arrange - team_search_dto = TeamSearchDTO() - team_search_dto.user_id = self.test_user.id - team_search_dto.team_name = self.test_team.name - team_search_dto.member = self.test_user.id - team_search_dto.organisation = self.test_team.organisation_id - - # Act - result = TeamService.get_all_teams(team_search_dto) - # Assert - self.assertEqual(len(result.to_primitive()["teams"]), 1) - self.assertEqual(result.to_primitive()["teams"][0]["teamId"], self.test_team.id) - self.assertEqual(result.to_primitive()["teams"][0]["name"], self.test_team.name) - self.assertEqual( - result.to_primitive()["teams"][0]["organisationId"], - self.test_team.organisation_id, - ) - - def test_get_team_as_dto(self): - # Arrange - team_id = self.test_team.id - user_id = self.test_user.id - abbreviated = False - # Act - result = TeamService.get_team_as_dto(team_id, user_id, abbreviated) - # Assert - self.assertEqual(result.team_id, self.test_team.id) - - def test_add_team_project(self): - # Arrange - team_id = self.test_team.id - user_id = self.test_user.id - function = 1 - active = True - # Act - TeamService.add_team_member(team_id, user_id, function, active) - # Assert - self.assertTrue( - TeamService.is_user_an_active_team_member( - self.test_team.id, self.test_user.id - ) - ) - - def test_delete_team_project(self): - # Act - TeamService.delete_team(self.test_team.id) - # Assert - with self.assertRaises(NotFound): - TeamService.get_team_by_id(self.test_team.id) - - def test_leave_team(self): - # Arrange - team_id = self.test_team.id - username = self.test_user.username - function = 1 - active = True - TeamService.add_team_member(team_id, self.test_user.id, function, active) - # Act - TeamService.leave_team(team_id, username) - # Assert - self.assertFalse( - TeamService.is_user_an_active_team_member( - self.test_team.id, self.test_user.id - ) - ) diff --git a/tests/backend/unit/services/test_validator_service.py b/tests/backend/unit/services/test_validator_service.py deleted file mode 100644 index 08bd2da8bc..0000000000 --- a/tests/backend/unit/services/test_validator_service.py +++ /dev/null @@ -1,218 +0,0 @@ -from unittest.mock import patch - -from backend.models.dtos.validator_dto import ValidatedTask -from backend.services.users.user_service import UserService -from backend.services.validator_service import ( - LockForValidationDTO, - NotFound, - ProjectService, - Task, - TaskStatus, - UnlockAfterValidationDTO, - UserLicenseError, - ValidatingNotAllowed, - ValidatorService, - ValidatorServiceError, -) -from tests.backend.base import BaseTestCase - - -class TestValidatorService(BaseTestCase): - unlock_task_stub = Task - - def setUp(self): - super().setUp() - self.unlock_task_stub = Task() - self.unlock_task_stub.task_status = TaskStatus.MAPPED.value - self.unlock_task_stub.lock_holder_id = 123456 - - @patch.object(Task, "get") - def test_lock_tasks_for_validation_raises_error_if_task_not_found(self, mock_task): - # Arrange - mock_task.return_value = None - - lock_dto = LockForValidationDTO() - lock_dto.project_id = 1 - lock_dto.task_ids = [1, 2] - - # Act / Assert - with self.assertRaises(NotFound): - ValidatorService.lock_tasks_for_validation(lock_dto) - - @patch.object(UserService, "is_user_blocked") - @patch.object(Task, "get") - def test_lock_tasks_for_validation_raises_error_if_task_not_mapped( - self, mock_task, mock_blocked - ): - # Arrange - task_stub = Task() - task_stub.task_status = TaskStatus.READY.value - mock_task.return_value = task_stub - mock_blocked.return_value = False - - lock_dto = LockForValidationDTO() - lock_dto.project_id = 1 - lock_dto.task_ids = [1, 2] - - # Act / Assert - with self.assertRaises(ValidatorServiceError): - ValidatorService.lock_tasks_for_validation(lock_dto) - - @patch.object(UserService, "is_user_an_admin") - @patch.object(Task, "get") - @patch.object(ProjectService, "is_user_permitted_to_validate") - def test_lock_tasks_raises_error_if_project_validator_only_and_user_not_validator( - self, mock_project, mock_task, mock_user - ): - # Arrange - task_stub = Task() - task_stub.task_status = TaskStatus.MAPPED.value - mock_task.return_value = task_stub - mock_project.return_value = False, ValidatingNotAllowed.USER_NOT_VALIDATOR - mock_user.return_value = True - - lock_dto = LockForValidationDTO() - lock_dto.project_id = 1 - lock_dto.task_ids = [1, 2] - lock_dto.user_id = 1234 - - with self.assertRaises(ValidatorServiceError): - ValidatorService.lock_tasks_for_validation(lock_dto) - - @patch.object(UserService, "is_user_an_admin") - @patch.object(Task, "get") - @patch.object(ProjectService, "is_user_permitted_to_validate") - def test_lock_tasks_raises_error_if_user_has_not_accepted_license( - self, mock_project, mock_task, mock_user - ): - # Arrange - task_stub = Task() - task_stub.task_status = TaskStatus.MAPPED.value - mock_task.return_value = task_stub - - mock_project.return_value = ( - False, - ValidatingNotAllowed.USER_NOT_ACCEPTED_LICENSE, - ) - mock_user.return_value = True - - lock_dto = LockForValidationDTO() - lock_dto.project_id = 1 - lock_dto.task_ids = [1, 2] - lock_dto.user_id = 123 - lock_dto.mapped_by = 1234 - - with self.assertRaises(UserLicenseError): - ValidatorService.lock_tasks_for_validation(lock_dto) - - @patch.object(Task, "get") - def test_unlock_tasks_for_validation_raises_error_if_task_not_found( - self, mock_task - ): - # Arrange - mock_task.return_value = None - - validated_task = ValidatedTask() - validated_task.task_id = 1 - validated_tasks = [validated_task] - - unlock_dto = UnlockAfterValidationDTO() - unlock_dto.project_id = 1 - unlock_dto.validated_tasks = validated_tasks - - # Act / Assert - with self.assertRaises(NotFound): - ValidatorService.unlock_tasks_after_validation(unlock_dto) - - @patch.object(Task, "get") - def test_unlock_tasks_for_validation_raises_error_if_task_not_done_or_validated( - self, mock_task - ): - # Arrange - self.unlock_task_stub.task_status = TaskStatus.READY.value - mock_task.return_value = self.unlock_task_stub - - validated_task = ValidatedTask() - validated_task.task_id = 1 - validated_tasks = [validated_task] - - unlock_dto = UnlockAfterValidationDTO() - unlock_dto.project_id = 1 - unlock_dto.validated_tasks = validated_tasks - - # Act / Assert - with self.assertRaises(ValidatorServiceError): - ValidatorService.unlock_tasks_after_validation(unlock_dto) - - @patch.object(Task, "get") - def test_unlock_tasks_for_validation_raises_error_if_task_not_locked( - self, mock_task - ): - # Arrange - self.unlock_task_stub.task_locked = False - mock_task.return_value = self.unlock_task_stub - - validated_task = ValidatedTask() - validated_task.task_id = 1 - validated_tasks = [validated_task] - - unlock_dto = UnlockAfterValidationDTO() - unlock_dto.project_id = 1 - unlock_dto.validated_tasks = validated_tasks - - # Act / Assert - with self.assertRaises(ValidatorServiceError): - ValidatorService.unlock_tasks_after_validation(unlock_dto) - - @patch.object(Task, "get") - def test_unlock_tasks_for_validation_raises_error_if_user_doesnt_own_the_lock( - self, mock_task - ): - mock_task.return_value = self.unlock_task_stub - - validated_task = ValidatedTask() - validated_task.task_id = 1 - validated_tasks = [validated_task] - - unlock_dto = UnlockAfterValidationDTO() - unlock_dto.project_id = 1 - unlock_dto.validated_tasks = validated_tasks - unlock_dto.user_id = 12 - - # Act / Assert - with self.assertRaises(ValidatorServiceError): - ValidatorService.unlock_tasks_after_validation(unlock_dto) - - @patch.object(UserService, "is_user_an_admin") - def test_user_can_validate_task_returns_false_when_user_not_a_pm_and_validating_own_task( - self, mock_user - ): - # Arrange - mock_user.return_value = False - user_id = 1234 - mapped_by = 1234 - - # act - user_can_validate_task = ValidatorService._user_can_validate_task( - user_id, mapped_by - ) - - # assert - self.assertFalse(user_can_validate_task) - - @patch.object(UserService, "is_user_an_admin") - def test_user_can_validate_task_returns_true_when_user_not_a_pm_and_not_validating_own_task( - self, mock_user - ): - # Arrange - mock_user.return_value = False - user_id = 5678 - mapped_by = 1234 - - # act - user_can_validate_task = ValidatorService._user_can_validate_task( - user_id, mapped_by - ) - - # assert - self.assertTrue(user_can_validate_task) diff --git a/tests/backend/unit/services/users/__init__.py b/tests/backend/unit/services/users/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/backend/unit/services/users/test_authentication_service.py b/tests/backend/unit/services/users/test_authentication_service.py deleted file mode 100644 index 86c44e560e..0000000000 --- a/tests/backend/unit/services/users/test_authentication_service.py +++ /dev/null @@ -1,67 +0,0 @@ -from urllib.parse import parse_qs, urlparse - -from backend.services.messaging.smtp_service import SMTPService -from backend.services.users.authentication_service import AuthenticationService -from tests.backend.base import BaseTestCase - - -class TestAuthenticationService(BaseTestCase): - def test_generate_session_token_for_user_returns_session_token(self): - # Act - session_token = AuthenticationService.generate_session_token_for_user(12345678) - - # Assert - self.assertIsNotNone(session_token) - - def test_is_valid_token_validates_user_token(self): - # Arrange - session_token = AuthenticationService.generate_session_token_for_user(12345678) - invalid_session_token = session_token + "x" - - # Act - is_valid_token, user_id = AuthenticationService.is_valid_token( - session_token, 604800 - ) - is_invalid_token, _user_id = AuthenticationService.is_valid_token( - invalid_session_token, 604800 - ) - - # Assert - self.assertEqual(user_id, 12345678) - self.assertTrue(is_valid_token) - self.assertFalse(is_invalid_token) - # Since token is invalid it should return the error message instead of the user id - self.assertEqual(_user_id, "BadSignature- Bad Token Signature") - - def test_get_authentication_failed_url_returns_expected_url(self): - # Act - auth_failed_url = AuthenticationService.get_authentication_failed_url() - - # Assert - parsed_url = urlparse(auth_failed_url) - self.assertEqual(parsed_url.path, "/auth-failed") - - def test_get_email_validated_url_returns_expected_url(self): - # Act - auth_failed_url = AuthenticationService._get_email_validated_url(True) - - # Assert - parsed_url = urlparse(auth_failed_url) - self.assertEqual(parsed_url.path, "/validate-email") - - def test_can_parse_email_verification_token(self): - # Arrange - Generate valid email verification url - test_email = "test@test.com" - auth_url = SMTPService._generate_email_verification_url(test_email, "mrtest") - - parsed_url = urlparse(auth_url) - query = parse_qs(parsed_url.query) - - # Arrange - is_valid, email_address = AuthenticationService.is_valid_token( - query["token"][0], 86400 - ) - - # Assert - self.assertTrue(is_valid) - self.assertEqual(email_address, test_email) diff --git a/tests/backend/unit/services/users/test_osm_service.py b/tests/backend/unit/services/users/test_osm_service.py deleted file mode 100644 index b431554914..0000000000 --- a/tests/backend/unit/services/users/test_osm_service.py +++ /dev/null @@ -1,21 +0,0 @@ -from backend.services.users.osm_service import OSMService, OSMServiceError -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import get_canned_osm_user_json_details - - -class TestOsmService(BaseTestCase): - def test_parse_osm_user_details_raises_error_if_user_not_found(self): - # Arrange - osm_response = get_canned_osm_user_json_details() - # Act/Assert - with self.assertRaises(OSMServiceError): - OSMService._parse_osm_user_details_response(osm_response, "wont-find") - - def test_parse_osm_user_details_can_parse_valid_osm_response(self): - # Arrange - osm_response = get_canned_osm_user_json_details() - # Act - dto = OSMService._parse_osm_user_details_response(osm_response, "user") - # Assert - self.assertEqual(dto.account_created, "2017-01-23T16:23:22Z") - self.assertEqual(dto.changeset_count, 16) diff --git a/tests/backend/unit/services/users/test_user_service.py b/tests/backend/unit/services/users/test_user_service.py deleted file mode 100644 index b6221c6784..0000000000 --- a/tests/backend/unit/services/users/test_user_service.py +++ /dev/null @@ -1,84 +0,0 @@ -from unittest.mock import patch - -from backend.models.postgis.user import User -from backend.services.users.user_service import ( - NotFound, - UserRole, - UserService, - UserServiceError, -) -from tests.backend.base import BaseTestCase -from tests.backend.helpers.test_helpers import create_canned_user, return_canned_user - - -class TestUserService(BaseTestCase): - def test_get_user_by_id_returns_user(self): - # Arrange - test_user = create_canned_user() - # Act - user = UserService.get_user_by_id(777777) - # Assert - self.assertEqual(user.username, test_user.username) - - def test_get_user_by_id_raises_error_if_user_not_found(self): - # Act/Assert - with self.assertRaises(NotFound): - UserService.get_user_by_id(123456) - - def test_get_user_by_username_returns_user(self): - # Arrange - test_user = create_canned_user() - # Act - user = UserService.get_user_by_username(test_user.username) - # Assert - self.assertEqual(user.id, 777777) - - def test_get_user_by_username_raises_error_if_user_not_found(self): - # Act/Assert - with self.assertRaises(NotFound): - UserService.get_user_by_username("Thinkwhere") - - def test_is_user_admin_returns_true_for_admin(self): - # Arrange - user = return_canned_user() - user.role = UserRole.ADMIN.value - user.create() - - # Act - self.assertTrue(UserService.is_user_an_admin(user.id)) - - def test_is_user_admin_returns_false_for_non_admin(self): - # Arrange - user = create_canned_user() - # Act - self.assertFalse(UserService.is_user_an_admin(user.id)) - - @patch.object(UserService, "get_user_by_id") - def test_mapper_role_is_not_recognized_as_a_validator(self, mock_user): - # Arrange - stub_user = User() - stub_user.role = UserRole.MAPPER.value - mock_user.return_value = stub_user - - # Act / Assert - self.assertFalse(UserService.is_user_validator(123)) - - @patch.object(UserService, "get_user_by_id") - def test_admin_role_is_recognized_as_a_validator(self, mock_user): - # Arrange - stub_user = User() - stub_user.role = UserRole.ADMIN.value - mock_user.return_value = stub_user - - # Act / Assert - self.assertTrue(UserService.is_user_validator(123)) - - def test_unknown_role_raise_error_when_setting_role(self): - # Act / Assert - with self.assertRaises(UserServiceError): - UserService.add_role_to_user(1, "test", "TEST") - - def test_unknown_level_raise_error_when_setting_level(self): - # Act / Assert - with self.assertRaises(UserServiceError): - UserService.set_user_mapping_level("test", "TEST")