Compare commits

..

178 Commits

Author SHA1 Message Date
Nabeel Shahzad
18206f4601 Update the meta link to include query strings 2021-06-10 19:29:25 -04:00
Nabeel Shahzad
845514da2c Fix tests 2021-06-10 13:13:09 -04:00
Nabeel Shahzad
531489bfde Remove pagination from getting airlines 2021-06-10 12:41:23 -04:00
Nabeel Shahzad
601a17e1e6 Blank out links for ACARS 2021-06-10 11:08:25 -04:00
Nabeel Shahzad
3be8b1c4b9 undo links 2021-06-10 10:09:28 -04:00
Nabeel Shahzad
b4e33bb37e Update akaunting money library 2021-06-10 09:08:41 -04:00
Nabeel Shahzad
a8e6f1191b Fix the missing links array 2021-06-10 08:46:56 -04:00
Nabeel Shahzad
3a0140c2d0 Don't use backup for cache key on dependencies 2021-06-09 16:29:57 -04:00
Nabeel Shahzad
547b159570 Zip file generation 2021-06-09 16:22:25 -04:00
Nabeel Shahzad
cab5c03c0b Generate zip file differently 2021-06-09 16:17:06 -04:00
B.Fatih KOZ
777a696b35 Use Profile Route for Author URL (Discord Messages) (#1227)
* Update PirepStatusChanged.php

Use profile route for author url instead of pirep

* Update PirepSubmitted.php

Use profile route for author url instead of pirep

* Update PirepPrefiled.php

Use profile route for author instead of pirep

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-06-09 11:43:08 -04:00
B.Fatih KOZ
90344fb6e6 Simbrief Edit & Download Latest OFP (#1228)
* SimBrief OFP Edit

Changes aim to have ability of editing generated SimBrief Flight Plans and re-downloading.

* Move url to config

* Blade update and $uri change

* Update simbrief_form.blade.php

Used `$flight->id` along with `$user->ident` to have a more unique static id value. No details given for that fields uniqueness requirements, this will be ok I think though. 
Also we are passing user's simbrief userid with api to find the flight plan, both combined, no chance to get another users plan and/or any other plan of same user.

* Update SimBriefController.php

Move `static_id` to controller

* Update simbrief_form.blade.php

Read `static_id` from controller

* StyleFix

* Update phpvms.php

* Update SimBriefService.php

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-06-09 11:38:14 -04:00
Nabeel S
7481dab012 Remove extraneous data from API response; force API to en (#1241)
* Remove extraneous data from API response; force API to en

* Style fixes

* Remove

* Fix the meta block

* Style fixes
2021-06-09 11:20:25 -04:00
Nabeel Shahzad
dead1cfd0f Style fixes 2021-06-08 17:49:42 -04:00
Nabeel Shahzad
544462f420 Fix environment mapping 2021-06-08 17:46:15 -04:00
B.Fatih KOZ
a31201dfd3 Fix secstohhmm typecast for PHP 8 (#1230)
* Update helpers.php

Looks like php8 is not liking numeric strings as we like them.

Fixes #1229

* StyleFix

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-06-08 11:00:18 -04:00
Andrew Roberts
9d336c1140 Fix typo (#1234) 2021-06-08 10:45:17 -04:00
Nabeel S
96d33c11c8 Fix data not showing up for live map (#1223)
* Fix data not showing up for live map

* StyleCI fixes
2021-06-04 16:57:27 -04:00
Robin
48cada2053 Fixed German Translation (#1222)
* New Language: German

* Update German K

* Fixed German Translation

Co-authored-by: derrobin154 <derrobin154@gmail.com>
Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-06-04 16:53:11 -04:00
Nabeel Shahzad
2a05013f66 Discord: Only add fields and footer if they're not empty 2021-06-04 15:16:36 -04:00
Nabeel Shahzad
4267648da5 Fields/fares not being saved properly 2021-06-04 15:06:19 -04:00
Nabeel Shahzad
5ada327236 Log request/response for Discord 2021-06-04 13:57:16 -04:00
Nabeel S
82825ef77b Add setting for recording IP address (#1221)
* Add setting for recording IP address

* Record IP on registration
2021-06-04 13:20:33 -04:00
Nabeel S
db532e0f16 Remove the IP address from being recorded (#1220) 2021-06-04 12:10:40 -04:00
Nabeel S
9b2e466b7e Discord notifications for PIREP and News events #433 (#1215)
* Discord notifications for events #433

* Style fixes

* Check for blank webhook urls and disable

* Cleanup items after review

* Changes and fixes

* Style fixes

* Don't load env for testing

* Fix status text

* Refactor saving fields/fares so events get the latest data

* Cleanup

* Style fixes
2021-06-04 10:51:59 -04:00
B.Fatih KOZ
17447c6903 Block aircraft with Simbrief (#1213)
* Block Aircraft with SimBrief

Changes aim to have the ability to block an aircraft's usage if it is used to generate a SimBrief OFP.

Unused/Expired briefings will be deleted by cron like before but will now be checked by HourlyCron, so admins can define more precise restrictions for them (and the blockage period of their aircraft)

Owner of the SimBrief OFP will be able to start a flight with acars using that particular aircraft, but pilots will get an Aircraft Not Available error (similar to Aircraft State check)

To prevent SimBrief OFP packs being marked as expired/unused, during pirep prefile, pirep_id will be saved to SimBrief model along with flight_id.

And when a flight is finished (pirep file), flight_id will be removed from SimBrief model as before. Only pirep_id will remain and aircraft will be available for another OFP generation.

* Update PirepController

In case a pirep is being saved/submitted with manual entry (but the va is using simbrief effectively) same logic should be applied during save/submit button selection.
Save will act like a pirep prefile , Submit will be pirep file.

* Manual Pirep Checks

Manual pireps, prefiled from a generated simbrief should be checked too. Also pirep.show blade's submit button should provide the same simbrief checks.

* Update PirepService.php

* Change settings and move sb cron to hourly

* StyleFix (SimBriefService)

* Another StyleFix (SimBriefService)

* Update SimBriefController

Removed null check of pirep_id for aircraft list generation to prevent live flights' aircraft being listed for another ofp generation.
( Active acars flights will have both flight_id and pirep_id at simbrief table)

* Update PirepService.php

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-06-03 16:17:16 -04:00
B.Fatih KOZ
ad86e996d7 Fix Aircraft Dropdown Grouping (#1216)
* Update PirepController

Frontend : Use `$subfleet->type`  instead of `name` for grouping aircraft list.

* Update PirepController (Admin)

Use `$subfleet->type` instead of `name` here too , for grouping aircraft list according to their subfleets.

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-06-03 14:41:31 -04:00
Robin
5a5fd02dac New Language: German (#1218)
* New Language: German

* Update German K

Co-authored-by: derrobin154 <derrobin154@gmail.com>
2021-06-03 11:46:32 -04:00
Nabeel Shahzad
97f095e4e9 Set default env name to "production" and debug to false 2021-05-29 18:13:36 -04:00
Jesper Falk
a2f91b6754 Add GD PHP Extension for docker container (#1212) 2021-05-28 08:48:52 -04:00
Nabeel Shahzad
a9e5554dea Trap migration error for modules if they don't exist 2021-05-27 16:14:13 -04:00
B.Fatih KOZ
5b10dca868 Fix SimBriefService (#1209)
* Fix removeExpiredEntires()

* Fix SimBriefTest

No need to add `'pirep_id' => ''` , just let it be `null` (like the core code does) and no need to convert Carbon to DateTimeString.
2021-05-27 09:27:38 -04:00
B.Fatih KOZ
11cebb3e6e Show only used Flight Types at Flight Search (#1207)
* Update Flight Controller

Show only used flight types in the search form instead of all IATA Flight Types.

* PrePR StyleFix

* StyleFix

* Use Model instead of DB

Also used the same $where array

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-05-25 16:14:42 -04:00
B.Fatih KOZ
96c17d33bc Add ability to search Flights by Code (#1205)
* Edit Search Form

Add ability to search via flight/route code (technically it was possible but the field was not present in the blade)

* Add Code (EN)

* Add Code (ES)

* Add Code (IT)

* Add Code (PT-BR)

* FlightCode => Code

* FlightCode => Code

* FlightCode => Code

* FlightCode => Code

* FlightCode => Code
2021-05-25 15:33:02 -04:00
Nabeel Shahzad
9abc892698 Update README 2021-05-25 15:11:09 -04:00
Nabeel Shahzad
67a51da220 Cleanup the docker-compose for local testing 2021-05-25 15:07:04 -04:00
Nabeel Shahzad
7e586a273a File/dir ownership in container 2021-05-25 13:37:53 -04:00
Nabeel Shahzad
8a591c11a5 Fix docker-compose for use non-locally 2021-05-25 13:14:08 -04:00
B.Fatih KOZ
728b033675 Fix Admin: UserController and Flight Edit (#1204)
* Fix Admin / UserController

Use Role Repository and `selectBoxList` method instead of the model itself.

* Fix Flight Fields

Added empty/blank option for clearing out the days when needed

* StyleFix
2021-05-24 19:13:44 -04:00
B.Fatih KOZ
68a6ed24cb Fix Flight Importer (#1202)
* Handle Route and Level fields too during import.
* Also removed the check for `visible => true` from `firstorNew` 'cause va admin may be importing to update not visible flights too.
  (by default all new flights are visible, so no affect on new flights)

Closes #1201
2021-05-24 15:19:06 -04:00
Nabeel S
7d8a34645e Add --force flag to migrations (#1203) 2021-05-24 10:58:10 -04:00
B.Fatih KOZ
4985da991b Remove Scripts (#1200)
* Remove Scripts

Remove scripts from create blade which are designed for edit blade in the first place (thus looking for flight object and its properties). 
No need to have an eyecandy date picker or a days selector, previous working version of create.blade was more than enough to manually add fights.

* Add placeholder for date fields
2021-05-23 20:47:15 -04:00
Nabeel Shahzad
c94358350a Add queue worker setting so those aren't run in cron if there's a worker 2021-05-21 12:31:32 -04:00
Nabeel S
d3ec0f4de3 5 char ICAO support #1052 (#1198) 2021-05-21 10:52:47 -04:00
Nabeel S
ede5b74383 Make fuel_used an optional field in PIREP file (#1197) 2021-05-21 10:02:07 -04:00
Nabeel S
e7bbd6cccb Use queues for notifications #1154 (#1174)
* Use queues for notifications #1154

* Styles

* Update defaults

* Include queueworker
2021-05-20 11:54:07 -04:00
Nabeel S
edcea258ce Remove the autoupdater #1133 (#1195)
* Remove the autoupdater #1133

* Remove self-updater package

* Package still needed :|
2021-05-20 11:37:27 -04:00
Nabeel Shahzad
5adc0b4072 Remove unused import 2021-05-20 09:20:12 -04:00
Nabeel Shahzad
fe7120e21a Add PHP 7.4 polyfill 2021-05-20 08:55:55 -04:00
B.Fatih KOZ
30be7c245c Fix Advanced Fuel Calculations (#1190)
* Fix Advanced Fuel Calculations

Current code works fine with a fresh submitted pirep but when a re-calculation is needed, fuel amount will not be correct if the aircraft was flown later on.
Commit provides fix for such re-calculation scenarios.

* StyleFix for the Comment Line !
2021-05-19 19:01:33 -04:00
Nabeel S
7cb9ae4ec3 intl dependency/polyfill updates (#1194) 2021-05-19 13:57:28 -04:00
Olli
6f1a5f1dc2 Update Flight Controller to fix an issue (#1192)
Closes #1180 and #1156. But now the script isn't beeing loaded

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-05-19 13:42:40 -04:00
Nabeel Shahzad
e3c3c81d19 Include missing scripts in flight create 2021-05-19 13:33:13 -04:00
Nabeel S
352f1ee9f8 Days::in should use in_mask; tests coverage #1180 (#1193) 2021-05-19 11:20:50 -04:00
Nabeel Shahzad
dff4273c72 Force empty to be 0 for in_mask #1180 2021-05-19 10:22:15 -04:00
Nabeel S
77a4acb569 Update dependencies (#1188) 2021-05-14 13:02:47 -04:00
B.Fatih KOZ
ff6827b368 Fix Installer Completed Blade (#1185)
We do not have a config.php anymore, page should refer to env.php for base level configuration.
2021-05-14 12:31:24 -04:00
B.Fatih KOZ
594d0eb222 Check Aircraft Availability (#1177)
* Check Aircraft Availability before Prefile

Check if the aircraft is available for flight (State : Parked / On Ground). If not throw new exception AircraftNotAvailable

* Add Exception

AircraftNotAvailable exception, used by PirepService during prefile checks.
2021-05-13 15:26:53 -04:00
Nabeel S
ee61de62fa Update to PHP 8 (#1118)
* Update to PHP 8

* Update composer file

* Remove PHP 8 incompatible library

* Remove PHP 8 incompatible library
2021-05-11 18:46:21 -04:00
B.Fatih KOZ
f2be14402f PirepCancelled Event (Cron Expired Pirep Deletion) (#1178)
* PirepCancelled Event (Cron Expired Pirep Deletion)

While deleting frozen in progress pireps we should at least send a PirepCancelled event for those who are listening.

(or we may have a new PirepDeleted event to be issued in such cases, I think PirepCancelled is enough though)

* StyleFix

* Another StyleFix

* Missing Log

Of course it will not be possible to write log entries without the Log itself.
2021-05-09 18:30:50 -04:00
B.Fatih KOZ
a186bfae2a Fix AirportController (Frontend) (#1176)
1. Inbound and Outbound flights were displaying all flights (active and inactive) , fixed to fetch only active flights.
2. Flash message and redirect to Dashboard was not working, instead we were getting 404 Not Found error.
2021-05-08 15:42:18 -04:00
Nabeel S
6e6ba85080 Fix for duplicated/wrong expenses being applied #915 (#1173)
* Fix for duplicated/wrong expenses being applied #915

* Style fixes
2021-05-06 12:42:56 -04:00
B.Fatih KOZ
d2272e32a6 100LL and MOGAS Fuel Cost (#1172)
* Add defaults for 100LL and MOGAS prices

Add missing defaults for 100LL and MOGAS Fuel prices.

* Calculate Fuel Cost according to Fuel Type

Calculate pirep fuel costs according to aircraft (subfleet) fuel type, use JetA as fail safe default.

* Fix for Failing AwardTest

At least attempting to fix

* Fix fuel types logic

* Style

* Invert the logic

Co-authored-by: Nabeel Shahzad <nabeel@nabeel.sh>
2021-05-06 08:16:33 -04:00
Nabeel S
b6c0946795 Delete users without PIREPS; pilot leave fix (#1171)
* Delete users without PIREPS; pilot leave fix

* Style fixes
2021-05-05 09:56:28 -04:00
Andrew Roberts
fca04e6b0c Allow session lifetime to be set in env variables (#1170)
* Allow session lifetime to be set in env variables

Currently the session live time defaults to 2 hours, adding an env variable will allow us to change this on a per site basis

* Add whitespace for consistency
2021-05-05 08:51:18 -04:00
Andrew Roberts
5094fce4b0 Disable autocomplete on admin email field (#1169)
* Disable autocomplete on admin email field

Fixes #1165

* Disable autocomplete on admin name and password

For sake of completeness and due to some over zealous autocompleters, also disable it on name and password fields
2021-05-04 13:26:16 -04:00
Nabeel S
fe0ef60b6c Block refiling of PIREPs (#1167)
* Block refiling of PIREPs

* Style fixes

* Package updates
2021-05-03 10:00:10 -04:00
B.Fatih KOZ
5094375e13 Fixes For GDPR/Deleted Users (#1164)
* Fix DeletedUsers being displayed at Homepage

Deleted users should not be displayed at homepage / newest pilots list. PR fixes that problem.

* Do Not Display Deleted Users with LatestPireps

As the main page, Latest Pilots widget should not display GDPR/Soft deleted users too.

* StyleFix
2021-05-03 08:46:21 -04:00
Nabeel Shahzad
ec6cb42bfd User guard for null 2021-04-23 13:47:54 -04:00
Nabeel S
14d0e99a37 Delete the user in a GDPR compatible way (#1151)
* Delete the user in a GDPR compatible way

* Block user from calls

* Style fix
2021-04-23 10:33:13 -04:00
B.Fatih KOZ
f8c7bc31f5 Add Airline ICAO to Subfleet selectBoxList (#1153)
* Add Airline ICAO to Subfleet selectBoxList

Subfleet dropdown at flight search will look like `Boeing B737-800 WL | THY`

* StyleFix
2021-04-23 09:44:37 -04:00
Nabeel Shahzad
2545328233 Fix APP_URL being called SITE_URL 2021-04-20 23:28:57 -04:00
Russell West
61739ce266 Pirep delete confirmation (#1143)
* adds 100ll option to airport admin

* Adds mogas field too

* adds basic confirmation when deleting pirep
2021-04-15 08:39:42 -04:00
Nabeel S
bffc4f911c Add tests for the cron jobs (#1141) 2021-04-14 08:37:48 -04:00
Nabeel Shahzad
d18925f473 Add tests for 0 results METAR 2021-04-14 06:45:35 -04:00
Russell West
f5e83461a3 adds 100ll option to airport admin (#1138)
* adds 100ll option to airport admin

* Adds mogas field too

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-04-13 12:03:03 -04:00
Nabeel S
bfddb2c84d Make sure all dates are in UTC (#1139) 2021-04-13 09:25:38 -04:00
B.Fatih KOZ
7e9eb08135 Use where iso whereTime (#1137)
Using whereTime may present a problem for flights conducted during utc midnight and some active/live flights may be deleted with whereTime.

Scenario;

now = today-01:00  utc
setting = 2 hours
date = yesterday-23:00 utc

Any live pireps will/may be deleted with whereTime 'cause their last updated TIME will be maximum 00:59 which is smaller than 23:00.
2021-04-13 09:08:50 -04:00
B.Fatih KOZ
3d55336823 Fix default value for Captcha setting (#1136) 2021-04-12 16:55:38 -04:00
Nabeel Shahzad
68ed2355ad Add GRAVATAR_DEFAULT_AVATAR to config 2021-04-11 18:42:51 -04:00
Nabeel S
fdab4ee530 Fix email for news not going out (#1131) 2021-04-11 14:32:58 -04:00
Nabeel Shahzad
648e7a261d Add APP_NAME to env stub 2021-04-11 13:46:52 -04:00
Nabeel Shahzad
9cb0a0cf36 Change the default driver to use mail 2021-04-11 12:36:37 -04:00
B.Fatih KOZ
2c8372d484 Read Captcha Settings From ENV (#1130)
* Read Captcha Settings From ENV

* Update captcha.php
2021-04-11 11:35:14 -04:00
Nabeel Shahzad
498d5bfaf0 Slugify cache prefix and quote it in the env 2021-04-10 21:13:34 -04:00
Nabeel Shahzad
2202c5b479 Change default env to prod for fresh install 2021-04-10 18:00:03 -04:00
Nabeel S
ac64a5db75 Migrate all configs into the env.php file #1075 (#1128)
* Migrate all configs into the env.php file #1075

* Style fixes

* Fix config names in CreateConfig

* Fix installer/installer error messages
2021-04-10 17:19:45 -04:00
B.Fatih KOZ
6c3992e781 Fix for Hourly Crons (#1127)
* Fix for Hourly Cron

We should be using whereTime instead of whereDate

https://laravel.com/docs/8.x/queries#additional-where-clauses
`The whereDate method may be used to compare a column's value against a date`

* Fix for RemoveExpiredBids

I used where to do check 'cause people may set 48 hours to remove a bid, thus neither whereDate nor whereTime will give a correct results.

* Fix for DeletePireps

I used where to do check 'cause people may set 48 hours to delete cancelled or rejected pireps, thus neither whereDate nor whereTime will give a correct results.
2021-04-09 19:15:22 -04:00
B.Fatih KOZ
344edde0fb Alphanumeric Callsign For Flights (#1124)
* Alphanumeric Callsign For Flights

PR adds ability to define alphanumeric callsigns to flights, display them and use them during SimBrief OFP generation (if pilot ident as callsign option is not enabled)

Translations for en/es/it/pt-br added.

* Change db table name

* Change db column name, fix rules

* Change db column name

* Another db column name change

* Just another one more

* Last one from anumeric_callsign to callsign

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-04-05 18:00:50 -04:00
Maximiliano Fallico
7502c053bf Show Airline logo / icao to subfleets table (#1121)
Will show the subfleet airline logo or icao in the admin flight create page table.

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-04-05 17:05:28 -04:00
Maximiliano Fallico
dbfaed0ecc Adds Airline Icao to Subfleet Select in Flight Create (#1123)
* Adds Airline Icao to Subfleet Select in Flight Create

* Fix Style

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-04-05 16:55:50 -04:00
Maximiliano Fallico
ff255c999b Add "View Pirep" In pirep cards (#1122)
Will show it in a new blank page in order to view pirep flight map.,

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-04-05 16:43:51 -04:00
Nabeel Shahzad
8c065a44cf Set default theme as "null" value 2021-04-03 10:25:02 -04:00
Nabeel Shahzad
8e9ba3b922 Fix styling that somehow slipped through 2021-04-01 17:33:57 -04:00
Nabeel Shahzad
677d30883f Check if flash messages are strings 2021-04-01 17:31:53 -04:00
Nabeel Shahzad
ede71e6927 Fix the PIREP edit permissions 2021-04-01 09:54:01 -04:00
Andrew Roberts
3f84f84309 Fix issue with being unable to save pirep edits (#1116)
Fixes issue being unable to save pirep edits from the admin section due to incorrect variable being used
2021-03-31 11:03:01 -04:00
exciler
50e8f2e52b Fetch timezone on airport lookup (#1103)
Co-authored-by: Andreas Palm <ap@ewsp.de>
2021-03-29 17:10:00 -04:00
Nabeel S
96fff0248d Save airport timezone (#1112)
* Fix airport timezone lookup

* Save timezone to the airport when importing
2021-03-29 15:49:34 -04:00
Nabeel S
9c4aced837 Move the prefile event and add a new error exception (#1111)
* Move the prefile event and add a new error exception

* Remove extra import

* Add empty handler for testing

* Fix styling

* Fix styleci
2021-03-29 14:53:35 -04:00
exciler
ed146b2c70 replace windows backslashes by slashes before path mapping (#1107)
Co-authored-by: Andreas Palm <ap@ewsp.de>
2021-03-28 18:15:56 -04:00
exciler
1e320835c2 fix map-info-box display (#1104)
* fix map-info-box display

* Check user on PIREP show/edit/update/submit

* add missing use

* refactoring according to comments; use UpdatePirepRequest for authorization and make user available to view

Co-authored-by: Andreas Palm <ap@ewsp.de>
Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-03-28 09:57:16 -04:00
exciler
d4c301a36c Remove remove_bid_after_accept setting (#1100)
* Remove "Remove bid on accept" setting and remove bids after PIREP was filed

fixes #1039

* Add migration to remove setting from database

* fix migration naming and remove obsolete code

Co-authored-by: Andreas Palm <ap@ewsp.de>
2021-03-27 08:33:21 -04:00
B.Fatih KOZ
c2b0b69eb2 Change LatestPireps Widget Sort Order (#1099)
* Change LatestPireps Widget Sort Order

Latest pireps should be ordered by `submitted_at` instead of `created_at` . 

Pirep may be created even a day before others (with the pause/resume ability we have in acars) but it gets submitted once when the flight is ended, thus I think it should be our reference to sort them in proper order.

* Trying to Pass UnitTest
2021-03-25 09:51:16 -04:00
Nabeel Shahzad
43c33adcfe Unit rounding 2021-03-25 08:59:45 -04:00
exciler
be6332936f When importing flights, set subfleet name only if subfleet has been created (#1095)
* when importing flights, set subfleet name only if subfleet has been created, do not update existing subfleets

* add tests for flights import regarding subfleets

Co-authored-by: Andreas Palm <ap@ewsp.de>
2021-03-23 08:50:19 -04:00
B.Fatih KOZ
8f38fc2dec Urgent Fix For SimBriefControlled (#1094)
Added missing Enums
2021-03-22 11:40:21 -04:00
B.Fatih KOZ
65015cbce2 Move SimBrief aircraft selection to Controller (#1093)
* Move SimBrief aircraft selection to Controller

Instead of passing subfleets to blade (and doing two foreach loops and ifs to populate the dropdown), we are building a proper aircraft list here.

Did not removed $subfleets from data being passed to blade on purpose, it may be removed later on.

* Style Fix

* Update aircraft selection blade to use $aircrafts

* Order generated Aircrafts collection

First ICAO then Registration

* Add privatized name setting for simbrief

To prevent possible privacy issues according to latest regulations.

* Add privatized name to SimBrief form

It is controlled with a setting, if not enabled we will not pass any names to SimBrief via API (this will result users SimBrief membership name being used at the OFP as before)
2021-03-22 10:55:33 -04:00
B.Fatih KOZ
3cc5ca2c32 DownloadController Improvements (#1091)
* DownloadController Improvements

Added multiple airline support to both Aircraft and Subfleet downloads, if the user has more than one active airline downloads will display the airline name before the object name. Also sorted the returned results to have a better look at the blade.

* Trying to pass broken UnitTest

Please do fix the UnitTest, this pr has nothing to do with units but still being tested with it and failing.
2021-03-21 09:33:04 -04:00
Maximiliano Fallico
30e88ac6bc Aircraft at departure airport restrictions (#1090)
* Update simbrief_aircraft.blade.php

If resrict airplane at location settings is enabled, Show only  aircraft at the departure location of the flight. Kingly made by @FatihKoz at my ocd request.

* Update simbrief_aircraft.blade.php
2021-03-20 20:03:24 -04:00
Nabeel Shahzad
61ee4254fc Style fix 2021-03-20 17:41:07 -04:00
Nabeel Shahzad
f9f0ee826d Fill the flight subfleets even if there's a simbrief 2021-03-20 17:28:54 -04:00
Nabeel Shahzad
4394487392 Add missing aircraft_id to sample data 2021-03-19 18:47:02 -04:00
Nabeel S
1287766a46 Fix aircraft retrieval for Simbrief (#1089)
* Fix full aircraft retrieval for simbriefs

* F off StyleCI
2021-03-19 18:25:19 -04:00
Nabeel Shahzad
11824c9f8b Flight search error 2021-03-19 16:59:39 -04:00
B.Fatih KOZ
bbd02bf5c7 Fix For GH Costs (#1088)
* Fix For GH Costs.

PR aims to fix the problem where Airport GH cost is not defined but recored to db as 0.00 or 0 (default value for airports table)
In such cases settings/default apt gh cost will be used.

* Updated logic for JetA1 cost check

* Remove default costs being used during import
2021-03-19 16:42:36 -04:00
exciler
9bb192b97f Add disable activity check option on certain roles #1078 (#1087)
* Add boolean field "disable activity checks" to role, check for this field inside PilotLeave-Check, add tests

* fix checkbox on form

* CS fixes

* CS fixes again :-)

Co-authored-by: Andreas Palm <ap@ewsp.de>
2021-03-19 13:09:29 -04:00
exciler
2cede04b1e Optimize view paths for module views in theme folder (#1081)
* override \Igaster\LaravelTheme\themeViewFinder as a workaround until PR#133 in igaster/laravel-theme is merged

* fixup code style

* further code style fix

Co-authored-by: Andreas Palm <ap@ewsp.de>
2021-03-19 09:22:03 -04:00
B.Fatih KOZ
7072428218 Fix Finance Memo (Ground Handling) (#1083)
PR fixes issue #1082
2021-03-18 20:04:13 -04:00
B.Fatih KOZ
1d83b85d8b Fix for Fuel and Ground Handling Costs (#1050)
* Fix for Fuel and Ground Handling Costs

PR aims to fix issue #1048  and implements the feature request #1049 

If no fuel cost is defined for departure airport, settings / airport fuel price will be used.
If no ground handling cost is defined for airports, settings / airport ground handling cost will be used.

Ground handling prices of both departure and arrival airport will be used for calculations.

* Resolve conflict with latest dev

PR will still fail checks due to double ground handling fares and will work on it to have two records at transactions for dep/arr

* Remove Double GH Costs / Fix The Bug Only

Removed double GH costs for now, pr aims only fixing the current issue (general settings not being read for fuel and ground handling costs)

* Add departure and arrival airports to ground handling

* Style fix

* Fix tests

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
Co-authored-by: Nabeel Shahzad <nabeel@nabeel.sh>
2021-03-18 11:32:40 -04:00
Nabeel S
63eef59060 Fix null visibility in METAR (#1079)
* Fix null visibility in METAR

* Report the text in units from the METAR
2021-03-17 17:40:45 -04:00
B.Fatih KOZ
0152ff6045 Update pireps/show.blade (#1080)
Added score and landing rate to right sidebar, sorted the pirep logs in asc order to make it easy to read.
2021-03-17 16:43:36 -04:00
B.Fatih KOZ
e45bd66388 Fix Metar Decoding / Wind check for Wind Chill (#1072)
* Fix Metar Decoding / Wind check for Wind Chill

PR aims to fix the bug #1071 by checking both the wind speed and it's value for starting Wind Chill calculation.
2021-03-15 10:41:05 -04:00
exciler
b9e7a2efc9 Add unit conversion handling for block_fuel like for fuel_used (#1076)
* Add unit conversion handling for block_fuel like for fuel_used, add further checks in PIREPTest->testUnitFields

* Remove accidentially added "use"

Co-authored-by: Andreas Palm <ap@ewsp.de>
2021-03-15 08:30:14 -04:00
Nabeel Shahzad
73f88fce0c Fix permissions with modules 2021-03-13 18:31:09 -05:00
Nabeel S
e70ee5aa6f Add web cron ability #821 (#1073)
* Use database for kvp storage

* Read kvpstore

* Add web cron ability through API #821

* Style fixes

* Fix text
2021-03-09 11:36:56 -05:00
nabeelio
f1c54bcc7c Add Postmark package #1067 2021-03-08 11:35:11 -05:00
nabeelio
d94d754961 Block user if they're not active #1066 2021-03-08 11:24:09 -05:00
nabeelio
9abfbd6c8c Remove unneeded import #1066 2021-03-08 11:21:55 -05:00
nabeelio
97fc1dd43d Don't block API logins #1066 2021-03-08 11:19:31 -05:00
Nabeel Shahzad
edc37f40fa Show either create/view simbrief button, not both 2021-03-06 16:48:50 -05:00
Nabeel S
950c7788be Restrict Simbrief to user who generated it (#1064)
* Restrict simbrief to user

* Style fixes

* Add tests

* Style fix
2021-03-06 13:49:42 -05:00
nabeelio
b3af50ac5a Add ignored solution provider 2021-03-05 08:00:34 -05:00
nabeelio
8a9b68d9ec Disable ignition runnable solutions 2021-03-05 07:59:50 -05:00
nabeelio
70a4cf9f90 Remove the laravel-backup library 2021-03-05 07:33:42 -05:00
Nabeel Shahzad
c3465851b2 Rename backups folder 2021-03-05 06:24:23 -05:00
Nabeel Shahzad
b13c4df338 laravel-backup changes 2021-03-05 06:00:36 -05:00
Nabeel Shahzad
c736a9b639 Disable encryption by default for backups 2021-03-05 05:44:04 -05:00
nabeelio
d2e1004e08 Undo composer downgrades 2021-03-04 17:17:39 -05:00
Nabeel S
3800c01d94 Update to Laravel 8 (#1058)
* Update Laravel and other dependencies

* Composer version in CI

* Remove the PHP exit from env file

* Add PHP 8 to testing matrix

* Update doctrine

* Update doctrine

* Update faker lib

* Rewrite TLD check to remove deprecated library

* Update version lib

* Remove PHP 8 for now

* Style fixes
2021-03-04 17:08:51 -05:00
Nabeel S
922e754c9e Check for valid reference object in recurring finance (#1056) 2021-03-02 16:19:54 -05:00
Nabeel S
936cd2efd3 Implement PIREP deletion #1014 (#1055)
* Implement PIREP deletion #1014

* Style fixes

* Add delete button to PIREP listing page

* Remove extra import
2021-03-02 15:43:34 -05:00
Nabeel S
e22d6d5996 Refactoring Simbrief fares and aircraft (#1054)
* Refactoring simbrief fares and aircraft

* Hide user full name/email

* Sort PIREP fields desc; fix cargo counts

* Change the sorting

* Extra logs

* Fix tests

* Return fare information through the API

* Style fixes

* Test fix

* Another test fix

* More fixes

* Set aircraft and fares in prefile

* Formatting
2021-03-02 12:29:04 -05:00
B.Fatih KOZ
efcb7e8895 Fix Advanced Fuel Calculations (#1053)
Due to an error on the settings check advanced fuel calculations was not working and defaulting to fuel used always.
2021-03-01 15:03:27 -05:00
Nabeel S
43fbe9e943 Update composer dependencies (#1047) 2021-02-26 12:23:50 -05:00
nabeelio
8fc0aec800 Set cache driver to array for tests 2021-02-25 13:50:37 -05:00
Nabeel Shahzad
bb84fa82a4 Default to file storage for sesions 2021-02-24 13:37:46 -05:00
B.Fatih KOZ
4fe323a763 Advanced Fuel Calculations (#1044)
* Advanced Fuel Calculations

PR aims to have realistic fuel debit calculations as in the real ops. When enabled, remaining fuel amounts from previous flight will be reduced from block fuel and airline will only pay for uplifted fuel amount.

If onboard fuel is enough for the flight or exceeds the required amount no fuel debit will be issued.

If this is the first flight of the aircraft or the tanks are dry, full block fuel will be treated as uplifted.

Disabled / uses current default (fuel_used will be debited)

Aircraft table also will hold the fuel_onboard value (not needed for calculations, just saving for displaying purposes)

* Style Fix

* Another Style Fix

Love StyleCi

* Fix Settings

Moved new setting under other pirep settings

* Fix Setting Check

* Fix EOF settings.yml

* Fix Settings
2021-02-24 12:22:52 -05:00
B.Fatih KOZ
e3b4a0ed2e SimBrief integration enhancements (#1045)
* SimBrief Integration Update

* Added SimBrief Type field to subfleets, can be used to assign simbrief airframes to subfleets and fix non existing or wrong types. If not used simbrief form will use aircraft's icao type code

* Added Passenger and Baggage weights to settings

* Added setting for using PhpVms Pilot/User  Ident as simbrief atc callsign

* SimBrief form code cleaned up a bit and improved. Now form supports both cargo and passenger fares to be used at the same time.

Generated passenger baggage weight will be reduced from aircraft's cargo capacity and remaining amount will be used for random cargo generation.

Also multiple cargo fares or any mix is possible now (like only cargo, only passenger, multiple cargo and passenger fares)

* StyleFix (SimBrief Controller)

* Fix Callsign Setting Check

* Code Cleanup

Reduced loops and removed if's in loops, getting fares from aircraft instead of flight/subfleets.

No need to go through getReconciledFaresForFlight anymore. Aircraft provides all fare info we need.

Removed unnecessary html elements, added some comments.

* Update Simbrief Controller

Fixed setting checks.

Removed non used $subfleet and from main form and $aircraft from aircraft selection form blade.

Added/fixed comments.

* StyleFix for Controller
2021-02-24 09:32:29 -05:00
Nabeel Shahzad
a4c431d39f Set missing value from default 2021-02-23 11:25:06 -05:00
Nabeel Shahzad
a52e0410a7 Force default to the value when syncing settings 2021-02-23 11:23:40 -05:00
B.Fatih KOZ
baf63361a0 Fix findUsersOnleave Function (#1042)
Query was checking status field instead of state field to find active users.
2021-02-22 11:23:50 -05:00
B.Fatih KOZ
b4d5c0fbcd Weather METAR/TAF enhancements (#964)
* Update AviationWeather.php

Added the ability to fetch latest TAF report of given icao from ADDS/NOAA

* Update Weather.php

Used updated Metar\AviationWeather service to improve the widget ability and provide raw TAF data for the view

* Style Fix 1

* Update weather.blade.php

Updated blade to match updated Metar\AviationWeather service and the Weather widget controller.

Also fixed the order of temp - dewpoint - humidity - visibility display according to aviation usage.

Widget now displays raw TAF data just below raw METAR data.

* Update Metar inferface and wrap TAF retrieval in cache

* Styles fix

* Add call to getTaf. Don't call AviationWeather directly

* Fix cache lookup strings

* Fix recursion error

* Update weather.blade.php

Used latest weather.blade , added $taf['raw'] after raw metar.

* Compatibility Update

Updated the widget controller to match latest dev (added raw_only to config)

* Update Weather Widget Blade

Made the widget blade compatible with the TAF reports, widget will display raw metar and taf after the decoder, if no metar or taf recieved it will be displayed in its own row. Also added the new option of raw_only to blade, if it is true, metar decoding will be skipped and only raw values will be displayed. ( Useful when displaying multiple wx widgets at the same page for departure, destination and alternate etc )

Co-authored-by: Nabeel Shahzad <nshahzad@live.com>
Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-02-19 12:45:39 -05:00
B.Fatih KOZ
6b7eab05e2 Assign subfleets from ranks when there are no subfleets on a flight
If no subfleets are assigned to a flight, vmsacars was not allowing the flight to be loaded and used 'cause the subfleets was returning null. With this pr, users will be able to use the aircrafts which they have access to by their ranks. ( Same logic was used in SimBrief Controller to populate the aircraft list for flight plan generation )

Co-authored-by: Nabeel S <nabeelio@users.noreply.github.com>
2021-02-19 08:20:17 -05:00
Jannis D
4c8e31ac6f Update installer.php (#1038)
Co-authored-by: Jannis D <Mail@JannisD.de>
2021-02-19 08:13:08 -05:00
B.Fatih KOZ
fe41e61c02 Fix for SimBrief VATSIM Prefile errors (#1037)
Speed is now checked and leading zero is removed, also changed the initial altitude to full feet value like 23000 instead of just 230.
2021-02-18 18:02:33 -05:00
Nabeel Shahzad
bd85a04530 Fix internal event for ON_LEAVE 2021-02-17 18:57:16 -05:00
Nabeel S
cbb7d6e274 Fix pilot leave calculation #1022 (#1035)
* Fix pilot leave calculation #1022

* Remove unused imports

* Add logging where fares are being saved
2021-02-17 18:54:18 -05:00
Nabeel Shahzad
8907527872 Remove invalid bids #1034 2021-02-17 18:03:07 -05:00
Nabeel Shahzad
942c060c99 Added opcache package 2021-02-17 14:44:41 -05:00
Nabeel Shahzad
68a9421445 Shrink backup sizes 2021-02-17 14:38:47 -05:00
Nabeel Shahzad
4e652c91ae Account for localhost/testing sites in domain checks 2021-02-13 15:59:19 -05:00
Nabeel Shahzad
a6f62045c4 Extend cron check for 12 hours 2021-02-13 15:17:16 -05:00
Nabeel Shahzad
3f3b63da6f Fix session database configuration 2021-02-12 11:43:00 -05:00
Nabeel Shahzad
dd7812e5c5 Undo primary idx change 2021-02-11 08:57:43 -05:00
Nabeel S
447d02bd4f Update the sessions table (#1030)
* Update the sessions table

* Add index on user_id
2021-02-11 08:50:49 -05:00
Nabeel Shahzad
be9b698f14 Merge branch 'dev' of https://github.com/nabeelio/phpvms into dev 2021-02-10 15:47:42 -05:00
Nabeel S
d110c2d951 ACARS table vs int to double (#1028)
* mail config - "driver" to "default"

* Change VS type from int to double

* Migration fix

* Fix type
2021-02-10 13:39:40 -05:00
Nabeel Shahzad
4d20998368 mail config - "driver" to "default" 2021-02-10 13:18:02 -05:00
Nabeel Shahzad
4a20b41b25 Rename driver to default in mail config 2021-02-10 13:15:18 -05:00
Olli
8c2513eb3d Update style.css for better mobile experience (#1018)
This edit hides the dropdown menu while being closed on mobile view
2021-02-05 08:38:32 -05:00
Nabeel Shahzad
2dbd58e59e Merge branch 'dev' of https://github.com/nabeelio/phpvms into dev 2021-02-04 14:54:20 -05:00
Nabeel Shahzad
bf77f7dd96 Add 'phase' as response output, deprecate "status" 2021-02-04 14:54:16 -05:00
B.Fatih KOZ
5a570989de Failsafe for SimBrief random pax generation (#1015)
* Failsafe for SimBrief random pax generation

PR fixes the problem for 0 load generation where va admins do not set load factor and variance values for their flights and also leave the general settings empty. In such cases, both loadmin and loadmax was returning 0 , resulting zero load.

Thanks @macofallico for figuring this out.

* StyleFix
2021-02-01 15:27:22 -05:00
B.Fatih KOZ
6b3207377a Fix Profile Fields (#1013)
* Fix Profile Fields

PR fixes two issues ;

1. Profile Fields not showing up on user profile
2. Profile Fields not showing up on user.profile.edit

Profile.index was looking for "public" to be true, while controller was sending "private" and it was not boolean.

Also profile controller was not sending the fields to the blade. Both fixed and working now

* Update index.blade.php
2021-01-28 08:31:29 -05:00
B.Fatih KOZ
ac1d5e1555 Fix PilotHoursAwards (#1011)
!is_int was causing the check always return false even when user enters a proper value like 6000 or 30000 in admin/award settings.

We should use !is_numeric instead to see if it is a valid numeric value.
2021-01-26 19:48:43 -05:00
B.Fatih KOZ
0d45fc287b AwardController text correction (#1010)
Fixed the flash message texts
2021-01-26 16:31:54 -05:00
B.Fatih KOZ
4911f6799d Fix for ACARS config download button not working #919 (#1009)
* Fix For Acars Config Download Button No Working Bug #919

PR fixes the Acars Config Download button not showing up at user profile.

Also fixes the problem where Generate New Api Key button not following user selections and generating a new key even if user clicks cancel.

* Style Fix for ? and !

Fix the typo :)
2021-01-25 16:04:43 -05:00
403 changed files with 48647 additions and 41414 deletions

View File

@@ -30,6 +30,7 @@ declare -a remove_files=(
intellij_style.xml
config.php
docker-compose.yml
docker-compose.local.yml
Makefile
phpcs.xml
phpunit.xml
@@ -73,8 +74,12 @@ ls -al $BASE_DIR/../
tar -czf $TAR_NAME -C $BASE_DIR .
sha256sum $TAR_NAME >"$TAR_NAME.sha256"
tar2zip $TAR_NAME
cd $BASE_DIR;
zip -r $ZIP_NAME *
sha256sum $ZIP_NAME >"$ZIP_NAME.sha256"
mv $ZIP_NAME /tmp
mv "$ZIP_NAME.sha256" /tmp
ls -al /tmp

View File

@@ -1,7 +1,3 @@
<?php
exit();
?>
APP_ENV="dev"
APP_KEY="base64:zdgcDqu9PM8uGWCtMxd74ZqdGJIrnw812oRMmwDF6KY="
APP_URL="http://localhost"
@@ -12,7 +8,7 @@ APP_LOCALE="en"
PHPVMS_INSTALLED="true"
APP_LOG="daily"
APP_LOG_LEVEL="debug"
LOG_LEVEL="debug"
APP_LOG_MAX_FILES="3"
DB_CONNECTION="mysql"

View File

@@ -7,7 +7,7 @@ jobs:
strategy:
fail-fast: true
matrix:
php-versions: ['7.3', '7.4']
php-versions: ['7.3', '7.4', '8.0']
name: PHP ${{ matrix.php-versions }}
env:
extensions: intl, pcov, mbstring
@@ -41,7 +41,6 @@ jobs:
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
# Configure PHP
- name: Setup PHP
@@ -71,7 +70,6 @@ jobs:
php --version
mysql --version
# Downgrade composer version to 1.x
composer self-update --1
composer install --dev --no-interaction --verbose
cp .github/scripts/env.php env.php
cp .github/scripts/phpunit.xml phpunit.xml
@@ -119,7 +117,6 @@ jobs:
run: |
rm -rf vendor
sudo npm i tar-to-zip -g
composer self-update --1
composer install --no-dev --prefer-dist --no-interaction --verbose
sudo chmod +x ./.github/scripts/*
@@ -183,7 +180,6 @@ jobs:
run: |
rm -rf vendor
sudo npm i tar-to-zip -g
composer self-update --1
composer install --no-dev --prefer-dist --no-interaction --verbose
sudo chmod +x ./.github/scripts/*

1
.gitignore vendored
View File

@@ -74,4 +74,5 @@ error_log
.sass-cache
.DS_Store
/config.php
/config.bak.php
/VERSION

View File

@@ -28,6 +28,8 @@ RedirectMatch 403 ^/composer.phar
RedirectMatch 403 ^/env.php.*?$
RedirectMatch 403 ^/env.php
RedirectMatch 403 ^/env.php$
RedirectMatch 403 ^/config.php$
RedirectMatch 403 ^/config.bak.php$
RedirectMatch 403 ^/Makefile
RedirectMatch 403 ^/package.json
RedirectMatch 403 ^/package-lock.json

View File

@@ -2,7 +2,7 @@ FROM php:7.4-fpm-alpine
WORKDIR /var/www/
RUN apk add gmp-dev
RUN apk add gmp-dev icu-dev zlib-dev libpng-dev
RUN curl --silent --show-error https://getcomposer.org/installer | php
# Copy any config files in
@@ -12,7 +12,9 @@ RUN ln -sf /dev/stderr /var/log/fpm-error.log
RUN docker-php-ext-install \
calendar \
intl \
pdo_mysql \
gd \
gmp \
opcache && \
docker-php-ext-enable pdo_mysql opcache
@@ -25,4 +27,6 @@ RUN php composer.phar install \
--no-scripts \
--prefer-dist
RUN chown -R www-data:www-data /var/www
EXPOSE 9000

View File

@@ -109,17 +109,9 @@ reset-installer:
@php artisan database:create --reset
@php artisan migrate:refresh --seed
.PHONY: docker
docker:
@mkdir -p $(CURR_PATH)/tmp/mysql
-docker rm -f phpvms
docker build -t phpvms .
docker run --name=phpvms \
-v $(CURR_PATH):/var/www/ \
-v $(CURR_PATH)/tmp/mysql:/var/lib/mysql \
-p 8080:80 \
phpvms
.PHONY: docker-test
docker-test:
@docker-compose -f docker-compose.yml -f docker-compose.local.yml up
.PHONY: docker-clean
docker-clean:

View File

@@ -30,15 +30,16 @@ A full distribution, with all of the composer dependencies, is available at this
[View installation details](https://docs.phpvms.net/installation/installation)
## Development Environment
## Development Environment with Docker
A full development environment can be brought up using Docker:
A full development environment can be brought up using Docker, without having to install composer/npm locally
```bash
composer install
yarn install
docker-compose build
docker-compose up
make docker-test
# **OR** with docker-compose directly
docker-compose -f docker-compose.yml -f docker-compose.local.yml up
```
Then go to `http://localhost`. If you're using dnsmasq, the `app` container is listening on `phpvms.test`, or you can add to your `/etc/hosts` file:
@@ -47,6 +48,8 @@ Then go to `http://localhost`. If you're using dnsmasq, the `app` container is l
127.0.0.1 phpvms.test
```
The `docker-compose.local.yml` overrides the `app` section in `docker-compose.yml`. The standard `docker-compose.yml` can be used if you want to deploy from the image, or as a template for your own Dockerized deployments.
### Building JS/CSS assets
Yarn is required, run:

View File

@@ -4,9 +4,9 @@ namespace App\Console\Commands;
use App;
use App\Contracts\Command;
use App\Services\Installer\ConfigService;
use App\Services\Installer\SeederService;
use DatabaseSeeder;
use Modules\Installer\Services\ConfigService;
/**
* Create the config files
@@ -81,13 +81,13 @@ class CreateConfigs extends Command
$this->info('Regenerating the config files');
$cfgSvc->createConfigFiles([
'APP_ENV' => 'dev',
'SITE_NAME' => $this->argument('name'),
'DB_CONN' => 'mysql',
'DB_HOST' => $this->argument('db_host'),
'DB_NAME' => $this->argument('db_name'),
'DB_USER' => $this->argument('db_user'),
'DB_PASS' => $this->argument('db_pass'),
'APP_ENV' => 'dev',
'SITE_NAME' => $this->argument('name'),
'DB_CONNECTION' => 'mysql',
'DB_HOST' => $this->argument('db_host'),
'DB_DATABASE' => $this->argument('db_name'),
'DB_USERNAME' => $this->argument('db_user'),
'DB_PASSWORD' => $this->argument('db_pass'),
]);
$this->info('Config files generated!');

View File

@@ -79,9 +79,9 @@ class DevInstall extends Command
$this->info('Regenerating the config files');
$cfgSvc->createConfigFiles([
'APP_ENV' => 'dev',
'SITE_NAME' => 'phpvms test',
'DB_CONN' => 'sqlite',
'APP_ENV' => 'dev',
'SITE_NAME' => 'phpvms test',
'DB_CONNECTION' => 'sqlite',
]);
$this->info('Config files generated!');

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Console\Commands;
use App;
use App\Contracts\Command;
class EmailTest extends Command
{
protected $signature = 'phpvms:email-test';
protected $description = 'Send a test notification to admins';
/**
* Run dev related commands
*
* @throws \Symfony\Component\HttpFoundation\File\Exception\FileException
*/
public function handle()
{
/** @var App\Notifications\NotificationEventsHandler $eventHandler */
$eventHandler = app(App\Notifications\NotificationEventsHandler::class);
$news = new App\Models\News();
$news->user_id = 1;
$news->subject = 'Test News';
$news->body = 'Test Body';
$news->save();
$newsEvent = new App\Events\NewsAdded($news);
$eventHandler->onNewsAdded($newsEvent);
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Console\Commands;
use App;
use App\Contracts\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
class ProcessQueue extends Command
{
protected $signature = 'queue:cron';
protected $description = 'Process the queue from a cron job';
/**
* Run the queue tasks
*/
public function handle()
{
Artisan::call('queue:work', [
'--sansdaemon' => null,
'--stop-when-empty' => null,
]);
Log::info(Artisan::output());
///** @var App\Support\WorkCommand $queueWorker */
//$queueWorker = new App\Support\WorkCommand(app('queue.worker'), app('cache.store'));
//$queueWorker->setInput($queueWorker->createInputFromArguments([]));
//$queueWorker->handle();
/*$output = $this->call('queue:work', [
'--stop-when-empty' => null,
]);
Log::info($output);*/
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Console\Commands;
use App\Contracts\Command;
use App\Services\Installer\ConfigService;
/**
* Command to rewrite the config files
*/
class RewriteConfigs extends Command
{
protected $signature = 'phpvms:rewrite-configs';
protected $description = 'Rewrite the config files';
/**
* Run dev related commands
*/
public function handle()
{
/** @var ConfigService $configSvc */
$configSvc = app(ConfigService::class);
$configSvc->rewriteConfigFiles();
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Console\Cron;
use App\Contracts\Command;
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
{
protected $signature = 'cron:queue';
protected $description = 'Run the cron queue tasks';
protected $schedule;
public function handle(): void
{
$this->redirectLoggingToFile('cron');
Artisan::call('queue:cron');
$this->info(Artisan::output());
}
}

View File

@@ -3,6 +3,7 @@
namespace App\Console;
use App\Console\Cron\Hourly;
use App\Console\Cron\JobQueue;
use App\Console\Cron\Monthly;
use App\Console\Cron\Nightly;
use App\Console\Cron\Weekly;
@@ -13,7 +14,11 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
* Define the application's command schedule. How this works... according to the command
* time, an event gets send out with the appropriate time (e.g, hourly sends an hourly event)
*
* Then the CronServiceProvider has the list of cronjobs which then run according to the events
* and then calls those at the proper times.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
*
@@ -21,16 +26,26 @@ class Kernel extends ConsoleKernel
*/
protected function schedule(Schedule $schedule): void
{
// If not using the queue worker then run those via cron
if (!config('queue.worker', false)) {
$schedule->command(JobQueue::class)
->everyMinute()
->withoutOverlapping();
}
$schedule->command(Nightly::class)->dailyAt('01:00');
$schedule->command(Weekly::class)->weeklyOn(0);
$schedule->command(Monthly::class)->monthlyOn(1);
$schedule->command(Hourly::class)->hourly();
// When spatie-backups runs
$schedule->command('backup:clean')->daily()->at('01:00');
$schedule->command('backup:run')->daily()->at('02:00');
/*if (config('backup.backup.enabled', false) === true) {
$schedule->command('backup:clean')->daily()->at('01:00');
$schedule->command('backup:run')->daily()->at('02:00');
}*/
// Update the last time the cron was run
/** @var CronService $cronSvc */
$cronSvc = app(CronService::class);
$cronSvc->updateLastRunTime();
}

View File

@@ -24,9 +24,9 @@ abstract class Command extends \Illuminate\Console\Command
parent::__construct();
// Running in the console but not in the tests
if (app()->runningInConsole() && env('APP_ENV') !== 'testing') {
/*if (app()->runningInConsole() && env('APP_ENV') !== 'testing') {
$this->redirectLoggingToFile('stdout');
}
}*/
}
/**

View File

@@ -12,13 +12,24 @@ abstract class Metar
{
/**
* Implement retrieving the METAR - return the METAR string. Needs to be protected,
* since this shouldn't be directly called. Call `get_metar($icao)` instead
* since this shouldn't be directly called. Call `metar($icao)`. If not implemented,
* return a blank string
*
* @param $icao
*
* @return mixed
*/
abstract protected function metar($icao): string;
abstract protected function get_metar($icao): string;
/**
* Implement retrieving the TAF - return the string. Call `taf($icao)`. If not implemented,
* return a blank string
*
* @param $icao
*
* @return mixed
*/
abstract protected function get_taf($icao): string;
/**
* Download the METAR, wrap in caching
@@ -27,9 +38,9 @@ abstract class Metar
*
* @return string
*/
public function get_metar($icao): string
public function metar($icao): string
{
$cache = config('cache.keys.WEATHER_LOOKUP');
$cache = config('cache.keys.METAR_WEATHER_LOOKUP');
$key = $cache['key'].$icao;
if (Cache::has($key)) {
@@ -40,7 +51,7 @@ abstract class Metar
}
try {
$raw_metar = $this->metar($icao);
$raw_metar = $this->get_metar($icao);
} catch (\Exception $e) {
Log::error('Error getting METAR: '.$e->getMessage(), $e->getTrace());
return '';
@@ -52,4 +63,37 @@ abstract class Metar
return $raw_metar;
}
/**
* Download the TAF, wrap in caching
*
* @param $icao
*
* @return string
*/
public function taf($icao): string
{
$cache = config('cache.keys.TAF_WEATHER_LOOKUP');
$key = $cache['key'].$icao;
if (Cache::has($key)) {
$taf = Cache::get($key);
if ($taf !== '') {
return $taf;
}
}
try {
$taf = $this->get_taf($icao);
} catch (\Exception $e) {
Log::error('Error getting TAF: '.$e->getMessage(), $e->getTrace());
return '';
}
if ($taf !== '') {
Cache::put($key, $taf, $cache['time']);
}
return $taf;
}
}

View File

@@ -2,9 +2,9 @@
namespace App\Contracts;
use App\Notifications\Channels\Discord\DiscordMessage;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;
class Notification extends \Illuminate\Notifications\Notification implements ShouldQueue
{
@@ -17,14 +17,14 @@ class Notification extends \Illuminate\Notifications\Notification implements Sho
{
// Look in the notifications.channels config and see where this particular
// notification can go. Map it to $channels
$klass = static::class;
/*$klass = static::class;
$notif_config = config('notifications.channels', []);
if (!array_key_exists($klass, $notif_config)) {
Log::error('Notification type '.$klass.' missing from notifications config, defaulting to mail');
return;
}
$this->channels = $notif_config[$klass];
$this->channels = $notif_config[$klass];*/
}
/**
@@ -34,8 +34,16 @@ class Notification extends \Illuminate\Notifications\Notification implements Sho
*
* @return array
*/
public function via($notifiable)
/*public function via($notifiable)
{
return $this->channels;
}*/
/**
* @return DiscordMessage|null
*/
public function toDiscordChannel($notifiable): ?DiscordMessage
{
return null;
}
}

View File

@@ -2,11 +2,14 @@
namespace App\Contracts;
use Exception;
use Illuminate\Validation\Validator;
use function is_array;
use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Exceptions\RepositoryException;
/**
* @mixin \Prettus\Repository\Eloquent\BaseRepository
* @mixin BaseRepository
*/
abstract class Repository extends BaseRepository
{
@@ -20,8 +23,8 @@ abstract class Repository extends BaseRepository
{
try {
return $this->find($id, $columns);
} catch (\Exception $e) {
return;
} catch (Exception $e) {
return null;
}
}
@@ -32,11 +35,7 @@ abstract class Repository extends BaseRepository
*/
public function validate($values)
{
$validator = Validator::make(
$values,
$this->model()->rules
);
$validator = Validator::make($values, $this->model()->rules);
if ($validator->fails()) {
return $validator->messages();
}
@@ -50,6 +49,8 @@ abstract class Repository extends BaseRepository
* @param int $count
* @param string $sort_by created_at (default) or updated_at
*
* @throws RepositoryException
*
* @return mixed
*/
public function recent($count = null, $sort_by = 'created_at')
@@ -71,7 +72,7 @@ abstract class Repository extends BaseRepository
return $this->scopeQuery(function ($query) use ($where, $sort_by, $order_by) {
$q = $query->where($where);
// See if there are multi-column sorts
if (\is_array($sort_by)) {
if (is_array($sort_by)) {
foreach ($sort_by as $key => $sort) {
$q = $q->orderBy($key, $sort);
}
@@ -98,7 +99,7 @@ abstract class Repository extends BaseRepository
return $this->scopeQuery(function ($query) use ($col, $values, $sort_by, $order_by) {
$q = $query->whereNotIn($col, $values);
// See if there are multi-column sorts
if (\is_array($sort_by)) {
if (is_array($sort_by)) {
foreach ($sort_by as $key => $sort) {
$q = $q->orderBy($key, $sort);
}
@@ -118,7 +119,7 @@ abstract class Repository extends BaseRepository
* @param array $columns
* @param string $method
*
* @throws \Prettus\Repository\Exceptions\RepositoryException
* @throws RepositoryException
*
* @return mixed
*/

View File

@@ -2,7 +2,10 @@
namespace App\Contracts;
use App\Support\Resources\CustomAnonymousResourceCollection;
use App\Support\Resources\CustomPaginatedResourceResponse;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Pagination\AbstractPaginator;
/**
* Base class for a resource/response
@@ -26,4 +29,28 @@ class Resource extends JsonResource
}
}
}
/**
* Customize the response to exclude all the extra data that isn't used. Based on:
* https://gist.github.com/derekphilipau/4be52164a69ce487dcd0673656d280da
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\JsonResponse
*/
public function toResponse($request)
{
return $this->resource instanceof AbstractPaginator
? (new CustomPaginatedResourceResponse($this))->toResponse($request)
: parent::toResponse($request);
}
public static function collection($resource)
{
return tap(new CustomAnonymousResourceCollection($resource, static::class), function ($collection) {
if (property_exists(static::class, 'preserveKeys')) {
$collection->preserveKeys = (new static([]))->preserveKeys === true;
}
});
}
}

View File

@@ -1,10 +1,11 @@
<?php
namespace App\Cron\Nightly;
namespace App\Cron\Hourly;
use App\Contracts\Listener;
use App\Events\CronNightly;
use App\Events\CronHourly;
use App\Services\SimBriefService;
use Illuminate\Support\Facades\Log;
/**
* Clear any expired SimBrief flight briefs that aren't attached to a PIREP
@@ -21,8 +22,9 @@ class ClearExpiredSimbrief extends Listener
/**
* @param \App\Events\CronNightly $event
*/
public function handle(CronNightly $event): void
public function handle(CronHourly $event): void
{
Log::info('Hourly: Removing expired Simbrief entries');
$this->simbriefSvc->removeExpiredEntries();
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Cron\Hourly;
use App\Contracts\Listener;
use App\Events\CronHourly;
use App\Models\Enums\PirepState;
use App\Models\Pirep;
use App\Services\PirepService;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
/**
* Remove cancelled/deleted PIREPs. Look for PIREPs that were created before the setting time
* (e.g, 12 hours ago) and are marked with the
*/
class DeletePireps extends Listener
{
/**
* Delete old rejected PIREPs
*
* @param CronHourly $event
*
* @throws \Exception
*/
public function handle(CronHourly $event): void
{
$this->deletePireps(setting('pireps.delete_rejected_hours'), PirepState::REJECTED);
$this->deletePireps(setting('pireps.delete_cancelled_hours'), PirepState::CANCELLED);
}
/**
* Look for and delete PIREPs which match the criteria
*
* @param int $expire_time_hours The time in hours to look for PIREPs
* @param int $state The PirepState enum value
*/
protected function deletePireps(int $expire_time_hours, int $state)
{
$dt = Carbon::now('UTC')->subHours($expire_time_hours);
$pireps = Pirep::where('created_at', '<', $dt)->where(['state' => $state])->get();
/** @var PirepService $pirepSvc */
$pirepSvc = app(PirepService::class);
/** @var Pirep $pirep */
foreach ($pireps as $pirep) {
Log::info('Cron: Deleting PIREP id='.$pirep->id.', state='.PirepState::label($state));
$pirepSvc->delete($pirep);
}
}
}

View File

@@ -25,7 +25,7 @@ class RemoveExpiredBids extends Listener
return;
}
$date = Carbon::now()->subHours(setting('bids.expire_time'));
Bid::whereDate('created_at', '<', $date)->delete();
$date = Carbon::now('UTC')->subHours(setting('bids.expire_time'));
Bid::where('created_at', '<', $date)->delete();
}
}

View File

@@ -4,9 +4,11 @@ namespace App\Cron\Hourly;
use App\Contracts\Listener;
use App\Events\CronHourly;
use App\Events\PirepCancelled;
use App\Models\Enums\PirepState;
use App\Models\Pirep;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
/**
* Remove expired live flights
@@ -26,9 +28,14 @@ class RemoveExpiredLiveFlights extends Listener
return;
}
$date = Carbon::now()->subHours(setting('acars.live_time'));
Pirep::whereDate('updated_at', '<', $date)
$date = Carbon::now('UTC')->subHours(setting('acars.live_time'));
$pireps = Pirep::where('updated_at', '<', $date)
->where('state', PirepState::IN_PROGRESS)
->delete();
->get();
foreach ($pireps as $pirep) {
event(new PirepCancelled($pirep));
Log::info('Cron: Deleting Expired Live PIREP id='.$pirep->id.', state='.PirepState::label($pirep->state));
$pirep->delete();
}
}
}

View File

@@ -6,6 +6,7 @@ use App\Contracts\Listener;
use App\Events\CronMonthly;
use App\Models\Enums\ExpenseType;
use App\Services\Finance\RecurringFinanceService;
use Illuminate\Support\Facades\Log;
/**
* Go through and apply any finances that are daily
@@ -35,6 +36,7 @@ class ApplyExpenses extends Listener
*/
public function handle(CronMonthly $event): void
{
Log::info('Monthly: Applying monthly expenses');
$this->financeSvc->processExpenses(ExpenseType::MONTHLY);
}
}

View File

@@ -6,6 +6,7 @@ use App\Contracts\Listener;
use App\Events\CronNightly;
use App\Models\Enums\ExpenseType;
use App\Services\Finance\RecurringFinanceService;
use Illuminate\Support\Facades\Log;
/**
* Go through and apply any finances that are daily
@@ -35,6 +36,7 @@ class ApplyExpenses extends Listener
*/
public function handle(CronNightly $event): void
{
Log::info('Nightly: Applying daily expenses');
$this->financeSvc->processExpenses(ExpenseType::DAILY);
}
}

View File

@@ -5,10 +5,8 @@ namespace App\Cron\Nightly;
use App\Contracts\Listener;
use App\Events\CronNightly;
use App\Services\VersionService;
use Illuminate\Support\Facades\Log;
/**
* Determine if any pilots should be set to ON LEAVE status
*/
class NewVersionCheck extends Listener
{
private $versionSvc;
@@ -28,6 +26,7 @@ class NewVersionCheck extends Listener
*/
public function handle(CronNightly $event): void
{
Log::info('Nightly: Checking for new version');
$this->versionSvc->isNewVersionAvailable();
}
}

View File

@@ -4,10 +4,8 @@ namespace App\Cron\Nightly;
use App\Contracts\Listener;
use App\Events\CronNightly;
use App\Models\Enums\UserState;
use App\Models\User;
use App\Services\UserService;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
/**
* Determine if any pilots should be set to ON LEAVE status
@@ -18,6 +16,8 @@ class PilotLeave extends Listener
/**
* PilotLeave constructor.
*
* @param UserService $userSvc
*/
public function __construct(UserService $userSvc)
{
@@ -34,13 +34,9 @@ class PilotLeave extends Listener
*/
public function handle(CronNightly $event): void
{
if (setting('pilots.auto_leave_days') === 0) {
return;
}
$date = Carbon::now()->subDay(setting('pilots.auto_leave_days'));
$users = User::where('status', UserState::ACTIVE)
->whereDate('updated_at', '<', $date);
Log::info('Cron: Running pilot leave check');
$users = $this->userSvc->findUsersOnLeave();
Log::info('Found '.count($users).' users on leave');
foreach ($users as $user) {
Log::info('Setting user '.$user->ident.' to ON LEAVE status');

View File

@@ -35,7 +35,7 @@ class RecalculateBalances extends Listener
*/
public function handle(CronNightly $event): void
{
Log::info('Recalculating balances');
Log::info('Nightly: Recalculating balances');
$journals = Journal::all();
foreach ($journals as $journal) {

View File

@@ -32,10 +32,10 @@ class RecalculateStats extends Listener
*/
public function handle(CronNightly $event): void
{
Log::info('Recalculating user stats');
Log::info('Nightly: Recalculating user stats');
$this->userSvc->recalculateAllUserStats();
Log::info('Recalcuating aircraft status');
Log::info('Nightly: Recalcuating aircraft status');
$this->aircraftSvc->recalculateStats();
}
}

View File

@@ -19,6 +19,8 @@ class SetActiveFlights extends Listener
*/
public function handle(CronNightly $event): void
{
Log::info('Nightly: Setting active flights');
$this->checkFlights();
}

View File

@@ -11,7 +11,7 @@ if (!function_exists('createFactoryICAO')) {
$characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$max = strlen($characters) - 1;
$string = '';
for ($i = 0; $i < 4; $i++) {
for ($i = 0; $i < 5; $i++) {
try {
$string .= $characters[random_int(0, $max)];
} catch (Exception $e) {

View File

@@ -1,17 +1,20 @@
<?php
use App\Models\Journal;
use Carbon\Carbon;
use Faker\Generator as Faker;
use Ramsey\Uuid\Uuid;
$factory->define(App\Models\JournalTransactions::class, function (Faker $faker) {
$factory->define(App\Models\JournalTransaction::class, function (Faker $faker) {
return [
'transaction_group' => \Ramsey\Uuid\Uuid::uuid4()->toString(),
'transaction_group' => Uuid::uuid4()->toString(),
'journal_id' => function () {
return factory(\App\Models\Journal::class)->create()->id;
return factory(Journal::class)->create()->id;
},
'credit' => $faker->numberBetween(100, 10000),
'debit' => $faker->numberBetween(100, 10000),
'currency' => 'USD',
'memo' => $faker->sentence(6),
'post_date' => \Carbon\Carbon::now(),
'post_date' => Carbon::now('UTC'),
];
});

View File

@@ -0,0 +1,13 @@
<?php
use Faker\Generator as Faker;
$factory->define(App\Models\Role::class, function (Faker $faker) {
return [
'id' => null,
'name' => $faker->name,
'display_name' => $faker->name,
'read_only' => false,
'disable_activity_checks' => $faker->boolean(),
];
});

View File

@@ -0,0 +1,18 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Change the vertical speed for the acars table to a double
*/
class ChangeAcarsVsType extends Migration
{
public function up()
{
Schema::table('acars', function (Blueprint $table) {
$table->float('vs')->change()->default(0.0)->nullable();
});
}
}

View File

@@ -0,0 +1,19 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Bring the sessions table in line with the latest
*/
class UpdateSessionsTable extends Migration
{
public function up()
{
Schema::table('sessions', function (Blueprint $table) {
$table->index('user_id');
$table->index('last_activity');
});
}
}

View File

@@ -0,0 +1,21 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Add a `fuel_onboard` column for recording what is left in tanks
*/
class AircraftAddFuelonboard extends Migration
{
public function up()
{
Schema::table('aircraft', function (Blueprint $table) {
$table->unsignedDecimal('fuel_onboard')
->nullable()
->default(0.0)
->after('zfw');
});
}
}

View File

@@ -0,0 +1,20 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Add a SimBrief Type to subfleet
*/
class AddSbtypeToSubfleets extends Migration
{
public function up()
{
Schema::table('subfleets', function (Blueprint $table) {
$table->string('simbrief_type', 20)
->nullable()
->after('type');
});
}
}

View File

@@ -0,0 +1,24 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Add a hub to the subfleet is
*/
class AddAircraftToSimbrief extends Migration
{
public function up()
{
Schema::table('simbrief', function (Blueprint $table) {
$table->unsignedInteger('aircraft_id')
->nullable()
->after('pirep_id');
// Temp column to hold the calculated fare data for the API
// Remove this once the prefile to acars feature is completed
$table->mediumText('fare_data')->nullable()->after('ofp_xml');
});
}
}

View File

@@ -0,0 +1,19 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Add a hub to the subfleet is
*/
class AddKvpTable extends Migration
{
public function up()
{
Schema::create('kvp', function (Blueprint $table) {
$table->string('key')->index();
$table->string('value');
});
}
}

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddDisableactivitychecksToRoles extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('roles', function (Blueprint $table) {
$table->boolean('disable_activity_checks')
->default(false)
->after('read_only');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('roles', function (Blueprint $table) {
$table->dropColumn('disable_activity_checks');
});
}
}

View File

@@ -0,0 +1,19 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
class RemoveSettingRemoveBidOnAccept extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::table('settings')
->where(['key' => 'pireps.remove_bid_on_accept'])
->delete();
}
}

View File

@@ -0,0 +1,30 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Add a `anumeric_callsign` column for Alphanumeric Callsign to be assigned for a flight
* Exp DLH78BF, THY8EA, OGE1978
* According to FAA and EASA, callsigns must be maximum 7 chars in which first 3 chars is
* airline ICAO code remaining rest can be used freely according to airline's choices
*/
class FlightsAddAlphanumericCallsign extends Migration
{
public function up()
{
Schema::table('flights', function (Blueprint $table) {
$table->string('callsign', 4)
->nullable()
->after('flight_number');
});
}
public function down()
{
Schema::table('flights', function (Blueprint $table) {
$table->dropColumn('callsign');
});
}
}

View File

@@ -0,0 +1,21 @@
<?php
use App\Contracts\Migration;
use App\Services\Installer\ConfigService;
/**
* Migrate the configuration files
*/
class MigrateConfigs extends Migration
{
public function up()
{
/** @var ConfigService $configSvc */
$configSvc = app(ConfigService::class);
$configSvc->rewriteConfigFiles();
}
public function down()
{
}
}

View File

@@ -0,0 +1,26 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Increase Airport ICAO size to 5 chars
* https://github.com/nabeelio/phpvms/issues/1052
*/
class IncreaseIcaoSizes extends Migration
{
public function up()
{
Schema::table('airports', function (Blueprint $table) {
$table->string('iata', 5)->change();
$table->string('icao', 5)->change();
});
Schema::table('pireps', function (Blueprint $table) {
$table->string('dpt_airport_id', 5)->change();
$table->string('arr_airport_id', 5)->change();
$table->string('alt_airport_id', 5)->change();
});
}
}

View File

@@ -0,0 +1,19 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
class RemoveSettingSimbriefExpireDays extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
DB::table('settings')
->where(['key' => 'simbrief.expire_days'])
->delete();
}
}

View File

@@ -0,0 +1,32 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class DiscordFields extends Migration
{
public function up()
{
// Delete the old Discord fields and then a webhook will get added
DB::table('settings')
->where(['key' => 'notifications.discord_api_key'])
->delete();
DB::table('settings')
->where(['key' => 'notifications.discord_public_channel_id'])
->delete();
DB::table('settings')
->where(['key' => 'notifications.discord_public_channel_id'])
->delete();
// Add a field to the user to enter their own Discord ID
Schema::table('users', function (Blueprint $table) {
$table->string('discord_id')
->default('')
->after('rank_id');
});
}
}

View File

@@ -0,0 +1,18 @@
<?php
use App\Contracts\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class DiscordPrivateChannelId extends Migration
{
public function up()
{
// Add a field to the user to enter their own Discord ID
Schema::table('users', function (Blueprint $table) {
$table->string('discord_private_channel_id')
->default('')
->after('discord_id');
});
}
}

View File

@@ -1,519 +1,5 @@
acars:
- id: aM8QpMPEB15e
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.934117958358'
lon: '-76.77856721815'
heading: '124'
altitude: '8.1663703232199'
vs: '0'
gs: '0.0064996252497234'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: eZ6VJ3xj8vge
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.934117498661'
lon: '-76.778566516289'
heading: '124'
altitude: '8.1664622222087'
vs: '0'
gs: '0'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bo2QqDLl2lLa
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.933884143334'
lon: '-76.778210172233'
heading: '124'
altitude: '8.1707802663933'
vs: '0'
gs: '14.419195209695'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aM8QpM4qV2Be
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.933705349611'
lon: '-76.777936938059'
heading: '124'
altitude: '8.170089899507'
vs: '0'
gs: '15.392330039049'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dR6oxR9qjoOd
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.933130691906'
lon: '-76.777152737985'
heading: '158'
altitude: '8.1683570286331'
vs: '0'
gs: '10.450467475023'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: erkRwJODRvEa
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.932580370289'
lon: '-76.777450200122'
heading: '221'
altitude: '8.1695896791822'
vs: '0'
gs: '12.932334300694'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: b2kv53VMy7Ad
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.932012550651'
lon: '-76.778009113329'
heading: '296'
altitude: '8.1683852467213'
vs: '0'
gs: '10.502719192825'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: eXDoE14JxAve
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.932052237309'
lon: '-76.778111495187'
heading: '290'
altitude: '8.1719753739837'
vs: '0'
gs: '12.643743277153'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: b68R5gZ5YyOe
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.932664026837'
lon: '-76.779705339967'
heading: '293'
altitude: '8.2203963962548'
vs: '0'
gs: '64.870244840054'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bqxYvGNN5N0a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.934300220408'
lon: '-76.783954914814'
heading: '293'
altitude: '8.3302468103811'
vs: '0'
gs: '122.78529244208'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: en5rpBKw514d
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.935736496556'
lon: '-76.78765616448'
heading: '293'
altitude: '49.554739665916'
vs: '21'
gs: '146.79677958636'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: erkRwJA29l2a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '17.976972983585'
lon: '-76.896548114872'
heading: '297'
altitude: '6228.684012199'
vs: '62'
gs: '281.03976876098'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dR6oxR3r5nwd
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.061360208405'
lon: '-77.056156629983'
heading: '301'
altitude: '12522.331716891'
vs: '25'
gs: '371.70833265547'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e1wr82J877Zb
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.17373613295'
lon: '-77.260347185993'
heading: '301'
altitude: '16802.15636323'
vs: '43'
gs: '421.37353688139'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bqxYvGyExN2a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.193907285814'
lon: '-77.29810465405'
heading: '297'
altitude: '17395.953175647'
vs: '40'
gs: '425.98105291451'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aQW0wQDQk5Md
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.648921231143'
lon: '-78.014696613517'
heading: '323'
altitude: '37108.124381987'
vs: '22'
gs: '438.52028383384'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e9rQ5lk3p63a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.796585259338'
lon: '-78.194734005052'
heading: '260'
altitude: '39718.178225504'
vs: '19'
gs: '432.41969107334'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aQW0wQP8vZqd
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.660552760063'
lon: '-78.407597067994'
heading: '242'
altitude: '40998.775690971'
vs: '-25'
gs: '449.51695639627'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bqxYvGKgp32a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.592775999582'
lon: '-78.638711340118'
heading: '298'
altitude: '41060.297106821'
vs: '0'
gs: '427.14806185954'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: bqxYvGg2r02a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.718367591656'
lon: '-78.840980459275'
heading: '284'
altitude: '41065.55293844'
vs: '1'
gs: '424.89060056552'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e0RV61wPj53b
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.77448809677'
lon: '-79.082727467209'
heading: '283'
altitude: '41069.809333539'
vs: '0'
gs: '425.02780492483'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dwpmBOo3wWwe
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.813031600863'
lon: '-79.249543355636'
heading: '283'
altitude: '41072.545805172'
vs: '0'
gs: '425.04687332464'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: ejRqlxXoZPle
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.840653974635'
lon: '-79.370042672541'
heading: '283'
altitude: '40396.200981621'
vs: '-16'
gs: '428.08364925851'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: eVOPBYw4q9Xa
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.868358744495'
lon: '-79.491434926253'
heading: '283'
altitude: '39399.093383161'
vs: '-16'
gs: '427.57826037174'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aOYyrOmVPzEd
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.896191929474'
lon: '-79.613169477385'
heading: '284'
altitude: '36491.730092364'
vs: '-55'
gs: '429.74732238829'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dL98oLQgyzje
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.9242378342'
lon: '-79.736368411294'
heading: '284'
altitude: '32998.644142986'
vs: '-61'
gs: '434.90864533098'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e9rQ5lqD2o8a
pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
name: null
log: null
lat: '18.952608029755'
lon: '-79.861339775352'
heading: '284'
altitude: '29069.168636089'
vs: '-68'
gs: '441.90475491564'
transponder: null
autopilot: null
fuel_flow: null
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: av2oANWY1vma
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -550,8 +36,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e1wr82gp8zGb
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -569,8 +54,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dG65jDL2gK0b
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -588,8 +72,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: epYQ0ENmyvXa
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -607,8 +90,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: erkRwJPrVoEa
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -626,8 +108,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: e1wr82gZXqZb
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -645,8 +126,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: eER95AJ4XLga
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -664,8 +144,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: dPNZvP0O0Gza
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -683,8 +162,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: aQW0wQYVm2Yd
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'
@@ -702,8 +180,7 @@ acars:
sim_time: now
created_at: 'now'
updated_at: 'now'
- id: eXDoE11x32We
pirep_id: b68R5gwVzpVe
- pirep_id: b68R5gwVzpVe
type: '0'
nav_type: null
order: '0'

View File

@@ -119,8 +119,8 @@ aircraft:
-
id: 1
subfleet_id: 1
icao: null
iata: null
icao: B744
iata: 744
airport_id: KJFK
landing_time: '2020-10-23 07:50:16'
name: 'Boeing 747-438'
@@ -136,8 +136,8 @@ aircraft:
-
id: 2
subfleet_id: 2
icao: null
iata: null
icao: B777
iata: 777
airport_id: LGRP
landing_time: null
name: 'Boeing 777-200'
@@ -153,8 +153,8 @@ aircraft:
-
id: 3
subfleet_id: 1
icao: null
iata: null
icao: B744
iata: 744
airport_id: KAUS
landing_time: '2020-10-24 08:50:13'
name: 'Boeing 747-412'
@@ -170,8 +170,8 @@ aircraft:
-
id: 4
subfleet_id: 1
icao: null
iata: null
icao: B744
iata: 744
airport_id: KAUS
landing_time: null
name: 'Boeing 747-436 RETIRED'
@@ -187,7 +187,7 @@ aircraft:
-
id: 5
subfleet_id: 4
icao: A320
icao: 'A320'
iata: '320'
airport_id: EGLL
landing_time: null

File diff suppressed because one or more lines are too long

View File

@@ -54,6 +54,13 @@
options: ''
type: text
description: 'Enter your Google Analytics Tracking ID'
- key: general.record_user_ip
name: 'Record user IP address'
group: general
value: true
options: ''
type: boolean
description: Record the user's IP address on register/login
- key: units.currency
name: 'Currency'
group: units
@@ -144,6 +151,20 @@
options:
type: text
description: If an airport's Jet A Fuel Cost isn't added, set this value by default
- key: airports.default_100ll_fuel_cost
name: 'Default 100LL Fuel Cost'
group: airports
value: 0.9
options:
type: text
description: If an airport's 100LL Fuel Cost isn't added, set this value by default
- key: airports.default_mogas_fuel_cost
name: 'Default MOGAS Fuel Cost'
group: airports
value: 0.8
options:
type: text
description: If an airport's MOGAS Fuel Cost isn't added, set this value by default
- key: bids.disable_flight_on_bid
name: 'Disable flight on bid'
group: bids
@@ -180,12 +201,12 @@
type: number
description: 'How much the load factor can vary per-flight'
- key: simbrief.api_key
name: 'SimBrief API Key'
name: 'Simbrief API Key'
group: simbrief
value: ''
options: ''
type: string
description: 'Your SimBrief API key'
description: 'Your Simbrief API key'
- key: simbrief.only_bids
name: 'Only allow for bids'
group: simbrief
@@ -193,13 +214,62 @@
options: ''
type: boolean
description: 'Only allow briefs to be created for bidded flights'
- key: simbrief.expire_days
name: 'SimBrief Expire Time'
- key: simbrief.expire_hours
name: 'Simbrief Expire Time'
group: simbrief
value: 5
value: 6
options: ''
type: number
description: 'Days after how long to remove unused briefs'
description: 'Hours after how long to remove unused briefs'
- key: simbrief.noncharter_pax_weight
name: 'Non-Charter Passenger Weight'
group: simbrief
value: 185
options: ''
type: number
description: 'Passenger weight for non-charter flights excluding baggage (lbs)'
- key: simbrief.noncharter_baggage_weight
name: 'Non-Charter Baggage Weight'
group: simbrief
value: 35
options: ''
type: number
description: 'Passenger baggage weight for non-charter flights (lbs)'
- key: simbrief.charter_pax_weight
name: 'Charter Passenger Weight'
group: simbrief
value: 168
options: ''
type: number
description: 'Passenger weight for charter flights excluding baggage (lbs)'
- key: simbrief.charter_baggage_weight
name: 'Charter Baggage Weight'
group: simbrief
value: 28
options: ''
type: number
description: 'Passenger baggage weight for charter flights (lbs)'
- key: simbrief.callsign
name: 'Use ATC Callsign'
group: simbrief
value: false
options: ''
type: boolean
description: 'Use pilot ident as Simbrief ATC Callsign'
- key: simbrief.name_private
name: 'Use Privatized Name at OFPs'
group: simbrief
value: false
options: ''
type: boolean
description: 'Use privatized user name as SimBrief OFP captain name'
- key: simbrief.block_aircraft
name: 'Restrict Aircraft'
group: simbrief
value: false
options: ''
type: boolean
description: 'When enabled, an aircraft can only be used for one active SimBrief OFP and Flight/Pirep'
- key: pireps.duplicate_check_time
name: 'PIREP duplicate time check'
group: pireps
@@ -221,13 +291,27 @@
options: ''
type: boolean
description: 'Only allow aircraft that are at the departure airport'
- key: pireps.remove_bid_on_accept
name: 'Remove bid on accept'
- key: pireps.advanced_fuel
name: 'Advanced Fuel Calculations'
group: pireps
value: false
options: ''
type: boolean
description: 'When a PIREP is accepted, remove the bid, if it exists'
description: 'Enables remaining fuel amounts to be considered for fuel expenses'
- key: pireps.delete_cancelled_hours
name: 'Delete cancelled PIREPs'
group: pireps
value: 12
options: ''
type: int
description: 'The time in hours to delete a cancelled PIREP'
- key: pireps.delete_rejected_hours
name: 'Delete rejected PIREPs'
group: pireps
value: 12
options: ''
type: int
description: 'The time in hours to delete a rejected PIREP'
- key: pilots.id_length
name: 'Pilot ID Length'
group: pilots
@@ -291,17 +375,23 @@
options: ''
type: boolean
description: 'Count transfer hours in calculations, like ranks and the total hours'
- key: notifications.discord_api_key
name: Discord API token
- key: notifications.discord_public_webhook_url
name: Discord Public Webhook URL
group: notifications
value: ''
options: ''
type: text
description: Discord API token for notifications
- key: 'notifications.discord_public_channel_id'
name: 'Discord Public Channel ID'
group: 'notifications'
description: The Discord Webhook URL for public notifications
- key: notifications.discord_private_webhook_url
name: Discord Private Webhook URL
group: notifications
value: ''
options: ''
type: 'text'
description: 'Discord public channel ID for broadcasat notifications'
type: text
description: The Discord Webhook URL for private notifications
- key: 'cron.random_id'
name: 'Cron Randomized ID'
group: 'cron'
value: ''
type: 'hidden'
description: ''

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Events;
use App\Contracts\Event;
use App\Models\Pirep;
class PirepStateChange extends Event
{
public $pirep;
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Events;
use App\Contracts\Event;
use App\Models\Pirep;
/**
* Status change like Boarding, Taxi, etc
*/
class PirepStatusChange extends Event
{
public $pirep;
public function __construct(Pirep $pirep)
{
$this->pirep = $pirep;
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Exceptions;
use App\Models\Aircraft;
class AircraftNotAvailable extends AbstractHttpException
{
public const MESSAGE = 'The aircraft is not available for flight';
private $aircraft;
public function __construct(Aircraft $aircraft)
{
$this->aircraft = $aircraft;
parent::__construct(
400,
static::MESSAGE
);
}
public function getErrorType(): string
{
return 'aircraft-not-available';
}
public function getErrorDetails(): string
{
return $this->getMessage();
}
public function getErrorMetadata(): array
{
return [
'aircraft_id' => $this->aircraft->id,
];
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Exceptions;
class CronInvalid extends AbstractHttpException
{
public const MESSAGE = 'Cron ID is disabled or invalid';
public function __construct()
{
parent::__construct(400, static::MESSAGE);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'cron-invalid';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [];
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Exceptions;
use App\Models\Pirep;
class PirepError extends AbstractHttpException
{
private $pirep;
private $error;
public function __construct(Pirep $pirep, string $error)
{
$this->error = $error;
$this->pirep = $pirep;
parent::__construct(400, $error);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'pirep-error';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [
'pirep_id' => $this->pirep->id,
];
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Exceptions;
/**
* Prefile Error
*
* If listening to the prefile event message, use `throw new PrefileError("message message");`
* to abort the prefile process and send the message up to ACARS
*/
class PrefileError extends AbstractHttpException
{
private $error;
public function __construct(string $error)
{
$this->error = $error;
parent::__construct(400, $error);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'prefile-error';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [];
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Exceptions;
class UserNotFound extends AbstractHttpException
{
public function __construct()
{
parent::__construct(
404,
'User not found'
);
}
/**
* Return the RFC 7807 error type (without the URL root)
*/
public function getErrorType(): string
{
return 'user-not-found';
}
/**
* Get the detailed error string
*/
public function getErrorDetails(): string
{
return $this->getMessage();
}
/**
* Return an array with the error details, merged with the RFC7807 response
*/
public function getErrorMetadata(): array
{
return [];
}
}

View File

@@ -186,13 +186,13 @@ class AwardController extends Controller
{
$award = $this->awardRepository->findWithoutFail($id);
if (empty($award)) {
Flash::error('Fare not found');
Flash::error('Award not found');
return redirect(route('admin.awards.index'));
}
$this->awardRepository->delete($id);
Flash::success('Fare deleted successfully.');
Flash::success('Award deleted successfully.');
return redirect(route('admin.awards.index'));
}

View File

@@ -115,7 +115,7 @@ class FlightController extends Controller
$avail_fleets = $all_aircraft->except($flight->subfleets->modelKeys());
foreach ($avail_fleets as $ac) {
$retval[$ac->id] = $ac->type.' - '.$ac->name;
$retval[$ac->id] = '['.$ac->airline->icao.']&nbsp;'.$ac->type.' - '.$ac->name;
}
return $retval;
@@ -152,7 +152,7 @@ class FlightController extends Controller
{
return view('admin.flights.create', [
'flight' => null,
'days' => [],
'days' => 0,
'flight_fields' => $this->flightFieldRepo->all(),
'airlines' => $this->airlineRepo->selectBoxList(),
'airports' => $this->airportRepo->selectBoxList(true, false),

View File

@@ -6,35 +6,36 @@ use App\Contracts\Controller;
use App\Repositories\KvpRepository;
use App\Services\CronService;
use App\Services\VersionService;
use Codedge\Updater\UpdaterManager;
use App\Support\Utils;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
use Laracasts\Flash\Flash;
use Nwidart\Modules\Facades\Module;
class MaintenanceController extends Controller
{
private $cronSvc;
private $kvpRepo;
private $updateManager;
private $versionSvc;
public function __construct(
CronService $cronSvc,
KvpRepository $kvpRepo,
UpdaterManager $updateManager,
VersionService $versionSvc
) {
$this->cronSvc = $cronSvc;
$this->kvpRepo = $kvpRepo;
$this->updateManager = $updateManager;
$this->versionSvc = $versionSvc;
}
public function index()
{
// Get the cron URL
$cron_id = setting('cron.random_id');
$cron_url = empty($cron_id) ? 'Not enabled' : url(route('api.maintenance.cron', $cron_id));
return view('admin.maintenance.index', [
'cron_url' => $cron_url,
'cron_path' => $this->cronSvc->getCronExecString(),
'cron_problem_exists' => $this->cronSvc->cronProblemExists(),
'new_version' => $this->kvpRepo->get('new_version_available', false),
@@ -101,20 +102,31 @@ class MaintenanceController extends Controller
}
/**
* Update the phpVMS install
* Enable the cron, or if it's enabled, change the ID that is used
*
* @param \Illuminate\Http\Request $request
* @param Request $request
*/
public function cron_enable(Request $request)
{
$id = Utils::generateNewId(24);
setting_save('cron.random_id', $id);
Flash::success('Web cron refreshed!');
return redirect(route('admin.maintenance.index'));
}
/**
* Disable the web cron
*
* @param Request $request
*
* @return mixed
*/
public function update(Request $request)
public function cron_disable(Request $request)
{
$new_version_tag = $this->kvpRepo->get('latest_version_tag');
Log::info('Attempting to update to '.$new_version_tag);
setting_save('cron.random_id', '');
$module = Module::find('updater');
$module->enable();
return redirect('/update/downloader');
Flash::success('Web cron disabled!');
return redirect(route('admin.maintenance.index'));
}
}

View File

@@ -100,7 +100,7 @@ class PirepController extends Controller
$tmp[$ac->id] = $ac['name'].' - '.$ac['registration'];
}
$aircraft[$subfleet->name] = $tmp;
$aircraft[$subfleet->type] = $tmp;
}
return $aircraft;
@@ -394,10 +394,10 @@ class PirepController extends Controller
return redirect(route('admin.pireps.index'));
}
$this->pirepRepo->delete($id);
$this->pirepSvc->delete($pirep);
Flash::success('Pirep deleted successfully.');
return redirect(route('admin.pireps.index'));
return redirect()->back();
}
/**

View File

@@ -62,7 +62,7 @@ class SettingsController extends Controller
*/
public function index()
{
$settings = Setting::orderBy('order', 'asc')->get();
$settings = Setting::where('type', '!=', 'hidden')->orderBy('order')->get();
$settings = $settings->groupBy('group');
return view('admin.settings.index', [

View File

@@ -6,12 +6,12 @@ use App\Contracts\Controller;
use App\Http\Requests\CreateUserRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Models\Rank;
use App\Models\Role;
use App\Models\User;
use App\Models\UserAward;
use App\Repositories\AirlineRepository;
use App\Repositories\AirportRepository;
use App\Repositories\PirepRepository;
use App\Repositories\RoleRepository;
use App\Repositories\UserRepository;
use App\Services\UserService;
use App\Support\Timezonelist;
@@ -29,6 +29,7 @@ class UserController extends Controller
private $airlineRepo;
private $airportRepo;
private $pirepRepo;
private $roleRepo;
private $userRepo;
private $userSvc;
@@ -38,6 +39,7 @@ class UserController extends Controller
* @param AirlineRepository $airlineRepo
* @param AirportRepository $airportRepo
* @param PirepRepository $pirepRepo
* @param RoleRepository $roleRepo
* @param UserRepository $userRepo
* @param UserService $userSvc
*/
@@ -45,12 +47,14 @@ class UserController extends Controller
AirlineRepository $airlineRepo,
AirportRepository $airportRepo,
PirepRepository $pirepRepo,
RoleRepository $roleRepo,
UserRepository $userRepo,
UserService $userSvc
) {
$this->airlineRepo = $airlineRepo;
$this->airportRepo = $airportRepo;
$this->pirepRepo = $pirepRepo;
$this->roleRepo = $roleRepo;
$this->userSvc = $userSvc;
$this->userRepo = $userRepo;
}
@@ -88,6 +92,7 @@ class UserController extends Controller
->mapWithKeys(function ($item, $key) {
return [strtolower($item['alpha2']) => $item['name']];
});
$roles = $this->roleRepo->selectBoxList(false, true);
return view('admin.users.create', [
'user' => null,
@@ -98,7 +103,7 @@ class UserController extends Controller
'countries' => $countries,
'airports' => $airports,
'ranks' => Rank::all()->pluck('name', 'id'),
'roles' => Role::all()->pluck('name', 'id'),
'roles' => $roles,
]);
}
@@ -163,6 +168,7 @@ class UserController extends Controller
$airlines = $this->airlineRepo->selectBoxList();
$airports = $this->airportRepo->selectBoxList(false);
$roles = $this->roleRepo->selectBoxList(false, true);
return view('admin.users.edit', [
'user' => $user,
@@ -173,7 +179,7 @@ class UserController extends Controller
'airports' => $airports,
'airlines' => $airlines,
'ranks' => Rank::all()->pluck('name', 'id'),
'roles' => Role::all()->pluck('name', 'id'),
'roles' => $roles,
]);
}
@@ -252,15 +258,12 @@ class UserController extends Controller
public function destroy($id)
{
$user = $this->userRepo->findWithoutFail($id);
if (empty($user)) {
Flash::error('User not found');
return redirect(route('admin.users.index'));
}
$this->userRepo->delete($id);
$this->userSvc->removeUser($user);
Flash::success('User deleted successfully.');
return redirect(route('admin.users.index'));

View File

@@ -16,9 +16,8 @@ class AirlineController extends Controller
*
* @param AirlineRepository $airlineRepo
*/
public function __construct(
AirlineRepository $airlineRepo
) {
public function __construct(AirlineRepository $airlineRepo)
{
$this->airlineRepo = $airlineRepo;
}
@@ -31,9 +30,7 @@ class AirlineController extends Controller
*/
public function index(Request $request)
{
$airports = $this->airlineRepo
->whereOrder(['active' => true], 'name', 'asc')
->paginate();
$airports = $this->airlineRepo->whereOrder(['active' => true], 'name')->get();
return AirlineResource::collection($airports);
}

View File

@@ -4,7 +4,6 @@ namespace App\Http\Controllers\Api;
use App\Contracts\Controller;
use App\Exceptions\AssetNotFound;
use App\Exceptions\Unauthorized;
use App\Http\Resources\Flight as FlightResource;
use App\Http\Resources\Navdata as NavdataResource;
use App\Models\SimBrief;

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Controllers\Api;
use App\Contracts\Controller;
use App\Exceptions\CronInvalid;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
class MaintenanceController extends Controller
{
/**
* Run the cron job from the web
*
* @param Request $request
* @param string $id The ID passed in for the cron
*
* @return mixed
*/
public function cron(Request $request, string $id)
{
$cron_id = setting('cron.random_id');
if (empty($cron_id) || $id !== $cron_id) {
throw new CronInvalid();
}
$output = '';
Artisan::call('schedule:run');
$output .= trim(Artisan::output());
return response([
'content' => $output,
]);
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Http\Controllers\Api;
use App\Contracts\Controller;
use App\Events\PirepPrefiled;
use App\Events\PirepUpdated;
use App\Exceptions\AircraftPermissionDenied;
use App\Exceptions\PirepCancelled;
@@ -24,10 +23,10 @@ use App\Models\Enums\PirepFieldSource;
use App\Models\Enums\PirepSource;
use App\Models\Pirep;
use App\Models\PirepComment;
use App\Repositories\AcarsRepository;
use App\Models\PirepFare;
use App\Models\PirepFieldValue;
use App\Repositories\JournalRepository;
use App\Repositories\PirepRepository;
use App\Services\FareService;
use App\Services\Finance\PirepFinanceService;
use App\Services\PirepService;
use App\Services\UserService;
@@ -38,8 +37,6 @@ use Illuminate\Support\Facades\Log;
class PirepController extends Controller
{
private $acarsRepo;
private $fareSvc;
private $financeSvc;
private $journalRepo;
private $pirepRepo;
@@ -47,8 +44,6 @@ class PirepController extends Controller
private $userSvc;
/**
* @param AcarsRepository $acarsRepo
* @param FareService $fareSvc
* @param PirepFinanceService $financeSvc
* @param JournalRepository $journalRepo
* @param PirepRepository $pirepRepo
@@ -56,16 +51,12 @@ class PirepController extends Controller
* @param UserService $userSvc
*/
public function __construct(
AcarsRepository $acarsRepo,
FareService $fareSvc,
PirepFinanceService $financeSvc,
JournalRepository $journalRepo,
PirepRepository $pirepRepo,
PirepService $pirepSvc,
UserService $userSvc
) {
$this->acarsRepo = $acarsRepo;
$this->fareSvc = $fareSvc;
$this->financeSvc = $financeSvc;
$this->journalRepo = $journalRepo;
$this->pirepRepo = $pirepRepo;
@@ -102,7 +93,7 @@ class PirepController extends Controller
/**
* Check if a PIREP is cancelled
*
* @param $pirep
* @param Pirep $pirep
*
* @throws \App\Exceptions\PirepCancelled
*/
@@ -114,50 +105,52 @@ class PirepController extends Controller
}
/**
* @param $pirep
* @param Request $request
*
* @return PirepFieldValue[]
*/
protected function updateFields($pirep, Request $request)
protected function getFields(Request $request): ?array
{
if (!$request->filled('fields')) {
return;
return [];
}
$pirep_fields = [];
foreach ($request->input('fields') as $field_name => $field_value) {
$pirep_fields[] = [
$pirep_fields[] = new PirepFieldValue([
'name' => $field_name,
'value' => $field_value,
'source' => PirepFieldSource::ACARS,
];
]);
}
$this->pirepSvc->updateCustomFields($pirep->id, $pirep_fields);
return $pirep_fields;
}
/**
* Save the fares
*
* @param $pirep
* @param Request $request
*
* @throws \Exception
*
* @return PirepFare[]
*/
protected function updateFares($pirep, Request $request)
protected function getFares(Request $request): ?array
{
if (!$request->filled('fares')) {
return;
return [];
}
$fares = [];
foreach ($request->post('fares') as $fare) {
$fares[] = [
$fares[] = new PirepFare([
'fare_id' => $fare['id'],
'count' => $fare['count'],
];
]);
}
$this->fareSvc->saveForPirep($pirep, $fares);
return $fares;
}
/**
@@ -174,6 +167,7 @@ class PirepController extends Controller
'comments',
'flight',
'simbrief',
'position',
'user',
];
@@ -211,16 +205,13 @@ class PirepController extends Controller
$attrs = $this->parsePirep($request);
$attrs['source'] = PirepSource::ACARS;
$pirep = $this->pirepSvc->prefile($user, $attrs);
$fields = $this->getFields($request);
$fares = $this->getFares($request);
$pirep = $this->pirepSvc->prefile($user, $attrs, $fields, $fares);
Log::info('PIREP PREFILED');
Log::info($pirep->id);
$this->updateFields($pirep, $request);
$this->updateFares($pirep, $request);
event(new PirepPrefiled($pirep));
return $this->get($pirep->id);
}
@@ -261,9 +252,9 @@ class PirepController extends Controller
}
}
$pirep = $this->pirepRepo->update($attrs, $pirep_id);
$this->updateFields($pirep, $request);
$this->updateFares($pirep, $request);
$fields = $this->getFields($request);
$fares = $this->getFares($request);
$pirep = $this->pirepSvc->update($pirep_id, $attrs, $fields, $fares);
event(new PirepUpdated($pirep));
@@ -306,11 +297,13 @@ class PirepController extends Controller
}
try {
$pirep = $this->pirepSvc->file($pirep, $attrs);
$this->updateFields($pirep, $request);
$this->updateFares($pirep, $request);
$fields = $this->getFields($request);
$fares = $this->getFares($request);
$pirep = $this->pirepSvc->file($pirep, $attrs, $fields, $fares);
} catch (\Exception $e) {
Log::error($e);
throw $e;
}
// See if there there is any route data posted
@@ -412,7 +405,8 @@ class PirepController extends Controller
$pirep = Pirep::find($pirep_id);
$this->checkCancelled($pirep);
$this->updateFields($pirep, $request);
$fields = $this->getFields($request);
$this->pirepSvc->updateCustomFields($pirep_id, $fields);
return new PirepFieldCollection($pirep->fields);
}

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Api;
use App\Contracts\Controller;
use App\Exceptions\UserNotFound;
use App\Http\Resources\Bid as BidResource;
use App\Http\Resources\Pirep as PirepResource;
use App\Http\Resources\Subfleet as SubfleetResource;
@@ -91,6 +92,10 @@ class UserController extends Controller
public function get($id)
{
$user = $this->userSvc->getUser($id);
if ($user === null) {
throw new UserNotFound();
}
return new UserResource($user);
}
@@ -106,7 +111,11 @@ class UserController extends Controller
*/
public function bids(Request $request)
{
$user = $this->userSvc->getUser($this->getUserId($request));
$user_id = $this->getUserId($request);
$user = $this->userSvc->getUser($user_id);
if ($user === null) {
throw new UserNotFound();
}
// Add a bid
if ($request->isMethod('PUT') || $request->isMethod('POST')) {
@@ -145,6 +154,10 @@ class UserController extends Controller
public function fleet(Request $request)
{
$user = $this->userRepo->find($this->getUserId($request));
if ($user === null) {
throw new UserNotFound();
}
$subfleets = $this->userSvc->getAllowableSubfleets($user);
return SubfleetResource::collection($subfleets);

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\Auth;
use App\Contracts\Controller;
use App\Exceptions\PilotIdNotFound;
use App\Models\Enums\UserState;
use App\Models\User;
use App\Services\UserService;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
@@ -104,14 +105,16 @@ class LoginController extends Controller
*/
protected function sendLoginResponse(Request $request)
{
/** @var User $user */
$user = Auth::user();
$user->last_ip = $request->ip();
$user->save();
if (setting('general.record_user_ip', true)) {
$user->last_ip = $request->ip();
$user->save();
}
if ($user->state !== UserState::ACTIVE && $user->state !== UserState::ON_LEAVE) {
Log::info('Trying to login '.$user->ident.', state '
.UserState::label($user->state));
Log::info('Trying to login '.$user->ident.', state '.UserState::label($user->state));
// Log them out
$this->guard()->logout();

View File

@@ -119,11 +119,16 @@ class RegisterController extends Controller
*
* @return User
*/
protected function create(array $opts)
protected function create(Request $request): User
{
// Default options
$opts = $request->all();
$opts['password'] = Hash::make($opts['password']);
if (setting('general.record_user_ip', true)) {
$opts['last_ip'] = $request->ip();
}
// Convert transfer hours into minutes
if (isset($opts['transfer_time'])) {
$opts['transfer_time'] *= 60;
@@ -158,7 +163,7 @@ class RegisterController extends Controller
{
$this->validator($request->all())->validate();
$user = $this->create($request->all());
$user = $this->create($request);
if ($user->state === UserState::PENDING) {
return view('auth.pending');
}

View File

@@ -36,8 +36,8 @@ class AirportController extends Controller
{
$id = strtoupper($id);
$airport = $this->airportRepo->find($id);
if (empty($airport)) {
$airport = $this->airportRepo->where('id', $id)->first();
if (!$airport) {
Flash::error('Airport not found!');
return redirect(route('frontend.dashboard.index'));
}
@@ -46,12 +46,14 @@ class AirportController extends Controller
->with(['dpt_airport', 'arr_airport', 'airline'])
->findWhere([
'arr_airport_id' => $id,
'active' => 1,
])->all();
$outbound_flights = $this->flightRepo
->with(['dpt_airport', 'arr_airport', 'airline'])
->findWhere([
'dpt_airport_id' => $id,
'active' => 1,
])->all();
return view('airports.show', [

View File

@@ -28,7 +28,10 @@ class DashboardController extends Controller
*/
public function index()
{
//dd(config('backup'));
$last_pirep = null;
/** @var \App\Models\User $user */
$user = Auth::user();
try {

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Frontend;
use App\Contracts\Controller;
use App\Models\Airline;
use App\Models\File;
use Auth;
use Flash;
@@ -18,6 +19,7 @@ class DownloadController extends Controller
*/
public function index()
{
$airlines = Airline::where('active', 1)->count();
$files = File::orderBy('ref_model', 'asc')->get();
/**
@@ -42,10 +44,14 @@ class DownloadController extends Controller
$category = explode('\\', $class);
$category = end($category);
if ($category == 'Aircraft') {
if ($category == 'Aircraft' && $airlines > 1) {
$group_name = $category.' > '.$obj->subfleet->airline->name.' '.$obj->icao.' '.$obj->registration;
} elseif ($category == 'Aircraft') {
$group_name = $category.' > '.$obj->icao.' '.$obj->registration;
} elseif ($category == 'Airport') {
$group_name = $category.' > '.$obj->icao.' : '.$obj->name.' ('.$obj->country.')';
} elseif ($category == 'Subfleet' && $airlines > 1) {
$group_name = $category.' > '.$obj->airline->name.' '.$obj->name;
} else {
$group_name = $category.' > '.$obj->name;
}
@@ -53,13 +59,15 @@ class DownloadController extends Controller
$regrouped_files[$group_name] = $files;
}
ksort($regrouped_files, SORT_STRING);
return view('downloads.index', [
'grouped_files' => $regrouped_files,
]);
}
/**
* Show the application dashboard.
* Show the application dashboard
*
* @param string $id
*

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\Frontend;
use App\Contracts\Controller;
use App\Models\Bid;
use App\Models\Enums\FlightType;
use App\Models\Flight;
use App\Repositories\AirlineRepository;
use App\Repositories\AirportRepository;
use App\Repositories\Criteria\WhereCriteria;
@@ -105,8 +106,23 @@ class FlightController extends Controller
Log::emergency($e);
}
// Get only used Flight Types for the search form
// And filter according to settings
$usedtypes = Flight::select('flight_type')->where($where)->groupby('flight_type')->orderby('flight_type', 'asc')->get();
// Build collection with type codes and labels
$flight_types = collect('', '');
foreach ($usedtypes as $ftype) {
$flight_types->put($ftype->flight_type, FlightType::label($ftype->flight_type));
}
$flights = $this->flightRepo->searchCriteria($request)
->with(['dpt_airport', 'arr_airport', 'airline'])
->with([
'dpt_airport',
'arr_airport',
'airline',
'simbrief' => function ($query) use ($user) {
$query->where('user_id', $user->id);
}, ])
->orderBy('flight_number', 'asc')
->orderBy('route_leg', 'asc')
->paginate();
@@ -115,13 +131,14 @@ class FlightController extends Controller
->pluck('flight_id')->toArray();
return view('flights.index', [
'user' => $user,
'airlines' => $this->airlineRepo->selectBoxList(true),
'airports' => $this->airportRepo->selectBoxList(true),
'flights' => $flights,
'saved' => $saved_flights,
'subfleets' => $this->subfleetRepo->selectBoxList(true),
'flight_number' => $request->input('flight_number'),
'flight_types' => FlightType::select(true),
'flight_types' => $flight_types,
'flight_type' => $request->input('flight_type'),
'arr_icao' => $request->input('arr_icao'),
'dep_icao' => $request->input('dep_icao'),
@@ -147,11 +164,18 @@ class FlightController extends Controller
$flights = collect();
$saved_flights = [];
foreach ($user->bids as $bid) {
// Remove any invalid bids (flight doesn't exist or something)
if (!$bid->flight) {
$bid->delete();
continue;
}
$flights->add($bid->flight);
$saved_flights[] = $bid->flight->id;
}
return view('flights.bids', [
'user' => $user,
'airlines' => $this->airlineRepo->selectBoxList(true),
'airports' => $this->airportRepo->selectBoxList(true),
'flights' => $flights,

View File

@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Frontend;
use App\Contracts\Controller;
use App\Models\Enums\UserState;
use App\Models\User;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\Log;
@@ -15,7 +16,7 @@ class HomeController extends Controller
public function index()
{
try {
$users = User::orderBy('created_at', 'desc')->take(4)->get();
$users = User::where('state', '!=', UserState::DELETED)->orderBy('created_at', 'desc')->take(4)->get();
} catch (\PDOException $e) {
Log::emergency($e);
return view('system/errors/database_error', [

View File

@@ -7,8 +7,9 @@ use App\Http\Requests\CreatePirepRequest;
use App\Http\Requests\UpdatePirepRequest;
use App\Models\Enums\PirepSource;
use App\Models\Enums\PirepState;
use App\Models\Enums\PirepStatus;
use App\Models\Fare;
use App\Models\Pirep;
use App\Models\PirepFare;
use App\Models\SimBrief;
use App\Models\User;
use App\Repositories\AircraftRepository;
@@ -103,7 +104,7 @@ class PirepController extends Controller
$tmp[$ac->id] = $ac['name'].' - '.$ac['registration'];
}
$aircraft[$subfleet->name] = $tmp;
$aircraft[$subfleet->type] = $tmp;
}
return $aircraft;
@@ -112,19 +113,18 @@ class PirepController extends Controller
/**
* Save any custom fields found
*
* @param Pirep $pirep
* @param Request $request
*/
protected function saveCustomFields(Pirep $pirep, Request $request)
protected function saveCustomFields(Request $request): array
{
$custom_fields = [];
$fields = [];
$pirep_fields = $this->pirepFieldRepo->all();
foreach ($pirep_fields as $field) {
if (!$request->filled($field->slug)) {
continue;
}
$custom_fields[] = [
$fields[] = [
'name' => $field->name,
'slug' => $field->slug,
'value' => $request->input($field->slug),
@@ -132,8 +132,9 @@ class PirepController extends Controller
];
}
Log::info('PIREP Custom Fields', $custom_fields);
$this->pirepSvc->updateCustomFields($pirep->id, $custom_fields);
Log::info('PIREP Custom Fields', $fields);
return $fields;
}
/**
@@ -159,10 +160,10 @@ class PirepController extends Controller
$count = $request->input($field_name);
}
$fares[] = [
$fares[] = new PirepFare([
'fare_id' => $fare->id,
'count' => $count,
];
]);
}
$this->fareSvc->saveForPirep($pirep, $fares);
@@ -211,6 +212,7 @@ class PirepController extends Controller
return view('pireps.show', [
'pirep' => $pirep,
'map_features' => $map_features,
'user' => Auth::user(),
]);
}
@@ -253,23 +255,48 @@ class PirepController extends Controller
/**
* They have a SimBrief ID, load that up and figure out the flight that it's from
*/
$fare_values = [];
$simbrief = null;
$simbrief_id = null;
$aircraft = null;
if ($request->has('sb_id')) {
$simbrief_id = $request->input('sb_id');
$brief = SimBrief::find($simbrief_id);
$pirep = Pirep::fromSimBrief($brief);
$simbrief = SimBrief::find($simbrief_id);
$pirep = Pirep::fromSimBrief($simbrief);
$aircraft = $simbrief->aircraft;
$aircraft_list[$aircraft->subfleet->name] = [];
$aircraft_list[$aircraft->subfleet->name][$aircraft->id] = $aircraft->name.' - '.$aircraft->registration;
// Convert the fare data into the expected output format
if (!empty($simbrief->fare_data)) {
$fare_values = json_decode($simbrief->fare_data, true);
$fares = [];
$fare_data = json_decode($simbrief->fare_data, true);
foreach ($fare_data as $fare) {
$fares[] = new Fare($fare);
}
$aircraft->subfleet->fares = collect($fares);
}
// TODO: Set more fields from the Simbrief to the PIREP form
} else {
$aircraft_list = $this->aircraftList(true);
}
return view('pireps.create', [
'aircraft' => null,
'aircraft' => $aircraft,
'pirep' => $pirep,
'read_only' => false,
'airline_list' => $this->airlineRepo->selectBoxList(true),
'aircraft_list' => $this->aircraftList(true),
'aircraft_list' => $aircraft_list,
'airport_list' => $this->airportRepo->selectBoxList(true),
'pirep_fields' => $this->pirepFieldRepo->all(),
'field_values' => [],
'fare_values' => $fare_values,
'simbrief_id' => $simbrief_id,
'simbrief' => $simbrief,
]);
}
@@ -363,8 +390,8 @@ class PirepController extends Controller
$attrs['submitted_at'] = Carbon::now('UTC');
$pirep->submitted_at = Carbon::now('UTC');
$pirep = $this->pirepSvc->create($pirep);
$this->saveCustomFields($pirep, $request);
$fields = $this->saveCustomFields($request);
$pirep = $this->pirepSvc->create($pirep, $fields);
$this->saveFares($pirep, $request);
$this->pirepSvc->saveRoute($pirep);
@@ -373,7 +400,13 @@ class PirepController extends Controller
if ($brief !== null) {
/** @var SimBriefService $sbSvc */
$sbSvc = app(SimBriefService::class);
$sbSvc->attachSimbriefToPirep($pirep, $brief);
// Keep the flight_id with SimBrief depending on the button selected
// Save = Keep the flight_id , Submit = Remove the flight_id
if ($attrs['submit'] === 'save') {
$sbSvc->attachSimbriefToPirep($pirep, $brief, true);
} elseif ($attrs['submit'] === 'submit') {
$sbSvc->attachSimbriefToPirep($pirep, $brief);
}
}
}
@@ -403,12 +436,18 @@ class PirepController extends Controller
*/
public function edit($id)
{
/** @var Pirep $pirep */
$pirep = $this->pirepRepo->findWithoutFail($id);
if (empty($pirep)) {
Flash::error('Pirep not found');
return redirect(route('frontend.pireps.index'));
}
if ($pirep->user_id !== Auth::id()) {
Flash::error('Cannot edit someone else\'s PIREP!');
return redirect(route('admin.pireps.index'));
}
// Eager load the subfleet and fares under it
if ($pirep->aircraft) {
$pirep->aircraft->load('subfleet.fares');
@@ -461,12 +500,21 @@ class PirepController extends Controller
*/
public function update($id, UpdatePirepRequest $request)
{
/** @var User $user */
$user = Auth::user();
/** @var Pirep $pirep */
$pirep = $this->pirepRepo->findWithoutFail($id);
if (empty($pirep)) {
Flash::error('Pirep not found');
return redirect(route('admin.pireps.index'));
}
if ($user->id !== $pirep->user_id) {
Flash::error('Cannot edit someone else\'s PIREP!');
return redirect(route('admin.pireps.index'));
}
$orig_route = $pirep->route;
$attrs = $request->all();
$attrs['submit'] = strtolower($attrs['submit']);
@@ -484,7 +532,8 @@ class PirepController extends Controller
$this->pirepSvc->saveRoute($pirep);
}
$this->saveCustomFields($pirep, $request);
$fields = $this->saveCustomFields($request);
$this->pirepSvc->updateCustomFields($pirep->id, $fields);
$this->saveFares($pirep, $request);
if ($attrs['submit'] === 'save') {
@@ -493,12 +542,8 @@ class PirepController extends Controller
$this->pirepSvc->submit($pirep);
Flash::success('PIREP submitted!');
} elseif ($attrs['submit'] === 'delete' || $attrs['submit'] === 'cancel') {
$this->pirepRepo->update([
'state' => PirepState::CANCELLED,
'status' => PirepStatus::CANCELLED,
], $pirep->id);
Flash::success('PIREP cancelled!');
$this->pirepSvc->delete($pirep);
Flash::success('PIREP deleted!');
return redirect(route('frontend.pireps.index'));
}
@@ -523,6 +568,11 @@ class PirepController extends Controller
return redirect(route('admin.pireps.index'));
}
if ($pirep->user_id !== Auth::id()) {
Flash::error('Cannot edit someone else\'s PIREP!');
return redirect(route('admin.pireps.index'));
}
$this->pirepSvc->submit($pirep);
return redirect(route('frontend.pireps.show', [$pirep->id]));
}

View File

@@ -10,6 +10,7 @@ use App\Repositories\AirlineRepository;
use App\Repositories\AirportRepository;
use App\Repositories\UserRepository;
use App\Support\Countries;
use App\Support\Discord;
use App\Support\Timezonelist;
use App\Support\Utils;
use Illuminate\Http\Request;
@@ -52,7 +53,7 @@ class ProfileController extends Controller
{
// Is the ACARS module enabled?
$acars_enabled = false;
$acars = Module::find('VMSACARS');
$acars = Module::find('VMSAcars');
if ($acars) {
$acars_enabled = $acars->isEnabled();
}
@@ -95,6 +96,7 @@ class ProfileController extends Controller
'user' => $user,
'userFields' => $userFields,
'airports' => $airports,
'acars' => $this->acarsEnabled(),
]);
}
@@ -121,7 +123,7 @@ class ProfileController extends Controller
$airlines = $this->airlineRepo->selectBoxList();
$airports = $this->airportRepo->selectBoxList(false, setting('pilots.home_hubs_only'));
$userFields = $this->userRepo->getUserFields($user, false);
$userFields = $this->userRepo->getUserFields($user, true);
return view('profile.edit', [
'user' => $user,
@@ -180,6 +182,16 @@ class ProfileController extends Controller
Storage::delete($user->avatar);
}
// Find out the user's private channel id
/*
// TODO: Uncomment when Discord API functionality is enabled
if ($request->filled('discord_id')) {
$discord_id = $request->post('discord_id');
if ($discord_id !== $user->discord_id) {
$req_data['discord_private_channel_id'] = Discord::getPrivateChannelId($discord_id);
}
}*/
if ($request->hasFile('avatar')) {
$avatar = $request->file('avatar');
$file_name = $user->ident.'.'.$avatar->getClientOriginalExtension();

View File

@@ -4,8 +4,14 @@ namespace App\Http\Controllers\Frontend;
use App\Exceptions\AssetNotFound;
use App\Models\Aircraft;
use App\Models\Enums\AircraftState;
use App\Models\Enums\AircraftStatus;
use App\Models\Enums\FareType;
use App\Models\Enums\FlightType;
use App\Models\Fare;
use App\Models\Flight;
use App\Models\SimBrief;
use App\Models\User;
use App\Repositories\FlightRepository;
use App\Services\FareService;
use App\Services\SimBriefService;
@@ -49,8 +55,9 @@ class SimBriefController
$flight_id = $request->input('flight_id');
$aircraft_id = $request->input('aircraft_id');
$flight = $this->flightRepo->with(['subfleets'])->find($flight_id);
$flight = $this->fareSvc->getReconciledFaresForFlight($flight);
/** @var Flight $flight */
$flight = $this->flightRepo->with(['fares', 'subfleets'])->find($flight_id);
if (!$flight) {
flash()->error('Unknown flight');
@@ -63,6 +70,53 @@ class SimBriefController
return redirect(route('frontend.flights.index'));
}
// Generate SimBrief Static ID
$static_id = $user->ident.'_'.$flight->id;
// No aircraft selected, show selection form
if (!$aircraft_id) {
// If no subfleets defined for flight get them from user
if ($flight->subfleets->count() > 0) {
$subfleets = $flight->subfleets;
} else {
$subfleets = $this->userSvc->getAllowableSubfleets($user);
}
// Build an array of subfleet id's from the subfleets collection
$sf_ids = $subfleets->map(function ($subfleets) {
return collect($subfleets->toArray())
->only(['id'])
->all();
});
// Now we can build a proper aircrafts collection
// Contents will be either members of flight->subfleets
// or members of user's allowable subfleets
$aircrafts = Aircraft::whereIn('subfleet_id', $sf_ids)
->where('state', AircraftState::PARKED)
->where('status', AircraftStatus::ACTIVE)
->orderby('icao')
->orderby('registration')
->get();
if (setting('pireps.only_aircraft_at_dpt_airport')) {
$aircrafts = $aircrafts->where('airport_id', $flight->dpt_airport_id);
}
if (setting('simbrief.block_aircraft')) {
// Build a list of aircraft_id's being used for active sb packs
$sb_aircraft = SimBrief::whereNotNull('flight_id')->pluck('aircraft_id');
// Filter aircraft list to non used/blocked ones
$aircrafts = $aircrafts->whereNotIn('id', $sb_aircraft);
}
return view('flights.simbrief_aircraft', [
'flight' => $flight,
'aircrafts' => $aircrafts,
'subfleets' => $subfleets,
]);
}
// Check if a Simbrief profile already exists
$simbrief = SimBrief::select('id')->where([
'flight_id' => $flight_id,
@@ -73,34 +127,26 @@ class SimBriefController
return redirect(route('frontend.simbrief.briefing', [$simbrief->id]));
}
// Simbrief Profile doesn't exist; prompt the user to create a new one
$aircraft = Aircraft::select('registration', 'name', 'icao', 'iata', 'subfleet_id')
->where('id', $aircraft_id)
->get();
// SimBrief profile does not exists and everything else is ok
// Select aircraft which will be used for calculations and details
/** @var Aircraft $aircraft */
$aircraft = Aircraft::where('id', $aircraft_id)->first();
if ($flight->subfleets->count() > 0) {
$subfleets = $flight->subfleets;
} else {
$subfleets = $this->userSvc->getAllowableSubfleets($user);
}
// Figure out the proper fares to use for this flight/aircraft
$all_fares = $this->fareSvc->getFareWithOverrides($aircraft->subfleet->fares, $flight->fares);
// TODO: Reconcile the fares for this aircraft w/ proper for the flight/subfleet
// Get passenger and baggage weights with failsafe defaults
if ($flight->flight_type === FlightType::CHARTER_PAX_ONLY) {
$pax_weight = 197;
$pax_weight = setting('simbrief.charter_pax_weight', 168);
$bag_weight = setting('simbrief.charter_baggage_weight', 28);
} else {
$pax_weight = 208;
$pax_weight = setting('simbrief.noncharter_pax_weight', 185);
$bag_weight = setting('simbrief.noncharter_baggage_weight', 35);
}
// No aircraft selected, show that form
if (!$aircraft_id) {
return view('flights.simbrief_aircraft', [
'flight' => $flight,
'aircraft' => $aircraft,
'subfleets' => $subfleets,
'pax_weight' => $pax_weight,
]);
}
// Get the correct load factors
// Get the load factors with failsafe for loadmax if nothing is defined
$lfactor = $flight->load_factor ?? setting('flights.default_load_factor');
$lfactorv = $flight->load_factor_variance ?? setting('flights.load_factor_variance');
@@ -110,14 +156,91 @@ class SimBriefController
$loadmax = $lfactor + $lfactorv;
$loadmax = $loadmax > 100 ? 100 : $loadmax;
if ($loadmax === 0) {
$loadmax = 100;
}
// Load fares for passengers
$loaddist = []; // The load distribution string
$pax_load_sheet = [];
$tpaxfig = 0;
/** @var Fare $fare */
foreach ($all_fares as $fare) {
if ($fare->type !== FareType::PASSENGER || empty($fare->capacity)) {
continue;
}
$count = floor(($fare->capacity * rand($loadmin, $loadmax)) / 100);
$tpaxfig += $count;
$pax_load_sheet[] = [
'id' => $fare->id,
'code' => $fare->code,
'name' => $fare->name,
'type' => $fare->type,
'capacity' => (int) $fare->capacity,
'count' => $count,
];
$loaddist[] = $fare->code.' '.$count;
}
// Calculate total weights
if (setting('units.weight') === 'kg') {
$tpaxload = round(($pax_weight * $tpaxfig) / 2.205);
$tbagload = round(($bag_weight * $tpaxfig) / 2.205);
} else {
$tpaxload = round($pax_weight * $tpaxfig);
$tbagload = round($bag_weight * $tpaxfig);
}
// Load up fares for cargo
$tcargoload = 0;
$cargo_load_sheet = [];
foreach ($all_fares as $fare) {
if ($fare->type !== FareType::CARGO || empty($fare->capacity)) {
continue;
}
$count = ceil((($fare->capacity - $tbagload) * rand($loadmin, $loadmax)) / 100);
$tcargoload += $count;
$cargo_load_sheet[] = [
'id' => $fare->id,
'code' => $fare->code,
'name' => $fare->name,
'type' => $fare->type,
'capacity' => $fare->capacity,
'count' => $count,
];
$loaddist[] = $fare->code.' '.$count;
}
$tpayload = $tpaxload + $tbagload + $tcargoload;
$request->session()->put('simbrief_fares', array_merge($pax_load_sheet, $cargo_load_sheet));
// Show the main simbrief form
return view('flights.simbrief_form', [
'flight' => $flight,
'aircraft' => $aircraft,
'subfleets' => $subfleets,
'pax_weight' => $pax_weight,
'loadmin' => $loadmin,
'loadmax' => $loadmax,
'user' => Auth::user(),
'flight' => $flight,
'aircraft' => $aircraft,
'pax_weight' => $pax_weight,
'bag_weight' => $bag_weight,
'loadmin' => $loadmin,
'loadmax' => $loadmax,
'pax_load_sheet' => $pax_load_sheet,
'cargo_load_sheet' => $cargo_load_sheet,
'tpaxfig' => $tpaxfig,
'tpaxload' => $tpaxload,
'tbagload' => $tbagload,
'tpayload' => $tpayload,
'tcargoload' => $tcargoload,
'loaddist' => implode(' ', $loaddist),
'static_id' => $static_id,
]);
}
@@ -222,6 +345,7 @@ class SimBriefController
/**
* Check whether the OFP was generated. Pass in two items, the flight_id and ofp_id
* This does the actual "attachment" of the Simbrief to the flight
*
* @param \Illuminate\Http\Request $request
*
@@ -229,10 +353,14 @@ class SimBriefController
*/
public function check_ofp(Request $request)
{
/** @var User $user */
$user = Auth::user();
$ofp_id = $request->input('ofp_id');
$flight_id = $request->input('flight_id');
$aircraft_id = $request->input('aircraft_id');
$fares = $request->session()->get('simbrief_fares', []);
$simbrief = $this->simBriefSvc->downloadOfp(Auth::user()->id, $ofp_id, $flight_id);
$simbrief = $this->simBriefSvc->downloadOfp($user->id, $ofp_id, $flight_id, $aircraft_id, $fares);
if ($simbrief === null) {
$error = new AssetNotFound(new Exception('Simbrief OFP not found'));
return $error->getResponse();
@@ -243,6 +371,31 @@ class SimBriefController
]);
}
/**
* Get the latest generated OFP. Pass in two additional items, the Simbrief userid and static_id
* This will get the latest edited/regenerated of from Simbrief and update our records
* We do not need to send the fares again, so used an empty array
*/
public function update_ofp(Request $request)
{
/** @var User $user */
$user = Auth::user();
$ofp_id = $request->input('ofp_id');
$flight_id = $request->input('flight_id');
$aircraft_id = $request->input('aircraft_id');
$sb_userid = $request->input('sb_userid');
$sb_static_id = $request->input('sb_static_id');
$fares = [];
$simbrief = $this->simBriefSvc->downloadOfp($user->id, $ofp_id, $flight_id, $aircraft_id, $fares, $sb_userid, $sb_static_id);
if ($simbrief === null) {
$error = new AssetNotFound(new Exception('Simbrief OFP not found'));
return $error->getResponse();
}
return redirect(route('frontend.simbrief.briefing', [$ofp_id]));
}
/**
* Generate the API code
*

View File

@@ -25,7 +25,6 @@ use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\View\View;
use function in_array;
use Laracasts\Flash\Flash;
use RuntimeException;
class InstallerController extends Controller
@@ -203,21 +202,21 @@ class InstallerController extends Controller
Log::error('Testing db before writing configs failed');
Log::error($e->getMessage());
Flash::error($e->getMessage());
flash()->error($e->getMessage());
return redirect(route('installer.step2'))->withInput();
}
// Now write out the env file
$attrs = [
'SITE_NAME' => $request->post('site_name'),
'SITE_URL' => $request->post('site_url'),
'DB_CONN' => $request->post('db_conn'),
'DB_HOST' => $request->post('db_host'),
'DB_PORT' => $request->post('db_port'),
'DB_NAME' => $request->post('db_name'),
'DB_USER' => $request->post('db_user'),
'DB_PASS' => $request->post('db_pass'),
'DB_PREFIX' => $request->post('db_prefix'),
'SITE_NAME' => $request->post('site_name'),
'APP_URL' => $request->post('app_url'),
'DB_CONNECTION' => $request->post('db_conn'),
'DB_HOST' => $request->post('db_host'),
'DB_PORT' => $request->post('db_port'),
'DB_DATABASE' => $request->post('db_name'),
'DB_USERNAME' => $request->post('db_user'),
'DB_PASSWORD' => $request->post('db_pass'),
'DB_PREFIX' => $request->post('db_prefix'),
];
/*
@@ -231,7 +230,7 @@ class InstallerController extends Controller
Log::error('Config files failed to write');
Log::error($e->getMessage());
Flash::error($e->getMessage());
flash()->error($e->getMessage());
return redirect(route('installer.step2'))->withInput();
}
@@ -257,7 +256,7 @@ class InstallerController extends Controller
Log::error('Error on db setup: '.$e->getMessage());
//dd($e);
$this->envSvc->removeConfigFiles();
Flash::error($e->getMessage());
flash()->error($e->getMessage());
return redirect(route('installer.step2'))->withInput();
}

View File

@@ -3,49 +3,32 @@
namespace App\Http\Controllers\System;
use App\Contracts\Controller;
use App\Repositories\KvpRepository;
use App\Services\AnalyticsService;
use App\Services\Installer\InstallerService;
use App\Services\Installer\MigrationService;
use App\Services\Installer\SeederService;
use Codedge\Updater\UpdaterManager;
use function count;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
class UpdateController extends Controller
{
private $analyticsSvc;
private $installerSvc;
private $kvpRepo;
private $migrationSvc;
private $seederSvc;
private $updateManager;
/**
* @param AnalyticsService $analyticsSvc
* @param InstallerService $installerSvc
* @param KvpRepository $kvpRepo
* @param MigrationService $migrationSvc
* @param SeederService $seederSvc
* @param UpdaterManager $updateManager
*/
public function __construct(
AnalyticsService $analyticsSvc,
InstallerService $installerSvc,
KvpRepository $kvpRepo,
MigrationService $migrationSvc,
SeederService $seederSvc,
UpdaterManager $updateManager
SeederService $seederSvc
) {
$this->analyticsSvc = $analyticsSvc;
$this->migrationSvc = $migrationSvc;
$this->seederSvc = $seederSvc;
$this->installerSvc = $installerSvc;
$this->kvpRepo = $kvpRepo;
$this->updateManager = $updateManager;
}
/**
@@ -107,38 +90,4 @@ class UpdateController extends Controller
{
return redirect('/admin');
}
/**
* Show the update page with the latest version
*
* @return Factory|View
*/
public function updater()
{
$version = $this->kvpRepo->get('latest_version_tag');
return view('system.updater.downloader/downloader', [
'version' => $version,
]);
}
/**
* Download the actual update and then forward the user to the updater page
*
* @return mixed
*/
public function update_download()
{
$version = $this->kvpRepo->get('latest_version_tag');
if (empty($version)) {
return view('system.updater.steps.step1-no-update');
}
$release = $this->updateManager->source('github')->fetch($version);
$this->updateManager->source('github')->update($release);
$this->analyticsSvc->sendUpdate();
Log::info('Update completed to '.$version.', redirecting');
return redirect('/update');
}
}

View File

@@ -39,7 +39,7 @@ class ApiAuth implements Middleware
return $this->unauthorized('User not found with key "'.$api_key.'"');
}
if ($user->state !== UserState::ACTIVE) {
if ($user->state !== UserState::ACTIVE && $user->state !== UserState::ON_LEAVE) {
return $this->unauthorized('User is not ACTIVE, please contact an administrator');
}
@@ -50,6 +50,9 @@ class ApiAuth implements Middleware
return $user;
});
// Force english locale for API
app()->setLocale('en');
return $next($request);
}

View File

@@ -15,6 +15,7 @@ class JsonResponse implements Middleware
{
$response = $next($request);
$response->headers->set('Content-Type', 'application/json');
$response->headers->set('charset', 'utf-8');
return $response;
}

View File

@@ -52,7 +52,7 @@ class SetActiveTheme implements Middleware
}
try {
$theme = setting('general.theme');
$theme = setting('general.theme', 'default');
} catch (\Exception $e) {
Log::error($e->getMessage());
$theme = 'default';

View File

@@ -19,7 +19,7 @@ class FileRequest extends FormRequest
return [
'distance' => 'required|numeric',
'flight_time' => 'required|integer',
'fuel_used' => 'required|numeric',
'fuel_used' => 'sometimes|numeric',
'block_time' => 'sometimes|integer',
'airline_id' => 'sometimes|exists:airlines,id',
'aircraft_id' => 'sometimes|exists:aircraft,id',

View File

@@ -9,7 +9,7 @@ class Bid extends Resource
public function toArray($request)
{
$res = parent::toArray($request);
$res['flight'] = new Flight($this->flight);
$res['flight'] = new BidFlight($this->flight);
return $res;
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Resources;
use App\Http\Resources\SimBrief as SimbriefResource;
/**
* @mixin \App\Models\Flight
*/
class BidFlight extends Flight
{
/**
* @param \Illuminate\Http\Request $request
*
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*
* @return array
*/
public function toArray($request)
{
$res = parent::toArray($request);
if ($this->whenLoaded('simbrief')) {
unset($res['subfleets']);
$res['simbrief'] = new SimbriefResource($this->simbrief);
} else {
unset($res['simbrief']);
$res['subfleets'] = Subfleet::collection($this->whenLoaded('subfleets'));
}
$res['fields'] = $this->setFields();
return $res;
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Resources;
class BidSubfleet extends Subfleet
{
protected $aircraft;
protected $fares;
public function __construct($resource, $aircraft, $fares)
{
parent::__construct($resource);
$this->aircraft = $aircraft;
$this->fares = $fares;
}
public function toArray($request)
{
$res = [];
$res['airline_id'] = $this->airline_id;
$res['hub_id'] = $this->hub_id;
$res['type'] = $this->type;
$res['simbrief_type'] = $this->simbrief_type;
$res['name'] = $this->name;
$res['fuel_type'] = $this->fuel_type;
$res['cost_block_hour'] = $this->cost_block_hour;
$res['cost_delay_minute'] = $this->cost_delay_minute;
$res['ground_handling_multiplier'] = $this->ground_handling_multiplier;
$res['cargo_capacity'] = $this->cargo_capacity;
$res['fuel_capacity'] = $this->fuel_capacity;
$res['gross_weight'] = $this->gross_weight;
$res['fares'] = Fare::collection($this->fares);
// There should only be one aircraft tied to a bid subfleet, wrap in a collection
$res['aircraft'] = Aircraft::collection([$this->aircraft]);
return $res;
}
}

View File

@@ -17,6 +17,7 @@ class Fare extends Resource
'name' => $this->name,
'capacity' => $this->capacity,
'cost' => $this->cost,
'count' => $this->count ?? 0,
'price' => $this->price,
'type' => $this->type,
'notes' => $this->notes,

View File

@@ -15,7 +15,7 @@ class Flight extends Resource
/**
* Set the fields on the flight object
*/
private function setFields()
protected function setFields()
{
/** @var \Illuminate\Support\Collection $field_values */
$return_values = new stdClass();

View File

@@ -18,7 +18,7 @@ class News extends Resource
$res = parent::toArray($request);
$res['user'] = [
'id' => $this->user->id,
'name' => $this->user->name,
'name' => $this->user->name_private,
];
return $res;

View File

@@ -27,6 +27,7 @@ class Pirep extends Resource
{
$res = parent::toArray($request);
$res['ident'] = $this->ident;
$res['phase'] = $this->status;
$res['status_text'] = PirepStatus::label($this->status);
// Set these to the response units
@@ -37,6 +38,13 @@ class Pirep extends Resource
$distance = new Distance($res['distance'], config('phpvms.internal_units.distance'));
$res['distance'] = $distance->getResponseUnits();
if (!array_key_exists('block_fuel', $res)) {
$res['block_fuel'] = 0;
}
$block_fuel = new Fuel($res['block_fuel'], config('phpvms.internal_units.fuel'));
$res['block_fuel'] = $block_fuel->getResponseUnits();
if (!array_key_exists('fuel_used', $res)) {
$res['fuel_used'] = 0;
}

View File

@@ -11,9 +11,29 @@ class SimBrief extends Resource
{
public function toArray($request)
{
return [
'id' => $this->id,
'url' => url(route('api.flights.briefing', ['id' => $this->id])),
$data = [
'id' => $this->id,
'aircraft_id' => $this->aircraft_id,
'url' => url(route('api.flights.briefing', ['id' => $this->id])),
];
$fares = [];
try {
if (!empty($this->fare_data)) {
$fare_data = json_decode($this->fare_data, true);
foreach ($fare_data as $fare) {
$fares[] = new \App\Models\Fare($fare);
}
$fares = collect($fares);
}
} catch (\Exception $e) {
// Invalid fare data
}
$data['subfleet'] = new BidSubfleet($this->aircraft->subfleet, $this->aircraft, $fares);
return $data;
}
}

View File

@@ -15,9 +15,8 @@ class User extends Resource
'id' => $this->id,
'pilot_id' => $this->pilot_id,
'ident' => $this->ident,
'name' => $this->name,
'name' => $this->name_private,
'name_private' => $this->name_private,
'email' => $this->email,
'avatar' => $this->resolveAvatarUrl(),
'rank_id' => $this->rank_id,
'home_airport' => $this->home_airport_id,

View File

@@ -3,8 +3,7 @@
namespace App\Listeners;
use App\Contracts\Listener;
use App\Events\PirepAccepted;
use App\Events\PirepRejected;
use App\Events\PirepFiled;
use App\Services\BidService;
/**
@@ -13,8 +12,7 @@ use App\Services\BidService;
class BidEventHandler extends Listener
{
public static $callbacks = [
PirepAccepted::class => 'onPirepAccept',
PirepRejected::class => 'onPirepReject',
PirepFiled::class => 'onPirepFiled',
];
private $bidSvc;
@@ -25,29 +23,15 @@ class BidEventHandler extends Listener
}
/**
* When a PIREP is accepted, remove any bids
* When a PIREP is filed, remove any bids
*
* @param PirepAccepted $event
* @param PirepFiled $event
*
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
* @throws \Exception
*/
public function onPirepAccept(PirepAccepted $event): void
{
$this->bidSvc->removeBidForPirep($event->pirep);
}
/**
* When a PIREP is accepted, remove any bids
*
* @param PirepRejected $event
*
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
* @throws \Exception
*/
public function onPirepReject(PirepRejected $event): void
public function onPirepFiled(PirepFiled $event): void
{
$this->bidSvc->removeBidForPirep($event->pirep);
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Listeners;
use Illuminate\Log\Events\MessageLogged;
use Symfony\Component\Console\Output\ConsoleOutput;
/**
* Show logs in the console
*
* https://stackoverflow.com/questions/48264479/log-laravel-with-artisan-output
*/
class MessageLoggedListener
{
public function handle(MessageLogged $event)
{
if (app()->runningInConsole() && app()->environment() !== 'testing') {
$output = new ConsoleOutput();
$output->writeln("<$event->level>$event->message</$event->level>");
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Listeners;
use App\Contracts\Listener;
use App\Events\PirepPrefiled;
/**
* Handler for PIREP events
*/
class PirepEventsHandler extends Listener
{
/** The events and the callback */
public static $callbacks = [
PirepPrefiled::class => 'onPirepPrefile',
];
/**
* Called when a PIREP is prefiled
*
* @param PirepPrefiled $event
*/
public function onPirepPrefile(PirepPrefiled $event)
{
}
}

View File

@@ -12,6 +12,7 @@ use Carbon\Carbon;
* @property int id
* @property mixed subfleet_id
* @property string airport_id The apt where the aircraft is
* @property string ident
* @property string name
* @property string icao
* @property string registration
@@ -24,6 +25,7 @@ use Carbon\Carbon;
* @property int status
* @property int state
* @property Carbon landing_time
* @property float fuel_onboard
*/
class Aircraft extends Model
{
@@ -70,6 +72,14 @@ class Aircraft extends Model
'zfw' => 'nullable|numeric',
];
/**
* @return string
*/
public function getIdentAttribute(): string
{
return $this->registration.' ('.$this->icao.')';
}
/**
* See if this aircraft is active
*

View File

@@ -6,6 +6,7 @@ use App\Contracts\Model;
use App\Models\Enums\JournalType;
use App\Models\Traits\FilesTrait;
use App\Models\Traits\JournalTrait;
use Illuminate\Support\Str;
/**
* Class Airline
@@ -84,7 +85,7 @@ class Airline extends Model
*/
public function setIataAttribute($iata)
{
$this->attributes['iata'] = strtoupper($iata);
$this->attributes['iata'] = Str::upper($iata);
}
/**
@@ -94,7 +95,7 @@ class Airline extends Model
*/
public function setIcaoAttribute($icao): void
{
$this->attributes['icao'] = strtoupper($icao);
$this->attributes['icao'] = Str::upper($icao);
}
public function subfleets()

Some files were not shown because too many files have changed in this diff Show More