From 9d3d284df7bb7e97330ef1b78e142e426ad13d0b Mon Sep 17 00:00:00 2001 From: Nabeel Shahzad Date: Thu, 12 Apr 2018 16:12:32 -0500 Subject: [PATCH] Check start/end/days of week in cron and active/deactivate flights accordingly --- app/Cron/Nightly/SetActiveFlights.php | 70 +++++++++++++++ app/Database/factories/FlightFactory.php | 13 +-- app/Models/Enums/Days.php | 23 +++++ app/Models/Flight.php | 18 ++++ app/Providers/EventServiceProvider.php | 3 + tests/FlightTest.php | 103 +++++++++++++++++++++++ 6 files changed, 224 insertions(+), 6 deletions(-) create mode 100644 app/Cron/Nightly/SetActiveFlights.php diff --git a/app/Cron/Nightly/SetActiveFlights.php b/app/Cron/Nightly/SetActiveFlights.php new file mode 100644 index 00000000..e63906d9 --- /dev/null +++ b/app/Cron/Nightly/SetActiveFlights.php @@ -0,0 +1,70 @@ +checkFlights(); + } + + /** + * Look through every single flight, check the start/end dates, + * as well of the days of week if this flight is active on this day + * + * TODO: Option to check the flight active/inactive against departure TZ + * TODO: Move to FlightService + */ + public function checkFlights(): void + { + $today = Carbon::now('UTC'); + $flights = Flight::all(); + + /** + * @var Flight $flight + */ + foreach($flights as $flight) { + + // dates aren't set, so just save if there were any changes above + // and move onto the next one + if ($flight->start_date === null || $flight->end_date === null) { + if ($flight->days > 0) { + $flight->active = Days::isToday($flight->days); + } + + $flight->save(); + continue; + } + + // Check the day of week now first + + // Start/end date is set, so make sure today is valid for it to be alive + // and then make sure if days of the week are specified, check that too + if ($today->gte($flight->start_date) && $today->lte($flight->end_date)) { + if ($flight->days > 0) { + $flight->active = Days::isToday($flight->days); + } else { + $flight->active = true; + } + } else { + $flight->active = false; + } + + $flight->save(); + } + } +} diff --git a/app/Database/factories/FlightFactory.php b/app/Database/factories/FlightFactory.php index b4d81fb1..b19b86cf 100644 --- a/app/Database/factories/FlightFactory.php +++ b/app/Database/factories/FlightFactory.php @@ -1,12 +1,11 @@ define(App\Models\Flight::class, function (Faker $faker) use ($airlinesAvailable) { +$factory->define(App\Models\Flight::class, function (Faker $faker) { return [ 'id' => null, 'airline_id' => function () { @@ -26,13 +25,15 @@ $factory->define(App\Models\Flight::class, function (Faker $faker) use ($airline }, 'distance' => $faker->numberBetween(0, 3000), 'route' => null, - 'days' => 0, 'level' => 0, 'dpt_time' => $faker->time(), 'arr_time' => $faker->time(), 'flight_time' => $faker->numberBetween(60, 360), 'has_bid' => false, 'active' => true, + 'days' => 0, + 'start_date' => null, + 'end_date' => null, 'created_at' => $faker->dateTimeBetween('-1 week', 'now'), 'updated_at' => function (array $flight) { return $flight['created_at']; diff --git a/app/Models/Enums/Days.php b/app/Models/Enums/Days.php index 92ce6848..5eaa0ee9 100644 --- a/app/Models/Enums/Days.php +++ b/app/Models/Enums/Days.php @@ -39,6 +39,19 @@ class Days extends Enum 'Su' => Days::SUNDAY, ]; + /** + * Map the ISO8601 numeric today to day + */ + public static $isoDayMap = [ + 1 => Days::MONDAY, + 2 => Days::TUESDAY, + 3 => Days::WEDNESDAY, + 4 => Days::THURSDAY, + 5 => Days::FRIDAY, + 6 => Days::SATURDAY, + 7 => Days::SUNDAY, + ]; + /** * Create the masked value for the days of week * @param array $days @@ -64,4 +77,14 @@ class Days extends Enum { return ($mask & $day) === $day; } + + /** + * Does the mask contain today? + * @param $val + * @return bool + */ + public static function isToday($val): bool + { + return static::in($val, static::$isoDayMap[(int) date('N')]); + } } diff --git a/app/Models/Flight.php b/app/Models/Flight.php index fa001c20..c1836a2d 100644 --- a/app/Models/Flight.php +++ b/app/Models/Flight.php @@ -6,6 +6,7 @@ use App\Interfaces\Model; use App\Models\Enums\Days; use App\Models\Traits\HashIdTrait; use App\Support\Units\Distance; +use Carbon\Carbon; use Illuminate\Support\Collection; use PhpUnitsOfMeasure\Exception\NonNumericValue; use PhpUnitsOfMeasure\Exception\NonStringUnitName; @@ -26,6 +27,9 @@ use PhpUnitsOfMeasure\Exception\NonStringUnitName; * @property string dpt_airport_id * @property string arr_airport_id * @property string alt_airport_id + * @property int active + * @property Carbon start_date + * @property Carbon end_date */ class Flight extends Model { @@ -178,6 +182,20 @@ class Flight extends Model return ''; } + /** + * Set the days parameter. If an array is passed, it's + * AND'd together to create the mask value + * @param array|int $val + */ + public function setDaysAttribute($val): void + { + if (\is_array($val)) { + $val = Days::getDaysMask($val); + } + + $this->attributes['days'] = $val; + } + /** * Relationship */ diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 5fba8898..5be19e72 100755 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Cron\Nightly\SetActiveFlights; use App\Events\CronMonthly; use App\Events\CronNightly; use App\Events\CronWeekly; @@ -29,6 +30,7 @@ class EventServiceProvider extends ServiceProvider ApplyExpenses::class, RecalculateBalances::class, PilotLeave::class, + SetActiveFlights::class, ], CronWeekly::class => [ @@ -42,6 +44,7 @@ class EventServiceProvider extends ServiceProvider AwardListener::class, ], ]; + protected $subscribe = [ FinanceEvents::class, NotificationEvents::class, diff --git a/tests/FlightTest.php b/tests/FlightTest.php index 83fc6666..94c95b85 100644 --- a/tests/FlightTest.php +++ b/tests/FlightTest.php @@ -149,6 +149,109 @@ class FlightTest extends TestCase $flight = Flight::findByDays([Days::WEDNESDAY, Days::THURSDAY])->first(); $this->assertNull($flight); + + + } + + /** + * Make sure that flights are marked as inactive when they're out of the start/end + * zones. also make sure that flights with a specific day of the week are only + * active on those days + */ + public function testDayOfWeekActive(): void + { + $this->user = factory(App\Models\User::class)->create(); + + // Set it to Monday or Tuesday, depending on what today is + if (date('N') === 1) { // today is a monday + $days = Days::getDaysMask([Days::TUESDAY]); + } else { + $days = Days::getDaysMask([Days::MONDAY]); + } + + factory(App\Models\Flight::class, 5)->create(); + $flight = factory(App\Models\Flight::class)->create([ + 'days' => $days, + #'start_date' => Carbon\Carbon::now('UTC')->subDay(1), + #'end_date' => Carbon\Carbon::now('UTC')->addDays(1), + ]); + + // Run the event that will enable/disable flights + $event = new \App\Events\CronNightly(); + (new \App\Cron\Nightly\SetActiveFlights())->handle($event); + + $res = $this->get('/api/flights'); + $body = $res->json('data'); + + $flights = collect($body)->where('id', $flight->id)->first(); + $this->assertNull($flights); + } + + public function testStartEndDate(): void + { + $this->user = factory(App\Models\User::class)->create(); + + factory(App\Models\Flight::class, 5)->create(); + $flight = factory(App\Models\Flight::class)->create([ + 'start_date' => Carbon\Carbon::now('UTC')->subDays(1), + 'end_date' => Carbon\Carbon::now('UTC')->addDays(1), + ]); + + $flight_not_active = factory(App\Models\Flight::class)->create([ + 'start_date' => Carbon\Carbon::now('UTC')->subDays(10), + 'end_date' => Carbon\Carbon::now('UTC')->subDays(2), + ]); + + // Run the event that will enable/disable flights + $event = new \App\Events\CronNightly(); + (new \App\Cron\Nightly\SetActiveFlights())->handle($event); + + $res = $this->get('/api/flights'); + $body = $res->json('data'); + + $flights = collect($body)->where('id', $flight->id)->first(); + $this->assertNotNull($flights); + + $flights = collect($body)->where('id', $flight_not_active->id)->first(); + $this->assertNull($flights); + } + + public function testStartEndDateDayOfWeek(): void + { + $this->user = factory(App\Models\User::class)->create(); + + // Set it to Monday or Tuesday, depending on what today is + if (date('N') === 1) { // today is a monday + $days = Days::getDaysMask([Days::TUESDAY]); + } else { + $days = Days::getDaysMask([Days::MONDAY]); + } + + factory(App\Models\Flight::class, 5)->create(); + $flight = factory(App\Models\Flight::class)->create([ + 'start_date' => Carbon\Carbon::now('UTC')->subDays(1), + 'end_date' => Carbon\Carbon::now('UTC')->addDays(1), + 'days' => Days::$isoDayMap[date('N')], + ]); + + $flight_not_active = factory(App\Models\Flight::class)->create([ + 'start_date' => Carbon\Carbon::now('UTC')->subDays(1), + 'end_date' => Carbon\Carbon::now('UTC')->addDays(1), + 'days' => $days, + ]); + + // Run the event that will enable/disable flights + $event = new \App\Events\CronNightly(); + (new \App\Cron\Nightly\SetActiveFlights())->handle($event); + + $res = $this->get('/api/flights'); + $body = $res->json('data'); + + $flights = collect($body)->where('id', $flight->id)->first(); + $this->assertNotNull($flights); + + $flights = collect($body)->where('id', $flight_not_active->id)->first(); + $this->assertNull($flights); } /**