199 lines
6.8 KiB
PHP
199 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\DirectMessage;
|
|
use App\Models\DirectMessageReport;
|
|
use App\Models\Friend;
|
|
use App\Models\User;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class DirectMessageController extends Controller
|
|
{
|
|
private function formatUser(User $u): array
|
|
{
|
|
return [
|
|
'id' => $u->id,
|
|
'username' => $u->username,
|
|
'name' => $u->name,
|
|
'avatar' => $u->avatar,
|
|
'avatar_url' => $u->avatar_url,
|
|
];
|
|
}
|
|
|
|
private function formatMessage(DirectMessage $m): array
|
|
{
|
|
return [
|
|
'id' => $m->id,
|
|
'message' => $m->is_deleted ? null : $m->message,
|
|
'sender_id' => $m->sender_id,
|
|
'is_deleted' => $m->is_deleted,
|
|
'is_read' => $m->is_read,
|
|
'created_at' => $m->created_at,
|
|
'user' => $m->sender ? $this->formatUser($m->sender) : null,
|
|
'reply_to' => $m->replyTo ? [
|
|
'id' => $m->replyTo->id,
|
|
'message' => $m->replyTo->is_deleted ? null : $m->replyTo->message,
|
|
'sender_id' => $m->replyTo->sender_id,
|
|
] : null,
|
|
];
|
|
}
|
|
|
|
// GET /api/dm/conversations
|
|
public function conversations()
|
|
{
|
|
$me = Auth::id();
|
|
|
|
$sent = DirectMessage::where('sender_id', $me)->select('receiver_id as partner_id');
|
|
$received = DirectMessage::where('receiver_id', $me)->select('sender_id as partner_id');
|
|
|
|
$partnerIds = $sent->union($received)->pluck('partner_id')->unique()->values();
|
|
|
|
$conversations = $partnerIds->map(function ($pid) use ($me) {
|
|
$partner = User::select('id', 'username', 'name', 'avatar', 'avatar_url')->find($pid);
|
|
if (!$partner) return null;
|
|
|
|
$lastMsg = DirectMessage::where(function ($q) use ($me, $pid) {
|
|
$q->where('sender_id', $me)->where('receiver_id', $pid);
|
|
})->orWhere(function ($q) use ($me, $pid) {
|
|
$q->where('sender_id', $pid)->where('receiver_id', $me);
|
|
})->orderByDesc('created_at')->first();
|
|
|
|
$unread = DirectMessage::where('sender_id', $pid)
|
|
->where('receiver_id', $me)
|
|
->where('is_read', false)
|
|
->count();
|
|
|
|
return [
|
|
'partner' => $this->formatUser($partner),
|
|
'last_message' => $lastMsg ? [
|
|
'id' => $lastMsg->id,
|
|
'message' => $lastMsg->is_deleted ? null : $lastMsg->message,
|
|
'sender_id' => $lastMsg->sender_id,
|
|
'created_at' => $lastMsg->created_at,
|
|
] : null,
|
|
'unread_count' => $unread,
|
|
];
|
|
})->filter()->sortByDesc(fn ($c) => optional($c['last_message'])['created_at'])->values();
|
|
|
|
return response()->json(['data' => $conversations]);
|
|
}
|
|
|
|
// GET /api/dm/{userId}
|
|
public function messages($userId)
|
|
{
|
|
$me = Auth::id();
|
|
|
|
$msgs = DirectMessage::where(function ($q) use ($me, $userId) {
|
|
$q->where('sender_id', $me)->where('receiver_id', $userId);
|
|
})->orWhere(function ($q) use ($me, $userId) {
|
|
$q->where('sender_id', $userId)->where('receiver_id', $me);
|
|
})
|
|
->with(['sender:id,username,name,avatar,avatar_url', 'replyTo'])
|
|
->orderBy('created_at')
|
|
->limit(100)
|
|
->get()
|
|
->map(fn ($m) => $this->formatMessage($m));
|
|
|
|
// Mark as read
|
|
DirectMessage::where('sender_id', $userId)
|
|
->where('receiver_id', $me)
|
|
->where('is_read', false)
|
|
->update(['is_read' => true]);
|
|
|
|
return response()->json(['data' => $msgs]);
|
|
}
|
|
|
|
// POST /api/dm/{userId}
|
|
public function send(Request $request, $userId)
|
|
{
|
|
$me = Auth::id();
|
|
$request->validate([
|
|
'message' => 'required|string|max:1000',
|
|
'reply_to_id' => 'nullable|integer|exists:direct_messages,id',
|
|
]);
|
|
|
|
User::findOrFail($userId);
|
|
|
|
$areFriends = Friend::where(function ($q) use ($me, $userId) {
|
|
$q->where('user_id', $me)->where('friend_id', $userId);
|
|
})->orWhere(function ($q) use ($me, $userId) {
|
|
$q->where('user_id', $userId)->where('friend_id', $me);
|
|
})->where('status', 'accepted')->exists();
|
|
|
|
if (!$areFriends) {
|
|
return response()->json(['error' => 'You must be friends to send messages.'], 403);
|
|
}
|
|
|
|
$msg = DirectMessage::create([
|
|
'sender_id' => $me,
|
|
'receiver_id' => $userId,
|
|
'message' => $request->message,
|
|
'reply_to_id' => $request->reply_to_id,
|
|
]);
|
|
|
|
$msg->load(['sender:id,username,name,avatar,avatar_url', 'replyTo']);
|
|
|
|
return response()->json(['data' => $this->formatMessage($msg)], 201);
|
|
}
|
|
|
|
// POST /api/dm/messages/{id}/report
|
|
public function report(Request $request, $messageId)
|
|
{
|
|
$me = Auth::id();
|
|
$request->validate([
|
|
'reason' => 'required|string|max:64',
|
|
'details' => 'nullable|string|max:500',
|
|
]);
|
|
|
|
$msg = DirectMessage::where(function ($q) use ($me) {
|
|
$q->where('sender_id', $me)->orWhere('receiver_id', $me);
|
|
})->findOrFail($messageId);
|
|
|
|
DirectMessageReport::firstOrCreate(
|
|
['reporter_id' => $me, 'message_id' => $msg->id],
|
|
['reason' => $request->reason, 'details' => $request->details]
|
|
);
|
|
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
|
|
// GET /api/friends
|
|
public function friends()
|
|
{
|
|
$me = Auth::id();
|
|
|
|
$friends = Friend::where(function ($q) use ($me) {
|
|
$q->where('user_id', $me)->orWhere('friend_id', $me);
|
|
})->where('status', 'accepted')
|
|
->with(['user:id,username,name,avatar,avatar_url', 'friend:id,username,name,avatar,avatar_url'])
|
|
->get()
|
|
->map(function ($f) use ($me) {
|
|
$partner = $f->user_id === $me ? $f->friend : $f->user;
|
|
return $partner ? $this->formatUser($partner) : null;
|
|
})->filter()->values();
|
|
|
|
return response()->json(['data' => $friends]);
|
|
}
|
|
|
|
// GET /api/friends/requests
|
|
public function friendRequests()
|
|
{
|
|
$me = Auth::id();
|
|
|
|
$requests = Friend::where('friend_id', $me)
|
|
->where('status', 'pending')
|
|
->with('user:id,username,name,avatar,avatar_url')
|
|
->orderByDesc('created_at')
|
|
->get()
|
|
->map(fn ($f) => [
|
|
'id' => $f->id,
|
|
'from' => $f->user ? $this->formatUser($f->user) : null,
|
|
'created_at' => $f->created_at,
|
|
])->filter(fn ($r) => $r['from'] !== null)->values();
|
|
|
|
return response()->json(['data' => $requests]);
|
|
}
|
|
}
|