diff --git a/app/Helpers/GeometryHelper.php b/app/Helpers/GeometryHelper.php new file mode 100644 index 000000000..337249d85 --- /dev/null +++ b/app/Helpers/GeometryHelper.php @@ -0,0 +1,117 @@ +selectRaw('ST_ASGEOJSON(ST_Envelope(geom)) as envelope') + ->get(); + + $maxX = $maxY = PHP_INT_MIN; + $minX = $minY = PHP_INT_MAX; + + foreach ($envelopes as $envelope) { + $geojson = json_decode($envelope->envelope); + $coordinates = $geojson->coordinates[0]; + + foreach ($coordinates as $point) { + $x = $point[0]; + $y = $point[1]; + $maxX = max($maxX, $x); + $minX = min($minX, $x); + $maxY = max($maxY, $y); + $minY = min($minY, $y); + } + } + + $bboxCoordinates = [$minX, $minY, $maxX, $maxY]; + + return $bboxCoordinates; + } + + public function updateProjectCentroid(string $projectUuid) + { + try { + $centroid = $this->centroidOfProject($projectUuid); + + if ($centroid === null) { + Log::warning("Invalid centroid for projectUuid: $projectUuid"); + } + + $centroidArray = json_decode($centroid, true); + + $latitude = $centroidArray['coordinates'][1]; + $longitude = $centroidArray['coordinates'][0]; + + + Project::where('uuid', $projectUuid) + ->update([ + 'lat' => $latitude, + 'long' => $longitude, + ]); + + + Log::info("Centroid updated for projectUuid: $projectUuid"); + + return 'Centroids updated successfully!'; + } catch (\Exception $e) { + Log::error("Error updating centroid for projectUuid: $projectUuid"); + + return response()->json([ + 'message' => 'Error updating centroid', + 'error' => $e->getMessage(), + ], 500); + } + + } + + public function centroidOfProject($projectUuid) + { + $project = Project::where('uuid', $projectUuid)->first(); + + if (! $project) { + return null; + } + + $polyIds = $project->sitePolygons()->pluck('poly_id')->toArray(); + + if (empty($polyIds)) { + return null; + } + + $centroids = PolygonGeometry::selectRaw('ST_AsGeoJSON(ST_Centroid(geom)) AS centroid') + ->whereIn('uuid', $polyIds) + ->get(); + + if ($centroids->isEmpty()) { + return null; // Return null if no centroids are found + } + + $centroidCount = $centroids->count(); + $totalLatitude = 0; + $totalLongitude = 0; + + foreach ($centroids as $centroid) { + $centroidData = json_decode($centroid->centroid, true); + $totalLatitude += $centroidData['coordinates'][1]; + $totalLongitude += $centroidData['coordinates'][0]; + } + + $averageLatitude = $totalLatitude / $centroidCount; + $averageLongitude = $totalLongitude / $centroidCount; + + $centroidOfCentroids = json_encode([ + 'type' => 'Point', + 'coordinates' => [$averageLongitude, $averageLatitude], + ]); + + return $centroidOfCentroids; + } +} diff --git a/app/Http/Controllers/V2/Sites/SitePolygonDataController.php b/app/Http/Controllers/V2/Sites/SitePolygonDataController.php new file mode 100644 index 000000000..215925299 --- /dev/null +++ b/app/Http/Controllers/V2/Sites/SitePolygonDataController.php @@ -0,0 +1,44 @@ +get(); + + return response()->json($sitePolygons); + } catch (\Exception $e) { + Log::error($e->getMessage()); + + return response()->json(['error' => 'An error occurred while fetching site polygons'], 500); + } + } + + public function getBboxOfCompleteSite($site): JsonResponse + { + try { + $sitePolygons = SitePolygon::where('site_id', $site)->get(); + if ($sitePolygons->isEmpty()) { + return response()->json(['error' => 'No polygons found for the site'], 404); + } + + $polygonsIds = $sitePolygons->pluck('poly_id'); + $bboxCoordinates = GeometryHelper::getPolygonsBbox($polygonsIds); + + return response()->json(['bbox' => $bboxCoordinates]); + } catch (\Exception $e) { + Log::error($e->getMessage()); + + return response()->json(['error' => 'An error occurred while fetching the bounding box coordinates'], 500); + } + } +} diff --git a/app/Http/Controllers/V2/Terrafund/TerrafundCreateGeometryController.php b/app/Http/Controllers/V2/Terrafund/TerrafundCreateGeometryController.php index f7893f39a..b550bb0df 100644 --- a/app/Http/Controllers/V2/Terrafund/TerrafundCreateGeometryController.php +++ b/app/Http/Controllers/V2/Terrafund/TerrafundCreateGeometryController.php @@ -60,14 +60,14 @@ public function storeGeometry(Request $request) /** * @throws ValidationException */ - public function insertGeojsonToDB(string $geojsonFilename) + public function insertGeojsonToDB(string $geojsonFilename, ?string $site_id = null) { $geojsonData = Storage::get("public/geojson_files/{$geojsonFilename}"); $geojson = json_decode($geojsonData, true); SitePolygonValidator::validate('FEATURE_BOUNDS', $geojson, false); - return App::make(PolygonService::class)->createGeojsonModels($geojson); + return App::make(PolygonService::class)->createGeojsonModels($geojson, ['site_id' => $site_id]); } public function validateDataInDB(Request $request) @@ -130,6 +130,7 @@ public function getGeometryProperties(string $geojsonFilename) public function uploadKMLFile(Request $request) { if ($request->hasFile('file')) { + $site_id = $request->input('uuid'); $kmlfile = $request->file('file'); $directory = storage_path('app/public/kml_files'); if (! file_exists($directory)) { @@ -147,7 +148,7 @@ public function uploadKMLFile(Request $request) return response()->json(['error' => 'Failed to convert KML to GeoJSON', 'message' => $process->getErrorOutput()], 500); } - $uuid = $this->insertGeojsonToDB($geojsonFilename); + $uuid = $this->insertGeojsonToDB($geojsonFilename, $site_id); if (isset($uuid['error'])) { return response()->json(['error' => 'Geometry not inserted into DB', 'message' => $uuid['error']], 500); } @@ -179,6 +180,7 @@ public function uploadShapefile(Request $request) { Log::debug('Upload Shape file data', ['request' => $request->all()]); if ($request->hasFile('file')) { + $site_id = $request->input('uuid'); $file = $request->file('file'); if ($file->getClientOriginalExtension() !== 'zip') { return response()->json(['error' => 'Only ZIP files are allowed'], 400); @@ -204,7 +206,7 @@ public function uploadShapefile(Request $request) return response()->json(['error' => 'Failed to convert Shapefile to GeoJSON', 'message' => $process->getErrorOutput()], 500); } - $uuid = $this->insertGeojsonToDB($geojsonFilename); + $uuid = $this->insertGeojsonToDB($geojsonFilename, $site_id); if (isset($uuid['error'])) { return response()->json(['error' => 'Geometry not inserted into DB', 'message' => $uuid['error']], 500); } @@ -327,7 +329,7 @@ public function getCriteriaData(Request $request) $criteriaList = []; foreach ($criteriaData as $criteria) { $criteriaId = $criteria->criteria_id; - $valid = CriteriaSite::where(['polygon_id' => $uuid, 'criteria_id' => $criteriaId])->select('valid')->first()?->valid; + $valid = CriteriaSite::where(['polygon_id' => $uuid, 'criteria_id' => $criteriaId])->orderBy('created_at', 'desc')->select('valid')->first()?->valid; $criteriaList[] = [ 'criteria_id' => $criteriaId, 'latest_created_at' => $criteria->latest_created_at, @@ -341,6 +343,7 @@ public function getCriteriaData(Request $request) public function uploadGeoJSONFile(Request $request) { if ($request->hasFile('file')) { + $site_id = $request->input('uuid'); $file = $request->file('file'); $directory = storage_path('app/public/geojson_files'); if (! file_exists($directory)) { @@ -348,7 +351,7 @@ public function uploadGeoJSONFile(Request $request) } $filename = uniqid('geojson_file_') . '.' . $file->getClientOriginalExtension(); $file->move($directory, $filename); - $uuid = $this->insertGeojsonToDB($filename); + $uuid = $this->insertGeojsonToDB($filename, $site_id); if (is_array($uuid) && isset($uuid['error'])) { return response()->json(['error' => 'Failed to insert GeoJSON data into the database', 'message' => $uuid['error']], 500); } @@ -381,35 +384,104 @@ public function validateEstimatedArea(Request $request) ); } - public function getPolygonsAsGeoJSON() + public function getPolygonAsGeoJSONDownload(Request $request) { - $limit = 2; - $polygons = PolygonGeometry::selectRaw('ST_AsGeoJSON(geom) AS geojson') - ->orderBy('created_at', 'desc') - ->whereNotNull('geom') - ->limit($limit) - ->get(); - $features = []; - - foreach ($polygons as $polygon) { - $coordinates = json_decode($polygon->geojson)->coordinates; + try { + $uuid = $request->query('uuid'); + + $polygonGeometry = PolygonGeometry::where('uuid', $uuid) + ->select(DB::raw('ST_AsGeoJSON(geom) AS geojsonGeom')) + ->first(); + + Log::info('Polygon Geometry', ['polygonGeometry' => $polygonGeometry]); + if (! $polygonGeometry) { + return response()->json(['message' => 'No polygon geometry found for the given UUID.'], 404); + } + + $sitePolygon = SitePolygon::where('poly_id', $uuid)->first(); + if (! $sitePolygon) { + return response()->json(['message' => 'No site polygon found for the given UUID.'], 404); + } + + $properties = []; + $fieldsToValidate = [ + 'poly_name', + 'plantstart', + 'plantend', + 'practice', + 'target_sys', + 'distr', + 'num_trees', + 'uuid', + 'site_id', + ]; + foreach ($fieldsToValidate as $field) { + $properties[$field] = $sitePolygon->$field; + } + + $propertiesJson = json_encode($properties); + $feature = [ - 'type' => 'Feature', - 'geometry' => [ - 'type' => 'Polygon', - 'coordinates' => $coordinates, - ], - 'properties' => [], + 'type' => 'Feature', + 'geometry' => json_decode($polygonGeometry->geojsonGeom), + 'properties' => json_decode($propertiesJson), + ]; + + $featureCollection = [ + 'type' => 'FeatureCollection', + 'features' => [$feature], ]; - $features[] = $feature; + + return response()->json($featureCollection); + } catch (\Exception $e) { + return response()->json(['message' => 'Failed to generate GeoJSON.', 'error' => $e->getMessage()], 500); } - $geojson = [ - 'type' => 'FeatureCollection', - 'features' => $features, - ]; + } + + public function getAllPolygonsAsGeoJSONDownload(Request $request) + { + try { + $siteUuid = $request->query('uuid'); + $polygonsUuids = SitePolygon::where('site_id', $siteUuid)->pluck('poly_id'); + $features = []; + foreach ($polygonsUuids as $polygonUuid) { + $feature = []; + $polygonGeometry = PolygonGeometry::where('uuid', $polygonUuid) + ->select(DB::raw('ST_AsGeoJSON(geom) AS geojsonGeom')) + ->first(); + if (! $polygonGeometry) { + return response()->json(['message' => 'No polygon geometry found for the given UUID.'], 404); + } + + $sitePolygon = SitePolygon::where('poly_id', $polygonUuid)->first(); + if (! $sitePolygon) { + return response()->json(['message' => 'No site polygon found for the given UUID.'], 404); + } - // Return the GeoJSON data - return response()->json($geojson); + $properties = []; + $fieldsToValidate = ['poly_name', 'plantstart', 'plantend', 'practice', 'target_sys', 'distr', 'num_trees', 'site_id']; + foreach ($fieldsToValidate as $field) { + $properties[$field] = $sitePolygon->$field; + } + + $propertiesJson = json_encode($properties); + + $feature = [ + 'type' => 'Feature', + 'geometry' => json_decode($polygonGeometry->geojsonGeom), + 'properties' => json_decode($propertiesJson), + ]; + $features[] = $feature; + } + $featureCollection = [ + 'type' => 'FeatureCollection', + 'features' => $features, + ]; + + return response()->json($featureCollection); + } catch (\Exception $e) { + return response()->json(['message' => 'Failed to generate GeoJSON.', 'error' => $e->getMessage()], 500); + } } public function getAllCountryNames() @@ -437,4 +509,103 @@ private function handlePolygonValidation($polygonUuid, $response, $criteriaId): return response()->json($response); } + + public function runValidationPolygon(string $uuid) + { + $request = new Request(['uuid' => $uuid]); + + $this->validateOverlapping($request); + $this->checkSelfIntersection($request); + $this->validatePolygonSize($request); + $this->checkWithinCountry($request); + $this->checkBoundarySegments($request); + $this->getGeometryType($request); + $this->validateEstimatedArea($request); + $this->validateDataInDB($request); + } + + public function getValidationPolygon(Request $request) + { + + $uuid = $request->input('uuid'); + $this->runValidationPolygon($uuid); + $criteriaData = $this->getCriteriaData($request); + + return $criteriaData; + } + + public function getSiteValidationPolygon(Request $request) + { + try { + $uuid = $request->input('uuid'); + + $sitePolygonsUuids = $this->getSitePolygonsUuids($uuid); + + foreach ($sitePolygonsUuids as $polygonUuid) { + $this->runValidationPolygon($polygonUuid); + } + + return response()->json(['message' => 'Validation completed for all site polygons']); + } catch (\Exception $e) { + Log::error('Error during site validation polygon: ' . $e->getMessage()); + + return response()->json(['error' => 'An error occurred during site validation'], 500); + } + } + + public function getCurrentSiteValidation(Request $request) + { + try { + $uuid = $request->input('uuid'); + + $sitePolygonsUuids = $this->getSitePolygonsUuids($uuid); + $checkedPolygons = []; + + foreach ($sitePolygonsUuids as $polygonUuid) { + $isValid = true; + $isChecked = true; + + $criteriaData = $this->fetchCriteriaData($polygonUuid); + + if (isset($criteriaData['error'])) { + Log::error('Error fetching criteria data', ['polygon_uuid' => $polygonUuid, 'error' => $criteriaData['error']]); + $isValid = false; + $isChecked = false; + } else { + foreach ($criteriaData['criteria_list'] as $criteria) { + if ($criteria['valid'] == 0) { + $isValid = false; + + break; + } + } + } + + $checkedPolygons[] = [ + 'uuid' => $polygonUuid, + 'valid' => $isValid, + 'checked' => $isChecked, + ]; + } + + return $checkedPolygons; + } catch (\Exception $e) { + Log::error('Error during current site validation: ' . $e->getMessage()); + + return response()->json(['error' => 'An error occurred during current site validation'], 500); + } + } + + private function getSitePolygonsUuids($uuid) + { + return SitePolygon::where('site_id', $uuid)->get()->pluck('poly_id'); + } + + private function fetchCriteriaData($polygonUuid) + { + $polygonRequest = new Request(['uuid' => $polygonUuid]); + $criteriaDataResponse = $this->getCriteriaData($polygonRequest); + + return json_decode($criteriaDataResponse->getContent(), true); + } } diff --git a/app/Http/Controllers/V2/Terrafund/TerrafundEditGeometryController.php b/app/Http/Controllers/V2/Terrafund/TerrafundEditGeometryController.php index ff7fc8849..fdeea0402 100644 --- a/app/Http/Controllers/V2/Terrafund/TerrafundEditGeometryController.php +++ b/app/Http/Controllers/V2/Terrafund/TerrafundEditGeometryController.php @@ -2,12 +2,14 @@ namespace App\Http\Controllers\V2\Terrafund; +use App\Helpers\GeometryHelper; use App\Http\Controllers\Controller; use App\Models\V2\PolygonGeometry; use App\Models\V2\Sites\SitePolygon; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; class TerrafundEditGeometryController extends Controller { @@ -26,18 +28,107 @@ public function getSitePolygonData(string $uuid) } } - public function updateGeometry(string $uuid, Request $request) + public function updateEstAreainSitePolygon($polygonGeometry, $geometry) { - $polygonGeometry = PolygonGeometry::where('uuid', $uuid)->first(); - if (! $polygonGeometry) { - return response()->json(['message' => 'No polygon geometry found for the given UUID.'], 404); + try { + $sitePolygon = SitePolygon::where('poly_id', $polygonGeometry->uuid)->first(); + + if ($sitePolygon) { + $geojson = json_encode($geometry); + $areaSqDegrees = DB::selectOne("SELECT ST_Area(ST_GeomFromGeoJSON('$geojson')) AS area")->area; + $latitude = DB::selectOne("SELECT ST_Y(ST_Centroid(ST_GeomFromGeoJSON('$geojson'))) AS latitude")->latitude; + $unitLatitude = 111320; + $areaSqMeters = $areaSqDegrees * pow($unitLatitude * cos(deg2rad($latitude)), 2); + $areaHectares = $areaSqMeters / 10000; + + $sitePolygon->calc_area = $areaHectares; + $sitePolygon->save(); + + Log::info("Updated area for site polygon with UUID: $sitePolygon->uuid"); + } else { + Log::warning("Updating Area: Site polygon with UUID $polygonGeometry->uuid not found."); + } + } catch (\Exception $e) { + Log::error('Error updating area in site polygon: ' . $e->getMessage()); } - $geometry = json_decode($request->input('geometry')); - $geom = DB::raw("ST_GeomFromGeoJSON('" . json_encode($geometry) . "')"); - $polygonGeometry->geom = $geom; - $polygonGeometry->save(); + } + + public function updateProjectCentroid($polygonGeometry) + { + try { + $sitePolygon = SitePolygon::where('poly_id', $polygonGeometry->uuid)->first(); + if (! $sitePolygon) { + Log::warning("Site polygon with UUID $polygonGeometry->uuid not found."); + + return null; + } + $project = $sitePolygon->project; + + if ($project) { + $geometryHelper = new GeometryHelper(); + $centroid = $geometryHelper->centroidOfProject($project->uuid); - return response()->json(['message' => 'Geometry updated successfully.', 'geometry' => $geometry, 'uuid' => $uuid]); + if ($centroid === null) { + Log::warning("Invalid centroid for project UUID: $project->uuid"); + } + } else { + Log::warning('Project UUID not found.'); + } + } catch (\Exception $e) { + Log::error('Error updating project centroid: ' . $e->getMessage()); + } + } + + public function deletePolygonAndSitePolygon(string $uuid) + { + try { + $polygonGeometry = PolygonGeometry::where('uuid', $uuid)->first(); + if (! $polygonGeometry) { + return response()->json(['message' => 'No polygon geometry found for the given UUID.'], 404); + } + $sitePolygon = SitePolygon::where('poly_id', $uuid)->first(); + $project = $sitePolygon->project; + if (! $project) { + return response()->json(['message' => 'No project found for the given UUID.'], 404); + } + if ($sitePolygon) { + Log::info("Deleting associated site polygon for UUID: $uuid"); + $sitePolygon->delete(); + } + $geometryHelper = new GeometryHelper(); + $geometryHelper->updateProjectCentroid($project->uuid); + $polygonGeometry->delete(); + Log::info("Polygon geometry and associated site polygon deleted successfully for UUID: $uuid"); + + return response()->json(['message' => 'Polygon geometry and associated site polygon deleted successfully.', 'uuid' => $uuid]); + } catch (\Exception $e) { + Log::error('An error occurred: ' . $e->getMessage()); + + // Return error response if an exception occurs + return response()->json(['error' => 'An error occurred: ' . $e->getMessage()], 500); + } + } + + public function updateGeometry(string $uuid, Request $request) + { + try { + Log::info("Updating geometry for polygon with UUID: $uuid"); + + $polygonGeometry = PolygonGeometry::where('uuid', $uuid)->first(); + if (! $polygonGeometry) { + return response()->json(['message' => 'No polygon geometry found for the given UUID.'], 404); + } + $geometry = json_decode($request->input('geometry')); + $geom = DB::raw("ST_GeomFromGeoJSON('" . json_encode($geometry) . "')"); + $polygonGeometry->geom = $geom; + $polygonGeometry->save(); + $this->updateEstAreainSitePolygon($polygonGeometry, $geometry); + $this->updateProjectCentroid($polygonGeometry); + + return response()->json(['message' => 'Geometry updated successfully.', 'geometry' => $geometry, 'uuid' => $uuid]); + } catch (\Exception $e) { + return response()->json(['error' => 'An error occurred: ' . $e->getMessage()], 500); + } } public function getPolygonGeojson(string $uuid) @@ -134,4 +225,17 @@ public function createSitePolygon(string $uuid, string $siteUuid, Request $reque return response()->json(['error' => 'An error occurred: ' . $e->getMessage()], 500); } } + + public function getPolygonBbox(string $uuid) + { + try { + $bboxCoordinates = GeometryHelper::getPolygonsBbox([$uuid]); + + return response()->json(['bbox' => $bboxCoordinates]); + } catch (\Exception $e) { + Log::error($e->getMessage()); + + return response()->json(['error' => 'An error occurred while fetching the bounding box coordinates'], 404); + } + } } diff --git a/openapi-src/V2/definitions/GeoJSONResponse.yml b/openapi-src/V2/definitions/GeoJSONResponse.yml new file mode 100644 index 000000000..ab67d4340 --- /dev/null +++ b/openapi-src/V2/definitions/GeoJSONResponse.yml @@ -0,0 +1,35 @@ +type: object +properties: + type: + type: string + features: + type: array + items: + type: object + properties: + type: + type: string + geometry: + type: object + properties: + type: + type: string + coordinates: + type: array + "properties": + type: object + properties: + poly_name: + type: string + plantstart: + type: string + plantend: + type: string + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer \ No newline at end of file diff --git a/openapi-src/V2/definitions/SitePolygon.yml b/openapi-src/V2/definitions/SitePolygon.yml new file mode 100644 index 000000000..51f5cd1e0 --- /dev/null +++ b/openapi-src/V2/definitions/SitePolygon.yml @@ -0,0 +1,55 @@ +title: SitePolygon +type: object +properties: + id: + type: integer + uuid: + type: string + project_id: + type: string + proj_name: + type: string + org_name: + type: string + poly_id: + type: string + poly_name: + type: string + site_id: + type: string + site_name: + type: string + plantstart: + type: string + format: date + plantend: + type: string + format: date + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer + calc_area: + type: number + format: float + created_by: + type: string + last_modified_by: + type: string + deleted_at: + type: string + format: date-time + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + status: + type: string + country: + type: string \ No newline at end of file diff --git a/openapi-src/V2/definitions/SitePolygonCreateResponse.yml b/openapi-src/V2/definitions/SitePolygonCreateResponse.yml new file mode 100644 index 000000000..3c5a29921 --- /dev/null +++ b/openapi-src/V2/definitions/SitePolygonCreateResponse.yml @@ -0,0 +1,12 @@ +type: object +properties: + message: + type: string + example: Site polygon created successfully + uuid: + type: string + description: UUID of the created site polygon + area: + type: number + format: double + description: Calculated area in hectares \ No newline at end of file diff --git a/openapi-src/V2/definitions/SitePolygonResponse.yml b/openapi-src/V2/definitions/SitePolygonResponse.yml new file mode 100644 index 000000000..f2bafdd02 --- /dev/null +++ b/openapi-src/V2/definitions/SitePolygonResponse.yml @@ -0,0 +1,27 @@ +type: object +properties: + id: + type: integer + uuid: + type: string + poly_name: + type: string + plantstart: + type: string + format: date + plantend: + type: string + format: date + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer + calc_area: + type: number + format: float + status: + type: string \ No newline at end of file diff --git a/openapi-src/V2/definitions/SitePolygonsBboxResponse.yml b/openapi-src/V2/definitions/SitePolygonsBboxResponse.yml new file mode 100644 index 000000000..0a454bac5 --- /dev/null +++ b/openapi-src/V2/definitions/SitePolygonsBboxResponse.yml @@ -0,0 +1,7 @@ +title: SitePolygonsBboxResponse +type: object +properties: + bbox: + type: array + items: + type: number \ No newline at end of file diff --git a/openapi-src/V2/definitions/SitePolygonsDataResponse.yml b/openapi-src/V2/definitions/SitePolygonsDataResponse.yml new file mode 100644 index 000000000..ddcedc790 --- /dev/null +++ b/openapi-src/V2/definitions/SitePolygonsDataResponse.yml @@ -0,0 +1,4 @@ +title: SitePolygonsDataResponse +type: array +items: + $ref: './_index.yml#/SitePolygon' \ No newline at end of file diff --git a/openapi-src/V2/definitions/V2TerrafundCriteriaData.yml b/openapi-src/V2/definitions/V2TerrafundCriteriaData.yml new file mode 100644 index 000000000..4d073736b --- /dev/null +++ b/openapi-src/V2/definitions/V2TerrafundCriteriaData.yml @@ -0,0 +1,21 @@ +type: object +properties: + polygon_id: + type: string + description: The ID of the polygon + criteria_list: + type: array + description: List of validation criteria + items: + type: object + properties: + criteria_id: + type: integer + description: The ID of the criteria + latest_created_at: + type: string + format: date-time + description: The latest created at timestamp of the criteria + valid: + type: integer + description: Indicates if the criteria is valid or not (1 for valid, 0 for invalid) \ No newline at end of file diff --git a/openapi-src/V2/definitions/V2TerrafundCriteriaSite.yml b/openapi-src/V2/definitions/V2TerrafundCriteriaSite.yml new file mode 100644 index 000000000..667dc4b02 --- /dev/null +++ b/openapi-src/V2/definitions/V2TerrafundCriteriaSite.yml @@ -0,0 +1,13 @@ +type: array +items: + type: object + properties: + uuid: + type: string + description: The UUID of the polygon. + valid: + type: boolean + description: Indicates if the polygon is valid or not. + checked: + type: boolean + description: Indicates if the polygon has been checked before or not. \ No newline at end of file diff --git a/openapi-src/V2/definitions/_index.yml b/openapi-src/V2/definitions/_index.yml index 3a8e731a1..9213aea8e 100644 --- a/openapi-src/V2/definitions/_index.yml +++ b/openapi-src/V2/definitions/_index.yml @@ -276,3 +276,19 @@ GeoJSON: $ref: './GeoJSON.yml' GeometryPost: $ref: './GeometryPost.yml' +V2TerrafundCriteriaData: + $ref: './V2TerrafundCriteriaData.yml' +V2TerrafundCriteriaSite: + $ref: './V2TerrafundCriteriaSite.yml' +SitePolygon: + $ref: './SitePolygon.yml' +SitePolygonsDataResponse: + $ref: './SitePolygonsDataResponse.yml' +SitePolygonsBboxResponse: + $ref: './SitePolygonsBboxResponse.yml' +SitePolygonResponse: + $ref: './SitePolygonResponse.yml' +SitePolygonCreateResponse: + $ref: './SitePolygonCreateResponse.yml' +GeoJSONResponse: + $ref: './GeoJSONResponse.yml' \ No newline at end of file diff --git a/openapi-src/V2/paths/Sites/get-v2-sites-polygon-bbox.yml b/openapi-src/V2/paths/Sites/get-v2-sites-polygon-bbox.yml new file mode 100644 index 000000000..f54bad8fb --- /dev/null +++ b/openapi-src/V2/paths/Sites/get-v2-sites-polygon-bbox.yml @@ -0,0 +1,16 @@ +summary: Get bbox for a specific site +parameters: + - in: path + name: site + required: true + type: string + description: The ID of the site +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/SitePolygonsBboxResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/Sites/get-v2-sites-polygons-data.yml b/openapi-src/V2/paths/Sites/get-v2-sites-polygons-data.yml new file mode 100644 index 000000000..485073593 --- /dev/null +++ b/openapi-src/V2/paths/Sites/get-v2-sites-polygons-data.yml @@ -0,0 +1,16 @@ +summary: Get polygons for a specific site +parameters: + - in: path + name: site + required: true + type: string + description: The ID of the site +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/SitePolygonsDataResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/Terrafund/delete-v2-polygon-uuid.yml b/openapi-src/V2/paths/Terrafund/delete-v2-polygon-uuid.yml new file mode 100644 index 000000000..982445259 --- /dev/null +++ b/openapi-src/V2/paths/Terrafund/delete-v2-polygon-uuid.yml @@ -0,0 +1,10 @@ +summary: Delete polygon records +parameters: + - in: path + name: uuid + required: true + type: string + description: The UUID of the polygon geometry to delete +responses: + '204': + description: No Content \ No newline at end of file diff --git a/openapi-src/V2/paths/Terrafund/get-v2-geojson-complete-download.yml b/openapi-src/V2/paths/Terrafund/get-v2-geojson-complete-download.yml new file mode 100644 index 000000000..5073d4122 --- /dev/null +++ b/openapi-src/V2/paths/Terrafund/get-v2-geojson-complete-download.yml @@ -0,0 +1,17 @@ +summary: Get Polygon as GeoJSON +description: Retrieve polygon geometry and properties as GeoJSON. +parameters: + - in: query + name: uuid + type: string + required: true + description: UUID of the polygon geometry. +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/GeoJSONResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/Terrafund/get-v2-polygon-bbox.yml b/openapi-src/V2/paths/Terrafund/get-v2-polygon-bbox.yml new file mode 100644 index 000000000..19d0dee0c --- /dev/null +++ b/openapi-src/V2/paths/Terrafund/get-v2-polygon-bbox.yml @@ -0,0 +1,16 @@ +summary: Get bbox for a polygon +parameters: + - in: path + name: uuid + required: true + type: string + description: The UUID of the polygon +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/SitePolygonsBboxResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-criteria-data.yml b/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-criteria-data.yml new file mode 100644 index 000000000..6ecd1611e --- /dev/null +++ b/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-criteria-data.yml @@ -0,0 +1,12 @@ +summary: Get criteria data validation results for a polygon +parameters: + - in: query + name: uuid + required: true + description: The UUID of the polygon + type: string +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/V2TerrafundCriteriaData' \ No newline at end of file diff --git a/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-criteria-site.yml b/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-criteria-site.yml new file mode 100644 index 000000000..acbb3b816 --- /dev/null +++ b/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-criteria-site.yml @@ -0,0 +1,12 @@ +summary: Get criteria data validation results for all polygons in a site +parameters: + - in: query + name: uuid + required: true + description: The UUID of the polygon + type: string +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/V2TerrafundCriteriaSite' \ No newline at end of file diff --git a/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-polygon.yml b/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-polygon.yml new file mode 100644 index 000000000..1f565764b --- /dev/null +++ b/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-polygon.yml @@ -0,0 +1,12 @@ +summary: Get validation results for a polygon +parameters: + - in: query + name: uuid + required: true + description: The UUID of the polygon + type: string +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/V2TerrafundCriteriaData' \ No newline at end of file diff --git a/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-sitepolygons.yml b/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-sitepolygons.yml new file mode 100644 index 000000000..6596857f6 --- /dev/null +++ b/openapi-src/V2/paths/Terrafund/get-v2-terrafund-validation-sitepolygons.yml @@ -0,0 +1,16 @@ +summary: Run validation for all polygons in a site +parameters: + - in: query + name: uuid + required: true + description: The UUID of the polygon + type: string +responses: + "200": + description: Successful response + schema: + type: object + properties: + message: + type: string + description: A message indicating the completion of validation for all site polygons. \ No newline at end of file diff --git a/openapi-src/V2/paths/Terrafund/post-v2-site-polygon-data.yml b/openapi-src/V2/paths/Terrafund/post-v2-site-polygon-data.yml new file mode 100644 index 000000000..d472868e6 --- /dev/null +++ b/openapi-src/V2/paths/Terrafund/post-v2-site-polygon-data.yml @@ -0,0 +1,26 @@ +summary: Create site polygon +parameters: + - in: path + name: uuid + required: true + type: string + description: The UUID of the polygon related + - in: path + name: siteUuid + required: true + type: string + description: The UUID of the site + - in: body + name: body + required: true + schema: + $ref: '../../definitions/_index.yml#/SitePolygonResponse' +responses: + '201': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/SitePolygonCreateResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/_index.yml b/openapi-src/V2/paths/_index.yml index 6de1735d2..23ebcc55d 100644 --- a/openapi-src/V2/paths/_index.yml +++ b/openapi-src/V2/paths/_index.yml @@ -2514,6 +2514,18 @@ /v2/{ENTITY}/{UUID}/export: get: $ref: './Exports/get-v2-entity-export-uuid.yml' +'/v2/terrafund/validation/polygon': + get: + $ref: './Terrafund/get-v2-terrafund-validation-polygon.yml' +'/v2/terrafund/validation/criteria-data': + get: + $ref: './Terrafund/get-v2-terrafund-validation-criteria-data.yml' +'/v2/terrafund/validation/sitePolygons': + get: + $ref: './Terrafund/get-v2-terrafund-validation-sitepolygons.yml' +'/v2/terrafund/validation/site': + get: + $ref: './Terrafund/get-v2-terrafund-validation-criteria-site.yml' /v2/geometry/validate: post: $ref: './Geometry/post-v2-geometry-validate.yml' @@ -2525,3 +2537,21 @@ /v2/geometry/{UUID}: put: $ref: './Geometry/put-v2-geometry-uuid.yml' +/v2/sites/{site}/polygon: + get: + $ref: './Sites/get-v2-sites-polygons-data.yml' +/v2/sites/{site}/bbox: + get: + $ref: './Sites/get-v2-sites-polygon-bbox.yml' +/v2/terrafund/site-polygon/{uuid}/{siteUuid}: + post: + $ref: './Terrafund/post-v2-site-polygon-data.yml' +/v2/terrafund/polygon/bbox/{uuid}: + get: + $ref: './Terrafund/get-v2-polygon-bbox.yml' +/v2/terrafund/geojson/complete: + get: + $ref: './Terrafund/get-v2-geojson-complete-download.yml' +/v2/terrafund/polygon/{uuid}: + delete: + $ref: './Terrafund/delete-v2-polygon-uuid.yml' \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3f348d81b..492c76df4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,10 +1,9 @@ { - "name": "wri-restoration-marketplace-api", + "name": "wri-terramatch-api", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "wri-restoration-marketplace-api", "dependencies": { "swagger-ui-dist": "^3.23.3" }, diff --git a/package.json b/package.json index 6a32704fa..cbfbdd6e8 100644 --- a/package.json +++ b/package.json @@ -18,14 +18,14 @@ "laravel-mix": "^6.0.12", "lodash": "^4.17.5", "popper.js": "^1.12", + "postcss": "^8.2.8", "resolve-url-loader": "^2.3.1", "sass": "^1.15.2", "sass-loader": "^7.1.0", "swagger-cli": "^4.0.4", "swagger-ui-dist": "^3.23.3", "vue": "^2.5.17", - "vue-template-compiler": "^2.6.10", - "postcss": "^8.2.8" + "vue-template-compiler": "^2.6.10" }, "dependencies": { "swagger-ui-dist": "^3.23.3" diff --git a/resources/docs/swagger-v2.yml b/resources/docs/swagger-v2.yml index 0cf2e0ac7..20eebcf24 100644 --- a/resources/docs/swagger-v2.yml +++ b/resources/docs/swagger-v2.yml @@ -44058,6 +44058,242 @@ definitions: message: type: string description: Human readable string in English to describe the error. + V2TerrafundCriteriaData: + type: object + properties: + polygon_id: + type: string + description: The ID of the polygon + criteria_list: + type: array + description: List of validation criteria + items: + type: object + properties: + criteria_id: + type: integer + description: The ID of the criteria + latest_created_at: + type: string + format: date-time + description: The latest created at timestamp of the criteria + valid: + type: integer + description: 'Indicates if the criteria is valid or not (1 for valid, 0 for invalid)' + V2TerrafundCriteriaSite: + type: array + items: + type: object + properties: + uuid: + type: string + description: The UUID of the polygon. + valid: + type: boolean + description: Indicates if the polygon is valid or not. + checked: + type: boolean + description: Indicates if the polygon has been checked before or not. + SitePolygon: + title: SitePolygon + type: object + properties: + id: + type: integer + uuid: + type: string + project_id: + type: string + proj_name: + type: string + org_name: + type: string + poly_id: + type: string + poly_name: + type: string + site_id: + type: string + site_name: + type: string + plantstart: + type: string + format: date + plantend: + type: string + format: date + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer + calc_area: + type: number + format: float + created_by: + type: string + last_modified_by: + type: string + deleted_at: + type: string + format: date-time + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + status: + type: string + country: + type: string + SitePolygonsDataResponse: + title: SitePolygonsDataResponse + type: array + items: + title: SitePolygon + type: object + properties: + id: + type: integer + uuid: + type: string + project_id: + type: string + proj_name: + type: string + org_name: + type: string + poly_id: + type: string + poly_name: + type: string + site_id: + type: string + site_name: + type: string + plantstart: + type: string + format: date + plantend: + type: string + format: date + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer + calc_area: + type: number + format: float + created_by: + type: string + last_modified_by: + type: string + deleted_at: + type: string + format: date-time + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + status: + type: string + country: + type: string + SitePolygonsBboxResponse: + title: SitePolygonsBboxResponse + type: object + properties: + bbox: + type: array + items: + type: number + SitePolygonResponse: + type: object + properties: + id: + type: integer + uuid: + type: string + poly_name: + type: string + plantstart: + type: string + format: date + plantend: + type: string + format: date + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer + calc_area: + type: number + format: float + status: + type: string + SitePolygonCreateResponse: + type: object + properties: + message: + type: string + example: Site polygon created successfully + uuid: + type: string + description: UUID of the created site polygon + area: + type: number + format: double + description: Calculated area in hectares + GeoJSONResponse: + type: object + properties: + type: + type: string + features: + type: array + items: + type: object + properties: + type: + type: string + geometry: + type: object + properties: + type: + type: string + coordinates: + type: array + properties: + type: object + properties: + poly_name: + type: string + plantstart: + type: string + plantend: + type: string + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer paths: '/v2/tree-species/{entity}/{UUID}': get: @@ -93711,6 +93947,118 @@ paths: description: OK schema: type: file + /v2/terrafund/validation/polygon: + get: + summary: Get validation results for a polygon + parameters: + - in: query + name: uuid + required: true + description: The UUID of the polygon + type: string + responses: + '200': + description: Successful response + schema: + type: object + properties: + polygon_id: + type: string + description: The ID of the polygon + criteria_list: + type: array + description: List of validation criteria + items: + type: object + properties: + criteria_id: + type: integer + description: The ID of the criteria + latest_created_at: + type: string + format: date-time + description: The latest created at timestamp of the criteria + valid: + type: integer + description: 'Indicates if the criteria is valid or not (1 for valid, 0 for invalid)' + /v2/terrafund/validation/criteria-data: + get: + summary: Get criteria data validation results for a polygon + parameters: + - in: query + name: uuid + required: true + description: The UUID of the polygon + type: string + responses: + '200': + description: Successful response + schema: + type: object + properties: + polygon_id: + type: string + description: The ID of the polygon + criteria_list: + type: array + description: List of validation criteria + items: + type: object + properties: + criteria_id: + type: integer + description: The ID of the criteria + latest_created_at: + type: string + format: date-time + description: The latest created at timestamp of the criteria + valid: + type: integer + description: 'Indicates if the criteria is valid or not (1 for valid, 0 for invalid)' + /v2/terrafund/validation/sitePolygons: + get: + summary: Run validation for all polygons in a site + parameters: + - in: query + name: uuid + required: true + description: The UUID of the polygon + type: string + responses: + '200': + description: Successful response + schema: + type: object + properties: + message: + type: string + description: A message indicating the completion of validation for all site polygons. + /v2/terrafund/validation/site: + get: + summary: Get criteria data validation results for all polygons in a site + parameters: + - in: query + name: uuid + required: true + description: The UUID of the polygon + type: string + responses: + '200': + description: Successful response + schema: + type: array + items: + type: object + properties: + uuid: + type: string + description: The UUID of the polygon. + valid: + type: boolean + description: Indicates if the polygon is valid or not. + checked: + type: boolean + description: Indicates if the polygon has been checked before or not. /v2/geometry/validate: post: summary: Test a set of geometries for validity @@ -94032,3 +94380,256 @@ paths: description: This account does not have permission to update the polygon. '404': description: Geometry was not found. + '/v2/sites/{site}/polygon': + get: + summary: Get polygons for a specific site + parameters: + - in: path + name: site + required: true + type: string + description: The ID of the site + responses: + '200': + description: Successful response + schema: + title: SitePolygonsDataResponse + type: array + items: + title: SitePolygon + type: object + properties: + id: + type: integer + uuid: + type: string + project_id: + type: string + proj_name: + type: string + org_name: + type: string + poly_id: + type: string + poly_name: + type: string + site_id: + type: string + site_name: + type: string + plantstart: + type: string + format: date + plantend: + type: string + format: date + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer + calc_area: + type: number + format: float + created_by: + type: string + last_modified_by: + type: string + deleted_at: + type: string + format: date-time + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + status: + type: string + country: + type: string + '400': + description: Bad request + '500': + description: Internal server error + '/v2/sites/{site}/bbox': + get: + summary: Get bbox for a specific site + parameters: + - in: path + name: site + required: true + type: string + description: The ID of the site + responses: + '200': + description: Successful response + schema: + title: SitePolygonsBboxResponse + type: object + properties: + bbox: + type: array + items: + type: number + '400': + description: Bad request + '500': + description: Internal server error + '/v2/terrafund/site-polygon/{uuid}/{siteUuid}': + post: + summary: Create site polygon + parameters: + - in: path + name: uuid + required: true + type: string + description: The UUID of the polygon related + - in: path + name: siteUuid + required: true + type: string + description: The UUID of the site + - in: body + name: body + required: true + schema: + type: object + properties: + id: + type: integer + uuid: + type: string + poly_name: + type: string + plantstart: + type: string + format: date + plantend: + type: string + format: date + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer + calc_area: + type: number + format: float + status: + type: string + responses: + '201': + description: Successful response + schema: + type: object + properties: + message: + type: string + example: Site polygon created successfully + uuid: + type: string + description: UUID of the created site polygon + area: + type: number + format: double + description: Calculated area in hectares + '400': + description: Bad request + '500': + description: Internal server error + '/v2/terrafund/polygon/bbox/{uuid}': + get: + summary: Get bbox for a polygon + parameters: + - in: path + name: uuid + required: true + type: string + description: The UUID of the polygon + responses: + '200': + description: Successful response + schema: + title: SitePolygonsBboxResponse + type: object + properties: + bbox: + type: array + items: + type: number + '400': + description: Bad request + '500': + description: Internal server error + /v2/terrafund/geojson/complete: + get: + summary: Get Polygon as GeoJSON + description: Retrieve polygon geometry and properties as GeoJSON. + parameters: + - in: query + name: uuid + type: string + required: true + description: UUID of the polygon geometry. + responses: + '200': + description: Successful response + schema: + type: object + properties: + type: + type: string + features: + type: array + items: + type: object + properties: + type: + type: string + geometry: + type: object + properties: + type: + type: string + coordinates: + type: array + properties: + type: object + properties: + poly_name: + type: string + plantstart: + type: string + plantend: + type: string + practice: + type: string + target_sys: + type: string + distr: + type: string + num_trees: + type: integer + '400': + description: Bad request + '500': + description: Internal server error + '/v2/terrafund/polygon/{uuid}': + delete: + summary: Delete polygon records + parameters: + - in: path + name: uuid + required: true + type: string + description: The UUID of the polygon geometry to delete + responses: + '204': + description: No Content diff --git a/routes/api_v2.php b/routes/api_v2.php index e1bb71c32..fda002ca7 100644 --- a/routes/api_v2.php +++ b/routes/api_v2.php @@ -157,6 +157,7 @@ use App\Http\Controllers\V2\Sites\Monitoring\AdminSoftDeleteSiteMonitoringController; use App\Http\Controllers\V2\Sites\Monitoring\AdminUpdateSiteMonitoringController; use App\Http\Controllers\V2\Sites\Monitoring\ViewSiteMonitoringController; +use App\Http\Controllers\V2\Sites\SitePolygonDataController; use App\Http\Controllers\V2\Sites\SoftDeleteSiteController; use App\Http\Controllers\V2\Sites\ViewASitesMonitoringsController; use App\Http\Controllers\V2\Stages\DeleteStageController; @@ -555,6 +556,8 @@ Route::get('/export', ExportAllSiteDataAsProjectDeveloperController::class); // deprecated, use POST api/v2/geometry instead (include site_id in the geometry's properties Route::post('/geometry', [GeometryController::class, 'storeSiteGeometry']); + Route::get('/polygon', [SitePolygonDataController::class, 'getSitePolygonData']); + Route::get('/bbox', [SitePolygonDataController::class, 'getBboxOfCompleteSite']); }); Route::prefix('geometry')->group(function () { @@ -615,8 +618,10 @@ Route::post('/upload-shapefile', [TerrafundCreateGeometryController::class, 'uploadShapefile']); Route::post('/upload-kml', [TerrafundCreateGeometryController::class, 'uploadKMLFile']); Route::post('/polygon/{uuid}', [TerrafundCreateGeometryController::class, 'processGeometry']); + Route::get('/geojson/complete', [TerrafundCreateGeometryController::class, 'getPolygonAsGeoJSONDownload']); + Route::get('/geojson/site', [TerrafundCreateGeometryController::class, 'getAllPolygonsAsGeoJSONDownload']); + - Route::get('/geojson/complete', [TerrafundCreateGeometryController::class, 'getPolygonsAsGeoJSON']); Route::get('/validation/self-intersection', [TerrafundCreateGeometryController::class, 'checkSelfIntersection']); Route::get('/validation/size-limit', [TerrafundCreateGeometryController::class, 'validatePolygonSize']); Route::get('/validation/spike', [TerrafundCreateGeometryController::class, 'checkBoundarySegments']); @@ -627,10 +632,16 @@ Route::get('/validation/overlapping', [TerrafundCreateGeometryController::class, 'validateOverlapping']); Route::get('/validation/estimated-area', [TerrafundCreateGeometryController::class, 'validateEstimatedArea']); Route::get('/validation/table-data', [TerrafundCreateGeometryController::class, 'validateDataInDB']); + Route::get('/validation/polygon', [TerrafundCreateGeometryController::class, 'getValidationPolygon']); + Route::get('/validation/sitePolygons', [TerrafundCreateGeometryController::class, 'getSiteValidationPolygon']); + Route::get('/validation/site', [TerrafundCreateGeometryController::class, 'getCurrentSiteValidation']); Route::get('/polygon/{uuid}', [TerrafundEditGeometryController::class, 'getSitePolygonData']); Route::get('/polygon/geojson/{uuid}', [TerrafundEditGeometryController::class, 'getPolygonGeojson']); Route::put('/polygon/{uuid}', [TerrafundEditGeometryController::class, 'updateGeometry']); + Route::delete('/polygon/{uuid}', [TerrafundEditGeometryController::class, 'deletePolygonAndSitePolygon']); + + Route::get('/polygon/bbox/{uuid}', [TerrafundEditGeometryController::class, 'getPolygonBbox']); Route::put('/site-polygon/{uuid}', [TerrafundEditGeometryController::class, 'updateSitePolygon']); Route::post('/site-polygon/{uuid}/{siteUuid}', [TerrafundEditGeometryController::class, 'createSitePolygon']);