postgres fixes
This commit is contained in:
parent
625082fdae
commit
67c244240a
@ -27,3 +27,6 @@ indent_size = 4
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
[justfile]
|
||||
indent_size = 2
|
||||
|
||||
36
.github/workflows/lint.yml
vendored
36
.github/workflows/lint.yml
vendored
@ -1,36 +0,0 @@
|
||||
#---
|
||||
#
|
||||
# Run Laravel Pint
|
||||
# https://laravel.com/docs/11.x/pint#running-tests-on-github-actions
|
||||
#
|
||||
# name: Check Code Style
|
||||
#
|
||||
# on:
|
||||
# pull_request:
|
||||
# push:
|
||||
# branches:
|
||||
# - main
|
||||
# - dev
|
||||
# - "feature/**"
|
||||
# - "release/**"
|
||||
# - "hotfix/**"
|
||||
#
|
||||
# jobs:
|
||||
# lint:
|
||||
# runs-on: ubuntu-latest
|
||||
# strategy:
|
||||
# fail-fast: true
|
||||
# matrix:
|
||||
# php: [8.4]
|
||||
#
|
||||
# steps:
|
||||
# - name: Checkout code
|
||||
# uses: actions/checkout@v4
|
||||
#
|
||||
# - name: Setup PHP
|
||||
# uses: shivammathur/setup-php@v2
|
||||
# with:
|
||||
# php-version: ${{ matrix.php }}
|
||||
# extensions: json, dom, curl, libxml, mbstring
|
||||
# coverage: none
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -30,6 +30,7 @@ storage/*.sqlite
|
||||
.envrc
|
||||
.env
|
||||
.github/scripts/env.test
|
||||
.mise.local.toml
|
||||
.vagrant
|
||||
.docker
|
||||
#Homestead.yaml
|
||||
@ -108,3 +109,4 @@ modules_statuses.json
|
||||
/phpvms
|
||||
.env.testing
|
||||
/intellij_style.xml
|
||||
/justfile
|
||||
|
||||
100
.mise.toml
Normal file
100
.mise.toml
Normal file
@ -0,0 +1,100 @@
|
||||
|
||||
[env]
|
||||
BUILDKIT_HOST = "docker-container://buildkit"
|
||||
PHPRC = "resources/mise"
|
||||
_.php = {
|
||||
prebuilt_static = true,
|
||||
prebuilt_static_flavor = "bulk",
|
||||
extra_configure_options = "--with-pdo-mysql --with-pdo-pgsql",
|
||||
pie_extensions = "redis/phpredis xdebug/xdebug"
|
||||
}
|
||||
|
||||
[tools]
|
||||
php = "8.5.6"
|
||||
#bun = "system"
|
||||
|
||||
[plugins]
|
||||
php = "https://github.com/verzly/mise-php#latest"
|
||||
|
||||
# -----------------------------------------------
|
||||
# Local tasks
|
||||
# mise run setup
|
||||
# -----------------------------------------------
|
||||
|
||||
[tasks.setup]
|
||||
run = [
|
||||
"mise install",
|
||||
"mise run run-buildkit-container || true"
|
||||
]
|
||||
|
||||
[tasks.run-buildkit-container]
|
||||
run = "docker run --rm --privileged -d --name buildkit -e BUILDKIT_DEBUG=1 moby/buildkit:latest"
|
||||
|
||||
[tasks.railpack]
|
||||
run = "railpack build ."
|
||||
|
||||
# Run the github workflows locally using act
|
||||
[tasks.gh-actions]
|
||||
env = {
|
||||
DOCKER_HOST = 'ssh://twilight.zsh.ad'
|
||||
}
|
||||
|
||||
run = '''
|
||||
act \
|
||||
--container-architecture linux/amd64 pull_request \
|
||||
--action-offline-mode
|
||||
'''
|
||||
|
||||
# -----------------------------------------------
|
||||
# Test against real databases
|
||||
# -----------------------------------------------
|
||||
|
||||
[tasks.test-db-up]
|
||||
description = "Start MySQL and PostgreSQL for testing"
|
||||
run = "docker compose -f compose.test.yml up -d --wait"
|
||||
|
||||
[tasks.test-db-down]
|
||||
description = "Stop test databases and remove volumes"
|
||||
run = "docker compose -f compose.test.yml down -v"
|
||||
|
||||
[tasks.'tests:mysql']
|
||||
description = "Run tests against MySQL (port 13306)"
|
||||
#depends = ["test-db-up"]
|
||||
#depends_post = ["test-db-down"]
|
||||
env = {
|
||||
DB_CONNECTION = 'mysql',
|
||||
DB_HOST = '127.0.0.1',
|
||||
DB_PORT = "13306",
|
||||
DB_DATABASE = "phpvms_test",
|
||||
DB_USERNAME = "phpvms",
|
||||
DB_PASSWORD = "password"
|
||||
}
|
||||
run = [
|
||||
"docker compose -f compose.test.yml up mysql -d --wait",
|
||||
"vendor/bin/pest --compact"
|
||||
]
|
||||
|
||||
[tasks.'tests:pgsql']
|
||||
description = "Run tests against PostgreSQL (port 15432)"
|
||||
#depends = ["test-db-up"]
|
||||
#depends_post = ["test-db-down"]
|
||||
env = {
|
||||
DB_CONNECTION = 'pgsql',
|
||||
DB_HOST = '127.0.0.1',
|
||||
DB_PORT = "15432",
|
||||
DB_DATABASE = "phpvms_test",
|
||||
DB_USERNAME = "phpvms",
|
||||
DB_PASSWORD = "password"
|
||||
}
|
||||
run = [
|
||||
"docker compose -f compose.test.yml up pgsql -d --wait",
|
||||
"vendor/bin/pest --compact"
|
||||
]
|
||||
|
||||
[tasks.test-db]
|
||||
description = "Run tests against MySQL and PostgreSQL"
|
||||
depends = ["test-mysql", "test-pgsql"]
|
||||
run = '''
|
||||
echo ""
|
||||
echo "All database tests passed."
|
||||
'''
|
||||
@ -5,6 +5,7 @@
|
||||
"modules/**",
|
||||
"resources/js/dist/**",
|
||||
".github/skills/*",
|
||||
".github/copilot-instructions.md"
|
||||
".github/copilot-instructions.md",
|
||||
"*.toml"
|
||||
]
|
||||
}
|
||||
|
||||
86
README.md
86
README.md
@ -1,16 +1,12 @@
|
||||
# phpVMS <sup>8</sup>
|
||||
# phpVMS 8 - Build, Fly, Extend
|
||||
|
||||
[](https://github.com/phpvms/phpvms/actions/workflows/build.yml)  [](https://packagist.org/packages/nabeel/phpvms)
|
||||

|
||||
|
||||
phpVMS is a PHP application to run and simulate an airline. It allowed users to register,
|
||||
view flight schedules that you create, and file flight reports, built on the Laravel framework.
|
||||
The latest documentation, with installation instructions is available on the
|
||||
[phpVMS documentation](https://docs.phpvms.net/) site.
|
||||
phpVMS is a PHP application to run and simulate an airline. It allowed users to register, view flight schedules that you create, and file flight reports, built on the Laravel framework. The latest documentation, with installation instructions is available on the [phpVMS documentation](https://docs.phpvms.net/) site.
|
||||
|
||||
## Installation
|
||||
|
||||
A full distribution, with all the composer dependencies, is available at this
|
||||
[GitHub Releases](https://github.com/nabeelio/phpvms/releases) link.
|
||||
A full distribution, with all the composer dependencies, is available at this [GitHub Releases](https://github.com/nabeelio/phpvms/releases) link.
|
||||
|
||||
### Requirements
|
||||
|
||||
@ -24,41 +20,28 @@ A full distribution, with all the composer dependencies, is available at this
|
||||
- tokenizer
|
||||
- intl
|
||||
- zip
|
||||
|
||||
- Database:
|
||||
- MySQL 8.0+ (or MySQL variant, including MariaDB 10.2+ and Percona 8.0+)
|
||||
- PostgreSQL 16+
|
||||
- MySQL 8.0+
|
||||
- MariaDB 10.6+
|
||||
- Redis 6.0+ (optional, recommended)
|
||||
|
||||
[View more details on requirements](https://docs.phpvms.net/requirements)
|
||||
|
||||
### Installer
|
||||
|
||||
1. Upload to your server
|
||||
2. Visit the site, and follow the link to the installer
|
||||
|
||||
[View installation details](https://docs.phpvms.net/installation)
|
||||
|
||||
## Production Deployment with Docker
|
||||
|
||||
The reference production stack is `compose.deploy.yml`. It runs the official
|
||||
phpVMS image (built from the repo `Dockerfile`, based on
|
||||
`serversideup/php:8.5-frankenphp`) with Laravel Octane worker mode enabled,
|
||||
plus MariaDB and Redis. No separate web-server sidecar is needed — FrankenPHP
|
||||
serves HTTP/HTTPS directly.
|
||||
The reference production stack is `compose.deploy.yml`. It runs the official phpvms image (built from the repo `Dockerfile`, based on `serversideup/php:8.5-frankenphp`) with Laravel Octane worker mode enabled, plus PostgreSQL and Redis. No separate web-server sidecar is needed — FrankenPHP serves HTTP/HTTPS directly.
|
||||
|
||||
```bash
|
||||
```shellscript
|
||||
docker compose -f compose.deploy.yml up -d
|
||||
```
|
||||
|
||||
### Octane worker mode
|
||||
|
||||
The image itself ships with serversideup's default classic FrankenPHP entry
|
||||
point (one PHP worker per request). `compose.deploy.yml` opts into Laravel
|
||||
Octane worker mode via a `command:` override on the `app` service — the
|
||||
[pattern documented upstream](https://serversideup.net/open-source/docker-php/docs/framework-guides/laravel/octane).
|
||||
The image itself ships with serversideup's default classic FrankenPHP entry point (one PHP worker per request). `compose.deploy.yml` opts into Laravel Octane worker mode via a `command:` override on the `app` service — the [pattern documented upstream](https://serversideup.net/open-source/docker-php/docs/framework-guides/laravel/octane).
|
||||
|
||||
To fall back to classic FrankenPHP + PHP-worker mode (matches the prior
|
||||
PHP-FPM request semantics — slower per request but bulletproof if a
|
||||
worker-mode bug hits), delete the `command:` line from the `app` service
|
||||
and recreate the container:
|
||||
To fall back to classic FrankenPHP + PHP-worker mode (matches the prior PHP-FPM request semantics — slower per request but bulletproof if a worker-mode bug hits), delete the `command:` line from the `app` service and recreate the container:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@ -66,24 +49,21 @@ services:
|
||||
# command: [...octane:start...] # remove this line
|
||||
```
|
||||
|
||||
Under worker mode, `KvpService` (the JSON-backed key/value store used for
|
||||
non-hot settings) is eventually consistent: writes from one worker
|
||||
propagate to other workers on their next read of the same key. If your
|
||||
deployment requires strong consistency for KVP, run with `--workers=1` or
|
||||
remove the `command:` override.
|
||||
Module authors: under Octane the framework stays booted across requests, so avoid per-request data in singleton-bound services, `static` array accumulators, and `boot()`-time toggles without a matching per-request reset. See `app/Http/Middleware/DisableActivityLoggingByDefault.php` for the pattern used to keep activity logging request-scoped.
|
||||
|
||||
Module authors: under Octane the framework stays booted across requests,
|
||||
so avoid per-request data in singleton-bound services, `static` array
|
||||
accumulators, and `boot()`-time toggles without a matching per-request
|
||||
reset. See `app/Http/Middleware/DisableActivityLoggingByDefault.php` for
|
||||
the pattern used to keep activity logging request-scoped.
|
||||
## Development Environment
|
||||
|
||||
## Development Environment with Docker
|
||||
The development environment uses mise. You can read about mise and install it from [here](https://mise.jdx.dev/). If you want mise to handle installing the correct PHP version, you can run:
|
||||
|
||||
A full development environment can be brought up using Docker and
|
||||
[Laravel Sail](https://laravel.com/docs/10.x/sail), without having to install composer/npm locally
|
||||
```shellscript
|
||||
mise install
|
||||
```
|
||||
|
||||
```bash
|
||||
If you install the `mise` shell script integration, the correct PHP version will automatically be selected for you.~~~~
|
||||
|
||||
A full development environment can be brought up using Docker and [Laravel Sail](https://laravel.com/docs/10.x/sail), without having to install composer/npm locally
|
||||
|
||||
```shellscript
|
||||
make docker-test
|
||||
|
||||
# **OR** with docker directly
|
||||
@ -101,16 +81,15 @@ docker run --rm \
|
||||
|
||||
Then go to `http://localhost`.
|
||||
|
||||
Instead of repeatedly typing vendor/bin/sail to execute Sail commands, you may wish to configure a
|
||||
shell alias that allows you to execute Sail's commands more easily:
|
||||
Instead of repeatedly typing vendor/bin/sail to execute Sail commands, you may wish to configure a shell alias that allows you to execute Sail's commands more easily:
|
||||
|
||||
```bash
|
||||
```shellscript
|
||||
alias sail='[ -f sail ] && sh sail || sh vendor/bin/sail'
|
||||
```
|
||||
|
||||
Then you can execute php, artisan, composer, npm, etc. commands using the sail prefix:
|
||||
|
||||
```bash
|
||||
```shellscript
|
||||
# PHP commands within Laravel Sail...
|
||||
sail php --version
|
||||
|
||||
@ -130,7 +109,7 @@ To interact with databases (MariaDB, Redis...), please refer to the Laravel Sail
|
||||
|
||||
Yarn is required, run:
|
||||
|
||||
```bash
|
||||
```shellscript
|
||||
make build-assets
|
||||
```
|
||||
|
||||
@ -138,10 +117,9 @@ This will build all the assets according to the webpack file.
|
||||
|
||||
### Laravel Boost
|
||||
|
||||
If you want to use AI agents for your development workflow, please ensure you install
|
||||
[Laravel Boost](https://laravel.com/ai/boost) by running the following command:
|
||||
If you want to use AI agents for your development workflow, please ensure you install [Laravel Boost](https://laravel.com/ai/boost) by running the following command:
|
||||
|
||||
```bash
|
||||
```shellscript
|
||||
php artisan boost:install
|
||||
```
|
||||
|
||||
@ -150,7 +128,3 @@ php artisan boost:install
|
||||
## Contributors
|
||||
|
||||
Thank you to everyone who've contributed to phpVMS!
|
||||
|
||||
<a href="https://github.com/phpvms/phpvms/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=phpvms/phpvms" alt="contributors images"/>
|
||||
</a>
|
||||
|
||||
@ -27,17 +27,14 @@ class CarbonCast implements CastsAttributes
|
||||
return new Carbon($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the attribute to its underlying model values.
|
||||
*
|
||||
* @param Model $model
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function set($model, string $key, $value, array $attributes)
|
||||
{
|
||||
if ($value instanceof Carbon) {
|
||||
return $value->toIso8601ZuluString();
|
||||
return $value->toDateTimeString();
|
||||
}
|
||||
|
||||
if (is_string($value)) {
|
||||
return (new Carbon($value))->toDateTimeString();
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
@ -173,6 +173,12 @@ class SetVisibleFlights extends Listener
|
||||
*/
|
||||
private static function sqlBool(bool $value): string
|
||||
{
|
||||
$driver = DB::connection()->getDriverName();
|
||||
|
||||
if ($driver === 'pgsql') {
|
||||
return $value ? 'TRUE' : 'FALSE';
|
||||
}
|
||||
|
||||
return $value ? '1' : '0';
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,5 +10,5 @@ use App\Models\Pirep;
|
||||
|
||||
class AcarsUpdate extends Event
|
||||
{
|
||||
public function __construct(public Pirep $pirep, public Acars $acars) {}
|
||||
public function __construct(public Pirep $pirep, public ?Acars $acars = null) {}
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ class FlightImporter extends Importer
|
||||
->rules(['required', 'integer']),
|
||||
|
||||
ImportColumn::make('callsign')
|
||||
->rules(['max:4']),
|
||||
->rules(['max:10']),
|
||||
|
||||
ImportColumn::make('route_code')
|
||||
->rules(['max:5']),
|
||||
@ -125,11 +125,11 @@ class FlightImporter extends Importer
|
||||
|
||||
ImportColumn::make('load_factor')
|
||||
->numeric()
|
||||
->rules(['nullable', 'integer']),
|
||||
->rules(['nullable', 'numeric', 'min:0', 'max:100']),
|
||||
|
||||
ImportColumn::make('load_factor_variance')
|
||||
->numeric()
|
||||
->rules(['nullable', 'integer']),
|
||||
->rules(['nullable', 'numeric', 'min:0', 'max:100']),
|
||||
|
||||
ImportColumn::make('route')
|
||||
->fillRecordUsing(function (Flight $record, ?string $state): void {
|
||||
|
||||
@ -51,7 +51,7 @@ class FlightForm
|
||||
TextInput::make('callsign')
|
||||
->label(__('flights.callsign'))
|
||||
->string()
|
||||
->maxLength(4),
|
||||
->maxLength(10),
|
||||
|
||||
TextInput::make('flight_number')
|
||||
->label(__('flights.flightnumber'))
|
||||
@ -82,10 +82,16 @@ class FlightForm
|
||||
Grid::make()->schema([
|
||||
TextInput::make('load_factor')
|
||||
->numeric()
|
||||
->minValue(0)
|
||||
->maxValue(100)
|
||||
->stripCharacters('%')
|
||||
->helperText(__('filament.flight_load_factor_hint')),
|
||||
|
||||
TextInput::make('load_factor_variance')
|
||||
->numeric()
|
||||
->minValue(0)
|
||||
->maxValue(100)
|
||||
->stripCharacters('%')
|
||||
->helperText(__('filament.flight_load_factor_variance_hint')),
|
||||
|
||||
])
|
||||
|
||||
@ -18,6 +18,7 @@ class NewsForm
|
||||
->label(__('filament.news_subject'))
|
||||
->string()
|
||||
->required()
|
||||
->maxLength(200)
|
||||
->columnSpanFull(),
|
||||
|
||||
RichEditor::make('body')
|
||||
|
||||
@ -34,6 +34,7 @@ use App\Services\RouteForge\RouteForgeService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Backend HTTP entry points for the RouteForge admin tool.
|
||||
@ -125,10 +126,8 @@ final class RouteForgeController extends Controller
|
||||
$query = FlightBundle::query()->orderBy('name');
|
||||
|
||||
if (is_string($search) && $search !== '') {
|
||||
// SQLite + MySQL both fold LIKE case-insensitively for ASCII; the
|
||||
// picker payload is name-keyed so non-ASCII picker UX is a non-issue
|
||||
// at the VA scale this is sized for.
|
||||
$query->where('name', 'like', '%'.$search.'%');
|
||||
$like = DB::connection()->getDriverName() === 'pgsql' ? 'ilike' : 'like';
|
||||
$query->where('name', $like, '%'.$search.'%');
|
||||
}
|
||||
|
||||
$paginated = $query->paginate($perPage);
|
||||
|
||||
@ -20,6 +20,7 @@ use DateTime;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
|
||||
@ -168,15 +169,16 @@ class AcarsController extends Controller
|
||||
}
|
||||
|
||||
try {
|
||||
if (!empty($position['id'])) {
|
||||
Acars::updateOrInsert(
|
||||
['id' => $position['id']],
|
||||
$position
|
||||
);
|
||||
} else {
|
||||
$update = Acars::create($position);
|
||||
$update->save();
|
||||
}
|
||||
DB::transaction(function () use ($position): void {
|
||||
if (!empty($position['id'])) {
|
||||
Acars::updateOrInsert(
|
||||
['id' => $position['id']],
|
||||
$position
|
||||
);
|
||||
} else {
|
||||
Acars::create($position);
|
||||
}
|
||||
});
|
||||
|
||||
$count++;
|
||||
} catch (QueryException $ex) {
|
||||
@ -229,15 +231,16 @@ class AcarsController extends Controller
|
||||
}
|
||||
|
||||
try {
|
||||
if (isset($log['id'])) {
|
||||
Acars::updateOrInsert(
|
||||
['id' => $log['id']],
|
||||
$log
|
||||
);
|
||||
} else {
|
||||
$acars = Acars::create($log);
|
||||
$acars->save();
|
||||
}
|
||||
DB::transaction(function () use ($log): void {
|
||||
if (isset($log['id'])) {
|
||||
Acars::updateOrInsert(
|
||||
['id' => $log['id']],
|
||||
$log
|
||||
);
|
||||
} else {
|
||||
Acars::create($log);
|
||||
}
|
||||
});
|
||||
|
||||
$count++;
|
||||
} catch (QueryException $ex) {
|
||||
@ -281,15 +284,16 @@ class AcarsController extends Controller
|
||||
}
|
||||
|
||||
try {
|
||||
if (isset($log['id'])) {
|
||||
Acars::updateOrInsert(
|
||||
['id' => $log['id']],
|
||||
$log
|
||||
);
|
||||
} else {
|
||||
$acars = Acars::create($log);
|
||||
$acars->save();
|
||||
}
|
||||
DB::transaction(function () use ($log): void {
|
||||
if (isset($log['id'])) {
|
||||
Acars::updateOrInsert(
|
||||
['id' => $log['id']],
|
||||
$log
|
||||
);
|
||||
} else {
|
||||
Acars::create($log);
|
||||
}
|
||||
});
|
||||
|
||||
$count++;
|
||||
} catch (QueryException $ex) {
|
||||
|
||||
@ -31,7 +31,7 @@ class SearchAirportsRequest extends FormRequest
|
||||
{
|
||||
public const array SEARCHABLE_FIELDS = ['iata', 'icao', 'name'];
|
||||
|
||||
public const array SEARCHABLE_OPERATORS = ['=', 'like'];
|
||||
public const array SEARCHABLE_OPERATORS = ['=', 'like', 'ilike'];
|
||||
|
||||
public const array SEARCH_MODES = ['substring', 'prefix'];
|
||||
|
||||
|
||||
@ -294,6 +294,7 @@ class Airport extends Model
|
||||
return [
|
||||
'lat' => 'float',
|
||||
'lon' => 'float',
|
||||
'elevation' => 'integer',
|
||||
'hub' => 'boolean',
|
||||
'ground_handling_cost' => 'float',
|
||||
'fuel_100ll_cost' => 'float',
|
||||
|
||||
@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Models;
|
||||
|
||||
use App\Contracts\Model;
|
||||
use Illuminate\Database\Eloquent\Attributes\WithoutIncrementing;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
@ -35,6 +36,7 @@ use Illuminate\Support\Carbon;
|
||||
*
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
#[WithoutIncrementing]
|
||||
class Event extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
@ -222,20 +222,21 @@ class Flight extends Model
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'flight_number' => 'integer',
|
||||
'days' => 'integer',
|
||||
'level' => 'integer',
|
||||
'distance' => DistanceCast::class,
|
||||
'flight_time' => 'integer',
|
||||
'flight_type' => FlightType::class,
|
||||
'departure_time' => 'datetime:H:i:s',
|
||||
'arrival_time' => 'datetime:H:i:s',
|
||||
'start_date' => 'datetime',
|
||||
'end_date' => 'datetime',
|
||||
'load_factor' => 'double',
|
||||
'load_factor_variance' => 'double',
|
||||
'pilot_pay' => 'float',
|
||||
'has_bid' => 'boolean',
|
||||
'flight_number' => 'integer',
|
||||
'days' => 'integer',
|
||||
'level' => 'integer',
|
||||
'distance' => DistanceCast::class,
|
||||
'flight_time' => 'integer',
|
||||
'flight_type' => FlightType::class,
|
||||
'departure_time' => 'datetime:H:i:s',
|
||||
'arrival_time' => 'datetime:H:i:s',
|
||||
'start_date' => 'datetime',
|
||||
'end_date' => 'datetime',
|
||||
// `load_factor` and `load_factor_variance` double casts are handled by
|
||||
// their Attribute mutators so blank string inputs canonicalize to NULL
|
||||
// rather than causing MySQL strict-mode errors on DECIMAL columns.
|
||||
'pilot_pay' => 'float',
|
||||
'has_bid' => 'boolean',
|
||||
// `route_leg` int cast is handled by the routeLeg() Attribute
|
||||
// mutator so empty / '0' inputs canonicalize to NULL rather than 0.
|
||||
'enabled' => 'boolean',
|
||||
@ -258,7 +259,7 @@ class Flight extends Model
|
||||
/** @noinspection DynamicInvocationViaScopeResolutionInspection */
|
||||
$flights = self::where('enabled', true);
|
||||
foreach ($days as $day) {
|
||||
$flights = $flights->where('days', '&', $day);
|
||||
$flights = $flights->whereRaw('("days" & ?) > 0', [$day]);
|
||||
}
|
||||
|
||||
return $flights;
|
||||
@ -379,6 +380,32 @@ class Flight extends Model
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize `load_factor` — convert blank strings to null
|
||||
* so MySQL strict mode doesn't reject them for the DECIMAL column.
|
||||
* Also handles float casting now that the `double` cast is removed.
|
||||
*/
|
||||
protected function loadFactor(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: static fn (mixed $value): ?float => $value === null ? null : (float) $value,
|
||||
set: static fn (mixed $value): ?float => blank($value) ? null : (float) $value,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonicalize `load_factor_variance` — convert blank strings to null
|
||||
* so MySQL strict mode doesn't reject them for the DECIMAL column.
|
||||
* Also handles float casting now that the `double` cast is removed.
|
||||
*/
|
||||
protected function loadFactorVariance(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: static fn (mixed $value): ?float => $value === null ? null : (float) $value,
|
||||
set: static fn (mixed $value): ?float => blank($value) ? null : (float) $value,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse null / '' / 0 / '0' to canonical NULL for route-key fields.
|
||||
*
|
||||
|
||||
@ -10,7 +10,7 @@ use Illuminate\Support\Carbon;
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $user_field_id
|
||||
* @property string $user_id
|
||||
* @property int $user_id
|
||||
* @property string|null $value
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
@ -42,6 +42,14 @@ class UserFieldValue extends Model
|
||||
|
||||
public static array $rules = [];
|
||||
|
||||
#[\Override]
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'user_id' => 'integer',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return related field's name along with field values
|
||||
*/
|
||||
|
||||
@ -5,6 +5,7 @@ namespace App\Queries;
|
||||
use App\Http\Requests\SearchAirportsRequest;
|
||||
use App\Models\Airport;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Build an Eloquent\Builder for airport listing/search endpoints.
|
||||
@ -31,6 +32,11 @@ class AirportSearchQueryV1
|
||||
{
|
||||
public function __construct(private readonly SearchAirportsRequest $request) {}
|
||||
|
||||
private function likeOperator(): string
|
||||
{
|
||||
return DB::connection()->getDriverName() === 'pgsql' ? 'ilike' : 'like';
|
||||
}
|
||||
|
||||
public function build(): Builder
|
||||
{
|
||||
$data = $this->request->validated();
|
||||
@ -114,7 +120,7 @@ class AirportSearchQueryV1
|
||||
*/
|
||||
private function resolveSearchFields(?string $searchFields, array $searchDataKeys): array
|
||||
{
|
||||
$defaultFields = array_fill_keys(SearchAirportsRequest::SEARCHABLE_FIELDS, 'like');
|
||||
$defaultFields = array_fill_keys(SearchAirportsRequest::SEARCHABLE_FIELDS, $this->likeOperator());
|
||||
if ($searchFields === null || $searchFields === '') {
|
||||
return $defaultFields;
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ namespace App\Queries;
|
||||
use App\Http\Requests\SearchFlightsRequest;
|
||||
use App\Models\Flight;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Builds the Eloquent query for Flight list/search endpoints.
|
||||
@ -19,14 +20,6 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
*/
|
||||
class FlightSearchQuery
|
||||
{
|
||||
/**
|
||||
* Field-specific search allowlist. Mirrors the old
|
||||
* FlightRepository::$fieldSearchable + RequestCriteria's
|
||||
* `?search=field:value;...` syntax. The 'like' entries match the
|
||||
* legacy LIKE behavior; everything else is exact match.
|
||||
*
|
||||
* @var array<string, 'exact'|'like'>
|
||||
*/
|
||||
private const array FIELD_SEARCH = [
|
||||
'arr_airport_id' => 'exact',
|
||||
'callsign' => 'exact',
|
||||
@ -41,6 +34,11 @@ class FlightSearchQuery
|
||||
'notes' => 'like',
|
||||
];
|
||||
|
||||
private function likeOperator(): string
|
||||
{
|
||||
return DB::connection()->getDriverName() === 'pgsql' ? 'ilike' : 'like';
|
||||
}
|
||||
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
@ -75,12 +73,6 @@ class FlightSearchQuery
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the legacy `?search=field:value;field:value` syntax.
|
||||
* Mirrors PirepSearchQuery / UserSearchQuery from earlier phases.
|
||||
*
|
||||
* @param Builder<Flight> $query
|
||||
*/
|
||||
private function applySearch(Builder $query, SearchFlightsRequest $request): void
|
||||
{
|
||||
$search = trim((string) $request->input('search', ''));
|
||||
@ -88,6 +80,8 @@ class FlightSearchQuery
|
||||
return;
|
||||
}
|
||||
|
||||
$like = $this->likeOperator();
|
||||
|
||||
if (str_contains($search, ':')) {
|
||||
$clauses = [];
|
||||
foreach (explode(';', $search) as $pair) {
|
||||
@ -114,10 +108,10 @@ class FlightSearchQuery
|
||||
}
|
||||
|
||||
if ($clauses !== []) {
|
||||
$query->where(function (Builder $q) use ($clauses): void {
|
||||
$query->where(function (Builder $q) use ($clauses, $like): void {
|
||||
foreach ($clauses as [$field, $value, $mode]) {
|
||||
if ($mode === 'like') {
|
||||
$q->orWhere($field, 'like', '%'.$value.'%');
|
||||
$q->orWhere($field, $like, '%'.$value.'%');
|
||||
} else {
|
||||
$q->orWhere($field, '=', $value);
|
||||
}
|
||||
@ -128,9 +122,9 @@ class FlightSearchQuery
|
||||
}
|
||||
}
|
||||
|
||||
$query->where(function (Builder $q) use ($search): void {
|
||||
$query->where(function (Builder $q) use ($search, $like): void {
|
||||
foreach (self::FREE_TEXT_COLUMNS as $column) {
|
||||
$q->orWhere($column, 'like', '%'.$search.'%');
|
||||
$q->orWhere($column, $like, '%'.$search.'%');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ namespace App\Queries;
|
||||
use App\Http\Requests\SearchPirepsRequest;
|
||||
use App\Models\Pirep;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Builds the Eloquent query for PIREP list endpoints.
|
||||
@ -37,6 +38,11 @@ class PirepSearchQuery
|
||||
*/
|
||||
private const array FREE_TEXT_COLUMNS = ['id', 'flight_number'];
|
||||
|
||||
private function likeOperator(): string
|
||||
{
|
||||
return DB::connection()->getDriverName() === 'pgsql' ? 'ilike' : 'like';
|
||||
}
|
||||
|
||||
public function build(SearchPirepsRequest $request): Builder
|
||||
{
|
||||
$query = Pirep::query()
|
||||
@ -92,8 +98,9 @@ class PirepSearchQuery
|
||||
}
|
||||
|
||||
$query->where(function (Builder $q) use ($search): void {
|
||||
$like = $this->likeOperator();
|
||||
foreach (self::FREE_TEXT_COLUMNS as $col) {
|
||||
$q->orWhere($col, 'like', '%'.$search.'%');
|
||||
$q->orWhere($col, $like, '%'.$search.'%');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ use App\Enums\UserState;
|
||||
use App\Http\Requests\SearchUsersRequest;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* Builds the Eloquent query for the public pilots list (`/users`).
|
||||
@ -37,6 +38,15 @@ class UserSearchQuery
|
||||
'state' => '=',
|
||||
];
|
||||
|
||||
private function resolveOperator(string $operator): string
|
||||
{
|
||||
if ($operator !== 'like') {
|
||||
return $operator;
|
||||
}
|
||||
|
||||
return $this->likeOperator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Free-text search columns (when search has no `field:` prefix).
|
||||
*
|
||||
@ -44,6 +54,11 @@ class UserSearchQuery
|
||||
*/
|
||||
private const array FREE_TEXT_COLUMNS = ['name', 'email'];
|
||||
|
||||
private function likeOperator(): string
|
||||
{
|
||||
return DB::connection()->getDriverName() === 'pgsql' ? 'ilike' : 'like';
|
||||
}
|
||||
|
||||
public function build(SearchUsersRequest $request): Builder
|
||||
{
|
||||
$query = User::query()
|
||||
@ -109,14 +124,14 @@ class UserSearchQuery
|
||||
continue;
|
||||
}
|
||||
|
||||
$clauses[] = [$field, self::FIELD_SEARCH[$field], $value];
|
||||
$clauses[] = [$field, $this->resolveOperator(self::FIELD_SEARCH[$field]), $value];
|
||||
}
|
||||
|
||||
if ($clauses !== []) {
|
||||
$query->where(function (Builder $q) use ($clauses): void {
|
||||
foreach ($clauses as [$field, $operator, $value]) {
|
||||
if ($operator === 'like') {
|
||||
$q->orWhere($field, 'like', '%'.$value.'%');
|
||||
if (in_array($operator, ['like', 'ilike'], true)) {
|
||||
$q->orWhere($field, $operator, '%'.$value.'%');
|
||||
} else {
|
||||
$q->orWhere($field, '=', $value);
|
||||
}
|
||||
@ -130,9 +145,10 @@ class UserSearchQuery
|
||||
}
|
||||
|
||||
// Free-text: OR across name + email
|
||||
$query->where(function (Builder $q) use ($search): void {
|
||||
$like = $this->likeOperator();
|
||||
$query->where(function (Builder $q) use ($search, $like): void {
|
||||
foreach (self::FREE_TEXT_COLUMNS as $col) {
|
||||
$q->orWhere($col, 'like', '%'.$search.'%');
|
||||
$q->orWhere($col, $like, '%'.$search.'%');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -179,16 +179,32 @@ class FlightService extends Service
|
||||
}
|
||||
|
||||
// Match nullable scalar columns including legacy empty-string values.
|
||||
// Stored values may be NULL, '', or an actual scalar; treat empty as
|
||||
// equivalent to null so casts that coerce '' to 0 (e.g. integer cast
|
||||
// on route_leg) still resolve correctly.
|
||||
foreach (['route_code', 'route_leg', 'days'] as $column) {
|
||||
// route_code is a string column — empty strings are valid on all DBs.
|
||||
// route_leg and days are integer columns — PG cannot compare int to '',
|
||||
// so only check null and 0.
|
||||
$stringColumns = ['route_code'];
|
||||
$integerColumns = ['route_leg', 'days'];
|
||||
|
||||
foreach ($stringColumns as $column) {
|
||||
$value = $flight->{$column};
|
||||
|
||||
if (in_array($value, [null, '', '0'], true)) {
|
||||
$query->where(function ($q) use ($column): void {
|
||||
$q->whereNull($column)
|
||||
->orWhere($column, '')
|
||||
->orWhere($column, 0);
|
||||
});
|
||||
} else {
|
||||
$query->where($column, $value);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($integerColumns as $column) {
|
||||
$value = $flight->{$column};
|
||||
|
||||
if (in_array($value, [null, '', 0, '0'], true)) {
|
||||
$query->where(function ($q) use ($column): void {
|
||||
$q->whereNull($column)
|
||||
->orWhere($column, '')
|
||||
->orWhere($column, 0);
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -58,6 +58,10 @@ class AirportImporter extends ImportExport
|
||||
$row['fuel_jeta_cost'] = (float) $row['fuel_jeta_cost'];
|
||||
}
|
||||
|
||||
$row['elevation'] = is_numeric($row['elevation'] ?? '') ? (int) $row['elevation'] : null;
|
||||
$row['fuel_100ll_cost'] = is_numeric($row['fuel_100ll_cost'] ?? '') ? (float) $row['fuel_100ll_cost'] : null;
|
||||
$row['fuel_mogas_cost'] = is_numeric($row['fuel_mogas_cost'] ?? '') ? (float) $row['fuel_mogas_cost'] : null;
|
||||
|
||||
try {
|
||||
Airport::updateOrCreate([
|
||||
'id' => $row['icao'],
|
||||
|
||||
@ -46,8 +46,8 @@ class FlightImporter extends ImportExport
|
||||
'distance' => 'nullable|numeric',
|
||||
'flight_time' => 'required|integer',
|
||||
'flight_type' => 'required|alpha',
|
||||
'load_factor' => 'nullable',
|
||||
'load_factor_variance' => 'nullable',
|
||||
'load_factor' => 'nullable|numeric|min:0|max:100',
|
||||
'load_factor_variance' => 'nullable|numeric|min:0|max:100',
|
||||
'pilot_pay' => 'nullable',
|
||||
'route' => 'nullable',
|
||||
'notes' => 'nullable',
|
||||
@ -226,9 +226,9 @@ class FlightImporter extends ImportExport
|
||||
$this->processAirport($row['alt_airport']);
|
||||
}
|
||||
|
||||
$this->processSubfleets($flight, $row['subfleets']);
|
||||
$this->processFares($flight, $row['fares']);
|
||||
$this->processFields($flight, $row['fields']);
|
||||
$this->processSubfleets($flight, $row['subfleets'] ?? '');
|
||||
$this->processFares($flight, $row['fares'] ?? '');
|
||||
$this->processFields($flight, $row['fields'] ?? '');
|
||||
|
||||
$this->log('Imported row '.($index + 1));
|
||||
|
||||
|
||||
@ -70,8 +70,8 @@ class SubfleetImporter extends ImportExport
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->processFares($subfleet, $row['fares']);
|
||||
$this->processRanks($subfleet, $row['ranks']);
|
||||
$this->processFares($subfleet, $row['fares'] ?? '');
|
||||
$this->processRanks($subfleet, $row['ranks'] ?? '');
|
||||
|
||||
$this->log('Imported '.$row['type']);
|
||||
|
||||
|
||||
@ -85,10 +85,11 @@ class ImportService extends Service
|
||||
$records = $reader->getRecords($header_rows);
|
||||
foreach ($records as $offset => $row) {
|
||||
// turn it into a collection and run some filtering
|
||||
$row = collect($row)->map(function ($val, $index): string {
|
||||
$row = collect($row)->map(function ($val, $index): ?string {
|
||||
$val = trim($val);
|
||||
$val = str_ireplace(['\\n', '\\r'], '', $val);
|
||||
|
||||
return str_ireplace(['\\n', '\\r'], '', $val);
|
||||
return $val === '' ? null : $val;
|
||||
})->toArray();
|
||||
|
||||
// Try to validate
|
||||
|
||||
@ -443,9 +443,9 @@ class PirepService extends Service
|
||||
|
||||
// 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) {
|
||||
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) {
|
||||
} elseif ($pirep->source === PirepSource::MANUAL && $pirep->user->rank?->auto_approve_manual) {
|
||||
$default_state = PirepState::ACCEPTED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Auth\Events\Registered;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@ -208,12 +209,15 @@ class UserService extends Service
|
||||
return $user;
|
||||
}
|
||||
|
||||
$user->pilot_id = $this->getNextAvailablePilotId();
|
||||
$user->save();
|
||||
return DB::transaction(function () use ($user): User {
|
||||
$maxPilotId = (int) User::withTrashed()->max('pilot_id');
|
||||
$user->pilot_id = $maxPilotId + 1;
|
||||
$user->save();
|
||||
|
||||
Log::info('Set pilot ID for user '.$user->id.' to '.$user->pilot_id);
|
||||
Log::info('Set pilot ID for user '.$user->id.' to '.$user->pilot_id);
|
||||
|
||||
return $user;
|
||||
return $user;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,19 +240,21 @@ class UserService extends Service
|
||||
return $user;
|
||||
}
|
||||
|
||||
if ($this->isPilotIdAlreadyUsed($pilot_id)) {
|
||||
Log::error('User with id '.$pilot_id.' already exists');
|
||||
return DB::transaction(function () use ($user, $pilot_id): User {
|
||||
if (User::where('pilot_id', '=', $pilot_id)->exists()) {
|
||||
Log::error('User with id '.$pilot_id.' already exists');
|
||||
|
||||
throw new UserPilotIdExists($user);
|
||||
}
|
||||
throw new UserPilotIdExists($user);
|
||||
}
|
||||
|
||||
$old_id = $user->pilot_id;
|
||||
$user->pilot_id = $pilot_id;
|
||||
$user->save();
|
||||
$old_id = $user->pilot_id;
|
||||
$user->pilot_id = $pilot_id;
|
||||
$user->save();
|
||||
|
||||
Log::info('Changed pilot ID for user '.$user->id.' from '.$old_id.' to '.$user->pilot_id);
|
||||
Log::info('Changed pilot ID for user '.$user->id.' from '.$old_id.' to '.$user->pilot_id);
|
||||
|
||||
return $user;
|
||||
return $user;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -268,12 +274,12 @@ class UserService extends Service
|
||||
|
||||
/** @var Airline $airline */
|
||||
foreach ($airlines as $airline) {
|
||||
if (str_contains($pilot_id, $airline->icao)) {
|
||||
if (str_starts_with($pilot_id, $airline->icao)) {
|
||||
$ident_str = $airline->icao;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($airline->iata) && str_contains($pilot_id, (string) $airline->iata)) {
|
||||
if (!empty($airline->iata) && str_starts_with($pilot_id, (string) $airline->iata)) {
|
||||
$ident_str = $airline->iata;
|
||||
break;
|
||||
}
|
||||
@ -284,6 +290,10 @@ class UserService extends Service
|
||||
}
|
||||
|
||||
$parsed_pilot_id = str_replace($ident_str, '', $pilot_id);
|
||||
if ($parsed_pilot_id === '' || !ctype_digit($parsed_pilot_id)) {
|
||||
throw new PilotIdNotFound($pilot_id);
|
||||
}
|
||||
|
||||
$user = User::where(['airline_id' => $airline->id, 'pilot_id' => $parsed_pilot_id])->first();
|
||||
if (empty($user)) {
|
||||
throw new PilotIdNotFound($pilot_id);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "phpvms/phpvms",
|
||||
"description": "phpVMS - Virtual Airline Administration",
|
||||
"version": "8.0",
|
||||
"keywords": [
|
||||
"phpvms",
|
||||
"virtual",
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/** @noinspection PhpIllegalPsrClassPathInspection */
|
||||
|
||||
namespace Database\Factories;
|
||||
@ -29,9 +31,9 @@ class AcarsFactory extends Factory
|
||||
'id' => null,
|
||||
'pirep_id' => null,
|
||||
'log' => fake()->text(100),
|
||||
'lat' => fake()->latitude,
|
||||
'lon' => fake()->longitude,
|
||||
'distance' => fake()->randomFloat(2, 0, 6000),
|
||||
'lat' => fake()->latitude(),
|
||||
'lon' => fake()->longitude(),
|
||||
'distance' => fake()->numberBetween(0, 6000),
|
||||
'heading' => fake()->numberBetween(0, 359),
|
||||
'altitude_agl' => fake()->numberBetween(20, 400),
|
||||
'altitude_msl' => fake()->numberBetween(20, 400),
|
||||
|
||||
@ -40,8 +40,8 @@ class AircraftFactory extends Factory
|
||||
return [
|
||||
'subfleet_id' => fn () => Subfleet::factory()->create()->id,
|
||||
'airport_id' => fn () => Airport::factory()->create()->id,
|
||||
'iata' => fake()->unique()->text(5),
|
||||
'icao' => fake()->unique()->text(5),
|
||||
'iata' => fake()->unique()->lexify('???'),
|
||||
'icao' => fake()->unique()->lexify('????'),
|
||||
'name' => fake()->text(50),
|
||||
'registration' => fake()->unique()->text(10),
|
||||
'hex_code' => ICAO::createHexCode(),
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Event;
|
||||
@ -20,6 +22,7 @@ class EventFactory extends Factory
|
||||
$startDate = fake()->dateTimeBetween('-1 month', '+1 month');
|
||||
|
||||
return [
|
||||
'id' => fake()->unique()->randomNumber(5),
|
||||
'type' => fake()->numberBetween(),
|
||||
'name' => fake()->text(50),
|
||||
'description' => fake()->text(150),
|
||||
|
||||
@ -32,7 +32,7 @@ class ExpenseFactory extends Factory
|
||||
return [
|
||||
'airline_id' => null,
|
||||
'name' => fake()->text(20),
|
||||
'amount' => fake()->randomFloat(2, 100, 1000),
|
||||
'amount' => fake()->numberBetween(100, 1000),
|
||||
'type' => ExpenseType::FLIGHT,
|
||||
'multiplier' => false,
|
||||
'ref_model_type' => Expense::class,
|
||||
|
||||
@ -31,8 +31,8 @@ class NewsFactory extends Factory
|
||||
{
|
||||
return [
|
||||
'user_id' => fn () => User::factory()->create()->id,
|
||||
'subject' => fake()->text(),
|
||||
'body' => fake()->sentence(),
|
||||
'subject' => fake()->sentence(),
|
||||
'body' => fake()->text(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ class PirepFactory extends Factory
|
||||
'planned_distance' => fake()->randomFloat(2, 0, 6000),
|
||||
'flight_time' => fake()->numberBetween(60, 360),
|
||||
'planned_flight_time' => fake()->numberBetween(60, 360),
|
||||
'zfw' => fake()->randomFloat(2),
|
||||
'zfw' => fake()->randomFloat(2, 0, 500000),
|
||||
'block_fuel' => fake()->randomFloat(2, 0, 1000),
|
||||
'fuel_used' => fn (array $pirep): float => round($pirep['block_fuel'] * .9, 2),
|
||||
'block_on_time' => Carbon::now('UTC'),
|
||||
|
||||
@ -12,7 +12,7 @@ return new class() extends Migration
|
||||
public function up(): void
|
||||
{
|
||||
if (!Schema::hasTable('migrations_data')) {
|
||||
Schema::create('migrations_data', function (Blueprint $table) {
|
||||
Schema::create('migrations_data', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -23,7 +23,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('users')) {
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
Schema::create('users', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -67,7 +67,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('acars')) {
|
||||
Schema::create('acars', function (Blueprint $table) {
|
||||
Schema::create('acars', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -100,7 +100,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('activity_log')) {
|
||||
Schema::create('activity_log', function (Blueprint $table) {
|
||||
Schema::create('activity_log', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -122,7 +122,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('aircraft')) {
|
||||
Schema::create('aircraft', function (Blueprint $table) {
|
||||
Schema::create('aircraft', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -145,7 +145,7 @@ return new class() extends Migration
|
||||
$table->string('simbrief_type', 25)->nullable();
|
||||
$table->decimal('fuel_onboard')->unsigned()->nullable()->default(0);
|
||||
$table->unsignedBigInteger('flight_time')->nullable()->default(0);
|
||||
$table->char('status', 1)->default('A');
|
||||
$table->string('status', 1)->default('A');
|
||||
$table->unsignedTinyInteger('state')->default(0);
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
@ -153,7 +153,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('airlines')) {
|
||||
Schema::create('airlines', function (Blueprint $table) {
|
||||
Schema::create('airlines', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -175,7 +175,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('airports')) {
|
||||
Schema::create('airports', function (Blueprint $table) {
|
||||
Schema::create('airports', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -201,7 +201,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('awards')) {
|
||||
Schema::create('awards', function (Blueprint $table) {
|
||||
Schema::create('awards', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -218,7 +218,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('bids')) {
|
||||
Schema::create('bids', function (Blueprint $table) {
|
||||
Schema::create('bids', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -233,7 +233,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('events')) {
|
||||
Schema::create('events', function (Blueprint $table) {
|
||||
Schema::create('events', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -249,7 +249,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('expenses')) {
|
||||
Schema::create('expenses', function (Blueprint $table) {
|
||||
Schema::create('expenses', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -257,7 +257,7 @@ return new class() extends Migration
|
||||
$table->unsignedInteger('airline_id')->nullable();
|
||||
$table->string('name');
|
||||
$table->unsignedInteger('amount');
|
||||
$table->char('type');
|
||||
$table->string('type', 1);
|
||||
$table->string('flight_type', 50)->nullable();
|
||||
$table->boolean('charge_to_user')->nullable()->default(false);
|
||||
$table->boolean('multiplier')->nullable()->default(false);
|
||||
@ -271,7 +271,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('failed_jobs')) {
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
Schema::create('failed_jobs', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -285,7 +285,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('fares')) {
|
||||
Schema::create('fares', function (Blueprint $table) {
|
||||
Schema::create('fares', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -304,7 +304,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('files')) {
|
||||
Schema::create('files', function (Blueprint $table) {
|
||||
Schema::create('files', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -324,7 +324,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('flight_fare')) {
|
||||
Schema::create('flight_fare', function (Blueprint $table) {
|
||||
Schema::create('flight_fare', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -340,7 +340,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('flight_field_values')) {
|
||||
Schema::create('flight_field_values', function (Blueprint $table) {
|
||||
Schema::create('flight_field_values', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -354,7 +354,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('flight_fields')) {
|
||||
Schema::create('flight_fields', function (Blueprint $table) {
|
||||
Schema::create('flight_fields', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -365,7 +365,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('flight_subfleet')) {
|
||||
Schema::create('flight_subfleet', function (Blueprint $table) {
|
||||
Schema::create('flight_subfleet', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -379,7 +379,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('flights')) {
|
||||
Schema::create('flights', function (Blueprint $table) {
|
||||
Schema::create('flights', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -397,7 +397,7 @@ return new class() extends Migration
|
||||
$table->unsignedInteger('level')->nullable()->default(0);
|
||||
$table->decimal('distance')->unsigned()->nullable()->default(0);
|
||||
$table->unsignedInteger('flight_time')->nullable();
|
||||
$table->char('flight_type', 1)->default('J');
|
||||
$table->string('flight_type', 1)->default('J');
|
||||
$table->decimal('load_factor', 5)->nullable();
|
||||
$table->decimal('load_factor_variance', 5)->nullable();
|
||||
$table->text('route')->nullable();
|
||||
@ -422,7 +422,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('invites')) {
|
||||
Schema::create('invites', function (Blueprint $table) {
|
||||
Schema::create('invites', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -437,7 +437,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('jobs')) {
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
Schema::create('jobs', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -452,7 +452,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('journal_transactions')) {
|
||||
Schema::create('journal_transactions', function (Blueprint $table) {
|
||||
Schema::create('journal_transactions', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -475,7 +475,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('journals')) {
|
||||
Schema::create('journals', function (Blueprint $table) {
|
||||
Schema::create('journals', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -493,7 +493,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('kvp')) {
|
||||
Schema::create('kvp', function (Blueprint $table) {
|
||||
Schema::create('kvp', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -503,7 +503,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('ledgers')) {
|
||||
Schema::create('ledgers', function (Blueprint $table) {
|
||||
Schema::create('ledgers', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -515,7 +515,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('navdata')) {
|
||||
Schema::create('navdata', function (Blueprint $table) {
|
||||
Schema::create('navdata', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -531,7 +531,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('news')) {
|
||||
Schema::create('news', function (Blueprint $table) {
|
||||
Schema::create('news', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -544,7 +544,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('notifications')) {
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
Schema::create('notifications', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -552,7 +552,7 @@ return new class() extends Migration
|
||||
$table->string('type');
|
||||
$table->string('notifiable_type');
|
||||
$table->unsignedBigInteger('notifiable_id');
|
||||
$table->text('data');
|
||||
$table->json('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
@ -561,7 +561,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('pages')) {
|
||||
Schema::create('pages', function (Blueprint $table) {
|
||||
Schema::create('pages', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -580,7 +580,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('password_resets')) {
|
||||
Schema::create('password_resets', function (Blueprint $table) {
|
||||
Schema::create('password_resets', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -633,7 +633,7 @@ return new class() extends Migration
|
||||
}*/
|
||||
|
||||
if (!Schema::hasTable('pirep_comments')) {
|
||||
Schema::create('pirep_comments', function (Blueprint $table) {
|
||||
Schema::create('pirep_comments', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -646,7 +646,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('pirep_fares')) {
|
||||
Schema::create('pirep_fares', function (Blueprint $table) {
|
||||
Schema::create('pirep_fares', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -665,7 +665,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('pirep_field_values')) {
|
||||
Schema::create('pirep_field_values', function (Blueprint $table) {
|
||||
Schema::create('pirep_field_values', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -680,7 +680,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('pirep_fields')) {
|
||||
Schema::create('pirep_fields', function (Blueprint $table) {
|
||||
Schema::create('pirep_fields', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -694,7 +694,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('pireps')) {
|
||||
Schema::create('pireps', function (Blueprint $table) {
|
||||
Schema::create('pireps', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -707,7 +707,7 @@ return new class() extends Migration
|
||||
$table->string('flight_number', 10)->nullable()->index();
|
||||
$table->string('route_code', 5)->nullable();
|
||||
$table->string('route_leg', 5)->nullable();
|
||||
$table->char('flight_type', 1)->default('J');
|
||||
$table->string('flight_type', 1)->default('J');
|
||||
$table->string('dpt_airport_id', 5)->index();
|
||||
$table->string('arr_airport_id', 5)->index();
|
||||
$table->string('alt_airport_id', 5)->nullable();
|
||||
@ -726,7 +726,7 @@ return new class() extends Migration
|
||||
$table->unsignedTinyInteger('source')->nullable()->default(0);
|
||||
$table->string('source_name', 50)->nullable();
|
||||
$table->unsignedSmallInteger('state')->default(1);
|
||||
$table->char('status', 3)->default('SCH');
|
||||
$table->string('status', 3)->default('SCH');
|
||||
$table->dateTime('submitted_at')->nullable();
|
||||
$table->dateTime('block_off_time')->nullable();
|
||||
$table->dateTime('block_on_time')->nullable();
|
||||
@ -736,7 +736,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('ranks')) {
|
||||
Schema::create('ranks', function (Blueprint $table) {
|
||||
Schema::create('ranks', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -786,7 +786,7 @@ return new class() extends Migration
|
||||
}*/
|
||||
|
||||
if (!Schema::hasTable('sessions')) {
|
||||
Schema::create('sessions', function (Blueprint $table) {
|
||||
Schema::create('sessions', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -800,7 +800,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('settings')) {
|
||||
Schema::create('settings', function (Blueprint $table) {
|
||||
Schema::create('settings', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -820,7 +820,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('simbrief')) {
|
||||
Schema::create('simbrief', function (Blueprint $table) {
|
||||
Schema::create('simbrief', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -840,7 +840,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('simbrief_aircraft')) {
|
||||
Schema::create('simbrief_aircraft', function (Blueprint $table) {
|
||||
Schema::create('simbrief_aircraft', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -853,7 +853,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('simbrief_airframes')) {
|
||||
Schema::create('simbrief_airframes', function (Blueprint $table) {
|
||||
Schema::create('simbrief_airframes', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -869,7 +869,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('simbrief_layouts')) {
|
||||
Schema::create('simbrief_layouts', function (Blueprint $table) {
|
||||
Schema::create('simbrief_layouts', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -881,7 +881,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('stats')) {
|
||||
Schema::create('stats', function (Blueprint $table) {
|
||||
Schema::create('stats', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -895,7 +895,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('subfleet_fare')) {
|
||||
Schema::create('subfleet_fare', function (Blueprint $table) {
|
||||
Schema::create('subfleet_fare', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -912,7 +912,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('subfleet_rank')) {
|
||||
Schema::create('subfleet_rank', function (Blueprint $table) {
|
||||
Schema::create('subfleet_rank', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -927,7 +927,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('subfleets')) {
|
||||
Schema::create('subfleets', function (Blueprint $table) {
|
||||
Schema::create('subfleets', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -950,7 +950,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('typerating_subfleet')) {
|
||||
Schema::create('typerating_subfleet', function (Blueprint $table) {
|
||||
Schema::create('typerating_subfleet', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -963,7 +963,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('typerating_user')) {
|
||||
Schema::create('typerating_user', function (Blueprint $table) {
|
||||
Schema::create('typerating_user', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -976,7 +976,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('typeratings')) {
|
||||
Schema::create('typeratings', function (Blueprint $table) {
|
||||
Schema::create('typeratings', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -993,7 +993,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('user_awards')) {
|
||||
Schema::create('user_awards', function (Blueprint $table) {
|
||||
Schema::create('user_awards', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -1007,7 +1007,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('user_field_values')) {
|
||||
Schema::create('user_field_values', function (Blueprint $table) {
|
||||
Schema::create('user_field_values', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -1022,7 +1022,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('user_fields')) {
|
||||
Schema::create('user_fields', function (Blueprint $table) {
|
||||
Schema::create('user_fields', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -1039,7 +1039,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (!Schema::hasTable('user_oauth_tokens')) {
|
||||
Schema::create('user_oauth_tokens', function (Blueprint $table) {
|
||||
Schema::create('user_oauth_tokens', function (Blueprint $table): void {
|
||||
$table->collation = 'utf8mb4_unicode_ci';
|
||||
$table->charset = 'utf8mb4';
|
||||
|
||||
@ -1054,7 +1054,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (Schema::hasTable('permission_role')) {
|
||||
Schema::table('permission_role', function (Blueprint $table) {
|
||||
Schema::table('permission_role', function (Blueprint $table): void {
|
||||
// Check if the foreign key already exists
|
||||
// See https://github.com/laravel/framework/discussions/43443
|
||||
$foreignKeys = collect(Schema::getForeignKeys('permission_role'));
|
||||
@ -1074,7 +1074,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (Schema::hasTable('permission_user')) {
|
||||
Schema::table('permission_user', function (Blueprint $table) {
|
||||
Schema::table('permission_user', function (Blueprint $table): void {
|
||||
$foreignKeys = collect(Schema::getForeignKeys('permission_user'));
|
||||
|
||||
if ($foreignKeys->where('name', 'permission_user_permission_id_foreign')->count() === 0) {
|
||||
@ -1086,7 +1086,7 @@ return new class() extends Migration
|
||||
}
|
||||
|
||||
if (Schema::hasTable('role_user')) {
|
||||
Schema::table('role_user', function (Blueprint $table) {
|
||||
Schema::table('role_user', function (Blueprint $table): void {
|
||||
$foreignKeys = collect(Schema::getForeignKeys('role_user'));
|
||||
|
||||
if ($foreignKeys->where('name', 'role_user_role_id_foreign')->count() === 0) {
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class() extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('airlines', function (Blueprint $table): void {
|
||||
$table->string('icao', 12)->change();
|
||||
$table->string('iata', 12)->nullable()->change();
|
||||
$table->string('country', 3)->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('airlines', function (Blueprint $table): void {
|
||||
$table->string('icao', 5)->change();
|
||||
$table->string('iata', 5)->nullable()->change();
|
||||
$table->string('country', 2)->nullable()->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class() extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('activity_log', function (Blueprint $table): void {
|
||||
$table->string('subject_id', 128)->nullable()->change();
|
||||
$table->string('batch_uuid', 36)->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('activity_log', function (Blueprint $table): void {
|
||||
$table->char('subject_id', 36)->nullable()->change();
|
||||
$table->char('batch_uuid', 36)->nullable()->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -1,8 +0,0 @@
|
||||
[env]
|
||||
BUILDKIT_HOST = "docker-container://buildkit"
|
||||
|
||||
[tasks.setup]
|
||||
run = ["mise install", "mise run run-buildkit-container || true"]
|
||||
|
||||
[tasks.run-buildkit-container]
|
||||
run = "docker run --rm --privileged -d --name buildkit -e BUILDKIT_DEBUG=1 moby/buildkit:latest"
|
||||
@ -31,9 +31,9 @@
|
||||
<env name="BCRYPT_ROUNDS" value="4" force="true"/>
|
||||
<env name="BROADCAST_CONNECTION" value="null" force="true"/>
|
||||
<env name="CACHE_STORE" value="array" force="true"/>
|
||||
<env name="DB_CONNECTION" value="sqlite" force="true"/>
|
||||
<env name="DB_DATABASE" value=":memory:" force="true"/>
|
||||
<env name="DB_URL" value="" force="true"/>
|
||||
<env name="DB_CONNECTION" value="sqlite"/>
|
||||
<env name="DB_DATABASE" value=":memory:"/>
|
||||
<env name="DB_URL" value=""/>
|
||||
<env name="MAIL_MAILER" value="array" force="true"/>
|
||||
<env name="QUEUE_CONNECTION" value="sync" force="true"/>
|
||||
<env name="SESSION_DRIVER" value="array" force="true"/>
|
||||
|
||||
32
resources/mise/php.ini
Normal file
32
resources/mise/php.ini
Normal file
@ -0,0 +1,32 @@
|
||||
; php.ini - Minimal Testing Configuration
|
||||
|
||||
error_reporting = E_ALL
|
||||
display_errors = On
|
||||
display_startup_errors = On
|
||||
log_errors = On
|
||||
html_errors = On
|
||||
|
||||
memory_limit = -1
|
||||
upload_max_filesize = 100M
|
||||
post_max_size = 100M
|
||||
max_execution_time = 300
|
||||
max_input_time = 300
|
||||
|
||||
variables_order = "EGPCS"
|
||||
default_socket_timeout = 60
|
||||
date.timezone = UTC
|
||||
session.use_strict_mode = 1
|
||||
session.use_cookies = 1
|
||||
session.use_only_cookies = 1
|
||||
|
||||
extension_dir = "/opt/homebrew/lib/php/pecl/20250925"
|
||||
|
||||
; Common Extensions (Uncomment as needed)
|
||||
; extension=curl
|
||||
; extension=gd
|
||||
; extension=mbstring
|
||||
; extension=openssl
|
||||
; extension=pdo_mysql
|
||||
|
||||
; On windows:
|
||||
;extension_dir = "ext"
|
||||
@ -261,6 +261,7 @@ it('can retrieve an airport', function (): void {
|
||||
apiAs($user);
|
||||
|
||||
$airport = Airport::factory()->create();
|
||||
$airport->refresh();
|
||||
|
||||
$response = $this->get('/api/airports/'.$airport->icao);
|
||||
|
||||
|
||||
@ -234,11 +234,11 @@ test('plain search matches free text columns', function (): void {
|
||||
/** @var Flight $target */
|
||||
$target = Flight::factory()->create([
|
||||
'dpt_airport_id' => 'KLAX',
|
||||
'callsign' => 'SEARCHME',
|
||||
'callsign' => 'SCH',
|
||||
]);
|
||||
Flight::factory()->create([
|
||||
'dpt_airport_id' => 'KJFK',
|
||||
'callsign' => 'IGNOREME',
|
||||
'callsign' => 'IGN',
|
||||
]);
|
||||
|
||||
$results = flightSearchRun(['search' => 'LAX']);
|
||||
|
||||
@ -1189,6 +1189,7 @@ test('daily expenses are applied', function (): void {
|
||||
'airline_id' => null,
|
||||
'type' => ExpenseType::DAILY,
|
||||
]);
|
||||
$expense->refresh();
|
||||
|
||||
/** @var RecurringFinanceService $recurringFService */
|
||||
$recurringFService = app(RecurringFinanceService::class);
|
||||
@ -1199,15 +1200,12 @@ test('daily expenses are applied', function (): void {
|
||||
'ref_model_type' => Expense::class,
|
||||
'ref_model_id' => $expense->id,
|
||||
'debit' => Money::createFromAmount($expense->amount)->toAmount(),
|
||||
'post_date' => Carbon::getTestNow(),
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('journal_transactions', [
|
||||
'journal_id' => $airline2->journal->id,
|
||||
'ref_model_type' => Expense::class,
|
||||
'ref_model_id' => $expense->id,
|
||||
'debit' => Money::createFromAmount($expense->amount)->toAmount(),
|
||||
'post_date' => Carbon::getTestNow(),
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@ -250,7 +250,7 @@ test('aircraft exporter', function (): void {
|
||||
$collection = collect([$aircraft]);
|
||||
$file = $exporter->exportAircraft($collection);
|
||||
|
||||
$status = $importer->importAircraft($file);
|
||||
$status = $importer->importAircraft($file, delete_previous: false);
|
||||
expect($status['success'])->toHaveCount(1)
|
||||
->and($status['errors'])->toHaveCount(0);
|
||||
});
|
||||
@ -272,7 +272,7 @@ test('airport exporter', function (): void {
|
||||
$importer = app(ImportService::class);
|
||||
$exporter = app(ExportService::class);
|
||||
$file = $exporter->exportAirports(collect([$airport]));
|
||||
$status = $importer->importAirports($file);
|
||||
$status = $importer->importAirports($file, delete_previous: false);
|
||||
|
||||
expect($status['success'])->toHaveCount(1)
|
||||
->and($status['errors'])->toHaveCount(0);
|
||||
@ -330,7 +330,7 @@ test('flight exporter', function (): void {
|
||||
$importer = app(ImportService::class);
|
||||
$exporter = app(ExportService::class);
|
||||
$file = $exporter->exportFlights(collect([$flight]));
|
||||
$status = $importer->importFlights($file);
|
||||
$status = $importer->importFlights($file, delete_previous: '');
|
||||
expect($status['success'])->toHaveCount(1)
|
||||
->and($status['errors'])->toHaveCount(0);
|
||||
});
|
||||
@ -339,14 +339,14 @@ test('invalid file import', function (): void {
|
||||
// $this->expectException(ValidationException::class);
|
||||
$file_path = base_path('tests/data/aircraft.csv');
|
||||
$importer = app(ImportService::class);
|
||||
$status = $importer->importAirports($file_path);
|
||||
$status = $importer->importAirports($file_path, delete_previous: false);
|
||||
expect($status['errors'])->toHaveCount(2);
|
||||
});
|
||||
|
||||
test('empty cols', function (): void {
|
||||
$file_path = base_path('tests/data/expenses_empty_rows.csv');
|
||||
$importer = app(ImportService::class);
|
||||
$status = $importer->importExpenses($file_path);
|
||||
$status = $importer->importExpenses($file_path, delete_previous: false);
|
||||
expect($status['success'])->toHaveCount(8)
|
||||
->and($status['errors'])->toHaveCount(0);
|
||||
});
|
||||
@ -367,7 +367,7 @@ test('expense exporter', function (): void {
|
||||
$importer = app(ImportService::class);
|
||||
$exporter = app(ExportService::class);
|
||||
$file = $exporter->exportExpenses(collect([$expense]));
|
||||
$status = $importer->importExpenses($file);
|
||||
$status = $importer->importExpenses($file, delete_previous: false);
|
||||
|
||||
expect($status['success'])->toHaveCount(1)
|
||||
->and($status['errors'])->toHaveCount(0);
|
||||
@ -383,7 +383,7 @@ test('expense importer', function (): void {
|
||||
|
||||
$importer = app(ImportService::class);
|
||||
$file_path = base_path('tests/data/expenses.csv');
|
||||
$status = $importer->importExpenses($file_path);
|
||||
$status = $importer->importExpenses($file_path, delete_previous: false);
|
||||
|
||||
expect($status['success'])->toHaveCount(8)
|
||||
->and($status['errors'])->toHaveCount(0);
|
||||
@ -414,7 +414,7 @@ test('expense importer', function (): void {
|
||||
test('fare importer', function (): void {
|
||||
$file_path = base_path('tests/data/fares.csv');
|
||||
$importer = app(ImportService::class);
|
||||
$status = $importer->importFares($file_path);
|
||||
$status = $importer->importFares($file_path, delete_previous: false);
|
||||
|
||||
expect($status['success'])->toHaveCount(4)
|
||||
->and($status['errors'])->toHaveCount(0);
|
||||
@ -591,7 +591,7 @@ test('aircraft importer', function (): void {
|
||||
$importer = app(ImportService::class);
|
||||
// $subfleet = \App\Models\Subfleet::factory()->create(['type' => 'A32X']);
|
||||
$file_path = base_path('tests/data/aircraft.csv');
|
||||
$status = $importer->importAircraft($file_path);
|
||||
$status = $importer->importAircraft($file_path, delete_previous: false);
|
||||
|
||||
expect($status['success'])->toHaveCount(1)
|
||||
->and($status['errors'])->toHaveCount(1);
|
||||
@ -615,7 +615,7 @@ test('aircraft importer', function (): void {
|
||||
// Now try importing the updated file, the status for the aircraft should change
|
||||
// to being stored
|
||||
$file_path = base_path('tests/data/aircraft-update.csv');
|
||||
$status = $importer->importAircraft($file_path);
|
||||
$status = $importer->importAircraft($file_path, delete_previous: false);
|
||||
expect($status['success'])->toHaveCount(1);
|
||||
|
||||
$aircraft = Aircraft::where([
|
||||
@ -628,7 +628,7 @@ test('aircraft importer', function (): void {
|
||||
test('airport importer', function (): void {
|
||||
$importer = app(ImportService::class);
|
||||
$file_path = base_path('tests/data/airports.csv');
|
||||
$status = $importer->importAirports($file_path);
|
||||
$status = $importer->importAirports($file_path, delete_previous: false);
|
||||
|
||||
expect($status['success'])->toHaveCount(2)
|
||||
->and($status['errors'])->toHaveCount(1);
|
||||
@ -648,8 +648,8 @@ test('airport importer', function (): void {
|
||||
->and($airport->country)->toEqual('US')
|
||||
->and($airport->timezone)->toEqual('America/Chicago')
|
||||
->and($airport->hub)->toBeTrue()
|
||||
->and($airport->lat)->toEqual('30.1945')
|
||||
->and($airport->lon)->toEqual('-97.6699')
|
||||
->and($airport->lat)->toEqualWithDelta(30.1945, 0.001)
|
||||
->and($airport->lon)->toEqualWithDelta(-97.6699, 0.001)
|
||||
->and($airport->ground_handling_cost)->toEqual(0.0)
|
||||
->and($airport->fuel_jeta_cost)->toEqual(setting('airports.default_jet_a_fuel_cost'))
|
||||
->and($airport->notes)->toEqual('Test Note');
|
||||
@ -668,7 +668,7 @@ test('airport importer', function (): void {
|
||||
test('airport importer invalid inputs', function (): void {
|
||||
$importer = app(ImportService::class);
|
||||
$file_path = base_path('tests/data/airports_errors.csv');
|
||||
$status = $importer->importAirports($file_path);
|
||||
$status = $importer->importAirports($file_path, delete_previous: false);
|
||||
|
||||
expect($status['success'])->toHaveCount(5)
|
||||
->and($status['errors'])->toHaveCount(1);
|
||||
@ -683,8 +683,8 @@ test('airport importer invalid inputs', function (): void {
|
||||
->and($airport->iata)->toEqual('')
|
||||
->and($airport->timezone)->toEqual('America/Winnipeg')
|
||||
->and($airport->hub)->toBeFalse()
|
||||
->and($airport->lat)->toEqual('50.0564003')
|
||||
->and($airport->lon)->toEqual('-97.03250122');
|
||||
->and($airport->lat)->toEqualWithDelta(50.0564, 0.001)
|
||||
->and($airport->lon)->toEqualWithDelta(-97.03250, 0.001);
|
||||
});
|
||||
|
||||
test('subfleet importer', function (): void {
|
||||
@ -696,7 +696,7 @@ test('subfleet importer', function (): void {
|
||||
|
||||
$importer = app(ImportService::class);
|
||||
$file_path = base_path('tests/data/subfleets.csv');
|
||||
$status = $importer->importSubfleets($file_path);
|
||||
$status = $importer->importSubfleets($file_path, delete_previous: false);
|
||||
|
||||
expect($status['success'])->toHaveCount(1)
|
||||
->and($status['errors'])->toHaveCount(1);
|
||||
@ -707,7 +707,7 @@ test('subfleet importer', function (): void {
|
||||
])->first();
|
||||
|
||||
expect($subfleet)->not->toBeNull()
|
||||
->and($subfleet->id)->toEqual($airline->id)
|
||||
->and($subfleet->airline_id)->toEqual($airline->id)
|
||||
->and($subfleet->type)->toEqual('A32X')
|
||||
->and($subfleet->name)->toEqual('Airbus A320');
|
||||
|
||||
@ -749,7 +749,7 @@ test('subfleet importer', function (): void {
|
||||
test('airport special chars importer', function (): void {
|
||||
$importer = app(ImportService::class);
|
||||
$file_path = base_path('tests/data/airports_special_chars.csv');
|
||||
$status = $importer->importAirports($file_path);
|
||||
$status = $importer->importAirports($file_path, delete_previous: false);
|
||||
|
||||
// See if it imported
|
||||
$airport = Airport::where([
|
||||
|
||||
@ -241,11 +241,13 @@ test('pirep notifications', function (): void {
|
||||
|
||||
Notification::fake();
|
||||
|
||||
$rank = Rank::factory()->create();
|
||||
|
||||
$user = User::factory()->create([
|
||||
'name' => 'testPirepNotifications user',
|
||||
'flights' => 0,
|
||||
'flight_time' => 0,
|
||||
'rank_id' => 1,
|
||||
'rank_id' => $rank->id,
|
||||
]);
|
||||
|
||||
$admin = createAdminUser(['name' => 'testPirepNotifications Admin']);
|
||||
@ -709,7 +711,7 @@ test('diversion handler reuses matching reposition flight and attaches subfleet'
|
||||
'airline_id' => $airline->id,
|
||||
'dpt_airport_id' => $departureAirport->id,
|
||||
'arr_airport_id' => $originalArrivalAirport->id,
|
||||
'callsign' => 'TEST6000',
|
||||
'callsign' => 'TST6',
|
||||
'flight_number' => 6000,
|
||||
]);
|
||||
$flight->subfleets()->syncWithoutDetaching([$subfleet->id]);
|
||||
|
||||
@ -270,8 +270,8 @@ test('attach to pirep', function (): void {
|
||||
|
||||
$fix = $acars->firstWhere('name', 'BOMUP');
|
||||
expect($fix['name'])->toEqual('BOMUP')
|
||||
->and($fix['lat'])->toEqual(24.484639)
|
||||
->and($fix['lon'])->toEqual(54.578444)
|
||||
->and($fix['lat'])->toEqualWithDelta(24.484639, 0.00001)
|
||||
->and($fix['lon'])->toEqualWithDelta(54.578444, 0.00001)
|
||||
->and($fix['order'])->toEqual(1);
|
||||
|
||||
$briefing->refresh();
|
||||
|
||||
@ -269,7 +269,7 @@ test('user pilot id split', function (): void {
|
||||
expect($found_user->id)->toEqual($user->id);
|
||||
|
||||
// Look for them with the IATA code
|
||||
$found_user = $userSvc->findUserByPilotId($user->airline->iata.$user->id);
|
||||
$found_user = $userSvc->findUserByPilotId($user->airline->iata.$user->pilot_id);
|
||||
expect($found_user->id)->toEqual($user->id);
|
||||
});
|
||||
|
||||
@ -293,21 +293,21 @@ test('user pilot id added', function (): void {
|
||||
$new_user = User::factory()->make()->makeVisible(['api_key', 'name', 'email'])->toArray();
|
||||
$new_user['password'] = Hash::make('secret');
|
||||
$user = $userSvc->createUser($new_user);
|
||||
expect($user->pilot_id)->toEqual($user->id);
|
||||
expect($user->pilot_id)->toBeGreaterThan(0);
|
||||
|
||||
// Add a second user
|
||||
$new_user = User::factory()->make()->makeVisible(['api_key', 'name', 'email'])->toArray();
|
||||
$new_user['password'] = Hash::make('secret');
|
||||
$user2 = $userSvc->createUser($new_user);
|
||||
expect($user2->pilot_id)->toEqual($user2->id);
|
||||
expect($user2->pilot_id)->toBeGreaterThan($user->pilot_id);
|
||||
|
||||
// Now try to change the original user's pilot_id to 4
|
||||
$user = $userSvc->changePilotId($user, 4);
|
||||
expect($user->pilot_id)->toEqual(4);
|
||||
|
||||
// Create a new user and the pilot_id should be 5
|
||||
// Create a new user and the pilot_id should be greater than the manually set 4
|
||||
$user3 = User::factory()->create();
|
||||
expect($user3->pilot_id)->toEqual(5);
|
||||
expect($user3->pilot_id)->toBeGreaterThan(4);
|
||||
});
|
||||
|
||||
test('user pilot deleted', function (): void {
|
||||
@ -320,7 +320,7 @@ test('user pilot deleted', function (): void {
|
||||
$new_user = User::factory()->make()->makeVisible(['api_key', 'name', 'email'])->toArray();
|
||||
$new_user['password'] = Hash::make('secret');
|
||||
$user = $userSvc->createUser($new_user);
|
||||
expect($user->pilot_id)->toEqual($user->id);
|
||||
expect($user->pilot_id)->toBeGreaterThan(0);
|
||||
|
||||
// Delete the user
|
||||
$userSvc->removeUser($user);
|
||||
@ -343,7 +343,7 @@ test('user pilot deleted with pireps', function (): void {
|
||||
$new_user = User::factory()->make()->makeVisible(['api_key', 'name', 'email'])->toArray();
|
||||
$new_user['password'] = Hash::make('secret');
|
||||
$user = $userSvc->createUser($new_user);
|
||||
expect($user->pilot_id)->toEqual($user->id);
|
||||
expect($user->pilot_id)->toBeGreaterThan(0);
|
||||
|
||||
Pirep::factory()->create([
|
||||
'user_id' => $user->id,
|
||||
@ -449,7 +449,7 @@ test('event called when profile updated', function (): void {
|
||||
$body = [
|
||||
'name' => 'Test User',
|
||||
'email' => $user->email,
|
||||
'airline_id' => 1,
|
||||
'airline_id' => $user->airline_id,
|
||||
];
|
||||
|
||||
$resp = $this->actingAs($user)->put('/profile/'.$user->id, $body);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user