Skip to content

Commit

Permalink
Add web cron ability #821 (#1073)
Browse files Browse the repository at this point in the history
* Use database for kvp storage

* Read kvpstore

* Add web cron ability through API #821

* Style fixes

* Fix text
  • Loading branch information
nabeelio committed Mar 9, 2021
1 parent f1c54bc commit e70ee5a
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 3 deletions.
19 changes: 19 additions & 0 deletions app/Database/migrations/2021_03_05_044305_add_kvp_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

/**
* Add a hub to the subfleet is
*/
class AddKvpTable extends Migration
{
public function up()
{
Schema::create('kvp', function (Blueprint $table) {
$table->string('key')->index();
$table->string('value');
});
}
}
6 changes: 6 additions & 0 deletions app/Database/seeds/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,9 @@
options: ''
type: 'text'
description: 'Discord public channel ID for broadcasat notifications'
- key: 'cron.random_id'
name: 'Cron Randomized ID'
group: 'cron'
value: ''
type: 'hidden'
description: ''
37 changes: 37 additions & 0 deletions app/Exceptions/CronInvalid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace App\Exceptions;

class CronInvalid extends AbstractHttpException
{
public const MESSAGE = 'Cron ID is disabled or invalid';

public function __construct()
{
parent::__construct(400, static::MESSAGE);
}

/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'cron-invalid';
}

/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}

/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [];
}
}
35 changes: 35 additions & 0 deletions app/Http/Controllers/Admin/MaintenanceController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Repositories\KvpRepository;
use App\Services\CronService;
use App\Services\VersionService;
use App\Support\Utils;
use Codedge\Updater\UpdaterManager;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
Expand Down Expand Up @@ -34,7 +35,12 @@ public function __construct(

public function index()
{
// Get the cron URL
$cron_id = setting('cron.random_id');
$cron_url = empty($cron_id) ? 'Not enabled' : url(route('api.maintenance.cron', $cron_id));

return view('admin.maintenance.index', [
'cron_url' => $cron_url,
'cron_path' => $this->cronSvc->getCronExecString(),
'cron_problem_exists' => $this->cronSvc->cronProblemExists(),
'new_version' => $this->kvpRepo->get('new_version_available', false),
Expand Down Expand Up @@ -117,4 +123,33 @@ public function update(Request $request)

return redirect('/update/downloader');
}

/**
* Enable the cron, or if it's enabled, change the ID that is used
*
* @param Request $request
*/
public function cron_enable(Request $request)
{
$id = Utils::generateNewId(24);
setting_save('cron.random_id', $id);

Flash::success('Web cron refreshed!');
return redirect(route('admin.maintenance.index'));
}

/**
* Disable the web cron
*
* @param Request $request
*
* @return mixed
*/
public function cron_disable(Request $request)
{
setting_save('cron.random_id', '');

Flash::success('Web cron disabled!');
return redirect(route('admin.maintenance.index'));
}
}
2 changes: 1 addition & 1 deletion app/Http/Controllers/Admin/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private function getCurrencyList(): array
*/
public function index()
{
$settings = Setting::orderBy('order', 'asc')->get();
$settings = Setting::where('type', '!=', 'hidden')->orderBy('order')->get();
$settings = $settings->groupBy('group');

return view('admin.settings.index', [
Expand Down
1 change: 0 additions & 1 deletion app/Http/Controllers/Api/FlightController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use App\Contracts\Controller;
use App\Exceptions\AssetNotFound;
use App\Exceptions\Unauthorized;
use App\Http\Resources\Flight as FlightResource;
use App\Http\Resources\Navdata as NavdataResource;
use App\Models\SimBrief;
Expand Down
35 changes: 35 additions & 0 deletions app/Http/Controllers/Api/MaintenanceController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace App\Http\Controllers\Api;

use App\Contracts\Controller;
use App\Exceptions\CronInvalid;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;

class MaintenanceController extends Controller
{
/**
* Run the cron job from the web
*
* @param Request $request
* @param string $id The ID passed in for the cron
*
* @return mixed
*/
public function cron(Request $request, string $id)
{
$cron_id = setting('cron.random_id');
if (empty($cron_id) || $id !== $cron_id) {
throw new CronInvalid();
}

$output = '';
Artisan::call('schedule:run');
$output .= trim(Artisan::output());

return response([
'content' => $output,
]);
}
}
23 changes: 23 additions & 0 deletions app/Models/Kvp.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace App\Models;

use App\Contracts\Model;

/**
* @property string key
* @property string value
*/
class Kvp extends Model
{
public $table = 'kvp';
public $timestamps = false;
public $incrementing = false;

protected $keyType = 'string';

public $fillable = [
'key',
'value',
];
}
1 change: 1 addition & 0 deletions app/Models/SimBrief.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* @property int $user_id The user that generated this
* @property string $flight_id Optional, if attached to a flight, removed if attached to PIREP
* @property string $pirep_id Optional, if attached to a PIREP, removed if attached to flight
* @property string $aircraft_id The aircraft this is for
* @property string $acars_xml
* @property string $ofp_xml
* @property string $ofp_html
Expand Down
8 changes: 8 additions & 0 deletions app/Providers/RouteServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,12 @@ private function mapAdminRoutes()
Route::match(['post'], 'maintenance/forcecheck', 'MaintenanceController@forcecheck')
->name('maintenance.forcecheck')->middleware('ability:admin,maintenance');

Route::match(['post'], 'maintenance/cron_enable', 'MaintenanceController@cron_enable')
->name('maintenance.cron_enable')->middleware('ability:admin,maintenance');

Route::match(['post'], 'maintenance/cron_disable', 'MaintenanceController@cron_disable')
->name('maintenance.cron_disable')->middleware('ability:admin,maintenance');

// subfleet
Route::get('subfleets/export', 'SubfleetController@export')
->name('subfleets.export')->middleware('ability:admin,fleet');
Expand Down Expand Up @@ -508,6 +514,8 @@ private function mapApiRoutes()
Route::get('pireps/{pirep_id}', 'PirepController@get');
Route::get('pireps/{pirep_id}/acars/geojson', 'AcarsController@acars_geojson');

Route::get('cron/{id}', 'MaintenanceController@cron')->name('maintenance.cron');

Route::get('news', 'NewsController@index');
Route::get('status', 'StatusController@status');
Route::get('version', 'StatusController@status');
Expand Down
42 changes: 41 additions & 1 deletion resources/views/admin/maintenance/cron.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
</h6>
<div class="row" style="padding-top: 5px">
<div class="col-sm-12">
<p>A cron must be created that runs every minute calling artisan. Example:</p>
<p>A cron must be created that runs every minute calling artisan. An example is below.
<strong><a href="{{ docs_link('cron') }}" target="_blank">See the docs</a></strong></p>
<label style="width: 100%">
<input type="text" value="{{ $cron_path }}" class="form-control" style="width: 100%"/>
</label>
Expand All @@ -20,6 +21,45 @@
@endif
</div>
</div>

<hr>

<div class="row" style="padding-top: 5px">
<div class="col-sm-12">
<h5>Web Cron</h5>
</div>
<div class="col-sm-6">
<p>
If you don't have cron access on your server, you can use a web-cron service to
access this URL every minute. Keep it disabled if you're not using it. It's a
unique ID that can be reset/changed if needed for security.
</p>
</div>
<div class="col-sm-6 pull-right">
<table class="table-condensed">
<tr class="text-right">
<td style="padding-right: 10px;" class="text-right">
{{ Form::open(['url' => route('admin.maintenance.cron_enable'),
'method' => 'post']) }}
{{ Form::button('Enable/Change ID', ['type' => 'submit', 'class' => 'btn btn-success']) }}
{{ Form::close() }}
</td>
<td class="text-right">
{{ Form::open(['url' => route('admin.maintenance.cron_disable'),
'method' => 'post']) }}
{{ Form::button('Disable', ['type' => 'submit', 'class' => 'btn btn-warning']) }}
{{ Form::close() }}
</td>
</tr>
</table>
</div>
<div class="col-sm-12">

<label style="width: 100%">
<input type="text" value="{{ $cron_url }}" class="form-control" style="width: 100%"/>
</label>
</div>
</div>
</div>
</div>
</div>
18 changes: 18 additions & 0 deletions tests/ApiTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use App\Models\Subfleet;
use App\Models\User;
use App\Services\FareService;
use App\Support\Utils;
use Exception;
use function random_int;

Expand Down Expand Up @@ -312,4 +313,21 @@ public function testGetUser()
$this->assertNotNull($user);
$this->assertTrue(strpos($user['avatar'], 'gravatar') !== -1);
}

/**
* Test that the web cron runs
*/
public function testWebCron()
{
$this->updateSetting('cron.random_id', '');
$this->get('/api/cron/sdf')->assertStatus(400);

$id = Utils::generateNewId(24);
$this->updateSetting('cron.random_id', $id);

$this->get('/api/cron/sdf')->assertStatus(400);

$res = $this->get('/api/cron/'.$id);
$res->assertStatus(200);
}
}
19 changes: 19 additions & 0 deletions tests/UtilsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Tests;

use App\Repositories\KvpRepository;
use App\Support\ICAO;
use App\Support\Units\Time;
use App\Support\Utils;
Expand All @@ -15,6 +16,24 @@ public function testDates()
$this->assertNotNull($carbon);
}

/**
* Simple test for KVP
*/
public function testKvp()
{
/** @var KvpRepository $kvpRepo */
$kvpRepo = app(KvpRepository::class);
$kvpRepo->save('testkey', 'some value');
$this->assertEquals('some value', $kvpRepo->get('testkey'));

// test that default value is working
$this->assertEquals('default value', $kvpRepo->get('unknownkey', 'default value'));

// try saving an integer
$kvpRepo->save('intval', 1);
$this->assertEquals(1, $kvpRepo->get('intval'));
}

/**
* @throws \Exception
*/
Expand Down

0 comments on commit e70ee5a

Please sign in to comment.