ADD: Plantilla Holos (#1)
This commit is contained in:
parent
97723f5b5c
commit
517628b92d
30
.env.example
30
.env.example
@ -2,16 +2,23 @@ APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost
|
||||
APP_TIMEZONE=America/Mexico_City
|
||||
APP_URL=http://backend.holos.test
|
||||
APP_FRONTEND_URL=http://frontend.holos.test
|
||||
APP_PAGINATION=25
|
||||
|
||||
APP_LOCALE=en
|
||||
APP_FALLBACK_LOCALE=en
|
||||
APP_FAKER_LOCALE=en_US
|
||||
APP_LOCALE=es
|
||||
APP_FALLBACK_LOCALE=es
|
||||
APP_FAKER_LOCALE=es_MX
|
||||
|
||||
APP_MAINTENANCE_DRIVER=file
|
||||
# APP_MAINTENANCE_STORE=database
|
||||
|
||||
CORS_ALLOWED_ORIGINS=frontend.holos.test
|
||||
|
||||
PULSE_ENABLED=false
|
||||
TELESCOPE_ENABLED=false
|
||||
|
||||
PHP_CLI_SERVER_WORKERS=4
|
||||
|
||||
BCRYPT_ROUNDS=12
|
||||
@ -21,12 +28,12 @@ LOG_STACK=single
|
||||
LOG_DEPRECATIONS_CHANNEL=null
|
||||
LOG_LEVEL=debug
|
||||
|
||||
DB_CONNECTION=sqlite
|
||||
# DB_HOST=127.0.0.1
|
||||
# DB_PORT=3306
|
||||
# DB_DATABASE=laravel
|
||||
# DB_USERNAME=root
|
||||
# DB_PASSWORD=
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=holos-backend
|
||||
DB_USERNAME=notsoweb
|
||||
DB_PASSWORD=
|
||||
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
@ -51,6 +58,7 @@ REDIS_PORT=6379
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=2525
|
||||
MAIL_DOMAIN=notsoweb.com
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/public/vendor
|
||||
/storage/*.key
|
||||
/storage/pail
|
||||
/vendor
|
||||
|
||||
48
app/Console/Commands/Broadcast.php
Normal file
48
app/Console/Commands/Broadcast.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
/**
|
||||
* Iniciar servicio de broadcast
|
||||
*/
|
||||
class Broadcast extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:broadcast
|
||||
{--start : Iniciar servicio de broadcast}
|
||||
{--stop : Detener servicio de broadcast}
|
||||
{--restart : Reiniciar servicio de broadcast}
|
||||
{--status : Mostrar estado del servicio de broadcast}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if ($this->option('stop') || $this->option('restart')) {
|
||||
echo "# Deteniendo servicio de broadcast... \n";
|
||||
echo shell_exec('pm2 delete broadcast');
|
||||
}
|
||||
|
||||
if ($this->option('start') || $this->option('restart')) {
|
||||
echo "# Iniciando servicio de broadcast... \n";
|
||||
echo shell_exec("pm2 start --name broadcast \"php artisan reverb:start --hostname=" . env('APP_URL') . "\"");
|
||||
}
|
||||
|
||||
if ($this->option('status')) {
|
||||
echo "# Estado del servicio de broadcast: \n";
|
||||
echo shell_exec('pm2 status broadcast');
|
||||
}
|
||||
}
|
||||
}
|
||||
57
app/Console/Commands/DownSecure.php
Normal file
57
app/Console/Commands/DownSecure.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php namespace App\Console\Commands;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb (https://notsoweb.com) - All rights reserved.
|
||||
*/
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
|
||||
/**
|
||||
* Mantenimiento seguro
|
||||
*
|
||||
* De forma automática pondrá al sistema en modo mantenimiento con una URL secreta para
|
||||
* poder acceder al sitio. El tiempo se puede configurar desde las variables de entorno.
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class DownSecure extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:secure';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Modo mantenimiento con un hash seguro';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$secret = Uuid::uuid4();
|
||||
|
||||
Artisan::call('down', [
|
||||
'--secret' => $secret
|
||||
]);
|
||||
|
||||
echo url($secret);
|
||||
echo "\n";
|
||||
|
||||
Log::channel('notsoweb')->info("Maintenance Mode Secure. Key: {$secret}");
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
59
app/Console/Commands/NotificationGlobal.php
Normal file
59
app/Console/Commands/NotificationGlobal.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php namespace App\Console\Commands;
|
||||
/**
|
||||
* @copyright Copyright (c) 2023 Notsoweb (https://notsoweb.com) - All rights reserved.
|
||||
*/
|
||||
|
||||
use App\Events\GlobalNotification;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
/**
|
||||
* Notificación global
|
||||
*
|
||||
* Notificación global a todos los usuarios conectados.
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class NotificationGlobal extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'notification:global
|
||||
{--message=Notificación de prueba : Mensaje de la notificación}
|
||||
{--title=Notificación Global : Título de la notificación}
|
||||
{--type=info : Tipo de notificación (info, success, warning, error)}
|
||||
{--timeout=15 : Tiempo de duración de la notificación}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Enviar notificación a todos los usuarios conectados';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$message = $this->option('message');
|
||||
$title = $this->option('title');
|
||||
$type = $this->option('type');
|
||||
$timeout = $this->option('timeout');
|
||||
|
||||
broadcast(new GlobalNotification(
|
||||
$title,
|
||||
$message,
|
||||
$type,
|
||||
$timeout
|
||||
));
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
55
app/Events/GlobalNotification.php
Normal file
55
app/Events/GlobalNotification.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php namespace App\Events;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb (https://notsoweb.com) - All rights reserved.
|
||||
*/
|
||||
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithBroadcasting;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Notificación global
|
||||
*
|
||||
* Notificación enviada a todos los usuarios conectados al canal Global.
|
||||
*
|
||||
* @author Moisés de Jesús Cortés Castellanos <ing.moisesdejesuscortesc@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class GlobalNotification implements ShouldBroadcastNow
|
||||
{
|
||||
use Dispatchable,
|
||||
InteractsWithBroadcasting,
|
||||
InteractsWithSockets,
|
||||
SerializesModels;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct(
|
||||
public string $title,
|
||||
public string $message,
|
||||
public string $type = 'info',
|
||||
public int $timeout = 15
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Nombre del evento
|
||||
*/
|
||||
public function broadcastAs(): string
|
||||
{
|
||||
return 'App\Events\Notification';
|
||||
}
|
||||
|
||||
/**
|
||||
* Canal de envío
|
||||
*/
|
||||
public function broadcastOn(): Channel
|
||||
{
|
||||
return new PrivateChannel('Global');
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
<?php namespace App\Http\Controllers;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
/**
|
||||
* Controlador base
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
|
||||
128
app/Http/Controllers/MyUserController.php
Normal file
128
app/Http/Controllers/MyUserController.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use App\Http\Requests\User\UserUpdateRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
use Notsoweb\LaravelCore\Supports\NotifySupport;
|
||||
|
||||
/**
|
||||
* Usuario autenticado
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class MyUserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Obtener usuario autenticado
|
||||
*/
|
||||
public function show()
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'user' => auth()->user()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualizar
|
||||
*/
|
||||
public function update(UserUpdateRequest $request)
|
||||
{
|
||||
$form = $request->validated();
|
||||
|
||||
if (isset($form['photo'])) {
|
||||
auth()->user()->updateProfilePhoto($form['photo']);
|
||||
}
|
||||
|
||||
auth()->user()->update($form);
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminar
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
auth()->user()->delete();
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirmar contraseña
|
||||
*
|
||||
* Autoriza una acción si la contraseña es correcta.
|
||||
*/
|
||||
public function confirmPassword(Request $request)
|
||||
{
|
||||
$form = $request->validate([
|
||||
'password' => ['required', 'string', 'min:8']
|
||||
]);
|
||||
|
||||
if (!Hash::check($form['password'], auth()->user()->password)) {
|
||||
NotifySupport::errorIn('password', __('validation.password'));
|
||||
}
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualizar contraseña
|
||||
*/
|
||||
public function updatePassword(Request $request)
|
||||
{
|
||||
$form = $request->validate([
|
||||
'current_password' => ['required', 'string'],
|
||||
'password' => ['required', 'string', 'min:8', 'confirmed']
|
||||
]);
|
||||
|
||||
if (!Hash::check($form['current_password'], auth()->user()->password)) {
|
||||
NotifySupport::errorIn('current_password', __('validation.password'));
|
||||
}
|
||||
|
||||
auth()->user()->update([
|
||||
'password' => bcrypt($form['password'])
|
||||
]);
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminar foto de perfil
|
||||
*/
|
||||
public function destroyPhoto()
|
||||
{
|
||||
auth()->user()->deleteProfilePhoto();
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permisos
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'permissions' => auth()->user()->getAllPermissions()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Roles
|
||||
*/
|
||||
public function roles()
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'roles' => auth()->user()
|
||||
->roles()
|
||||
->select('id', 'name', 'description')
|
||||
->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
75
app/Http/Controllers/System/LoginController.php
Normal file
75
app/Http/Controllers/System/LoginController.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php namespace App\Http\Controllers\System;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Auth\LoginRequest;
|
||||
use App\Http\Requests\User\ForgotRequest;
|
||||
use App\Models\User;
|
||||
use App\Notifications\ForgotPasswordNotification;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
|
||||
/**
|
||||
* Controlador de sesiones
|
||||
*
|
||||
* @author Moisés Cortés C <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class LoginController extends Controller
|
||||
{
|
||||
/**
|
||||
* Iniciar sesión
|
||||
*/
|
||||
public function login(LoginRequest $request)
|
||||
{
|
||||
return (Auth::attempt($request->all()))
|
||||
? ApiResponse::OK->onSuccess([
|
||||
'user' => auth()->user(),
|
||||
'token' => auth()->user()
|
||||
->createToken('golscore')
|
||||
->accessToken,
|
||||
])
|
||||
: ApiResponse::UNPROCESSABLE_CONTENT->response([
|
||||
'email' => ['Usuario no valido']
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cerrar sesión
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'is_revoked' => auth()->user()->token()->revoke()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contraseña olvidada
|
||||
*/
|
||||
public function forgotPassword(ForgotRequest $request)
|
||||
{
|
||||
$data = $request->validated();
|
||||
|
||||
$user = User::where('email', $data['email'])->first();
|
||||
|
||||
try {
|
||||
$user->notify(new ForgotPasswordNotification());
|
||||
|
||||
return ApiResponse::OK->response([
|
||||
'is_sent' => true
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
Log::channel('mail')->info("Email: {$data['email']}");
|
||||
Log::channel('mail')->error($th->getMessage());
|
||||
|
||||
return ApiResponse::INTERNAL_ERROR->response([
|
||||
'is_sent' => false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
95
app/Http/Controllers/System/NotificationController.php
Executable file
95
app/Http/Controllers/System/NotificationController.php
Executable file
@ -0,0 +1,95 @@
|
||||
<?php namespace App\Http\Controllers\System;
|
||||
/**
|
||||
* @copyright 2024 Notsoweb (https://notsoweb.com) - All rights reserved.
|
||||
*/
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Notifications\DatabaseNotification;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
use Notsoweb\LaravelCore\Controllers\VueController;
|
||||
|
||||
/**
|
||||
* Sistema de notificaciones
|
||||
*
|
||||
* @author Moisés de Jesús Cortés Castellanos <ing.moisesdejesuscortesc@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class NotificationController extends VueController
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->root('notifications');
|
||||
}
|
||||
|
||||
/**
|
||||
* Listar notificaciones del usuario
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$q = request()->get('query');
|
||||
|
||||
$model = auth()->user()
|
||||
->notifications();
|
||||
|
||||
if($q) {
|
||||
$model = $model->where('data->title', 'LIKE', "%{$q}%")
|
||||
->orWhere('data->message', "LIKE", "%{$q}%");
|
||||
}
|
||||
|
||||
return $this->view('index', [
|
||||
'models' => $model
|
||||
->paginate(config('app.pagination'))
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Todas las notificaciones
|
||||
*/
|
||||
public function all(): JsonResponse
|
||||
{
|
||||
$query = request()->get('query');
|
||||
|
||||
$model = auth()->user()
|
||||
->notifications();
|
||||
|
||||
if($query) {
|
||||
$model = $model->where('data->title', 'LIKE', "%{$query}%")
|
||||
->orWhere('data->message', "LIKE", "%{$query}%");
|
||||
}
|
||||
|
||||
return ApiResponse::OK->axios([
|
||||
'notifications' => $model
|
||||
->paginate(config('app.pagination'))
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marcar notificación como leída
|
||||
*/
|
||||
public function read(Request $request): JsonResponse
|
||||
{
|
||||
$notification = DatabaseNotification::find($request->get('id'));
|
||||
|
||||
if ($notification) {
|
||||
$notification->markAsRead();
|
||||
}
|
||||
|
||||
return ApiResponse::OK->axios();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener notificaciones no leídas recientes
|
||||
*/
|
||||
public function allUnread(): JsonResponse
|
||||
{
|
||||
return ApiResponse::OK->axios([
|
||||
'total' => auth()->user()->unreadNotifications()->count(),
|
||||
'notifications' => auth()->user()->unreadNotifications()->limit(10)->get(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
46
app/Http/Controllers/System/SystemController.php
Normal file
46
app/Http/Controllers/System/SystemController.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php namespace App\Http\Controllers\System;
|
||||
/**
|
||||
* @copyright 2024 Notsoweb (https://notsoweb.com) - All rights reserved.
|
||||
*/
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
/**
|
||||
* Recursos del sistema
|
||||
*
|
||||
* Contiene determinados recursos que el sistema requiere para funcionar por parte del
|
||||
* frontend.
|
||||
*
|
||||
* @author Moisés de Jesús Cortés Castellanos <ing.moisesdejesuscortesc@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class SystemController extends Controller
|
||||
{
|
||||
/**
|
||||
* Listar permisos del sistema
|
||||
*/
|
||||
public function permissions()
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'permissions' => Permission::orderBy('name')
|
||||
->select('id', 'name', 'description')
|
||||
->get()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listar roles del sistema
|
||||
*/
|
||||
public function roles()
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'roles' => Role::orderBy('description')
|
||||
->select('id', 'name', 'description')
|
||||
->get()
|
||||
]);
|
||||
}
|
||||
}
|
||||
131
app/Http/Controllers/UserController.php
Normal file
131
app/Http/Controllers/UserController.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php namespace App\Http\Controllers;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Users\PasswordUpdateRequest;
|
||||
use App\Http\Requests\Users\UserStoreRequest;
|
||||
use App\Http\Requests\Users\UserUpdateRequest;
|
||||
use App\Models\User;
|
||||
use App\Supports\QuerySupport;
|
||||
use Illuminate\Http\Request;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
|
||||
/**
|
||||
* Controlador de usuarios
|
||||
*
|
||||
* Permite la administración de los usuarios en general.
|
||||
*
|
||||
* @author Moisés Cortés C <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Listar
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$users = User::orderBy('name');
|
||||
|
||||
QuerySupport::queryByKeys($users, ['name', 'email']);
|
||||
|
||||
return ApiResponse::OK->response([
|
||||
'users' => $users->paginate(config('app.pagination'))
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Almacenar
|
||||
*/
|
||||
public function store(UserStoreRequest $request)
|
||||
{
|
||||
$user = User::create($request->all());
|
||||
|
||||
if ($request->has('roles')) {
|
||||
$user->roles()->sync($request->roles);
|
||||
}
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mostrar
|
||||
*/
|
||||
public function show(User $user)
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'user' => $user
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualizar
|
||||
*/
|
||||
public function update(UserUpdateRequest $request, User $user)
|
||||
{
|
||||
$user->update($request->all());
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminar
|
||||
*/
|
||||
public function destroy(User $user)
|
||||
{
|
||||
$user->delete();
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Permisos del usuario
|
||||
*/
|
||||
public function permissions(User $user)
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'permissions' => $user->getAllPermissions()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Roles del usuario
|
||||
*/
|
||||
public function roles(User $user)
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'roles' => $user
|
||||
->roles()
|
||||
->select('id', 'name', 'description')
|
||||
->get()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualizar roles
|
||||
*/
|
||||
public function updateRoles(Request $request, User $user)
|
||||
{
|
||||
if ($request->has('roles')) {
|
||||
$user->roles()->sync($request->roles);
|
||||
}
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualizar contraseña
|
||||
*/
|
||||
public function updatePassword(PasswordUpdateRequest $request, User $user)
|
||||
{
|
||||
$user->update([
|
||||
'password' => bcrypt($request->password)
|
||||
]);
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
}
|
||||
37
app/Http/Requests/Auth/LoginRequest.php
Normal file
37
app/Http/Requests/Auth/LoginRequest.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php namespace App\Http\Requests\Auth;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Solicitud de login
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class LoginRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email' => ['required', 'email'],
|
||||
'password' => ['required', 'min:8'],
|
||||
];
|
||||
}
|
||||
}
|
||||
34
app/Http/Requests/User/ForgotRequest.php
Normal file
34
app/Http/Requests/User/ForgotRequest.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php namespace App\Http\Requests\User;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Solicitud de olvido de contraseña
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class ForgotRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determinar si el usuario está autorizado para realizar esta solicitud
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener las reglas de validación que se aplican a la solicitud
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email' => ['required', 'email', 'exists:users,email']
|
||||
];
|
||||
}
|
||||
}
|
||||
46
app/Http/Requests/User/UserUpdateRequest.php
Normal file
46
app/Http/Requests/User/UserUpdateRequest.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php namespace App\Http\Requests\User;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/**
|
||||
* Actualizar perfil usuario actual
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class UserUpdateRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determinar si el usuario está autorizado para realizar esta solicitud
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener las reglas de validación que se aplican a la solicitud
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'paternal' => ['required', 'string', 'max:255'],
|
||||
'maternal' => ['required', 'string', 'max:255'],
|
||||
'email' => [
|
||||
'required',
|
||||
'string',
|
||||
'email',
|
||||
'max:255',
|
||||
Rule::unique('users')->ignore(auth()->user()->id),
|
||||
],
|
||||
'phone' => ['nullable', 'numeric', 'digits:10'],
|
||||
'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:2048'],
|
||||
];
|
||||
}
|
||||
}
|
||||
34
app/Http/Requests/Users/PasswordUpdateRequest.php
Normal file
34
app/Http/Requests/Users/PasswordUpdateRequest.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php namespace App\Http\Requests\Users;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Actualizar contraseña desde gestión de usuarios
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class PasswordUpdateRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determinar si el usuario está autorizado para realizar esta solicitud
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener las reglas de validación que se aplican a la solicitud
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'password' => ['required', 'string', 'min:8', 'confirmed']
|
||||
];
|
||||
}
|
||||
}
|
||||
42
app/Http/Requests/Users/UserStoreRequest.php
Normal file
42
app/Http/Requests/Users/UserStoreRequest.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php namespace App\Http\Requests\Users;
|
||||
/**
|
||||
* @copyright (C) 2024 Notsoweb Software (https://notsoweb.com) - All rights reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Almacenar usuario
|
||||
*
|
||||
* @author Moisés Cortés C <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class UserStoreRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'paternal' => ['required', 'string', 'max:255'],
|
||||
'maternal' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
|
||||
'phone' => ['nullable', 'numeric', 'digits:10'],
|
||||
'password' => ['required', 'string', 'min:8'],
|
||||
'roles' => ['nullable', 'array']
|
||||
];
|
||||
}
|
||||
}
|
||||
42
app/Http/Requests/Users/UserUpdateRequest.php
Normal file
42
app/Http/Requests/Users/UserUpdateRequest.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php namespace App\Http\Requests\Users;
|
||||
/**
|
||||
* @copyright (C) 2024 Notsoweb Software (https://notsoweb.com) - All rights reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/**
|
||||
* Actualizar usuario
|
||||
*
|
||||
* @author Moisés Cortés C <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class UserUpdateRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'paternal' => ['required', 'string', 'max:255'],
|
||||
'maternal' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', Rule::unique('users')->ignore($this->route('user'))],
|
||||
'phone' => ['nullable', 'numeric', 'digits:10'],
|
||||
'roles' => ['nullable', 'array']
|
||||
];
|
||||
}
|
||||
}
|
||||
86
app/Http/Traits/HasProfilePhoto.php
Normal file
86
app/Http/Traits/HasProfilePhoto.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php namespace App\Http\Traits;
|
||||
/**
|
||||
* @copyright (C) 2024 Notsoweb Software (https://notsoweb.com) - All rights reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Trait para manejar la foto de perfil
|
||||
*
|
||||
* @author Moisés Cortés C <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
trait HasProfilePhoto
|
||||
{
|
||||
/**
|
||||
* Actualizar la foto de perfil del usuario
|
||||
*/
|
||||
public function updateProfilePhoto(UploadedFile $photo, $storagePath = 'photos') : void
|
||||
{
|
||||
tap($this->profile_photo_path, function ($previous) use ($photo, $storagePath) {
|
||||
$this->forceFill([
|
||||
'profile_photo_path' => $photo->storePublicly(
|
||||
$storagePath, ['disk' => $this->profilePhotoDisk()]
|
||||
),
|
||||
])->save();
|
||||
|
||||
if ($previous) {
|
||||
Storage::disk($this->profilePhotoDisk())->delete($previous);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Eliminar la foto de perfil del usuario
|
||||
*/
|
||||
public function deleteProfilePhoto() : void
|
||||
{
|
||||
if (is_null($this->profile_photo_path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Storage::disk($this->profilePhotoDisk())->delete($this->profile_photo_path);
|
||||
|
||||
$this->forceFill([
|
||||
'profile_photo_path' => null,
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener la URL de la foto de perfil del usuario
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Casts\Attribute
|
||||
*/
|
||||
public function profilePhotoUrl(): Attribute
|
||||
{
|
||||
return Attribute::get(function (): string {
|
||||
return $this->profile_photo_path
|
||||
? Storage::disk($this->profilePhotoDisk())->url($this->profile_photo_path)
|
||||
: $this->defaultProfilePhotoUrl();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener la URL de la foto de perfil por defecto si no se ha subido ninguna
|
||||
*/
|
||||
protected function defaultProfilePhotoUrl() : string
|
||||
{
|
||||
$name = trim(collect(explode(' ', $this->name))->map(function ($segment) {
|
||||
return mb_substr($segment, 0, 1);
|
||||
})->join(' '));
|
||||
|
||||
return 'https://ui-avatars.com/api/?name='.urlencode($name).'&color=7F9CF5&background=EBF4FF';
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el disco donde se deben almacenar las fotos de perfil
|
||||
*/
|
||||
protected function profilePhotoDisk() : string
|
||||
{
|
||||
return 'profile';
|
||||
}
|
||||
}
|
||||
24
app/Models/PermissionType.php
Normal file
24
app/Models/PermissionType.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php namespace App\Models;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All rights reserved.
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Tipos de permisos
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class PermissionType extends Model
|
||||
{
|
||||
/**
|
||||
* Atributos permitidos
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description'
|
||||
];
|
||||
}
|
||||
25
app/Models/ResetPassword.php
Normal file
25
app/Models/ResetPassword.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php namespace App\Models;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* Modelo de contraseñas olvidadas
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class ResetPassword extends Model
|
||||
{
|
||||
/**
|
||||
* Atributos asignables
|
||||
*/
|
||||
protected $fillable = [
|
||||
'email',
|
||||
'token',
|
||||
'created_at',
|
||||
];
|
||||
}
|
||||
@ -1,32 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
<?php namespace App\Models;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use App\Http\Traits\HasProfilePhoto;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<\Database\Factories\UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
use Laravel\Passport\HasApiTokens;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
* Modelo de usuario
|
||||
*
|
||||
* @var array<int, string>
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens,
|
||||
HasFactory,
|
||||
HasRoles,
|
||||
HasProfilePhoto,
|
||||
Notifiable;
|
||||
|
||||
/**
|
||||
* Atributos permitidos
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'paternal',
|
||||
'maternal',
|
||||
'email',
|
||||
'phone',
|
||||
'password',
|
||||
'profile_photo_path',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var array<int, string>
|
||||
* Atributos ocultos
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
@ -34,9 +48,7 @@ class User extends Authenticatable
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
* Atributos que se deben convertir
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
@ -45,4 +57,11 @@ protected function casts(): array
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Los accesores a añadir al modelo en su forma de array
|
||||
*/
|
||||
protected $appends = [
|
||||
'profile_photo_url',
|
||||
];
|
||||
}
|
||||
|
||||
57
app/Notifications/ForgotPasswordNotification.php
Normal file
57
app/Notifications/ForgotPasswordNotification.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php namespace App\Notifications;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
/**
|
||||
* Descripción
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class ForgotPasswordNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener los canales de entrega de la notificación
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener la representación del mensaje de la notificación
|
||||
*/
|
||||
public function toMail(object $notifiable): MailMessage
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject(__('auth.forgot-password.subject'))
|
||||
->markdown('user.password-forgot');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener la representación en array de la notificación
|
||||
*/
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
62
app/Notifications/UserNotification.php
Normal file
62
app/Notifications/UserNotification.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\BroadcastMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
|
||||
class UserNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*/
|
||||
public function __construct(
|
||||
public string $title,
|
||||
public string $description,
|
||||
public ?string $message = null,
|
||||
public string $type = 'info',
|
||||
public int $timeout = 20,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public function via(object $notifiable): array
|
||||
{
|
||||
return [
|
||||
'broadcast',
|
||||
'database'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function toArray(object $notifiable): array
|
||||
{
|
||||
return [
|
||||
'title' => $this->title,
|
||||
'description' => $this->description,
|
||||
'message' => $this->message,
|
||||
'type' => $this->type,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmitir notificación
|
||||
*/
|
||||
public function toBroadcast($notifiable)
|
||||
{
|
||||
return new BroadcastMessage([
|
||||
'title' => $this->title,
|
||||
'description' => $this->description,
|
||||
'typeNotification' => $this->type,
|
||||
'timeout' => $this->timeout,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
<?php namespace App\Providers;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
/**
|
||||
* Proveedor de servicios de la aplicación
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
* Registrar cualquier servicio de la aplicación
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
if ($this->app->environment('local')) {
|
||||
$this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
|
||||
$this->app->register(TelescopeServiceProvider::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -19,6 +33,14 @@ public function register(): void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
Passport::loadKeysFrom(storage_path('app/keys'));
|
||||
Passport::tokensExpireIn(now()->addDays(30));
|
||||
Passport::refreshTokensExpireIn(now()->addDays(60));
|
||||
Passport::personalAccessTokensExpireIn(now()->addMonths(12));
|
||||
|
||||
// Acceso a Pulse
|
||||
Gate::define('viewPulse', function (User $user) {
|
||||
return $user->hasRole('developer');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
71
app/Providers/TelescopeServiceProvider.php
Normal file
71
app/Providers/TelescopeServiceProvider.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php namespace App\Providers;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
|
||||
*/
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Laravel\Telescope\IncomingEntry;
|
||||
use Laravel\Telescope\Telescope;
|
||||
use Laravel\Telescope\TelescopeApplicationServiceProvider;
|
||||
|
||||
/**
|
||||
* Proveedor de servicios de Telescope
|
||||
*
|
||||
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
|
||||
{
|
||||
/**
|
||||
* Registrar cualquier servicio de la aplicación
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
Telescope::night();
|
||||
|
||||
$this->hideSensitiveRequestDetails();
|
||||
|
||||
$isLocal = $this->app->environment('local');
|
||||
|
||||
Telescope::filter(function (IncomingEntry $entry) use ($isLocal) {
|
||||
return $isLocal ||
|
||||
$entry->isReportableException() ||
|
||||
$entry->isFailedRequest() ||
|
||||
$entry->isFailedJob() ||
|
||||
$entry->isScheduledTask() ||
|
||||
$entry->hasMonitoredTag();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevenir que los detalles de las solicitudes sensibles se registren en Telescope.
|
||||
*/
|
||||
protected function hideSensitiveRequestDetails(): void
|
||||
{
|
||||
if ($this->app->environment('local')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Telescope::hideRequestParameters(['_token']);
|
||||
|
||||
Telescope::hideRequestHeaders([
|
||||
'cookie',
|
||||
'x-csrf-token',
|
||||
'x-xsrf-token',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registrar la puerta de acceso de Telescope.
|
||||
*
|
||||
* Esta puerta determina quién puede acceder a Telescope en entornos no locales.
|
||||
*/
|
||||
protected function gate(): void
|
||||
{
|
||||
Gate::define('viewTelescope', function (User $user) {
|
||||
return $user->hasRole('developer');
|
||||
});
|
||||
}
|
||||
}
|
||||
23
app/Schedules/DeleteResetPasswords.php
Normal file
23
app/Schedules/DeleteResetPasswords.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php namespace App\Schedules;
|
||||
/**
|
||||
* @copyright (c) 2024 Notsoweb Software (https://www.notsoweb.com) - All rights reserved.
|
||||
*/
|
||||
|
||||
use App\Models\ResetPassword;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* Eliminar tokens de reseteos de contraseñas
|
||||
*
|
||||
* @author Moisés Cortés C <moises.cortes@notsoweb.com>
|
||||
*/
|
||||
class DeleteResetPasswords
|
||||
{
|
||||
/**
|
||||
* Manipulador
|
||||
*/
|
||||
public function __invoke()
|
||||
{
|
||||
ResetPassword::where('created_at', '<', Carbon::now()->subMinutes(10))->delete();
|
||||
}
|
||||
}
|
||||
64
app/Supports/QuerySupport.php
Normal file
64
app/Supports/QuerySupport.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php namespace App\Supports;
|
||||
/**
|
||||
* @copyright Copyright (c) 2024 Notsoweb (https://notsoweb.com) - All rights reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Facilita algunas consultas de búsqueda
|
||||
*
|
||||
* @author Moisés de Jesús Cortés Castellanos <ing.moisesdejesuscortesc@notsoweb.com>
|
||||
*
|
||||
* @version 1.0.0
|
||||
*/
|
||||
class QuerySupport
|
||||
{
|
||||
/**
|
||||
* Realiza una búsqueda por medio de una clave
|
||||
*/
|
||||
public static function queryByKey(&$model, $key = 'name')
|
||||
{
|
||||
$query = request()->get('q');
|
||||
|
||||
if ($query) {
|
||||
$model = $model->where($key, $query);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Realiza una búsqueda por medio de una clave e incluye relaciones anidadas
|
||||
*/
|
||||
public static function queryByKeys(&$model, array $keys = ['name'])
|
||||
{
|
||||
$query = request()->get('q');
|
||||
|
||||
if ($query) {
|
||||
$model = $model->where(function ($x) use ($query, $keys) {
|
||||
$count = 0;
|
||||
|
||||
foreach ($keys as $key) {
|
||||
if (strpos($key, '.') !== false) {
|
||||
// Si la clave contiene un punto, asumimos que es una relación anidada
|
||||
list($relation, $relationKey) = explode('.', $key);
|
||||
|
||||
$x = ($count == 0)
|
||||
? $x->whereHas($relation, function ($q) use ($query, $relationKey) {
|
||||
$q->where($relationKey, 'LIKE', "%{$query}%");
|
||||
})
|
||||
: $x->orWhereHas($relation, function ($q) use ($query, $relationKey) {
|
||||
$q->where($relationKey, 'LIKE', "%{$query}%");
|
||||
});
|
||||
} else {
|
||||
$x = ($count == 0)
|
||||
? $x->where($key, 'LIKE', "%{$query}%")
|
||||
: $x->orWhere($key, 'LIKE', "%{$query}%");
|
||||
}
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $x;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,12 +6,25 @@
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withBroadcasting(
|
||||
channels: __DIR__.'/../routes/channels.php',
|
||||
attributes: ['middleware' => ['auth:api']]
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
//
|
||||
$middleware->validateCsrfTokens(except: [
|
||||
'sanctum/csrf-cookie',
|
||||
'user/*'
|
||||
]);
|
||||
$middleware->alias([
|
||||
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
|
||||
'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
|
||||
'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
//
|
||||
|
||||
0
bootstrap/cache/.gitignore
vendored
Normal file → Executable file
0
bootstrap/cache/.gitignore
vendored
Normal file → Executable file
@ -2,4 +2,6 @@
|
||||
|
||||
return [
|
||||
App\Providers\AppServiceProvider::class,
|
||||
Notsoweb\LaravelCore\ServiceProvider::class,
|
||||
Spatie\Permission\PermissionServiceProvider::class,
|
||||
];
|
||||
|
||||
@ -8,7 +8,12 @@
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"laravel/framework": "^11.31",
|
||||
"laravel/passport": "^12.0",
|
||||
"laravel/pulse": "^1.2",
|
||||
"laravel/reverb": "^1.0",
|
||||
"laravel/tinker": "^2.9",
|
||||
"notsoweb/laravel-core": "dev-main",
|
||||
"spatie/laravel-permission": "^6.10",
|
||||
"tightenco/ziggy": "^2.4"
|
||||
},
|
||||
"require-dev": {
|
||||
@ -16,6 +21,7 @@
|
||||
"laravel/pail": "^1.1",
|
||||
"laravel/pint": "^1.13",
|
||||
"laravel/sail": "^1.26",
|
||||
"laravel/telescope": "^5.2",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.1",
|
||||
"phpunit/phpunit": "^11.0.1"
|
||||
@ -51,11 +57,54 @@
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
|
||||
],
|
||||
"env:dev": [
|
||||
"composer install",
|
||||
"composer run post-root-package-install",
|
||||
"composer run post-create-project-cmd",
|
||||
"@php artisan storage:link"
|
||||
],
|
||||
"env:prod": [
|
||||
"composer install --no-dev",
|
||||
"composer run post-root-package-install",
|
||||
"composer run post-create-project-cmd",
|
||||
"@php artisan storage:link"
|
||||
],
|
||||
"db:dev": [
|
||||
"@php artisan migrate:fresh --seeder=DevSeeder",
|
||||
"@php artisan passport:client --personal --name=Holos"
|
||||
],
|
||||
"db:prod": [
|
||||
"@php artisan migrate:fresh --seed",
|
||||
"@php artisan passport:client --personal --name=Holos"
|
||||
],
|
||||
"jobs:start": [
|
||||
"pm2 start \"php artisan schedule:work\" --name holos-schedules",
|
||||
"pm2 start \"php artisan queue:work\" --name holos-queue"
|
||||
],
|
||||
"jobs:stop": [
|
||||
"pm2 delete holos-schedules",
|
||||
"pm2 delete holos-queue"
|
||||
],
|
||||
"jobs:status": [
|
||||
"pm2 show holos-schedules",
|
||||
"pm2 show holos-queue"
|
||||
],
|
||||
"broadcast:start": [
|
||||
"pm2 start \"php artisan reverb:start\" --name=holos-broadcasts"
|
||||
],
|
||||
"broadcast:stop": [
|
||||
"pm2 delete holos-broadcasts"
|
||||
],
|
||||
"broadcast:status": [
|
||||
"pm2 show holos-broadcasts"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": []
|
||||
"dont-discover": [
|
||||
"laravel/telescope"
|
||||
]
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
@ -67,6 +116,6 @@
|
||||
"php-http/discovery": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
||||
2952
composer.lock
generated
2952
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -12,9 +12,12 @@
|
||||
| other UI elements where an application name needs to be displayed.
|
||||
|
|
||||
*/
|
||||
'version' => '0.0.1',
|
||||
|
||||
'name' => env('APP_NAME', 'Laravel'),
|
||||
|
||||
'pagination' => env('APP_PAGINATION', 25),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Environment
|
||||
@ -122,5 +125,4 @@
|
||||
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
|
||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@ -40,6 +40,10 @@
|
||||
'driver' => 'session',
|
||||
'provider' => 'users',
|
||||
],
|
||||
'api' => [
|
||||
'driver' => 'passport',
|
||||
'provider' => 'users',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
@ -64,11 +68,6 @@
|
||||
'driver' => 'eloquent',
|
||||
'model' => env('AUTH_MODEL', App\Models\User::class),
|
||||
],
|
||||
|
||||
// 'users' => [
|
||||
// 'driver' => 'database',
|
||||
// 'table' => 'users',
|
||||
// ],
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
82
config/broadcasting.php
Normal file
82
config/broadcasting.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Broadcaster
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default broadcaster that will be used by the
|
||||
| framework when an event needs to be broadcast. You may set this to
|
||||
| any of the connections defined in the "connections" array below.
|
||||
|
|
||||
| Supported: "reverb", "pusher", "ably", "redis", "log", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('BROADCAST_CONNECTION', 'null'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Broadcast Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of the broadcast connections that will be used
|
||||
| to broadcast events to other systems or over WebSockets. Samples of
|
||||
| each available type of connection are provided inside this array.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'reverb' => [
|
||||
'driver' => 'reverb',
|
||||
'key' => env('REVERB_APP_KEY'),
|
||||
'secret' => env('REVERB_APP_SECRET'),
|
||||
'app_id' => env('REVERB_APP_ID'),
|
||||
'options' => [
|
||||
'host' => env('REVERB_HOST'),
|
||||
'port' => env('REVERB_PORT', 443),
|
||||
'scheme' => env('REVERB_SCHEME', 'https'),
|
||||
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
||||
],
|
||||
'client_options' => [
|
||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||
],
|
||||
],
|
||||
|
||||
'pusher' => [
|
||||
'driver' => 'pusher',
|
||||
'key' => env('PUSHER_APP_KEY'),
|
||||
'secret' => env('PUSHER_APP_SECRET'),
|
||||
'app_id' => env('PUSHER_APP_ID'),
|
||||
'options' => [
|
||||
'cluster' => env('PUSHER_APP_CLUSTER'),
|
||||
'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
|
||||
'port' => env('PUSHER_PORT', 443),
|
||||
'scheme' => env('PUSHER_SCHEME', 'https'),
|
||||
'encrypted' => true,
|
||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
||||
],
|
||||
'client_options' => [
|
||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
||||
],
|
||||
],
|
||||
|
||||
'ably' => [
|
||||
'driver' => 'ably',
|
||||
'key' => env('ABLY_KEY'),
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'driver' => 'log',
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'null',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
33
config/cors.php
Normal file
33
config/cors.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cross-Origin Resource Sharing (CORS) Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure your settings for cross-origin resource sharing
|
||||
| or "CORS". This determines what cross-origin operations may execute
|
||||
| in web browsers. You are free to adjust these settings as needed.
|
||||
|
|
||||
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
|
|
||||
*/
|
||||
|
||||
'paths' => ['api/*', 'sanctum/csrf-cookie', 'user/*', 'broadcasting/auth'],
|
||||
|
||||
'allowed_methods' => ['*'],
|
||||
|
||||
'allowed_origins' => explode(',', env('CORS_ALLOWED_ORIGINS')),
|
||||
|
||||
'allowed_origins_patterns' => [],
|
||||
|
||||
'allowed_headers' => ['*'],
|
||||
|
||||
'exposed_headers' => [],
|
||||
|
||||
'max_age' => 0,
|
||||
|
||||
'supports_credentials' => true,
|
||||
];
|
||||
@ -45,6 +45,14 @@
|
||||
'throw' => false,
|
||||
],
|
||||
|
||||
'profile' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/profile'),
|
||||
'url' => env('APP_URL').'/profile',
|
||||
'visibility' => 'public',
|
||||
'throw' => false,
|
||||
],
|
||||
|
||||
's3' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
@ -56,7 +64,6 @@
|
||||
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
|
||||
'throw' => false,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
@ -72,6 +79,6 @@
|
||||
|
||||
'links' => [
|
||||
public_path('storage') => storage_path('app/public'),
|
||||
public_path('profile') => storage_path('app/profile'),
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@ -51,7 +51,6 @@
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => explode(',', env('LOG_STACK', 'single')),
|
||||
@ -127,6 +126,9 @@
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
],
|
||||
|
||||
'mail' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/mail.log'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
return [
|
||||
|
||||
'domain' => env('MAIL_DOMAIN', 'notsoweb.com'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Mailer
|
||||
|
||||
75
config/passport.php
Normal file
75
config/passport.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Passport Guard
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which authentication guard Passport will use when
|
||||
| authenticating users. This value should correspond with one of your
|
||||
| guards that is already present in your "auth" configuration file.
|
||||
|
|
||||
*/
|
||||
|
||||
'guard' => 'web',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Keys
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Passport uses encryption keys while generating secure access tokens for
|
||||
| your application. By default, the keys are stored as local files but
|
||||
| can be set via environment variables when that is more convenient.
|
||||
|
|
||||
*/
|
||||
|
||||
'private_key' => env('PASSPORT_PRIVATE_KEY'),
|
||||
|
||||
'public_key' => env('PASSPORT_PUBLIC_KEY'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Passport Database Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default, Passport's models will utilize your application's default
|
||||
| database connection. If you wish to use a different connection you
|
||||
| may specify the configured name of the database connection here.
|
||||
|
|
||||
*/
|
||||
|
||||
'connection' => env('PASSPORT_CONNECTION'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Client UUIDs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default, Passport uses auto-incrementing primary keys when assigning
|
||||
| IDs to clients. However, if Passport is installed using the provided
|
||||
| --uuids switch, this will be set to "true" and UUIDs will be used.
|
||||
|
|
||||
*/
|
||||
|
||||
'client_uuids' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Personal Access Client
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you enable client hashing, you should set the personal access client
|
||||
| ID and unhashed secret within your environment file. The values will
|
||||
| get used while issuing fresh personal access tokens to your users.
|
||||
|
|
||||
*/
|
||||
|
||||
'personal_access_client' => [
|
||||
'id' => env('PASSPORT_PERSONAL_ACCESS_CLIENT_ID'),
|
||||
'secret' => env('PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET'),
|
||||
],
|
||||
|
||||
];
|
||||
186
config/permission.php
Normal file
186
config/permission.php
Normal file
@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'models' => [
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your permissions. Of course, it
|
||||
* is often just the "Permission" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Permission model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Permission` contract.
|
||||
*/
|
||||
|
||||
'permission' => Spatie\Permission\Models\Permission::class,
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* Eloquent model should be used to retrieve your roles. Of course, it
|
||||
* is often just the "Role" model but you may use whatever you like.
|
||||
*
|
||||
* The model you want to use as a Role model needs to implement the
|
||||
* `Spatie\Permission\Contracts\Role` contract.
|
||||
*/
|
||||
|
||||
'role' => Spatie\Permission\Models\Role::class,
|
||||
|
||||
],
|
||||
|
||||
'table_names' => [
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'roles' => 'roles',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your permissions. We have chosen a basic
|
||||
* default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'permissions' => 'permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasPermissions" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_permissions' => 'model_has_permissions',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your models roles. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'model_has_roles' => 'model_has_roles',
|
||||
|
||||
/*
|
||||
* When using the "HasRoles" trait from this package, we need to know which
|
||||
* table should be used to retrieve your roles permissions. We have chosen a
|
||||
* basic default value but you may easily change it to any table you like.
|
||||
*/
|
||||
|
||||
'role_has_permissions' => 'role_has_permissions',
|
||||
],
|
||||
|
||||
'column_names' => [
|
||||
/*
|
||||
* Change this if you want to name the related pivots other than defaults
|
||||
*/
|
||||
'role_pivot_key' => null, //default 'role_id',
|
||||
'permission_pivot_key' => null, //default 'permission_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to name the related model primary key other than
|
||||
* `model_id`.
|
||||
*
|
||||
* For example, this would be nice if your primary keys are all UUIDs. In
|
||||
* that case, name this `model_uuid`.
|
||||
*/
|
||||
|
||||
'model_morph_key' => 'model_id',
|
||||
|
||||
/*
|
||||
* Change this if you want to use the teams feature and your related model's
|
||||
* foreign key is other than `team_id`.
|
||||
*/
|
||||
|
||||
'team_foreign_key' => 'team_id',
|
||||
],
|
||||
|
||||
/*
|
||||
* When set to true, the method for checking permissions will be registered on the gate.
|
||||
* Set this to false if you want to implement custom logic for checking permissions.
|
||||
*/
|
||||
|
||||
'register_permission_check_method' => true,
|
||||
|
||||
/*
|
||||
* When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered
|
||||
* this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated
|
||||
* NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it.
|
||||
*/
|
||||
'register_octane_reset_listener' => false,
|
||||
|
||||
/*
|
||||
* Teams Feature.
|
||||
* When set to true the package implements teams using the 'team_foreign_key'.
|
||||
* If you want the migrations to register the 'team_foreign_key', you must
|
||||
* set this to true before doing the migration.
|
||||
* If you already did the migration then you must make a new migration to also
|
||||
* add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions'
|
||||
* (view the latest version of this package's migration file)
|
||||
*/
|
||||
|
||||
'teams' => false,
|
||||
|
||||
/*
|
||||
* Passport Client Credentials Grant
|
||||
* When set to true the package will use Passports Client to check permissions
|
||||
*/
|
||||
|
||||
'use_passport_client_credentials' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required permission names are added to exception messages.
|
||||
* This could be considered an information leak in some contexts, so the default
|
||||
* setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_permission_in_exception' => false,
|
||||
|
||||
/*
|
||||
* When set to true, the required role names are added to exception messages.
|
||||
* This could be considered an information leak in some contexts, so the default
|
||||
* setting is false here for optimum safety.
|
||||
*/
|
||||
|
||||
'display_role_in_exception' => false,
|
||||
|
||||
/*
|
||||
* By default wildcard permission lookups are disabled.
|
||||
* See documentation to understand supported syntax.
|
||||
*/
|
||||
|
||||
'enable_wildcard_permission' => false,
|
||||
|
||||
/*
|
||||
* The class to use for interpreting wildcard permissions.
|
||||
* If you need to modify delimiters, override the class and specify its name here.
|
||||
*/
|
||||
// 'permission.wildcard_permission' => Spatie\Permission\WildcardPermission::class,
|
||||
|
||||
/* Cache-specific settings */
|
||||
|
||||
'cache' => [
|
||||
|
||||
/*
|
||||
* By default all permissions are cached for 24 hours to speed up performance.
|
||||
* When permissions or roles are updated the cache is flushed automatically.
|
||||
*/
|
||||
|
||||
'expiration_time' => \DateInterval::createFromDateString('24 hours'),
|
||||
|
||||
/*
|
||||
* The cache key used to store all permissions.
|
||||
*/
|
||||
|
||||
'key' => 'spatie.permission.cache',
|
||||
|
||||
/*
|
||||
* You may optionally indicate a specific cache driver to use for permission and
|
||||
* role caching using any of the `store` drivers listed in the cache.php config
|
||||
* file. Using 'default' here means to use the `default` set in cache.php.
|
||||
*/
|
||||
|
||||
'store' => 'default',
|
||||
],
|
||||
];
|
||||
232
config/pulse.php
Normal file
232
config/pulse.php
Normal file
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Pulse\Http\Middleware\Authorize;
|
||||
use Laravel\Pulse\Pulse;
|
||||
use Laravel\Pulse\Recorders;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pulse Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the subdomain which the Pulse dashboard will be accessible from.
|
||||
| When set to null, the dashboard will reside under the same domain as
|
||||
| the application. Remember to configure your DNS entries correctly.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('PULSE_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pulse Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the path which the Pulse dashboard will be accessible from. Feel
|
||||
| free to change this path to anything you'd like. Note that this won't
|
||||
| affect the path of the internal API that is never exposed to users.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => env('PULSE_PATH', 'pulse'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pulse Master Switch
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration option may be used to completely disable all Pulse
|
||||
| data recorders regardless of their individual configurations. This
|
||||
| provides a single option to quickly disable all Pulse recording.
|
||||
|
|
||||
*/
|
||||
|
||||
'enabled' => env('PULSE_ENABLED', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pulse Storage Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration option determines which storage driver will be used
|
||||
| while storing entries from Pulse's recorders. In addition, you also
|
||||
| may provide any options to configure the selected storage driver.
|
||||
|
|
||||
*/
|
||||
|
||||
'storage' => [
|
||||
'driver' => env('PULSE_STORAGE_DRIVER', 'database'),
|
||||
|
||||
'database' => [
|
||||
'connection' => env('PULSE_DB_CONNECTION'),
|
||||
'chunk' => 1000,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pulse Ingest Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration options determines the ingest driver that will be used
|
||||
| to capture entries from Pulse's recorders. Ingest drivers are great to
|
||||
| free up your request workers quickly by offloading the data storage.
|
||||
|
|
||||
*/
|
||||
|
||||
'ingest' => [
|
||||
'driver' => env('PULSE_INGEST_DRIVER', 'storage'),
|
||||
|
||||
'buffer' => env('PULSE_INGEST_BUFFER', 5_000),
|
||||
|
||||
'trim' => [
|
||||
'lottery' => [1, 1_000],
|
||||
'keep' => '7 days',
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'connection' => env('PULSE_REDIS_CONNECTION'),
|
||||
'chunk' => 1000,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pulse Cache Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration option determines the cache driver that will be used
|
||||
| for various tasks, including caching dashboard results, establishing
|
||||
| locks for events that should only occur on one server and signals.
|
||||
|
|
||||
*/
|
||||
|
||||
'cache' => env('PULSE_CACHE_DRIVER'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pulse Route Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These middleware will be assigned to every Pulse route, giving you the
|
||||
| chance to add your own middleware to this list or change any of the
|
||||
| existing middleware. Of course, reasonable defaults are provided.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => [
|
||||
'web',
|
||||
Authorize::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pulse Recorders
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following array lists the "recorders" that will be registered with
|
||||
| Pulse, along with their configuration. Recorders gather application
|
||||
| event data from requests and tasks to pass to your ingest driver.
|
||||
|
|
||||
*/
|
||||
|
||||
'recorders' => [
|
||||
Recorders\CacheInteractions::class => [
|
||||
'enabled' => env('PULSE_CACHE_INTERACTIONS_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_CACHE_INTERACTIONS_SAMPLE_RATE', 1),
|
||||
'ignore' => [
|
||||
...Pulse::defaultVendorCacheKeys(),
|
||||
],
|
||||
'groups' => [
|
||||
'/^job-exceptions:.*/' => 'job-exceptions:*',
|
||||
// '/:\d+/' => ':*',
|
||||
],
|
||||
],
|
||||
|
||||
Recorders\Exceptions::class => [
|
||||
'enabled' => env('PULSE_EXCEPTIONS_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_EXCEPTIONS_SAMPLE_RATE', 1),
|
||||
'location' => env('PULSE_EXCEPTIONS_LOCATION', true),
|
||||
'ignore' => [
|
||||
// '/^Package\\\\Exceptions\\\\/',
|
||||
],
|
||||
],
|
||||
|
||||
Recorders\Queues::class => [
|
||||
'enabled' => env('PULSE_QUEUES_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_QUEUES_SAMPLE_RATE', 1),
|
||||
'ignore' => [
|
||||
// '/^Package\\\\Jobs\\\\/',
|
||||
],
|
||||
],
|
||||
|
||||
Recorders\Servers::class => [
|
||||
'server_name' => env('PULSE_SERVER_NAME', gethostname()),
|
||||
'directories' => explode(':', env('PULSE_SERVER_DIRECTORIES', '/')),
|
||||
],
|
||||
|
||||
Recorders\SlowJobs::class => [
|
||||
'enabled' => env('PULSE_SLOW_JOBS_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_SLOW_JOBS_SAMPLE_RATE', 1),
|
||||
'threshold' => env('PULSE_SLOW_JOBS_THRESHOLD', 1000),
|
||||
'ignore' => [
|
||||
// '/^Package\\\\Jobs\\\\/',
|
||||
],
|
||||
],
|
||||
|
||||
Recorders\SlowOutgoingRequests::class => [
|
||||
'enabled' => env('PULSE_SLOW_OUTGOING_REQUESTS_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_SLOW_OUTGOING_REQUESTS_SAMPLE_RATE', 1),
|
||||
'threshold' => env('PULSE_SLOW_OUTGOING_REQUESTS_THRESHOLD', 1000),
|
||||
'ignore' => [
|
||||
// '#^http://127\.0\.0\.1:13714#', // Inertia SSR...
|
||||
],
|
||||
'groups' => [
|
||||
// '#^https://api\.github\.com/repos/.*$#' => 'api.github.com/repos/*',
|
||||
// '#^https?://([^/]*).*$#' => '\1',
|
||||
// '#/\d+#' => '/*',
|
||||
],
|
||||
],
|
||||
|
||||
Recorders\SlowQueries::class => [
|
||||
'enabled' => env('PULSE_SLOW_QUERIES_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_SLOW_QUERIES_SAMPLE_RATE', 1),
|
||||
'threshold' => env('PULSE_SLOW_QUERIES_THRESHOLD', 1000),
|
||||
'location' => env('PULSE_SLOW_QUERIES_LOCATION', true),
|
||||
'max_query_length' => env('PULSE_SLOW_QUERIES_MAX_QUERY_LENGTH'),
|
||||
'ignore' => [
|
||||
'/(["`])pulse_[\w]+?\1/', // Pulse tables...
|
||||
'/(["`])telescope_[\w]+?\1/', // Telescope tables...
|
||||
],
|
||||
],
|
||||
|
||||
Recorders\SlowRequests::class => [
|
||||
'enabled' => env('PULSE_SLOW_REQUESTS_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_SLOW_REQUESTS_SAMPLE_RATE', 1),
|
||||
'threshold' => env('PULSE_SLOW_REQUESTS_THRESHOLD', 1000),
|
||||
'ignore' => [
|
||||
'#^/'.env('PULSE_PATH', 'pulse').'$#', // Pulse dashboard...
|
||||
'#^/telescope#', // Telescope dashboard...
|
||||
],
|
||||
],
|
||||
|
||||
Recorders\UserJobs::class => [
|
||||
'enabled' => env('PULSE_USER_JOBS_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_USER_JOBS_SAMPLE_RATE', 1),
|
||||
'ignore' => [
|
||||
// '/^Package\\\\Jobs\\\\/',
|
||||
],
|
||||
],
|
||||
|
||||
Recorders\UserRequests::class => [
|
||||
'enabled' => env('PULSE_USER_REQUESTS_ENABLED', true),
|
||||
'sample_rate' => env('PULSE_USER_REQUESTS_SAMPLE_RATE', 1),
|
||||
'ignore' => [
|
||||
'#^/'.env('PULSE_PATH', 'pulse').'$#', // Pulse dashboard...
|
||||
'#^/telescope#', // Telescope dashboard...
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
92
config/reverb.php
Normal file
92
config/reverb.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Reverb Server
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default server used by Reverb to handle
|
||||
| incoming messages as well as broadcasting message to all your
|
||||
| connected clients. At this time only "reverb" is supported.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('REVERB_SERVER', 'reverb'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Reverb Servers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define details for each of the supported Reverb servers.
|
||||
| Each server has its own configuration options that are defined in
|
||||
| the array below. You should ensure all the options are present.
|
||||
|
|
||||
*/
|
||||
|
||||
'servers' => [
|
||||
|
||||
'reverb' => [
|
||||
'host' => env('REVERB_SERVER_HOST', '0.0.0.0'),
|
||||
'port' => env('REVERB_SERVER_PORT', 8080),
|
||||
'hostname' => env('REVERB_HOST'),
|
||||
'options' => [
|
||||
'tls' => [],
|
||||
],
|
||||
'max_request_size' => env('REVERB_MAX_REQUEST_SIZE', 10_000),
|
||||
'scaling' => [
|
||||
'enabled' => env('REVERB_SCALING_ENABLED', false),
|
||||
'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'),
|
||||
'server' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'username' => env('REDIS_USERNAME'),
|
||||
'password' => env('REDIS_PASSWORD'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
],
|
||||
],
|
||||
'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15),
|
||||
'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Reverb Applications
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define how Reverb applications are managed. If you choose
|
||||
| to use the "config" provider, you may define an array of apps which
|
||||
| your server will support, including their connection credentials.
|
||||
|
|
||||
*/
|
||||
|
||||
'apps' => [
|
||||
|
||||
'provider' => 'config',
|
||||
|
||||
'apps' => [
|
||||
[
|
||||
'key' => env('REVERB_APP_KEY'),
|
||||
'secret' => env('REVERB_APP_SECRET'),
|
||||
'app_id' => env('REVERB_APP_ID'),
|
||||
'options' => [
|
||||
'host' => env('REVERB_HOST'),
|
||||
'port' => env('REVERB_PORT', 443),
|
||||
'scheme' => env('REVERB_SCHEME', 'https'),
|
||||
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
||||
],
|
||||
'allowed_origins' => ['*'],
|
||||
'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60),
|
||||
'activity_timeout' => env('REVERB_APP_ACTIVITY_TIMEOUT', 30),
|
||||
'max_message_size' => env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000),
|
||||
],
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
205
config/telescope.php
Normal file
205
config/telescope.php
Normal file
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Telescope\Http\Middleware\Authorize;
|
||||
use Laravel\Telescope\Watchers;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Master Switch
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option may be used to disable all Telescope watchers regardless
|
||||
| of their individual configuration, which simply provides a single
|
||||
| and convenient way to enable or disable Telescope data storage.
|
||||
|
|
||||
*/
|
||||
|
||||
'enabled' => env('TELESCOPE_ENABLED', true),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the subdomain where Telescope will be accessible from. If the
|
||||
| setting is null, Telescope will reside under the same domain as the
|
||||
| application. Otherwise, this value will be used as the subdomain.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('TELESCOPE_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the URI path where Telescope will be accessible from. Feel free
|
||||
| to change this path to anything you like. Note that the URI will not
|
||||
| affect the paths of its internal API that aren't exposed to users.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => env('TELESCOPE_PATH', 'telescope'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Storage Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration options determines the storage driver that will
|
||||
| be used to store Telescope's data. In addition, you may set any
|
||||
| custom options as needed by the particular driver you choose.
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('TELESCOPE_DRIVER', 'database'),
|
||||
|
||||
'storage' => [
|
||||
'database' => [
|
||||
'connection' => env('DB_CONNECTION', 'mysql'),
|
||||
'chunk' => 1000,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Queue
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration options determines the queue connection and queue
|
||||
| which will be used to process ProcessPendingUpdate jobs. This can
|
||||
| be changed if you would prefer to use a non-default connection.
|
||||
|
|
||||
*/
|
||||
|
||||
'queue' => [
|
||||
'connection' => env('TELESCOPE_QUEUE_CONNECTION', null),
|
||||
'queue' => env('TELESCOPE_QUEUE', null),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Route Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These middleware will be assigned to every Telescope route, giving you
|
||||
| the chance to add your own middleware to this list or change any of
|
||||
| the existing middleware. Or, you can simply stick with this list.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => [
|
||||
'web',
|
||||
Authorize::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Allowed / Ignored Paths & Commands
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following array lists the URI paths and Artisan commands that will
|
||||
| not be watched by Telescope. In addition to this list, some Laravel
|
||||
| commands, like migrations and queue commands, are always ignored.
|
||||
|
|
||||
*/
|
||||
|
||||
'only_paths' => [
|
||||
// 'api/*'
|
||||
],
|
||||
|
||||
'ignore_paths' => [
|
||||
'livewire*',
|
||||
'nova-api*',
|
||||
'pulse*',
|
||||
],
|
||||
|
||||
'ignore_commands' => [
|
||||
//
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Watchers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following array lists the "watchers" that will be registered with
|
||||
| Telescope. The watchers gather the application's profile data when
|
||||
| a request or task is executed. Feel free to customize this list.
|
||||
|
|
||||
*/
|
||||
|
||||
'watchers' => [
|
||||
Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true),
|
||||
|
||||
Watchers\CacheWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_CACHE_WATCHER', true),
|
||||
'hidden' => [],
|
||||
],
|
||||
|
||||
Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true),
|
||||
|
||||
Watchers\CommandWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
|
||||
'ignore' => [],
|
||||
],
|
||||
|
||||
Watchers\DumpWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_DUMP_WATCHER', true),
|
||||
'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false),
|
||||
],
|
||||
|
||||
Watchers\EventWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_EVENT_WATCHER', true),
|
||||
'ignore' => [],
|
||||
],
|
||||
|
||||
Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
|
||||
|
||||
Watchers\GateWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_GATE_WATCHER', true),
|
||||
'ignore_abilities' => [],
|
||||
'ignore_packages' => true,
|
||||
'ignore_paths' => [],
|
||||
],
|
||||
|
||||
Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
|
||||
|
||||
Watchers\LogWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_LOG_WATCHER', true),
|
||||
'level' => 'error',
|
||||
],
|
||||
|
||||
Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
|
||||
|
||||
Watchers\ModelWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
|
||||
'events' => ['eloquent.*'],
|
||||
'hydrations' => true,
|
||||
],
|
||||
|
||||
Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
|
||||
|
||||
Watchers\QueryWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
|
||||
'ignore_packages' => true,
|
||||
'ignore_paths' => [],
|
||||
'slow' => 100,
|
||||
],
|
||||
|
||||
Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
|
||||
|
||||
Watchers\RequestWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
|
||||
'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
|
||||
'ignore_http_methods' => [],
|
||||
'ignore_status_codes' => [],
|
||||
],
|
||||
|
||||
Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
|
||||
Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true),
|
||||
],
|
||||
];
|
||||
@ -14,10 +14,15 @@ public function up(): void
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('paternal');
|
||||
$table->string('maternal')->nullable();
|
||||
$table->string('phone')->nullable();
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->foreignId('current_team_id')->nullable();
|
||||
$table->string('profile_photo_path', 2048)->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
<?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
|
||||
{
|
||||
Schema::create('oauth_auth_codes', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->unsignedBigInteger('user_id')->index();
|
||||
$table->uuid('client_id');
|
||||
$table->text('scopes')->nullable();
|
||||
$table->boolean('revoked');
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_auth_codes');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,33 @@
|
||||
<?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
|
||||
{
|
||||
Schema::create('oauth_access_tokens', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->unsignedBigInteger('user_id')->nullable()->index();
|
||||
$table->uuid('client_id');
|
||||
$table->string('name')->nullable();
|
||||
$table->text('scopes')->nullable();
|
||||
$table->boolean('revoked');
|
||||
$table->timestamps();
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_access_tokens');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,29 @@
|
||||
<?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
|
||||
{
|
||||
Schema::create('oauth_refresh_tokens', function (Blueprint $table) {
|
||||
$table->string('id', 100)->primary();
|
||||
$table->string('access_token_id', 100)->index();
|
||||
$table->boolean('revoked');
|
||||
$table->dateTime('expires_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_refresh_tokens');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,35 @@
|
||||
<?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
|
||||
{
|
||||
Schema::create('oauth_clients', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->unsignedBigInteger('user_id')->nullable()->index();
|
||||
$table->string('name');
|
||||
$table->string('secret', 100)->nullable();
|
||||
$table->string('provider')->nullable();
|
||||
$table->text('redirect');
|
||||
$table->boolean('personal_access_client');
|
||||
$table->boolean('password_client');
|
||||
$table->boolean('revoked');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_clients');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,28 @@
|
||||
<?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
|
||||
{
|
||||
Schema::create('oauth_personal_access_clients', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->uuid('client_id');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('oauth_personal_access_clients');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Laravel\Pulse\Support\PulseMigration;
|
||||
|
||||
return new class extends PulseMigration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
if (! $this->shouldRun()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Schema::create('pulse_values', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedInteger('timestamp');
|
||||
$table->string('type');
|
||||
$table->mediumText('key');
|
||||
match ($this->driver()) {
|
||||
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||
'sqlite' => $table->string('key_hash'),
|
||||
};
|
||||
$table->mediumText('value');
|
||||
|
||||
$table->index('timestamp'); // For trimming...
|
||||
$table->index('type'); // For fast lookups and purging...
|
||||
$table->unique(['type', 'key_hash']); // For data integrity and upserts...
|
||||
});
|
||||
|
||||
Schema::create('pulse_entries', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedInteger('timestamp');
|
||||
$table->string('type');
|
||||
$table->mediumText('key');
|
||||
match ($this->driver()) {
|
||||
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||
'sqlite' => $table->string('key_hash'),
|
||||
};
|
||||
$table->bigInteger('value')->nullable();
|
||||
|
||||
$table->index('timestamp'); // For trimming...
|
||||
$table->index('type'); // For purging...
|
||||
$table->index('key_hash'); // For mapping...
|
||||
$table->index(['timestamp', 'type', 'key_hash', 'value']); // For aggregate queries...
|
||||
});
|
||||
|
||||
Schema::create('pulse_aggregates', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedInteger('bucket');
|
||||
$table->unsignedMediumInteger('period');
|
||||
$table->string('type');
|
||||
$table->mediumText('key');
|
||||
match ($this->driver()) {
|
||||
'mariadb', 'mysql' => $table->char('key_hash', 16)->charset('binary')->virtualAs('unhex(md5(`key`))'),
|
||||
'pgsql' => $table->uuid('key_hash')->storedAs('md5("key")::uuid'),
|
||||
'sqlite' => $table->string('key_hash'),
|
||||
};
|
||||
$table->string('aggregate');
|
||||
$table->decimal('value', 20, 2);
|
||||
$table->unsignedInteger('count')->nullable();
|
||||
|
||||
$table->unique(['bucket', 'period', 'type', 'aggregate', 'key_hash']); // Force "on duplicate update"...
|
||||
$table->index(['period', 'bucket']); // For trimming...
|
||||
$table->index('type'); // For purging...
|
||||
$table->index(['period', 'type', 'aggregate', 'bucket']); // For aggregate queries...
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('pulse_values');
|
||||
Schema::dropIfExists('pulse_entries');
|
||||
Schema::dropIfExists('pulse_aggregates');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Get the migration connection name.
|
||||
*/
|
||||
public function getConnection(): ?string
|
||||
{
|
||||
return config('telescope.storage.database.connection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$schema = Schema::connection($this->getConnection());
|
||||
|
||||
$schema->create('telescope_entries', function (Blueprint $table) {
|
||||
$table->bigIncrements('sequence');
|
||||
$table->uuid('uuid');
|
||||
$table->uuid('batch_id');
|
||||
$table->string('family_hash')->nullable();
|
||||
$table->boolean('should_display_on_index')->default(true);
|
||||
$table->string('type', 20);
|
||||
$table->longText('content');
|
||||
$table->dateTime('created_at')->nullable();
|
||||
|
||||
$table->unique('uuid');
|
||||
$table->index('batch_id');
|
||||
$table->index('family_hash');
|
||||
$table->index('created_at');
|
||||
$table->index(['type', 'should_display_on_index']);
|
||||
});
|
||||
|
||||
$schema->create('telescope_entries_tags', function (Blueprint $table) {
|
||||
$table->uuid('entry_uuid');
|
||||
$table->string('tag');
|
||||
|
||||
$table->primary(['entry_uuid', 'tag']);
|
||||
$table->index('tag');
|
||||
|
||||
$table->foreign('entry_uuid')
|
||||
->references('uuid')
|
||||
->on('telescope_entries')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
|
||||
$schema->create('telescope_monitoring', function (Blueprint $table) {
|
||||
$table->string('tag')->primary();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$schema = Schema::connection($this->getConnection());
|
||||
|
||||
$schema->dropIfExists('telescope_entries_tags');
|
||||
$schema->dropIfExists('telescope_entries');
|
||||
$schema->dropIfExists('telescope_monitoring');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('permission_types', function (Blueprint $table) {
|
||||
$table->id('id');
|
||||
$table->string('name');
|
||||
$table->string('description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
// Tabla de equipos
|
||||
$teams = config('permission.teams');
|
||||
// Nombre de tablas
|
||||
$tableNames = config('permission.table_names');
|
||||
// Nombre columnas
|
||||
$columnNames = config('permission.column_names');
|
||||
// FK de roles
|
||||
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
|
||||
// FK de permisos
|
||||
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
|
||||
|
||||
// No permitir continuar sin tener declarado el nombre de las tablas
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
}
|
||||
// No permitir continuar sin tener declarado el nombre de la columna de equipo
|
||||
if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
|
||||
throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
|
||||
}
|
||||
|
||||
// Crear tabla de permisos
|
||||
Schema::create($tableNames['permissions'], function (Blueprint $table) {
|
||||
//$table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // permission id
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->string('description')->nullable();
|
||||
$table->foreignId('permission_type_id')
|
||||
->nullable()
|
||||
->constrained()
|
||||
->nullOnDelete();
|
||||
|
||||
$table->timestamps();
|
||||
$table->unique(['name', 'guard_name']);
|
||||
});
|
||||
|
||||
// Crear tabla de roles
|
||||
Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
|
||||
//$table->engine('InnoDB');
|
||||
$table->bigIncrements('id'); // role id
|
||||
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
|
||||
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
|
||||
}
|
||||
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
|
||||
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
|
||||
$table->string('description')->nullable();
|
||||
$table->timestamps();
|
||||
if ($teams || config('permission.testing')) {
|
||||
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
|
||||
} else {
|
||||
$table->unique(['name', 'guard_name']);
|
||||
}
|
||||
});
|
||||
|
||||
// Crear tabla de relación de modelos con permisos
|
||||
Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_permissions_permission_model_type_primary');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Crear tabla de relación de modelos con roles
|
||||
Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->string('model_type');
|
||||
$table->unsignedBigInteger($columnNames['model_morph_key']);
|
||||
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
if ($teams) {
|
||||
$table->unsignedBigInteger($columnNames['team_foreign_key']);
|
||||
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
|
||||
|
||||
$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
} else {
|
||||
$table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
|
||||
'model_has_roles_role_model_type_primary');
|
||||
}
|
||||
});
|
||||
|
||||
// Crear tabla de relación de roles con permisos
|
||||
Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
|
||||
$table->unsignedBigInteger($pivotPermission);
|
||||
$table->unsignedBigInteger($pivotRole);
|
||||
|
||||
$table->foreign($pivotPermission)
|
||||
->references('id') // permission id
|
||||
->on($tableNames['permissions'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign($pivotRole)
|
||||
->references('id') // role id
|
||||
->on($tableNames['roles'])
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
|
||||
});
|
||||
|
||||
app('cache')
|
||||
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
|
||||
->forget(config('permission.cache.key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$tableNames = config('permission.table_names');
|
||||
|
||||
if (empty($tableNames)) {
|
||||
throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
|
||||
}
|
||||
|
||||
Schema::drop('permission_types');
|
||||
Schema::drop($tableNames['role_has_permissions']);
|
||||
Schema::drop($tableNames['model_has_roles']);
|
||||
Schema::drop($tableNames['model_has_permissions']);
|
||||
Schema::drop($tableNames['roles']);
|
||||
Schema::drop($tableNames['permissions']);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,28 @@
|
||||
<?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
|
||||
{
|
||||
Schema::create('reset_passwords', function (Blueprint $table) {
|
||||
$table->string('email')->index();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('reset_passwords');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
<?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
|
||||
{
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->string('type');
|
||||
$table->morphs('notifiable');
|
||||
$table->text('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
}
|
||||
};
|
||||
15
database/seeders/DevSeeder.php
Normal file
15
database/seeders/DevSeeder.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DevSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$this->call(RoleSeeder::class);
|
||||
$this->call(UserSeeder::class);
|
||||
}
|
||||
}
|
||||
49
database/seeders/RoleSeeder.php
Normal file
49
database/seeders/RoleSeeder.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php namespace Database\Seeders;
|
||||
|
||||
use App\Models\PermissionType;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Notsoweb\LaravelCore\Traits\MySql\RolePermission;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
class RoleSeeder extends Seeder
|
||||
{
|
||||
use RolePermission;
|
||||
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$users = PermissionType::create([
|
||||
'name' => 'Usuarios'
|
||||
]);
|
||||
|
||||
[
|
||||
$userIndex,
|
||||
$userCreate,
|
||||
$userEdit,
|
||||
$userDestroy
|
||||
] = $this->onCRUD('users', $users);
|
||||
|
||||
$userSettings = $this->onPermission('users.settings', 'Configuración de usuarios', $users);
|
||||
|
||||
// Desarrollador
|
||||
Role::create([
|
||||
'name' => 'developer',
|
||||
'description' => 'Desarrollador'
|
||||
])->givePermissionTo(Permission::all());
|
||||
|
||||
// Administrador
|
||||
Role::create([
|
||||
'name' => 'admin',
|
||||
'description' => 'Administrador'
|
||||
])->givePermissionTo(
|
||||
$userIndex,
|
||||
$userCreate,
|
||||
$userEdit,
|
||||
$userDestroy,
|
||||
$userSettings
|
||||
);
|
||||
}
|
||||
}
|
||||
32
database/seeders/UserSeeder.php
Normal file
32
database/seeders/UserSeeder.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Notsoweb\LaravelCore\Supports\UserSecureSupport;
|
||||
|
||||
class UserSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
$developer = UserSecureSupport::create('developer@notsoweb.com');
|
||||
|
||||
User::create([
|
||||
'name' => 'Developer',
|
||||
'paternal' => 'Notsoweb',
|
||||
'email' => $developer->email,
|
||||
'password' => $developer->hash,
|
||||
])->assignRole(__('developer'));
|
||||
|
||||
$admin = UserSecureSupport::create('admin@notsoweb.com');
|
||||
|
||||
User::create([
|
||||
'name' => 'Developer',
|
||||
'paternal' => 'Notsoweb',
|
||||
'email' => $admin->email,
|
||||
'password' => $admin->hash,
|
||||
])->assignRole(__('admin'));
|
||||
}
|
||||
}
|
||||
20
lang/en/auth.php
Normal file
20
lang/en/auth.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used during authentication for various
|
||||
| messages that we need to display to the user. You are free to modify
|
||||
| these language lines according to your application's requirements.
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => 'These credentials do not match our records.',
|
||||
'password' => 'The provided password is incorrect.',
|
||||
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
|
||||
|
||||
];
|
||||
6
lang/en/cache.php
Normal file
6
lang/en/cache.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'no-cache' => ':label ":var" does not exist in the cache',
|
||||
'save' => ':label ":var" saved in the cache',
|
||||
];
|
||||
19
lang/en/pagination.php
Normal file
19
lang/en/pagination.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pagination Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used by the paginator library to build
|
||||
| the simple pagination links. You are free to change them to anything
|
||||
| you want to customize your views to better match your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'previous' => '« Previous',
|
||||
'next' => 'Next »',
|
||||
|
||||
];
|
||||
23
lang/en/passwords.php
Normal file
23
lang/en/passwords.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are the default lines which match reasons
|
||||
| that are given by the password broker for a password update attempt
|
||||
| has failed, such as for an invalid token or invalid new password.
|
||||
|
|
||||
*/
|
||||
|
||||
'no_match' => 'The provided password does not match your current password.',
|
||||
'reset' => 'Your password has been reset!',
|
||||
'sent' => 'We have emailed your password reset link!',
|
||||
'throttled' => 'Please wait before retrying.',
|
||||
'token' => 'This password reset token is invalid.',
|
||||
'user' => "We can't find a user with that email address.",
|
||||
|
||||
];
|
||||
174
lang/en/validation.php
Normal file
174
lang/en/validation.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines contain the default error messages used by
|
||||
| the validator class. Some of these rules have multiple versions such
|
||||
| as the size rules. Feel free to tweak each of these messages here.
|
||||
|
|
||||
*/
|
||||
|
||||
'accepted' => 'The :attribute must be accepted.',
|
||||
'accepted_if' => 'The :attribute must be accepted when :other is :value.',
|
||||
'active_url' => 'The :attribute is not a valid URL.',
|
||||
'after' => 'The :attribute must be a date after :date.',
|
||||
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
|
||||
'alpha' => 'The :attribute must only contain letters.',
|
||||
'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.',
|
||||
'alpha_num' => 'The :attribute must only contain letters and numbers.',
|
||||
'array' => 'The :attribute must be an array.',
|
||||
'before' => 'The :attribute must be a date before :date.',
|
||||
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
|
||||
'between' => [
|
||||
'array' => 'The :attribute must have between :min and :max items.',
|
||||
'file' => 'The :attribute must be between :min and :max kilobytes.',
|
||||
'numeric' => 'The :attribute must be between :min and :max.',
|
||||
'string' => 'The :attribute must be between :min and :max characters.',
|
||||
],
|
||||
'boolean' => 'The :attribute field must be true or false.',
|
||||
'confirmed' => 'The :attribute confirmation does not match.',
|
||||
'current_password' => 'The password is incorrect.',
|
||||
'date' => 'The :attribute is not a valid date.',
|
||||
'date_equals' => 'The :attribute must be a date equal to :date.',
|
||||
'date_format' => 'The :attribute does not match the format :format.',
|
||||
'declined' => 'The :attribute must be declined.',
|
||||
'declined_if' => 'The :attribute must be declined when :other is :value.',
|
||||
'different' => 'The :attribute and :other must be different.',
|
||||
'digits' => 'The :attribute must be :digits digits.',
|
||||
'digits_between' => 'The :attribute must be between :min and :max digits.',
|
||||
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||
'distinct' => 'The :attribute field has a duplicate value.',
|
||||
'doesnt_end_with' => 'The :attribute may not end with one of the following: :values.',
|
||||
'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',
|
||||
'email' => 'The :attribute must be a valid email address.',
|
||||
'ends_with' => 'The :attribute must end with one of the following: :values.',
|
||||
'enum' => 'The selected :attribute is invalid.',
|
||||
'exists' => 'The selected :attribute is invalid.',
|
||||
'file' => 'The :attribute must be a file.',
|
||||
'filled' => 'The :attribute field must have a value.',
|
||||
'gt' => [
|
||||
'array' => 'The :attribute must have more than :value items.',
|
||||
'file' => 'The :attribute must be greater than :value kilobytes.',
|
||||
'numeric' => 'The :attribute must be greater than :value.',
|
||||
'string' => 'The :attribute must be greater than :value characters.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'The :attribute must have :value items or more.',
|
||||
'file' => 'The :attribute must be greater than or equal to :value kilobytes.',
|
||||
'numeric' => 'The :attribute must be greater than or equal to :value.',
|
||||
'string' => 'The :attribute must be greater than or equal to :value characters.',
|
||||
],
|
||||
'image' => 'The :attribute must be an image.',
|
||||
'in' => 'The selected :attribute is invalid.',
|
||||
'in_array' => 'The :attribute field does not exist in :other.',
|
||||
'integer' => 'The :attribute must be an integer.',
|
||||
'ip' => 'The :attribute must be a valid IP address.',
|
||||
'ipv4' => 'The :attribute must be a valid IPv4 address.',
|
||||
'ipv6' => 'The :attribute must be a valid IPv6 address.',
|
||||
'json' => 'The :attribute must be a valid JSON string.',
|
||||
'lt' => [
|
||||
'array' => 'The :attribute must have less than :value items.',
|
||||
'file' => 'The :attribute must be less than :value kilobytes.',
|
||||
'numeric' => 'The :attribute must be less than :value.',
|
||||
'string' => 'The :attribute must be less than :value characters.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'The :attribute must not have more than :value items.',
|
||||
'file' => 'The :attribute must be less than or equal to :value kilobytes.',
|
||||
'numeric' => 'The :attribute must be less than or equal to :value.',
|
||||
'string' => 'The :attribute must be less than or equal to :value characters.',
|
||||
],
|
||||
'mac_address' => 'The :attribute must be a valid MAC address.',
|
||||
'max' => [
|
||||
'array' => 'The :attribute must not have more than :max items.',
|
||||
'file' => 'The :attribute must not be greater than :max kilobytes.',
|
||||
'numeric' => 'The :attribute must not be greater than :max.',
|
||||
'string' => 'The :attribute must not be greater than :max characters.',
|
||||
],
|
||||
'max_digits' => 'The :attribute must not have more than :max digits.',
|
||||
'mimes' => 'The :attribute must be a file of type: :values.',
|
||||
'mimetypes' => 'The :attribute must be a file of type: :values.',
|
||||
'min' => [
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
'file' => 'The :attribute must be at least :min kilobytes.',
|
||||
'numeric' => 'The :attribute must be at least :min.',
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
],
|
||||
'min_digits' => 'The :attribute must have at least :min digits.',
|
||||
'multiple_of' => 'The :attribute must be a multiple of :value.',
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
'password' => [
|
||||
'letters' => 'The :attribute must contain at least one letter.',
|
||||
'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',
|
||||
'numbers' => 'The :attribute must contain at least one number.',
|
||||
'symbols' => 'The :attribute must contain at least one symbol.',
|
||||
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
|
||||
],
|
||||
'present' => 'The :attribute field must be present.',
|
||||
'prohibited' => 'The :attribute field is prohibited.',
|
||||
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
|
||||
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
|
||||
'prohibits' => 'The :attribute field prohibits :other from being present.',
|
||||
'regex' => 'The :attribute format is invalid.',
|
||||
'required' => 'The :attribute field is required.',
|
||||
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
|
||||
'required_if' => 'The :attribute field is required when :other is :value.',
|
||||
'required_if_accepted' => 'The :attribute field is required when :other is accepted.',
|
||||
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||
'required_with' => 'The :attribute field is required when :values is present.',
|
||||
'required_with_all' => 'The :attribute field is required when :values are present.',
|
||||
'required_without' => 'The :attribute field is required when :values is not present.',
|
||||
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
||||
'same' => 'The :attribute and :other must match.',
|
||||
'size' => [
|
||||
'array' => 'The :attribute must contain :size items.',
|
||||
'file' => 'The :attribute must be :size kilobytes.',
|
||||
'numeric' => 'The :attribute must be :size.',
|
||||
'string' => 'The :attribute must be :size characters.',
|
||||
],
|
||||
'starts_with' => 'The :attribute must start with one of the following: :values.',
|
||||
'string' => 'The :attribute must be a string.',
|
||||
'timezone' => 'The :attribute must be a valid timezone.',
|
||||
'unique' => 'The :attribute has already been taken.',
|
||||
'uploaded' => 'The :attribute failed to upload.',
|
||||
'url' => 'The :attribute must be a valid URL.',
|
||||
'uuid' => 'The :attribute must be a valid UUID.',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify custom validation messages for attributes using the
|
||||
| convention "attribute.rule" to name the lines. This makes it quick to
|
||||
| specify a specific custom language line for a given attribute rule.
|
||||
|
|
||||
*/
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Attributes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used to swap our attribute placeholder
|
||||
| with something more reader friendly such as "E-Mail Address" instead
|
||||
| of "email". This simply helps us make our message more expressive.
|
||||
|
|
||||
*/
|
||||
|
||||
'attributes' => [],
|
||||
|
||||
];
|
||||
4
lang/es.json
Normal file
4
lang/es.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"Female": "Femenino",
|
||||
"Male": "Masculino"
|
||||
}
|
||||
24
lang/es/auth.php
Normal file
24
lang/es/auth.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used during authentication for various
|
||||
| messages that we need to display to the user. You are free to modify
|
||||
| these language lines according to your application's requirements.
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => 'Estas credenciales no coinciden con nuestros registros.',
|
||||
'password' => 'The provided password is incorrect.',
|
||||
'throttle' => 'Demasiados intentos de acceso. Por favor inténtelo de nuevo en :seconds segundos.',
|
||||
'forgot' => [
|
||||
'subject' => 'Recuperación de contraseña',
|
||||
'line' => 'Por favor, haga clic en el siguiente enlace para restaurar su contraseña. El enlace expira en 15 minutos.',
|
||||
'button' => 'Restaurar contraseña',
|
||||
],
|
||||
];
|
||||
6
lang/es/cache.php
Normal file
6
lang/es/cache.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'no-cache' => ':label ":var" no existe en la cache',
|
||||
'save' => ':label ":var" guardado en la cache',
|
||||
];
|
||||
5
lang/es/login.php
Normal file
5
lang/es/login.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'required' => 'Es necesario autenticarse para continuar.'
|
||||
];
|
||||
19
lang/es/pagination.php
Normal file
19
lang/es/pagination.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pagination Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used by the paginator library to build
|
||||
| the simple pagination links. You are free to change them to anything
|
||||
| you want to customize your views to better match your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'previous' => '« Anterior',
|
||||
'next' => 'Siguiente »',
|
||||
|
||||
];
|
||||
24
lang/es/passwords.php
Normal file
24
lang/es/passwords.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are the default lines which match reasons
|
||||
| that are given by the password broker for a password update attempt
|
||||
| has failed, such as for an invalid token or invalid new password.
|
||||
|
|
||||
*/
|
||||
|
||||
'no_match' => 'La contraseña proporcionada no coincide con su contraseña actual.',
|
||||
'reset' => '¡Su contraseña ha sido restablecida!',
|
||||
'sent' => '¡Recordatorio de contraseña enviado!',
|
||||
'token' => 'Este token de restablecimiento de contraseña es inválido.',
|
||||
'user' => 'No se ha encontrado un usuario con esa dirección de correo.',
|
||||
'throttled' => 'Por favor espere antes de volver a intentarlo.',
|
||||
'password' => 'Las contraseñas deben tener al menos seis caracteres y coincidir con la confirmación.',
|
||||
'verify' => 'Si el correo :email existe, te enviaremos un correo con el token de recuperación.'
|
||||
];
|
||||
174
lang/es/validation.php
Normal file
174
lang/es/validation.php
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines contain the default error messages used by
|
||||
| the validator class. Some of these rules have multiple versions such
|
||||
| as the size rules. Feel free to tweak each of these messages here.
|
||||
|
|
||||
*/
|
||||
|
||||
'accepted' => 'El campo :attribute debe ser aceptado.',
|
||||
'active_url' => 'El campo :attribute no es una URL válida.',
|
||||
'after' => 'El campo :attribute debe ser una fecha posterior a :date.',
|
||||
'after_or_equal' => 'El campo :attribute debe ser una fecha posterior o igual a :date.',
|
||||
'alpha' => 'El campo :attribute solo puede contener letras.',
|
||||
'alpha_dash' => 'El campo :attribute solo puede contener letras, números, guiones y guiones bajos.',
|
||||
'alpha_num' => 'El campo :attribute solo puede contener letras y números.',
|
||||
'array' => 'El campo :attribute debe ser un array.',
|
||||
'before' => 'El campo :attribute debe ser una fecha anterior a :date.',
|
||||
'before_or_equal' => 'El campo :attribute debe ser una fecha anterior o igual a :date.',
|
||||
'between' => [
|
||||
'numeric' => 'El campo :attribute debe ser un valor entre :min y :max.',
|
||||
'file' => 'El archivo :attribute debe pesar entre :min y :max kilobytes.',
|
||||
'string' => 'El campo :attribute debe contener entre :min y :max caracteres.',
|
||||
'array' => 'El campo :attribute debe contener entre :min y :max elementos.',
|
||||
],
|
||||
'boolean' => 'El campo :attribute debe ser verdadero o falso.',
|
||||
'confirmed' => 'El campo confirmación de :attribute no coincide.',
|
||||
'current_password' => 'La contraseñas son diferentes',
|
||||
'date' => 'El campo :attribute no corresponde con una fecha válida.',
|
||||
'date_equals' => 'El campo :attribute debe ser una fecha igual a :date.',
|
||||
'date_format' => 'El campo :attribute no corresponde con el formato de fecha :format.',
|
||||
'different' => 'Los campos :attribute y :other deben ser diferentes.',
|
||||
'digits' => 'El campo :attribute debe ser un número de :digits dígitos.',
|
||||
'digits_between' => 'El campo :attribute debe contener entre :min y :max dígitos.',
|
||||
'dimensions' => 'El campo :attribute tiene dimensiones de imagen inválidas.',
|
||||
'distinct' => 'El campo :attribute tiene un valor duplicado.',
|
||||
'email' => 'El campo :attribute debe ser una dirección de correo válida.',
|
||||
'ends_with' => 'El campo :attribute debe finalizar con alguno de los siguientes valores: :values',
|
||||
'exists' => 'El campo :attribute seleccionado no existe.',
|
||||
'exist_section' => 'Este :attribute no existe.',
|
||||
'file' => 'El campo :attribute debe ser un archivo.',
|
||||
'filled' => 'El campo :attribute debe tener un valor.',
|
||||
'gt' => [
|
||||
'numeric' => 'El campo :attribute debe ser mayor a :value.',
|
||||
'file' => 'El archivo :attribute debe pesar más de :value kilobytes.',
|
||||
'string' => 'El campo :attribute debe contener más de :value caracteres.',
|
||||
'array' => 'El campo :attribute debe contener más de :value elementos.',
|
||||
],
|
||||
'gte' => [
|
||||
'numeric' => 'El campo :attribute debe ser mayor o igual a :value.',
|
||||
'file' => 'El archivo :attribute debe pesar :value o más kilobytes.',
|
||||
'string' => 'El campo :attribute debe contener :value o más caracteres.',
|
||||
'array' => 'El campo :attribute debe contener :value o más elementos.',
|
||||
],
|
||||
'image' => 'El campo :attribute debe ser una imagen.',
|
||||
'in' => 'El campo :attribute es inválido.',
|
||||
'in_array' => 'El campo :attribute no existe en :other.',
|
||||
'integer' => 'El campo :attribute debe ser un número entero.',
|
||||
'ip' => 'El campo :attribute debe ser una dirección IP válida.',
|
||||
'ipv4' => 'El campo :attribute debe ser una dirección IPv4 válida.',
|
||||
'ipv6' => 'El campo :attribute debe ser una dirección IPv6 válida.',
|
||||
'json' => 'El campo :attribute debe ser una cadena de texto JSON válida.',
|
||||
'lt' => [
|
||||
'numeric' => 'El campo :attribute debe ser menor a :value.',
|
||||
'file' => 'El archivo :attribute debe pesar menos de :value kilobytes.',
|
||||
'string' => 'El campo :attribute debe contener menos de :value caracteres.',
|
||||
'array' => 'El campo :attribute debe contener menos de :value elementos.',
|
||||
],
|
||||
'lte' => [
|
||||
'numeric' => 'El campo :attribute debe ser menor o igual a :value.',
|
||||
'file' => 'El archivo :attribute debe pesar :value o menos kilobytes.',
|
||||
'string' => 'El campo :attribute debe contener :value o menos caracteres.',
|
||||
'array' => 'El campo :attribute debe contener :value o menos elementos.',
|
||||
],
|
||||
'max' => [
|
||||
'numeric' => 'El campo :attribute no debe ser mayor a :max.',
|
||||
'file' => 'El archivo :attribute no debe pesar más de :max kilobytes.',
|
||||
'string' => 'El campo :attribute no debe contener más de :max caracteres.',
|
||||
'array' => 'El campo :attribute no debe contener más de :max elementos.',
|
||||
],
|
||||
'mimes' => 'El campo :attribute debe ser un archivo de tipo: :values.',
|
||||
'mimetypes' => 'El campo :attribute debe ser un archivo de tipo: :values.',
|
||||
'min' => [
|
||||
'numeric' => 'El campo :attribute debe ser al menos :min.',
|
||||
'file' => 'El archivo :attribute debe pesar al menos :min kilobytes.',
|
||||
'string' => 'El campo :attribute debe contener al menos :min caracteres.',
|
||||
'array' => 'El campo :attribute debe contener al menos :min elementos.',
|
||||
],
|
||||
'not_in' => 'El campo :attribute seleccionado es inválido.',
|
||||
'not_regex' => 'El formato del campo :attribute es inválido.',
|
||||
'numeric' => 'El campo :attribute debe ser un número.',
|
||||
'password' => 'La contraseña es incorrecta.',
|
||||
'present' => 'El campo :attribute debe estar presente.',
|
||||
'regex' => 'El formato del campo :attribute es inválido.',
|
||||
'required' => 'El campo :attribute es obligatorio.',
|
||||
'required_if' => 'El campo :attribute es obligatorio cuando el campo :other es :value.',
|
||||
'required_unless' => 'El campo :attribute es requerido a menos que :other se encuentre en :values.',
|
||||
'required_with' => 'El campo :attribute es obligatorio cuando :values está presente.',
|
||||
'required_with_all' => 'El campo :attribute es obligatorio cuando :values están presentes.',
|
||||
'required_without' => 'El campo :attribute es obligatorio cuando :values no está presente.',
|
||||
'required_without_all' => 'El campo :attribute es obligatorio cuando ninguno de los campos :values están presentes.',
|
||||
'same' => 'Los campos :attribute y :other deben coincidir.',
|
||||
'size' => [
|
||||
'numeric' => 'El campo :attribute debe ser :size.',
|
||||
'file' => 'El archivo :attribute debe pesar :size kilobytes.',
|
||||
'string' => 'El campo :attribute debe contener :size caracteres.',
|
||||
'array' => 'El campo :attribute debe contener :size elementos.',
|
||||
],
|
||||
'starts_with' => 'El campo :attribute debe comenzar con uno de los siguientes valores: :values',
|
||||
'string' => 'El campo :attribute debe ser una cadena de caracteres.',
|
||||
'timezone' => 'El campo :attribute debe ser una zona horaria válida.',
|
||||
'unique' => 'El valor del campo :attribute ya está en uso.',
|
||||
'uploaded' => 'El campo :attribute no se pudo subir.',
|
||||
'url' => 'El formato del campo :attribute es inválido.',
|
||||
'uuid' => 'El campo :attribute debe ser un UUID válido.',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify custom validation messages for attributes using the
|
||||
| convention "attribute.rule" to name the lines. This makes it quick to
|
||||
| specify a specific custom language line for a given attribute rule.
|
||||
|
|
||||
*/
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Attributes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used to swap attribute place-holders
|
||||
| with something more reader friendly such as E-Mail Address instead
|
||||
| of "email". This simply helps us make messages a little cleaner.
|
||||
|
|
||||
*/
|
||||
|
||||
'attributes' => [
|
||||
'barcode' => 'código de barras',
|
||||
'section.number' => 'sección',
|
||||
'name' => 'nombre',
|
||||
'paternal' => 'apellido paterno',
|
||||
'maternal' => 'apellido materno',
|
||||
'email' => 'correo',
|
||||
'phone' => 'teléfono',
|
||||
'type_ck' => 'tipo',
|
||||
'*.name' => 'nombre',
|
||||
'*.paternal' => 'apellido paterno',
|
||||
'*.maternal' => 'apellido materno',
|
||||
'*.email' => 'correo',
|
||||
'*.phone' => 'teléfono',
|
||||
'*.street' => 'calle',
|
||||
'*.inner_number' => 'número interior',
|
||||
'*.outer_number' => 'número exterior',
|
||||
'*.colony' => 'colonia',
|
||||
'*.zipcode' => 'código postal',
|
||||
'*.expiration' => 'vencimiento',
|
||||
'*.section' => 'sección',
|
||||
'*.voter_identifier' => 'clave de elector'
|
||||
],
|
||||
];
|
||||
2948
package-lock.json
generated
Normal file
2948
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,10 @@
|
||||
"autoprefixer": "^10.4.20",
|
||||
"axios": "^1.7.4",
|
||||
"concurrently": "^9.0.1",
|
||||
"laravel-echo": "^1.17.1",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"postcss": "^8.4.47",
|
||||
"pusher-js": "^8.4.0-rc2",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"vite": "^5.0"
|
||||
}
|
||||
|
||||
7
permission.sh
Executable file
7
permission.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
read -p "Usuario del sistema: " myuser
|
||||
|
||||
chown -R $myuser:www-data bootstrap/cache/ storage/
|
||||
chmod -R 775 bootstrap/cache/ storage/
|
||||
|
||||
echo "Done!"
|
||||
1
public/profile
Symbolic link
1
public/profile
Symbolic link
@ -0,0 +1 @@
|
||||
/var/www/notsoweb/holos.backend/storage/app/profile
|
||||
8
resources/js/bootstrap.js
vendored
8
resources/js/bootstrap.js
vendored
@ -2,3 +2,11 @@ import axios from 'axios';
|
||||
window.axios = axios;
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allow your team to quickly build robust real-time web applications.
|
||||
*/
|
||||
|
||||
import './echo';
|
||||
|
||||
14
resources/js/echo.js
Normal file
14
resources/js/echo.js
Normal file
@ -0,0 +1,14 @@
|
||||
import Echo from 'laravel-echo';
|
||||
|
||||
import Pusher from 'pusher-js';
|
||||
window.Pusher = Pusher;
|
||||
|
||||
window.Echo = new Echo({
|
||||
broadcaster: 'reverb',
|
||||
key: import.meta.env.VITE_REVERB_APP_KEY,
|
||||
wsHost: import.meta.env.VITE_REVERB_HOST,
|
||||
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
|
||||
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
|
||||
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
|
||||
enabledTransports: ['ws', 'wss'],
|
||||
});
|
||||
12
resources/views/mail/forgot-password-mail.blade.php
Normal file
12
resources/views/mail/forgot-password-mail.blade.php
Normal file
@ -0,0 +1,12 @@
|
||||
<x-mail::message>
|
||||
# Introduction
|
||||
|
||||
The body of your message.
|
||||
|
||||
<x-mail::button :url="''">
|
||||
Button Text
|
||||
</x-mail::button>
|
||||
|
||||
Thanks,<br>
|
||||
{{ config('app.name') }}
|
||||
</x-mail::message>
|
||||
10
resources/views/user/password-forgot.blade.php
Normal file
10
resources/views/user/password-forgot.blade.php
Normal file
@ -0,0 +1,10 @@
|
||||
<x-mail::message>
|
||||
{{ __('auth.forgot.line') }}
|
||||
|
||||
<x-mail::button :url="env('APP_FRONTEND_URL') . '/auth.html#/reset-password?code=12345234234'">
|
||||
{{ __('auth.forgot.button') }}
|
||||
</x-mail::button>
|
||||
|
||||
{{ __('thanks')}},<br>
|
||||
{{ config('app.name') }}
|
||||
</x-mail::message>
|
||||
24
resources/views/vendor/mail/html/button.blade.php
vendored
Normal file
24
resources/views/vendor/mail/html/button.blade.php
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
@props([
|
||||
'url',
|
||||
'color' => 'primary',
|
||||
'align' => 'center',
|
||||
])
|
||||
<table class="action" align="{{ $align }}" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr>
|
||||
<td align="{{ $align }}">
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr>
|
||||
<td align="{{ $align }}">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ $url }}" class="button button-{{ $color }}" target="_blank" rel="noopener">{{ $slot }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
11
resources/views/vendor/mail/html/footer.blade.php
vendored
Normal file
11
resources/views/vendor/mail/html/footer.blade.php
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<tr>
|
||||
<td>
|
||||
<table class="footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr>
|
||||
<td class="content-cell" align="center">
|
||||
{{ Illuminate\Mail\Markdown::parse($slot) }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
12
resources/views/vendor/mail/html/header.blade.php
vendored
Normal file
12
resources/views/vendor/mail/html/header.blade.php
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
@props(['url'])
|
||||
<tr>
|
||||
<td class="header">
|
||||
<a href="{{ $url }}" style="display: inline-block;">
|
||||
@if (trim($slot) === 'Laravel')
|
||||
<img src="https://laravel.com/img/notification-logo.png" class="logo" alt="Laravel Logo">
|
||||
@else
|
||||
{{ $slot }}
|
||||
@endif
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
58
resources/views/vendor/mail/html/layout.blade.php
vendored
Normal file
58
resources/views/vendor/mail/html/layout.blade.php
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>{{ config('app.name') }}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<meta name="color-scheme" content="light">
|
||||
<meta name="supported-color-schemes" content="light">
|
||||
<style>
|
||||
@media only screen and (max-width: 600px) {
|
||||
.inner-body {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
.button {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{{ $head ?? '' }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table class="wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table class="content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||
{{ $header ?? '' }}
|
||||
|
||||
<!-- Email Body -->
|
||||
<tr>
|
||||
<td class="body" width="100%" cellpadding="0" cellspacing="0" style="border: hidden !important;">
|
||||
<table class="inner-body" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<!-- Body content -->
|
||||
<tr>
|
||||
<td class="content-cell">
|
||||
{{ Illuminate\Mail\Markdown::parse($slot) }}
|
||||
|
||||
{{ $subcopy ?? '' }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{{ $footer ?? '' }}
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
27
resources/views/vendor/mail/html/message.blade.php
vendored
Normal file
27
resources/views/vendor/mail/html/message.blade.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<x-mail::layout>
|
||||
{{-- Header --}}
|
||||
<x-slot:header>
|
||||
<x-mail::header :url="config('app.url')">
|
||||
{{ config('app.name') }}
|
||||
</x-mail::header>
|
||||
</x-slot:header>
|
||||
|
||||
{{-- Body --}}
|
||||
{{ $slot }}
|
||||
|
||||
{{-- Subcopy --}}
|
||||
@isset($subcopy)
|
||||
<x-slot:subcopy>
|
||||
<x-mail::subcopy>
|
||||
{{ $subcopy }}
|
||||
</x-mail::subcopy>
|
||||
</x-slot:subcopy>
|
||||
@endisset
|
||||
|
||||
{{-- Footer --}}
|
||||
<x-slot:footer>
|
||||
<x-mail::footer>
|
||||
© {{ date('Y') }} {{ config('app.name') }}. {{ __('All rights reserved.') }}
|
||||
</x-mail::footer>
|
||||
</x-slot:footer>
|
||||
</x-mail::layout>
|
||||
14
resources/views/vendor/mail/html/panel.blade.php
vendored
Normal file
14
resources/views/vendor/mail/html/panel.blade.php
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<table class="panel" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr>
|
||||
<td class="panel-content">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr>
|
||||
<td class="panel-item">
|
||||
{{ Illuminate\Mail\Markdown::parse($slot) }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
7
resources/views/vendor/mail/html/subcopy.blade.php
vendored
Normal file
7
resources/views/vendor/mail/html/subcopy.blade.php
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
<table class="subcopy" width="100%" cellpadding="0" cellspacing="0" role="presentation">
|
||||
<tr>
|
||||
<td>
|
||||
{{ Illuminate\Mail\Markdown::parse($slot) }}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
3
resources/views/vendor/mail/html/table.blade.php
vendored
Normal file
3
resources/views/vendor/mail/html/table.blade.php
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="table">
|
||||
{{ Illuminate\Mail\Markdown::parse($slot) }}
|
||||
</div>
|
||||
291
resources/views/vendor/mail/html/themes/default.css
vendored
Normal file
291
resources/views/vendor/mail/html/themes/default.css
vendored
Normal file
@ -0,0 +1,291 @@
|
||||
/* Base */
|
||||
|
||||
body,
|
||||
body *:not(html):not(style):not(br):not(tr):not(code) {
|
||||
box-sizing: border-box;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
|
||||
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-text-size-adjust: none;
|
||||
background-color: #ffffff;
|
||||
color: #718096;
|
||||
height: 100%;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
p,
|
||||
ul,
|
||||
ol,
|
||||
blockquote {
|
||||
line-height: 1.4;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3869d4;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Typography */
|
||||
|
||||
h1 {
|
||||
color: #3d4852;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
line-height: 1.5em;
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p.sub {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
|
||||
.wrapper {
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
background-color: #edf2f7;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
.header {
|
||||
padding: 25px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header a {
|
||||
color: #3d4852;
|
||||
font-size: 19px;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Logo */
|
||||
|
||||
.logo {
|
||||
height: 75px;
|
||||
max-height: 75px;
|
||||
width: 75px;
|
||||
}
|
||||
|
||||
/* Body */
|
||||
|
||||
.body {
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
background-color: #edf2f7;
|
||||
border-bottom: 1px solid #edf2f7;
|
||||
border-top: 1px solid #edf2f7;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.inner-body {
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 570px;
|
||||
background-color: #ffffff;
|
||||
border-color: #e8e5ef;
|
||||
border-radius: 2px;
|
||||
border-width: 1px;
|
||||
box-shadow: 0 2px 0 rgba(0, 0, 150, 0.025), 2px 4px 0 rgba(0, 0, 150, 0.015);
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 570px;
|
||||
}
|
||||
|
||||
/* Subcopy */
|
||||
|
||||
.subcopy {
|
||||
border-top: 1px solid #e8e5ef;
|
||||
margin-top: 25px;
|
||||
padding-top: 25px;
|
||||
}
|
||||
|
||||
.subcopy p {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
|
||||
.footer {
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 570px;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
width: 570px;
|
||||
}
|
||||
|
||||
.footer p {
|
||||
color: #b0adc5;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #b0adc5;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
|
||||
.table table {
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
margin: 30px auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.table th {
|
||||
border-bottom: 1px solid #edeff2;
|
||||
margin: 0;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.table td {
|
||||
color: #74787e;
|
||||
font-size: 15px;
|
||||
line-height: 18px;
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.content-cell {
|
||||
max-width: 100vw;
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.action {
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
-premailer-width: 100%;
|
||||
margin: 30px auto;
|
||||
padding: 0;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
float: unset;
|
||||
}
|
||||
|
||||
.button {
|
||||
-webkit-text-size-adjust: none;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button-blue,
|
||||
.button-primary {
|
||||
background-color: #2d3748;
|
||||
border-bottom: 8px solid #2d3748;
|
||||
border-left: 18px solid #2d3748;
|
||||
border-right: 18px solid #2d3748;
|
||||
border-top: 8px solid #2d3748;
|
||||
}
|
||||
|
||||
.button-green,
|
||||
.button-success {
|
||||
background-color: #48bb78;
|
||||
border-bottom: 8px solid #48bb78;
|
||||
border-left: 18px solid #48bb78;
|
||||
border-right: 18px solid #48bb78;
|
||||
border-top: 8px solid #48bb78;
|
||||
}
|
||||
|
||||
.button-red,
|
||||
.button-error {
|
||||
background-color: #e53e3e;
|
||||
border-bottom: 8px solid #e53e3e;
|
||||
border-left: 18px solid #e53e3e;
|
||||
border-right: 18px solid #e53e3e;
|
||||
border-top: 8px solid #e53e3e;
|
||||
}
|
||||
|
||||
/* Panels */
|
||||
|
||||
.panel {
|
||||
border-left: #2d3748 solid 4px;
|
||||
margin: 21px 0;
|
||||
}
|
||||
|
||||
.panel-content {
|
||||
background-color: #edf2f7;
|
||||
color: #718096;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.panel-content p {
|
||||
color: #718096;
|
||||
}
|
||||
|
||||
.panel-item {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.panel-item p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
|
||||
.break-all {
|
||||
word-break: break-all;
|
||||
}
|
||||
1
resources/views/vendor/mail/text/button.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/button.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{ $slot }}: {{ $url }}
|
||||
1
resources/views/vendor/mail/text/footer.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/footer.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{ $slot }}
|
||||
1
resources/views/vendor/mail/text/header.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/header.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{ $slot }}: {{ $url }}
|
||||
9
resources/views/vendor/mail/text/layout.blade.php
vendored
Normal file
9
resources/views/vendor/mail/text/layout.blade.php
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{!! strip_tags($header ?? '') !!}
|
||||
|
||||
{!! strip_tags($slot) !!}
|
||||
@isset($subcopy)
|
||||
|
||||
{!! strip_tags($subcopy) !!}
|
||||
@endisset
|
||||
|
||||
{!! strip_tags($footer ?? '') !!}
|
||||
27
resources/views/vendor/mail/text/message.blade.php
vendored
Normal file
27
resources/views/vendor/mail/text/message.blade.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<x-mail::layout>
|
||||
{{-- Header --}}
|
||||
<x-slot:header>
|
||||
<x-mail::header :url="config('app.url')">
|
||||
{{ config('app.name') }}
|
||||
</x-mail::header>
|
||||
</x-slot:header>
|
||||
|
||||
{{-- Body --}}
|
||||
{{ $slot }}
|
||||
|
||||
{{-- Subcopy --}}
|
||||
@isset($subcopy)
|
||||
<x-slot:subcopy>
|
||||
<x-mail::subcopy>
|
||||
{{ $subcopy }}
|
||||
</x-mail::subcopy>
|
||||
</x-slot:subcopy>
|
||||
@endisset
|
||||
|
||||
{{-- Footer --}}
|
||||
<x-slot:footer>
|
||||
<x-mail::footer>
|
||||
© {{ date('Y') }} {{ config('app.name') }}. @lang('All rights reserved.')
|
||||
</x-mail::footer>
|
||||
</x-slot:footer>
|
||||
</x-mail::layout>
|
||||
1
resources/views/vendor/mail/text/panel.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/panel.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{ $slot }}
|
||||
1
resources/views/vendor/mail/text/subcopy.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/subcopy.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{ $slot }}
|
||||
1
resources/views/vendor/mail/text/table.blade.php
vendored
Normal file
1
resources/views/vendor/mail/text/table.blade.php
vendored
Normal file
@ -0,0 +1 @@
|
||||
{{ $slot }}
|
||||
58
resources/views/vendor/notifications/email.blade.php
vendored
Normal file
58
resources/views/vendor/notifications/email.blade.php
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
<x-mail::message>
|
||||
{{-- Greeting --}}
|
||||
@if (! empty($greeting))
|
||||
# {{ $greeting }}
|
||||
@else
|
||||
@if ($level === 'error')
|
||||
# @lang('Whoops!')
|
||||
@else
|
||||
# @lang('Hello!')
|
||||
@endif
|
||||
@endif
|
||||
|
||||
{{-- Intro Lines --}}
|
||||
@foreach ($introLines as $line)
|
||||
{{ $line }}
|
||||
|
||||
@endforeach
|
||||
|
||||
{{-- Action Button --}}
|
||||
@isset($actionText)
|
||||
<?php
|
||||
$color = match ($level) {
|
||||
'success', 'error' => $level,
|
||||
default => 'primary',
|
||||
};
|
||||
?>
|
||||
<x-mail::button :url="$actionUrl" :color="$color">
|
||||
{{ $actionText }}
|
||||
</x-mail::button>
|
||||
@endisset
|
||||
|
||||
{{-- Outro Lines --}}
|
||||
@foreach ($outroLines as $line)
|
||||
{{ $line }}
|
||||
|
||||
@endforeach
|
||||
|
||||
{{-- Salutation --}}
|
||||
@if (! empty($salutation))
|
||||
{{ $salutation }}
|
||||
@else
|
||||
@lang('Regards,')<br>
|
||||
{{ config('app.name') }}
|
||||
@endif
|
||||
|
||||
{{-- Subcopy --}}
|
||||
@isset($actionText)
|
||||
<x-slot:subcopy>
|
||||
@lang(
|
||||
"If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\n".
|
||||
'into your web browser:',
|
||||
[
|
||||
'actionText' => $actionText,
|
||||
]
|
||||
) <span class="break-all">[{{ $displayableActionUrl }}]({{ $actionUrl }})</span>
|
||||
</x-slot:subcopy>
|
||||
@endisset
|
||||
</x-mail::message>
|
||||
File diff suppressed because one or more lines are too long
64
routes/api.php
Normal file
64
routes/api.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\MyUserController;
|
||||
use App\Http\Controllers\System\LoginController;
|
||||
use App\Http\Controllers\System\NotificationController;
|
||||
use App\Http\Controllers\System\SystemController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
use Tighten\Ziggy\Ziggy;
|
||||
|
||||
Route::get('/', function () {
|
||||
return ApiResponse::OK->response([
|
||||
"message" => "It's fine :D"
|
||||
]);
|
||||
});
|
||||
|
||||
Route::name('api.')->group(function () {
|
||||
Route::get('/routes', function () {
|
||||
return (new Ziggy('api'))->toArray();
|
||||
})->name('routes');
|
||||
});
|
||||
|
||||
Route::middleware('auth:api')->group(function () {
|
||||
// Aplicación
|
||||
Route::prefix('user')->name('user.')->group(function() {
|
||||
Route::get('/', [MyUserController::class, 'show'])->name('show');
|
||||
Route::put('/', [MyUserController::class, 'update'])->name('update');
|
||||
Route::delete('/', [MyUserController::class, 'destroy'])->name('destroy');
|
||||
Route::delete('photo', [MyUserController::class, 'destroyPhoto'])->name('photo');
|
||||
Route::put('password', [MyUserController::class, 'updatePassword'])->name('password');
|
||||
Route::post('password-confirm', [MyUserController::class, 'confirmPassword'])->name('password-confirm');
|
||||
Route::get('permissions', [MyUserController::class, 'permissions'])->name('permissions');
|
||||
Route::get('roles', [MyUserController::class, 'roles'])->name('roles');
|
||||
});
|
||||
|
||||
Route::prefix('users')->name('users.')->group(function() {
|
||||
Route::prefix('{user}')->group(function() {
|
||||
Route::get('roles', [UserController::class, 'roles'])->name('roles');
|
||||
Route::put('roles', [UserController::class, 'updateRoles']);
|
||||
Route::put('password', [UserController::class, 'updatePassword'])->name('password');
|
||||
Route::get('permissions', [UserController::class, 'permissions'])->name('permissions');
|
||||
});
|
||||
});
|
||||
Route::apiResource('users', UserController::class);
|
||||
|
||||
// Sistema
|
||||
Route::prefix('system')->name('system.')->group(function() {
|
||||
Route::get('permissions', [SystemController::class, 'permissions'])->name('permissions');
|
||||
Route::get('roles', [SystemController::class, 'roles'])->name('roles');
|
||||
Route::prefix('notifications')->name('notifications.')->group(function() {
|
||||
Route::get('all-unread', [NotificationController::class, 'allUnread'])->name('all-unread');
|
||||
Route::post('read', [NotificationController::class, 'read'])->name('read');
|
||||
});
|
||||
});
|
||||
|
||||
Route::post('auth/logout', [LoginController::class, 'logout'])->name('auth.logout');
|
||||
});
|
||||
|
||||
Route::prefix('auth')->name('auth.')->group(function () {
|
||||
Route::post('login', [LoginController::class, 'login'])->name('login');
|
||||
Route::post('forgot-password', [LoginController::class, 'forgotPassword'])->name('forgot-password');
|
||||
Route::post('reset-password', [LoginController::class, 'resetPassword'])->name('reset-password');
|
||||
});
|
||||
9
routes/channels.php
Normal file
9
routes/channels.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php use Illuminate\Support\Facades\Broadcast;
|
||||
|
||||
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
|
||||
return (int) $user->id === (int) $id;
|
||||
});
|
||||
|
||||
Broadcast::channel('Global', function ($user) {
|
||||
return $user->id !== null;
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user