Initialer Laravel Commit für BetiX
This commit is contained in:
377
app/Http/Controllers/SocialController.php
Normal file
377
app/Http/Controllers/SocialController.php
Normal file
@@ -0,0 +1,377 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Friend;
|
||||
use App\Models\ProfileComment;
|
||||
use App\Models\ProfileLike;
|
||||
use App\Models\ProfileReport;
|
||||
use App\Models\Tip;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Inertia\Inertia;
|
||||
|
||||
class SocialController extends Controller
|
||||
{
|
||||
// Profile page
|
||||
public function show(string $username)
|
||||
{
|
||||
$user = User::query()
|
||||
->where('username', $username)
|
||||
->first();
|
||||
|
||||
if (!$user) {
|
||||
abort(404, 'User not found');
|
||||
}
|
||||
|
||||
$auth = Auth::user();
|
||||
$authId = $auth?->id;
|
||||
|
||||
$likesCount = ProfileLike::where('profile_id', $user->id)->count();
|
||||
$hasLiked = $authId ? ProfileLike::where('profile_id', $user->id)->where('user_id', $authId)->exists() : false;
|
||||
|
||||
$comments = ProfileComment::with(['user:id,username,avatar'])
|
||||
->where('profile_id', $user->id)
|
||||
->latest()
|
||||
->limit(20)
|
||||
->get()
|
||||
->map(function ($c) {
|
||||
return [
|
||||
'id' => $c->id,
|
||||
'user' => [
|
||||
'id' => $c->user->id,
|
||||
'username' => $c->user->username,
|
||||
'avatar' => $c->user->avatar,
|
||||
],
|
||||
'content' => $c->content,
|
||||
'created_at' => $c->created_at,
|
||||
];
|
||||
});
|
||||
|
||||
// Friendship flags
|
||||
$isFriend = false;
|
||||
$isPending = false; // I sent them a request (outgoing)
|
||||
$theyRequestedMe = false; // They sent me a request (incoming — I can accept/decline)
|
||||
$friendRowId = null;
|
||||
if ($authId) {
|
||||
$friendRow = Friend::where(function ($q) use ($authId, $user) {
|
||||
$q->where('user_id', $authId)->where('friend_id', $user->id);
|
||||
})->orWhere(function ($q) use ($authId, $user) {
|
||||
$q->where('user_id', $user->id)->where('friend_id', $authId);
|
||||
})->first();
|
||||
if ($friendRow) {
|
||||
$isFriend = $friendRow->status === 'accepted';
|
||||
$isPending = $friendRow->status === 'pending' && $friendRow->user_id == $authId;
|
||||
$theyRequestedMe = $friendRow->status === 'pending' && $friendRow->user_id == $user->id;
|
||||
$friendRowId = $friendRow->id;
|
||||
}
|
||||
}
|
||||
|
||||
$profile = [
|
||||
'id' => $user->id,
|
||||
'username' => $user->username,
|
||||
'avatar' => $user->avatar ?? $user->avatar_url,
|
||||
'banner' => $user->banner,
|
||||
'bio' => $user->bio,
|
||||
'vip_level' => (int) ($user->vip_level ?? 0),
|
||||
'role' => $user->role ?? 'User',
|
||||
'clan_tag' => $user->clan_tag,
|
||||
'stats' => [
|
||||
'wagered' => (float) ($user->stats?->total_wagered ?? 0),
|
||||
'wins' => (int) ($user->stats?->total_wins ?? 0),
|
||||
'losses' => null,
|
||||
'biggest_win' => (float) ($user->stats?->biggest_win ?? 0),
|
||||
'biggest_win_game' => $user->stats?->biggest_win_game ?? null,
|
||||
'join_date' => optional($user->created_at)->toDateString(),
|
||||
'likes_count' => $likesCount,
|
||||
],
|
||||
'best_wins' => [],
|
||||
'comments' => $comments,
|
||||
];
|
||||
|
||||
return Inertia::render('Social/Profile', [
|
||||
'profile' => $profile,
|
||||
'isOwnProfile' => $authId ? ((int)$authId === (int)$user->id) : false,
|
||||
'isFriend' => $isFriend,
|
||||
'isPending' => $isPending,
|
||||
'theyRequestedMe' => $theyRequestedMe,
|
||||
'friendRowId' => $friendRowId,
|
||||
'hasLiked' => $hasLiked,
|
||||
]);
|
||||
}
|
||||
|
||||
// Update own profile
|
||||
public function update(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
abort_unless($user, 403);
|
||||
|
||||
$data = $request->validate([
|
||||
'is_public' => 'boolean',
|
||||
'bio' => 'nullable|string|max:160',
|
||||
'avatar' => 'nullable|string',
|
||||
'banner' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$user->fill([
|
||||
'is_public' => (bool) ($data['is_public'] ?? $user->is_public),
|
||||
'bio' => $data['bio'] ?? $user->bio,
|
||||
'avatar' => $data['avatar'] ?? $user->avatar,
|
||||
'banner' => $data['banner'] ?? $user->banner,
|
||||
])->save();
|
||||
|
||||
return back()->with('success', 'Profile updated.');
|
||||
}
|
||||
|
||||
// Upload avatar or banner
|
||||
public function uploadImage(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
abort_unless($user, 403);
|
||||
|
||||
$request->validate([
|
||||
'type' => 'required|in:avatar,banner',
|
||||
'file' => 'required|file|mimes:jpeg,jpg,png,gif,webp,bmp|max:5120',
|
||||
]);
|
||||
|
||||
$file = $request->file('file');
|
||||
$type = $request->input('type');
|
||||
$path = $file->store("profile/{$type}s", 'public');
|
||||
$url = Storage::disk('public')->url($path);
|
||||
|
||||
if ($type === 'banner') {
|
||||
$user->banner = $url;
|
||||
} else {
|
||||
$user->avatar = $url;
|
||||
}
|
||||
$user->save();
|
||||
|
||||
return response()->json(['url' => $url], 200);
|
||||
}
|
||||
|
||||
// Toggle like on a profile
|
||||
public function like($id)
|
||||
{
|
||||
$me = Auth::user();
|
||||
abort_unless($me, 403);
|
||||
$target = User::findOrFail($id);
|
||||
if ($target->id === $me->id) {
|
||||
return back();
|
||||
}
|
||||
$like = ProfileLike::where('user_id', $me->id)->where('profile_id', $target->id)->first();
|
||||
if ($like) {
|
||||
$like->delete();
|
||||
} else {
|
||||
ProfileLike::create(['user_id' => $me->id, 'profile_id' => $target->id]);
|
||||
}
|
||||
return back();
|
||||
}
|
||||
|
||||
// Add a comment to a profile
|
||||
public function comment(Request $request, $id)
|
||||
{
|
||||
$me = Auth::user();
|
||||
abort_unless($me, 403);
|
||||
$data = $request->validate(['content' => 'required|string|max:500']);
|
||||
$target = User::findOrFail($id);
|
||||
ProfileComment::create([
|
||||
'user_id' => $me->id,
|
||||
'profile_id' => $target->id,
|
||||
'content' => $data['content'],
|
||||
]);
|
||||
return back()->with('success', 'Comment posted.');
|
||||
}
|
||||
|
||||
// Report a profile
|
||||
public function report(Request $request, $id)
|
||||
{
|
||||
$me = Auth::user();
|
||||
abort_unless($me, 403);
|
||||
$data = $request->validate([
|
||||
'reason' => 'required|string',
|
||||
'details' => 'nullable|string',
|
||||
'snapshot' => 'nullable|array',
|
||||
'screenshot' => 'nullable|string',
|
||||
]);
|
||||
$target = User::findOrFail($id);
|
||||
|
||||
$screenshotPath = null;
|
||||
if (!empty($data['screenshot'])) {
|
||||
$base64 = $data['screenshot'];
|
||||
// Strip data URI prefix if present
|
||||
if (str_contains($base64, ',')) {
|
||||
$base64 = explode(',', $base64, 2)[1];
|
||||
}
|
||||
$decoded = base64_decode($base64, true);
|
||||
if ($decoded !== false) {
|
||||
$filename = 'reports/profile-screenshots/' . $target->id . '_' . time() . '.png';
|
||||
Storage::disk('public')->put($filename, $decoded);
|
||||
$screenshotPath = $filename;
|
||||
}
|
||||
}
|
||||
|
||||
ProfileReport::create([
|
||||
'reporter_id' => $me->id,
|
||||
'profile_id' => $target->id,
|
||||
'reason' => $data['reason'],
|
||||
'details' => $data['details'] ?? null,
|
||||
'snapshot' => $data['snapshot'] ?? null,
|
||||
'screenshot_path' => $screenshotPath,
|
||||
]);
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
return back()->with('success', 'Profile reported.');
|
||||
}
|
||||
|
||||
// User search
|
||||
public function search(Request $request)
|
||||
{
|
||||
$q = (string) $request->input('q', '');
|
||||
if (strlen($q) < 1) return response()->json([]);
|
||||
|
||||
$users = User::query()
|
||||
->where('username', 'like', "%" . str_replace(['%','_'], ['\\%','\\_'], $q) . "%")
|
||||
->orWhere('id', '=', $q)
|
||||
->orderBy('username')
|
||||
->limit(10)
|
||||
->get(['id', 'username', 'avatar', 'avatar_url', 'vip_level', 'balance']);
|
||||
|
||||
$out = $users->map(function ($u) {
|
||||
return [
|
||||
'id' => $u->id,
|
||||
'username' => $u->username,
|
||||
'avatar' => $u->avatar ?? $u->avatar_url,
|
||||
'avatar_url' => $u->avatar_url ?? $u->avatar,
|
||||
'vip_level' => (int) ($u->vip_level ?? 0),
|
||||
'stats' => [
|
||||
'wager' => 0, // Placeholder
|
||||
'wins' => 0, // Placeholder
|
||||
'balance' => $u->balance
|
||||
]
|
||||
];
|
||||
});
|
||||
return response()->json($out->all(), 200);
|
||||
}
|
||||
|
||||
// Send a tip (balance transfer) and record it
|
||||
public function tip(Request $request, $id)
|
||||
{
|
||||
$sender = Auth::user();
|
||||
abort_unless($sender, 403);
|
||||
|
||||
$data = $request->validate([
|
||||
'currency' => 'required|string|max:10',
|
||||
'amount' => 'required|numeric|min:0.00000001',
|
||||
'note' => 'nullable|string|max:140',
|
||||
]);
|
||||
|
||||
if ((int)$id === (int)$sender->id) {
|
||||
return back()->withErrors(['amount' => 'You cannot tip yourself.']);
|
||||
}
|
||||
|
||||
$receiver = User::findOrFail($id);
|
||||
$amount = (float) $data['amount'];
|
||||
|
||||
if ($sender->balance < $amount) {
|
||||
return back()->withErrors(['amount' => 'Insufficient balance']);
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($sender, $receiver, $amount, $data) {
|
||||
// Simple balance transfer using users.balance
|
||||
$sender->balance = (float) $sender->balance - $amount;
|
||||
$receiver->balance = (float) $receiver->balance + $amount;
|
||||
$sender->save();
|
||||
$receiver->save();
|
||||
|
||||
Tip::create([
|
||||
'from_user_id' => $sender->id,
|
||||
'to_user_id' => $receiver->id,
|
||||
'currency' => strtoupper($data['currency']),
|
||||
'amount' => $amount,
|
||||
'note' => $data['note'] ?? null,
|
||||
]);
|
||||
});
|
||||
|
||||
return back()->with('success', 'Tip sent successfully.');
|
||||
}
|
||||
|
||||
// --- Friends ---
|
||||
public function requestFriend(Request $request)
|
||||
{
|
||||
$me = Auth::user();
|
||||
abort_unless($me, 403);
|
||||
$data = $request->validate([
|
||||
'user_id' => 'required|integer',
|
||||
]);
|
||||
$targetId = (int) $data['user_id'];
|
||||
if ($targetId === (int)$me->id) {
|
||||
return back()->withErrors(['friend' => 'You cannot add yourself.']);
|
||||
}
|
||||
$target = User::findOrFail($targetId);
|
||||
|
||||
$existing = Friend::where('user_id', $me->id)->where('friend_id', $target->id)->first();
|
||||
if ($existing) {
|
||||
if ($existing->status === 'pending') {
|
||||
return back()->with('success', 'Friend request already sent.');
|
||||
}
|
||||
if ($existing->status === 'accepted') {
|
||||
return back()->with('success', 'You are already friends.');
|
||||
}
|
||||
}
|
||||
Friend::updateOrCreate([
|
||||
'user_id' => $me->id,
|
||||
'friend_id' => $target->id,
|
||||
], [ 'status' => 'pending' ]);
|
||||
|
||||
return back()->with('success', 'Friend request sent.');
|
||||
}
|
||||
|
||||
public function acceptFriend($id)
|
||||
{
|
||||
$me = Auth::user();
|
||||
abort_unless($me, 403);
|
||||
$requestRow = Friend::where('user_id', $id)->where('friend_id', $me->id)->where('status', 'pending')->first();
|
||||
if (!$requestRow) {
|
||||
return back()->withErrors(['friend' => 'Request not found.']);
|
||||
}
|
||||
DB::transaction(function () use ($requestRow, $me, $id) {
|
||||
$requestRow->status = 'accepted';
|
||||
$requestRow->save();
|
||||
// Ensure reciprocal row
|
||||
Friend::updateOrCreate([
|
||||
'user_id' => $me->id,
|
||||
'friend_id' => (int) $id,
|
||||
], [ 'status' => 'accepted' ]);
|
||||
});
|
||||
return back()->with('success', 'Friend request accepted.');
|
||||
}
|
||||
|
||||
public function declineFriend($id)
|
||||
{
|
||||
$me = Auth::user();
|
||||
abort_unless($me, 403);
|
||||
$requestRow = Friend::where('user_id', $id)->where('friend_id', $me->id)->where('status', 'pending')->first();
|
||||
if (!$requestRow) {
|
||||
return back()->withErrors(['friend' => 'Request not found.']);
|
||||
}
|
||||
$requestRow->delete();
|
||||
return back()->with('success', 'Friend request declined.');
|
||||
}
|
||||
|
||||
public function hub()
|
||||
{
|
||||
return Inertia::render('Social/Hub');
|
||||
}
|
||||
|
||||
public function me()
|
||||
{
|
||||
return Inertia::render('Social/Settings', [
|
||||
'user' => Auth::user(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user