diff --git a/backend/configs/config.json b/backend/configs/all4trees_config.json similarity index 100% rename from backend/configs/config.json rename to backend/configs/all4trees_config.json diff --git a/backend/configs/seed_config.json b/backend/configs/seed_config.json new file mode 100644 index 00000000..2333a25d --- /dev/null +++ b/backend/configs/seed_config.json @@ -0,0 +1,100 @@ +{ + "layers": [ + { + "id": "satellite", + "type": "xyzservices", + "provider": "Esri.WorldImagery" + }, + { + "id": "villages", + "type": "openmaptiles", + "layer": "place", + "filters": { + "class": "village" + } + }, + { + "id": "towns", + "type": "openmaptiles", + "layer": "place", + "filters": { + "class": "town" + } + }, + { + "id": "boundaries", + "type": "openmaptiles", + "layer": "boundary", + "filters": { + "admin_level": 2 + }, + "style": { + "paint": { + "line-color": "hsl(248,7%,66%)" + } + } + }, + { + "id": "seed", + "type": "datapackage", + "path": "../catalog/seed/datapackage.json", + "resource": "survey", + "minzoom": 13, + "columns": { + "geom": "geom", + "id": "OGC_FID", + "orga": "votre_orga", + "responsable": "nom_du_res", + "date_plantation": "date_de_pl", + "type_plant": "type_de_pl", + "prelevement_mangrove": "trace_de_p", + "test": "round(random() * 4 ) + 1" + }, + "paint": { + "fill-color": [ + "interpolate", + ["linear"], + ["number", ["get", "test"]], + 1, + "#2DC4B2", + 2, + "#3BB3C3", + 3, + "#669EC4", + 4, + "#A2719B", + 5, + "#AA5E79" + ], + "fill-opacity": 0.8 + }, + "popup": { + "trigger": "click" + } + }, + { + "id": "seed_point", + "type": "datapackage", + "path": "../catalog/seed/datapackage.json", + "resource": "survey", + "columns": { + "geom": "centroid(geom)" + }, + "maxzoom": 13 + } + ], + "controls": [ + { + "type": "compass", + "position": "top-left" + }, + { + "type": "layer", + "position": "top-right" + }, + { + "type": "scale", + "position": "bottom-left" + } + ] +} diff --git a/backend/maps/views.py b/backend/maps/views.py index 8a277f31..e7e53617 100644 --- a/backend/maps/views.py +++ b/backend/maps/views.py @@ -2,30 +2,37 @@ from django.conf import settings from django.http import JsonResponse from django.contrib.auth.decorators import permission_required -from rest_framework.decorators import api_view, permission_classes +from rest_framework.decorators import api_view, permission_classes, authentication_classes from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework import status +from rest_framework_simplejwt.authentication import JWTAuthentication +from users.models import ADMIN_PROJECT +from copy import copy from . import stats from .datapackage_manager import DatapackageManager -config_path = settings.BASE_DIR / "configs" / "config.json" -map = Map.from_file(config_path) +ALL4TREES_LAYERS = ['inventaire_for', 'enquete'] +config_path = settings.BASE_DIR / "configs" / "all4trees_config.json" +map = Map.from_file(config_path) +@api_view(['GET', 'POST']) +@authentication_classes([JWTAuthentication]) def my_map_view(request, subpath): - return JsonResponse( - map.handle_request( + + return JsonResponse(get_map(request.user).handle_request( request.method, subpath, request.body, - ) - ) + )) +@api_view(['GET']) +@authentication_classes([JWTAuthentication]) def dashboard_view(request, layer_id): - data = map.handle_request( + data = get_map(request.user).handle_request( 'POST', layer_id, request.body) @@ -39,7 +46,6 @@ def dashboard_view(request, layer_id): }, status=status.HTTP_501_NOT_IMPLEMENTED) - @api_view(["POST"]) @permission_classes([IsAuthenticated]) @permission_required("users.add_data") @@ -97,4 +103,17 @@ def remove_foreign_key_view(request): """ View for adding a foreign key to a DataPackage. """ - return DatapackageManager(request).remove_foreign_key() \ No newline at end of file + return DatapackageManager(request).remove_foreign_key() + + +def get_map(user): + user_map = copy(map) + if user.is_authenticated: + project = user.project + if (project.lower() != ADMIN_PROJECT): + filter = f"proj = '{project}' or conf = 1" + else: + filter = 'conf = 1' + + user_map.set_filters(ALL4TREES_LAYERS, filter) + return user_map diff --git a/backend/requirements.txt b/backend/requirements.txt index 927fe2d6..68fbf144 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,6 +1,6 @@ asgiref==3.8.1 chardet==7.4.3 -coordo @ git+https://github.com/dataforgoodfr/Coordonnees.git@0.7.0#subdirectory=coordo-py +coordo @ git+https://github.com/dataforgoodfr/Coordonnees.git@0.8.0#subdirectory=coordo-py Django>=4.2.27 djangorestframework==3.16.0 djangorestframework_simplejwt==5.5.1 diff --git a/backend/users/models.py b/backend/users/models.py index 46476488..51585bc5 100644 --- a/backend/users/models.py +++ b/backend/users/models.py @@ -1,6 +1,7 @@ from django.contrib.auth.models import AbstractUser from django.db.models import AutoField, CharField +ADMIN_PROJECT = "all4trees" class CustomUser(AbstractUser): id = AutoField(primary_key=True) project = CharField("projet", max_length=30, blank=True, null=True) diff --git a/webapp/src/app/providers/AuthProvider.tsx b/webapp/src/app/providers/AuthProvider.tsx index 10d33c2f..6b5e3b83 100644 --- a/webapp/src/app/providers/AuthProvider.tsx +++ b/webapp/src/app/providers/AuthProvider.tsx @@ -53,6 +53,8 @@ export function AuthProvider({ children }: AuthProviderProps) { localStorage.removeItem("username"); setToken(null); setIsAuthenticated(false); + // Reload page to reinstantiate map at logout + window.location.reload(); }; return ( diff --git a/webapp/src/app/providers/map-provider-all4trees.tsx b/webapp/src/app/providers/map-provider-all4trees.tsx index b31f2a29..51771624 100644 --- a/webapp/src/app/providers/map-provider-all4trees.tsx +++ b/webapp/src/app/providers/map-provider-all4trees.tsx @@ -1,5 +1,6 @@ import { type ReactNode, useCallback, useRef, useState } from "react"; +import { useAuth } from "@features/auth"; import { useCategoriesFilters } from "@features/categories-filters/use-categories-filters"; import { renderAnchor, renderLayerRow } from "@features/controls/layer-control"; @@ -29,6 +30,8 @@ type MapProviderAll4TreesProps = { export function MapProviderAll4Trees({ children }: MapProviderAll4TreesProps) { const [isReady, setIsReady] = useState(false); + const { isAuthenticated, token } = useAuth(); + const mapApiRef = useRef | null>(null); const [forests, setForests] = useState([]); const [mapSettings, setMapSettings] = useLocalStorage( @@ -78,6 +81,7 @@ export function MapProviderAll4Trees({ children }: MapProviderAll4TreesProps) { renderAnchor, renderLayerRow, }, + headers: isAuthenticated ? { Authorization: `Bearer ${token}` } : {}, zoom: mapSettings.zoom, }); if (import.meta.env.DEV) {