311 lines
9.4 KiB
PHP
311 lines
9.4 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Jobs\ProjectDownloadTiffJob;
|
|
use App\Jobs\ProjectMosiacGeneratorJob;
|
|
use Carbon\CarbonPeriod;
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
|
|
class Project extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $fillable = [
|
|
'name',
|
|
'mail_template',
|
|
'mail_subject',
|
|
'mail_frequency',
|
|
'mail_day',
|
|
'download_path',
|
|
];
|
|
|
|
public static function saveWithFormData(mixed $formData)
|
|
{
|
|
$uniqueIdentifier = ['id' => $formData['id'] ?? null];
|
|
$project = Project::updateOrCreate($uniqueIdentifier, $formData);
|
|
$project->upsertBoundingBox($formData);
|
|
$project->upsertMailRecipients($formData);
|
|
}
|
|
|
|
private function upsertBoundingBox($formData)
|
|
{
|
|
$boundingBoxesData = array_map(function ($boundingBox) {
|
|
$boundingBox['project_id'] = $this->id;
|
|
unset($boundingBox['created_at']);
|
|
unset($boundingBox['updated_at']);
|
|
$boundingBox['id'] ??= null;
|
|
return $boundingBox;
|
|
}, $formData['boundingBoxes'] ?? []);
|
|
|
|
ProjectBoundingBox::upsert(
|
|
$boundingBoxesData,
|
|
['id', 'project_id'],
|
|
[
|
|
'name',
|
|
'top_left_latitude',
|
|
'top_left_longitude',
|
|
'bottom_right_latitude',
|
|
'bottom_right_longitude'
|
|
]
|
|
);
|
|
}
|
|
|
|
private function upsertMailRecipients($formData)
|
|
{
|
|
$mailRecipientsData = array_map(function ($mailRecipient) {
|
|
$mailRecipient['project_id'] = $this->id;
|
|
unset($mailRecipient['created_at']);
|
|
unset($mailRecipient['updated_at']);
|
|
$mailRecipient['id'] ??= null;
|
|
return $mailRecipient;
|
|
}, $formData['mail_recipients'] ?? []);
|
|
ProjectEmailRecipient::upsert(
|
|
$mailRecipientsData,
|
|
['id', 'project_id'],
|
|
['name', 'email',]
|
|
);
|
|
}
|
|
|
|
public function getMosaicPath()
|
|
{
|
|
return sprintf('%s/%s', $this->download_path, 'weekly_mosaic');
|
|
}
|
|
|
|
public function getMosaicList(): \Illuminate\Support\Collection
|
|
{
|
|
return collect(Storage::files($this->getMosaicPath()))
|
|
->filter(fn($file) => Str::endsWith($file, '.tif'))
|
|
->sortByDesc(function ($file) {
|
|
$parts = explode('_', str_replace('.tif', '', $file));
|
|
$week = $parts[1];
|
|
$year = $parts[2];
|
|
return $year.sprintf('%02d', $week);
|
|
})
|
|
->values();
|
|
}
|
|
|
|
protected static function boot()
|
|
{
|
|
parent::boot(); // TODO: Change the autogenerated stub
|
|
|
|
static::deleting(function ($project) {
|
|
$project->boundingBoxes()->delete();
|
|
$project->emailRecipients()->delete();
|
|
$project->mailings()->each(function ($mailing) {
|
|
$mailing->attachments()->delete();
|
|
$mailing->recipients()->delete();
|
|
});
|
|
$project->mailings()->delete();
|
|
});
|
|
}
|
|
|
|
public function reports()
|
|
{
|
|
return $this->hasMany(ProjectReport::class);
|
|
}
|
|
|
|
public function getAttachmentPathAttribute()
|
|
{
|
|
return storage_path(sprintf('%s/attachments', $this->download_path));
|
|
|
|
return '/storage/'.$this->download_path.'/attachments';
|
|
}
|
|
|
|
public function boundingBoxes()
|
|
{
|
|
return $this->hasMany(ProjectBoundingBox::class);
|
|
}
|
|
|
|
public function emailRecipients()
|
|
{
|
|
return $this->hasMany(ProjectEmailRecipient::class);
|
|
}
|
|
|
|
public function mailings()
|
|
{
|
|
return $this->hasMany(ProjectMailing::class);
|
|
}
|
|
|
|
public function downloads(): \Illuminate\Database\Eloquent\Relations\HasMany
|
|
{
|
|
return $this->hasMany(ProjectDownload::class);
|
|
}
|
|
|
|
public function mosaics(): \Illuminate\Database\Eloquent\Relations\HasMany
|
|
{
|
|
return $this->hasMany(ProjectMosaic::class);
|
|
}
|
|
|
|
|
|
public function allMosaicsPresent(Carbon $endDate): bool
|
|
{
|
|
// end date is in the future
|
|
if ($endDate->isFuture()) {
|
|
throw new \Exception('End date is in the future');
|
|
}
|
|
|
|
$mosaicsNotPresentInFilesystem = $this->getMosiacFilenameListByEndDate($endDate)
|
|
->filter(function ($filename) {
|
|
return !$this->getMosaicList()->contains(function ($mosaicFilename) use ($filename) {
|
|
return Str::endsWith($mosaicFilename, substr($filename, -16));
|
|
});
|
|
});
|
|
if ($mosaicsNotPresentInFilesystem->count() === 0) {
|
|
return true;
|
|
}
|
|
$message = sprintf(
|
|
'Missing mosaics: %s',
|
|
$mosaicsNotPresentInFilesystem->implode(', ')
|
|
);
|
|
throw new \Exception($message);
|
|
}
|
|
|
|
public function getMosiacFilenameListByEndDate(Carbon $endDate): \Illuminate\Support\Collection
|
|
{
|
|
$result = collect([]);
|
|
for ($i = 0; $i < 4; $i++) {
|
|
$week = $endDate->weekOfYear;
|
|
$year = $endDate->year;
|
|
if ($week === 53) {
|
|
$year--;
|
|
}
|
|
|
|
$result->add(sprintf('week_%02d_%04d.tif', $week, $year));
|
|
|
|
$endDate = $endDate->subWeek();
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
public function getMosiacList()
|
|
{
|
|
return collect(Storage::files($this->getMosaicPath()))
|
|
->filter(fn($file) => Str::endsWith($file, '.tif'))
|
|
->sortByDesc(function ($file) {
|
|
$parts = explode('_', str_replace('.tif', '', $file));
|
|
$week = $parts[1];
|
|
$year = $parts[2];
|
|
return $year.sprintf('%02d', $week);
|
|
})
|
|
->values();
|
|
}
|
|
|
|
public static function getAllDatesOfWeeksInYear($year, $weekNumber): Collection
|
|
{
|
|
$startOfWeek = Carbon::now()->setISODate($year, $weekNumber)->startOfWeek();
|
|
$dates = collect([]);
|
|
|
|
for ($day = 0; $day < 7; $day++) {
|
|
$dates->push((clone $startOfWeek)->addDays($day)->toDateString());
|
|
}
|
|
|
|
return $dates;
|
|
}
|
|
|
|
public function allMergedTiffsPresent(Collection $haystack, Collection $needles)
|
|
{
|
|
$needlesNotInHaystack = $needles->filter(function ($needle) use ($haystack) {
|
|
return !$haystack->contains(function ($item) use ($needle) {
|
|
return str_contains($item, $needle);
|
|
});
|
|
});
|
|
|
|
if ($needlesNotInHaystack->count() > 0) {
|
|
$message = sprintf(
|
|
'Missing merged tiffs: %s',
|
|
$needlesNotInHaystack->implode(', ')
|
|
);
|
|
|
|
throw new \Exception($message);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function getMergedTiffList()
|
|
{
|
|
return collect(Storage::files($this->download_path.'/merged_final_tif'))
|
|
->filter(fn($file) => Str::endsWith($file, '.tif'))
|
|
->sortByDesc(function ($file) {
|
|
$parts = explode('_', str_replace('.tif', '', $file));
|
|
$date = $parts[1];
|
|
return $date;
|
|
})
|
|
->values();
|
|
}
|
|
|
|
public function hasPendingDownload(): bool
|
|
{
|
|
return $this->downloads()->where('status', 'pending')->count() > 0;
|
|
}
|
|
|
|
public function hasPendingMosaic(): bool
|
|
{
|
|
return $this->mosaics()->where('status', 'pending')->count() > 0;
|
|
}
|
|
|
|
public function startDownload(Carbon $date)
|
|
{
|
|
$downloadRequest = $this->downloads()->updateOrCreate(
|
|
[
|
|
'project_id' => $this->id, // of een andere manier om project_id te bepalen
|
|
'name' => sprintf('%s.tif', $date->format('Y-m-d')),
|
|
],
|
|
[
|
|
'path' => sprintf('%s/%s/%s.tif', $this->download_path, 'merged_final_tif', $date->format('Y-m-d')),
|
|
'status' => 'pending',
|
|
]
|
|
);
|
|
ProjectDownloadTiffJob::dispatch($downloadRequest, $date);
|
|
}
|
|
|
|
public function scheduleReport($year, $week)
|
|
{
|
|
if ($this->reports()->where(['year' => $year, 'week' => $week])->count() > 0) {
|
|
return;
|
|
}
|
|
|
|
Bus::chain([
|
|
Bus::batch(self::getFileDownloadsFor($year, $week)),
|
|
Bus::batch(self::getMosiacsFor($year, $week)),
|
|
Bus::batch(self::getReport($year, $week)),
|
|
])->dispatch();
|
|
}
|
|
|
|
public function getReport($year, $week)
|
|
{
|
|
|
|
$report = $this->reports()->create([
|
|
'name' => 'Report for week '.$week.' of '.$year,
|
|
'week' => $week,
|
|
'year' => $year,
|
|
'path' => 'reports/week_'.$week.'_'.$year.'.docx',
|
|
]);
|
|
|
|
return new ProjectReportGeneratorJob($report);
|
|
}
|
|
|
|
public function getFileDownloadsFor($year, $startWeekNumber): Collection
|
|
{
|
|
$endOfRange = \Illuminate\Support\Carbon::now()->setISODate($year, $startWeekNumber)->endOfWeek();
|
|
$startOfRange = (clone $endOfRange)->subWeeks(2)->startOfWeek();
|
|
|
|
$dateRange = CarbonPeriod::create($startOfRange, $endOfRange);
|
|
|
|
return collect($dateRange)
|
|
->map(fn($date) => ProjectDownloadTiffJob::handleForDate($this, $date))
|
|
->filter();
|
|
}
|
|
|
|
public function getMosaicsFor($year, $startWeekNumber)
|
|
{
|
|
return collect(range(0, 2))
|
|
->map(fn($weekDiff) => ProjectMosiacGeneratorJob::handleFor($this, $year, $startWeekNumber - $weekDiff));
|
|
}
|
|
}
|