Compare commits

...
Author SHA1 Message Date
snyk-bot af9cba4a5f fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-ANSIHTML-1296849
2022-03-13 18:17:55 +00:00
B.Fatih KOZ 00bf18c225 Fix Cron Deleting Paused Pireps (#1434) 2022-03-07 09:55:30 -05:00
Toni VicenteandNabeel S b81dd97822 Changed es directory es by es-es (#1421)
This structure will allow for other variants derived from the Spanish of Spain.

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2022-02-28 13:34:01 -05:00
B.Fatih KOZ 7a40a9d128 Add DRAFT state in conditional check (#1422)
Add DRAFT state in conditional check
2022-02-28 09:52:57 -05:00
B.Fatih KOZ 9d368e8efa Allow bids on same flight by multiple users
Dash out unnecessary check, let multiple users to bid on same flight according to settings.
2022-02-25 14:40:53 -05:00
Toni Vicente 219a7cf6f9 fixed incorrect translation & Make TOC only readeable (#1408)
* fixed incorrect translation

Bloque de combustible -> Combustible en calzos

* Make TOC only redeable

make toc only readable for the user
2022-02-22 09:35:21 -05:00
Nabeel Shahzad 54bc5ccb30 Update example cron path to point to bin/cron 2022-02-21 10:36:54 -05:00
Nabeel Shahzad 648659aea5 Check if PIREP doesn't exist before cancelling 2022-02-16 19:13:47 -05:00
B.Fatih KOZ 08f82f8a2e Admin and Discord Notification Improvements (#1407)
* Backend changes

Sorting for : Airlines, Subfleets, Type Ratings and exported Flights

Blade : Added WYSIWYG editor to flight remarks/notes field

Notifications :

Mails > Added enabled/disabled settings for mails. Discord > Dashed out PirepPreFiled, re-enabled PirepStatusChanged with reduced messages

* Update PirepStatusChanged.php

* Update NotificationEventsHandler.php

* in_array fix

* Fix Discord Notifications

* Discord Notifications

Removed the pirep url from message as it is mostly private at phpvms side.

Also removed the Flight Ident from fields 'cause it is being used in the title.

Added the user avatar as thumbnail, and pirep filed message uses the airline logo as the main image.

Even though the outgoing pirep status messages are reduced, it is still possible to enable/disable them from admin settings.

Pirep Filed is always being sent (if the webhook is defined)

* StyleFix
2022-02-14 16:24:22 -05:00
Nabeel Shahzad 60cec870f6 Add aircraft ident to API response 2022-02-14 12:53:12 -05:00
Nabeel S 78fd8367a1 Add separate cron runner that doesn't use proc_open (#1405)
* Add alternative to using the artisan schedule runner

* StyleCI fixes

* Add additional cron time periods

* Style fixes

* Typo

* Update the web cron to use the new system

* Write out JSON for which tasks were run

* Rename cron.php to just cron
2022-02-11 16:24:06 -05:00
B.Fatih KOZ 607ea6f5e5 Add Notes to Users (#1406)
* Fix migration

Add Notes

* Migration to add mediumtext field
* Model update
* Admin blade update

* Hide notes by default

* Fix fields layout
2022-02-11 15:58:16 -05:00
66 changed files with 955 additions and 376 deletions
+5 -1
View File
@@ -22,7 +22,11 @@ class ProcessQueue extends Command
'--stop-when-empty' => null,
]);
Log::info(Artisan::output());
$jobOutput = trim(Artisan::output());
if (!empty($jobOutput)) {
Log::info($jobOutput);
}
///** @var App\Support\WorkCommand $queueWorker */
//$queueWorker = new App\Support\WorkCommand(app('queue.worker'), app('cache.store'));
+90
View File
@@ -0,0 +1,90 @@
<?php
/**
* This runs any of the cron tasks that are set to run according to the Laravel schedule
*/
namespace App\Console;
use App\Console\Cron\FifteenMinute;
use App\Console\Cron\FiveMinute;
use App\Console\Cron\Hourly;
use App\Console\Cron\JobQueue;
use App\Console\Cron\Monthly;
use App\Console\Cron\Nightly;
use App\Console\Cron\ThirtyMinute;
use App\Console\Cron\Weekly;
use App\Contracts\Command;
use Illuminate\Console\Scheduling\Schedule;
class Cron
{
/** @var Schedule */
private $scheduler;
/**
* @var string[] The cron tasks which get called/run
*/
private $cronTasks = [
JobQueue::class,
FiveMinute::class,
FifteenMinute::class,
ThirtyMinute::class,
Hourly::class,
Nightly::class,
Weekly::class,
Monthly::class,
];
/**
* @var array Stores the instantiated cron tasks
*/
private $cronRunners = [];
/**
* @param Schedule $scheduler
*/
public function __construct(Schedule $scheduler)
{
$this->scheduler = $scheduler;
foreach ($this->cronTasks as $task) {
/** @var Command $cronTask */
$cronTask = app($task);
$signature = $cronTask->getSignature();
if (empty($signature)) {
continue;
}
$this->cronRunners[$signature] = $cronTask;
}
}
/**
* Try to figure out which commands are supposed to run right now
*
* @return array string of tasks that were run
*/
public function run(): array
{
$events = $this->scheduler->dueEvents(app());
if (empty($events)) {
return [];
}
$run = [];
/** @var \Illuminate\Console\Scheduling\Event $event */
foreach ($events as $event) {
foreach ($this->cronRunners as $signature => $task) {
if (!str_contains($event->command, $signature)) {
continue;
}
$task->callEvent();
$run[] = $signature;
}
}
return $run;
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Console\Cron;
use App\Contracts\CronCommand;
use App\Events\CronFifteenMinute;
/**
* The actual cron tasks are in app/Cron
*/
class FifteenMinute extends CronCommand
{
protected $signature = 'cron:fifteen';
protected $description = 'Run the 15 minute cron tasks';
protected $schedule;
public function handle(): void
{
$this->callEvent();
}
public function callEvent()
{
event(new CronFifteenMinute());
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace App\Console\Cron;
use App\Contracts\CronCommand;
use App\Events\CronFiveMinute;
/**
* This just calls the CronNightly event, so all of the
* listeners, etc can just be called to run those tasks
*
* The actual cron tasks are in app/Cron
*/
class FiveMinute extends CronCommand
{
protected $signature = 'cron:five';
protected $description = 'Run the 5 minute cron tasks';
protected $schedule;
public function handle(): void
{
$this->callEvent();
}
public function callEvent()
{
event(new CronFiveMinute());
}
}
+7 -3
View File
@@ -2,14 +2,14 @@
namespace App\Console\Cron;
use App\Contracts\Command;
use App\Contracts\CronCommand;
use App\Events\CronHourly;
/**
* This just calls the CronHourly event, so all of the
* listeners, etc can just be called to run those tasks
*/
class Hourly extends Command
class Hourly extends CronCommand
{
protected $signature = 'cron:hourly';
protected $description = 'Run the hourly cron tasks';
@@ -17,7 +17,11 @@ class Hourly extends Command
public function handle(): void
{
$this->redirectLoggingToFile('cron');
$this->callEvent();
}
public function callEvent()
{
event(new CronHourly());
}
}
+12 -5
View File
@@ -2,14 +2,14 @@
namespace App\Console\Cron;
use App\Contracts\Command;
use App\Contracts\CronCommand;
use Illuminate\Support\Facades\Artisan;
/**
* This just calls the CronHourly event, so all of the
* listeners, etc can just be called to run those tasks
*/
class JobQueue extends Command
class JobQueue extends CronCommand
{
protected $signature = 'cron:queue';
protected $description = 'Run the cron queue tasks';
@@ -17,9 +17,16 @@ class JobQueue extends Command
public function handle(): void
{
$this->redirectLoggingToFile('cron');
Artisan::call('queue:cron');
$this->callEvent();
$this->info(Artisan::output());
$queueOutput = trim(Artisan::output());
if (!empty($queueOutput)) {
$this->info($queueOutput);
}
}
public function callEvent()
{
Artisan::call('queue:cron');
}
}
+7 -3
View File
@@ -2,7 +2,7 @@
namespace App\Console\Cron;
use App\Contracts\Command;
use App\Contracts\CronCommand;
use App\Events\CronMonthly;
/**
@@ -11,7 +11,7 @@ use App\Events\CronMonthly;
*
* The actual cron tasks are in app/Cron
*/
class Monthly extends Command
class Monthly extends CronCommand
{
protected $signature = 'cron:monthly';
protected $description = 'Run the monthly cron tasks';
@@ -19,7 +19,11 @@ class Monthly extends Command
public function handle(): void
{
$this->redirectLoggingToFile('cron');
$this->callEvent();
}
public function callEvent()
{
event(new CronMonthly());
}
}
+7 -3
View File
@@ -2,7 +2,7 @@
namespace App\Console\Cron;
use App\Contracts\Command;
use App\Contracts\CronCommand;
use App\Events\CronNightly;
/**
@@ -11,7 +11,7 @@ use App\Events\CronNightly;
*
* The actual cron tasks are in app/Cron
*/
class Nightly extends Command
class Nightly extends CronCommand
{
protected $signature = 'cron:nightly';
protected $description = 'Run the nightly cron tasks';
@@ -19,7 +19,11 @@ class Nightly extends Command
public function handle(): void
{
$this->redirectLoggingToFile('cron');
$this->callEvent();
}
public function callEvent()
{
event(new CronNightly());
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Console\Cron;
use App\Contracts\CronCommand;
use App\Events\CronThirtyMinute;
/**
* The actual cron tasks are in app/Cron
*/
class ThirtyMinute extends CronCommand
{
protected $signature = 'cron:thirty';
protected $description = 'Run the 30 minute cron tasks';
protected $schedule;
public function handle(): void
{
$this->callEvent();
}
public function callEvent()
{
event(new CronThirtyMinute());
}
}
+7 -3
View File
@@ -2,7 +2,7 @@
namespace App\Console\Cron;
use App\Contracts\Command;
use App\Contracts\CronCommand;
use App\Events\CronWeekly;
/**
@@ -11,7 +11,7 @@ use App\Events\CronWeekly;
*
* The actual cron tasks are in app/Cron
*/
class Weekly extends Command
class Weekly extends CronCommand
{
protected $signature = 'cron:weekly';
protected $description = 'Run the weekly cron tasks';
@@ -19,7 +19,11 @@ class Weekly extends Command
public function handle(): void
{
$this->redirectLoggingToFile('cron');
$this->callEvent();
}
public function callEvent()
{
event(new CronWeekly());
}
}
+10 -1
View File
@@ -2,10 +2,13 @@
namespace App\Console;
use App\Console\Cron\FifteenMinute;
use App\Console\Cron\FiveMinute;
use App\Console\Cron\Hourly;
use App\Console\Cron\JobQueue;
use App\Console\Cron\Monthly;
use App\Console\Cron\Nightly;
use App\Console\Cron\ThirtyMinute;
use App\Console\Cron\Weekly;
use App\Services\CronService;
use Illuminate\Console\Scheduling\Schedule;
@@ -33,10 +36,16 @@ class Kernel extends ConsoleKernel
->withoutOverlapping();
}
/*
* NOTE: IF MORE TASKS ARE ADDED, THEY ALSO MUST BE ADDED TO THE CRON.PHP
*/
$schedule->command(FiveMinute::class)->everyFiveMinutes();
$schedule->command(FifteenMinute::class)->everyFifteenMinutes();
$schedule->command(ThirtyMinute::class)->everyThirtyMinutes();
$schedule->command(Nightly::class)->dailyAt('01:00');
$schedule->command(Hourly::class)->hourly();
$schedule->command(Weekly::class)->weeklyOn(0);
$schedule->command(Monthly::class)->monthlyOn(1);
$schedule->command(Hourly::class)->hourly();
// When spatie-backups runs
/*if (config('backup.backup.enabled', false) === true) {
+10
View File
@@ -29,6 +29,16 @@ abstract class Command extends \Illuminate\Console\Command
}*/
}
/**
* Return the signature of the command
*
* @return string
*/
public function getSignature(): string
{
return $this->signature;
}
/**
* Splice the logger and replace the active handlers with the handlers from the
* a stack in config/logging.php
+5 -4
View File
@@ -87,16 +87,17 @@ abstract class Controller extends \Illuminate\Routing\Controller
*
* @return \Illuminate\Http\JsonResponse
*/
public function message($message, $count = null)
public function message($message, $count = null, $attrs = [])
{
$attrs = [
$ret = [
'message' => $message,
'attrs' => $attrs,
];
if ($count !== null) {
$attrs['count'] = $count;
$ret['count'] = $count;
}
return response()->json($attrs);
return response()->json($ret);
}
}
+20
View File
@@ -0,0 +1,20 @@
<?php
namespace App\Contracts;
abstract class CronCommand extends Command
{
/**
* @return mixed
*/
abstract public function callEvent();
/**
* Adjust the logging depending on where we're running from
*/
public function __construct()
{
parent::__construct();
$this->redirectLoggingToFile('cron');
}
}
+1 -1
View File
@@ -20,7 +20,7 @@ class ClearExpiredSimbrief extends Listener
}
/**
* @param \App\Events\CronNightly $event
* @param CronHourly $event
*/
public function handle(CronHourly $event): void
{
@@ -6,6 +6,7 @@ use App\Contracts\Listener;
use App\Events\CronHourly;
use App\Events\PirepCancelled;
use App\Models\Enums\PirepState;
use App\Models\Enums\PirepStatus;
use App\Models\Pirep;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
@@ -31,6 +32,7 @@ class RemoveExpiredLiveFlights extends Listener
$date = Carbon::now('UTC')->subHours(setting('acars.live_time'));
$pireps = Pirep::where('updated_at', '<', $date)
->where('state', PirepState::IN_PROGRESS)
->where('status', '<>', PirepStatus::PAUSED)
->get();
foreach ($pireps as $pirep) {
@@ -0,0 +1,15 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class UpdateUsersAddNotes extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->mediumText('notes')->nullable()->after('remember_token');
});
}
}
+35
View File
@@ -410,6 +410,41 @@
options: ''
type: text
description: The Discord Webhook URL for private notifications
- key: notifications.discord_pirep_status
name: Discord Pirep Messages (Public)
group: notifications
value: true
options: ''
type: boolean
description: Pirep status messages (Only key events are being sent)
- key: notifications.mail_pirep_admin
name: Pirep Filed (Admin)
group: notifications
value: true
options: ''
type: boolean
description: Pirep filed mails sent to admins
- key: notifications.mail_pirep_user_ack
name: Pirep Accepted (Pilot)
group: notifications
value: true
options: ''
type: boolean
description: Pirep Accepted mails sent to pilots
- key: notifications.mail_pirep_user_rej
name: Pirep Rejected (Pilot)
group: notifications
value: true
options: ''
type: boolean
description: Pirep Rejected mails sent to pilots
- key: notifications.mail_news
name: News Mails
group: notifications
value: true
options: ''
type: boolean
description: News mails sent to all members
- key: 'cron.random_id'
name: 'Cron Randomized ID'
group: 'cron'
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Events;
use App\Contracts\Event;
class CronFifteenMinute extends Event
{
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Events;
use App\Contracts\Event;
class CronFiveMinute extends Event
{
}
+9
View File
@@ -0,0 +1,9 @@
<?php
namespace App\Events;
use App\Contracts\Event;
class CronThirtyMinute extends Event
{
}
@@ -38,7 +38,7 @@ class AirlinesController extends Controller
public function index(Request $request)
{
$this->airlineRepo->pushCriteria(new RequestCriteria($request));
$airlines = $this->airlineRepo->all();
$airlines = $this->airlineRepo->orderby('name', 'asc')->get();
return view('admin.airlines.index', [
'airlines' => $airlines,
@@ -308,7 +308,7 @@ class FlightController extends Controller
$where['airline_id'] = $airline_id;
$file_name = 'flights-'.$airline_id.'.csv';
}
$flights = $this->flightRepo->where($where)->get();
$flights = $this->flightRepo->where($where)->orderBy('airline_id')->orderBy('flight_number')->orderBy('route_code')->orderBy('route_leg')->get();
$path = $exporter->exportFlights($flights);
return response()->download($path, $file_name, ['content-type' => 'text/csv'])->deleteFileAfterSend(true);
@@ -83,7 +83,7 @@ class SubfleetController extends Controller
public function index(Request $request)
{
$this->subfleetRepo->with(['airline'])->pushCriteria(new RequestCriteria($request));
$subfleets = $this->subfleetRepo->all();
$subfleets = $this->subfleetRepo->orderby('name', 'asc')->get();
return view('admin.subfleets.index', [
'subfleets' => $subfleets,
@@ -32,7 +32,7 @@ class TypeRatingController extends Controller
public function index(Request $request)
{
$this->typeratingRepo->pushCriteria(new RequestCriteria($request));
$typeratings = $this->typeratingRepo->all();
$typeratings = $this->typeratingRepo->orderby('type', 'asc')->get();
return view('admin.typeratings.index', [
'typeratings' => $typeratings,
@@ -50,7 +50,6 @@ class TypeRatingController extends Controller
$model = $this->typeratingRepo->create($input);
Flash::success('Type Rating saved successfully.');
// Cache::forget(config('cache.keys.RANKS_PILOT_LIST.key'));
return redirect(route('admin.typeratings.edit', [$model->id]));
}
@@ -2,10 +2,10 @@
namespace App\Http\Controllers\Api;
use App\Console\Cron;
use App\Contracts\Controller;
use App\Exceptions\CronInvalid;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
class MaintenanceController extends Controller
{
@@ -24,12 +24,12 @@ class MaintenanceController extends Controller
throw new CronInvalid();
}
$output = '';
Artisan::call('schedule:run');
$output .= trim(Artisan::output());
$cron = app(Cron::class);
$run = $cron->run();
return response([
'content' => $output,
return response()->json([
'count' => count($run),
'tasks' => $run,
]);
}
}
+5 -3
View File
@@ -334,16 +334,18 @@ class PirepController extends Controller
*
* @throws \Prettus\Validator\Exceptions\ValidatorException
*
* @return PirepResource
* @return mixed
*/
public function cancel($pirep_id, Request $request)
{
Log::info('PIREP '.$pirep_id.' Cancel, user '.Auth::id(), $request->post());
$pirep = Pirep::find($pirep_id);
$this->pirepSvc->cancel($pirep);
if (!empty($pirep)) {
$this->pirepSvc->cancel($pirep);
}
return new PirepResource($pirep);
return $this->message('PIREP '.$pirep_id.' cancelled');
}
/**
+10
View File
@@ -4,6 +4,16 @@ namespace App\Http\Resources;
use App\Contracts\Resource;
/**
* @mixin \App\Models\Aircraft
*/
class Aircraft extends Resource
{
public function toArray($request)
{
$res = parent::toArray($request);
$res['ident'] = $this->ident;
return $res;
}
}
+2
View File
@@ -88,6 +88,7 @@ class User extends Authenticatable
'toc_accepted',
'opt_in',
'last_ip',
'notes',
'created_at',
'updated_at',
];
@@ -104,6 +105,7 @@ class User extends Authenticatable
'password',
'last_ip',
'remember_token',
'notes',
];
protected $casts = [
@@ -11,14 +11,16 @@ use Carbon\Carbon;
*/
class DiscordMessage
{
const COLOR_SUCCESS = '#0B6623';
const COLOR_WARNING = '#FD6A02';
const COLOR_ERROR = '#ED2939';
const COLOR_SUCCESS = '0B6623';
const COLOR_WARNING = 'FD6A02';
const COLOR_ERROR = 'ED2939';
public $webhook_url;
protected $title;
protected $url;
protected $thumbnail = [];
protected $image = [];
protected $description;
protected $timestamp;
protected $footer;
@@ -26,30 +28,43 @@ class DiscordMessage
protected $author = [];
protected $fields = [];
/**
* Supply the webhook URL that this should be going to
*/
// Supply the webhook URL that this should be going to
public function webhook(string $url): self
{
$this->webhook_url = $url;
return $this;
}
/**
* Title of the notification
*/
// Title of the embed
public function title(string $title): self
{
$this->title = $title;
return $this;
}
// URL of the Title
public function url(string $url): self
{
$this->url = $url;
return $this;
}
// Thumbnail image (placed right side of embed)
// ['url' => '']
public function thumbnail(array $thumbnail): self
{
$this->thumbnail = $thumbnail;
return $this;
}
// Main image (placed bottom of embed)
// ['url' => '']
public function image(array $image): self
{
$this->image = $image;
return $this;
}
/**
* @param array|string $descriptionLines
*/
@@ -63,22 +78,15 @@ class DiscordMessage
return $this;
}
/**
* Set the author information:
* [
* 'name' => '',
* 'url' => '',
* 'icon_url' => '',
*/
// Author details
// ['name' => '', 'url' => '', 'icon_url' => '']
public function author(array $author): self
{
$this->author = $author;
return $this;
}
/**
* Set the fields
*/
// Fields
public function fields(array $fields): self
{
$this->fields = [];
@@ -99,32 +107,45 @@ class DiscordMessage
return $this;
}
// Fixed Success Color
public function success(): self
{
$this->color = static::COLOR_SUCCESS;
$this->color = hexdec('0B6623'); // static::COLOR_SUCCESS;
return $this;
}
// Fixed Warning
public function warning(): self
{
$this->color = static::COLOR_WARNING;
$this->color = hexdec('FD6A02'); // static::COLOR_WARNING;
return $this;
}
// Fixed Error
public function error(): self
{
$this->color = static::COLOR_ERROR;
$this->color = hexdec('ED2939'); // static::COLOR_ERROR;
return $this;
}
// Custom Color
public function color(string $embed_color): self
{
$this->color = hexdec($embed_color);
return $this;
}
public function toArray(): array
{
$embeds = [
'type' => 'rich',
'color' => $this->color,
'title' => $this->title,
'url' => $this->url,
'type' => 'rich',
'thumbnail' => $this->thumbnail,
'description' => $this->description,
'author' => $this->author,
'image' => $this->image,
'timestamp' => Carbon::now('UTC'),
];
@@ -31,7 +31,7 @@ class NewsAdded extends Notification implements ShouldQueue
public function toDiscordChannel($news): ?DiscordMessage
{
$dm = new DiscordMessage();
return $dm->url(setting('notifications.discord_public_webhook_url'))
return $dm->webhook(setting('notifications.discord_public_webhook_url'))
->success()
->title('News: '.$news->subject)
->author([
@@ -43,11 +43,10 @@ class PirepFiled extends Notification implements ShouldQueue
{
$title = 'Flight '.$pirep->ident.' Filed';
$fields = [
'Flight' => $pirep->ident,
'Departure Airport' => $pirep->dpt_airport_id,
'Arrival Airport' => $pirep->arr_airport_id,
'Equipment' => $pirep->aircraft->ident,
'Flight Time' => Time::minutesToTimeString($pirep->flight_time),
'Dep.Airport' => $pirep->dpt_airport_id,
'Arr.Airport' => $pirep->arr_airport_id,
'Equipment' => $pirep->aircraft->ident,
'Flight Time' => Time::minutesToTimeString($pirep->flight_time),
];
if ($pirep->distance) {
@@ -63,16 +62,19 @@ class PirepFiled extends Notification implements ShouldQueue
}
}
// User avatar, somehow $pirep->user->resolveAvatarUrl() is not being accepted by Discord as thumbnail
$user_avatar = !empty($pirep->user->avatar) ? $pirep->user->avatar->url : $pirep->user->gravatar(256);
$dm = new DiscordMessage();
return $dm->url(setting('notifications.discord_public_webhook_url'))
return $dm->webhook(setting('notifications.discord_public_webhook_url'))
->success()
->title($title)
->description($pirep->user->discord_id ? 'Flight by <@'.$pirep->user->discord_id.'>' : '')
->url(route('frontend.pireps.show', [$pirep->id]))
->thumbnail(['url' => $user_avatar])
->image(['url' => $pirep->airline->logo])
->author([
'name' => $pirep->user->ident.' - '.$pirep->user->name_private,
'url' => route('frontend.profile.show', [$pirep->user_id]),
'icon_url' => $pirep->user->resolveAvatarUrl(),
'name' => $pirep->user->ident.' - '.$pirep->user->name_private,
'url' => route('frontend.profile.show', [$pirep->user_id]),
])
->fields($fields);
}
@@ -9,11 +9,9 @@ use App\Notifications\Channels\Discord\DiscordMessage;
use App\Notifications\Channels\Discord\DiscordWebhook;
use App\Support\Units\Distance;
use App\Support\Units\Time;
use function config;
use Illuminate\Contracts\Queue\ShouldQueue;
use PhpUnitsOfMeasure\Exception\NonNumericValue;
use PhpUnitsOfMeasure\Exception\NonStringUnitName;
use function route;
/**
* Send the PIREP accepted message to a particular user, can also be sent to Discord
@@ -75,14 +73,16 @@ class PirepStatusChanged extends Notification implements ShouldQueue
*/
public function toDiscordChannel($pirep): ?DiscordMessage
{
$title = 'Flight '.$pirep->ident.' '.self::$verbs[$pirep->status];
if (empty(setting('notifications.discord_public_webhook_url'))) {
return null;
}
$title = 'Flight '.$pirep->ident.' '.self::$verbs[$pirep->status];
$fields = [
'Flight' => $pirep->ident,
'Departure Airport' => $pirep->dpt_airport_id,
'Arrival Airport' => $pirep->arr_airport_id,
'Equipment' => $pirep->aircraft->ident,
'Flight Time' => Time::minutesToTimeString($pirep->flight_time),
'Dep.Airport' => $pirep->dpt_airport_id,
'Arr.Airport' => $pirep->arr_airport_id,
'Equipment' => $pirep->aircraft->ident,
'Flight Time' => Time::minutesToTimeString($pirep->flight_time),
];
// Show the distance, but include the planned distance if it's been set
@@ -109,16 +109,29 @@ class PirepStatusChanged extends Notification implements ShouldQueue
}
}
// User avatar, somehow $pirep->user->resolveAvatarUrl() is not being accepted by Discord as thumbnail
$user_avatar = !empty($pirep->user->avatar) ? $pirep->user->avatar->url : $pirep->user->gravatar(256);
// Proper coloring for the messages
// Pirep Filed > success, normals > warning, non-normals > error
$danger_types = [
PirepStatus::GRND_RTRN,
PirepStatus::DIVERTED,
PirepStatus::CANCELLED,
PirepStatus::PAUSED,
PirepStatus::EMERG_DESCENT,
];
$color = in_array($pirep->status, $danger_types, true) ? 'ED2939' : 'FD6A02';
$dm = new DiscordMessage();
return $dm->url(setting('notifications.discord_public_webhook_url'))
->success()
return $dm->webhook(setting('notifications.discord_public_webhook_url'))
->color($color)
->title($title)
->description($pirep->user->discord_id ? 'Flight by <@'.$pirep->user->discord_id.'>' : '')
->url(route('frontend.pireps.show', [$pirep->id]))
->thumbnail(['url' => $user_avatar])
->author([
'name' => $pirep->user->ident.' - '.$pirep->user->name_private,
'url' => route('frontend.profile.show', [$pirep->user_id]),
'icon_url' => $pirep->user->resolveAvatarUrl(),
'name' => $pirep->user->ident.' - '.$pirep->user->name_private,
'url' => route('frontend.profile.show', [$pirep->user_id]),
])
->fields($fields);
}
@@ -49,7 +49,7 @@ class UserRegistered extends Notification implements ShouldQueue
public function toDiscordChannel($notifiable): ?DiscordMessage
{
$dm = new DiscordMessage();
return $dm->url(setting('notifications.discord_private_webhook_url'))
return $dm->webhook(setting('notifications.discord_private_webhook_url'))
->success()
->title('New User Registered: '.$this->user->ident)
->author([
+37 -11
View File
@@ -11,6 +11,7 @@ use App\Events\PirepRejected;
use App\Events\PirepStatusChange;
use App\Events\UserRegistered;
use App\Events\UserStateChanged;
use App\Models\Enums\PirepStatus;
use App\Models\Enums\UserState;
use App\Models\User;
use App\Notifications\Messages\UserRejected;
@@ -161,7 +162,7 @@ class NotificationEventsHandler extends Listener
}
/**
* Prefile notification
* Prefile notification. Disabled intentionally, No need to send it to Discord
*/
public function onPirepPrefile(PirepPrefiled $event): void
{
@@ -170,16 +171,33 @@ class NotificationEventsHandler extends Listener
/*
* Broadcast notifications
*/
Notification::send([$event->pirep], new Messages\Broadcast\PirepPrefiled($event->pirep));
// Notification::send([$event->pirep], new Messages\Broadcast\PirepPrefiled($event->pirep));
}
/**
* Status Change notification. Disabled for now, too noisy
* Status Change notification.
* Reduced the messages (Boarding, Pushback, TakeOff, Landing and non-normals only)
* If needed array can be tied to a setting at admin side for further customization
*/
public function onPirepStatusChange(PirepStatusChange $event): void
{
// Log::info('NotificationEvents::onPirepStatusChange: '.$event->pirep->id.' prefiled');
// Notification::send([$event->pirep], new Messages\Discord\PirepStatusChanged($event->pirep));
Log::info('NotificationEvents::onPirepStatusChange: '.$event->pirep->id.' status changed');
$message_types = [
PirepStatus::BOARDING,
PirepStatus::PUSHBACK_TOW,
PirepStatus::GRND_RTRN,
PirepStatus::TAKEOFF,
PirepStatus::LANDED,
PirepStatus::DIVERTED,
PirepStatus::CANCELLED,
PirepStatus::PAUSED,
PirepStatus::EMERG_DESCENT,
];
if (setting('notifications.discord_pirep_status', true) && in_array($event->pirep->status, $message_types, true)) {
Notification::send([$event->pirep], new Messages\Broadcast\PirepStatusChanged($event->pirep));
}
}
/**
@@ -190,7 +208,9 @@ class NotificationEventsHandler extends Listener
public function onPirepFile(PirepFiled $event): void
{
Log::info('NotificationEvents::onPirepFile: '.$event->pirep->id.' filed');
$this->notifyAdmins(new Messages\PirepFiled($event->pirep));
if (setting('notifications.mail_pirep_admin', true)) {
$this->notifyAdmins(new Messages\PirepFiled($event->pirep));
}
/*
* Broadcast notifications
@@ -205,8 +225,10 @@ class NotificationEventsHandler extends Listener
*/
public function onPirepAccepted(PirepAccepted $event): void
{
Log::info('NotificationEvents::onPirepAccepted: '.$event->pirep->id.' accepted');
$this->notifyUser($event->pirep->user, new Messages\PirepAccepted($event->pirep));
if (setting('notifications.mail_pirep_user_ack', true)) {
Log::info('NotificationEvents::onPirepAccepted: '.$event->pirep->id.' accepted');
$this->notifyUser($event->pirep->user, new Messages\PirepAccepted($event->pirep));
}
}
/**
@@ -216,8 +238,10 @@ class NotificationEventsHandler extends Listener
*/
public function onPirepRejected(PirepRejected $event): void
{
Log::info('NotificationEvents::onPirepRejected: '.$event->pirep->id.' rejected');
$this->notifyUser($event->pirep->user, new Messages\PirepRejected($event->pirep));
if (setting('notifications.mail_pirep_user_rej', true)) {
Log::info('NotificationEvents::onPirepRejected: '.$event->pirep->id.' rejected');
$this->notifyUser($event->pirep->user, new Messages\PirepRejected($event->pirep));
}
}
/**
@@ -228,7 +252,9 @@ class NotificationEventsHandler extends Listener
public function onNewsAdded(NewsAdded $event): void
{
Log::info('NotificationEvents::onNewsAdded');
$this->notifyAllUsers(new Messages\NewsAdded($event->news));
if (setting('notifications.mail_news', true)) {
$this->notifyAllUsers(new Messages\NewsAdded($event->news));
}
/*
* Broadcast notifications
+12 -9
View File
@@ -12,9 +12,12 @@ use App\Cron\Nightly\PilotLeave;
use App\Cron\Nightly\RecalculateBalances;
use App\Cron\Nightly\RecalculateStats;
use App\Cron\Nightly\SetActiveFlights;
use App\Events\CronFifteenMinute;
use App\Events\CronFiveMinute;
use App\Events\CronHourly;
use App\Events\CronMonthly;
use App\Events\CronNightly;
use App\Events\CronThirtyMinute;
use App\Events\CronWeekly;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
@@ -24,6 +27,15 @@ use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvi
class CronServiceProvider extends ServiceProvider
{
protected $listen = [
CronFiveMinute::class => [],
CronFifteenMinute::class => [],
CronThirtyMinute::class => [],
CronHourly::class => [
DeletePireps::class,
RemoveExpiredBids::class,
RemoveExpiredLiveFlights::class,
ClearExpiredSimbrief::class,
],
CronNightly::class => [
ApplyExpenses::class,
RecalculateBalances::class,
@@ -32,19 +44,10 @@ class CronServiceProvider extends ServiceProvider
RecalculateStats::class,
NewVersionCheck::class,
],
CronWeekly::class => [
],
CronMonthly::class => [
\App\Cron\Monthly\ApplyExpenses::class,
],
CronHourly::class => [
DeletePireps::class,
RemoveExpiredBids::class,
RemoveExpiredLiveFlights::class,
ClearExpiredSimbrief::class,
],
];
}
+3 -1
View File
@@ -138,8 +138,10 @@ class BidService extends Service
throw new BidExistsForFlight($flight);
}
// This is already controlled above at line 114 with user bid count,
// To prevent or allow multiple bids. Should not be here at all
if (setting('bids.allow_multiple_bids') === false) {
throw new BidExistsForFlight($flight);
// throw new BidExistsForFlight($flight);
}
} else {
/* @noinspection NestedPositiveIfStatementsInspection */
+1 -2
View File
@@ -39,8 +39,7 @@ class CronService extends Service
$path = [
$php_exec,
base_path('artisan'),
'schedule:run',
base_path('bin/cron'),
];
return implode(' ', $path);
+2 -2
View File
@@ -485,8 +485,8 @@ class PirepService extends Service
$default_state = $pirep->state;
}
// If pirep is still at PENDING state decide the default behavior by looking at rank settings
if ($pirep->state === PirepState::PENDING) {
// If pirep is still at PENDING or DRAFT state decide the default behavior by looking at rank settings
if ($pirep->state === PirepState::PENDING || $pirep->state === PirepState::DRAFT) {
if ($pirep->source === PirepSource::ACARS && $pirep->user->rank->auto_approve_acars) {
$default_state = PirepState::ACCEPTED;
} elseif ($pirep->source === PirepSource::MANUAL && $pirep->user->rank->auto_approve_manual) {
Executable
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env php
<?php
/**
* THIS CRON FILE IS A BACKUP METHOD IF YOUR SERVER DOES NOT HAVE PROC_OPEN ENABLED
* YOU SHOULD TRY USING THE DEFAULT INSTRUCTIONS OF USING ARTISAN SCHEDULE:RUN
*/
define('LARAVEL_START', microtime(true));
use App\Console\Cron;
use App\Console\Kernel;
require __DIR__.'/../vendor/autoload.php';
/** @var Application $app */
$app = require_once __DIR__.'/../bootstrap/app.php';
/** @var Kernel $kernel */
$kernel = $app->make(Kernel::class);
// Run a null artisan thing just so Laravel internals can be setup properly
$status = $kernel->handle(
$input = new Symfony\Component\Console\Input\ArrayInput([
'command' => 'version',
]),
new Symfony\Component\Console\Output\NullOutput()
);
/** @var Cron $cron */
$cron = app(Cron::class);
$run = $cron->run();
echo json_encode([
'count' => count($run),
'tasks' => $run,
]);
+376 -234
View File
@@ -1,5 +1,5 @@
{
"name": "phpvms",
"name": "npm-proj-1647195469379-0.2625236740756156F6TT9D",
"lockfileVersion": 2,
"requires": true,
"packages": {
@@ -22,7 +22,7 @@
"jquery": "^3.5.1",
"jquery-pjax": "~2.0",
"js-yaml": "^3.14.0",
"laravel-mix": "^6.0.25",
"laravel-mix": "^6.0.30",
"leaflet": "^1.3.4",
"leaflet-ajax": "2.1.0",
"leaflet-providers": "1.0.*",
@@ -1752,9 +1752,9 @@
}
},
"node_modules/@types/http-proxy": {
"version": "1.17.7",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz",
"integrity": "sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w==",
"version": "1.17.8",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
"integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==",
"dependencies": {
"@types/node": "*"
}
@@ -1801,9 +1801,9 @@
}
},
"node_modules/@types/json-schema": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz",
"integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg=="
"version": "7.0.9",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ=="
},
"node_modules/@types/minimatch": {
"version": "3.0.5",
@@ -2039,6 +2039,42 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dependencies": {
"ajv": "^8.0.0"
},
"peerDependencies": {
"ajv": "^8.0.0"
},
"peerDependenciesMeta": {
"ajv": {
"optional": true
}
}
},
"node_modules/ajv-formats/node_modules/ajv": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz",
"integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
@@ -2082,10 +2118,10 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ansi-html": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
"integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",
"node_modules/ansi-html-community": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
"integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
"engines": [
"node >= 0.8.0"
],
@@ -4009,6 +4045,14 @@
"node": ">= 10"
}
},
"node_modules/define-lazy-prop": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
"engines": {
"node": ">=8"
}
},
"node_modules/define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -6168,6 +6212,20 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
"dependencies": {
"has-symbols": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
@@ -7162,11 +7220,12 @@
}
},
"node_modules/is-arguments": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz",
"integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"dependencies": {
"call-bind": "^1.0.0"
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
@@ -7738,11 +7797,6 @@
"node": ">=8"
}
},
"node_modules/killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
"integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg=="
},
"node_modules/kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
@@ -7778,9 +7832,9 @@
}
},
"node_modules/laravel-mix": {
"version": "6.0.25",
"resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.25.tgz",
"integrity": "sha512-SDpLGUnXJ8g0rvtiLljSTJSR6awj86M2Jd3MhbtT32TCgwXdtajVLF7Mv2blsPLixGHtynwZgi+UFlYQbquPLg==",
"version": "6.0.30",
"resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.30.tgz",
"integrity": "sha512-Y5EjdPVEqVMgnglzJvDuDEpUa2EouutS4ySrukZkBWh2EPPYM1iszu8TItvQ2J08N5BPIrYWh8McUbTwq6tcrQ==",
"dependencies": {
"@babel/core": "^7.14.5",
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
@@ -7827,7 +7881,7 @@
"vue-style-loader": "^4.1.3",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "4.0.0-beta.3",
"webpack-dev-server": "4.1.1",
"webpack-merge": "^5.8.0",
"webpack-notifier": "^1.13.0",
"webpackbar": "^5.0.0-3",
@@ -7878,9 +7932,9 @@
}
},
"node_modules/laravel-mix/node_modules/ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"engines": {
"node": ">=8"
}
@@ -7981,18 +8035,26 @@
}
},
"node_modules/laravel-mix/node_modules/http-proxy-middleware": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz",
"integrity": "sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz",
"integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==",
"dependencies": {
"@types/http-proxy": "^1.17.5",
"@types/http-proxy": "^1.17.8",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.1",
"is-plain-obj": "^3.0.0",
"micromatch": "^4.0.2"
},
"engines": {
"node": ">=8.0.0"
"node": ">=12.0.0"
},
"peerDependencies": {
"@types/express": "^4.17.13"
},
"peerDependenciesMeta": {
"@types/express": {
"optional": true
}
}
},
"node_modules/laravel-mix/node_modules/import-local": {
@@ -8058,15 +8120,16 @@
}
},
"node_modules/laravel-mix/node_modules/open": {
"version": "7.4.2",
"resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz",
"integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==",
"dependencies": {
"is-docker": "^2.0.0",
"is-wsl": "^2.1.1"
"define-lazy-prop": "^2.0.0",
"is-docker": "^2.1.1",
"is-wsl": "^2.2.0"
},
"engines": {
"node": ">=8"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -8175,11 +8238,11 @@
}
},
"node_modules/laravel-mix/node_modules/strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dependencies": {
"ansi-regex": "^5.0.0"
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
@@ -8251,37 +8314,35 @@
}
},
"node_modules/laravel-mix/node_modules/webpack-dev-server": {
"version": "4.0.0-beta.3",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.0.0-beta.3.tgz",
"integrity": "sha512-Ud7ieH15No/KiSdRuzk+2k+S4gSCR/N7m4hJhesDbKQEZy3P+NPXTXfsimNOZvbVX2TRuIEFB+VdLZFn8DwGwg==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.1.1.tgz",
"integrity": "sha512-Kl1mnCEw8Cy1Kw173gCxLIB242LfPKEOj9WoKhKz/MbryZTNrILzOJTk8kiczw/YUEPzn3gcltCQv6hDsLudRg==",
"dependencies": {
"ansi-html": "^0.0.7",
"ansi-html-community": "^0.0.8",
"bonjour": "^3.5.0",
"chokidar": "^3.5.1",
"colorette": "^1.2.2",
"compression": "^1.7.4",
"connect-history-api-fallback": "^1.6.0",
"del": "^6.0.0",
"express": "^4.17.1",
"find-cache-dir": "^3.3.1",
"graceful-fs": "^4.2.6",
"html-entities": "^2.3.2",
"http-proxy-middleware": "^1.3.1",
"http-proxy-middleware": "^2.0.0",
"internal-ip": "^6.2.0",
"ipaddr.js": "^2.0.0",
"is-absolute-url": "^3.0.3",
"killable": "^1.0.1",
"open": "^7.4.2",
"ipaddr.js": "^2.0.1",
"open": "^8.0.9",
"p-retry": "^4.5.0",
"portfinder": "^1.0.28",
"schema-utils": "^3.0.0",
"schema-utils": "^3.1.0",
"selfsigned": "^1.10.11",
"serve-index": "^1.9.1",
"sockjs": "^0.3.21",
"spdy": "^4.0.2",
"strip-ansi": "^6.0.0",
"strip-ansi": "^7.0.0",
"url": "^0.11.0",
"webpack-dev-middleware": "^4.1.0",
"ws": "^7.4.5"
"webpack-dev-middleware": "^5.0.0",
"ws": "^8.1.0"
},
"bin": {
"webpack-dev-server": "bin/webpack-dev-server.js"
@@ -8290,7 +8351,7 @@
"node": ">= 12.13.0"
},
"peerDependencies": {
"webpack": "^4.0.0 || ^5.0.0"
"webpack": "^4.37.0 || ^5.0.0"
},
"peerDependenciesMeta": {
"webpack-cli": {
@@ -8298,12 +8359,37 @@
}
}
},
"node_modules/laravel-mix/node_modules/ws": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz",
"integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==",
"node_modules/laravel-mix/node_modules/webpack-dev-server/node_modules/ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
"engines": {
"node": ">=8.3.0"
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/laravel-mix/node_modules/webpack-dev-server/node_modules/strip-ansi": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
"integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
"dependencies": {
"ansi-regex": "^6.0.1"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/laravel-mix/node_modules/ws": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
@@ -8521,17 +8607,6 @@
"semver": "bin/semver.js"
}
},
"node_modules/map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"dependencies": {
"p-defer": "^1.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -8601,33 +8676,10 @@
"node": ">= 0.6"
}
},
"node_modules/mem": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz",
"integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==",
"dependencies": {
"map-age-cleaner": "^0.1.3",
"mimic-fn": "^3.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sindresorhus/mem?sponsor=1"
}
},
"node_modules/mem/node_modules/mimic-fn": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
"integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
"engines": {
"node": ">=8"
}
},
"node_modules/memfs": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.2.2.tgz",
"integrity": "sha512-RE0CwmIM3CEvpcdK3rZ19BC4E6hv9kADkMN5rPduRak58cNArWLi/9jFLsa4rhsjfVxMP3v0jO7FHXq7SvFY5Q==",
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz",
"integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==",
"dependencies": {
"fs-monkey": "1.0.3"
},
@@ -9555,14 +9607,6 @@
"node": ">=0.10.0"
}
},
"node_modules/p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
"engines": {
"node": ">=4"
}
},
"node_modules/p-event": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
@@ -11332,6 +11376,14 @@
"node": ">=0.10.0"
}
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
@@ -11656,9 +11708,9 @@
"integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw=="
},
"node_modules/selfsigned": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz",
"integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==",
"version": "1.10.14",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz",
"integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==",
"dependencies": {
"node-forge": "^0.10.0"
}
@@ -13653,19 +13705,18 @@
}
},
"node_modules/webpack-dev-middleware": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-4.3.0.tgz",
"integrity": "sha512-PjwyVY95/bhBh6VUqt6z4THplYcsvQ8YNNBTBM873xLVmw8FLeALn0qurHbs9EmcfhzQis/eoqypSnZeuUz26w==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz",
"integrity": "sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==",
"dependencies": {
"colorette": "^1.2.2",
"mem": "^8.1.1",
"memfs": "^3.2.2",
"mime-types": "^2.1.30",
"colorette": "^2.0.10",
"memfs": "^3.4.1",
"mime-types": "^2.1.31",
"range-parser": "^1.2.1",
"schema-utils": "^3.0.0"
"schema-utils": "^4.0.0"
},
"engines": {
"node": ">= v10.23.3"
"node": ">= 12.13.0"
},
"funding": {
"type": "opencollective",
@@ -13675,17 +13726,54 @@
"webpack": "^4.0.0 || ^5.0.0"
}
},
"node_modules/webpack-dev-middleware/node_modules/schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"node_modules/webpack-dev-middleware/node_modules/ajv": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz",
"integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==",
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/webpack-dev-middleware/node_modules/ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"dependencies": {
"fast-deep-equal": "^3.1.3"
},
"peerDependencies": {
"ajv": "^8.8.2"
}
},
"node_modules/webpack-dev-middleware/node_modules/colorette": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
"integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g=="
},
"node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"node_modules/webpack-dev-middleware/node_modules/schema-utils": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
"integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
"dependencies": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.8.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.0.0"
},
"engines": {
"node": ">= 10.13.0"
"node": ">= 12.13.0"
},
"funding": {
"type": "opencollective",
@@ -15421,9 +15509,9 @@
}
},
"@types/http-proxy": {
"version": "1.17.7",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.7.tgz",
"integrity": "sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w==",
"version": "1.17.8",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
"integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==",
"requires": {
"@types/node": "*"
}
@@ -15470,9 +15558,9 @@
}
},
"@types/json-schema": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz",
"integrity": "sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg=="
"version": "7.0.9",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
"integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ=="
},
"@types/minimatch": {
"version": "3.0.5",
@@ -15687,6 +15775,32 @@
"uri-js": "^4.2.2"
}
},
"ajv-formats": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"requires": {
"ajv": "^8.0.0"
},
"dependencies": {
"ajv": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz",
"integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==",
"requires": {
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
}
},
"json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
}
}
},
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
@@ -15718,10 +15832,10 @@
}
}
},
"ansi-html": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
"integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4="
"ansi-html-community": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
"integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw=="
},
"ansi-regex": {
"version": "4.1.0",
@@ -17210,6 +17324,11 @@
"execa": "^5.0.0"
}
},
"define-lazy-prop": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
"integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -18881,6 +19000,14 @@
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
},
"has-tostringtag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
"requires": {
"has-symbols": "^1.0.2"
}
},
"has-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
@@ -19637,11 +19764,12 @@
}
},
"is-arguments": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz",
"integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"requires": {
"call-bind": "^1.0.0"
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
}
},
"is-arrayish": {
@@ -20041,11 +20169,6 @@
"resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
"integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ=="
},
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
"integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg=="
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
@@ -20075,9 +20198,9 @@
}
},
"laravel-mix": {
"version": "6.0.25",
"resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.25.tgz",
"integrity": "sha512-SDpLGUnXJ8g0rvtiLljSTJSR6awj86M2Jd3MhbtT32TCgwXdtajVLF7Mv2blsPLixGHtynwZgi+UFlYQbquPLg==",
"version": "6.0.30",
"resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.30.tgz",
"integrity": "sha512-Y5EjdPVEqVMgnglzJvDuDEpUa2EouutS4ySrukZkBWh2EPPYM1iszu8TItvQ2J08N5BPIrYWh8McUbTwq6tcrQ==",
"requires": {
"@babel/core": "^7.14.5",
"@babel/plugin-proposal-object-rest-spread": "^7.14.5",
@@ -20124,7 +20247,7 @@
"vue-style-loader": "^4.1.3",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "4.0.0-beta.3",
"webpack-dev-server": "4.1.1",
"webpack-merge": "^5.8.0",
"webpack-notifier": "^1.13.0",
"webpackbar": "^5.0.0-3",
@@ -20152,9 +20275,9 @@
"requires": {}
},
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
},
"ansi-styles": {
"version": "4.3.0",
@@ -20222,11 +20345,11 @@
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
"http-proxy-middleware": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz",
"integrity": "sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz",
"integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==",
"requires": {
"@types/http-proxy": "^1.17.5",
"@types/http-proxy": "^1.17.8",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.1",
"is-plain-obj": "^3.0.0",
@@ -20275,12 +20398,13 @@
}
},
"open": {
"version": "7.4.2",
"resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz",
"integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==",
"requires": {
"is-docker": "^2.0.0",
"is-wsl": "^2.1.1"
"define-lazy-prop": "^2.0.0",
"is-docker": "^2.1.1",
"is-wsl": "^2.2.0"
}
},
"p-limit": {
@@ -20349,11 +20473,11 @@
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"requires": {
"ansi-regex": "^5.0.0"
"ansi-regex": "^5.0.1"
}
},
"supports-color": {
@@ -20393,43 +20517,56 @@
}
},
"webpack-dev-server": {
"version": "4.0.0-beta.3",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.0.0-beta.3.tgz",
"integrity": "sha512-Ud7ieH15No/KiSdRuzk+2k+S4gSCR/N7m4hJhesDbKQEZy3P+NPXTXfsimNOZvbVX2TRuIEFB+VdLZFn8DwGwg==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.1.1.tgz",
"integrity": "sha512-Kl1mnCEw8Cy1Kw173gCxLIB242LfPKEOj9WoKhKz/MbryZTNrILzOJTk8kiczw/YUEPzn3gcltCQv6hDsLudRg==",
"requires": {
"ansi-html": "^0.0.7",
"ansi-html-community": "^0.0.8",
"bonjour": "^3.5.0",
"chokidar": "^3.5.1",
"colorette": "^1.2.2",
"compression": "^1.7.4",
"connect-history-api-fallback": "^1.6.0",
"del": "^6.0.0",
"express": "^4.17.1",
"find-cache-dir": "^3.3.1",
"graceful-fs": "^4.2.6",
"html-entities": "^2.3.2",
"http-proxy-middleware": "^1.3.1",
"http-proxy-middleware": "^2.0.0",
"internal-ip": "^6.2.0",
"ipaddr.js": "^2.0.0",
"is-absolute-url": "^3.0.3",
"killable": "^1.0.1",
"open": "^7.4.2",
"ipaddr.js": "^2.0.1",
"open": "^8.0.9",
"p-retry": "^4.5.0",
"portfinder": "^1.0.28",
"schema-utils": "^3.0.0",
"schema-utils": "^3.1.0",
"selfsigned": "^1.10.11",
"serve-index": "^1.9.1",
"sockjs": "^0.3.21",
"spdy": "^4.0.2",
"strip-ansi": "^6.0.0",
"strip-ansi": "^7.0.0",
"url": "^0.11.0",
"webpack-dev-middleware": "^4.1.0",
"ws": "^7.4.5"
"webpack-dev-middleware": "^5.0.0",
"ws": "^8.1.0"
},
"dependencies": {
"ansi-regex": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
"integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="
},
"strip-ansi": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz",
"integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==",
"requires": {
"ansi-regex": "^6.0.1"
}
}
}
},
"ws": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz",
"integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==",
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
"requires": {}
}
}
@@ -20605,14 +20742,6 @@
}
}
},
"map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"requires": {
"p-defer": "^1.0.0"
}
},
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -20667,26 +20796,10 @@
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"mem": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz",
"integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==",
"requires": {
"map-age-cleaner": "^0.1.3",
"mimic-fn": "^3.1.0"
},
"dependencies": {
"mimic-fn": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
"integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ=="
}
}
},
"memfs": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.2.2.tgz",
"integrity": "sha512-RE0CwmIM3CEvpcdK3rZ19BC4E6hv9kADkMN5rPduRak58cNArWLi/9jFLsa4rhsjfVxMP3v0jO7FHXq7SvFY5Q==",
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz",
"integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==",
"requires": {
"fs-monkey": "1.0.3"
}
@@ -21405,11 +21518,6 @@
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
},
"p-event": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
@@ -22695,6 +22803,11 @@
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
},
"require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
@@ -22924,9 +23037,9 @@
"integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw=="
},
"selfsigned": {
"version": "1.10.11",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz",
"integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==",
"version": "1.10.14",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz",
"integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==",
"requires": {
"node-forge": "^0.10.0"
}
@@ -24577,26 +24690,55 @@
}
},
"webpack-dev-middleware": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-4.3.0.tgz",
"integrity": "sha512-PjwyVY95/bhBh6VUqt6z4THplYcsvQ8YNNBTBM873xLVmw8FLeALn0qurHbs9EmcfhzQis/eoqypSnZeuUz26w==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz",
"integrity": "sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==",
"requires": {
"colorette": "^1.2.2",
"mem": "^8.1.1",
"memfs": "^3.2.2",
"mime-types": "^2.1.30",
"colorette": "^2.0.10",
"memfs": "^3.4.1",
"mime-types": "^2.1.31",
"range-parser": "^1.2.1",
"schema-utils": "^3.0.0"
"schema-utils": "^4.0.0"
},
"dependencies": {
"schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"ajv": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz",
"integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==",
"requires": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
"fast-deep-equal": "^3.1.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
}
},
"ajv-keywords": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
"requires": {
"fast-deep-equal": "^3.1.3"
}
},
"colorette": {
"version": "2.0.16",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
"integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g=="
},
"json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
},
"schema-utils": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
"integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
"requires": {
"@types/json-schema": "^7.0.9",
"ajv": "^8.8.0",
"ajv-formats": "^2.1.1",
"ajv-keywords": "^5.0.0"
}
}
}
+1 -1
View File
@@ -27,7 +27,7 @@
"jquery": "^3.5.1",
"jquery-pjax": "~2.0",
"js-yaml": "^3.14.0",
"laravel-mix": "^6.0.25",
"laravel-mix": "^6.0.30",
"leaflet": "^1.3.4",
"leaflet-ajax": "2.1.0",
"leaflet-providers": "1.0.*",
@@ -22,7 +22,7 @@ return [
'fieldsreadonly' => 'Una vez que se ha enviado un PIREP, ciertos campos pasan al modo de solo lectura.',
'flightinformations' => 'Información de vuelo',
'flightident' => 'Vuelo Número/Código/Etapa',
'block_fuel' => 'Bloque de Combustible',
'block_fuel' => 'Combustible en calzos',
'fuel_used' => 'Combustible Usado',
'codeoptional' => 'Código (opcional)',
'legoptional' => 'Etapa (opcional)',
+10 -3
View File
@@ -174,7 +174,6 @@
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-container">
@@ -260,8 +259,9 @@
<div class="row">
<div class="form-group col-sm-12">
{{ Form::textarea('notes', null, [
'class' => 'form-control input-text',
'style' => 'padding: 10px',
'id' => 'editor',
'class' => 'editor',
'style' => 'padding: 5px',
]) }}
<p class="text-danger">{{ $errors->first('notes') }}</p>
</div>
@@ -288,3 +288,10 @@
</div>
</div>
</div>
@section('scripts')
@parent
<script src="{{ public_asset('assets/vendor/ckeditor4/ckeditor.js') }}"></script>
<script>
$(document).ready(function () { CKEDITOR.replace('editor'); });
</script>
@endsection
+16 -24
View File
@@ -5,19 +5,16 @@
{{ Form::number('pilot_id', null, ['class' => 'form-control']) }}
<p class="text-danger">{{ $errors->first('pilot_id') }}</p>
</div>
<div class="form-group col-sm-3">
{{ Form::label('name', 'Name:') }}
{{ Form::text('name', null, ['class' => 'form-control', 'autocomplete' => 'off']) }}
<p class="text-danger">{{ $errors->first('name') }}</p>
</div>
<div class="form-group col-sm-3">
{{ Form::label('email', 'Email:') }}
{{ Form::text('email', null, ['class' => 'form-control', 'autocomplete' => 'off']) }}
<p class="text-danger">{{ $errors->first('email') }}</p>
</div>
<div class="form-group col-sm-3">
{{ Form::label('password', 'Password:') }}
{{ Form::password('password', ['class' => 'form-control', 'autocomplete' => 'off']) }}
@@ -52,7 +49,6 @@
{{ Form::select('curr_airport_id', $airports, null , ['class' => 'form-control select2']) }}
<p class="text-danger">{{ $errors->first('curr_airport_id') }}</p>
</div>
</div>
<div class="row">
@@ -60,12 +56,10 @@
{{ Form::label('airline_id', 'Airline:') }}
{{ Form::select('airline_id', $airlines, null, ['class' => 'form-control select2', 'placeholder' => 'Select Airline']) }}
</div>
<div class="form-group col-sm-4">
{{ Form::label('rank_id', 'Rank:') }}
{{ Form::select('rank_id', $ranks, null, ['class' => 'form-control select2', 'placeholder' => 'Select Rank']) }}
</div>
<div class="form-group col-sm-4">
{{ Form::label('roles', 'Roles:') }}
{{ Form::select('roles[]', $roles, $user->roles->pluck('id'),
@@ -74,17 +68,21 @@
</div>
<div class="row">
<div class="form-group col-sm-6">
<div class="form-group col-md-4">
{{ Form::label('state', 'State:') }}
<label class="checkbox-inline">
{{ Form::select('state', UserState::labels(), null, ['class' => 'form-control select2']) }}
</label>
{{-- <label class="checkbox-inline"> --}}
{{ Form::select('state', UserState::labels(), null, ['class' => 'form-control select2', 'style' => 'width: 100%;']) }}
{{-- </label> --}}
</div>
<div class="form-group col-md-8">
{{ Form::label('notes', 'Management Notes:') }}
{{ Form::textarea('notes', null, ['class' => 'form-control', 'rows' => 4, 'autocomplete' => 'off']) }}
</div>
</div>
<!-- Submit Field -->
<div class="form-group col-sm-6 text-right">
{{--<a href="{{ route('admin.users.regen_apikey', [$user->id]) }}" class="btn btn-warning"
onclick="return confirm('Are you sure? This will reset this user\'s API key.')">new api key</a>--}}
<div class="row">
<div class="form-group col-sm-12 text-right">
{{-- <a href="{{ route('admin.users.regen_apikey', [$user->id]) }}" class="btn btn-warning" onclick="return confirm('Are you sure? This will reset this user\'s API key.')">New API Key</a> --}}
&nbsp;
{{ Form::button('Save', ['type' => 'submit', 'class' => 'btn btn-success']) }}
<a href="{{ route('admin.users.index') }}" class="btn btn-default">Cancel</a>
@@ -95,10 +93,8 @@
<div class="form-group col-sm-12">
<table class="table table-hover">
<tr>
<td colspan="2">
<h5>User Details</h5>
</td>
</tr>
<td colspan="2"><h5>User Details</h5></td>
</tr>
<tr>
<td>Total Flights</td>
<td>{{ $user->flights }}</td>
@@ -127,14 +123,10 @@
<td>@lang('profile.opt-in')</td>
<td>{{ $user->opt_in ? __('common.yes') : __('common.no') }}</td>
</tr>
@if($user->fields)
<tr>
<td colspan="2">
<h5>Custom Fields</h5>
</td>
<td colspan="2"><h5>Custom Fields</h5></td>
</tr>
{{-- Custom Fields --}}
@foreach($user->fields as $field)
<tr>
@@ -145,4 +137,4 @@
@endif
</table>
</div>
</div>
</div>
@@ -1,5 +1,5 @@
<h4>@lang('toc.title')</h4>
<textarea class="form-control" style="height: 150px; border: 1px #ccc solid;">
<textarea readonly class="form-control" style="height: 150px; border: 1px #ccc solid;">
{{ config('app.name') }} offers this Web site, including all information, software,
products and services available from this Web site or offered as part of or in conjunction
with this Web site (the “Web site”), to you, the user, conditioned upon your acceptance of
+7
View File
@@ -279,6 +279,9 @@ class ApiTest extends TestCase
}
$this->assertCount($size, $subfleet['aircraft']);
foreach ($subfleet['aircraft'] as $aircraft) {
$this->assertNotEmpty($aircraft['ident']);
}
}
}
@@ -314,6 +317,7 @@ class ApiTest extends TestCase
$this->assertEquals($body['id'], $aircraft->id);
$this->assertEquals($body['name'], $aircraft->name);
$this->assertNotEmpty($body['ident']);
$this->assertEquals($body['mtow'], $aircraft->mtow);
$this->assertEquals($body['zfw'], $aircraft->zfw);
@@ -325,6 +329,9 @@ class ApiTest extends TestCase
$this->assertEquals($body['mtow'], $aircraft->mtow);
$this->assertEquals($body['zfw'], $aircraft->zfw);
$this->assertNotEmpty($body['ident']);
$this->assertEquals($body['ident'], $aircraft->ident);
$resp = $this->get('/api/fleet/aircraft/'.$aircraft->id.'?icao='.$aircraft->icao);
$body = $resp->json()['data'];