Ahora si :)))))))))))))))))

This commit is contained in:
Laucha1312
2026-06-04 15:10:18 -03:00
parent 47408d49fc
commit 1a8c01ae45
167 changed files with 15870 additions and 0 deletions
+411
View File
@@ -0,0 +1,411 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\Models\Jugador;
use App\Models\Aficionado;
use App\Models\AdminUser;
use App\Models\Club;
use App\Mail\WelcomeMail;
use App\Mail\ResetPasswordMail;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Http;
class AuthController extends Controller
{
/**
* Valida el token de Cloudflare Turnstile
*/
private function verifyTurnstile($token)
{
if (in_array(config('app.env'), ['local', 'testing']) && $token === '1x00000000000000000000AA') {
return true;
}
if (!$token) return false;
$response = Http::asForm()->post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
'secret' => config('services.turnstile.secret_key'),
'response' => $token,
'remoteip' => request()->ip(),
]);
return $response->successful() && $response->json('success');
}
public function login(Request $request)
{
$tipo = $request->input('tipo');
if ($tipo === 'admin') {
return $this->loginAdmin($request);
}
return $this->loginPlayer($request);
}
public function loginPlayer(Request $request)
{
if (!$this->verifyTurnstile($request->input('cf-turnstile-response'))) {
return back()->with('login_error', 'Error de verificación de seguridad (Turnstile).')->with('login_tab', 'player');
}
$dni = $request->input('dni');
$password = $request->input('password');
$jugador = Jugador::where('documento', $dni)->where('activo', true)->first();
if ($jugador && $jugador->password && Hash::check($password, $jugador->password)) {
$request->session()->put('user_logged_in', true);
$request->session()->put('user_tipo', 'jugador');
$request->session()->put('user_id', $jugador->id_jugador);
$request->session()->put('user_name', $jugador->nombre . ' ' . $jugador->apellido);
$request->session()->put('user_documento', $jugador->documento);
$request->session()->put('user_ultimo_acceso', time());
return redirect()->intended('/');
}
$aficionado = Aficionado::where('dni', $dni)->first();
if ($aficionado && $aficionado->password && Hash::check($password, $aficionado->password)) {
$request->session()->put('user_logged_in', true);
$request->session()->put('user_tipo', 'aficionado');
$request->session()->put('user_id', $aficionado->id_aficionado);
$request->session()->put('user_name', $aficionado->nombre . ' ' . $aficionado->apellido);
$request->session()->put('user_documento', $aficionado->dni);
$request->session()->put('user_ultimo_acceso', time());
return redirect()->intended('/');
}
return back()->with('login_error', 'DNI o contraseña incorrectos')->with('login_tab', 'player');
}
public function loginAdmin(Request $request)
{
if (!$this->verifyTurnstile($request->input('cf-turnstile-response'))) {
return back()->with('login_error', 'Error de verificación de seguridad (Turnstile).')->with('login_tab', 'admin');
}
$username = $request->input('username');
$password = $request->input('password');
$admin = AdminUser::whereRaw('BINARY `username` = ?', [$username])->first();
if ($admin && Hash::check($password, $admin->password)) {
$request->session()->put('admin_logged_in', true);
$request->session()->put('admin_id', $admin->id);
$request->session()->put('admin_username', $admin->username);
$request->session()->put('admin_role', $admin->role);
$request->session()->put('admin_id_club', $admin->id_club);
if ($admin->id_club && $admin->club) {
$request->session()->put('admin_club_nombre', $admin->club->nombre);
}
$request->session()->put('ultimo_acceso', time());
return redirect()->intended('/');
}
return back()->with('login_error', 'Usuario o contraseña incorrectos')->with('login_tab', 'admin');
}
public function logout(Request $request)
{
$isAdmin = $request->session()->get('admin_logged_in');
if ($isAdmin) {
$request->session()->forget(['admin_logged_in', 'admin_id', 'admin_username', 'admin_role', 'ultimo_acceso']);
$msg = 'Sesión de administrador cerrada correctamente.';
} else {
$request->session()->forget(['user_logged_in', 'user_tipo', 'user_id', 'user_name', 'user_documento', 'user_ultimo_acceso']);
$msg = 'Sesión cerrada correctamente.';
}
return redirect('/?logout_msg=' . urlencode($msg));
}
public function showLoginForm()
{
return view('welcome');
}
public function recuperar(Request $request)
{
if (!$this->verifyTurnstile($request->input('cf-turnstile-response'))) {
return back()->with('mensaje', '⚠️ Error de verificación de seguridad (Captcha).');
}
$dni = trim($request->input('dni'));
$email = trim($request->input('email'));
if (empty($dni) || empty($email)) {
return back()->with('mensaje', 'Debes ingresar tu DNI y correo electrónico.');
}
$jugador = Jugador::where('documento', $dni)->where('email', $email)->first();
$aficionado = Aficionado::where('dni', $dni)->where('email', $email)->first();
$usuario = $jugador ?: $aficionado;
if (!$usuario) {
return back()->with('mensaje', 'No se encontró un usuario con ese DNI y correo.');
}
$token = bin2hex(random_bytes(16));
$expires = now()->addHour();
if ($jugador) {
$jugador->update([
'reset_token' => $token,
'reset_expira' => $expires
]);
} else {
$aficionado->update([
'reset_token' => $token,
'reset_expira' => $expires
]);
}
try {
Mail::to($usuario->email)->send(new ResetPasswordMail($usuario, $token));
} catch (\Exception $e) {
Log::error("Error enviando mail de recuperación: " . $e->getMessage());
}
return back()->with('mensaje', '📩 Te enviamos un correo con las instrucciones para recuperar tu contraseña.');
}
public function resetPasswordForm($token)
{
// Verificar que el token exista y no esté expirado
$jugador = Jugador::where('reset_token', $token)->where('reset_expira', '>', now())->first();
$aficionado = Aficionado::where('reset_token', $token)->where('reset_expira', '>', now())->first();
if (!$jugador && !$aficionado) {
return redirect()->route('recuperar')->with('mensaje', '❌ El enlace es inválido o ya expiró. Solicitá uno nuevo.');
}
return view('auth.reset_password', compact('token'));
}
public function resetPassword(Request $request)
{
$request->validate([
'token' => 'required|string',
'password' => 'required|confirmed|min:6',
]);
$token = $request->input('token');
$jugador = Jugador::where('reset_token', $token)->where('reset_expira', '>', now())->first();
$aficionado = Aficionado::where('reset_token', $token)->where('reset_expira', '>', now())->first();
$usuario = $jugador ?: $aficionado;
if (!$usuario) {
return redirect()->route('recuperar')->with('mensaje', '❌ El enlace es inválido o ya expiró. Solicitá uno nuevo.');
}
$usuario->update([
'password' => bcrypt($request->input('password')),
'reset_token' => null,
'reset_expira' => null,
]);
return redirect('/')->with('login_success', '✅ Contraseña cambiada correctamente. Ya podés iniciar sesión.');
}
public function registroAficionado(Request $request)
{
if (!$this->verifyTurnstile($request->input('cf-turnstile-response'))) {
return back()->with('registro_msg', '⚠️ Error de verificación de seguridad (Captcha).')->withInput();
}
$data = $request->validate([
'nombre' => 'required|string|max:100',
'apellido' => 'required|string|max:100',
'dni' => 'required|string|unique:aficionados,dni',
'email' => 'required|email|unique:aficionados,email',
'fecha_nacimiento' => 'nullable|date',
'telefono' => 'nullable|string|max:50',
'localidad' => 'nullable|string|max:100',
'password' => 'required|confirmed|min:6',
]);
$data['password'] = bcrypt($data['password']);
$data['fecha_registro'] = now();
$aficionado = Aficionado::create($data);
try {
Mail::to($aficionado->email)->send(new WelcomeMail($aficionado, 'aficionado'));
} catch (\Exception $e) {
Log::error("Error enviando mail de bienvenida a Aficionado: " . $e->getMessage());
}
return redirect()->route('asociate')->with('mensaje', '✅ Te registraste correctamente. Ya podés iniciar sesión.');
}
public function buscarJugador(Request $request)
{
$request->validate([
'nombre' => 'required|string',
'apellido' => 'required|string',
'dni' => 'required|string',
'acepto' => 'required',
]);
$dni = preg_replace('/[^0-9]/', '', $request->input('dni'));
$nombre = strtoupper(trim($request->input('nombre')));
$apellido = strtoupper(trim($request->input('apellido')));
// Buscar jugador por DNI
$jugador = Jugador::where('documento', $dni)->first();
if (!$jugador) {
// Verificar si ya está registrado como aficionado
$aficionado = Aficionado::where('dni', $dni)->first();
if ($aficionado) {
return redirect()->route('asociate')->with('mensaje', '⚠️ Ya estás registrado como aficionado.');
}
// No existe - se debe registrar como aficionado
return redirect()->route('asociate')->with('mensaje', '⚠️ No encontramos tu registro como jugador. Podés registrarte como aficionado.');
}
// --- Lógica Smart Match ---
$nombreEnBD = $this->normalizeString($jugador->nombre ?? '');
$apellidoEnBD = $this->normalizeString($jugador->apellido ?? '');
$terminosBD = explode(' ', $nombreEnBD . ' ' . $apellidoEnBD);
$palabrasNombreIn = explode(' ', $this->normalizeString($nombre));
$palabrasApellidoIn = explode(' ', $this->normalizeString($apellido));
$nombreCoincide = false;
foreach ($palabrasNombreIn as $p) {
if ($this->isApproxMatch($p, $terminosBD)) {
$nombreCoincide = true;
break;
}
}
$apellidoCoincide = false;
foreach ($palabrasApellidoIn as $p) {
if ($this->isApproxMatch($p, $terminosBD)) {
$apellidoCoincide = true;
break;
}
}
if (!$nombreCoincide || !$apellidoCoincide) {
return redirect()->route('asociate')->with('mensaje', '⚠️ El DNI ingresado no coincide con el Nombre y Apellido proporcionados. Por favor, verifica tus datos.');
}
// --- Fin Smart Match ---
if ($jugador->activo) {
return redirect()->route('asociate')->with('registro_msg', 'Este jugador ya está registrado en el sistema.');
}
// Jugador encontrado e inactivo - mostrar formulario para completar
$club = null;
if ($jugador->id_club_actual) {
$clubObj = \App\Models\Club::find($jugador->id_club_actual);
$club = $clubObj ? $clubObj->nombre : null;
}
$jugador_encontrado = [
'documento' => $jugador->documento,
'nombre' => $jugador->nombre,
'apellido' => $jugador->apellido,
'fecha_nacimiento' => $jugador->fecha_nacimiento,
'club' => $club,
'categoria' => $jugador->categoria,
];
return view('auth.asociate', compact('jugador_encontrado'))->with('tab', 'jugador');
}
public function completarRegistroJugador(Request $request)
{
if (!$this->verifyTurnstile($request->input('cf-turnstile-response'))) {
return back()->with('registro_msg', '⚠️ Error de verificación de seguridad (Captcha).')->withInput();
}
$request->validate([
'dni' => 'required|string',
'email' => 'required|email',
'telefono' => 'nullable|string',
'password' => 'required|confirmed|min:6',
]);
$dni = preg_replace('/[^0-9]/', '', $request->input('dni'));
$jugador = Jugador::where('documento', $dni)->first();
if (!$jugador) {
return redirect()->route('asociate')->with('registro_msg', 'Jugador no encontrado.');
}
if ($jugador->activo) {
return redirect()->route('asociate')->with('registro_msg', 'Este jugador ya está registrado.');
}
$jugador->update([
'email' => $request->input('email'),
'telefono' => $request->input('telefono'),
'password' => bcrypt($request->input('password')),
'activo' => 1,
'fecha_registro' => now(),
]);
try {
Mail::to($jugador->email)->send(new WelcomeMail($jugador, 'jugador'));
} catch (\Exception $e) {
Log::error("Error enviando mail de bienvenida a Jugador: " . $e->getMessage());
}
return redirect()->route('asociate')->with('mensaje', '✅ Registro completado exitosamente. Ya podés iniciar sesión.');
}
/**
* Normaliza un string para comparaciones (mayúsculas, sin acentos, sin espacios extras)
*/
private function normalizeString($str)
{
$unwanted_array = ['Š'=>'S', 'š'=>'s', 'Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E',
'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U',
'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss', 'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c',
'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o',
'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y'];
$str = strtr($str, $unwanted_array);
return strtoupper(trim(preg_replace('/\s+/', ' ', $str)));
}
/**
* Comprueba si una palabra coincide aproximadamente con alguna de la lista
*/
private function isApproxMatch($word, $list)
{
if (strlen($word) < 3) return false;
foreach ($list as $item) {
if (strlen($item) < 3) continue;
// Coincidencia exacta o contenida
if ($word === $item || strpos($item, $word) !== false || strpos($word, $item) !== false) {
return true;
}
// Levenshtein para errores de tipeo (máximo 1 de distancia)
if (levenshtein($word, $item) <= 1) {
return true;
}
}
return false;
}
}