Add admin job list and manual exec to admin

This commit is contained in:
Matteo Gheza 2024-01-12 15:56:24 +01:00
parent 3a4c475488
commit fc04e2dace
11 changed files with 142 additions and 14 deletions

View File

@ -5,9 +5,9 @@ namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use App\Jobs\NotifyUsersManualModeOn;
use App\Jobs\RemoveOldIpAddressesFromLogs;
use App\Jobs\ResetAvailabilityMinutes;
use App\Jobs\NotifyUsersManualModeOnJob;
use App\Jobs\RemoveOldIpAddressesFromLogsJob;
use App\Jobs\ResetAvailabilityMinutesJob;
use App\Jobs\UpdateAvailabilityWithSchedulesJob;
class Kernel extends ConsoleKernel
@ -17,13 +17,13 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule): void
{
$schedule->job(new NotifyUsersManualModeOn)
$schedule->job(new NotifyUsersManualModeOnJob)
->dailyAt('7:00');
//->sentryMonitor();
$schedule->job(new RemoveOldIpAddressesFromLogs)
$schedule->job(new RemoveOldIpAddressesFromLogsJob)
->dailyAt('0:30');
//->sentryMonitor();
$schedule->job(new ResetAvailabilityMinutes)
$schedule->job(new ResetAvailabilityMinutesJob)
->monthlyOn(1, '0:00');
//->sentryMonitor();
$schedule->job(new UpdateAvailabilityWithSchedulesJob)

View File

@ -94,6 +94,43 @@ class AdminController extends Controller
]);
}
public function getJobsList() {
if(!request()->user()->hasPermission("admin-maintenance-read")) abort(401);
$jobPath = app_path('Jobs');
$jobs = [];
$files = scandir($jobPath);
foreach ($files as $file) {
if (pathinfo($file, PATHINFO_EXTENSION) == 'php') {
$jobs[] = pathinfo($file, PATHINFO_FILENAME);
}
}
return response()->json($jobs);
}
public function runJob(Request $request) {
if(!request()->user()->hasPermission("admin-maintenance-update")) abort(401);
$request->validate([
'job' => 'required|string'
]);
Artisan::call('schedule:test', ['--name' => "App\\Jobs\\".$request->input('job')]);
$output = Artisan::output();
if(str_contains($output, 'No matching scheduled command found.')) {
return response()->json([
'message' => 'Job not found'
], 404);
}
return response()->json([
'message' => 'Job ran successfully'
]);
}
public function getMaintenanceMode() {
if(!request()->user()->hasPermission("admin-maintenance-read")) abort(401);

View File

@ -14,7 +14,7 @@ use DefStudio\Telegraph\Keyboard\Button;
use DefStudio\Telegraph\Keyboard\Keyboard;
use DefStudio\Telegraph\Facades\Telegraph;
class NotifyUsersManualModeOn implements ShouldQueue
class NotifyUsersManualModeOnJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

View File

@ -10,7 +10,7 @@ use Illuminate\Queue\SerializesModels;
use App\Models\Log;
use Carbon\Carbon;
class RemoveOldIpAddressesFromLogs implements ShouldQueue
class RemoveOldIpAddressesFromLogsJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

View File

@ -11,7 +11,7 @@ use Illuminate\Queue\SerializesModels;
use App\Models\User;
use App\Models\AvailabilityMinutesArchive;
class ResetAvailabilityMinutes implements ShouldQueue
class ResetAvailabilityMinutesJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

View File

@ -99,6 +99,9 @@ Route::middleware('auth:sanctum')->group( function () {
Route::post('/admin/runMigrations', [AdminController::class, 'runMigrations']);
Route::post('/admin/runSeeding', [AdminController::class, 'runSeeding']);
Route::get('/admin/jobs', [AdminController::class, 'getJobsList']);
Route::post('/admin/runJob', [AdminController::class, 'runJob']);
Route::get('/admin/maintenanceMode', [AdminController::class, 'getMaintenanceMode']);
Route::post('/admin/maintenanceMode', [AdminController::class, 'updateMaintenanceMode']);

View File

@ -2,7 +2,7 @@
<div class="row">
<div class="col-md-6 right-border">
<div class="row">
<h4>Database:</h4>
<h4>{{ 'admin.database'|translate|ftitlecase }}:</h4>
<div class="table-responsive ms-3 pe-5">
<table class="table table-striped table-bordered">
@ -66,8 +66,6 @@
<button type="button" class="btn btn-lg btn-danger" (click)="runSeeding()">{{ 'admin.run_seeding'|translate|ftitlecase }}</button>
</div>
<hr>
<div class="mb-2 ms-3 ps-5 pe-5" *ngIf="db && db.tables">
<button type="button" class="btn btn-primary" (click)="isTableListCollaped = !isTableListCollaped"
[attr.aria-expanded]="!isTableListCollaped" aria-controls="collapseBasic">
@ -94,6 +92,30 @@
</table>
</div>
</div>
<hr>
<div class="row">
<h4>{{ 'admin.operations'|translate|ftitlecase }}:</h4>
<div class="table-responsive ms-3 pe-5">
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>{{ 'name'|translate|ftitlecase }}</th>
<th>{{ 'admin.manual_execution'|translate|ftitlecase }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let job of jobs">
<td>{{ job }}</td>
<td (click)="runJob(job)" class="pointer text-center"
[ngClass]="{'text-bg-danger': ultraDangerousJobs.includes(job), 'text-bg-warning': dangerousJobs.includes(job)}">
<i class="fas fa-play"></i> {{ 'admin.run'|translate|ftitlecase }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">

View File

@ -12,6 +12,10 @@
animation: blink 2s linear infinite;
}
.pointer {
cursor: pointer;
}
.right-border {
border-right: #0000004a 1px solid
}

View File

@ -12,6 +12,15 @@ export class AdminMaintenanceComponent implements OnInit {
public db: any | undefined = undefined;
public isTableListCollaped = true;
public jobs: string[] = [];
//Hard-coded list of jobs that should not be run manually
public dangerousJobs: string[] = [
"NotifyUsersManualModeOnJob"
];
public ultraDangerousJobs: string[] = [
"ResetAvailabilityMinutesJob"
];
public isMaintenanceModeActive = false;
public telegramBotInfo: any | undefined = undefined;
@ -40,6 +49,19 @@ export class AdminMaintenanceComponent implements OnInit {
});
}
getJobs() {
this.api.get('admin/jobs').then((res: any) => {
this.jobs = res;
console.log(this.jobs);
}).catch((err: any) => {
Swal.fire({
icon: 'error',
title: this.translateService.instant('error_title'),
text: err.message
});
});
}
getMaintenanceMode() {
this.api.get('admin/maintenanceMode').then((res: any) => {
this.isMaintenanceModeActive = res.enabled;
@ -68,6 +90,7 @@ export class AdminMaintenanceComponent implements OnInit {
ngOnInit(): void {
this.getDB();
this.getJobs();
this.getMaintenanceMode();
this.getTelegramBotDebugInfo();
}
@ -118,6 +141,35 @@ export class AdminMaintenanceComponent implements OnInit {
});
}
runJob(job: string) {
//Require confirmation before proceeding
Swal.fire({
title: this.translateService.instant('admin.run_confirm_title'),
text: this.translateService.instant('admin.run_confirm_text'),
icon: 'warning',
showCancelButton: true,
confirmButtonText: this.translateService.instant('yes'),
cancelButtonText: this.translateService.instant('no')
}).then((result) => {
if (result.isConfirmed) {
this.api.post('admin/runJob', { job }).then((res: any) => {
Swal.fire({
icon: 'success',
title: this.translateService.instant('success_title'),
text: this.translateService.instant('admin.run_success')
});
this.getJobs();
}).catch((err: any) => {
Swal.fire({
icon: 'error',
title: this.translateService.instant('error_title'),
text: err.error.message
});
});
}
});
}
updateMaintenanceMode(enabled: boolean) {
this.api.post('admin/maintenanceMode', { enabled }).then((res: any) => {
this.isMaintenanceModeActive = enabled;

View File

@ -46,7 +46,12 @@
"telegram_webhook_set": "Set Telegram Webhook",
"telegram_webhook_set_success": "Telegram Webhook set successfully",
"telegram_webhook_unset": "Unset Telegram Webhook",
"telegram_webhook_unset_success": "Telegram Webhook unset successfully"
"telegram_webhook_unset_success": "Telegram Webhook unset successfully",
"manual_execution": "manual execution",
"run": "run",
"run_confirm_title": "Are you sure you want to run this command?",
"run_confirm_text": "This action cannot be undone.",
"run_success": "Command executed successfully"
},
"table": {
"yes_remove": "Yes, remove",

View File

@ -46,7 +46,12 @@
"telegram_webhook_set": "Imposta Webhook Telegram",
"telegram_webhook_set_success": "Webhook Telegram impostato con successo",
"telegram_webhook_unset": "Rimuovi Webhook Telegram",
"telegram_webhook_unset_success": "Webhook Telegram rimosso con successo"
"telegram_webhook_unset_success": "Webhook Telegram rimosso con successo",
"manual_execution": "esecuzione manuale",
"run": "esegui",
"run_confirm_title": "Sei sicuro di voler eseguire questo comando?",
"run_confirm_text": "Questa operazione non potrà essere annullata.",
"run_success": "Comando eseguito con successo"
},
"table": {
"yes_remove": "Si, rimuovi",