add: login con username

This commit is contained in:
Juan Felipe Zapata Moreno 2026-01-14 15:08:54 -06:00
parent 2ca6950751
commit 46367238f5
5 changed files with 167 additions and 14 deletions

View File

@ -25,14 +25,20 @@ class LoginController extends Controller
{
/**
* Iniciar sesión
* Permite login con username O email
*/
public function login(LoginRequest $request)
{
$user = User::where('email', $request->get('email'))->first();
$credential = $request->get('username');
// Buscar por username o email
$user = User::where('username', $credential)
->orWhere('email', $credential)
->first();
if (!$user || !$user->validateForPassportPasswordGrant($request->get('password'))) {
return ApiResponse::UNPROCESSABLE_CONTENT->response([
'email' => ['Usuario no valido']
'username' => ['Credenciales inválidas']
]);
}

View File

@ -30,8 +30,17 @@ public function authorize(): bool
public function rules(): array
{
return [
'email' => ['required', 'email'],
'username' => ['required', 'string'], // Acepta username o email
'password' => ['required', 'min:8'],
];
}
public function messages(): array
{
return [
'username.required' => 'El usuario o email es requerido',
'password.required' => 'La contraseña es requerida',
'password.min' => 'La contraseña debe tener al menos 8 caracteres',
];
}
}

View File

@ -3,6 +3,7 @@
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All rights reserved
*/
use App\Models\User;
use Illuminate\Foundation\Http\FormRequest;
/**
@ -39,4 +40,21 @@ public function rules(): array
'roles' => ['nullable', 'array']
];
}
/**
* Preparar datos antes de la validación
* Genera el username automáticamente
*/
protected function prepareForValidation(): void
{
if ($this->has('name') && $this->has('paternal')) {
$this->merge([
'username' => User::generateUsername(
$this->input('name'),
$this->input('paternal'),
$this->input('maternal')
)
]);
}
}
}

View File

@ -1,4 +1,7 @@
<?php namespace App\Models;
<?php
namespace App\Models;
/**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/
@ -42,6 +45,7 @@ class User extends Authenticatable
'name',
'paternal',
'maternal',
'username',
'email',
'phone',
'password',
@ -141,4 +145,90 @@ public function responsibleModule()
{
return $this->hasOne(Module::class, 'responsible_id');
}
/**
* Generar username automático al crear usuario
* Formato: inicial nombre + inicial segundo nombre + apellido paterno + inicial materno
*/
public static function generateUsername(?string $name, ?string $paternal, ?string $maternal = null): string
{
// Validar que al menos tengamos nombre y apellido paterno
if (empty($name) || empty($paternal)) {
return self::ensureUniqueUsername('user');
}
$name = self::normalizeString($name);
$paternal = self::normalizeString($paternal);
$maternal = $maternal ? self::normalizeString($maternal) : '';
// Separar nombres y obtener iniciales
$nameParts = preg_split('/\s+/', trim($name));
$firstInitial = !empty($nameParts[0]) ? substr($nameParts[0], 0, 1) : '';
$secondInitial = isset($nameParts[1]) && !empty($nameParts[1]) ? substr($nameParts[1], 0, 1) : '';
$maternalInitial = !empty($maternal) ? substr($maternal, 0, 1) : '';
// Construir username
$baseUsername = $firstInitial . $secondInitial . $paternal . $maternalInitial;
// Si el username queda vacío, usar fallback
if (empty($baseUsername)) {
$baseUsername = 'user';
}
return self::ensureUniqueUsername($baseUsername);
}
/**
* Normalizar string: quitar acentos, convertir a minúsculas, solo letras
*/
private static function normalizeString(string $string): string
{
// Convertir a minúsculas
$string = mb_strtolower($string);
// Reemplazar caracteres acentuados
$replacements = [
'á' => 'a',
'é' => 'e',
'í' => 'i',
'ó' => 'o',
'ú' => 'u',
'ä' => 'a',
'ë' => 'e',
'ï' => 'i',
'ö' => 'o',
'ü' => 'u',
'à' => 'a',
'è' => 'e',
'ì' => 'i',
'ò' => 'o',
'ù' => 'u',
'ñ' => 'n',
'ç' => 'c',
];
$string = strtr($string, $replacements);
// Eliminar cualquier caracter que no sea letra o espacio
$string = preg_replace('/[^a-z\s]/', '', $string);
return $string;
}
/**
* Asegurar que el username sea único, agregando número si es necesario
*/
private static function ensureUniqueUsername(string $baseUsername): string
{
$username = $baseUsername;
$counter = 1;
while (self::where('username', $username)->exists()) {
$counter++;
$username = $baseUsername . $counter;
}
return $username;
}
}

View File

@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
if (!Schema::hasColumn('users', 'username')) {
Schema::table('users', function (Blueprint $table) {
$table->string('username')->nullable()->unique()->after('maternal');
});
}
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('username');
});
}
};