212 lines
8.0 KiB
PHP
212 lines
8.0 KiB
PHP
<?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(),
|
|
]);
|
|
}
|
|
} |