Initial commit: Animexe Laravel platform

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 00:01:48 +03:00
co-authored by Claude Opus 4.8
commit a63515cfc6
366 changed files with 74773 additions and 0 deletions
@@ -0,0 +1,235 @@
<?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.');
}
}