Save workspace changes
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\ArtworkAward;
|
||||
use App\Models\ArtworkMedal;
|
||||
use App\Models\ArtworkMedalStat;
|
||||
use App\Services\ArtworkMedalService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
final class ArtworkAwardController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ArtworkMedalService $service
|
||||
) {}
|
||||
|
||||
/**
|
||||
* POST /api/artworks/{id}/award
|
||||
* Award the artwork with a medal.
|
||||
*/
|
||||
public function store(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$artwork = Artwork::findOrFail($id);
|
||||
|
||||
$this->authorize('award', [ArtworkAward::class, $artwork]);
|
||||
|
||||
$data = $request->validate([
|
||||
'medal' => ['required', 'string', 'in:gold,silver,bronze'],
|
||||
]);
|
||||
|
||||
$this->service->award($artwork, $user, $data['medal']);
|
||||
|
||||
// Record activity event
|
||||
try {
|
||||
\App\Models\ActivityEvent::record(
|
||||
actorId: $user->id,
|
||||
type: \App\Models\ActivityEvent::TYPE_AWARD,
|
||||
targetType: \App\Models\ActivityEvent::TARGET_ARTWORK,
|
||||
targetId: $artwork->id,
|
||||
meta: ['medal' => $data['medal']],
|
||||
);
|
||||
} catch (\Throwable) {}
|
||||
|
||||
return response()->json(
|
||||
$this->buildPayload($artwork->id, $user->id),
|
||||
201
|
||||
);
|
||||
}
|
||||
|
||||
public function upsert(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$artwork = Artwork::findOrFail($id);
|
||||
|
||||
$this->authorize('award', [ArtworkAward::class, $artwork]);
|
||||
|
||||
$data = $request->validate([
|
||||
'medal_type' => ['required', 'string', 'in:gold,silver,bronze'],
|
||||
]);
|
||||
|
||||
$existed = ArtworkMedal::query()
|
||||
->where('artwork_id', $artwork->id)
|
||||
->where('user_id', $user->id)
|
||||
->exists();
|
||||
|
||||
$this->service->upsert($artwork, $user, $data['medal_type']);
|
||||
|
||||
return response()->json(
|
||||
array_merge($this->buildPayload($artwork->id, $user->id), [
|
||||
'message' => $existed ? 'Medal updated.' : 'Medal added.',
|
||||
]),
|
||||
$existed ? 200 : 201,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT /api/artworks/{id}/award
|
||||
* Change an existing award medal.
|
||||
*/
|
||||
public function update(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$artwork = Artwork::findOrFail($id);
|
||||
|
||||
$existingAward = ArtworkMedal::where('artwork_id', $artwork->id)
|
||||
->where('user_id', $user->id)
|
||||
->firstOrFail();
|
||||
|
||||
$this->authorize('change', $existingAward);
|
||||
|
||||
$data = $request->validate([
|
||||
'medal' => ['required', 'string', 'in:gold,silver,bronze'],
|
||||
]);
|
||||
|
||||
$this->service->changeMedal($artwork, $user, $data['medal']);
|
||||
|
||||
return response()->json($this->buildPayload($artwork->id, $user->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/artworks/{id}/award
|
||||
* Remove the user's award for this artwork.
|
||||
*/
|
||||
public function destroy(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$artwork = Artwork::findOrFail($id);
|
||||
|
||||
$existingAward = ArtworkMedal::where('artwork_id', $artwork->id)
|
||||
->where('user_id', $user->id)
|
||||
->firstOrFail();
|
||||
|
||||
$this->authorize('remove', $existingAward);
|
||||
|
||||
$this->service->removeMedal($artwork, $user);
|
||||
|
||||
return response()->json($this->buildPayload($artwork->id, $user->id));
|
||||
}
|
||||
|
||||
public function destroyMedal(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
$artwork = Artwork::findOrFail($id);
|
||||
|
||||
$this->service->removeMedal($artwork, $user);
|
||||
|
||||
return response()->json(array_merge($this->buildPayload($artwork->id, $user->id), [
|
||||
'message' => 'Medal removed.',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/artworks/{id}/awards
|
||||
* Return award stats + viewer's current award.
|
||||
*/
|
||||
public function show(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$artwork = Artwork::findOrFail($id);
|
||||
|
||||
return response()->json($this->buildPayload($artwork->id, $request->user()?->id));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// All authorization is delegated to ArtworkAwardPolicy via $this->authorize().
|
||||
|
||||
private function buildPayload(int $artworkId, ?int $userId): array
|
||||
{
|
||||
$stat = ArtworkMedalStat::find($artworkId);
|
||||
|
||||
$userAward = $userId
|
||||
? ArtworkMedal::where('artwork_id', $artworkId)
|
||||
->where('user_id', $userId)
|
||||
->value('medal_type')
|
||||
: null;
|
||||
|
||||
$medals = [
|
||||
'gold' => (int) ($stat?->gold_count ?? 0),
|
||||
'silver' => (int) ($stat?->silver_count ?? 0),
|
||||
'bronze' => (int) ($stat?->bronze_count ?? 0),
|
||||
'score' => (int) ($stat?->score_total ?? 0),
|
||||
'score_7d' => (int) ($stat?->score_7d ?? 0),
|
||||
'score_30d' => (int) ($stat?->score_30d ?? 0),
|
||||
'last_medaled_at' => $stat?->last_medaled_at?->toIsoString(),
|
||||
];
|
||||
|
||||
return [
|
||||
'awards' => $medals,
|
||||
'medals' => $medals,
|
||||
'viewer_award' => $userAward,
|
||||
'current_user_medal' => $userAward,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user