597 lines
25 KiB
Python
597 lines
25 KiB
Python
from django.test import TestCase, Client
|
|
from django.contrib.auth import get_user_model
|
|
from django.urls import reverse
|
|
from django.contrib.gis.geos import Polygon, MultiPolygon, Point
|
|
|
|
from common.models import Thematic, Role, UserConfig, UserThematics
|
|
from assets.models import (
|
|
ManagementZoneType,
|
|
ManagementZone,
|
|
ManagementZoneAsset,
|
|
NatureGreenSurface,
|
|
NatureLocation,
|
|
)
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
class ManagementZoneModelTests(TestCase):
|
|
def setUp(self):
|
|
self.thematic_nature = Thematic.objects.create(
|
|
code="nature",
|
|
name_fr="Nature",
|
|
name_nl="Natuur"
|
|
)
|
|
self.zone_type = ManagementZoneType.objects.create(
|
|
code="fauche_tardive",
|
|
name_fr="Fauche tardive",
|
|
name_nl="Laat maaien",
|
|
thematic=self.thematic_nature,
|
|
default_color="#28a745",
|
|
description="Zone de gestion écologique avec fauche annuelle en automne."
|
|
)
|
|
|
|
def test_management_zone_type_bilingual_and_str(self):
|
|
self.assertEqual(self.zone_type.name_fr, "Fauche tardive")
|
|
self.assertEqual(self.zone_type.name_nl, "Laat maaien")
|
|
self.assertIn("Fauche tardive", str(self.zone_type))
|
|
|
|
def test_management_zone_creation_geometry_and_color_fallback(self):
|
|
poly = Polygon(((0, 0), (100, 0), (100, 100), (0, 100), (0, 0)))
|
|
multi_poly = MultiPolygon([poly], srid=3812)
|
|
|
|
# 1. Sans couleur explicite -> prend la couleur par défaut du type
|
|
zone1 = ManagementZone.objects.create(
|
|
code="ZG-NAT-001",
|
|
name_fr="Marais de Jette - Prairie",
|
|
name_nl="Moeras van Jette - Weide",
|
|
thematic=self.thematic_nature,
|
|
zone_type=self.zone_type,
|
|
geom=multi_poly,
|
|
target_frequency_days=365,
|
|
seasonality_notes="Fauche en septembre; pas de taille au printemps",
|
|
instructions="Attention aux zones humides et aux ornières.",
|
|
)
|
|
self.assertEqual(zone1.get_color(), "#28a745")
|
|
self.assertEqual(zone1.geom.srid, 3812)
|
|
self.assertEqual(zone1.geom.geom_type, "MultiPolygon")
|
|
|
|
# GeoJSON property
|
|
geojson = zone1.geojson_geometry
|
|
self.assertIsNotNone(geojson)
|
|
self.assertEqual(geojson["type"], "MultiPolygon")
|
|
|
|
# Spatial intersection
|
|
pt_inside = Point(50, 50, srid=3812)
|
|
pt_outside = Point(200, 200, srid=3812)
|
|
self.assertTrue(ManagementZone.objects.filter(pk=zone1.pk, geom__intersects=pt_inside).exists())
|
|
self.assertFalse(ManagementZone.objects.filter(pk=zone1.pk, geom__intersects=pt_outside).exists())
|
|
|
|
# 2. Avec couleur personnalisée explicite
|
|
zone2 = ManagementZone.objects.create(
|
|
code="ZG-NAT-002",
|
|
name_fr="Zone spéciale",
|
|
thematic=self.thematic_nature,
|
|
color="#ff5722",
|
|
)
|
|
self.assertEqual(zone2.get_color(), "#ff5722")
|
|
|
|
|
|
class ManagementZoneAssetTests(TestCase):
|
|
def setUp(self):
|
|
self.thematic_nature = Thematic.objects.create(code="nature", name_fr="Nature", name_nl="Natuur")
|
|
self.zone = ManagementZone.objects.create(
|
|
code="ZG-NAT-TEST",
|
|
name_fr="Zone test",
|
|
thematic=self.thematic_nature,
|
|
)
|
|
self.location = NatureLocation.objects.create(code="LOC-01", name_fr="Parc de Jette")
|
|
self.green_surface = NatureGreenSurface.objects.create(
|
|
code="GS-01",
|
|
name_fr="Pelouse 1",
|
|
location=self.location,
|
|
)
|
|
|
|
def test_explicit_asset_association_and_exclusion(self):
|
|
# Association explicite d'inclusion
|
|
link = ManagementZoneAsset.objects.create(
|
|
management_zone=self.zone,
|
|
asset=self.green_surface,
|
|
is_excluded=False,
|
|
notes="Inclus dans le plan"
|
|
)
|
|
self.assertIn("Inclus", str(link))
|
|
self.assertEqual(self.zone.explicit_assets.count(), 1)
|
|
self.assertEqual(self.zone.explicit_assets.first().asset, self.green_surface)
|
|
|
|
# Bascule en exclusion
|
|
link.is_excluded = True
|
|
link.save()
|
|
self.assertIn("Exclu", str(link))
|
|
|
|
|
|
class ManagementZoneGeojsonEndpointTests(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create_user(username="nature_manager", password="password")
|
|
self.role_manager = Role.objects.create(name="manager")
|
|
self.config = UserConfig.objects.create(user=self.user)
|
|
self.config.roles.add(self.role_manager)
|
|
|
|
self.thematic_nature = Thematic.objects.create(code="nature", name_fr="Nature", name_nl="Natuur")
|
|
self.thematic_roads = Thematic.objects.create(code="roads", name_fr="Voiries", name_nl="Wegen")
|
|
|
|
UserThematics.objects.create(
|
|
user_config=self.config,
|
|
thematic=self.thematic_nature,
|
|
can_view_assets=True,
|
|
can_edit_assets=True
|
|
)
|
|
|
|
self.zone_type = ManagementZoneType.objects.create(
|
|
code="fauche",
|
|
name_fr="Fauche tardive",
|
|
thematic=self.thematic_nature,
|
|
default_color="#198754"
|
|
)
|
|
|
|
poly = Polygon(((0, 0), (10, 0), (10, 10), (0, 10), (0, 0)))
|
|
self.multi_poly = MultiPolygon([poly], srid=3812)
|
|
|
|
self.zone_nature = ManagementZone.objects.create(
|
|
code="ZG-NAT-1",
|
|
name_fr="Prairie fleurie",
|
|
thematic=self.thematic_nature,
|
|
zone_type=self.zone_type,
|
|
geom=self.multi_poly,
|
|
instructions="Ne pas tondre au printemps",
|
|
target_frequency_days=180,
|
|
seasonality_notes="Septembre",
|
|
)
|
|
|
|
self.zone_roads = ManagementZone.objects.create(
|
|
code="ZG-ROAD-1",
|
|
name_fr="Itinéraire déneigement P1",
|
|
thematic=self.thematic_roads,
|
|
geom=self.multi_poly,
|
|
color="#0d6efd",
|
|
)
|
|
|
|
def test_anonymous_access_redirects(self):
|
|
url = reverse("assets:management_zones_geojson")
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 302)
|
|
|
|
def test_authenticated_user_access_nature_zones(self):
|
|
self.client.login(username="nature_manager", password="password")
|
|
url = reverse("assets:management_zones_geojson") + "?thematic=nature"
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
data = response.json()
|
|
self.assertEqual(data["type"], "FeatureCollection")
|
|
self.assertEqual(len(data["features"]), 1)
|
|
|
|
feat = data["features"][0]
|
|
self.assertEqual(feat["id"], self.zone_nature.id)
|
|
self.assertEqual(feat["properties"]["code"], "ZG-NAT-1")
|
|
self.assertEqual(feat["properties"]["name"], "Prairie fleurie")
|
|
self.assertEqual(feat["properties"]["thematic"], "nature")
|
|
self.assertEqual(feat["properties"]["zone_type_name"], "Fauche tardive")
|
|
self.assertEqual(feat["properties"]["color"], "#198754")
|
|
self.assertEqual(feat["properties"]["instructions"], "Ne pas tondre au printemps")
|
|
self.assertEqual(feat["properties"]["target_frequency_days"], 180)
|
|
self.assertEqual(feat["geometry"]["type"], "MultiPolygon")
|
|
|
|
def test_user_without_thematic_permission_denied(self):
|
|
self.client.login(username="nature_manager", password="password")
|
|
# nature_manager n'a pas accès à la thématique 'roads'
|
|
url = reverse("assets:management_zones_geojson") + "?thematic=roads"
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 403)
|
|
|
|
def test_superuser_access_all_thematics(self):
|
|
admin = User.objects.create_superuser(username="superadmin", password="password", email="admin@example.com")
|
|
self.client.login(username="superadmin", password="password")
|
|
|
|
# Sans paramètre thématique, superuser reçoit toutes les zones avec géométrie
|
|
url = reverse("assets:management_zones_geojson")
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 200)
|
|
data = response.json()
|
|
self.assertEqual(len(data["features"]), 2)
|
|
|
|
|
|
import json
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
from assets.permissions import (
|
|
can_view_management_zones,
|
|
can_edit_management_zones,
|
|
can_delete_management_zone,
|
|
get_editable_thematics_for_management_zones,
|
|
)
|
|
from assets.forms import ManagementZoneForm
|
|
from assets.models import ManagementZoneDocument
|
|
|
|
|
|
class ManagementZonesPermissionAndCRUDTests(TestCase):
|
|
def setUp(self):
|
|
# Users
|
|
self.user_manager = User.objects.create_user(username="mgr", password="password")
|
|
self.user_viewer = User.objects.create_user(username="viewer", password="password")
|
|
self.user_editor = User.objects.create_user(username="editor", password="password")
|
|
self.user_no_access = User.objects.create_user(username="no_access", password="password")
|
|
|
|
# Thematics
|
|
self.thematic_nature = Thematic.objects.create(code="nature", name_fr="Nature", name_nl="Natuur")
|
|
self.thematic_roads = Thematic.objects.create(code="roads", name_fr="Voiries", name_nl="Wegen")
|
|
|
|
# Roles & Configs
|
|
self.role_manager = Role.objects.create(name="manager")
|
|
self.role_operator = Role.objects.create(name="operator")
|
|
|
|
self.config_mgr = UserConfig.objects.create(user=self.user_manager)
|
|
self.config_mgr.roles.add(self.role_manager)
|
|
|
|
self.config_viewer = UserConfig.objects.create(user=self.user_viewer)
|
|
UserThematics.objects.create(
|
|
user_config=self.config_viewer,
|
|
thematic=self.thematic_nature,
|
|
can_view_assets=True,
|
|
can_edit_assets=False,
|
|
can_edit_management_zones=False
|
|
)
|
|
|
|
self.config_editor = UserConfig.objects.create(user=self.user_editor)
|
|
UserThematics.objects.create(
|
|
user_config=self.config_editor,
|
|
thematic=self.thematic_nature,
|
|
can_view_assets=True,
|
|
can_edit_assets=False,
|
|
can_edit_management_zones=True # Specific permission
|
|
)
|
|
|
|
self.config_no_access = UserConfig.objects.create(user=self.user_no_access)
|
|
|
|
# Type de zone
|
|
self.zone_type = ManagementZoneType.objects.create(
|
|
code="fauche_eco",
|
|
name_fr="Fauche écologique",
|
|
thematic=self.thematic_nature,
|
|
default_color="#20c997"
|
|
)
|
|
|
|
poly = Polygon(((0, 0), (50, 0), (50, 50), (0, 50), (0, 0)))
|
|
self.zone = ManagementZone.objects.create(
|
|
code="ZG-TEST-01",
|
|
name_fr="Zone Test Marais",
|
|
name_nl="Testzone Moeras",
|
|
thematic=self.thematic_nature,
|
|
zone_type=self.zone_type,
|
|
geom=MultiPolygon([poly], srid=3812),
|
|
target_frequency_days=90,
|
|
seasonality_notes="Avril-Septembre",
|
|
instructions="Attention à la faune aquatique",
|
|
is_active=True
|
|
)
|
|
|
|
def test_permission_functions(self):
|
|
# Manager can view and edit any thematic
|
|
self.assertTrue(can_view_management_zones(self.user_manager))
|
|
self.assertTrue(can_edit_management_zones(self.user_manager))
|
|
self.assertTrue(can_edit_management_zones(self.user_manager, thematic=self.thematic_nature))
|
|
|
|
# Viewer can view nature, but cannot edit
|
|
self.assertTrue(can_view_management_zones(self.user_viewer, thematic=self.thematic_nature))
|
|
self.assertFalse(can_view_management_zones(self.user_viewer, thematic=self.thematic_roads))
|
|
self.assertFalse(can_edit_management_zones(self.user_viewer))
|
|
self.assertFalse(can_edit_management_zones(self.user_viewer, thematic=self.thematic_nature))
|
|
|
|
# Editor with can_edit_management_zones=True
|
|
self.assertTrue(can_view_management_zones(self.user_editor, thematic=self.thematic_nature))
|
|
self.assertTrue(can_edit_management_zones(self.user_editor))
|
|
self.assertTrue(can_edit_management_zones(self.user_editor, thematic=self.thematic_nature))
|
|
self.assertFalse(can_edit_management_zones(self.user_editor, thematic=self.thematic_roads))
|
|
|
|
# Editable thematics
|
|
editable = get_editable_thematics_for_management_zones(self.user_editor)
|
|
self.assertIn(self.thematic_nature, editable)
|
|
self.assertNotIn(self.thematic_roads, editable)
|
|
|
|
def test_management_zone_form_with_geom_geojson(self):
|
|
# Test initial geojson
|
|
form = ManagementZoneForm(instance=self.zone, user=self.user_editor)
|
|
self.assertIn('geom_geojson', form.initial)
|
|
geom_dict = json.loads(form.initial['geom_geojson'])
|
|
self.assertEqual(geom_dict['type'], 'MultiPolygon')
|
|
|
|
# Test saving with new GeoJSON polygon in WGS84
|
|
geojson_polygon = {
|
|
"type": "Polygon",
|
|
"coordinates": [[[4.35, 50.84], [4.36, 50.84], [4.36, 50.85], [4.35, 50.85], [4.35, 50.84]]]
|
|
}
|
|
data = {
|
|
'code': 'ZG-NEW-01',
|
|
'name_fr': 'Nouvelle zone',
|
|
'thematic': self.thematic_nature.pk,
|
|
'zone_type': self.zone_type.pk,
|
|
'color': '#ff9900',
|
|
'target_frequency_days': 30,
|
|
'geom_geojson': json.dumps(geojson_polygon),
|
|
'is_active': True,
|
|
}
|
|
form = ManagementZoneForm(data=data, user=self.user_editor)
|
|
self.assertTrue(form.is_valid(), form.errors)
|
|
new_zone = form.save()
|
|
self.assertEqual(new_zone.code, 'ZG-NEW-01')
|
|
self.assertIsNotNone(new_zone.geom)
|
|
self.assertEqual(new_zone.geom.srid, 3812)
|
|
self.assertEqual(new_zone.geom.geom_type, 'MultiPolygon')
|
|
|
|
def test_management_zones_index_view(self):
|
|
url = reverse("assets:management_zones_index")
|
|
|
|
# Anonymous -> 302
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 302)
|
|
|
|
# No access user -> 403
|
|
self.client.login(username="no_access", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 403)
|
|
|
|
# Viewer -> 200
|
|
self.client.login(username="viewer", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
self.assertContains(res, "ZG-TEST-01")
|
|
self.assertFalse(res.context['can_create'])
|
|
|
|
# Editor -> 200 and can_create is True
|
|
self.client.login(username="editor", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
self.assertTrue(res.context['can_create'])
|
|
|
|
def test_management_zone_create_view(self):
|
|
url = reverse("assets:management_zone_create")
|
|
|
|
# Viewer cannot create -> 403
|
|
self.client.login(username="viewer", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 403)
|
|
|
|
# Editor can access form
|
|
self.client.login(username="editor", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
self.assertContains(res, "layer-switcher-control.js")
|
|
self.assertContains(res, "AddressSearchControl")
|
|
|
|
# Post valid zone
|
|
geojson_polygon = {
|
|
"type": "Polygon",
|
|
"coordinates": [[[4.35, 50.84], [4.36, 50.84], [4.36, 50.85], [4.35, 50.85], [4.35, 50.84]]]
|
|
}
|
|
post_data = {
|
|
'code': 'ZG-CREATED-01',
|
|
'name_fr': 'Zone créée',
|
|
'thematic': self.thematic_nature.pk,
|
|
'zone_type': self.zone_type.pk,
|
|
'color': '#28a745',
|
|
'target_frequency_days': 15,
|
|
'geom_geojson': json.dumps(geojson_polygon),
|
|
'instructions': 'Passage le matin uniquement',
|
|
'is_active': True,
|
|
}
|
|
res = self.client.post(url, post_data)
|
|
self.assertEqual(res.status_code, 302)
|
|
|
|
created_zone = ManagementZone.objects.get(code='ZG-CREATED-01')
|
|
self.assertEqual(created_zone.created_by, self.user_editor)
|
|
self.assertEqual(created_zone.instructions, 'Passage le matin uniquement')
|
|
self.assertEqual(created_zone.geom.srid, 3812)
|
|
|
|
def test_management_zone_edit_view(self):
|
|
url = reverse("assets:management_zone_edit", kwargs={'pk': self.zone.pk})
|
|
|
|
# Viewer cannot edit -> 403
|
|
self.client.login(username="viewer", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 403)
|
|
|
|
# Editor can edit
|
|
self.client.login(username="editor", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
self.assertContains(res, "layer-switcher-control.js")
|
|
self.assertContains(res, "AddressSearchControl")
|
|
|
|
post_data = {
|
|
'code': self.zone.code,
|
|
'name_fr': 'Nom Modifié Marais',
|
|
'thematic': self.thematic_nature.pk,
|
|
'zone_type': self.zone_type.pk,
|
|
'color': '#ff5500',
|
|
'target_frequency_days': 120,
|
|
'geom_geojson': json.dumps({
|
|
"type": "Polygon",
|
|
"coordinates": [[[4.35, 50.84], [4.37, 50.84], [4.37, 50.86], [4.35, 50.86], [4.35, 50.84]]]
|
|
}),
|
|
'instructions': 'Consigne mise à jour',
|
|
'is_active': True,
|
|
}
|
|
res = self.client.post(url, post_data)
|
|
self.assertEqual(res.status_code, 302)
|
|
|
|
self.zone.refresh_from_db()
|
|
self.assertEqual(self.zone.name_fr, 'Nom Modifié Marais')
|
|
self.assertEqual(self.zone.color, '#ff5500')
|
|
self.assertEqual(self.zone.target_frequency_days, 120)
|
|
|
|
def test_management_zone_detail_view(self):
|
|
url = reverse("assets:management_zone_detail", kwargs={'pk': self.zone.pk})
|
|
|
|
# Viewer can view
|
|
self.client.login(username="viewer", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
self.assertContains(res, "ZG-TEST-01")
|
|
self.assertFalse(res.context['can_edit'])
|
|
|
|
# Editor can view with can_edit=True
|
|
self.client.login(username="editor", password="password")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
self.assertTrue(res.context['can_edit'])
|
|
|
|
def test_management_zone_delete_view(self):
|
|
zone_to_del = ManagementZone.objects.create(
|
|
code="ZG-TO-DELETE",
|
|
name_fr="A supprimer",
|
|
thematic=self.thematic_nature,
|
|
)
|
|
url = reverse("assets:management_zone_delete", kwargs={'pk': zone_to_del.pk})
|
|
|
|
# Viewer cannot delete -> 403
|
|
self.client.login(username="viewer", password="password")
|
|
res = self.client.post(url)
|
|
self.assertEqual(res.status_code, 403)
|
|
|
|
# Editor can delete
|
|
self.client.login(username="editor", password="password")
|
|
res = self.client.post(url)
|
|
self.assertEqual(res.status_code, 302)
|
|
self.assertFalse(ManagementZone.objects.filter(pk=zone_to_del.pk).exists())
|
|
|
|
def test_management_zone_document_upload_and_delete(self):
|
|
self.client.login(username="editor", password="password")
|
|
|
|
# Upload document
|
|
upload_url = reverse("assets:management_zone_add_document", kwargs={'pk': self.zone.pk})
|
|
fake_file = SimpleUploadedFile("rapport_tonte.pdf", b"Dummy PDF content", content_type="application/pdf")
|
|
res = self.client.post(upload_url, {'documents': [fake_file]})
|
|
self.assertEqual(res.status_code, 302)
|
|
|
|
self.assertEqual(self.zone.documents.count(), 1)
|
|
doc = self.zone.documents.first()
|
|
self.assertEqual(doc.uploaded_by, self.user_editor)
|
|
|
|
# Delete document
|
|
delete_url = reverse("assets:management_zone_delete_document", kwargs={'pk': self.zone.pk, 'document_id': doc.pk})
|
|
res = self.client.post(delete_url)
|
|
self.assertEqual(res.status_code, 302)
|
|
self.assertEqual(self.zone.documents.count(), 0)
|
|
|
|
def test_management_zone_types_ajax(self):
|
|
self.client.login(username="editor", password="password")
|
|
url = reverse("assets:management_zone_types_ajax") + f"?thematic_id={self.thematic_nature.pk}"
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
data = res.json()
|
|
self.assertEqual(len(data['types']), 1)
|
|
self.assertEqual(data['types'][0]['code'], 'fauche_eco')
|
|
|
|
|
|
class ManagementZoneUnifiedViewIntegrationTests(TestCase):
|
|
def setUp(self):
|
|
self.thematic_nature = Thematic.objects.create(name_fr="Nature", name_nl="Natuur", code="nature")
|
|
self.thematic_roads = Thematic.objects.create(name_fr="Voirie", name_nl="Wegen", code="roads")
|
|
|
|
self.user_editor = User.objects.create_user(username="editor_unified", password="password")
|
|
self.user_viewer = User.objects.create_user(username="viewer_unified", password="password")
|
|
|
|
self.config_editor = UserConfig.objects.create(user=self.user_editor)
|
|
self.config_viewer = UserConfig.objects.create(user=self.user_viewer)
|
|
|
|
UserThematics.objects.create(
|
|
user_config=self.config_editor,
|
|
thematic=self.thematic_nature,
|
|
can_view_assets=True,
|
|
can_edit_assets=True,
|
|
can_edit_management_zones=True,
|
|
)
|
|
|
|
UserThematics.objects.create(
|
|
user_config=self.config_viewer,
|
|
thematic=self.thematic_nature,
|
|
can_view_assets=True,
|
|
can_edit_assets=False,
|
|
can_edit_management_zones=False,
|
|
)
|
|
|
|
self.zone_type = ManagementZoneType.objects.create(
|
|
thematic=self.thematic_nature,
|
|
code="fauche_eco",
|
|
name_fr="Fauche tardive",
|
|
name_nl="Laat maaien",
|
|
default_color="#27ae60",
|
|
)
|
|
|
|
poly = Polygon(((149000, 170000), (149100, 170000), (149100, 170100), (149000, 170100), (149000, 170000)))
|
|
multi_poly = MultiPolygon([poly], srid=3812)
|
|
self.zone = ManagementZone.objects.create(
|
|
thematic=self.thematic_nature,
|
|
zone_type=self.zone_type,
|
|
code="ZN-TEST-001",
|
|
name_fr="Pelouse A",
|
|
name_nl="Grasveld A",
|
|
geom=multi_poly,
|
|
is_active=True,
|
|
created_by=self.user_editor,
|
|
)
|
|
|
|
def test_build_thematic_config_includes_management_zones_url(self):
|
|
from assets.views.core import build_thematic_config
|
|
config = build_thematic_config([self.thematic_nature, self.thematic_roads])
|
|
self.assertIn("nature", config)
|
|
self.assertIn("management_zones_geojson_url", config["nature"])
|
|
self.assertEqual(config["nature"]["management_zones_geojson_url"], reverse("assets:management_zones_geojson"))
|
|
|
|
def test_build_unified_add_modal_config_permissions(self):
|
|
from assets.views.core import build_unified_add_modal_config
|
|
# Editor can edit management zones in nature
|
|
editor_config = build_unified_add_modal_config([self.thematic_nature], user=self.user_editor)
|
|
self.assertIn("management_zone_thematics", editor_config)
|
|
editor_codes = [t["code"] for t in editor_config["management_zone_thematics"]]
|
|
self.assertIn("nature", editor_codes)
|
|
|
|
# Viewer cannot edit management zones
|
|
viewer_config = build_unified_add_modal_config([self.thematic_nature], user=self.user_viewer)
|
|
viewer_codes = [t["code"] for t in viewer_config["management_zone_thematics"]]
|
|
self.assertNotIn("nature", viewer_codes)
|
|
|
|
def test_management_zones_geojson_properties_for_unified_table(self):
|
|
self.client.login(username="editor_unified", password="password")
|
|
url = reverse("assets:management_zones_geojson") + f"?thematic={self.thematic_nature.code}"
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
data = res.json()
|
|
self.assertEqual(len(data["features"]), 1)
|
|
feat = data["features"][0]
|
|
props = feat["properties"]
|
|
|
|
self.assertTrue(props["is_management_zone"])
|
|
self.assertFalse(props["is_location"])
|
|
self.assertEqual(props["asset_type"], "managementzone")
|
|
self.assertIn(props["element_type"], ["Zone de gestion", "Management zone"])
|
|
self.assertEqual(props["category"], "Fauche tardive")
|
|
self.assertEqual(props["status"], "active")
|
|
self.assertIsNotNone(props["lon"])
|
|
self.assertIsNotNone(props["lat"])
|
|
self.assertIsNotNone(props["area"])
|
|
self.assertEqual(props["detail_url"], reverse("assets:management_zone_detail", kwargs={"pk": self.zone.pk}))
|
|
|
|
def test_unified_index_page_contains_management_zone_elements(self):
|
|
self.client.login(username="editor_unified", password="password")
|
|
url = reverse("assets:index")
|
|
res = self.client.get(url)
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
# Check filter modal checkboxes
|
|
self.assertContains(res, 'id="type-cb-assets"')
|
|
self.assertContains(res, 'id="type-cb-locations"')
|
|
self.assertContains(res, 'id="type-cb-management-zones"')
|
|
|
|
# Check add modal card
|
|
self.assertContains(res, 'id="unified-add-management-zone-thematic"')
|
|
self.assertContains(res, 'id="unified-add-management-zone-open"')
|