update
This commit is contained in:
212
app/Http/Controllers/Api/SocialCompatibilityController.php
Normal file
212
app/Http/Controllers/Api/SocialCompatibilityController.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Story;
|
||||
use App\Models\StoryBookmark;
|
||||
use App\Services\SocialService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
final class SocialCompatibilityController extends Controller
|
||||
{
|
||||
public function __construct(private readonly SocialService $social) {}
|
||||
|
||||
public function like(Request $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validate([
|
||||
'entity_type' => ['required', 'string', 'in:artwork,story'],
|
||||
'entity_id' => ['required', 'integer'],
|
||||
'state' => ['nullable', 'boolean'],
|
||||
]);
|
||||
|
||||
$state = array_key_exists('state', $payload)
|
||||
? (bool) $payload['state']
|
||||
: ! $request->isMethod('delete');
|
||||
|
||||
if ($payload['entity_type'] === 'story') {
|
||||
$story = Story::published()->findOrFail((int) $payload['entity_id']);
|
||||
|
||||
$result = $this->social->toggleStoryLike($request->user(), $story, $state);
|
||||
|
||||
return response()->json([
|
||||
'ok' => (bool) ($result['ok'] ?? true),
|
||||
'liked' => (bool) ($result['liked'] ?? false),
|
||||
'likes_count' => (int) ($result['likes_count'] ?? 0),
|
||||
'is_liked' => (bool) ($result['liked'] ?? false),
|
||||
'stats' => [
|
||||
'likes' => (int) ($result['likes_count'] ?? 0),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$artworkId = (int) $payload['entity_id'];
|
||||
abort_unless(Artwork::public()->published()->whereKey($artworkId)->exists(), 404);
|
||||
|
||||
return app(ArtworkInteractionController::class)->like(
|
||||
$request->merge(['state' => $state]),
|
||||
$artworkId,
|
||||
);
|
||||
}
|
||||
|
||||
public function comments(Request $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validate([
|
||||
'entity_type' => ['required', 'string', 'in:artwork,story'],
|
||||
'entity_id' => ['required', 'integer'],
|
||||
'content' => [$request->isMethod('get') ? 'nullable' : 'required', 'string', 'min:1', 'max:10000'],
|
||||
'parent_id' => ['nullable', 'integer'],
|
||||
]);
|
||||
|
||||
if ($payload['entity_type'] === 'story') {
|
||||
if ($request->isMethod('get')) {
|
||||
$story = Story::published()->findOrFail((int) $payload['entity_id']);
|
||||
|
||||
return response()->json(
|
||||
$this->social->listStoryComments($story, $request->user()?->id, (int) $request->query('page', 1), 20)
|
||||
);
|
||||
}
|
||||
|
||||
$story = Story::published()->findOrFail((int) $payload['entity_id']);
|
||||
$comment = $this->social->addStoryComment(
|
||||
$request->user(),
|
||||
$story,
|
||||
(string) $payload['content'],
|
||||
isset($payload['parent_id']) ? (int) $payload['parent_id'] : null,
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'data' => $this->social->formatComment($comment, (int) $request->user()->id, true),
|
||||
], 201);
|
||||
}
|
||||
|
||||
$artworkId = (int) $payload['entity_id'];
|
||||
abort_unless(Artwork::public()->published()->whereKey($artworkId)->exists(), 404);
|
||||
|
||||
if ($request->isMethod('get')) {
|
||||
return app(ArtworkCommentController::class)->index($request, $artworkId);
|
||||
}
|
||||
|
||||
return app(ArtworkCommentController::class)->store(
|
||||
$request->merge([
|
||||
'content' => $payload['content'],
|
||||
'parent_id' => $payload['parent_id'] ?? null,
|
||||
]),
|
||||
$artworkId,
|
||||
);
|
||||
}
|
||||
|
||||
public function bookmark(Request $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validate([
|
||||
'entity_type' => ['required', 'string', 'in:artwork,story'],
|
||||
'entity_id' => ['required', 'integer'],
|
||||
'state' => ['nullable', 'boolean'],
|
||||
]);
|
||||
|
||||
$state = array_key_exists('state', $payload)
|
||||
? (bool) $payload['state']
|
||||
: ! $request->isMethod('delete');
|
||||
|
||||
if ($payload['entity_type'] === 'story') {
|
||||
$story = Story::published()->findOrFail((int) $payload['entity_id']);
|
||||
|
||||
$result = $this->social->toggleStoryBookmark($request->user(), $story, $state);
|
||||
|
||||
return response()->json([
|
||||
'ok' => (bool) ($result['ok'] ?? true),
|
||||
'bookmarked' => (bool) ($result['bookmarked'] ?? false),
|
||||
'bookmarks_count' => (int) ($result['bookmarks_count'] ?? 0),
|
||||
'is_bookmarked' => (bool) ($result['bookmarked'] ?? false),
|
||||
'stats' => [
|
||||
'bookmarks' => (int) ($result['bookmarks_count'] ?? 0),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$artworkId = (int) $payload['entity_id'];
|
||||
abort_unless(Artwork::public()->published()->whereKey($artworkId)->exists(), 404);
|
||||
|
||||
return app(ArtworkInteractionController::class)->bookmark(
|
||||
$request->merge(['state' => $state]),
|
||||
$artworkId,
|
||||
);
|
||||
}
|
||||
|
||||
public function bookmarks(Request $request): JsonResponse
|
||||
{
|
||||
$payload = $request->validate([
|
||||
'entity_type' => ['nullable', 'string', 'in:artwork,story'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:50'],
|
||||
]);
|
||||
|
||||
$perPage = (int) ($payload['per_page'] ?? 20);
|
||||
$userId = (int) $request->user()->id;
|
||||
$type = $payload['entity_type'] ?? null;
|
||||
|
||||
$items = collect();
|
||||
|
||||
if ($type === null || $type === 'artwork') {
|
||||
$items = $items->concat(
|
||||
Schema::hasTable('artwork_bookmarks')
|
||||
? DB::table('artwork_bookmarks')
|
||||
->join('artworks', 'artworks.id', '=', 'artwork_bookmarks.artwork_id')
|
||||
->where('artwork_bookmarks.user_id', $userId)
|
||||
->where('artworks.is_public', true)
|
||||
->where('artworks.is_approved', true)
|
||||
->select([
|
||||
'artwork_bookmarks.created_at as saved_at',
|
||||
'artworks.id',
|
||||
'artworks.title',
|
||||
'artworks.slug',
|
||||
])
|
||||
->latest('artwork_bookmarks.created_at')
|
||||
->limit($perPage)
|
||||
->get()
|
||||
->map(fn ($row) => [
|
||||
'type' => 'artwork',
|
||||
'id' => (int) $row->id,
|
||||
'title' => (string) $row->title,
|
||||
'url' => route('art.show', ['id' => (int) $row->id, 'slug' => Str::slug((string) ($row->slug ?: $row->title)) ?: (string) $row->id]),
|
||||
'saved_at' => Carbon::parse($row->saved_at)->toIso8601String(),
|
||||
])
|
||||
: collect()
|
||||
);
|
||||
}
|
||||
|
||||
if ($type === null || $type === 'story') {
|
||||
$items = $items->concat(
|
||||
StoryBookmark::query()
|
||||
->with('story:id,slug,title')
|
||||
->where('user_id', $userId)
|
||||
->latest('created_at')
|
||||
->limit($perPage)
|
||||
->get()
|
||||
->filter(fn (StoryBookmark $bookmark) => $bookmark->story !== null)
|
||||
->map(fn (StoryBookmark $bookmark) => [
|
||||
'type' => 'story',
|
||||
'id' => (int) $bookmark->story->id,
|
||||
'title' => (string) $bookmark->story->title,
|
||||
'url' => route('stories.show', ['slug' => $bookmark->story->slug]),
|
||||
'saved_at' => $bookmark->created_at?->toIso8601String(),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'data' => $items
|
||||
->sortByDesc('saved_at')
|
||||
->take($perPage)
|
||||
->values()
|
||||
->all(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user