236 lines
8.6 KiB
PHP
236 lines
8.6 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Frontend;
|
||
|
||
use App\Http\Controllers\Controller;
|
||
use App\Models\AnimeSwipe;
|
||
use App\Models\Comment;
|
||
use App\Models\Watchlist;
|
||
use App\Models\ContinueWatching;
|
||
use App\Models\UserAchievement;
|
||
use App\Models\EpisodeNote;
|
||
use App\Services\AchievementService;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Hash;
|
||
use Illuminate\Support\Facades\Storage;
|
||
use Illuminate\Validation\Rules\Password;
|
||
|
||
class ProfileController extends Controller
|
||
{
|
||
public function show()
|
||
{
|
||
$user = Auth::user();
|
||
|
||
$recentComments = Comment::where('user_id', $user->id)
|
||
->where('status', 'approved')
|
||
->orderByDesc('created_at')
|
||
->limit(10)
|
||
->get();
|
||
|
||
$commentCount = Comment::where('user_id', $user->id)
|
||
->where('status', 'approved')
|
||
->count();
|
||
|
||
// İzleme listesi (status gruplu)
|
||
$watchlistItems = Watchlist::where('user_id', $user->id)
|
||
->with('anime:id,title,slug,cover_image,type,rating')
|
||
->orderByDesc('created_at')
|
||
->get()
|
||
->filter(fn($wl) => $wl->anime !== null)
|
||
->groupBy('status');
|
||
|
||
// Devam et listesi
|
||
$continueItems = ContinueWatching::where('user_id', $user->id)
|
||
->with('anime:id,title,slug,cover_image')
|
||
->where('percent_complete', '<', 95)
|
||
->orderByDesc('updated_at')
|
||
->limit(12)
|
||
->get();
|
||
|
||
// İzleme istatistikleri
|
||
$watchStats = [
|
||
'episodes' => ContinueWatching::where('user_id', $user->id)->where('percent_complete', '>=', 70)->count(),
|
||
'hours' => round(ContinueWatching::where('user_id', $user->id)->sum('seconds_watched') / 3600, 1),
|
||
'watchlist'=> Watchlist::where('user_id', $user->id)->count(),
|
||
'ratings' => DB::table('anime_ratings')->where('user_id', $user->id)->count(),
|
||
];
|
||
|
||
// Başarımlar
|
||
AchievementService::check($user); // yeni kazanılanları kontrol et
|
||
$achievements = UserAchievement::where('user_id', $user->id)
|
||
->with('achievement')
|
||
->orderByDesc('earned_at')
|
||
->get();
|
||
|
||
$allAchievements = \App\Models\Achievement::all();
|
||
|
||
// İzleme Heatmap (son 365 gün)
|
||
$heatmapRaw = DB::table('analytics_watch_events')
|
||
->where('user_id', $user->id)
|
||
->where('created_at', '>=', now()->subDays(365))
|
||
->selectRaw('DATE(created_at) as d, COUNT(DISTINCT episode_id) as cnt')
|
||
->groupBy('d')
|
||
->pluck('cnt', 'd')
|
||
->toArray();
|
||
|
||
// Bölüm notları (son 20)
|
||
$episodeNotes = EpisodeNote::where('user_id', $user->id)
|
||
->with('episode:id,title,episode_number,anime_id', 'anime:id,title,slug')
|
||
->orderByDesc('created_at')
|
||
->limit(20)
|
||
->get();
|
||
|
||
// Keşfet geçmişi (beğenilenler + geçilenler)
|
||
$swipeHistory = AnimeSwipe::where('user_id', $user->id)
|
||
->with('anime:id,title,slug,cover_image,rating,release_year,type')
|
||
->orderByDesc('created_at')
|
||
->limit(60)
|
||
->get()
|
||
->filter(fn($s) => $s->anime !== null);
|
||
|
||
return view('frontend.profile', compact(
|
||
'user', 'recentComments', 'commentCount',
|
||
'watchlistItems', 'continueItems', 'watchStats',
|
||
'achievements', 'allAchievements',
|
||
'heatmapRaw', 'episodeNotes', 'swipeHistory'
|
||
));
|
||
}
|
||
|
||
public function publicProfile(\App\Models\User $user)
|
||
{
|
||
$commentCount = Comment::where('user_id', $user->id)->where('status', 'approved')->count();
|
||
|
||
$watchlistItems = Watchlist::where('user_id', $user->id)
|
||
->with('anime:id,title,slug,cover_image,type,rating')
|
||
->orderByDesc('created_at')
|
||
->get()
|
||
->filter(fn($wl) => $wl->anime !== null)
|
||
->groupBy('status');
|
||
|
||
$watchStats = [
|
||
'episodes' => ContinueWatching::where('user_id', $user->id)->where('percent_complete', '>=', 70)->count(),
|
||
'hours' => round(ContinueWatching::where('user_id', $user->id)->sum('seconds_watched') / 3600, 1),
|
||
'watchlist'=> Watchlist::where('user_id', $user->id)->count(),
|
||
'ratings' => DB::table('anime_ratings')->where('user_id', $user->id)->count(),
|
||
];
|
||
|
||
$achievements = UserAchievement::where('user_id', $user->id)
|
||
->with('achievement')
|
||
->where('earned_at', '!=', null)
|
||
->orderByDesc('earned_at')
|
||
->get();
|
||
|
||
$recentComments = Comment::where('user_id', $user->id)
|
||
->where('status', 'approved')
|
||
->orderByDesc('created_at')
|
||
->limit(6)
|
||
->get();
|
||
|
||
$isOwnProfile = Auth::id() === $user->id;
|
||
$isFollowing = Auth::check() && !$isOwnProfile ? Auth::user()->isFollowing($user->id) : false;
|
||
$followerCount = \App\Models\UserFollow::where('following_id', $user->id)->count();
|
||
$followingCount= \App\Models\UserFollow::where('follower_id', $user->id)->count();
|
||
$compatibility = (Auth::check() && !$isOwnProfile)
|
||
? Auth::user()->compatibilityWith($user)
|
||
: null;
|
||
|
||
return view('frontend.public-profile', compact(
|
||
'user', 'commentCount', 'watchlistItems',
|
||
'watchStats', 'achievements', 'recentComments', 'isOwnProfile',
|
||
'isFollowing', 'followerCount', 'followingCount', 'compatibility'
|
||
));
|
||
}
|
||
|
||
public function settings()
|
||
{
|
||
return view('frontend.profile-settings', ['user' => Auth::user()]);
|
||
}
|
||
|
||
public function update(Request $request)
|
||
{
|
||
$user = Auth::user();
|
||
|
||
$data = $request->validate([
|
||
'name' => 'required|string|max:60',
|
||
'username' => 'nullable|string|max:30|alpha_dash|unique:users,username,' . $user->id,
|
||
'bio' => 'nullable|string|max:300',
|
||
'website' => 'nullable|url|max:200',
|
||
'twitter' => 'nullable|string|max:50',
|
||
'instagram' => 'nullable|string|max:50',
|
||
'discord' => 'nullable|string|max:80',
|
||
'profile_color' => 'nullable|regex:/^#[0-9a-fA-F]{6}$/',
|
||
'show_watchlist' => 'boolean',
|
||
'show_activity' => 'boolean',
|
||
]);
|
||
|
||
// Checkboxlar false gelince request'te bulunmaz
|
||
$data['show_watchlist'] = $request->boolean('show_watchlist');
|
||
$data['show_activity'] = $request->boolean('show_activity');
|
||
|
||
// @ işaretlerini temizle
|
||
if (isset($data['twitter'])) $data['twitter'] = ltrim($data['twitter'], '@');
|
||
if (isset($data['instagram'])) $data['instagram'] = ltrim($data['instagram'], '@');
|
||
|
||
$user->update($data);
|
||
|
||
return back()->with('success', 'Profil güncellendi.');
|
||
}
|
||
|
||
public function updateAvatar(Request $request)
|
||
{
|
||
$request->validate([
|
||
'avatar' => 'required|image|mimes:jpg,jpeg,png,webp,gif|max:2048',
|
||
]);
|
||
|
||
$user = Auth::user();
|
||
|
||
// Eski avatarı sil
|
||
if ($user->avatar && Storage::disk('public')->exists($user->avatar)) {
|
||
Storage::disk('public')->delete($user->avatar);
|
||
}
|
||
|
||
$path = $request->file('avatar')->store('avatars', 'public');
|
||
$user->update(['avatar' => $path]);
|
||
|
||
return back()->with('success', 'Profil fotoğrafı güncellendi.');
|
||
}
|
||
|
||
public function updateBanner(Request $request)
|
||
{
|
||
$request->validate([
|
||
'banner' => 'required|image|mimes:jpg,jpeg,png,webp|max:5120',
|
||
]);
|
||
|
||
$user = Auth::user();
|
||
|
||
if ($user->banner_image && Storage::disk('public')->exists($user->banner_image)) {
|
||
Storage::disk('public')->delete($user->banner_image);
|
||
}
|
||
|
||
$path = $request->file('banner')->store('banners', 'public');
|
||
$user->update(['banner_image' => $path]);
|
||
|
||
return back()->with('success', 'Profil kapak fotoğrafı güncellendi.');
|
||
}
|
||
|
||
public function updatePassword(Request $request)
|
||
{
|
||
$request->validate([
|
||
'current_password' => 'required',
|
||
'password' => ['required', 'confirmed', Password::min(8)],
|
||
]);
|
||
|
||
$user = Auth::user();
|
||
|
||
if (!Hash::check($request->current_password, $user->password)) {
|
||
return back()->withErrors(['current_password' => 'Mevcut şifre yanlış.']);
|
||
}
|
||
|
||
$user->update(['password' => $request->password]);
|
||
|
||
return back()->with('success', 'Şifre güncellendi.');
|
||
}
|
||
}
|