112 lines
3.8 KiB
PHP
112 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use App\Services\CaldavService;
|
|
use App\Models\Todo;
|
|
use App\Models\PipelineItem;
|
|
|
|
class CaldavSyncCommand extends Command
|
|
{
|
|
protected $signature = 'caldav:sync';
|
|
protected $description = 'Sync CalDAV VTODOs into local todos table';
|
|
|
|
public function handle(CaldavService $service)
|
|
{
|
|
// only run every 5 minutes although the task is called every minute
|
|
$cacheKey = 'caldav_sync_last_run';
|
|
if (\Illuminate\Support\Facades\Cache::has($cacheKey)) {
|
|
Log::info('CalDAV sync Throttled');
|
|
return 0;
|
|
}
|
|
Cache::put($cacheKey, true, 300);
|
|
|
|
Log::info('Running CalDAV sync');
|
|
$this->info('Starting CalDAV sync');
|
|
|
|
$todos = $service->getTodos();
|
|
|
|
$count = 0;
|
|
foreach ($todos as $todo) {
|
|
// Only update the fields that are present in CalDAV
|
|
$data = $todo->attributesToArray();
|
|
$data = array_intersect_key($data, array_flip([
|
|
'id',
|
|
'etag',
|
|
'title',
|
|
'description',
|
|
'type_id',
|
|
'url',
|
|
'due_date',
|
|
'recurring',
|
|
'priority',
|
|
'status',
|
|
'created_at',
|
|
'last_modified',
|
|
'parent',
|
|
'object',
|
|
]));
|
|
|
|
// Parse the title to extract the todoable title and todo title
|
|
if (isset($data['title'])) {
|
|
$titleParts = explode('] ', $data['title'], 2);
|
|
if (count($titleParts) === 2) {
|
|
$todoableTitle = trim($titleParts[0], '[]');
|
|
$todoTitle = $titleParts[1];
|
|
|
|
// Find the todoable model by title
|
|
$models = [
|
|
'PipelineItem' => PipelineItem::class,
|
|
// Add other models here as needed
|
|
];
|
|
|
|
foreach ($models as $modelName => $modelClass) {
|
|
$todoable = $modelClass::where('title', $todoableTitle)->first();
|
|
if ($todoable) {
|
|
$data['todoable_type'] = 'App\\Models\\' . $modelName;
|
|
$data['todoable_id'] = $todoable->id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Todo::upsert($data, 'id');
|
|
$count++;
|
|
}
|
|
|
|
// Collect hrefs/URLs returned by the CalDAV server so we can remove local
|
|
// todos that belong to this calendar but were deleted on the server.
|
|
$hrefs = array_values(array_filter(array_map(function ($t) {
|
|
return $t->url ?? null;
|
|
}, $todos)));
|
|
|
|
// Remove local todos that have a URL in this calendar but weren't returned
|
|
// by the server (i.e. they were deleted remotely). Scope deletion by
|
|
// calendar prefix to avoid touching other calendars.
|
|
$calendarId = $service->getCalendarId();
|
|
$username = config('caldav.username') ?? '';
|
|
$calendarPrefix = 'calendars/' . $username . '/' . $calendarId;
|
|
|
|
if ($calendarId && $username) {
|
|
Todo::whereNotNull('url')
|
|
->where('url', 'like', '%' . $calendarPrefix . "%")
|
|
->whereNotIn('url', $hrefs ?: [''])
|
|
->delete();
|
|
}
|
|
|
|
// Remove old todos
|
|
Todo::where('status', 'COMPLETED')
|
|
->where('last_modified', '<', now()->subDays(30)) // TODO: get from settings
|
|
->where('due_date', '<', now()->subDays(30))
|
|
->delete();
|
|
|
|
Log::info("Synced " . count($todos) . " todos.");
|
|
$this->info("Synced " . count($todos) . " todos.");
|
|
return 0;
|
|
}
|
|
}
|