Skip to content

Commit

Permalink
feat: added sync external profile job (#748)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kyrch authored Sep 24, 2024
1 parent 61a8d53 commit ef0bfb8
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 32 deletions.
105 changes: 105 additions & 0 deletions app/Actions/Models/List/ExternalProfile/SyncExternalProfileAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

declare(strict_types=1);

namespace App\Actions\Models\List\ExternalProfile;

use App\Actions\Models\List\BaseStoreExternalProfileAction;
use App\Actions\Models\List\ExternalProfile\ExternalEntry\BaseExternalEntryAction;
use App\Actions\Models\List\ExternalProfile\ExternalEntry\BaseExternalEntryTokenAction;
use App\Actions\Models\List\ExternalProfile\ExternalEntry\Site\AnilistExternalEntryAction;
use App\Actions\Models\List\ExternalProfile\ExternalEntry\Site\AnilistExternalEntryTokenAction;
use App\Enums\Models\List\ExternalProfileSite;
use App\Models\List\External\ExternalEntry;
use App\Models\List\ExternalProfile;
use Exception;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
* Class SyncExternalProfileAction.
*/
class SyncExternalProfileAction extends BaseStoreExternalProfileAction
{
/**
* Sync the profile.
*
* @param ExternalProfile $profile
* @return ExternalProfile|null
*/
public function handle(ExternalProfile $profile): ?ExternalProfile
{
try {
DB::beginTransaction();

$action = $profile->isClaimed()
? $this->getClaimedActionClass($profile)
: $this->getUnclaimedActionClass($profile);

$entries = $action->getEntries();

$this->preloadResources($profile->site, $entries);

$externalEntries = [];
foreach ($entries as $entry) {
$externalId = Arr::get($entry, 'external_id');

foreach ($this->getAnimesByExternalId($externalId) as $anime) {
$externalEntries[] = [
ExternalEntry::ATTRIBUTE_SCORE => Arr::get($entry, ExternalEntry::ATTRIBUTE_SCORE),
ExternalEntry::ATTRIBUTE_IS_FAVORITE => Arr::get($entry, ExternalEntry::ATTRIBUTE_IS_FAVORITE),
ExternalEntry::ATTRIBUTE_WATCH_STATUS => Arr::get($entry, ExternalEntry::ATTRIBUTE_WATCH_STATUS),
ExternalEntry::ATTRIBUTE_ANIME => $anime->getKey(),
ExternalEntry::ATTRIBUTE_PROFILE => $profile->getKey(),
];
}
}

// Delete the old entries before creating new ones.
$profile->externalentries->each(function (ExternalEntry $entry) {
ExternalEntry::withoutEvents(function () use ($entry) {
$entry->delete();
});
});

ExternalEntry::insert($externalEntries);

return $profile;
} catch (Exception $e) {
Log::error($e->getMessage());

DB::rollBack();

return null;
}
}

/**
* Get the mapping for the entries token class.
*
* @param ExternalProfile $profile
* @return BaseExternalEntryTokenAction|null
*/
protected function getClaimedActionClass(ExternalProfile $profile): ?BaseExternalEntryTokenAction
{
return match ($profile->site) {
ExternalProfileSite::ANILIST => new AnilistExternalEntryTokenAction($profile->externaltoken),
default => null,
};
}

/**
* Get the mapping for the entries class.
*
* @param ExternalProfile $profile
* @return BaseExternalEntryAction|null
*/
protected function getUnclaimedActionClass(ExternalProfile $profile): ?BaseExternalEntryAction
{
return match ($profile->site) {
ExternalProfileSite::ANILIST => new AnilistExternalEntryAction($profile->toArray()),
default => null,
};
}
}
19 changes: 17 additions & 2 deletions app/Http/Controllers/List/SyncExternalProfileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
use App\Http\Controllers\Controller;
use App\Http\Middleware\Api\EnabledOnlyOnLocalhost;
use App\Http\Requests\Api\ShowRequest;
use App\Jobs\List\SyncExternalProfileJob;
use App\Models\List\ExternalProfile;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Str;
use Laravel\Pennant\Middleware\EnsureFeaturesAreActive;

Expand Down Expand Up @@ -44,9 +46,22 @@ public function show(ShowRequest $request, ExternalProfile $externalprofile)

/**
* Start a new sync job.
*
* @param ExternalProfile $externalProfile
* @return JsonResponse
*/
public function store()
public function store(ExternalProfile $externalProfile)
{
// TODO
if (!$externalProfile->canBeSynced()) {
return new JsonResponse([
'error' => 'This external profile cannot be synced at the moment.'
], 403);
}

SyncExternalProfileJob::dispatch($externalProfile);

return new JsonResponse([
'message' => 'Job dispatched.'
], 201);
}
}
71 changes: 71 additions & 0 deletions app/Jobs/List/SyncExternalProfileJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace App\Jobs\List;

use App\Actions\Models\List\ExternalProfile\SyncExternalProfileAction;
use App\Features\AllowExternalProfileManagement;
use App\Jobs\Middleware\RateLimited;
use App\Models\List\ExternalProfile;
use DateTime;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Laravel\Pennant\Feature;

/**
* Class SyncExternalProfileJob.
*/
class SyncExternalProfileJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;

/**
* Create a new job instance.
*
* @param ExternalProfile $profile
* @return void
*/
public function __construct(protected readonly ExternalProfile $profile)
{
$this->onQueue('sync-external-profile');
}

/**
* Execute the job.
*
* @return void
*/
public function handle(): void
{
if (Feature::for(null)->active(AllowExternalProfileManagement::class)) {
$action = new SyncExternalProfileAction();

$action->handle($this->profile);
}
}

/**
* Get the middleware the job should pass through.
*
* @return array
*/
public function middleware(): array
{
return [new RateLimited()];
}

/**
* Determine the time at which the job should time out.
*
* @return DateTime
*/
public function retryUntil(): DateTime
{
return now()->addMinutes(15);
}
}
10 changes: 10 additions & 0 deletions app/Models/List/ExternalProfile.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ public function isClaimed(): bool
return $this->user()->exists() || $this->externaltoken()->exists();
}

/**
* Determine if the profile can be synced.
*
* @return bool
*/
public function canBeSynced(): bool
{
return !$this->synced_at || $this->synced_at->addHours(3)->isPast();
}

/**
* Get the entries for the profile.
*
Expand Down
30 changes: 0 additions & 30 deletions database/seeders/DeletePermissionsSeeder.php

This file was deleted.

0 comments on commit ef0bfb8

Please sign in to comment.