Skip to content

Commit

Permalink
[TM-1438] add delayed job for active projects controller (#544)
Browse files Browse the repository at this point in the history
  • Loading branch information
LimberHope authored Nov 1, 2024
1 parent 30cce31 commit 305a410
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 104 deletions.
141 changes: 37 additions & 104 deletions app/Http/Controllers/V2/Dashboard/ActiveProjectsTableController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,117 +2,50 @@

namespace App\Http\Controllers\V2\Dashboard;

use App\Helpers\TerrafundDashboardQueryHelper;
use App\Http\Controllers\Controller;
use App\Models\V2\Forms\FormOptionList;
use App\Models\V2\Forms\FormOptionListOption;
use App\Http\Resources\DelayedJobResource;
use App\Jobs\Dashboard\RunActiveProjectsJob;
use App\Models\DelayedJob;
use App\Models\Traits\HasCacheParameter;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class ActiveProjectsTableController extends Controller
{
public function __invoke(Request $request)
{
$perPage = $request->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,
]);
}
use HasCacheParameter;

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,
'hectares_under_restoration' => round($project->sitePolygons->sum('calc_area')),
'programme' => $project->framework_key,
];
});
}

public function treesUnderRestoration($project)
{
return $project->trees_planted_count;
}

public function jobsCreated($project)
public function __invoke(Request $request)
{
$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;
try {
$cacheParameter = $this->getParametersFromRequest($request);
$cacheValue = Redis::get('active-projects-'.$cacheParameter);

if (! $cacheValue) {
$frameworks = data_get($request, 'filter.programmes', []);
$landscapes = data_get($request, 'filter.landscapes', []);
$organisations = data_get($request, 'filter.organisations.type', []);
$country = data_get($request, 'filter.country', '');

$delayedJob = DelayedJob::create();
$job = new RunActiveProjectsJob(
$delayedJob->id,
$frameworks,
$landscapes,
$organisations,
$country,
$cacheParameter
);
dispatch($job);

return (new DelayedJobResource($delayedJob))->additional(['message' => 'Data for active projects is being processed']);
} else {
return response()->json(json_decode($cacheValue));
}
} catch (\Exception $e) {
Log::error('Error during active-projects : ' . $e->getMessage());

return response()->json(['error' => 'An error occurred during active-projects'. $e->getMessage()], 500);
}
}

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);
}
}
86 changes: 86 additions & 0 deletions app/Jobs/Dashboard/RunActiveProjectsJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace App\Jobs\Dashboard;

use App\Models\DelayedJob;
use App\Services\Dashboard\RunActiveProjectsService;
use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;

class RunActiveProjectsJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;

public $timeout = 0;

protected $uuid;

protected $delayed_job_id;

protected $frameworks;

protected $landscapes;

protected $organisations;

protected $country;

protected $cacheParameter;

public function __construct(string $delayed_job_id, array $frameworks, array $landscapes, array $organisations, string $country, int $cacheParameter)
{
$this->delayed_job_id = $delayed_job_id;
$this->frameworks = $frameworks;
$this->landscapes = $landscapes;
$this->organisations = $organisations;
$this->country = $country;
$this->cacheParameter = $cacheParameter;
}

public function handle(RunActiveProjectsService $runActiveProjectsService)
{
try {
$delayedJob = DelayedJob::findOrFail($this->delayed_job_id);

$request = new Request(
[
'filter' => [
'country' => $this->country,
'programmes' => $this->frameworks,
'landscapes' => $this->landscapes,
'organisations.type' => $this->organisations,
],
]
);
$response = $runActiveProjectsService->runActiveProjectsJob($request);
Redis::set('active-projects-' . $this->cacheParameter, json_encode($response));


$delayedJob->update([
'status' => DelayedJob::STATUS_SUCCEEDED,
'payload' => ['message' => 'Active Projects Calculation completed'],
'status_code' => Response::HTTP_OK,
]);

} catch (Exception $e) {
Log::error('Error in RunActiveProjectsJob: ' . $e->getMessage());

DelayedJob::where('id', $this->delayed_job_id)->update([
'status' => DelayedJob::STATUS_FAILED,
'payload' => json_encode(['error' => $e->getMessage()]),
'status_code' => Response::HTTP_INTERNAL_SERVER_ERROR,
]);
}
}
}
117 changes: 117 additions & 0 deletions app/Services/Dashboard/RunActiveProjectsService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace App\Services\Dashboard;

use App\Helpers\TerrafundDashboardQueryHelper;
use App\Models\V2\Forms\FormOptionList;
use App\Models\V2\Forms\FormOptionListOption;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;

class RunActiveProjectsService
{
public function runActiveProjectsJob(Request $request)
{
$perPage = $request->input('per_page', PHP_INT_MAX);
$page = $request->input('page', 1);

$projects = $this->getAllProjects($request, $perPage, $page);
$count = $this->getQuery($request)->count();

return (object) [
'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,
'hectares_under_restoration' => round($project->sitePolygons->sum('calc_area')),
'programme' => $project->framework_key,
];
});
}

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);
}
}

0 comments on commit 305a410

Please sign in to comment.