Initialer Laravel Commit für BetiX
This commit is contained in:
249
app/Http/Controllers/ChatController.php
Normal file
249
app/Http/Controllers/ChatController.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\ChatMessage;
|
||||
use App\Models\ChatMessageReaction;
|
||||
use App\Models\ChatMessageReport;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ChatController extends Controller
|
||||
{
|
||||
private function formatMessage(ChatMessage $m, int $authId = 0): array
|
||||
{
|
||||
$user = $m->user;
|
||||
$reactionsAgg = [];
|
||||
|
||||
foreach ($m->reactions->groupBy('emoji') as $emoji => $group) {
|
||||
$reactionsAgg[] = [
|
||||
'emoji' => $emoji,
|
||||
'count' => $group->count(),
|
||||
'reactedByMe' => $group->contains('user_id', $authId),
|
||||
];
|
||||
}
|
||||
|
||||
$replyTo = null;
|
||||
if ($m->reply_to_id && $m->replyTo) {
|
||||
$replyTo = [
|
||||
'id' => $m->replyTo->id,
|
||||
'message' => $m->replyTo->message,
|
||||
'user' => [
|
||||
'id' => $m->replyTo->user?->id,
|
||||
'username' => $m->replyTo->user?->username,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $m->id,
|
||||
'user_id' => $m->user_id,
|
||||
'message' => $m->is_deleted ? null : $m->message,
|
||||
'is_deleted' => (bool) $m->is_deleted,
|
||||
'deleted_by_user' => $m->is_deleted && $m->deletedByUser ? [
|
||||
'id' => $m->deletedByUser->id,
|
||||
'username' => $m->deletedByUser->username,
|
||||
'role' => $m->deletedByUser->role ?? 'user',
|
||||
] : null,
|
||||
'reply_to_id' => $m->reply_to_id,
|
||||
'reply_to' => $replyTo,
|
||||
'created_at' => $m->created_at?->toIso8601String(),
|
||||
'user' => [
|
||||
'id' => $user?->id,
|
||||
'username' => $user?->username,
|
||||
'avatar_url' => $user?->avatar_url ?? $user?->avatar ?? null,
|
||||
'role' => $user?->role ?? 'user',
|
||||
'vip_level' => (int) ($user?->vip_level ?? 0),
|
||||
'clan_tag' => $user?->clan_tag ?? null,
|
||||
],
|
||||
'reactions_agg' => $reactionsAgg,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* List recent chat messages from local DB.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$limit = min(max((int) $request->query('limit', 50), 1), 200);
|
||||
$afterId = $request->query('after_id');
|
||||
$authId = (int) optional($request->user())->id;
|
||||
|
||||
$query = ChatMessage::with([
|
||||
'user:id,username,avatar,avatar_url,role,vip_level,clan_tag',
|
||||
'reactions',
|
||||
'replyTo:id,message,user_id',
|
||||
'replyTo.user:id,username',
|
||||
'deletedByUser:id,username,role',
|
||||
])->orderBy('id', 'asc');
|
||||
|
||||
if ($afterId !== null) {
|
||||
$query->where('id', '>', (int) $afterId);
|
||||
} else {
|
||||
// Return last N messages
|
||||
$query = ChatMessage::with([
|
||||
'user:id,username,avatar,avatar_url,role,vip_level,clan_tag',
|
||||
'reactions',
|
||||
'replyTo:id,message,user_id',
|
||||
'replyTo.user:id,username',
|
||||
])->orderBy('id', 'desc')->limit($limit);
|
||||
|
||||
$messages = $query->get()->reverse()->values();
|
||||
$formatted = $messages->map(fn ($m) => $this->formatMessage($m, $authId))->values()->all();
|
||||
$lastId = $messages->last()?->id;
|
||||
|
||||
return response()->json(['data' => $formatted, 'last_id' => $lastId]);
|
||||
}
|
||||
|
||||
$messages = $query->limit($limit)->get();
|
||||
$formatted = $messages->map(fn ($m) => $this->formatMessage($m, $authId))->values()->all();
|
||||
$lastId = $messages->last()?->id;
|
||||
|
||||
return response()->json(['data' => $formatted, 'last_id' => $lastId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new chat message in local DB.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) return response()->json(['message' => 'Unauthenticated'], 401);
|
||||
|
||||
$validated = $request->validate([
|
||||
'message' => ['required', 'string', 'min:1', 'max:300'],
|
||||
'reply_to_id' => ['nullable', 'integer', 'exists:chat_messages,id'],
|
||||
]);
|
||||
|
||||
// Check local chat ban
|
||||
$chatBan = \App\Models\UserRestriction::where('user_id', $user->id)
|
||||
->where('type', 'chat_ban')
|
||||
->where('active', true)
|
||||
->where(fn($q) => $q->whereNull('ends_at')->orWhere('ends_at', '>', now()))
|
||||
->first();
|
||||
if ($chatBan) {
|
||||
return response()->json([
|
||||
'message' => 'Du bist vom Chat gebannt.',
|
||||
'type' => 'chat_ban',
|
||||
'ends_at' => $chatBan->ends_at?->toIso8601String(),
|
||||
], 403);
|
||||
}
|
||||
|
||||
$msg = ChatMessage::create([
|
||||
'user_id' => $user->id,
|
||||
'message' => $validated['message'],
|
||||
'reply_to_id' => $validated['reply_to_id'] ?? null,
|
||||
]);
|
||||
|
||||
$msg->load([
|
||||
'user:id,username,avatar,avatar_url,role,vip_level,clan_tag',
|
||||
'reactions',
|
||||
'replyTo:id,message,user_id',
|
||||
'replyTo.user:id,username',
|
||||
'deletedByUser:id,username,role',
|
||||
]);
|
||||
|
||||
return response()->json(['data' => $this->formatMessage($msg, (int) $user->id)], 201);
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft-delete a chat message (admin/mod only).
|
||||
*/
|
||||
public function destroy(Request $request, int $id)
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) return response()->json(['message' => 'Unauthenticated'], 401);
|
||||
|
||||
$role = strtolower((string) $user->role);
|
||||
if (!in_array($role, ['admin', 'moderator', 'mod'])) {
|
||||
return response()->json(['message' => 'Forbidden'], 403);
|
||||
}
|
||||
|
||||
$msg = ChatMessage::findOrFail($id);
|
||||
$msg->update(['is_deleted' => true, 'deleted_by' => $user->id]);
|
||||
|
||||
$msg->load([
|
||||
'user:id,username,avatar,avatar_url,role,vip_level,clan_tag',
|
||||
'reactions',
|
||||
'replyTo:id,message,user_id',
|
||||
'replyTo.user:id,username',
|
||||
'deletedByUser:id,username,role',
|
||||
]);
|
||||
|
||||
return response()->json(['data' => $this->formatMessage($msg, (int) $user->id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle a reaction on a message.
|
||||
*/
|
||||
public function react(Request $request, int $id)
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) return response()->json(['message' => 'Unauthenticated'], 401);
|
||||
|
||||
$validated = $request->validate([
|
||||
'emoji' => ['required', 'string', 'max:8'],
|
||||
]);
|
||||
|
||||
$msg = ChatMessage::findOrFail($id);
|
||||
|
||||
$existing = ChatMessageReaction::where([
|
||||
'message_id' => $msg->id,
|
||||
'user_id' => $user->id,
|
||||
'emoji' => $validated['emoji'],
|
||||
])->first();
|
||||
|
||||
if ($existing) {
|
||||
$existing->delete();
|
||||
} else {
|
||||
ChatMessageReaction::create([
|
||||
'message_id' => $msg->id,
|
||||
'user_id' => $user->id,
|
||||
'emoji' => $validated['emoji'],
|
||||
]);
|
||||
}
|
||||
|
||||
$msg->load([
|
||||
'user:id,username,avatar,avatar_url,role,vip_level,clan_tag',
|
||||
'reactions',
|
||||
'replyTo:id,message,user_id',
|
||||
'replyTo.user:id,username',
|
||||
'deletedByUser:id,username,role',
|
||||
]);
|
||||
|
||||
return response()->json(['data' => $this->formatMessage($msg, (int) $user->id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a chat message.
|
||||
*/
|
||||
public function report(Request $request, int $id)
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) return response()->json(['message' => 'Unauthenticated'], 401);
|
||||
|
||||
$validated = $request->validate([
|
||||
'message_text' => ['required', 'string', 'max:500'],
|
||||
'sender_id' => ['nullable', 'integer'],
|
||||
'sender_username' => ['nullable', 'string', 'max:255'],
|
||||
'reason' => ['nullable', 'string', 'max:255'],
|
||||
'context_messages' => ['nullable', 'array'],
|
||||
'context_messages.*.id' => ['nullable'],
|
||||
'context_messages.*.message' => ['nullable', 'string', 'max:500'],
|
||||
'context_messages.*.user' => ['nullable', 'array'],
|
||||
'context_messages.*.created_at' => ['nullable', 'string'],
|
||||
]);
|
||||
|
||||
ChatMessageReport::create([
|
||||
'reporter_id' => $user->id,
|
||||
'message_id' => (string) $id,
|
||||
'message_text' => $validated['message_text'],
|
||||
'sender_id' => $validated['sender_id'] ?? null,
|
||||
'sender_username' => $validated['sender_username'] ?? null,
|
||||
'reason' => $validated['reason'] ?? null,
|
||||
'context_messages' => $validated['context_messages'] ?? null,
|
||||
]);
|
||||
|
||||
return response()->json(['message' => 'Reported.'], 201);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user