185 lines
6.9 KiB
PHP
185 lines
6.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Conversation;
|
|
use App\Models\Message;
|
|
use App\Models\User;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class MessageApiController extends Controller
|
|
{
|
|
// GET /api/messages — conversations list
|
|
public function conversations()
|
|
{
|
|
$user = Auth::user();
|
|
|
|
$convs = $user->conversations()
|
|
->with(['participants', 'lastMessage.user'])
|
|
->orderByDesc('conversations.updated_at')
|
|
->limit(50)
|
|
->get()
|
|
->map(function ($conv) use ($user) {
|
|
$other = $conv->participants->firstWhere('id', '!=', $user->id);
|
|
$last = $conv->lastMessage;
|
|
$unread = $conv->unreadCountFor($user->id);
|
|
|
|
$preview = null;
|
|
if ($last) {
|
|
if (str_starts_with($last->body, 'IMAGE::')) $preview = '📷 Fotoğraf';
|
|
elseif (str_starts_with($last->body, 'GIF::')) $preview = '🎞 GIF';
|
|
elseif (str_starts_with($last->body, 'ANIMESHARE::')) {
|
|
try { $sd = json_decode(substr($last->body, 12), true); $preview = '🎬 ' . ($sd['title'] ?? 'Anime'); } catch (\Throwable) {}
|
|
} else {
|
|
$isMine = $last->user_id === $user->id;
|
|
$preview = ($isMine ? 'Sen: ' : '') . \Illuminate\Support\Str::limit($last->body, 60);
|
|
}
|
|
}
|
|
|
|
return [
|
|
'id' => $conv->id,
|
|
'other_user' => $other ? [
|
|
'id' => $other->id,
|
|
'name' => $other->name,
|
|
'username' => $other->username,
|
|
'avatar' => $other->avatar ? \App\Support\MediaUrl::fromStoragePath($other->avatar) : null,
|
|
] : null,
|
|
'last_message' => $last ? [
|
|
'body' => $preview ?? '',
|
|
'user_id' => $last->user_id,
|
|
'created_at' => $last->created_at?->toISOString(),
|
|
] : null,
|
|
'unread_count' => $unread,
|
|
'updated_at' => $conv->updated_at?->toISOString(),
|
|
];
|
|
});
|
|
|
|
return response()->json(['conversations' => $convs]);
|
|
}
|
|
|
|
// GET /api/messages/{conversation} — messages in a conversation
|
|
public function show(Conversation $conversation)
|
|
{
|
|
$user = Auth::user();
|
|
|
|
abort_unless($conversation->participants()->where('user_id', $user->id)->exists(), 403);
|
|
|
|
$other = $conversation->participants()->where('user_id', '!=', $user->id)->first();
|
|
|
|
$messages = $conversation->messages()
|
|
->with('user')
|
|
->orderBy('created_at')
|
|
->get()
|
|
->map(fn($m) => [
|
|
'id' => $m->id,
|
|
'user_id' => $m->user_id,
|
|
'body' => $m->body,
|
|
'created_at' => $m->created_at?->toISOString(),
|
|
'author' => [
|
|
'id' => $m->user?->id,
|
|
'name' => $m->user?->name,
|
|
'avatar' => $m->user?->avatar ? \App\Support\MediaUrl::fromStoragePath($m->user->avatar) : null,
|
|
],
|
|
]);
|
|
|
|
// Mark as read
|
|
$conversation->participants()->updateExistingPivot($user->id, ['last_read_at' => now()]);
|
|
|
|
return response()->json([
|
|
'messages' => $messages,
|
|
'other_user' => $other ? [
|
|
'id' => $other->id,
|
|
'name' => $other->name,
|
|
'username' => $other->username,
|
|
'avatar' => $other->avatar ? \App\Support\MediaUrl::fromStoragePath($other->avatar) : null,
|
|
] : null,
|
|
]);
|
|
}
|
|
|
|
// POST /api/messages/{conversation} — send a message
|
|
public function send(Request $request, Conversation $conversation)
|
|
{
|
|
$user = Auth::user();
|
|
|
|
abort_unless($conversation->participants()->where('user_id', $user->id)->exists(), 403);
|
|
|
|
$request->validate(['body' => 'required|string|max:5000']);
|
|
|
|
$message = Message::create([
|
|
'conversation_id' => $conversation->id,
|
|
'user_id' => $user->id,
|
|
'body' => $request->body,
|
|
]);
|
|
|
|
$conversation->touch();
|
|
$conversation->participants()->updateExistingPivot($user->id, ['last_read_at' => now()]);
|
|
|
|
return response()->json([
|
|
'id' => $message->id,
|
|
'user_id' => $user->id,
|
|
'body' => $message->body,
|
|
'created_at' => $message->created_at->toISOString(),
|
|
'author' => [
|
|
'id' => $user->id,
|
|
'name' => $user->name,
|
|
'avatar' => $user->avatar ? \App\Support\MediaUrl::fromStoragePath($user->avatar) : null,
|
|
],
|
|
]);
|
|
}
|
|
|
|
// POST /api/messages/start/{user} — start or open conversation
|
|
public function startConversation(User $user)
|
|
{
|
|
$me = Auth::user();
|
|
|
|
if ($me->id === $user->id) abort(422, 'Kendinize mesaj gönderemezsiniz.');
|
|
|
|
$conv = Conversation::whereHas('participants', fn($q) => $q->where('user_id', $me->id))
|
|
->whereHas('participants', fn($q) => $q->where('user_id', $user->id))
|
|
->first();
|
|
|
|
if (!$conv) {
|
|
$conv = DB::transaction(function () use ($me, $user) {
|
|
$c = Conversation::create();
|
|
$c->participants()->attach([$me->id, $user->id]);
|
|
return $c;
|
|
});
|
|
}
|
|
|
|
return response()->json(['conversation_id' => $conv->id]);
|
|
}
|
|
|
|
// GET /api/messages/{conv}/poll?after={id} — poll for new messages (mobile)
|
|
public function poll(Request $request, Conversation $conversation)
|
|
{
|
|
$user = Auth::user();
|
|
abort_unless($conversation->participants()->where('user_id', $user->id)->exists(), 403);
|
|
|
|
$after = (int) $request->query('after', 0);
|
|
|
|
$messages = $conversation->messages()
|
|
->with('user')
|
|
->where('id', '>', $after)
|
|
->orderBy('created_at')
|
|
->get()
|
|
->map(fn($m) => [
|
|
'id' => $m->id,
|
|
'user_id' => $m->user_id,
|
|
'body' => $m->body,
|
|
'created_at' => $m->created_at?->toISOString(),
|
|
'author' => [
|
|
'id' => $m->user?->id,
|
|
'name' => $m->user?->name,
|
|
'avatar' => $m->user?->avatar ? \App\Support\MediaUrl::fromStoragePath($m->user->avatar) : null,
|
|
],
|
|
]);
|
|
|
|
$conversation->participants()->updateExistingPivot($user->id, ['last_read_at' => now()]);
|
|
|
|
return response()->json(['messages' => $messages]);
|
|
}
|
|
}
|