* 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: ''
|
||||
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
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\Services\CronService;
|
||||
use App\Services\VersionService;
|
||||
use App\Support\Utils;
|
||||
use Codedge\Updater\UpdaterManager;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
@ -34,7 +35,12 @@ class MaintenanceController extends Controller
|
||||
|
||||
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),
|
||||
@ -117,4 +123,33 @@ class MaintenanceController extends Controller
|
||||
|
||||
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()
|
||||
{
|
||||
$settings = Setting::orderBy('order', 'asc')->get();
|
||||
$settings = Setting::where('type', '!=', 'hidden')->orderBy('order')->get();
|
||||
$settings = $settings->groupBy('group');
|
||||
|
||||
return view('admin.settings.index', [
|
||||
|
@ -4,7 +4,6 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
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;
|
||||
|
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 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
|
||||
|
@ -392,6 +392,12 @@ class RouteServiceProvider extends ServiceProvider
|
||||
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');
|
||||
@ -508,6 +514,8 @@ class RouteServiceProvider extends ServiceProvider
|
||||
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');
|
||||
|
@ -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>
|
||||
@ -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>
|
||||
|
@ -12,6 +12,7 @@ use App\Models\News;
|
||||
use App\Models\Subfleet;
|
||||
use App\Models\User;
|
||||
use App\Services\FareService;
|
||||
use App\Support\Utils;
|
||||
use Exception;
|
||||
use function random_int;
|
||||
|
||||
@ -312,4 +313,21 @@ class ApiTest extends TestCase
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Tests;
|
||||
|
||||
use App\Repositories\KvpRepository;
|
||||
use App\Support\ICAO;
|
||||
use App\Support\Units\Time;
|
||||
use App\Support\Utils;
|
||||
@ -15,6 +16,24 @@ class UtilsTest extends TestCase
|
||||
$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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user