messages implemented
This commit is contained in:
96
app/Http/Controllers/Api/Messaging/TypingController.php
Normal file
96
app/Http/Controllers/Api/Messaging/TypingController.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Messaging;
|
||||
|
||||
use App\Events\TypingStarted;
|
||||
use App\Events\TypingStopped;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ConversationParticipant;
|
||||
use Illuminate\Cache\Repository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class TypingController extends Controller
|
||||
{
|
||||
public function start(Request $request, int $conversationId): JsonResponse
|
||||
{
|
||||
$this->assertParticipant($request, $conversationId);
|
||||
|
||||
$ttl = max(5, (int) config('messaging.typing.ttl_seconds', 8));
|
||||
$this->store()->put($this->key($conversationId, (int) $request->user()->id), 1, now()->addSeconds($ttl));
|
||||
|
||||
if ((bool) config('messaging.realtime', false)) {
|
||||
event(new TypingStarted($conversationId, (int) $request->user()->id));
|
||||
}
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
public function stop(Request $request, int $conversationId): JsonResponse
|
||||
{
|
||||
$this->assertParticipant($request, $conversationId);
|
||||
$this->store()->forget($this->key($conversationId, (int) $request->user()->id));
|
||||
|
||||
if ((bool) config('messaging.realtime', false)) {
|
||||
event(new TypingStopped($conversationId, (int) $request->user()->id));
|
||||
}
|
||||
|
||||
return response()->json(['ok' => true]);
|
||||
}
|
||||
|
||||
public function index(Request $request, int $conversationId): JsonResponse
|
||||
{
|
||||
$this->assertParticipant($request, $conversationId);
|
||||
$userId = (int) $request->user()->id;
|
||||
|
||||
$participants = ConversationParticipant::query()
|
||||
->where('conversation_id', $conversationId)
|
||||
->whereNull('left_at')
|
||||
->where('user_id', '!=', $userId)
|
||||
->with('user:id,username')
|
||||
->get();
|
||||
|
||||
$typing = $participants
|
||||
->filter(fn ($p) => $this->store()->has($this->key($conversationId, (int) $p->user_id)))
|
||||
->map(fn ($p) => [
|
||||
'user_id' => (int) $p->user_id,
|
||||
'username' => (string) ($p->user->username ?? ''),
|
||||
])
|
||||
->values();
|
||||
|
||||
return response()->json(['typing' => $typing]);
|
||||
}
|
||||
|
||||
private function assertParticipant(Request $request, int $conversationId): void
|
||||
{
|
||||
abort_unless(
|
||||
ConversationParticipant::query()
|
||||
->where('conversation_id', $conversationId)
|
||||
->where('user_id', $request->user()->id)
|
||||
->whereNull('left_at')
|
||||
->exists(),
|
||||
403,
|
||||
'You are not a participant of this conversation.'
|
||||
);
|
||||
}
|
||||
|
||||
private function key(int $conversationId, int $userId): string
|
||||
{
|
||||
return "typing:{$conversationId}:{$userId}";
|
||||
}
|
||||
|
||||
private function store(): Repository
|
||||
{
|
||||
$store = (string) config('messaging.typing.cache_store', 'redis');
|
||||
if ($store === 'redis' && ! class_exists('Redis')) {
|
||||
return Cache::store();
|
||||
}
|
||||
|
||||
try {
|
||||
return Cache::store($store);
|
||||
} catch (\Throwable) {
|
||||
return Cache::store();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user