Save workspace changes
This commit is contained in:
162
app/Services/Artworks/ArtworkPublicationService.php
Normal file
162
app/Services/Artworks/ArtworkPublicationService.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Services\Artworks;
|
||||
|
||||
use App\Models\ActivityEvent;
|
||||
use App\Models\Artwork;
|
||||
use App\Services\Activity\UserActivityService;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ArtworkPublicationService
|
||||
{
|
||||
public function publishNow(Artwork $artwork, ?Carbon $publishedAt = null): Artwork
|
||||
{
|
||||
$publishedAt ??= now()->utc();
|
||||
|
||||
$artwork->forceFill([
|
||||
'artwork_status' => 'published',
|
||||
'publish_at' => null,
|
||||
'artwork_timezone' => null,
|
||||
'published_at' => $publishedAt,
|
||||
'is_public' => $artwork->visibility !== Artwork::VISIBILITY_PRIVATE,
|
||||
])->save();
|
||||
|
||||
$this->syncSearch($artwork);
|
||||
$this->recordActivity($artwork);
|
||||
|
||||
return $artwork;
|
||||
}
|
||||
|
||||
public function publishIfDue(Artwork $artwork, ?Carbon $now = null): Artwork
|
||||
{
|
||||
$now ??= now()->utc();
|
||||
|
||||
if (! $this->isDue($artwork, $now)) {
|
||||
return $artwork;
|
||||
}
|
||||
|
||||
DB::transaction(function () use (&$artwork, $now): void {
|
||||
$locked = Artwork::query()
|
||||
->lockForUpdate()
|
||||
->find($artwork->id);
|
||||
|
||||
if (! $locked || ! $this->isDue($locked, $now)) {
|
||||
if ($locked) {
|
||||
$artwork = $locked;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$artwork = $this->publishNow($locked, $now);
|
||||
});
|
||||
|
||||
return $artwork->fresh() ?? $artwork;
|
||||
}
|
||||
|
||||
public function publishDueScheduled(int $limit = 100, ?Carbon $now = null): array
|
||||
{
|
||||
$now ??= now()->utc();
|
||||
|
||||
$candidates = Artwork::query()
|
||||
->where('artwork_status', 'scheduled')
|
||||
->where('publish_at', '<=', $now)
|
||||
->where('is_approved', true)
|
||||
->orderBy('publish_at')
|
||||
->limit($limit)
|
||||
->get(['id', 'user_id', 'title', 'publish_at', 'artwork_status']);
|
||||
|
||||
$published = collect();
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
$result = null;
|
||||
|
||||
DB::transaction(function () use ($candidate, $now, &$result): void {
|
||||
$locked = Artwork::query()
|
||||
->lockForUpdate()
|
||||
->where('id', $candidate->id)
|
||||
->where('artwork_status', 'scheduled')
|
||||
->first();
|
||||
|
||||
if (! $locked || ! $this->isDue($locked, $now)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->publishNow($locked, $now);
|
||||
});
|
||||
|
||||
if ($result instanceof Artwork) {
|
||||
$published->push($result);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'candidates' => $candidates,
|
||||
'published' => $published,
|
||||
];
|
||||
}
|
||||
|
||||
public function publishDueScheduledForUser(int $userId, int $limit = 100, ?Carbon $now = null): void
|
||||
{
|
||||
$now ??= now()->utc();
|
||||
|
||||
$candidateIds = Artwork::query()
|
||||
->where('user_id', $userId)
|
||||
->where('artwork_status', 'scheduled')
|
||||
->where('publish_at', '<=', $now)
|
||||
->where('is_approved', true)
|
||||
->orderBy('publish_at')
|
||||
->limit($limit)
|
||||
->pluck('id');
|
||||
|
||||
foreach ($candidateIds as $candidateId) {
|
||||
$artwork = Artwork::query()->find((int) $candidateId);
|
||||
if ($artwork) {
|
||||
$this->publishIfDue($artwork, $now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function isDue(Artwork $artwork, Carbon $now): bool
|
||||
{
|
||||
return $artwork->artwork_status === 'scheduled'
|
||||
&& $artwork->is_approved
|
||||
&& $artwork->publish_at !== null
|
||||
&& $artwork->publish_at->lte($now);
|
||||
}
|
||||
|
||||
private function syncSearch(Artwork $artwork): void
|
||||
{
|
||||
if (! method_exists($artwork, 'searchable')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$artwork->searchable();
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning("PublishScheduled: scout reindex failed for #{$artwork->id}: {$e->getMessage()}");
|
||||
}
|
||||
}
|
||||
|
||||
private function recordActivity(Artwork $artwork): void
|
||||
{
|
||||
try {
|
||||
ActivityEvent::record(
|
||||
actorId: (int) $artwork->user_id,
|
||||
type: ActivityEvent::TYPE_UPLOAD,
|
||||
targetType: ActivityEvent::TARGET_ARTWORK,
|
||||
targetId: (int) $artwork->id,
|
||||
);
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
|
||||
try {
|
||||
app(UserActivityService::class)->logUpload((int) $artwork->user_id, (int) $artwork->id);
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user