diff --git a/app/Helpers/GeometryHelper.php b/app/Helpers/GeometryHelper.php index 337249d85..55c25234c 100644 --- a/app/Helpers/GeometryHelper.php +++ b/app/Helpers/GeometryHelper.php @@ -8,32 +8,46 @@ class GeometryHelper { - public static function getPolygonsBbox($polygonsIds) + public function centroidOfProject($projectUuid) { - $envelopes = PolygonGeometry::whereIn('uuid', $polygonsIds) - ->selectRaw('ST_ASGEOJSON(ST_Envelope(geom)) as envelope') + $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(); - $maxX = $maxY = PHP_INT_MIN; - $minX = $minY = PHP_INT_MAX; + if ($centroids->isEmpty()) { + return null; // Return null if no centroids are found + } - foreach ($envelopes as $envelope) { - $geojson = json_decode($envelope->envelope); - $coordinates = $geojson->coordinates[0]; + $centroidCount = $centroids->count(); + $totalLatitude = 0; + $totalLongitude = 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); - } + foreach ($centroids as $centroid) { + $centroidData = json_decode($centroid->centroid, true); + $totalLatitude += $centroidData['coordinates'][1]; + $totalLongitude += $centroidData['coordinates'][0]; } - $bboxCoordinates = [$minX, $minY, $maxX, $maxY]; + $averageLatitude = $totalLatitude / $centroidCount; + $averageLongitude = $totalLongitude / $centroidCount; + + $centroidOfCentroids = json_encode([ + 'type' => 'Point', + 'coordinates' => [$averageLongitude, $averageLatitude], + ]); - return $bboxCoordinates; + return $centroidOfCentroids; } public function updateProjectCentroid(string $projectUuid) @@ -60,7 +74,10 @@ public function updateProjectCentroid(string $projectUuid) Log::info("Centroid updated for projectUuid: $projectUuid"); - return 'Centroids updated successfully!'; + return response()->json([ + 'message' => 'Centroid updated', + 'centroid' => $centroid, + ], 200); } catch (\Exception $e) { Log::error("Error updating centroid for projectUuid: $projectUuid"); @@ -72,46 +89,29 @@ public function updateProjectCentroid(string $projectUuid) } - public function centroidOfProject($projectUuid) + public static function getPolygonsBbox($polygonsIds) { - $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) + $envelopes = PolygonGeometry::whereIn('uuid', $polygonsIds) + ->selectRaw('ST_ASGEOJSON(ST_Envelope(geom)) as envelope') ->get(); - if ($centroids->isEmpty()) { - return null; // Return null if no centroids are found - } + $maxX = $maxY = PHP_INT_MIN; + $minX = $minY = PHP_INT_MAX; - $centroidCount = $centroids->count(); - $totalLatitude = 0; - $totalLongitude = 0; + foreach ($envelopes as $envelope) { + $geojson = json_decode($envelope->envelope); + $coordinates = $geojson->coordinates[0]; - foreach ($centroids as $centroid) { - $centroidData = json_decode($centroid->centroid, true); - $totalLatitude += $centroidData['coordinates'][1]; - $totalLongitude += $centroidData['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); + } } - $averageLatitude = $totalLatitude / $centroidCount; - $averageLongitude = $totalLongitude / $centroidCount; - - $centroidOfCentroids = json_encode([ - 'type' => 'Point', - 'coordinates' => [$averageLongitude, $averageLatitude], - ]); - - return $centroidOfCentroids; + return [$minX, $minY, $maxX, $maxY]; } } diff --git a/app/Http/Controllers/V2/Dashboard/ActiveProjectsTableController.php b/app/Http/Controllers/V2/Dashboard/ActiveProjectsTableController.php new file mode 100644 index 000000000..3ece3a76b --- /dev/null +++ b/app/Http/Controllers/V2/Dashboard/ActiveProjectsTableController.php @@ -0,0 +1,116 @@ +input('per_page', PHP_INT_MAX); + $page = $request->input('page', 1); + + $projects = $this->getAllProjects($request, $perPage, $page); + $count = $this->getQuery($request)->count(); + + return response()->json([ + 'current_page' => $page, + 'data' => $projects, + 'per_page' => $perPage, + 'last_page' => ceil($count / $perPage), + 'total' => $count, + ]); + } + + public function getQuery($request) + { + return TerrafundDashboardQueryHelper::buildQueryFromRequest($request) + ->with('organisation') + ->withCount(['sites', 'nurseries']); + } + + public function getAllProjects($request, $perPage, $page) + { + $query = $this->getQuery($request) + ->skip(($page - 1) * $perPage) + ->take($perPage); + + $projects = $query->get(); + + return $projects->map(function ($project) { + return [ + 'uuid' => $project->uuid, + 'name' => $project->name, + 'organisation' => $project->organisation->name, + 'trees_under_restoration' => $this->treesUnderRestoration($project), + 'jobs_created' => $this->jobsCreated($project), + 'volunteers' => $this->volunteers($project), + 'beneficiaries' => $this->beneficiaries($project), + 'survival_rate' => $project->survival_rate, + 'number_of_sites' => $project->sites_count, + 'number_of_nurseries' => $project->nurseries_count, + 'project_country' => $this->projectCountry($project->country), + 'country_slug' => $project->country, + 'number_of_trees_goal' => $project->trees_grown_goal, + 'date_added' => $project->created_at, + ]; + }); + } + + public function treesUnderRestoration($project) + { + return $project->trees_planted_count; + } + + public function jobsCreated($project) + { + $projectReport = $project->reports() + ->selectRaw('SUM(ft_total) as total_ft, SUM(pt_total) as total_pt') + ->groupBy('project_id') + ->first(); + + if ($projectReport) { + return $projectReport->total_ft + $projectReport->total_pt; + } else { + return 0; + } + } + + public function volunteers($project) + { + $totalVolunteers = $project->reports()->selectRaw('SUM(volunteer_total) as total')->first(); + + return $totalVolunteers ? intval($totalVolunteers->total) : 0; + } + + public function beneficiaries($project) + { + $totalBeneficiaries = $project->reports()->selectRaw('SUM(beneficiaries) as total')->first(); + + return $totalBeneficiaries ? intval($totalBeneficiaries->total) : 0; + } + + public function projectCountry($slug) + { + $countryId = FormOptionList::where('key', 'countries')->value('id'); + + return FormOptionListOption::where('form_option_list_id', $countryId) + ->where('slug', $slug) + ->value('label'); + } + + public function paginate($items, $perPage = 10, $page = null, $options = []) + { + $page = $page ?: (LengthAwarePaginator::resolveCurrentPage() ?: 1); + $items = $items instanceof Collection ? $items : Collection::make($items); + + return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options); + } +} diff --git a/app/Http/Controllers/V2/Dashboard/CountryDataController.php b/app/Http/Controllers/V2/Dashboard/CountryDataController.php new file mode 100644 index 000000000..48fcb98d2 --- /dev/null +++ b/app/Http/Controllers/V2/Dashboard/CountryDataController.php @@ -0,0 +1,109 @@ +selectRaw('ST_AsGeoJSON(ST_Envelope(geometry)) AS bbox, country') + ->first(); + + if (! $countryData) { + return response()->json(['error' => 'Country not found'], 404); + } + + // Decode the GeoJSON bbox + $geoJson = json_decode($countryData->bbox); + + // Extract the bounding box coordinates + $coordinates = $geoJson->coordinates[0]; + + // Get the country name + $countryName = $countryData->country; + + // Construct the bbox data in the specified format + $countryBbox = [ + $countryName, + [$coordinates[0][0], $coordinates[0][1], $coordinates[2][0], $coordinates[2][1]], + ]; + + return response()->json(['bbox' => $countryBbox]); + } + + public function getPolygonData(string $uuid) + { + $sitePolygon = SitePolygon::where('poly_id', $uuid)->first(); + + if (! $sitePolygon) { + return response()->json(['error' => 'Polygon not found'], 404); + } + + $project = $sitePolygon->project()->first(); + + if (! $project) { + Log::error("Project not found for site polygon with ID: $sitePolygon->id"); + } + + $site = $sitePolygon->site()->first(); + + if(! $site) { + Log::error("Site not found for site polygon with ID: $sitePolygon->id"); + + } + + $data = [ + ['key' => 'poly_name', 'title' => 'title', 'value' => $sitePolygon->poly_name ?? null], + ['key' => 'project_name', 'title' => 'Project', 'value' => $project->name ?? null], + ['key' => 'site_name', 'title' => 'Site', 'value' => $site?->name ?? null], + ['key' => 'num_trees', 'title' => 'Number of trees', 'value' => $sitePolygon->num_trees ?? null], + ['key' => 'plantstart', 'title' => 'Plant Start Date', 'value' => $sitePolygon->plantstart ?? null], + ['key' => 'status', 'title' => 'Status', 'value' => $sitePolygon->status ?? null], + + ]; + + return response()->json(['data' => $data]); + } + + public function getProjectData(string $uuid) + { + try { + $project = Project::isUuid($uuid)->first(); + + if (! $project) { + Log::error("Project not found for project with UUID: $uuid"); + + return response()->json(['error' => 'Project not found'], 404); + } + $countSitePolygons = $project->total_site_polygons; + + $organization = $project->organisation()->first(); + if (! $organization) { + Log::error("Organization not found for project with ID: $project->id"); + } + + $country = WorldCountryGeneralized::where('iso', $project->country)->first(); + $data = [ + ['key' => 'project_name', 'title' => 'title', 'value' => $project->name], + ['key' => 'country', 'title' => 'Country', 'value' => $country?->country], + ['key' => 'polygon_counts', 'title' => 'No. of Site - Polygons', 'value' => $countSitePolygons], + ['key' => 'organizations', 'title' => 'Organization', 'value' => $organization?->name], + ]; + + return response()->json(['data' => $data]); + } catch (\Exception $e) { + Log::error($e->getMessage()); + + return response()->json(['error' => 'An error occurred while fetching project data', 'message' => $e->getMessage()], 500); + } + + } +} diff --git a/app/Http/Controllers/V2/Dashboard/GetPolygonsController.php b/app/Http/Controllers/V2/Dashboard/GetPolygonsController.php new file mode 100644 index 000000000..cf210820b --- /dev/null +++ b/app/Http/Controllers/V2/Dashboard/GetPolygonsController.php @@ -0,0 +1,47 @@ +pluck('uuid'); + + return new GetPolygonsResource([ + 'data' => $polygons, + ]); + } + + public function getPolygonsByStatusOfProject(Request $request): GetPolygonsResource + { + $polygonsIds = TerrafundDashboardQueryHelper::getPolygonsByStatusOfProject($request); + + return new GetPolygonsResource([ + 'data' => $polygonsIds, + ]); + } + + public function getBboxOfCompleteProject(Request $request) + { + try { + $polygonsIds = TerrafundDashboardQueryHelper::getPolygonIdsOfProject($request); + $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'], 404); + } + } +}; diff --git a/app/Http/Controllers/V2/Dashboard/ProjectListExportController.php b/app/Http/Controllers/V2/Dashboard/ProjectListExportController.php new file mode 100644 index 000000000..1aa65a7af --- /dev/null +++ b/app/Http/Controllers/V2/Dashboard/ProjectListExportController.php @@ -0,0 +1,62 @@ +exportCsv($request); + } + + public function exportCsv($request) + { + $activeProjectsController = new ActiveProjectsTableController(); + $perPage = $request->input('per_page', PHP_INT_MAX); + $page = $request->input('page', 1); + + $projects = $activeProjectsController->getAllProjects($request, $perPage, $page); + + $headers = [ + 'uuid' => 'UUID', + 'name' => 'Project Name', + 'organisation' => 'Organisation', + 'project_country' => 'Country', + 'number_of_trees_goal' => 'No. of Trees Goal', + 'trees_under_restoration' => 'No. of Trees Restored', + 'jobs_created' => 'No. of Jobs Created', + 'date_added' => 'Date Added', + 'number_of_sites' => 'No. of Sites', + 'number_of_nurseries' => 'No. of Nurseries', + ]; + + $filteredProjects = []; + foreach ($projects as $project) { + $filteredProject = []; + foreach ($headers as $key => $label) { + $filteredProject[$key] = $project[$key] ?? ''; + } + $filteredProjects[] = $filteredProject; + } + + $csv = Writer::createFromString(''); + + $csv->insertOne(array_values($headers)); + + foreach ($filteredProjects as $filteredProject) { + $csv->insertOne(array_values($filteredProject)); + } + + $csvContent = $csv->toString(); + + return response($csvContent, 200, [ + 'Content-Type' => 'text/csv', + 'Content-Disposition' => 'attachment; filename=activeProject.csv', + ]); + + } +} diff --git a/app/Http/Controllers/V2/Dashboard/ViewRestorationStrategyController.php b/app/Http/Controllers/V2/Dashboard/ViewRestorationStrategyController.php new file mode 100644 index 000000000..b749c7ac3 --- /dev/null +++ b/app/Http/Controllers/V2/Dashboard/ViewRestorationStrategyController.php @@ -0,0 +1,126 @@ +buildProjectQuery($request); + + $projectIds = $query->pluck('v2_projects.id')->toArray(); + + $restorationStrategy = $this->getRestorationStrategy($projectIds); + + $landUseType = $this->getLandUseType($projectIds); + + $landTenures = $this->getLandTenures($projectIds); + + $result = [ + 'restorationStrategies' => $this->getResultArray($restorationStrategy, 'strategy'), + 'landUseTypes' => $this->getResultArray($landUseType, 'land_use'), + 'landTenures' => $this->getResultArray($landTenures, 'land_tenure'), + ]; + + return response()->json($result); + } + + private function buildProjectQuery(Request $request) + { + return TerrafundDashboardQueryHelper::buildQueryFromRequest($request); + } + + private function getRestorationStrategy(array $projectIds) + { + $conditions = implode(' OR ', array_map(function ($strategy) { + return "JSON_UNQUOTE(JSON_EXTRACT(restoration_strategy, CONCAT('\$[', numbers.n, ']'))) = '$strategy'"; + }, self::RESTORATION_STRATEGIES)); + + $numbers = implode(' UNION ALL ', array_map(function ($n) { + return "SELECT $n AS n"; + }, range(0, 3))); + + return DB::table(DB::raw("(SELECT DISTINCT + project_id, + JSON_UNQUOTE(JSON_EXTRACT(restoration_strategy, CONCAT('\$[', numbers.n, ']'))) AS strategy + FROM + v2_sites + CROSS JOIN + ($numbers) numbers + WHERE + project_id IN (" . implode(',', $projectIds) . ") + AND ($conditions) + ) AS subquery")) + ->groupBy('strategy') + ->select('strategy', DB::raw('COUNT(*) as count_per_project')) + ->get(); + } + + private function getLandUseType(array $projectIds) + { + $conditions = implode(' OR ', array_map(function ($type) { + return "JSON_UNQUOTE(JSON_EXTRACT(v2_sites.land_use_types, CONCAT('\$[', numbers.n, ']'))) = '$type'"; + }, self::LAND_USE_TYPES)); + + $numbers = implode(' UNION ALL ', array_map(function ($n) { + return "SELECT $n AS n"; + }, range(0, 4))); + + return Site::select('land_use', DB::raw('COUNT(DISTINCT v2_sites.project_id) as count_per_project')) + ->join(DB::raw("(SELECT project_id, + JSON_UNQUOTE(JSON_EXTRACT(land_use_types, CONCAT('\$[', numbers.n, ']'))) AS land_use + FROM v2_sites + CROSS JOIN + ($numbers) numbers + WHERE + v2_sites.project_id IN (" . implode(',', $projectIds) . ") + AND ($conditions) + ) AS subquery"), function ($join) { + $join->on('v2_sites.project_id', '=', 'subquery.project_id'); + }) + ->groupBy('land_use') + ->get(); + } + + private function getLandTenures(array $projectIds) + { + $conditions = implode(' OR ', array_map(function ($type) { + return "JSON_UNQUOTE(JSON_EXTRACT(v2_sites.land_tenures, CONCAT('\$[', numbers.n, ']'))) = '$type'"; + }, self::LAND_TENURES)); + + $numbers = implode(' UNION ALL ', array_map(function ($n) { + return "SELECT $n AS n"; + }, range(0, 4))); + + return Site::select('land_tenure', DB::raw('COUNT(DISTINCT v2_sites.project_id) as count_per_project')) + ->join(DB::raw("(SELECT project_id, + JSON_UNQUOTE(JSON_EXTRACT(land_tenures, CONCAT('\$[', numbers.n, ']'))) AS land_tenure + FROM v2_sites + CROSS JOIN + ($numbers) numbers + WHERE + v2_sites.project_id IN (" . implode(',', $projectIds) . ") + AND ($conditions) + ) AS subquery"), function ($join) { + $join->on('v2_sites.project_id', '=', 'subquery.project_id'); + }) + ->groupBy('land_tenure') + ->get(); + } + + private function getResultArray($data, $key) + { + return collect($data)->pluck('count_per_project', $key)->toArray(); + } +} diff --git a/app/Http/Controllers/V2/Dashboard/ViewTreeRestorationGoalController.php b/app/Http/Controllers/V2/Dashboard/ViewTreeRestorationGoalController.php new file mode 100644 index 000000000..c9ba5469c --- /dev/null +++ b/app/Http/Controllers/V2/Dashboard/ViewTreeRestorationGoalController.php @@ -0,0 +1,177 @@ +prepareProjectQuery($request); + $rawProjectIds = $this->getRawProjectIds($query); + $allProjectIds = $this->getAllProjectIds($rawProjectIds); + $siteIds = $this->getSiteIds($allProjectIds); + $distinctDates = $this->getDistinctDates($siteIds); + $latestDueDate = $this->getLatestDueDate($distinctDates); + + $forProfitProjectIds = $this->filterProjectIdsByType($rawProjectIds, 'for-profit-organization'); + $nonProfitProjectIds = $this->filterProjectIdsByType($rawProjectIds, 'non-profit-organization'); + $forProfitSiteIds = $this->getSiteIds($forProfitProjectIds); + $nonProfitSiteIds = $this->getSiteIds($nonProfitProjectIds); + + $forProfitTreeCount = $this->treeCountByDueDate($forProfitProjectIds); + $nonProfitTreeCount = $this->treeCountByDueDate($nonProfitProjectIds); + + $totalTreesGrownGoal = $query->sum('trees_grown_goal'); + + $treesUnderRestorationActualTotal = $this->treeCountPerPeriod($siteIds, $distinctDates, $totalTreesGrownGoal); + $treesUnderRestorationActualForProfit = $this->treeCountPerPeriod($forProfitSiteIds, $distinctDates, $totalTreesGrownGoal); + $treesUnderRestorationActualNonProfit = $this->treeCountPerPeriod($nonProfitSiteIds, $distinctDates, $totalTreesGrownGoal); + + $averageSurvivalRateTotal = $this->getAverageSurvival($allProjectIds); + $averageSurvivalRateForProfit = $this->getAverageSurvival($forProfitProjectIds); + $averageSurvivalRateNonProfit = $this->getAverageSurvival($nonProfitProjectIds); + + $result = [ + 'forProfitTreeCount' => (int) $forProfitTreeCount, + 'nonProfitTreeCount' => (int) $nonProfitTreeCount, + 'totalTreesGrownGoal' => (int) $totalTreesGrownGoal, + 'treesUnderRestorationActualTotal' => $treesUnderRestorationActualTotal, + 'treesUnderRestorationActualForProfit' => $treesUnderRestorationActualForProfit, + 'treesUnderRestorationActualNonProfit' => $treesUnderRestorationActualNonProfit, + 'averageSurvivalRateTotal' => floatval($averageSurvivalRateTotal), + 'averageSurvivalRateForProfit' => floatval($averageSurvivalRateForProfit), + 'averageSurvivalRateNonProfit' => floatval($averageSurvivalRateNonProfit), + ]; + + return new JsonResponse(ViewTreeRestorationGoalResource::make($result)); + } + + private function prepareProjectQuery(Request $request) + { + return TerrafundDashboardQueryHelper::buildQueryFromRequest($request); + } + + private function getRawProjectIds($query) + { + return $query + ->join('organisations', 'v2_projects.organisation_id', '=', 'organisations.id') + ->select('v2_projects.id', 'organisations.type') + ->get(); + } + + private function getAllProjectIds($projectIds) + { + return $projectIds->pluck('id')->toArray(); + } + + private function getSiteIds($projectIds) + { + return Site::whereIn('project_id', $projectIds)->where('status', EntityStatusStateMachine::APPROVED)->pluck('id'); + } + + private function getDistinctDates($siteIds) + { + return SiteReport::selectRaw('YEAR(due_at) as year, MONTH(due_at) as month') + ->whereNotNull('due_at') + ->whereIn('site_id', $siteIds) + ->groupBy('year', 'month') + ->get() + ->toArray(); + } + + private function filterProjectIdsByType($projectIds, $type) + { + return collect($projectIds)->filter(function ($row) use ($type) { + return $row->type === $type; + })->pluck('id')->toArray(); + } + + private function treeCountByDueDate(array $projectIds) + { + $projects = Project::whereIn('id', $projectIds)->get(); + + return $projects->sum(function ($project) { + return $project->trees_planted_count; + }); + } + + private function treeCountPerPeriod($siteIds, $distinctDates, $totalTreesGrownGoal) + { + $treesUnderRestorationActual = []; + $totalAmount = 0; + + foreach ($distinctDates as $date) { + $year = $date['year']; + $month = $date['month']; + $treeSpeciesAmount = 0; + + $reports = SiteReport::whereIn('site_id', $siteIds) + ->whereNotIn('v2_site_reports.status', SiteReport::UNSUBMITTED_STATUSES) + ->whereYear('v2_site_reports.due_at', $year) + ->whereMonth('v2_site_reports.due_at', $month) + ->get(); + + foreach ($reports as $report) { + $treeSpeciesAmount += $report->treeSpecies()->where('collection', TreeSpecies::COLLECTION_PLANTED)->sum('amount'); + } + + $totalAmount = $totalTreesGrownGoal; + + $formattedDate = Carbon::create($year, $month, 1); + + $treesUnderRestorationActual[] = [ + 'dueDate' => $formattedDate, + 'treeSpeciesAmount' => (int) $treeSpeciesAmount, + 'treeSpeciesPercentage' => 0, + ]; + } + + foreach ($treesUnderRestorationActual as &$treeData) { + $percentage = ($totalAmount != 0) ? ($treeData['treeSpeciesAmount'] / $totalAmount) * 100 : 0; + $treeData['treeSpeciesPercentage'] = floatval(number_format($percentage, 3)); + } + + return $treesUnderRestorationActual; + } + + private function getLatestDueDate($distinctDates) + { + $latestYear = 0; + $latestMonth = 0; + + foreach ($distinctDates as $entry) { + $year = $entry['year']; + $month = $entry['month']; + + if ($year > $latestYear || ($year == $latestYear && $month > $latestMonth)) { + $latestYear = $year; + $latestMonth = $month; + } + } + + $latestDate = [ + 'year' => $latestYear, + 'month' => $latestMonth, + ]; + + return $latestDate; + } + + private function getAverageSurvival(array $projectIds) + { + return ProjectReport::isApproved()->whereIn('project_id', $projectIds)->avg('pct_survival_to_date'); + } +} diff --git a/app/Http/Resources/V2/Dashboard/GetPolygonsResource.php b/app/Http/Resources/V2/Dashboard/GetPolygonsResource.php new file mode 100644 index 000000000..b01aaa77c --- /dev/null +++ b/app/Http/Resources/V2/Dashboard/GetPolygonsResource.php @@ -0,0 +1,19 @@ +resource; + } +} diff --git a/app/Http/Resources/V2/Dashboard/ViewTreeRestorationGoalResource.php b/app/Http/Resources/V2/Dashboard/ViewTreeRestorationGoalResource.php new file mode 100644 index 000000000..bf4af65ae --- /dev/null +++ b/app/Http/Resources/V2/Dashboard/ViewTreeRestorationGoalResource.php @@ -0,0 +1,29 @@ + (int) $this->resource['forProfitTreeCount'], + 'nonProfitTreeCount' => (int) $this->resource['nonProfitTreeCount'], + 'totalTreesGrownGoal' => (int) $this->resource['totalTreesGrownGoal'], + 'treesUnderRestorationActualTotal' => $this->resource['treesUnderRestorationActualTotal'], + 'treesUnderRestorationActualForProfit' => $this->resource['treesUnderRestorationActualForProfit'], + 'treesUnderRestorationActualNonProfit' => $this->resource['treesUnderRestorationActualNonProfit'], + 'averageSurvivalRateTotal' => floatval($this->resource['averageSurvivalRateTotal']), + 'averageSurvivalRateForProfit' => floatval($this->resource['averageSurvivalRateForProfit']), + 'averageSurvivalRateNonProfit' => floatval($this->resource['averageSurvivalRateNonProfit']), + ]; + } +} diff --git a/app/Models/V2/Projects/Project.php b/app/Models/V2/Projects/Project.php index 58bc83f7e..9350d5cd0 100644 --- a/app/Models/V2/Projects/Project.php +++ b/app/Models/V2/Projects/Project.php @@ -122,6 +122,8 @@ class Project extends Model implements MediaModel, AuditableContract, EntityMode 'pct_beneficiaries_large', 'pct_beneficiaries_youth', 'land_tenure_project_area', + 'lat', + 'long', 'answers', 'ppc_external_id', 'detailed_intervention_types', @@ -496,4 +498,9 @@ private function submittedSiteReportIds(): HasManyThrough { return $this->submittedSiteReports()->select('v2_site_reports.id'); } + + public function getTotalSitePolygonsAttribute() + { + return $this->sitePolygons()->count(); + } } diff --git a/app/Models/V2/Sites/SitePolygon.php b/app/Models/V2/Sites/SitePolygon.php index 2c60977e3..b434c3281 100644 --- a/app/Models/V2/Sites/SitePolygon.php +++ b/app/Models/V2/Sites/SitePolygon.php @@ -63,6 +63,11 @@ public function project(): BelongsToThrough ); } + public function site() + { + return $this->belongsTo(Site::class, 'site_id', 'id'); + } + public function createdBy(): HasOne { return $this->hasOne(User::class, 'id', 'created_by'); diff --git a/openapi-src/V2/definitions/DashboardBBOXCountry.yml b/openapi-src/V2/definitions/DashboardBBOXCountry.yml new file mode 100644 index 000000000..da26f3ec8 --- /dev/null +++ b/openapi-src/V2/definitions/DashboardBBOXCountry.yml @@ -0,0 +1,6 @@ +type: object +properties: + bbox: + type: array + items: + type: number \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardBBOXProject.yml b/openapi-src/V2/definitions/DashboardBBOXProject.yml new file mode 100644 index 000000000..da26f3ec8 --- /dev/null +++ b/openapi-src/V2/definitions/DashboardBBOXProject.yml @@ -0,0 +1,6 @@ +type: object +properties: + bbox: + type: array + items: + type: number \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardGetPolygonStatusResponse.yml b/openapi-src/V2/definitions/DashboardGetPolygonStatusResponse.yml new file mode 100644 index 000000000..c32e7b879 --- /dev/null +++ b/openapi-src/V2/definitions/DashboardGetPolygonStatusResponse.yml @@ -0,0 +1,13 @@ +properties: + data: + type: array + properties: + NeedsMoreInfo: + type: array + description: Ids of polygons that need more information + Submitted: + type: array + description: Ids of submitted polygons + Approved: + type: array + description: Ids of approved polygons \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardGetProjectsData.yml b/openapi-src/V2/definitions/DashboardGetProjectsData.yml new file mode 100644 index 000000000..1a11b4df2 --- /dev/null +++ b/openapi-src/V2/definitions/DashboardGetProjectsData.yml @@ -0,0 +1,12 @@ +type: object +properties: + uuid: + type: string + name: + type: string + lat: + type: number + format: double + long: + type: number + format: double \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardGetProjectsResponse.yml b/openapi-src/V2/definitions/DashboardGetProjectsResponse.yml new file mode 100644 index 000000000..1b5258c43 --- /dev/null +++ b/openapi-src/V2/definitions/DashboardGetProjectsResponse.yml @@ -0,0 +1,6 @@ +type: object +properties: + data: + type: array + items: + $ref: './_index.yml#/DashboardGetProjectsData' \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardJobsCreatedData.yml b/openapi-src/V2/definitions/DashboardJobsCreatedData.yml new file mode 100644 index 000000000..01fcdf9f7 --- /dev/null +++ b/openapi-src/V2/definitions/DashboardJobsCreatedData.yml @@ -0,0 +1,36 @@ +type: object +properties: + totalJobsCreated: + type: integer + forProfitJobsCreated: + type: integer + nonProfitJobsCreated: + type: integer + total_ft: + type: integer + total_pt: + type: integer + total_men: + type: integer + total_pt_men: + type: integer + total_ft_men: + type: integer + total_women: + type: integer + total_pt_women: + type: integer + total_ft_women: + type: integer + total_youth: + type: integer + total_pt_youth: + type: integer + total_ft_youth: + type: integer + total_non_youth: + type: integer + total_pt_non_youth: + type: integer + total_ft_non_youth: + type: integer \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardJobsCreatedResponse.yml b/openapi-src/V2/definitions/DashboardJobsCreatedResponse.yml new file mode 100644 index 000000000..871e86211 --- /dev/null +++ b/openapi-src/V2/definitions/DashboardJobsCreatedResponse.yml @@ -0,0 +1,4 @@ +type: object +properties: + data: + $ref: './_index.yml#/DashboardJobsCreatedData' \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardPolygonData.yml b/openapi-src/V2/definitions/DashboardPolygonData.yml new file mode 100644 index 000000000..476d85e3a --- /dev/null +++ b/openapi-src/V2/definitions/DashboardPolygonData.yml @@ -0,0 +1,16 @@ +type: object +properties: + data: + type: array + items: + type: object + properties: + title: + type: string + description: Title of the data field + value: + type: string + description: Value of the data field + key: + type: string + description: Key of the data field \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardRestorationStrategyResponse.yml b/openapi-src/V2/definitions/DashboardRestorationStrategyResponse.yml new file mode 100644 index 000000000..faa59812d --- /dev/null +++ b/openapi-src/V2/definitions/DashboardRestorationStrategyResponse.yml @@ -0,0 +1,47 @@ +type: object +properties: + restorationStrategies: + type: object + properties: + direct-seeding: + type: integer + tree-planting: + type: integer + assisted-natural-regeneration: + type: integer + landUseTypes: + type: object + properties: + agroforest: + type: integer + open-natural-ecosystem: + type: integer + mangrove: + type: integer + natural-forest: + type: integer + peatland: + type: integer + riparian-area-or-wetland: + type: integer + silvopasture: + type: integer + urban-forest: + type: integer + woodlot-or-plantation: + type: integer + landTenures: + type: object + properties: + communal: + type: integer + indigenous: + type: integer + national_protected_area: + type: integer + other: + type: integer + private: + type: integer + public: + type: integer \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardTreeRestorationGoalResponse.yml b/openapi-src/V2/definitions/DashboardTreeRestorationGoalResponse.yml new file mode 100644 index 000000000..1721e0dbc --- /dev/null +++ b/openapi-src/V2/definitions/DashboardTreeRestorationGoalResponse.yml @@ -0,0 +1,26 @@ +type: object +properties: + forProfitTreeCount: + type: integer + nonProfitTreeCount: + type: integer + totalTreesGrownGoal: + type: integer + treesUnderRestorationActualTotal: + type: array + items: + $ref: './_index.yml#/DashboardTreesUnderRestorationActual' + treesUnderRestorationActualForProfit: + type: array + items: + $ref: './_index.yml#/DashboardTreesUnderRestorationActual' + treesUnderRestorationActualNonProfit: + type: array + items: + $ref: './_index.yml#/DashboardTreesUnderRestorationActual' + averageSurvivalRateTotal: + type: number + averageSurvivalRateForProfit: + type: number + averageSurvivalRateNonProfit: + type: number \ No newline at end of file diff --git a/openapi-src/V2/definitions/DashboardTreesUnderRestorationActual.yml b/openapi-src/V2/definitions/DashboardTreesUnderRestorationActual.yml new file mode 100644 index 000000000..8549a3627 --- /dev/null +++ b/openapi-src/V2/definitions/DashboardTreesUnderRestorationActual.yml @@ -0,0 +1,9 @@ +type: object +properties: + dueDate: + type: string + format: date + treeSpeciesAmount: + type: integer + treeSpeciesPercentage: + type: number \ No newline at end of file diff --git a/openapi-src/V2/definitions/_index.yml b/openapi-src/V2/definitions/_index.yml index 9213aea8e..8bb6ff277 100644 --- a/openapi-src/V2/definitions/_index.yml +++ b/openapi-src/V2/definitions/_index.yml @@ -291,4 +291,26 @@ SitePolygonResponse: SitePolygonCreateResponse: $ref: './SitePolygonCreateResponse.yml' GeoJSONResponse: - $ref: './GeoJSONResponse.yml' \ No newline at end of file + $ref: './GeoJSONResponse.yml' +DashboardJobsCreatedResponse: + $ref: './DashboardJobsCreatedResponse.yml' +DashboardJobsCreatedData: + $ref: './DashboardJobsCreatedData.yml' +DashboardRestorationStrategyResponse: + $ref: './DashboardRestorationStrategyResponse.yml' +DashboardTreeRestorationGoalResponse: + $ref: './DashboardTreeRestorationGoalResponse.yml' +DashboardTreesUnderRestorationActual: + $ref: './DashboardTreesUnderRestorationActual.yml' +DashboardGetProjectsResponse: + $ref: './DashboardGetProjectsResponse.yml' +DashboardGetProjectsData: + $ref: './DashboardGetProjectsData.yml' +DashboardGetPolygonStatusResponse: + $ref: './DashboardGetPolygonStatusResponse.yml' +DashboardBBOXProject: + $ref: './DashboardBBOXProject.yml' +DashboardBBOXCountry: + $ref: './DashboardBBOXCountry.yml' +DashboardPolygonData: + $ref: './DashboardPolygonData.yml' \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-country.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-country.yml new file mode 100644 index 000000000..e2cea3338 --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-country.yml @@ -0,0 +1,16 @@ +summary: Get the bounding box of a country +tags: + - Country +parameters: + - in: path + name: country + type: string + description: ISO code of the country + required: true +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/DashboardBBOXCountry' + '404': + description: Country not found \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-bbox-project.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-bbox-project.yml new file mode 100644 index 000000000..2f25e13af --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-bbox-project.yml @@ -0,0 +1,16 @@ +summary: Get Bbox of all polygons of project +tags: + - Projects +parameters: + - in: query + name: uuid + type: string + description: UUID of the project + required: true +responses: + '200': + description: Successful response + schema: + $ref: ../../definitions/_index.yml#/DashboardBBOXProject + '404': + description: Project not found \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-polygons-statuses.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-polygons-statuses.yml new file mode 100644 index 000000000..1fc7e17b3 --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-polygons-statuses.yml @@ -0,0 +1,17 @@ +summary: Retrieve all polygons. +description: | + This endpoint returns all polygons by project uuid. +parameters: + - in: query + name: uuid + type: string + description: uuid for the given project +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/DashboardGetPolygonStatusResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-polygons.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-polygons.yml new file mode 100644 index 000000000..96bb442d3 --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-get-polygons.yml @@ -0,0 +1,17 @@ +summary: Retrieve all polygons. +description: | + This endpoint returns all polygons by project uuid. +parameters: + - in: query + name: uuid + type: string + description: uuid for the given project +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/DashboardGetProjectsResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-jobs-created.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-jobs-created.yml new file mode 100644 index 000000000..f11c47321 --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-jobs-created.yml @@ -0,0 +1,19 @@ +summary: view Jobs created for dashboard +parameters: + - in: query + name: country + type: string + description: Optional. Filter counts and metrics by country. + - in: query + name: uuid + type: string + description: Optional. Filter counts and metrics by UUID. +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/DashboardJobsCreatedResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-polygon-data-uuid.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-polygon-data-uuid.yml new file mode 100644 index 000000000..c74a4d4ec --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-polygon-data-uuid.yml @@ -0,0 +1,16 @@ +summary: Get Get allowed to project +tags: + - Get allowed to project +parameters: + - in: path + name: uuid + type: string + description: UUID of the polygon + required: true +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/DashboardPolygonData' + '404': + description: Polygon not found \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-project-data-uuid.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-project-data-uuid.yml new file mode 100644 index 000000000..964c02a42 --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-project-data-uuid.yml @@ -0,0 +1,16 @@ +summary: Get project point data by UUID +tags: + - Project point data by UUID +parameters: + - in: path + name: uuid + type: string + description: UUID of the project point + required: true +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/DashboardPolygonData' + '500': + description: Error in queries \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-project-list-export.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-project-list-export.yml new file mode 100644 index 000000000..e954d9cd7 --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-project-list-export.yml @@ -0,0 +1,10 @@ +summary: Export CSV document of active projects +tags: + - Export +produces: + - text/plain +responses: + '200': + description: OK + schema: + type: file \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-restoration-strategy.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-restoration-strategy.yml new file mode 100644 index 000000000..3f74571cd --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-restoration-strategy.yml @@ -0,0 +1,19 @@ +summary: View Restoration Strategy for dashboard +parameters: + - in: query + name: country + type: string + description: Optional. Filter restoration strategy by country. + - in: query + name: uuid + type: string + description: Optional. Filter restoration strategy by UUID. +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/DashboardRestorationStrategyResponse' + '400': + description: Bad request + '500': + description: Internal server error \ No newline at end of file diff --git a/openapi-src/V2/paths/Dashboard/get-v2-dashboard-tree-restoration-goal.yml b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-tree-restoration-goal.yml new file mode 100644 index 000000000..9df68908d --- /dev/null +++ b/openapi-src/V2/paths/Dashboard/get-v2-dashboard-tree-restoration-goal.yml @@ -0,0 +1,19 @@ +summary: View Tree Restoration Goal for dashboard +parameters: + - in: query + name: country + type: string + description: Optional. Filter tree restoration goal by country. + - in: query + name: uuid + type: string + description: Optional. Filter tree restoration goal by UUID. +responses: + '200': + description: Successful response + schema: + $ref: '../../definitions/_index.yml#/DashboardTreeRestorationGoalResponse' + '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 23ebcc55d..3900cd570 100644 --- a/openapi-src/V2/paths/_index.yml +++ b/openapi-src/V2/paths/_index.yml @@ -2554,4 +2554,34 @@ $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 + $ref: './Terrafund/delete-v2-polygon-uuid.yml' +/v2/dashboard/jobs-created: + get: + $ref: './Dashboard/get-v2-dashboard-jobs-created.yml' +'/v2/dashboard/restoration-strategy': + get: + $ref: './Dashboard/get-v2-dashboard-restoration-strategy.yml' +'/v2/dashboard/tree-restoration-goal': + get: + $ref: './Dashboard/get-v2-dashboard-tree-restoration-goal.yml' +'/v2/dashboard/project-list-export': + get: + $ref: './Dashboard/get-v2-dashboard-project-list-export.yml' +/v2/dashboard/get-polygons: + get: + $ref: './Dashboard/get-v2-dashboard-get-polygons.yml' +/v2/dashboard/get-polygons/statuses: + get: + $ref: './Dashboard/get-v2-dashboard-get-polygons-statuses.yml' +/v2/dashboard/get-bbox-project: + get: + $ref: './Dashboard/get-v2-dashboard-get-bbox-project.yml' +/v2/dashboard/country/{country}: + get: + $ref: './Dashboard/get-v2-dashboard-country.yml' +/v2/dashboard/polygon-data/{uuid}: + get: + $ref: './Dashboard/get-v2-dashboard-polygon-data-uuid.yml' +/v2/dashboard/project-data/{uuid}: + get: + $ref: './Dashboard/get-v2-dashboard-project-data-uuid.yml' \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 492c76df4..3f348d81b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,10 @@ { - "name": "wri-terramatch-api", + "name": "wri-restoration-marketplace-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 cbfbdd6e8..6a32704fa 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" + "vue-template-compiler": "^2.6.10", + "postcss": "^8.2.8" }, "dependencies": { "swagger-ui-dist": "^3.23.3" diff --git a/resources/docs/swagger-v2.yml b/resources/docs/swagger-v2.yml index 20eebcf24..aeff0dffc 100644 --- a/resources/docs/swagger-v2.yml +++ b/resources/docs/swagger-v2.yml @@ -44294,6 +44294,268 @@ definitions: type: string num_trees: type: integer + DashboardJobsCreatedResponse: + type: object + properties: + data: + type: object + properties: + totalJobsCreated: + type: integer + forProfitJobsCreated: + type: integer + nonProfitJobsCreated: + type: integer + total_ft: + type: integer + total_pt: + type: integer + total_men: + type: integer + total_pt_men: + type: integer + total_ft_men: + type: integer + total_women: + type: integer + total_pt_women: + type: integer + total_ft_women: + type: integer + total_youth: + type: integer + total_pt_youth: + type: integer + total_ft_youth: + type: integer + total_non_youth: + type: integer + total_pt_non_youth: + type: integer + total_ft_non_youth: + type: integer + DashboardJobsCreatedData: + type: object + properties: + totalJobsCreated: + type: integer + forProfitJobsCreated: + type: integer + nonProfitJobsCreated: + type: integer + total_ft: + type: integer + total_pt: + type: integer + total_men: + type: integer + total_pt_men: + type: integer + total_ft_men: + type: integer + total_women: + type: integer + total_pt_women: + type: integer + total_ft_women: + type: integer + total_youth: + type: integer + total_pt_youth: + type: integer + total_ft_youth: + type: integer + total_non_youth: + type: integer + total_pt_non_youth: + type: integer + total_ft_non_youth: + type: integer + DashboardRestorationStrategyResponse: + type: object + properties: + restorationStrategies: + type: object + properties: + direct-seeding: + type: integer + tree-planting: + type: integer + assisted-natural-regeneration: + type: integer + landUseTypes: + type: object + properties: + agroforest: + type: integer + open-natural-ecosystem: + type: integer + mangrove: + type: integer + natural-forest: + type: integer + peatland: + type: integer + riparian-area-or-wetland: + type: integer + silvopasture: + type: integer + urban-forest: + type: integer + woodlot-or-plantation: + type: integer + landTenures: + type: object + properties: + communal: + type: integer + indigenous: + type: integer + national_protected_area: + type: integer + other: + type: integer + private: + type: integer + public: + type: integer + DashboardTreeRestorationGoalResponse: + type: object + properties: + forProfitTreeCount: + type: integer + nonProfitTreeCount: + type: integer + totalTreesGrownGoal: + type: integer + treesUnderRestorationActualTotal: + type: array + items: + type: object + properties: + dueDate: + type: string + format: date + treeSpeciesAmount: + type: integer + treeSpeciesPercentage: + type: number + treesUnderRestorationActualForProfit: + type: array + items: + type: object + properties: + dueDate: + type: string + format: date + treeSpeciesAmount: + type: integer + treeSpeciesPercentage: + type: number + treesUnderRestorationActualNonProfit: + type: array + items: + type: object + properties: + dueDate: + type: string + format: date + treeSpeciesAmount: + type: integer + treeSpeciesPercentage: + type: number + averageSurvivalRateTotal: + type: number + averageSurvivalRateForProfit: + type: number + averageSurvivalRateNonProfit: + type: number + DashboardTreesUnderRestorationActual: + type: object + properties: + dueDate: + type: string + format: date + treeSpeciesAmount: + type: integer + treeSpeciesPercentage: + type: number + DashboardGetProjectsResponse: + type: object + properties: + data: + type: array + items: + type: object + properties: + uuid: + type: string + name: + type: string + lat: + type: number + format: double + long: + type: number + format: double + DashboardGetProjectsData: + type: object + properties: + uuid: + type: string + name: + type: string + lat: + type: number + format: double + long: + type: number + format: double + DashboardGetPolygonStatusResponse: + properties: + data: + type: array + properties: + NeedsMoreInfo: + type: array + description: Ids of polygons that need more information + Submitted: + type: array + description: Ids of submitted polygons + Approved: + type: array + description: Ids of approved polygons + DashboardBBOXProject: + type: object + properties: + bbox: + type: array + items: + type: number + DashboardBBOXCountry: + type: object + properties: + bbox: + type: array + items: + type: number + DashboardPolygonData: + type: object + properties: + data: + type: array + items: + type: object + properties: + title: + type: string + description: Title of the data field + value: + type: string + description: Value of the data field + key: + type: string + description: Key of the data field paths: '/v2/tree-species/{entity}/{UUID}': get: @@ -94633,3 +94895,389 @@ paths: responses: '204': description: No Content + /v2/dashboard/jobs-created: + get: + summary: view Jobs created for dashboard + parameters: + - in: query + name: country + type: string + description: Optional. Filter counts and metrics by country. + - in: query + name: uuid + type: string + description: Optional. Filter counts and metrics by UUID. + responses: + '200': + description: Successful response + schema: + type: object + properties: + data: + type: object + properties: + totalJobsCreated: + type: integer + forProfitJobsCreated: + type: integer + nonProfitJobsCreated: + type: integer + total_ft: + type: integer + total_pt: + type: integer + total_men: + type: integer + total_pt_men: + type: integer + total_ft_men: + type: integer + total_women: + type: integer + total_pt_women: + type: integer + total_ft_women: + type: integer + total_youth: + type: integer + total_pt_youth: + type: integer + total_ft_youth: + type: integer + total_non_youth: + type: integer + total_pt_non_youth: + type: integer + total_ft_non_youth: + type: integer + '400': + description: Bad request + '500': + description: Internal server error + /v2/dashboard/restoration-strategy: + get: + summary: View Restoration Strategy for dashboard + parameters: + - in: query + name: country + type: string + description: Optional. Filter restoration strategy by country. + - in: query + name: uuid + type: string + description: Optional. Filter restoration strategy by UUID. + responses: + '200': + description: Successful response + schema: + type: object + properties: + restorationStrategies: + type: object + properties: + direct-seeding: + type: integer + tree-planting: + type: integer + assisted-natural-regeneration: + type: integer + landUseTypes: + type: object + properties: + agroforest: + type: integer + open-natural-ecosystem: + type: integer + mangrove: + type: integer + natural-forest: + type: integer + peatland: + type: integer + riparian-area-or-wetland: + type: integer + silvopasture: + type: integer + urban-forest: + type: integer + woodlot-or-plantation: + type: integer + landTenures: + type: object + properties: + communal: + type: integer + indigenous: + type: integer + national_protected_area: + type: integer + other: + type: integer + private: + type: integer + public: + type: integer + '400': + description: Bad request + '500': + description: Internal server error + /v2/dashboard/tree-restoration-goal: + get: + summary: View Tree Restoration Goal for dashboard + parameters: + - in: query + name: country + type: string + description: Optional. Filter tree restoration goal by country. + - in: query + name: uuid + type: string + description: Optional. Filter tree restoration goal by UUID. + responses: + '200': + description: Successful response + schema: + type: object + properties: + forProfitTreeCount: + type: integer + nonProfitTreeCount: + type: integer + totalTreesGrownGoal: + type: integer + treesUnderRestorationActualTotal: + type: array + items: + type: object + properties: + dueDate: + type: string + format: date + treeSpeciesAmount: + type: integer + treeSpeciesPercentage: + type: number + treesUnderRestorationActualForProfit: + type: array + items: + type: object + properties: + dueDate: + type: string + format: date + treeSpeciesAmount: + type: integer + treeSpeciesPercentage: + type: number + treesUnderRestorationActualNonProfit: + type: array + items: + type: object + properties: + dueDate: + type: string + format: date + treeSpeciesAmount: + type: integer + treeSpeciesPercentage: + type: number + averageSurvivalRateTotal: + type: number + averageSurvivalRateForProfit: + type: number + averageSurvivalRateNonProfit: + type: number + '400': + description: Bad request + '500': + description: Internal server error + /v2/dashboard/project-list-export: + get: + summary: Export CSV document of active projects + tags: + - Export + produces: + - text/plain + responses: + '200': + description: OK + schema: + type: file + /v2/dashboard/get-polygons: + get: + summary: Retrieve all polygons. + description: | + This endpoint returns all polygons by project uuid. + parameters: + - in: query + name: uuid + type: string + description: uuid for the given project + responses: + '200': + description: Successful response + schema: + type: object + properties: + data: + type: array + items: + type: object + properties: + uuid: + type: string + name: + type: string + lat: + type: number + format: double + long: + type: number + format: double + '400': + description: Bad request + '500': + description: Internal server error + /v2/dashboard/get-polygons/statuses: + get: + summary: Retrieve all polygons. + description: | + This endpoint returns all polygons by project uuid. + parameters: + - in: query + name: uuid + type: string + description: uuid for the given project + responses: + '200': + description: Successful response + schema: + properties: + data: + type: array + properties: + NeedsMoreInfo: + type: array + description: Ids of polygons that need more information + Submitted: + type: array + description: Ids of submitted polygons + Approved: + type: array + description: Ids of approved polygons + '400': + description: Bad request + '500': + description: Internal server error + /v2/dashboard/get-bbox-project: + get: + summary: Get Bbox of all polygons of project + tags: + - Projects + parameters: + - in: query + name: uuid + type: string + description: UUID of the project + required: true + responses: + '200': + description: Successful response + schema: + type: object + properties: + bbox: + type: array + items: + type: number + '404': + description: Project not found + '/v2/dashboard/country/{country}': + get: + summary: Get the bounding box of a country + tags: + - Country + parameters: + - in: path + name: country + type: string + description: ISO code of the country + required: true + responses: + '200': + description: Successful response + schema: + type: object + properties: + bbox: + type: array + items: + type: number + '404': + description: Country not found + '/v2/dashboard/polygon-data/{uuid}': + get: + summary: Get Get allowed to project + tags: + - Get allowed to project + parameters: + - in: path + name: uuid + type: string + description: UUID of the polygon + required: true + responses: + '200': + description: Successful response + schema: + type: object + properties: + data: + type: array + items: + type: object + properties: + title: + type: string + description: Title of the data field + value: + type: string + description: Value of the data field + key: + type: string + description: Key of the data field + '404': + description: Polygon not found + '/v2/dashboard/project-data/{uuid}': + get: + summary: Get project point data by UUID + tags: + - Project point data by UUID + parameters: + - in: path + name: uuid + type: string + description: UUID of the project point + required: true + responses: + '200': + description: Successful response + schema: + type: object + properties: + data: + type: array + items: + type: object + properties: + title: + type: string + description: Title of the data field + value: + type: string + description: Value of the data field + key: + type: string + description: Key of the data field + '500': + description: Error in queries diff --git a/routes/api_v2.php b/routes/api_v2.php index fda002ca7..0be75ac9e 100644 --- a/routes/api_v2.php +++ b/routes/api_v2.php @@ -15,7 +15,12 @@ use App\Http\Controllers\V2\CoreTeamLeader\DeleteCoreTeamLeaderController; use App\Http\Controllers\V2\CoreTeamLeader\StoreCoreTeamLeaderController; use App\Http\Controllers\V2\CoreTeamLeader\UpdateCoreTeamLeaderController; +use App\Http\Controllers\V2\Dashboard\CountryDataController; use App\Http\Controllers\V2\Dashboard\GetJobsCreatedController; +use App\Http\Controllers\V2\Dashboard\GetPolygonsController; +use App\Http\Controllers\V2\Dashboard\ProjectListExportController; +use App\Http\Controllers\V2\Dashboard\ViewRestorationStrategyController; +use App\Http\Controllers\V2\Dashboard\ViewTreeRestorationGoalController; use App\Http\Controllers\V2\Disturbances\DeleteDisturbanceController; use App\Http\Controllers\V2\Disturbances\GetDisturbancesForEntityController; use App\Http\Controllers\V2\Disturbances\StoreDisturbanceController; @@ -665,5 +670,14 @@ function () { //Route::delete('file/{uuid}', [FilePropertiesController::class, 'destroy']); Route::prefix('dashboard')->group(function () { + Route::get('/restoration-strategy', ViewRestorationStrategyController::class); Route::get('/jobs-created', GetJobsCreatedController::class); + Route::get('/tree-restoration-goal', ViewTreeRestorationGoalController::class); + Route::get('/project-list-export', ProjectListExportController::class); + Route::get('/get-polygons', [GetPolygonsController::class, 'getPolygonsOfProject']); + Route::get('/get-polygons/statuses', [GetPolygonsController::class, 'getPolygonsByStatusOfProject']); + Route::get('/get-bbox-project', [GetPolygonsController::class, 'getBboxOfCompleteProject']); + Route::get('/country/{country}', [CountryDataController::class, 'getCountryBbox']); + Route::get('/polygon-data/{uuid}', [CountryDataController::class, 'getPolygonData']); + Route::get('/project-data/{uuid}', [CountryDataController::class, 'getProjectData']); });