Rutas del sistema y archivos de configuración
This commit is contained in:
+4
-4
@@ -65,7 +65,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'timezone' => 'UTC',
|
'timezone' => 'America/Argentina/Buenos_Aires',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -78,11 +78,11 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'locale' => env('APP_LOCALE', 'en'),
|
'locale' => env('APP_LOCALE', 'es'),
|
||||||
|
|
||||||
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
|
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'es'),
|
||||||
|
|
||||||
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
|
'faker_locale' => env('APP_FAKER_LOCALE', 'es_AR'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -0,0 +1,344 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
'backup' => [
|
||||||
|
/*
|
||||||
|
* The name of this application. You can use this name to monitor
|
||||||
|
* the backups.
|
||||||
|
*/
|
||||||
|
'name' => env('APP_NAME', 'AbogadasDelLitoral'),
|
||||||
|
|
||||||
|
'source' => [
|
||||||
|
'files' => [
|
||||||
|
/*
|
||||||
|
* The list of directories and files that will be included in the backup.
|
||||||
|
*/
|
||||||
|
'include' => array_values(array_filter([
|
||||||
|
storage_path('app/public/fotos'),
|
||||||
|
storage_path('app/private/documentacion-clientes'),
|
||||||
|
public_path('images/profesionales'),
|
||||||
|
public_path('images/servicios'),
|
||||||
|
public_path('images/bugs'),
|
||||||
|
public_path('uploads/documentacion-clientes'),
|
||||||
|
filter_var(env('BACKUP_INCLUDE_ENV', false), FILTER_VALIDATE_BOOLEAN) ? base_path('.env') : null,
|
||||||
|
], static fn (mixed $path): bool => is_string($path) && (is_dir($path) || is_file($path)))),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These directories and files will be excluded from the backup.
|
||||||
|
*
|
||||||
|
* Directories used by the backup process will automatically be excluded.
|
||||||
|
*/
|
||||||
|
'exclude' => [],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determines if symlinks should be followed.
|
||||||
|
*/
|
||||||
|
'follow_links' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determines if it should avoid unreadable folders.
|
||||||
|
*/
|
||||||
|
'ignore_unreadable_directories' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This path is used to make directories in resulting zip-file relative
|
||||||
|
* Set to `null` to include complete absolute path
|
||||||
|
* Example: base_path()
|
||||||
|
*/
|
||||||
|
'relative_path' => base_path(),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The names of the connections to the databases that should be backed up
|
||||||
|
* MySQL, PostgreSQL, SQLite and Mongo databases are supported.
|
||||||
|
*
|
||||||
|
* The content of the database dump may be customized for each connection
|
||||||
|
* by adding a 'dump' key to the connection settings in config/database.php.
|
||||||
|
* E.g.
|
||||||
|
* 'mysql' => [
|
||||||
|
* ...
|
||||||
|
* 'dump' => [
|
||||||
|
* 'exclude_tables' => [
|
||||||
|
* 'table_to_exclude_from_backup',
|
||||||
|
* 'another_table_to_exclude'
|
||||||
|
* ]
|
||||||
|
* ],
|
||||||
|
* ],
|
||||||
|
*
|
||||||
|
* If you are using only InnoDB tables on a MySQL server, you can
|
||||||
|
* also supply the useSingleTransaction option to avoid table locking.
|
||||||
|
*
|
||||||
|
* E.g.
|
||||||
|
* 'mysql' => [
|
||||||
|
* ...
|
||||||
|
* 'dump' => [
|
||||||
|
* 'useSingleTransaction' => true,
|
||||||
|
* ],
|
||||||
|
* ],
|
||||||
|
*
|
||||||
|
* For a complete list of available customization options, see https://github.com/spatie/db-dumper
|
||||||
|
*/
|
||||||
|
'databases' => [
|
||||||
|
env('DB_CONNECTION', 'mysql'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The database dump can be compressed to decrease disk space usage.
|
||||||
|
*
|
||||||
|
* Out of the box Laravel-backup supplies
|
||||||
|
* Spatie\DbDumper\Compressors\GzipCompressor::class.
|
||||||
|
*
|
||||||
|
* You can also create custom compressor. More info on that here:
|
||||||
|
* https://github.com/spatie/db-dumper#using-compression
|
||||||
|
*
|
||||||
|
* If you do not want any compressor at all, set it to null.
|
||||||
|
*/
|
||||||
|
'database_dump_compressor' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If specified, the database dumped file name will contain a timestamp (e.g.: 'Y-m-d-H-i-s').
|
||||||
|
*/
|
||||||
|
'database_dump_file_timestamp_format' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The base of the dump filename, either 'database' or 'connection'
|
||||||
|
*
|
||||||
|
* If 'database' (default), the dumped filename will contain the database name.
|
||||||
|
* If 'connection', the dumped filename will contain the connection name.
|
||||||
|
*/
|
||||||
|
'database_dump_filename_base' => 'database',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The file extension used for the database dump files.
|
||||||
|
*
|
||||||
|
* If not specified, the file extension will be .archive for MongoDB and .sql for all other databases
|
||||||
|
* The file extension should be specified without a leading .
|
||||||
|
*/
|
||||||
|
'database_dump_file_extension' => '',
|
||||||
|
|
||||||
|
'destination' => [
|
||||||
|
/*
|
||||||
|
* The compression algorithm to be used for creating the zip archive.
|
||||||
|
*
|
||||||
|
* If backing up only database, you may choose gzip compression for db dump and no compression at zip.
|
||||||
|
*
|
||||||
|
* Some common algorithms are listed below:
|
||||||
|
* ZipArchive::CM_STORE (no compression at all; set 0 as compression level)
|
||||||
|
* ZipArchive::CM_DEFAULT
|
||||||
|
* ZipArchive::CM_DEFLATE
|
||||||
|
* ZipArchive::CM_BZIP2
|
||||||
|
* ZipArchive::CM_XZ
|
||||||
|
*
|
||||||
|
* For more check https://www.php.net/manual/zip.constants.php and confirm it's supported by your system.
|
||||||
|
*/
|
||||||
|
'compression_method' => ZipArchive::CM_DEFAULT,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The compression level corresponding to the used algorithm; an integer between 0 and 9.
|
||||||
|
*
|
||||||
|
* Check supported levels for the chosen algorithm, usually 1 means the fastest and weakest compression,
|
||||||
|
* while 9 the slowest and strongest one.
|
||||||
|
*
|
||||||
|
* Setting of 0 for some algorithms may switch to the strongest compression.
|
||||||
|
*/
|
||||||
|
'compression_level' => 9,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The filename prefix used for the backup zip file.
|
||||||
|
*/
|
||||||
|
'filename_prefix' => '',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The disk names on which the backups will be stored.
|
||||||
|
*/
|
||||||
|
'disks' => [
|
||||||
|
...array_values(array_filter(array_map('trim', explode(',', env('BACKUP_DESTINATION_DISK', 'local'))))),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The directory where the temporary files will be stored.
|
||||||
|
*/
|
||||||
|
'temporary_directory' => storage_path('app/backup-temp'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The password to be used for archive encryption.
|
||||||
|
* Set to `null` to disable encryption.
|
||||||
|
*/
|
||||||
|
'password' => env('BACKUP_ARCHIVE_PASSWORD') ?: null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The encryption algorithm to be used for archive encryption.
|
||||||
|
* You can set it to `null` or `false` to disable encryption.
|
||||||
|
*
|
||||||
|
* When set to 'default', we'll use ZipArchive::EM_AES_256 if it is
|
||||||
|
* available on your system.
|
||||||
|
*/
|
||||||
|
'encryption' => env('BACKUP_ARCHIVE_PASSWORD') ? 'default' : false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of attempts, in case the backup command encounters an exception
|
||||||
|
*/
|
||||||
|
'tries' => 1,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of seconds to wait before attempting a new backup if the previous try failed
|
||||||
|
* Set to `0` for none
|
||||||
|
*/
|
||||||
|
'retry_delay' => 0,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can get notified when specific events occur. Out of the box you can use 'mail' and 'slack'.
|
||||||
|
* For Slack you need to install laravel/slack-notification-channel.
|
||||||
|
*
|
||||||
|
* You can also use your own notification classes, just make sure the class is named after one of
|
||||||
|
* the `Spatie\Backup\Notifications\Notifications` classes.
|
||||||
|
*/
|
||||||
|
'notifications' => [
|
||||||
|
'notifications' => [
|
||||||
|
\Spatie\Backup\Notifications\Notifications\BackupHasFailedNotification::class => ['mail'],
|
||||||
|
\Spatie\Backup\Notifications\Notifications\UnhealthyBackupWasFoundNotification::class => ['mail'],
|
||||||
|
\Spatie\Backup\Notifications\Notifications\CleanupHasFailedNotification::class => ['mail'],
|
||||||
|
\Spatie\Backup\Notifications\Notifications\BackupWasSuccessfulNotification::class => [],
|
||||||
|
\Spatie\Backup\Notifications\Notifications\HealthyBackupWasFoundNotification::class => [],
|
||||||
|
\Spatie\Backup\Notifications\Notifications\CleanupWasSuccessfulNotification::class => [],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Here you can specify the notifiable to which the notifications should be sent. The default
|
||||||
|
* notifiable will use the variables specified in this config file.
|
||||||
|
*/
|
||||||
|
'notifiable' => \Spatie\Backup\Notifications\Notifiable::class,
|
||||||
|
|
||||||
|
'mail' => [
|
||||||
|
'to' => env('BACKUP_MAIL_TO', env('MAIL_FROM_ADDRESS', 'admin@example.com')),
|
||||||
|
|
||||||
|
'from' => [
|
||||||
|
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
|
||||||
|
'name' => env('MAIL_FROM_NAME', 'Example'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'slack' => [
|
||||||
|
'webhook_url' => '',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is set to null the default channel of the webhook will be used.
|
||||||
|
*/
|
||||||
|
'channel' => null,
|
||||||
|
|
||||||
|
'username' => null,
|
||||||
|
|
||||||
|
'icon' => null,
|
||||||
|
],
|
||||||
|
|
||||||
|
'discord' => [
|
||||||
|
'webhook_url' => '',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is an empty string, the name field on the webhook will be used.
|
||||||
|
*/
|
||||||
|
'username' => '',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is an empty string, the avatar on the webhook will be used.
|
||||||
|
*/
|
||||||
|
'avatar_url' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Here you can specify which backups should be monitored.
|
||||||
|
* If a backup does not meet the specified requirements the
|
||||||
|
* UnHealthyBackupWasFound event will be fired.
|
||||||
|
*/
|
||||||
|
'monitor_backups' => [
|
||||||
|
[
|
||||||
|
'name' => env('APP_NAME', 'laravel-backup'),
|
||||||
|
'disks' => array_values(array_filter(array_map('trim', explode(',', env('BACKUP_DESTINATION_DISK', 'local'))))),
|
||||||
|
'health_checks' => [
|
||||||
|
\Spatie\Backup\Tasks\Monitor\HealthChecks\MaximumAgeInDays::class => (int) env('BACKUP_MAX_AGE_DAYS', 7),
|
||||||
|
\Spatie\Backup\Tasks\Monitor\HealthChecks\MaximumStorageInMegabytes::class => (int) env('BACKUP_MAX_STORAGE_MB', 5000),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
[
|
||||||
|
'name' => 'name of the second app',
|
||||||
|
'disks' => ['local', 's3'],
|
||||||
|
'health_checks' => [
|
||||||
|
\Spatie\Backup\Tasks\Monitor\HealthChecks\MaximumAgeInDays::class => 1,
|
||||||
|
\Spatie\Backup\Tasks\Monitor\HealthChecks\MaximumStorageInMegabytes::class => 5000,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
],
|
||||||
|
|
||||||
|
'cleanup' => [
|
||||||
|
/*
|
||||||
|
* The strategy that will be used to cleanup old backups. The default strategy
|
||||||
|
* will keep all backups for a certain amount of days. After that period only
|
||||||
|
* a daily backup will be kept. After that period only weekly backups will
|
||||||
|
* be kept and so on.
|
||||||
|
*
|
||||||
|
* No matter how you configure it the default strategy will never
|
||||||
|
* delete the newest backup.
|
||||||
|
*/
|
||||||
|
'strategy' => \Spatie\Backup\Tasks\Cleanup\Strategies\DefaultStrategy::class,
|
||||||
|
|
||||||
|
'default_strategy' => [
|
||||||
|
/*
|
||||||
|
* The number of days for which backups must be kept.
|
||||||
|
*/
|
||||||
|
'keep_all_backups_for_days' => (int) env('BACKUP_KEEP_ALL_DAYS', 7),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After the "keep_all_backups_for_days" period is over, the most recent backup
|
||||||
|
* of that day will be kept. Older backups within the same day will be removed.
|
||||||
|
* If you create backups only once a day, no backups will be removed yet.
|
||||||
|
*/
|
||||||
|
'keep_daily_backups_for_days' => (int) env('BACKUP_KEEP_DAILY_DAYS', 16),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After the "keep_daily_backups_for_days" period is over, the most recent backup
|
||||||
|
* of that week will be kept. Older backups within the same week will be removed.
|
||||||
|
* If you create backups only once a week, no backups will be removed yet.
|
||||||
|
*/
|
||||||
|
'keep_weekly_backups_for_weeks' => (int) env('BACKUP_KEEP_WEEKLY_WEEKS', 8),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After the "keep_weekly_backups_for_weeks" period is over, the most recent backup
|
||||||
|
* of that month will be kept. Older backups within the same month will be removed.
|
||||||
|
*/
|
||||||
|
'keep_monthly_backups_for_months' => (int) env('BACKUP_KEEP_MONTHLY_MONTHS', 4),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After the "keep_monthly_backups_for_months" period is over, the most recent backup
|
||||||
|
* of that year will be kept. Older backups within the same year will be removed.
|
||||||
|
*/
|
||||||
|
'keep_yearly_backups_for_years' => (int) env('BACKUP_KEEP_YEARLY_YEARS', 2),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After cleaning up the backups remove the oldest backup until
|
||||||
|
* this amount of megabytes has been reached.
|
||||||
|
* Set null for unlimited size.
|
||||||
|
*/
|
||||||
|
'delete_oldest_backups_when_using_more_megabytes_than' => (int) env('BACKUP_MAX_STORAGE_LIMIT_MB', 5000),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of attempts, in case the cleanup command encounters an exception
|
||||||
|
*/
|
||||||
|
'tries' => 1,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of seconds to wait before attempting a new cleanup if the previous try failed
|
||||||
|
* Set to `0` for none
|
||||||
|
*/
|
||||||
|
'retry_delay' => 0,
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
+8
-1
@@ -16,7 +16,7 @@ return [
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'default' => env('DB_CONNECTION', 'sqlite'),
|
'default' => env('DB_CONNECTION', 'mysql'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -60,7 +60,13 @@ return [
|
|||||||
'engine' => null,
|
'engine' => null,
|
||||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
(PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
|
(PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci',
|
||||||
]) : [],
|
]) : [],
|
||||||
|
'dump' => [
|
||||||
|
'dump_binary_path' => env('DB_DUMP_BINARY_PATH', PHP_OS_FAMILY === 'Windows' ? 'C:/xampp/mysql/bin/' : '/usr/bin/'),
|
||||||
|
'use_single_transaction' => true,
|
||||||
|
'timeout' => 60 * 5, // 5 minutos de tiempo límite
|
||||||
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
'mariadb' => [
|
'mariadb' => [
|
||||||
@@ -80,6 +86,7 @@ return [
|
|||||||
'engine' => null,
|
'engine' => null,
|
||||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||||
(PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
|
(PHP_VERSION_ID >= 80500 ? \Pdo\Mysql::ATTR_SSL_CA : \PDO::MYSQL_ATTR_SSL_CA) => env('MYSQL_ATTR_SSL_CA'),
|
||||||
|
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci',
|
||||||
]) : [],
|
]) : [],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -39,9 +39,9 @@ use App\Http\Controllers\UbicacionController;
|
|||||||
use App\Http\Controllers\UserController;
|
use App\Http\Controllers\UserController;
|
||||||
|
|
||||||
Route::middleware('api')->group(function () {
|
Route::middleware('api')->group(function () {
|
||||||
Route::post('auth/login/cliente', [AuthController::class, 'loginCliente']);
|
Route::post('auth/login/cliente', [AuthController::class, 'loginCliente'])->middleware('throttle:login-cliente-api');
|
||||||
Route::post('auth/login/personal', [AuthController::class, 'loginPersonal']);
|
Route::post('auth/login/personal', [AuthController::class, 'loginPersonal'])->middleware('throttle:login-personal-api');
|
||||||
Route::post('auth/login', [AuthController::class, 'login']);
|
Route::post('auth/login', [AuthController::class, 'login'])->middleware('throttle:login-api-general');
|
||||||
Route::post('auth/logout', [AuthController::class, 'logout']);
|
Route::post('auth/logout', [AuthController::class, 'logout']);
|
||||||
|
|
||||||
// Rutas API Resource estándar
|
// Rutas API Resource estándar
|
||||||
|
|||||||
@@ -1,8 +1,233 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Administrador;
|
||||||
|
use App\Models\Formulario;
|
||||||
|
use App\Models\LogSeguridad;
|
||||||
|
use Database\Seeders\BulkDataSeeder;
|
||||||
use Illuminate\Foundation\Inspiring;
|
use Illuminate\Foundation\Inspiring;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Illuminate\Support\Facades\Schedule;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
Artisan::command('inspire', function () {
|
Artisan::command('inspire', function () {
|
||||||
$this->comment(Inspiring::quote());
|
$this->comment(Inspiring::quote());
|
||||||
})->purpose('Display an inspiring quote');
|
})->purpose('Display an inspiring quote');
|
||||||
|
|
||||||
|
Artisan::command('logs:purge-old-security', function () {
|
||||||
|
$fechaLimite = now()->subMonths(2);
|
||||||
|
|
||||||
|
$eliminados = LogSeguridad::query()
|
||||||
|
->where('fechahora', '<', $fechaLimite)
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
$this->info('Logs eliminados: ' . $eliminados);
|
||||||
|
})->purpose('Elimina logs de seguridad con más de 2 meses de antigüedad');
|
||||||
|
|
||||||
|
Artisan::command('seed:bulk {--modo=masivo} {--clientes=} {--profesionales=} {--servicios=} {--profesiones=} {--fresh}', function () {
|
||||||
|
$presets = [
|
||||||
|
'rapido' => ['clientes' => 100, 'profesionales' => 20, 'servicios' => 10, 'profesiones' => 2],
|
||||||
|
'medio' => ['clientes' => 500, 'profesionales' => 50, 'servicios' => 20, 'profesiones' => 3],
|
||||||
|
'masivo' => ['clientes' => 1000, 'profesionales' => 100, 'servicios' => 30, 'profesiones' => 4],
|
||||||
|
];
|
||||||
|
|
||||||
|
$modo = strtolower((string) $this->option('modo'));
|
||||||
|
|
||||||
|
if (!array_key_exists($modo, $presets)) {
|
||||||
|
$this->error('Modo invalido. Usa: rapido, medio o masivo.');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clientes = max(0, (int) ($this->option('clientes') ?? $presets[$modo]['clientes']));
|
||||||
|
$profesionales = max(0, (int) ($this->option('profesionales') ?? $presets[$modo]['profesionales']));
|
||||||
|
$servicios = max(0, (int) ($this->option('servicios') ?? $presets[$modo]['servicios']));
|
||||||
|
$profesiones = max(0, (int) ($this->option('profesiones') ?? $presets[$modo]['profesiones']));
|
||||||
|
|
||||||
|
config([
|
||||||
|
'bulk_seed.enabled' => false,
|
||||||
|
'bulk_seed.clientes' => $clientes,
|
||||||
|
'bulk_seed.profesionales' => $profesionales,
|
||||||
|
'bulk_seed.servicios' => $servicios,
|
||||||
|
'bulk_seed.profesiones' => $profesiones,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ((bool) $this->option('fresh')) {
|
||||||
|
$this->info('Ejecutando migrate:fresh --seed...');
|
||||||
|
$exitMigrate = Artisan::call('migrate:fresh', ['--seed' => true]);
|
||||||
|
$this->line(Artisan::output());
|
||||||
|
|
||||||
|
if ($exitMigrate !== 0) {
|
||||||
|
$this->error('Fallo migrate:fresh --seed');
|
||||||
|
|
||||||
|
return $exitMigrate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info("Cargando datos masivos (modo={$modo})...");
|
||||||
|
$exitBulk = Artisan::call('db:seed', ['--class' => BulkDataSeeder::class]);
|
||||||
|
$this->line(Artisan::output());
|
||||||
|
|
||||||
|
if ($exitBulk !== 0) {
|
||||||
|
$this->error('Fallo la ejecucion de BulkDataSeeder.');
|
||||||
|
|
||||||
|
return $exitBulk;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info("Datos creados: {$profesiones} profesiones, {$servicios} servicios, {$clientes} clientes y {$profesionales} profesionales.");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
})->purpose('Carga datos de prueba masivos por modo o por cantidades personalizadas');
|
||||||
|
|
||||||
|
Artisan::command('formularios:sync-rejected-status', function () {
|
||||||
|
$formulariosPendientes = Formulario::query()
|
||||||
|
->where('estado', 'Pendiente')
|
||||||
|
->get(['id', 'profesion_id']);
|
||||||
|
|
||||||
|
$actualizados = 0;
|
||||||
|
|
||||||
|
foreach ($formulariosPendientes as $formulario) {
|
||||||
|
$formularioId = (int) $formulario->id;
|
||||||
|
$profesionFormularioId = (int) $formulario->profesion_id;
|
||||||
|
|
||||||
|
$asignadosActivos = DB::table('profesionales_formularios as pf')
|
||||||
|
->join('profesionales as p', 'p.id', '=', 'pf.profesional_id')
|
||||||
|
->where('pf.formulario_id', $formularioId)
|
||||||
|
->where('p.baja_id', 1)
|
||||||
|
->where(function ($query) use ($profesionFormularioId): void {
|
||||||
|
$query->where('p.profesion_id', $profesionFormularioId)
|
||||||
|
->orWhereExists(function ($subquery) use ($profesionFormularioId): void {
|
||||||
|
$subquery->select(DB::raw(1))
|
||||||
|
->from('profesionales_profesiones as pp')
|
||||||
|
->whereColumn('pp.profesional_id', 'p.id')
|
||||||
|
->where('pp.profesion_id', $profesionFormularioId);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->count();
|
||||||
|
|
||||||
|
if ($asignadosActivos === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hayActivosSinRechazar = DB::table('profesionales_formularios as pf')
|
||||||
|
->join('profesionales as p', 'p.id', '=', 'pf.profesional_id')
|
||||||
|
->where('pf.formulario_id', $formularioId)
|
||||||
|
->where('p.baja_id', 1)
|
||||||
|
->where(function ($query) use ($profesionFormularioId): void {
|
||||||
|
$query->where('p.profesion_id', $profesionFormularioId)
|
||||||
|
->orWhereExists(function ($subquery) use ($profesionFormularioId): void {
|
||||||
|
$subquery->select(DB::raw(1))
|
||||||
|
->from('profesionales_profesiones as pp')
|
||||||
|
->whereColumn('pp.profesional_id', 'p.id')
|
||||||
|
->where('pp.profesion_id', $profesionFormularioId);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
->whereRaw("LOWER(TRIM(pf.estado)) <> 'rechazado'")
|
||||||
|
->exists();
|
||||||
|
|
||||||
|
if (!$hayActivosSinRechazar) {
|
||||||
|
Formulario::query()
|
||||||
|
->where('id', $formularioId)
|
||||||
|
->update(['estado' => 'Rechazado por todos']);
|
||||||
|
|
||||||
|
$actualizados++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Formularios actualizados: ' . $actualizados);
|
||||||
|
})->purpose('Sincroniza formularios pendientes a Rechazado por todos cuando todos los profesionales activos rechazaron');
|
||||||
|
|
||||||
|
Artisan::command('backup:daily-email {--keep=4}', function () {
|
||||||
|
$includeEnv = (bool) filter_var((string) env('BACKUP_INCLUDE_ENV', false), FILTER_VALIDATE_BOOLEAN);
|
||||||
|
$archivePassword = trim((string) env('BACKUP_ARCHIVE_PASSWORD', ''));
|
||||||
|
|
||||||
|
if ($includeEnv && $archivePassword === '') {
|
||||||
|
$this->error('BACKUP_INCLUDE_ENV=true requiere BACKUP_ARCHIVE_PASSWORD configurado para cifrar el ZIP.');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Iniciando backup semanal de base de datos y archivos...');
|
||||||
|
|
||||||
|
$backupExitCode = Artisan::call('backup:run');
|
||||||
|
$this->line(Artisan::output());
|
||||||
|
|
||||||
|
if ($backupExitCode !== 0) {
|
||||||
|
$this->error('No se pudo generar el backup.');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$disk = Storage::disk('local');
|
||||||
|
$backupFolder = trim((string) config('backup.backup.name', 'Laravel'), '/');
|
||||||
|
|
||||||
|
$files = collect($disk->files($backupFolder))
|
||||||
|
->filter(fn (string $file): bool => str_ends_with(strtolower($file), '.zip'))
|
||||||
|
->sortByDesc(fn (string $file): int => $disk->lastModified($file))
|
||||||
|
->values();
|
||||||
|
|
||||||
|
if ($files->isEmpty()) {
|
||||||
|
$this->error('No se encontró el archivo ZIP del backup para enviar por email.');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$latestBackup = (string) $files->first();
|
||||||
|
|
||||||
|
$adminRecipients = Administrador::query()
|
||||||
|
->select('correo')
|
||||||
|
->whereNotNull('correo')
|
||||||
|
->pluck('correo')
|
||||||
|
->map(fn ($correo): string => trim((string) $correo))
|
||||||
|
->filter(fn (string $correo): bool => $correo !== '' && filter_var($correo, FILTER_VALIDATE_EMAIL) !== false)
|
||||||
|
->unique()
|
||||||
|
->values()
|
||||||
|
->all();
|
||||||
|
|
||||||
|
$fallbackRecipient = (string) env('BACKUP_MAIL_TO', (string) config('backup.notifications.mail.to'));
|
||||||
|
$recipients = !empty($adminRecipients)
|
||||||
|
? $adminRecipients
|
||||||
|
: array_values(array_filter([(string) $fallbackRecipient]));
|
||||||
|
|
||||||
|
if (empty($recipients)) {
|
||||||
|
$this->error('No hay correos de administradores ni BACKUP_MAIL_TO configurado para enviar el backup.');
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Mail::raw('Se adjunta el backup semanal de base de datos y archivos.', function ($message) use ($disk, $latestBackup, $recipients): void {
|
||||||
|
$message->to($recipients)
|
||||||
|
->subject('Backup semanal - ' . now()->format('d/m/Y'))
|
||||||
|
->attachData(
|
||||||
|
$disk->get($latestBackup),
|
||||||
|
basename($latestBackup),
|
||||||
|
['mime' => 'application/zip']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->error('El backup se generó, pero falló el envío de email: ' . $e->getMessage());
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$keep = max(1, (int) $this->option('keep'));
|
||||||
|
|
||||||
|
$files->slice($keep)->each(function (string $file) use ($disk): void {
|
||||||
|
$disk->delete($file);
|
||||||
|
});
|
||||||
|
|
||||||
|
$deletedCount = max(0, $files->count() - $keep);
|
||||||
|
|
||||||
|
$this->info('Backup enviado a: ' . implode(', ', $recipients));
|
||||||
|
$this->info('Backups eliminados por retención: ' . $deletedCount);
|
||||||
|
$this->info('Backups conservados: ' . $keep);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
})->purpose('Genera backup semanal de BD y archivos, lo envía por mail y conserva solo los últimos N backups');
|
||||||
|
|
||||||
|
Schedule::command('logs:purge-old-security')->daily();
|
||||||
|
Schedule::command('backup:daily-email --keep=4')->dailyAt('16:00'); //ejecuta backup:run
|
||||||
|
Schedule::command('backup:clean')->dailyAt('16:20');
|
||||||
|
Schedule::command('backup:monitor')->dailyAt('16:30');
|
||||||
|
|||||||
+6273
-6
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user