* Use database for kvp storage * Read kvpstore * Add web cron ability through API #821 * Style fixes * Fix text
This commit is contained in:
parent
f1c54bcc7c
commit
e70ee5aa6f
19
app/Database/migrations/2021_03_05_044305_add_kvp_table.php
Normal file
19
app/Database/migrations/2021_03_05_044305_add_kvp_table.php
Normal file
@ -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');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -361,3 +361,9 @@
|
|||||||
options: ''
|
options: ''
|
||||||
type: 'text'
|
type: 'text'
|
||||||
description: 'Discord public channel ID for broadcasat notifications'
|
description: 'Discord public channel ID for broadcasat notifications'
|
||||||
|
- key: 'cron.random_id'
|
||||||
|
name: 'Cron Randomized ID'
|
||||||
|
group: 'cron'
|
||||||
|
value: ''
|
||||||
|
type: 'hidden'
|
||||||
|
description: ''
|
||||||
|
37
app/Exceptions/CronInvalid.php
Normal file
37
app/Exceptions/CronInvalid.php
Normal file
@ -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 [];
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ use App\Contracts\Controller;
|
|||||||
use App\Repositories\KvpRepository;
|
use App\Repositories\KvpRepository;
|
||||||
use App\Services\CronService;
|
use App\Services\CronService;
|
||||||
use App\Services\VersionService;
|
use App\Services\VersionService;
|
||||||
|
use App\Support\Utils;
|
||||||
use Codedge\Updater\UpdaterManager;
|
use Codedge\Updater\UpdaterManager;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
@ -34,7 +35,12 @@ class MaintenanceController extends Controller
|
|||||||
|
|
||||||
public function index()
|
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', [
|
return view('admin.maintenance.index', [
|
||||||
|
'cron_url' => $cron_url,
|
||||||
'cron_path' => $this->cronSvc->getCronExecString(),
|
'cron_path' => $this->cronSvc->getCronExecString(),
|
||||||
'cron_problem_exists' => $this->cronSvc->cronProblemExists(),
|
'cron_problem_exists' => $this->cronSvc->cronProblemExists(),
|
||||||
'new_version' => $this->kvpRepo->get('new_version_available', false),
|
'new_version' => $this->kvpRepo->get('new_version_available', false),
|
||||||
@ -117,4 +123,33 @@ class MaintenanceController extends Controller
|
|||||||
|
|
||||||
return redirect('/update/downloader');
|
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'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ class SettingsController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$settings = Setting::orderBy('order', 'asc')->get();
|
$settings = Setting::where('type', '!=', 'hidden')->orderBy('order')->get();
|
||||||
$settings = $settings->groupBy('group');
|
$settings = $settings->groupBy('group');
|
||||||
|
|
||||||
return view('admin.settings.index', [
|
return view('admin.settings.index', [
|
||||||
|
@ -4,7 +4,6 @@ namespace App\Http\Controllers\Api;
|
|||||||
|
|
||||||
use App\Contracts\Controller;
|
use App\Contracts\Controller;
|
||||||
use App\Exceptions\AssetNotFound;
|
use App\Exceptions\AssetNotFound;
|
||||||
use App\Exceptions\Unauthorized;
|
|
||||||
use App\Http\Resources\Flight as FlightResource;
|
use App\Http\Resources\Flight as FlightResource;
|
||||||
use App\Http\Resources\Navdata as NavdataResource;
|
use App\Http\Resources\Navdata as NavdataResource;
|
||||||
use App\Models\SimBrief;
|
use App\Models\SimBrief;
|
||||||
|
35
app/Http/Controllers/Api/MaintenanceController.php
Normal file
35
app/Http/Controllers/Api/MaintenanceController.php
Normal file
@ -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
app/Models/Kvp.php
Normal file
23
app/Models/Kvp.php
Normal file
@ -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',
|
||||||
|
];
|
||||||
|
}
|
@ -10,6 +10,7 @@ use Illuminate\Support\Collection;
|
|||||||
* @property int $user_id The user that generated this
|
* @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 $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 $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 $acars_xml
|
||||||
* @property string $ofp_xml
|
* @property string $ofp_xml
|
||||||
* @property string $ofp_html
|
* @property string $ofp_html
|
||||||
|
@ -392,6 +392,12 @@ class RouteServiceProvider extends ServiceProvider
|
|||||||
Route::match(['post'], 'maintenance/forcecheck', 'MaintenanceController@forcecheck')
|
Route::match(['post'], 'maintenance/forcecheck', 'MaintenanceController@forcecheck')
|
||||||
->name('maintenance.forcecheck')->middleware('ability:admin,maintenance');
|
->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
|
// subfleet
|
||||||
Route::get('subfleets/export', 'SubfleetController@export')
|
Route::get('subfleets/export', 'SubfleetController@export')
|
||||||
->name('subfleets.export')->middleware('ability:admin,fleet');
|
->name('subfleets.export')->middleware('ability:admin,fleet');
|
||||||
@ -508,6 +514,8 @@ class RouteServiceProvider extends ServiceProvider
|
|||||||
Route::get('pireps/{pirep_id}', 'PirepController@get');
|
Route::get('pireps/{pirep_id}', 'PirepController@get');
|
||||||
Route::get('pireps/{pirep_id}/acars/geojson', 'AcarsController@acars_geojson');
|
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('news', 'NewsController@index');
|
||||||
Route::get('status', 'StatusController@status');
|
Route::get('status', 'StatusController@status');
|
||||||
Route::get('version', 'StatusController@status');
|
Route::get('version', 'StatusController@status');
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
</h6>
|
</h6>
|
||||||
<div class="row" style="padding-top: 5px">
|
<div class="row" style="padding-top: 5px">
|
||||||
<div class="col-sm-12">
|
<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%">
|
<label style="width: 100%">
|
||||||
<input type="text" value="{{ $cron_path }}" class="form-control" style="width: 100%"/>
|
<input type="text" value="{{ $cron_path }}" class="form-control" style="width: 100%"/>
|
||||||
</label>
|
</label>
|
||||||
@ -20,6 +21,45 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,6 +12,7 @@ use App\Models\News;
|
|||||||
use App\Models\Subfleet;
|
use App\Models\Subfleet;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\FareService;
|
use App\Services\FareService;
|
||||||
|
use App\Support\Utils;
|
||||||
use Exception;
|
use Exception;
|
||||||
use function random_int;
|
use function random_int;
|
||||||
|
|
||||||
@ -312,4 +313,21 @@ class ApiTest extends TestCase
|
|||||||
$this->assertNotNull($user);
|
$this->assertNotNull($user);
|
||||||
$this->assertTrue(strpos($user['avatar'], 'gravatar') !== -1);
|
$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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace Tests;
|
namespace Tests;
|
||||||
|
|
||||||
|
use App\Repositories\KvpRepository;
|
||||||
use App\Support\ICAO;
|
use App\Support\ICAO;
|
||||||
use App\Support\Units\Time;
|
use App\Support\Units\Time;
|
||||||
use App\Support\Utils;
|
use App\Support\Utils;
|
||||||
@ -15,6 +16,24 @@ class UtilsTest extends TestCase
|
|||||||
$this->assertNotNull($carbon);
|
$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
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user