diff --git a/.env b/.env index 3229096ab..f9a323986 100644 --- a/.env +++ b/.env @@ -20,7 +20,7 @@ CACHE_PREFIX=services QUEUE_DRIVER=redis QUEUE_CONNECTION=redis -SESSION_DRIVER=file +SESSION_DRIVER=redis SESSION_LIFETIME=120 REDIS_HOST=127.0.0.1 @@ -28,7 +28,10 @@ REDIS_PASSWORD=null REDIS_PORT=6379 REDIS_DB=8 REDIS_CACHE_DB=9 +REDIS_SESSION_DB=10 +REDIS_QUEUE_DB=11 REDIS_CLIENT=predis + MAIL_DRIVER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 diff --git a/composer.json b/composer.json index f53f527c2..b58a26486 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "predis/predis": "^1.1", "socialiteproviders/manager": "^4.0", "spatie/laravel-rate-limited-job-middleware": "^1.5", + "spatie/laravel-schedule-monitor": "2.0.1", "twbs/bootstrap": "^4.5", "web-token/jwt-easy": "^2.2", "web-token/jwt-signature-algorithm-ecdsa": "^2.2", diff --git a/composer.lock b/composer.lock index 98f86036e..65ff25a50 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "83223e04c66a8cd1187f8679792e00ad", + "content-hash": "6fdcdd62287b3668ac2947c95d07f87b", "packages": [ { "name": "brick/math", @@ -1717,6 +1717,53 @@ }, "time": "2020-09-28T09:39:08+00:00" }, + { + "name": "lorisleiva/cron-translator", + "version": "v0.1.1", + "source": { + "type": "git", + "url": "https://github.com/lorisleiva/cron-translator.git", + "reference": "784a6f6255a4b5f45da5d89dc6ec631a14d7b011" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lorisleiva/cron-translator/zipball/784a6f6255a4b5f45da5d89dc6ec631a14d7b011", + "reference": "784a6f6255a4b5f45da5d89dc6ec631a14d7b011", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lorisleiva\\CronTranslator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Loris LEIVA", + "email": "loris.leiva@gmail.com", + "homepage": "https://lorisleiva.com" + } + ], + "description": "Makes CRON expressions human-readable", + "homepage": "https://github.com/lorisleiva/cron-translator", + "keywords": [ + "cron", + "expression", + "human" + ], + "support": { + "issues": "https://github.com/lorisleiva/cron-translator/issues", + "source": "https://github.com/lorisleiva/cron-translator/tree/v0.1.1" + }, + "time": "2020-03-01T14:44:47+00:00" + }, { "name": "monolog/monolog", "version": "2.2.0", @@ -2712,6 +2759,81 @@ ], "time": "2020-11-27T09:36:55+00:00" }, + { + "name": "spatie/laravel-schedule-monitor", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-schedule-monitor.git", + "reference": "4ffdaea81b5c27a119b6cbac8f4894657b8fd6d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-schedule-monitor/zipball/4ffdaea81b5c27a119b6cbac8f4894657b8fd6d9", + "reference": "4ffdaea81b5c27a119b6cbac8f4894657b8fd6d9", + "shasum": "" + }, + "require": { + "illuminate/bus": "^7.19|^8.0", + "lorisleiva/cron-translator": "^0.1.1", + "php": "^7.4" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "laravel/legacy-factories": "^1.0.4", + "ohdearapp/ohdear-php-sdk": "^3.0", + "orchestra/testbench": "^5.0|^6.0", + "phpunit/phpunit": "^9.0", + "spatie/phpunit-snapshot-assertions": "^4.2", + "spatie/test-time": "^1.2", + "vimeo/psalm": "^3.11" + }, + "suggest": { + "ohdearapp/ohdear-php-sdk": "Needed to sync your schedule with Oh Dear" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\ScheduleMonitor\\ScheduleMonitorServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\ScheduleMonitor\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Monitor scheduled tasks in a Laravel app", + "homepage": "https://github.com/spatie/laravel-schedule-monitor", + "keywords": [ + "laravel-schedule-monitor", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-schedule-monitor/issues", + "source": "https://github.com/spatie/laravel-schedule-monitor/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2020-10-06T10:38:45+00:00" + }, { "name": "spomky-labs/base64url", "version": "v2.0.4", diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index 1a58957d2..247294d66 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -42,6 +42,8 @@ namespace Composer\Autoload; */ class ClassLoader { + private $vendorDir; + // PSR-4 private $prefixLengthsPsr4 = array(); private $prefixDirsPsr4 = array(); @@ -57,6 +59,13 @@ class ClassLoader private $missingClasses = array(); private $apcuPrefix; + private static $registeredLoaders = array(); + + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + } + public function getPrefixes() { if (!empty($this->prefixesPsr0)) { @@ -300,6 +309,17 @@ class ClassLoader public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } } /** @@ -308,6 +328,10 @@ class ClassLoader public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } } /** @@ -367,6 +391,16 @@ class ClassLoader return $file; } + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + private function findFileWithExtension($class, $ext) { // PSR-4 lookup diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index 161dc5332..af932799b 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -12,6 +12,7 @@ namespace Composer; +use Composer\Autoload\ClassLoader; use Composer\Semver\VersionParser; @@ -29,7 +30,7 @@ private static $installed = array ( 'aliases' => array ( ), - 'reference' => '4b72a59e62d368371546246a68aef55ee21c2705', + 'reference' => '40ed5dd5a576916f6561953482f68722d1ecce8f', 'name' => 'laravel/laravel', ), 'versions' => @@ -463,7 +464,7 @@ private static $installed = array ( 'aliases' => array ( ), - 'reference' => '4b72a59e62d368371546246a68aef55ee21c2705', + 'reference' => '40ed5dd5a576916f6561953482f68722d1ecce8f', ), 'laravel/socialite' => array ( @@ -528,6 +529,15 @@ private static $installed = array ( ), 'reference' => '159c3d2bf27568f9af87d6c3f4bb616a251eb12b', ), + 'lorisleiva/cron-translator' => + array ( + 'pretty_version' => 'v0.1.1', + 'version' => '0.1.1.0', + 'aliases' => + array ( + ), + 'reference' => '784a6f6255a4b5f45da5d89dc6ec631a14d7b011', + ), 'mockery/mockery' => array ( 'pretty_version' => '1.4.2', @@ -946,6 +956,15 @@ private static $installed = array ( ), 'reference' => '7b72592e0d823e2948c413f5e661de0fd3431db5', ), + 'spatie/laravel-schedule-monitor' => + array ( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '4ffdaea81b5c27a119b6cbac8f4894657b8fd6d9', + ), 'spomky-labs/base64url' => array ( 'pretty_version' => 'v2.0.4', @@ -1356,6 +1375,8 @@ private static $installed = array ( ), ), ); +private static $canGetVendors; +private static $installedByVendor = array(); @@ -1365,7 +1386,17 @@ private static $installed = array ( public static function getInstalledPackages() { -return array_keys(self::$installed['versions']); +$packages = array(); +foreach (self::getInstalled() as $installed) { +$packages[] = array_keys($installed['versions']); +} + + +if (1 === \count($packages)) { +return $packages[0]; +} + +return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); } @@ -1378,7 +1409,13 @@ return array_keys(self::$installed['versions']); public static function isInstalled($packageName) { -return isset(self::$installed['versions'][$packageName]); +foreach (self::getInstalled() as $installed) { +if (isset($installed['versions'][$packageName])) { +return true; +} +} + +return false; } @@ -1413,42 +1450,50 @@ return $provided->matches($constraint); public static function getVersionRanges($packageName) { -if (!isset(self::$installed['versions'][$packageName])) { -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; } $ranges = array(); -if (isset(self::$installed['versions'][$packageName]['pretty_version'])) { -$ranges[] = self::$installed['versions'][$packageName]['pretty_version']; +if (isset($installed['versions'][$packageName]['pretty_version'])) { +$ranges[] = $installed['versions'][$packageName]['pretty_version']; } -if (array_key_exists('aliases', self::$installed['versions'][$packageName])) { -$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['aliases']); +if (array_key_exists('aliases', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); } -if (array_key_exists('replaced', self::$installed['versions'][$packageName])) { -$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['replaced']); +if (array_key_exists('replaced', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); } -if (array_key_exists('provided', self::$installed['versions'][$packageName])) { -$ranges = array_merge($ranges, self::$installed['versions'][$packageName]['provided']); +if (array_key_exists('provided', $installed['versions'][$packageName])) { +$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); } return implode(' || ', $ranges); } +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +} + public static function getVersion($packageName) { -if (!isset(self::$installed['versions'][$packageName])) { -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; } -if (!isset(self::$installed['versions'][$packageName]['version'])) { +if (!isset($installed['versions'][$packageName]['version'])) { return null; } -return self::$installed['versions'][$packageName]['version']; +return $installed['versions'][$packageName]['version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } @@ -1457,15 +1502,19 @@ return self::$installed['versions'][$packageName]['version']; public static function getPrettyVersion($packageName) { -if (!isset(self::$installed['versions'][$packageName])) { -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; } -if (!isset(self::$installed['versions'][$packageName]['pretty_version'])) { +if (!isset($installed['versions'][$packageName]['pretty_version'])) { return null; } -return self::$installed['versions'][$packageName]['pretty_version']; +return $installed['versions'][$packageName]['pretty_version']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } @@ -1474,15 +1523,19 @@ return self::$installed['versions'][$packageName]['pretty_version']; public static function getReference($packageName) { -if (!isset(self::$installed['versions'][$packageName])) { -throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); +foreach (self::getInstalled() as $installed) { +if (!isset($installed['versions'][$packageName])) { +continue; } -if (!isset(self::$installed['versions'][$packageName]['reference'])) { +if (!isset($installed['versions'][$packageName]['reference'])) { return null; } -return self::$installed['versions'][$packageName]['reference']; +return $installed['versions'][$packageName]['reference']; +} + +throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); } @@ -1491,7 +1544,9 @@ return self::$installed['versions'][$packageName]['reference']; public static function getRootPackage() { -return self::$installed['root']; +$installed = self::getInstalled(); + +return $installed[0]['root']; } @@ -1526,5 +1581,32 @@ return self::$installed; public static function reload($data) { self::$installed = $data; +self::$installedByVendor = array(); +} + + + + +private static function getInstalled() +{ +if (null === self::$canGetVendors) { +self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); +} + +$installed = array(); + +if (self::$canGetVendors) { +foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { +if (isset(self::$installedByVendor[$vendorDir])) { +$installed[] = self::$installedByVendor[$vendorDir]; +} elseif (is_file($vendorDir.'/composer/installed.php')) { +$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; +} +} +} + +$installed[] = self::$installed; + +return $installed; } } diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 64f15b3d3..378d3c8c2 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -16,7 +16,9 @@ return array( 'App\\Console\\Commands\\Files\\MoonFormatter' => $baseDir . '/app/Console/Commands/Files/MoonFormatter.php', 'App\\Console\\Commands\\Files\\UpdateItemCompositionFromSDECommand' => $baseDir . '/app/Console/Commands/Files/UpdateItemCompositionFromSDECommand.php', 'App\\Console\\Commands\\Finances\\UpdateAllianceWalletJournal' => $baseDir . '/app/Console/Commands/Finances/UpdateAllianceWalletJournal.php', + 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesDataCleanup' => $baseDir . '/app/Console/Commands/MiningTaxes/MiningTaxesDataCleanup.php', 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesInvoices' => $baseDir . '/app/Console/Commands/MiningTaxes/MiningTaxesInvoices.php', + 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesInvoicesNew' => $baseDir . '/app/Console/Commands/MiningTaxes/MiningTaxesInvoicesNew.php', 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesLedgers' => $baseDir . '/app/Console/Commands/MiningTaxes/MiningTaxesLedgers.php', 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesObservers' => $baseDir . '/app/Console/Commands/MiningTaxes/MiningTaxesObservers.php', 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesPayments' => $baseDir . '/app/Console/Commands/MiningTaxes/MiningTaxesPayments.php', @@ -31,7 +33,6 @@ return array( 'App\\Http\\Controllers\\Blacklist\\BlacklistController' => $baseDir . '/app/Http/Controllers/Blacklist/BlacklistController.php', 'App\\Http\\Controllers\\Contracts\\SupplyChainController' => $baseDir . '/app/Http/Controllers/Contracts/SupplyChainController.php', 'App\\Http\\Controllers\\Controller' => $baseDir . '/app/Http/Controllers/Controller.php', - 'App\\Http\\Controllers\\Dashboard\\AdminController' => $baseDir . '/app/Http/Controllers/Dashboard/AdminController.php', 'App\\Http\\Controllers\\Dashboard\\AdminDashboardController' => $baseDir . '/app/Http/Controllers/Dashboard/AdminDashboardController.php', 'App\\Http\\Controllers\\Dashboard\\DashboardController' => $baseDir . '/app/Http/Controllers/Dashboard/DashboardController.php', 'App\\Http\\Controllers\\Logistics\\FuelController' => $baseDir . '/app/Http/Controllers/Logistics/FuelController.php', @@ -50,10 +51,16 @@ return array( 'App\\Http\\Middleware\\TrimStrings' => $baseDir . '/app/Http/Middleware/TrimStrings.php', 'App\\Http\\Middleware\\TrustProxies' => $baseDir . '/app/Http/Middleware/TrustProxies.php', 'App\\Http\\Middleware\\VerifyCsrfToken' => $baseDir . '/app/Http/Middleware/VerifyCsrfToken.php', + 'App\\Jobs\\Commands\\Data\\PurgeUsersJob' => $baseDir . '/app/Jobs/Commands/Data/PurgeUsersJob.php', 'App\\Jobs\\Commands\\Eve\\ItemPricesUpdateJob' => $baseDir . '/app/Jobs/Commands/Eve/ItemPricesUpdateJob.php', 'App\\Jobs\\Commands\\Eve\\ProcessSendEveMailJob' => $baseDir . '/app/Jobs/Commands/Eve/ProcessSendEveMailJob.php', + 'App\\Jobs\\Commands\\Eve\\ProcessSendEveMailJobRL' => $baseDir . '/app/Jobs/Commands/Eve/ProcessSendEveMailJobRL.php', + 'App\\Jobs\\Commands\\Finances\\UpdateItemPricesJob' => $baseDir . '/app/Jobs/Commands/Finances/UpdateItemPricesJob.php', 'App\\Jobs\\Commands\\MiningTaxes\\FetchMiningTaxesLedgersJob' => $baseDir . '/app/Jobs/Commands/MiningTaxes/FetchMiningTaxesLedgersJob.php', + 'App\\Jobs\\Commands\\MiningTaxes\\FetchMiningTaxesObserversJob' => $baseDir . '/app/Jobs/Commands/MiningTaxes/FetchMiningTaxesObserversJob.php', + 'App\\Jobs\\Commands\\MiningTaxes\\ProcessMiningTaxesLedgersJob' => $baseDir . '/app/Jobs/Commands/MiningTaxes/ProcessMiningTaxesLedgersJob.php', 'App\\Jobs\\Commands\\MiningTaxes\\ProcessMiningTaxesPaymentsJob' => $baseDir . '/app/Jobs/Commands/MiningTaxes/ProcessMiningTaxesPaymentsJob.php', + 'App\\Jobs\\Commands\\MiningTaxes\\SendMiningTaxesInvoicesJob' => $baseDir . '/app/Jobs/Commands/MiningTaxes/SendMiningTaxesInvoicesJob.php', 'App\\Jobs\\Commands\\SupplyChain\\EndSupplyChainContractJob' => $baseDir . '/app/Jobs/Commands/SupplyChain/EndSupplyChainContractJob.php', 'App\\Library\\Esi\\Esi' => $baseDir . '/app/Library/Esi/Esi.php', 'App\\Library\\Helpers\\AssetHelper' => $baseDir . '/app/Library/Helpers/AssetHelper.php', @@ -65,6 +72,8 @@ return array( 'App\\Library\\Helpers\\TaxesHelper' => $baseDir . '/app/Library/Helpers/TaxesHelper.php', 'App\\Library\\Moons\\MoonCalc' => $baseDir . '/app/Library/Moons/MoonCalc.php', 'App\\Models\\Admin\\AllowedLogin' => $baseDir . '/app/Models/Admin/AllowedLogin.php', + 'App\\Models\\AfterActionReports\\AfterActionReport' => $baseDir . '/app/Models/AfterActionReports/AfterActionReport.php', + 'App\\Models\\AfterActionReports\\AfterActionReportComment' => $baseDir . '/app/Models/AfterActionReports/AfterActionReportComment.php', 'App\\Models\\Blacklist\\BlacklistEntity' => $baseDir . '/app/Models/Blacklist/BlacklistEntity.php', 'App\\Models\\Contracts\\SupplyChainBid' => $baseDir . '/app/Models/Contracts/SupplyChainBid.php', 'App\\Models\\Contracts\\SupplyChainContract' => $baseDir . '/app/Models/Contracts/SupplyChainContract.php', @@ -2698,6 +2707,15 @@ return array( 'League\\OAuth1\\Client\\Signature\\RsaSha1Signature' => $vendorDir . '/league/oauth1-client/src/Signature/RsaSha1Signature.php', 'League\\OAuth1\\Client\\Signature\\Signature' => $vendorDir . '/league/oauth1-client/src/Signature/Signature.php', 'League\\OAuth1\\Client\\Signature\\SignatureInterface' => $vendorDir . '/league/oauth1-client/src/Signature/SignatureInterface.php', + 'Lorisleiva\\CronTranslator\\CronParsingException' => $vendorDir . '/lorisleiva/cron-translator/src/CronParsingException.php', + 'Lorisleiva\\CronTranslator\\CronTranslator' => $vendorDir . '/lorisleiva/cron-translator/src/CronTranslator.php', + 'Lorisleiva\\CronTranslator\\CronType' => $vendorDir . '/lorisleiva/cron-translator/src/CronType.php', + 'Lorisleiva\\CronTranslator\\DaysOfMonthField' => $vendorDir . '/lorisleiva/cron-translator/src/DaysOfMonthField.php', + 'Lorisleiva\\CronTranslator\\DaysOfWeekField' => $vendorDir . '/lorisleiva/cron-translator/src/DaysOfWeekField.php', + 'Lorisleiva\\CronTranslator\\Field' => $vendorDir . '/lorisleiva/cron-translator/src/Field.php', + 'Lorisleiva\\CronTranslator\\HoursField' => $vendorDir . '/lorisleiva/cron-translator/src/HoursField.php', + 'Lorisleiva\\CronTranslator\\MinutesField' => $vendorDir . '/lorisleiva/cron-translator/src/MinutesField.php', + 'Lorisleiva\\CronTranslator\\MonthsField' => $vendorDir . '/lorisleiva/cron-translator/src/MonthsField.php', 'Mockery' => $vendorDir . '/mockery/mockery/library/Mockery.php', 'Mockery\\Adapter\\Phpunit\\MockeryPHPUnitIntegration' => $vendorDir . '/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php', 'Mockery\\Adapter\\Phpunit\\MockeryPHPUnitIntegrationAssertPostConditions' => $vendorDir . '/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegrationAssertPostConditions.php', @@ -4093,6 +4111,32 @@ return array( 'SocialiteProviders\\Manager\\SocialiteWasCalled' => $vendorDir . '/socialiteproviders/manager/src/SocialiteWasCalled.php', 'SolarSystemSeeder' => $baseDir . '/database/seeds/SolarSystemSeeder.php', 'Spatie\\RateLimitedMiddleware\\RateLimited' => $vendorDir . '/spatie/laravel-rate-limited-job-middleware/src/RateLimited.php', + 'Spatie\\ScheduleMonitor\\Commands\\CleanLogCommand' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/CleanLogCommand.php', + 'Spatie\\ScheduleMonitor\\Commands\\ListCommand' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/ListCommand.php', + 'Spatie\\ScheduleMonitor\\Commands\\SyncCommand' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/SyncCommand.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\DuplicateTasksTable' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/Tables/DuplicateTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\MonitoredTasksTable' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/Tables/MonitoredTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\ReadyForMonitoringTasksTable' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/Tables/ReadyForMonitoringTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\ScheduledTasksTable' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/Tables/ScheduledTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\UnnamedTasksTable' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/Tables/UnnamedTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\VerifyCommand' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Commands/VerifyCommand.php', + 'Spatie\\ScheduleMonitor\\EventHandlers\\BackgroundCommandListener' => $vendorDir . '/spatie/laravel-schedule-monitor/src/EventHandlers/BackgroundCommandListener.php', + 'Spatie\\ScheduleMonitor\\EventHandlers\\ScheduledTaskEventSubscriber' => $vendorDir . '/spatie/laravel-schedule-monitor/src/EventHandlers/ScheduledTaskEventSubscriber.php', + 'Spatie\\ScheduleMonitor\\Jobs\\PingOhDearJob' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Jobs/PingOhDearJob.php', + 'Spatie\\ScheduleMonitor\\Models\\MonitoredScheduledTask' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTask.php', + 'Spatie\\ScheduleMonitor\\Models\\MonitoredScheduledTaskLogItem' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTaskLogItem.php', + 'Spatie\\ScheduleMonitor\\ScheduleMonitorServiceProvider' => $vendorDir . '/spatie/laravel-schedule-monitor/src/ScheduleMonitorServiceProvider.php', + 'Spatie\\ScheduleMonitor\\Support\\OhDearPayload\\OhDearPayloadFactory' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/OhDearPayloadFactory.php', + 'Spatie\\ScheduleMonitor\\Support\\OhDearPayload\\Payloads\\FailedPayload' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FailedPayload.php', + 'Spatie\\ScheduleMonitor\\Support\\OhDearPayload\\Payloads\\FinishedPayload' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FinishedPayload.php', + 'Spatie\\ScheduleMonitor\\Support\\OhDearPayload\\Payloads\\Payload' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/Payload.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\ScheduledTaskFactory' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTaskFactory.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\ScheduledTasks' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTasks.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\ClosureTask' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ClosureTask.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\CommandTask' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/CommandTask.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\JobTask' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/JobTask.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\ShellTask' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ShellTask.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\Task' => $vendorDir . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/Task.php', 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', 'Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Application.php', 'Symfony\\Component\\Console\\Color' => $vendorDir . '/symfony/console/Color.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index f7f098c50..8e154cd8a 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -38,6 +38,7 @@ return array( 'Symfony\\Component\\ErrorHandler\\' => array($vendorDir . '/symfony/error-handler'), 'Symfony\\Component\\CssSelector\\' => array($vendorDir . '/symfony/css-selector'), 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), + 'Spatie\\ScheduleMonitor\\' => array($vendorDir . '/spatie/laravel-schedule-monitor/src'), 'Spatie\\RateLimitedMiddleware\\' => array($vendorDir . '/spatie/laravel-rate-limited-job-middleware/src'), 'SocialiteProviders\\Manager\\' => array($vendorDir . '/socialiteproviders/manager/src'), 'Seat\\Eseye\\' => array($vendorDir . '/eveseat/eseye/src'), @@ -54,6 +55,7 @@ return array( 'Opis\\Closure\\' => array($vendorDir . '/opis/closure/src'), 'NunoMaduro\\Collision\\' => array($vendorDir . '/nunomaduro/collision/src'), 'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'), + 'Lorisleiva\\CronTranslator\\' => array($vendorDir . '/lorisleiva/cron-translator/src'), 'League\\OAuth1\\Client\\' => array($vendorDir . '/league/oauth1-client/src'), 'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 788ec4b8c..c5da339b2 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -25,7 +25,7 @@ class ComposerAutoloaderInitc3f953f8a7291d41a76e1664339777c9 require __DIR__ . '/platform_check.php'; spl_autoload_register(array('ComposerAutoloaderInitc3f953f8a7291d41a76e1664339777c9', 'loadClassLoader'), true, true); - self::$loader = $loader = new \Composer\Autoload\ClassLoader(); + self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); spl_autoload_unregister(array('ComposerAutoloaderInitc3f953f8a7291d41a76e1664339777c9', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 59b50d824..8a8bdfcf8 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -84,6 +84,7 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 'Symfony\\Component\\ErrorHandler\\' => 31, 'Symfony\\Component\\CssSelector\\' => 30, 'Symfony\\Component\\Console\\' => 26, + 'Spatie\\ScheduleMonitor\\' => 23, 'Spatie\\RateLimitedMiddleware\\' => 29, 'SocialiteProviders\\Manager\\' => 27, 'Seat\\Eseye\\' => 11, @@ -118,6 +119,7 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 ), 'L' => array ( + 'Lorisleiva\\CronTranslator\\' => 26, 'League\\OAuth1\\Client\\' => 21, 'League\\MimeTypeDetection\\' => 25, 'League\\Flysystem\\' => 17, @@ -319,6 +321,10 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 array ( 0 => __DIR__ . '/..' . '/symfony/console', ), + 'Spatie\\ScheduleMonitor\\' => + array ( + 0 => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src', + ), 'Spatie\\RateLimitedMiddleware\\' => array ( 0 => __DIR__ . '/..' . '/spatie/laravel-rate-limited-job-middleware/src', @@ -383,6 +389,10 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 array ( 0 => __DIR__ . '/..' . '/monolog/monolog/src/Monolog', ), + 'Lorisleiva\\CronTranslator\\' => + array ( + 0 => __DIR__ . '/..' . '/lorisleiva/cron-translator/src', + ), 'League\\OAuth1\\Client\\' => array ( 0 => __DIR__ . '/..' . '/league/oauth1-client/src', @@ -556,7 +566,9 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 'App\\Console\\Commands\\Files\\MoonFormatter' => __DIR__ . '/../..' . '/app/Console/Commands/Files/MoonFormatter.php', 'App\\Console\\Commands\\Files\\UpdateItemCompositionFromSDECommand' => __DIR__ . '/../..' . '/app/Console/Commands/Files/UpdateItemCompositionFromSDECommand.php', 'App\\Console\\Commands\\Finances\\UpdateAllianceWalletJournal' => __DIR__ . '/../..' . '/app/Console/Commands/Finances/UpdateAllianceWalletJournal.php', + 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesDataCleanup' => __DIR__ . '/../..' . '/app/Console/Commands/MiningTaxes/MiningTaxesDataCleanup.php', 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesInvoices' => __DIR__ . '/../..' . '/app/Console/Commands/MiningTaxes/MiningTaxesInvoices.php', + 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesInvoicesNew' => __DIR__ . '/../..' . '/app/Console/Commands/MiningTaxes/MiningTaxesInvoicesNew.php', 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesLedgers' => __DIR__ . '/../..' . '/app/Console/Commands/MiningTaxes/MiningTaxesLedgers.php', 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesObservers' => __DIR__ . '/../..' . '/app/Console/Commands/MiningTaxes/MiningTaxesObservers.php', 'App\\Console\\Commands\\MiningTaxes\\MiningTaxesPayments' => __DIR__ . '/../..' . '/app/Console/Commands/MiningTaxes/MiningTaxesPayments.php', @@ -571,7 +583,6 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 'App\\Http\\Controllers\\Blacklist\\BlacklistController' => __DIR__ . '/../..' . '/app/Http/Controllers/Blacklist/BlacklistController.php', 'App\\Http\\Controllers\\Contracts\\SupplyChainController' => __DIR__ . '/../..' . '/app/Http/Controllers/Contracts/SupplyChainController.php', 'App\\Http\\Controllers\\Controller' => __DIR__ . '/../..' . '/app/Http/Controllers/Controller.php', - 'App\\Http\\Controllers\\Dashboard\\AdminController' => __DIR__ . '/../..' . '/app/Http/Controllers/Dashboard/AdminController.php', 'App\\Http\\Controllers\\Dashboard\\AdminDashboardController' => __DIR__ . '/../..' . '/app/Http/Controllers/Dashboard/AdminDashboardController.php', 'App\\Http\\Controllers\\Dashboard\\DashboardController' => __DIR__ . '/../..' . '/app/Http/Controllers/Dashboard/DashboardController.php', 'App\\Http\\Controllers\\Logistics\\FuelController' => __DIR__ . '/../..' . '/app/Http/Controllers/Logistics/FuelController.php', @@ -590,10 +601,16 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 'App\\Http\\Middleware\\TrimStrings' => __DIR__ . '/../..' . '/app/Http/Middleware/TrimStrings.php', 'App\\Http\\Middleware\\TrustProxies' => __DIR__ . '/../..' . '/app/Http/Middleware/TrustProxies.php', 'App\\Http\\Middleware\\VerifyCsrfToken' => __DIR__ . '/../..' . '/app/Http/Middleware/VerifyCsrfToken.php', + 'App\\Jobs\\Commands\\Data\\PurgeUsersJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/Data/PurgeUsersJob.php', 'App\\Jobs\\Commands\\Eve\\ItemPricesUpdateJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/Eve/ItemPricesUpdateJob.php', 'App\\Jobs\\Commands\\Eve\\ProcessSendEveMailJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/Eve/ProcessSendEveMailJob.php', + 'App\\Jobs\\Commands\\Eve\\ProcessSendEveMailJobRL' => __DIR__ . '/../..' . '/app/Jobs/Commands/Eve/ProcessSendEveMailJobRL.php', + 'App\\Jobs\\Commands\\Finances\\UpdateItemPricesJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/Finances/UpdateItemPricesJob.php', 'App\\Jobs\\Commands\\MiningTaxes\\FetchMiningTaxesLedgersJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/MiningTaxes/FetchMiningTaxesLedgersJob.php', + 'App\\Jobs\\Commands\\MiningTaxes\\FetchMiningTaxesObserversJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/MiningTaxes/FetchMiningTaxesObserversJob.php', + 'App\\Jobs\\Commands\\MiningTaxes\\ProcessMiningTaxesLedgersJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/MiningTaxes/ProcessMiningTaxesLedgersJob.php', 'App\\Jobs\\Commands\\MiningTaxes\\ProcessMiningTaxesPaymentsJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/MiningTaxes/ProcessMiningTaxesPaymentsJob.php', + 'App\\Jobs\\Commands\\MiningTaxes\\SendMiningTaxesInvoicesJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/MiningTaxes/SendMiningTaxesInvoicesJob.php', 'App\\Jobs\\Commands\\SupplyChain\\EndSupplyChainContractJob' => __DIR__ . '/../..' . '/app/Jobs/Commands/SupplyChain/EndSupplyChainContractJob.php', 'App\\Library\\Esi\\Esi' => __DIR__ . '/../..' . '/app/Library/Esi/Esi.php', 'App\\Library\\Helpers\\AssetHelper' => __DIR__ . '/../..' . '/app/Library/Helpers/AssetHelper.php', @@ -605,6 +622,8 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 'App\\Library\\Helpers\\TaxesHelper' => __DIR__ . '/../..' . '/app/Library/Helpers/TaxesHelper.php', 'App\\Library\\Moons\\MoonCalc' => __DIR__ . '/../..' . '/app/Library/Moons/MoonCalc.php', 'App\\Models\\Admin\\AllowedLogin' => __DIR__ . '/../..' . '/app/Models/Admin/AllowedLogin.php', + 'App\\Models\\AfterActionReports\\AfterActionReport' => __DIR__ . '/../..' . '/app/Models/AfterActionReports/AfterActionReport.php', + 'App\\Models\\AfterActionReports\\AfterActionReportComment' => __DIR__ . '/../..' . '/app/Models/AfterActionReports/AfterActionReportComment.php', 'App\\Models\\Blacklist\\BlacklistEntity' => __DIR__ . '/../..' . '/app/Models/Blacklist/BlacklistEntity.php', 'App\\Models\\Contracts\\SupplyChainBid' => __DIR__ . '/../..' . '/app/Models/Contracts/SupplyChainBid.php', 'App\\Models\\Contracts\\SupplyChainContract' => __DIR__ . '/../..' . '/app/Models/Contracts/SupplyChainContract.php', @@ -3238,6 +3257,15 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 'League\\OAuth1\\Client\\Signature\\RsaSha1Signature' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/RsaSha1Signature.php', 'League\\OAuth1\\Client\\Signature\\Signature' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/Signature.php', 'League\\OAuth1\\Client\\Signature\\SignatureInterface' => __DIR__ . '/..' . '/league/oauth1-client/src/Signature/SignatureInterface.php', + 'Lorisleiva\\CronTranslator\\CronParsingException' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/CronParsingException.php', + 'Lorisleiva\\CronTranslator\\CronTranslator' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/CronTranslator.php', + 'Lorisleiva\\CronTranslator\\CronType' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/CronType.php', + 'Lorisleiva\\CronTranslator\\DaysOfMonthField' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/DaysOfMonthField.php', + 'Lorisleiva\\CronTranslator\\DaysOfWeekField' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/DaysOfWeekField.php', + 'Lorisleiva\\CronTranslator\\Field' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/Field.php', + 'Lorisleiva\\CronTranslator\\HoursField' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/HoursField.php', + 'Lorisleiva\\CronTranslator\\MinutesField' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/MinutesField.php', + 'Lorisleiva\\CronTranslator\\MonthsField' => __DIR__ . '/..' . '/lorisleiva/cron-translator/src/MonthsField.php', 'Mockery' => __DIR__ . '/..' . '/mockery/mockery/library/Mockery.php', 'Mockery\\Adapter\\Phpunit\\MockeryPHPUnitIntegration' => __DIR__ . '/..' . '/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegration.php', 'Mockery\\Adapter\\Phpunit\\MockeryPHPUnitIntegrationAssertPostConditions' => __DIR__ . '/..' . '/mockery/mockery/library/Mockery/Adapter/Phpunit/MockeryPHPUnitIntegrationAssertPostConditions.php', @@ -4633,6 +4661,32 @@ class ComposerStaticInitc3f953f8a7291d41a76e1664339777c9 'SocialiteProviders\\Manager\\SocialiteWasCalled' => __DIR__ . '/..' . '/socialiteproviders/manager/src/SocialiteWasCalled.php', 'SolarSystemSeeder' => __DIR__ . '/../..' . '/database/seeds/SolarSystemSeeder.php', 'Spatie\\RateLimitedMiddleware\\RateLimited' => __DIR__ . '/..' . '/spatie/laravel-rate-limited-job-middleware/src/RateLimited.php', + 'Spatie\\ScheduleMonitor\\Commands\\CleanLogCommand' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/CleanLogCommand.php', + 'Spatie\\ScheduleMonitor\\Commands\\ListCommand' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/ListCommand.php', + 'Spatie\\ScheduleMonitor\\Commands\\SyncCommand' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/SyncCommand.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\DuplicateTasksTable' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/Tables/DuplicateTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\MonitoredTasksTable' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/Tables/MonitoredTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\ReadyForMonitoringTasksTable' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/Tables/ReadyForMonitoringTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\ScheduledTasksTable' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/Tables/ScheduledTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\Tables\\UnnamedTasksTable' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/Tables/UnnamedTasksTable.php', + 'Spatie\\ScheduleMonitor\\Commands\\VerifyCommand' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Commands/VerifyCommand.php', + 'Spatie\\ScheduleMonitor\\EventHandlers\\BackgroundCommandListener' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/EventHandlers/BackgroundCommandListener.php', + 'Spatie\\ScheduleMonitor\\EventHandlers\\ScheduledTaskEventSubscriber' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/EventHandlers/ScheduledTaskEventSubscriber.php', + 'Spatie\\ScheduleMonitor\\Jobs\\PingOhDearJob' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Jobs/PingOhDearJob.php', + 'Spatie\\ScheduleMonitor\\Models\\MonitoredScheduledTask' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTask.php', + 'Spatie\\ScheduleMonitor\\Models\\MonitoredScheduledTaskLogItem' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTaskLogItem.php', + 'Spatie\\ScheduleMonitor\\ScheduleMonitorServiceProvider' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/ScheduleMonitorServiceProvider.php', + 'Spatie\\ScheduleMonitor\\Support\\OhDearPayload\\OhDearPayloadFactory' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/OhDearPayloadFactory.php', + 'Spatie\\ScheduleMonitor\\Support\\OhDearPayload\\Payloads\\FailedPayload' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FailedPayload.php', + 'Spatie\\ScheduleMonitor\\Support\\OhDearPayload\\Payloads\\FinishedPayload' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FinishedPayload.php', + 'Spatie\\ScheduleMonitor\\Support\\OhDearPayload\\Payloads\\Payload' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/Payload.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\ScheduledTaskFactory' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTaskFactory.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\ScheduledTasks' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTasks.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\ClosureTask' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ClosureTask.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\CommandTask' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/CommandTask.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\JobTask' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/JobTask.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\ShellTask' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ShellTask.php', + 'Spatie\\ScheduleMonitor\\Support\\ScheduledTasks\\Tasks\\Task' => __DIR__ . '/..' . '/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/Task.php', 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', 'Symfony\\Component\\Console\\Application' => __DIR__ . '/..' . '/symfony/console/Application.php', 'Symfony\\Component\\Console\\Color' => __DIR__ . '/..' . '/symfony/console/Color.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index e20aba482..bfa982228 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -2040,6 +2040,56 @@ }, "install-path": "../league/oauth1-client" }, + { + "name": "lorisleiva/cron-translator", + "version": "v0.1.1", + "version_normalized": "0.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/lorisleiva/cron-translator.git", + "reference": "784a6f6255a4b5f45da5d89dc6ec631a14d7b011" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lorisleiva/cron-translator/zipball/784a6f6255a4b5f45da5d89dc6ec631a14d7b011", + "reference": "784a6f6255a4b5f45da5d89dc6ec631a14d7b011", + "shasum": "" + }, + "require-dev": { + "phpunit/phpunit": "^8.0" + }, + "time": "2020-03-01T14:44:47+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Lorisleiva\\CronTranslator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Loris LEIVA", + "email": "loris.leiva@gmail.com", + "homepage": "https://lorisleiva.com" + } + ], + "description": "Makes CRON expressions human-readable", + "homepage": "https://github.com/lorisleiva/cron-translator", + "keywords": [ + "cron", + "expression", + "human" + ], + "support": { + "issues": "https://github.com/lorisleiva/cron-translator/issues", + "source": "https://github.com/lorisleiva/cron-translator/tree/v0.1.1" + }, + "install-path": "../lorisleiva/cron-translator" + }, { "name": "mockery/mockery", "version": "1.4.2", @@ -4645,6 +4695,84 @@ ], "install-path": "../spatie/laravel-rate-limited-job-middleware" }, + { + "name": "spatie/laravel-schedule-monitor", + "version": "2.0.1", + "version_normalized": "2.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-schedule-monitor.git", + "reference": "4ffdaea81b5c27a119b6cbac8f4894657b8fd6d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-schedule-monitor/zipball/4ffdaea81b5c27a119b6cbac8f4894657b8fd6d9", + "reference": "4ffdaea81b5c27a119b6cbac8f4894657b8fd6d9", + "shasum": "" + }, + "require": { + "illuminate/bus": "^7.19|^8.0", + "lorisleiva/cron-translator": "^0.1.1", + "php": "^7.4" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "laravel/legacy-factories": "^1.0.4", + "ohdearapp/ohdear-php-sdk": "^3.0", + "orchestra/testbench": "^5.0|^6.0", + "phpunit/phpunit": "^9.0", + "spatie/phpunit-snapshot-assertions": "^4.2", + "spatie/test-time": "^1.2", + "vimeo/psalm": "^3.11" + }, + "suggest": { + "ohdearapp/ohdear-php-sdk": "Needed to sync your schedule with Oh Dear" + }, + "time": "2020-10-06T10:38:45+00:00", + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\ScheduleMonitor\\ScheduleMonitorServiceProvider" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Spatie\\ScheduleMonitor\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "Monitor scheduled tasks in a Laravel app", + "homepage": "https://github.com/spatie/laravel-schedule-monitor", + "keywords": [ + "laravel-schedule-monitor", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-schedule-monitor/issues", + "source": "https://github.com/spatie/laravel-schedule-monitor/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "install-path": "../spatie/laravel-schedule-monitor" + }, { "name": "spomky-labs/base64url", "version": "v2.0.4", diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 1ae30bf40..0b5df5f3c 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -6,7 +6,7 @@ 'aliases' => array ( ), - 'reference' => '4b72a59e62d368371546246a68aef55ee21c2705', + 'reference' => '40ed5dd5a576916f6561953482f68722d1ecce8f', 'name' => 'laravel/laravel', ), 'versions' => @@ -440,7 +440,7 @@ 'aliases' => array ( ), - 'reference' => '4b72a59e62d368371546246a68aef55ee21c2705', + 'reference' => '40ed5dd5a576916f6561953482f68722d1ecce8f', ), 'laravel/socialite' => array ( @@ -505,6 +505,15 @@ ), 'reference' => '159c3d2bf27568f9af87d6c3f4bb616a251eb12b', ), + 'lorisleiva/cron-translator' => + array ( + 'pretty_version' => 'v0.1.1', + 'version' => '0.1.1.0', + 'aliases' => + array ( + ), + 'reference' => '784a6f6255a4b5f45da5d89dc6ec631a14d7b011', + ), 'mockery/mockery' => array ( 'pretty_version' => '1.4.2', @@ -923,6 +932,15 @@ ), 'reference' => '7b72592e0d823e2948c413f5e661de0fd3431db5', ), + 'spatie/laravel-schedule-monitor' => + array ( + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'aliases' => + array ( + ), + 'reference' => '4ffdaea81b5c27a119b6cbac8f4894657b8fd6d9', + ), 'spomky-labs/base64url' => array ( 'pretty_version' => 'v2.0.4', diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php index 92370c5a0..580fa9609 100644 --- a/vendor/composer/platform_check.php +++ b/vendor/composer/platform_check.php @@ -4,8 +4,8 @@ $issues = array(); -if (!(PHP_VERSION_ID >= 70300)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.0". You are running ' . PHP_VERSION . '.'; +if (!(PHP_VERSION_ID >= 70400)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.'; } if ($issues) { diff --git a/vendor/lorisleiva/cron-translator/.github/workflows/tests.yml b/vendor/lorisleiva/cron-translator/.github/workflows/tests.yml new file mode 100644 index 000000000..d667097cf --- /dev/null +++ b/vendor/lorisleiva/cron-translator/.github/workflows/tests.yml @@ -0,0 +1,42 @@ +name: Tests + +on: [push] + +jobs: + phpunit73: + name: "Tests on PHP 7.3" + runs-on: ubuntu-latest + container: + image: lorisleiva/laravel-docker:7.3 + steps: + - uses: actions/checkout@v2 + - name: Validate composer.json and composer.lock + run: composer validate + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: /composer/cache/files + key: dependencies-composer-${{ hashFiles('composer.json') }} + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-suggest + - name: Run tests + run: phpunit + + phpunit74: + name: "Tests on PHP 7.4" + runs-on: ubuntu-latest + container: + image: lorisleiva/laravel-docker:7.4 + steps: + - uses: actions/checkout@v2 + - name: Validate composer.json and composer.lock + run: composer validate + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: /composer/cache/files + key: dependencies-composer-${{ hashFiles('composer.json') }} + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-suggest + - name: Run tests + run: phpunit diff --git a/vendor/lorisleiva/cron-translator/.gitignore b/vendor/lorisleiva/cron-translator/.gitignore new file mode 100644 index 000000000..b800b8c72 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/.gitignore @@ -0,0 +1,4 @@ +vendor +composer.lock +.phpunit.result.cache +build \ No newline at end of file diff --git a/vendor/lorisleiva/cron-translator/LICENSE b/vendor/lorisleiva/cron-translator/LICENSE new file mode 100644 index 000000000..fdf460a8f --- /dev/null +++ b/vendor/lorisleiva/cron-translator/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Loris Leiva + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/lorisleiva/cron-translator/README.md b/vendor/lorisleiva/cron-translator/README.md new file mode 100644 index 000000000..144eca7ec --- /dev/null +++ b/vendor/lorisleiva/cron-translator/README.md @@ -0,0 +1,31 @@ +# CRON Translator +⏰️ Makes CRON expressions human-readable + +![intro-rounded](https://user-images.githubusercontent.com/3642397/60768671-7d6c7100-a0be-11e9-8cee-8a8d2780d76f.png) + +## Installation + +```sh +composer require lorisleiva/cron-translator +``` + +## Usage + +```php +use Lorisleiva\CronTranslator\CronTranslator; + +CronTranslator::translate('* * * * *'); // => Every minute +CronTranslator::translate('30 22 * * *'); // => Every day at 10:30pm +CronTranslator::translate('0 16 * * 1'); // => Every Monday at 4:00pm +CronTranslator::translate('0 0 1 1 *'); // => Every year on January the 1st at 12:00am +CronTranslator::translate('0 0 1 * *'); // => The 1st of every month at 12:00am +CronTranslator::translate('0 * * * 1'); // => Once an hour on Mondays +CronTranslator::translate('* 1-20 * * *'); // => Every minute 20 hours a day +CronTranslator::translate('0,30 * * * *'); // => Twice an hour +CronTranslator::translate('0 1-5 * * *'); // => 5 times a day +CronTranslator::translate('0 1 1-5 * *'); // => 5 days a month at 1:00am +CronTranslator::translate('*/2 * * * *'); // => Every 2 minutes +CronTranslator::translate('* 1/3 2 * *'); // => Every minute of every 3 hours on the 2nd of every month +CronTranslator::translate('1-3/5 * * * *'); // => 3 times every 5 minutes +CronTranslator::translate('1,2 0 */2 1,2 *'); // => Twice an hour every 2 days 2 months a year at 12am +``` diff --git a/vendor/lorisleiva/cron-translator/composer.json b/vendor/lorisleiva/cron-translator/composer.json new file mode 100644 index 000000000..79fb6332e --- /dev/null +++ b/vendor/lorisleiva/cron-translator/composer.json @@ -0,0 +1,33 @@ +{ + "name": "lorisleiva/cron-translator", + "description": "Makes CRON expressions human-readable", + "keywords": [ + "cron", + "expression", + "human" + ], + "homepage": "https://github.com/lorisleiva/cron-translator", + "license": "MIT", + "authors": [ + { + "name": "Loris LEIVA", + "email": "loris.leiva@gmail.com", + "homepage": "https://lorisleiva.com" + } + ], + "require-dev": { + "phpunit/phpunit" : "^8.0" + }, + "autoload": { + "psr-4": { + "Lorisleiva\\CronTranslator\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Lorisleiva\\CronTranslator\\Tests\\": "tests" + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} \ No newline at end of file diff --git a/vendor/lorisleiva/cron-translator/phpunit.xml b/vendor/lorisleiva/cron-translator/phpunit.xml new file mode 100644 index 000000000..8ebf05d08 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/phpunit.xml @@ -0,0 +1,21 @@ + + + + + ./tests + + + + + ./src + + + \ No newline at end of file diff --git a/vendor/lorisleiva/cron-translator/src/CronParsingException.php b/vendor/lorisleiva/cron-translator/src/CronParsingException.php new file mode 100644 index 000000000..06f8c7335 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/src/CronParsingException.php @@ -0,0 +1,13 @@ + '0 0 1 1 *', + '@annually' => '0 0 1 1 *', + '@monthly' => '0 0 1 * *', + '@weekly' => '0 0 * * 0', + '@daily' => '0 0 * * *', + '@hourly' => '0 * * * *' + ]; + + public static function translate($cron) + { + if (isset(self::$extendedMap[$cron])) { + $cron = self::$extendedMap[$cron]; + } + + try { + $fields = static::parseFields($cron); + $orderedFields = static::orderFields($fields); + $fieldsAsObject = static::getFieldsAsObject($fields); + + $translations = array_map(function ($field) use ($fieldsAsObject) { + return $field->translate($fieldsAsObject); + }, $orderedFields); + + return ucfirst(implode(' ', array_filter($translations))); + } catch (\Throwable $th) { + throw new CronParsingException($cron); + } + } + + protected static function parseFields($cron) + { + $fields = explode(' ', $cron); + + return [ + new MinutesField($fields[0]), + new HoursField($fields[1]), + new DaysOfMonthField($fields[2]), + new MonthsField($fields[3]), + new DaysOfWeekField($fields[4]), + ]; + } + + protected static function orderFields($fields) + { + // Group fields by CRON types. + $onces = static::filterType($fields, 'Once'); + $everys = static::filterType($fields, 'Every'); + $incrementsAndMultiples = static::filterType($fields, 'Increment', 'Multiple'); + + // Decide whether to keep one or zero CRON type "Every". + $firstEvery = reset($everys)->position ?? PHP_INT_MIN; + $firstIncrementOrMultiple = reset($incrementsAndMultiples)->position ?? PHP_INT_MAX; + $numberOfEverysKept = $firstIncrementOrMultiple < $firstEvery ? 0 : 1; + + // Mark fields that will not be displayed as dropped. + // This allows other fields to check whether some + // information is missing and adapt their translation. + foreach (array_slice($everys, $numberOfEverysKept) as $field) { + $field->dropped = true; + } + + return array_merge( + // Place one or zero "Every" field at the beginning. + array_slice($everys, 0, $numberOfEverysKept), + + // Place all "Increment" and "Multiple" fields in the middle. + $incrementsAndMultiples, + + // Finish with the "Once" fields reversed (i.e. from months to minutes). + array_reverse($onces) + ); + } + + protected static function filterType($fields, ...$types) + { + return array_filter($fields, function ($field) use ($types) { + return $field->hasType(...$types); + }); + } + + protected static function getFieldsAsObject($fields) + { + return (object) [ + 'minute' => $fields[0], + 'hour' => $fields[1], + 'day' => $fields[2], + 'month' => $fields[3], + 'weekday' => $fields[4], + ]; + } +} diff --git a/vendor/lorisleiva/cron-translator/src/CronType.php b/vendor/lorisleiva/cron-translator/src/CronType.php new file mode 100644 index 000000000..787804adb --- /dev/null +++ b/vendor/lorisleiva/cron-translator/src/CronType.php @@ -0,0 +1,88 @@ +type = $type; + $this->value = $value; + $this->count = $count; + $this->increment = $increment; + } + + public static function every() + { + return new static('Every'); + } + + public static function increment($increment, $count = 1) + { + return new static('Increment', null, $count, $increment); + } + + public static function multiple($count) + { + return new static('Multiple', null, $count); + } + + public static function once($value) + { + return new static('Once', $value); + } + + public static function parse($expression) + { + // Parse "*". + if ($expression === '*') { + return static::every(); + } + + // Parse fixed values like "1". + if (preg_match("/^[0-9]+$/", $expression)) { + return static::once((int) $expression); + } + + // Parse multiple selected values like "1,2,5". + if (preg_match("/^[0-9]+(,[0-9]+)+$/", $expression)) { + return static::multiple(count(explode(',', $expression))); + } + + // Parse ranges of selected values like "1-5". + if (preg_match("/^([0-9]+)\-([0-9]+)$/", $expression, $matches)) { + $count = $matches[2] - $matches[1] + 1; + return $count > 1 + ? static::multiple($count) + : static::once((int) $matches[1]); + } + + // Parse incremental expressions like "*/2", "1-4/10" or "1,3/4". + if (preg_match("/(.+)\/([0-9]+)$/", $expression, $matches)) { + $range = static::parse($matches[1]); + if ($range->hasType('Once', 'Every')) { + return static::Increment($matches[2]); + } + if ($range->hasType('Multiple')) { + return static::Increment($matches[2], $range->count); + } + } + + // Unsupported expressions throw exceptions. + throw new CronParsingException($expression); + } + + public function hasType() + { + return in_array($this->type, func_get_args()); + } +} diff --git a/vendor/lorisleiva/cron-translator/src/DaysOfMonthField.php b/vendor/lorisleiva/cron-translator/src/DaysOfMonthField.php new file mode 100644 index 000000000..1eb8c736d --- /dev/null +++ b/vendor/lorisleiva/cron-translator/src/DaysOfMonthField.php @@ -0,0 +1,65 @@ +weekday->hasType('Once')) { + return "every {$fields->weekday->format()}"; + } + + return 'every day'; + } + + public function translateIncrement() + { + if ($this->count > 1) { + return "{$this->count} days out of {$this->increment}"; + } + + return "every {$this->increment} days"; + } + + public function translateMultiple() + { + return "{$this->count} days a month"; + } + + public function translateOnce($fields) + { + if ($fields->month->hasType('Once')) { + return; // MonthsField adapts to "On January the 1st". + } + + if ($fields->month->hasType('Every') && ! $fields->month->dropped) { + return; // MonthsField adapts to "The 1st of every month". + } + + if ($fields->month->hasType('Every') && $fields->month->dropped) { + return 'on the ' . $this->format() . ' of every month'; + } + + return 'on the ' . $this->format(); + } + + public function format() + { + if (in_array($this->value, [1, 21, 31])) { + return $this->value . 'st'; + } + + if (in_array($this->value, [2, 22])) { + return $this->value . 'nd'; + } + + if (in_array($this->value, [3, 23])) { + return $this->value . 'rd'; + } + + return $this->value . 'th'; + } +} diff --git a/vendor/lorisleiva/cron-translator/src/DaysOfWeekField.php b/vendor/lorisleiva/cron-translator/src/DaysOfWeekField.php new file mode 100644 index 000000000..a9b252485 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/src/DaysOfWeekField.php @@ -0,0 +1,54 @@ +count > 1) { + return "{$this->count} days of the week out of {$this->increment}"; + } + + return "every {$this->increment} days of the week"; + } + + public function translateMultiple() + { + return "{$this->count} days a week"; + } + + public function translateOnce($fields) + { + if ($fields->day->hasType('Every') && ! $fields->day->dropped) { + return; // DaysOfMonthField adapts to "Every Sunday". + } + + return "on {$this->format()}s"; + } + + public function format() + { + if ($this->value < 0 || $this->value > 7) { + throw new \Exception(); + } + + return [ + 0 => 'Sunday', + 1 => 'Monday', + 2 => 'Tuesday', + 3 => 'Wednesday', + 4 => 'Thursday', + 5 => 'Friday', + 6 => 'Saturday', + 7 => 'Sunday', + ][$this->value]; + } +} diff --git a/vendor/lorisleiva/cron-translator/src/Field.php b/vendor/lorisleiva/cron-translator/src/Field.php new file mode 100644 index 000000000..501c87010 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/src/Field.php @@ -0,0 +1,47 @@ +expression = $expression; + $cronType = CronType::parse($expression); + $this->type = $cronType->type; + $this->value = $cronType->value; + $this->count = $cronType->count; + $this->increment = $cronType->increment; + } + + public function translate($fields) + { + foreach (CronType::TYPES as $type) { + if ($this->hasType($type) && method_exists($this, "translate{$type}")) { + return $this->{"translate{$type}"}($fields); + } + } + } + + public function hasType() + { + return in_array($this->type, func_get_args()); + } + + public function times($count) + { + switch ($count) { + case 1: return 'once'; + case 2: return 'twice'; + default: return "{$count} times"; + } + } +} diff --git a/vendor/lorisleiva/cron-translator/src/HoursField.php b/vendor/lorisleiva/cron-translator/src/HoursField.php new file mode 100644 index 000000000..4d4dcead9 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/src/HoursField.php @@ -0,0 +1,61 @@ +minute->hasType('Once')) { + return 'once an hour'; + } + + return 'every hour'; + } + + public function translateIncrement($fields) + { + if ($fields->minute->hasType('Once')) { + return $this->times($this->count) . " every {$this->increment} hours"; + } + + if ($this->count > 1) { + return "{$this->count} hours out of {$this->increment}"; + } + + if ($fields->minute->hasType('Every')) { + return "of every {$this->increment} hours"; + } + + return "every {$this->increment} hours"; + } + + public function translateMultiple($fields) + { + if ($fields->minute->hasType('Once')) { + return $this->times($this->count) . " a day"; + } + + return "{$this->count} hours a day"; + } + + public function translateOnce($fields) + { + return 'at ' . $this->format( + $fields->minute->hasType('Once') ? $fields->minute : null + ); + } + + public function format($minute = null) + { + $amOrPm = $this->value < 12 ? 'am' : 'pm'; + $hour = $this->value === 0 ? 12 : $this->value; + $hour = $hour > 12 ? $hour - 12 : $hour; + + return $minute + ? "{$hour}:{$minute->format()}{$amOrPm}" + : "{$hour}{$amOrPm}"; + } +} diff --git a/vendor/lorisleiva/cron-translator/src/MinutesField.php b/vendor/lorisleiva/cron-translator/src/MinutesField.php new file mode 100644 index 000000000..995c69fc2 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/src/MinutesField.php @@ -0,0 +1,32 @@ +count > 1) { + return $this->times($this->count) . " every {$this->increment} minutes"; + } + + return "every {$this->increment} minutes"; + } + + public function translateMultiple() + { + return $this->times($this->count) . " an hour"; + } + + public function format() + { + return ($this->value < 10 ? '0' : '') . $this->value; + } +} diff --git a/vendor/lorisleiva/cron-translator/src/MonthsField.php b/vendor/lorisleiva/cron-translator/src/MonthsField.php new file mode 100644 index 000000000..4e8e28743 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/src/MonthsField.php @@ -0,0 +1,62 @@ +day->hasType('Once')) { + return 'the ' . $fields->day->format() . ' of every month'; + } + + return 'every month'; + } + + public function translateIncrement() + { + if ($this->count > 1) { + return "{$this->count} months out of {$this->increment}"; + } + + return "every {$this->increment} months"; + } + + public function translateMultiple() + { + return "{$this->count} months a year"; + } + + public function translateOnce($fields) + { + if ($fields->day->hasType('Once')) { + return "on {$this->format()} the {$fields->day->format()}"; + } + + return "on {$this->format()}"; + } + + public function format() + { + if ($this->value < 1 || $this->value > 12) { + throw new \Exception(); + } + + return [ + 1 => 'January', + 2 => 'February', + 3 => 'March', + 4 => 'April', + 5 => 'May', + 6 => 'June', + 7 => 'July', + 8 => 'August', + 9 => 'September', + 10 => 'October', + 11 => 'November', + 12 => 'December', + ][$this->value]; + } +} diff --git a/vendor/lorisleiva/cron-translator/tests/CronTranslatorTest.php b/vendor/lorisleiva/cron-translator/tests/CronTranslatorTest.php new file mode 100644 index 000000000..af94136f6 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/tests/CronTranslatorTest.php @@ -0,0 +1,142 @@ +assertCronTranslateTo('Every minute', '* * * * *'); + $this->assertCronTranslateTo('Every minute on Sundays', '* * * * 0'); + $this->assertCronTranslateTo('Every minute on January', '* * * 1 *'); + $this->assertCronTranslateTo('Every minute on Sundays on January', '* * * 1 0'); + $this->assertCronTranslateTo('Every minute on the 1st of every month', '* * 1 * *'); + $this->assertCronTranslateTo('Every minute on Sundays on the 1st of every month', '* * 1 * 0'); + $this->assertCronTranslateTo('Every minute on January the 1st', '* * 1 1 *'); + $this->assertCronTranslateTo('Every minute on Sundays on January the 1st', '* * 1 1 0'); + $this->assertCronTranslateTo('Every minute at 12am', '* 0 * * *'); + $this->assertCronTranslateTo('Every minute on Sundays at 12am', '* 0 * * 0'); + $this->assertCronTranslateTo('Every minute on January at 12am', '* 0 * 1 *'); + $this->assertCronTranslateTo('Every minute on Sundays on January at 12am', '* 0 * 1 0'); + $this->assertCronTranslateTo('Every minute on the 1st of every month at 12am', '* 0 1 * *'); + $this->assertCronTranslateTo('Every minute on Sundays on the 1st of every month at 12am', '* 0 1 * 0'); + $this->assertCronTranslateTo('Every minute on January the 1st at 12am', '* 0 1 1 *'); + $this->assertCronTranslateTo('Every minute on Sundays on January the 1st at 12am', '* 0 1 1 0'); + $this->assertCronTranslateTo('Once an hour', '0 * * * *'); + $this->assertCronTranslateTo('Once an hour on Sundays', '0 * * * 0'); + $this->assertCronTranslateTo('Once an hour on January', '0 * * 1 *'); + $this->assertCronTranslateTo('Once an hour on Sundays on January', '0 * * 1 0'); + $this->assertCronTranslateTo('Once an hour on the 1st of every month', '0 * 1 * *'); + $this->assertCronTranslateTo('Once an hour on Sundays on the 1st of every month', '0 * 1 * 0'); + $this->assertCronTranslateTo('Once an hour on January the 1st', '0 * 1 1 *'); + $this->assertCronTranslateTo('Once an hour on Sundays on January the 1st', '0 * 1 1 0'); + $this->assertCronTranslateTo('Every day at 12:00am', '0 0 * * *'); + $this->assertCronTranslateTo('Every Sunday at 12:00am', '0 0 * * 0'); + $this->assertCronTranslateTo('Every day on January at 12:00am', '0 0 * 1 *'); + $this->assertCronTranslateTo('Every Sunday on January at 12:00am', '0 0 * 1 0'); + $this->assertCronTranslateTo('The 1st of every month at 12:00am', '0 0 1 * *'); + $this->assertCronTranslateTo('The 1st of every month on Sundays at 12:00am', '0 0 1 * 0'); + $this->assertCronTranslateTo('Every year on January the 1st at 12:00am', '0 0 1 1 *'); + $this->assertCronTranslateTo('On Sundays on January the 1st at 12:00am', '0 0 1 1 0'); + + // More realistic examples. + $this->assertCronTranslateTo('Every year on January the 1st at 12:00pm', '0 12 1 1 *'); + $this->assertCronTranslateTo('Every minute on Mondays at 3pm', '* 15 * * 1'); + $this->assertCronTranslateTo('Every minute on January the 3rd', '* * 3 1 *'); + $this->assertCronTranslateTo('Every minute on Mondays on April', '* * * 4 1'); + $this->assertCronTranslateTo('On Mondays on April the 22nd at 3:10pm', '10 15 22 4 1'); + + // Paparazzi examples. + $this->assertCronTranslateTo('Every day at 10:00pm', '0 22 * * *'); + $this->assertCronTranslateTo('Every day at 9:00am', '0 9 * * *'); + $this->assertCronTranslateTo('Every Monday at 4:00pm', '0 16 * * 1'); + $this->assertCronTranslateTo('Every year on January the 1st at 12:00am', '0 0 1 1 *'); + $this->assertCronTranslateTo('The 1st of every month at 12:00am', '0 0 1 * *'); + } + + /** @test */ + public function it_translate_expressions_with_multiple() + { + $this->assertCronTranslateTo('Every minute 2 hours a day', '* 8,18 * * *'); + $this->assertCronTranslateTo('Every minute 3 hours a day', '* 8,18,20 * * *'); + $this->assertCronTranslateTo('Every minute 20 hours a day', '* 1-20 * * *'); + $this->assertCronTranslateTo('Twice an hour', '0,30 * * * *'); + $this->assertCronTranslateTo('Twice an hour 5 hours a day', '0,30 1-5 * * *'); + $this->assertCronTranslateTo('5 times a day', '0 1-5 * * *'); + $this->assertCronTranslateTo('Every minute 5 hours a day', '* 1-5 * * *'); + $this->assertCronTranslateTo('5 days a month at 1:00am', '0 1 1-5 * *'); + $this->assertCronTranslateTo('5 days a month 2 months a year at 1:00am', '0 1 1-5 5,6 *'); + $this->assertCronTranslateTo('2 months a year on the 5th at 1:00am', '0 1 5 5,6 *'); + $this->assertCronTranslateTo('The 5th of every month 4 days a week at 1:00am', '0 1 5 * 1-4'); + } + + /** @test */ + public function it_translate_expressions_with_increment() + { + $this->assertCronTranslateTo('Every 2 minutes', '*/2 * * * *'); + $this->assertCronTranslateTo('Every 2 minutes', '1/2 * * * *'); + $this->assertCronTranslateTo('Twice every 4 minutes', '1,3/4 * * * *'); + $this->assertCronTranslateTo('3 times every 5 minutes', '1-3/5 * * * *'); + $this->assertCronTranslateTo('Every 2 minutes at 2pm', '*/2 14 * * *'); + $this->assertCronTranslateTo('Once an hour every 2 days', '0 * */2 * *'); + $this->assertCronTranslateTo('Every minute every 2 days', '* * */2 * *'); + $this->assertCronTranslateTo('Once every 2 hours', '0 */2 * * *'); + $this->assertCronTranslateTo('Twice every 5 hours', '0 1,2/5 * * *'); + $this->assertCronTranslateTo('Every minute 2 hours out of 5', '* 1,2/5 * * *'); + $this->assertCronTranslateTo('Every day every 4 months at 12:00am', '0 0 * */4 *'); + } + + /** @test */ + public function it_adds_junctions_to_certain_combinations_of_cron_types() + { + $this->assertCronTranslateTo('Every minute of every 2 hours', '* */2 * * *'); + $this->assertCronTranslateTo('Every minute of every 3 hours on the 2nd of every month', '* 1/3 2 * *'); + } + + /** @test */ + public function it_converts_ranges_of_one_into_once_cron_types() + { + $this->assertCronTranslateTo('Every minute at 8am', '* 8-8 * * *'); + $this->assertCronTranslateTo('Every minute on January', '* * * 1-1 *'); + } + + /** @test */ + public function it_handles_extended_cron_syntax() + { + $this->assertCronTranslateTo('Once an hour', '@hourly'); + $this->assertCronTranslateTo('Every day at 12:00am', '@daily'); + $this->assertCronTranslateTo('Every Sunday at 12:00am', '@weekly'); + $this->assertCronTranslateTo('The 1st of every month at 12:00am', '@monthly'); + $this->assertCronTranslateTo('Every year on January the 1st at 12:00am', '@yearly'); + $this->assertCronTranslateTo('Every year on January the 1st at 12:00am', '@annually'); + } + + /** @test */ + public function it_returns_parsing_errors_when_something_goes_wrong() + { + $this->assertCronThrowsParsingError('I_AM_NOT_A_CRON_EXPRESSION'); + $this->assertCronThrowsParsingError('A * * * *'); + $this->assertCronThrowsParsingError('1,2-3 * * * *'); + $this->assertCronThrowsParsingError('1/2/3 * * * *'); + $this->assertCronThrowsParsingError('* * * 0 *'); + $this->assertCronThrowsParsingError('* * * 13 *'); + $this->assertCronThrowsParsingError('* * * * 8'); + } + + /** + * @skip + * @doesNotPerformAssertions + */ + public function result_generator() + { + $this->generateCombinationsFromMatrix([ + ['*', '0', '1,2', '*/2'], + ['*', '0', '1,2', '*/2'], + ['*', '1', '1,2', '*/2'], + ['*', '1', '1,2', '*/2'], + ['*', '0', '1,2', '*/2'], + ]); + } +} diff --git a/vendor/lorisleiva/cron-translator/tests/TestCase.php b/vendor/lorisleiva/cron-translator/tests/TestCase.php new file mode 100644 index 000000000..f079267f1 --- /dev/null +++ b/vendor/lorisleiva/cron-translator/tests/TestCase.php @@ -0,0 +1,48 @@ +assertEquals($expected, CronTranslator::translate($actual)); + } + + public function assertCronThrowsParsingError($cron) + { + try { + CronTranslator::translate($cron); + } catch (CronParsingException $expression) { + return $this->addToAssertionCount(1); + } + + $this->fail("Expected CronParsingError exception for [$cron]"); + } + + public function generateCombinationsFromMatrix($matrix) + { + function combinations($matrix, $acc = []) { + if (empty($matrix)) { + return [implode(' ', $acc)]; + } + + $current = array_shift($matrix); + $results = []; + + foreach ($current as $value) { + $results[] = combinations($matrix, array_merge($acc, [$value])); + } + + return array_merge(...$results); + } + + foreach (combinations($matrix) as $cron) { + echo "\n" . $cron . "\t=> " . CronTranslator::translate($cron); + } + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/.php_cs b/vendor/spatie/laravel-schedule-monitor/.php_cs new file mode 100644 index 000000000..1c4e7d562 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/.php_cs @@ -0,0 +1,37 @@ +notPath('bootstrap/*') + ->notPath('storage/*') + ->notPath('resources/view/mail/*') + ->in([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->name('*.php') + ->notName('*.blade.php') + ->ignoreDotFiles(true) + ->ignoreVCS(true); + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR2' => true, + 'array_syntax' => ['syntax' => 'short'], + 'ordered_imports' => ['sortAlgorithm' => 'alpha'], + 'no_unused_imports' => true, + 'not_operator_with_successor_space' => true, + 'trailing_comma_in_multiline_array' => true, + 'phpdoc_scalar' => true, + 'unary_operator_spaces' => true, + 'binary_operator_spaces' => true, + 'blank_line_before_statement' => [ + 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], + ], + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_var_without_name' => true, + 'method_argument_space' => [ + 'on_multiline' => 'ensure_fully_multiline', + 'keep_multiple_spaces_after_comma' => true, + ] + ]) + ->setFinder($finder); diff --git a/vendor/spatie/laravel-schedule-monitor/CHANGELOG.md b/vendor/spatie/laravel-schedule-monitor/CHANGELOG.md new file mode 100644 index 000000000..c0b9eb04c --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog + +All notable changes to `laravel-schedule-monitor` will be documented in this file + +## 2.0.1 - 2020-10-06 + +- report right exit code for scheduled tasks in background + +## 2.0.0 - 2020-09-29 + +- add support for timezones + +## 1.0.4 - 2020-09-08 + +- add support for Laravel 8 + +## 1.0.3 - 2020-07-14 + +- fix link config file + +## 1.0.2 - 2020-07-14 + +- add `CarbonImmutable` support (#3) + +## 1.0.1 - 2020-07-12 + +- improve output of commands + +## 1.0.0 - 2020-07-09 + +- initial release diff --git a/vendor/spatie/laravel-schedule-monitor/CONTRIBUTING.md b/vendor/spatie/laravel-schedule-monitor/CONTRIBUTING.md new file mode 100644 index 000000000..b4ae1c4a7 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +Please read and understand the contribution guide before creating an issue or pull request. + +## Etiquette + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code +held within. They make the code freely available in the hope that it will be of use to other developers. It would be +extremely unfair for them to suffer abuse or anger for their hard work. + +Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the +world that developers are civilized and selfless people. + +It's the duty of the maintainer to ensure that all submissions to the project are of sufficient +quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. + +## Viability + +When requesting or submitting new features, first consider whether it might be useful to others. Open +source projects are used by many developers, who may have entirely different needs to your own. Think about +whether or not your feature is likely to be used by other users of the project. + +## Procedure + +Before filing an issue: + +- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. +- Check to make sure your feature suggestion isn't already present within the project. +- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. +- Check the pull requests tab to ensure that the feature isn't already in progress. + +Before submitting a pull request: + +- Check the codebase to ensure that your feature doesn't already exist. +- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. + +## Requirements + +If the project maintainer has any additional requirements, you will find them listed here. + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + +**Happy coding**! diff --git a/vendor/spatie/laravel-schedule-monitor/LICENSE.md b/vendor/spatie/laravel-schedule-monitor/LICENSE.md new file mode 100644 index 000000000..b94142e7d --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Immutable + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/spatie/laravel-schedule-monitor/README.md b/vendor/spatie/laravel-schedule-monitor/README.md new file mode 100644 index 000000000..6dacb6041 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/README.md @@ -0,0 +1,282 @@ +# Monitor scheduled tasks in a Laravel app + +[![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-schedule-monitor.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-schedule-monitor) +![Tests](https://github.com/spatie/laravel-schedule-monitor/workflows/Tests/badge.svg) +[![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-schedule-monitor.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-schedule-monitor) + +This package will monitor your Laravel schedule. It will write an entry to a log table in the db each time a schedule tasks starts, end, fails or is skipped. Using the `list` command you can check when the scheduled tasks have been executed. + +![screenshot](https://github.com/spatie/laravel-schedule-monitor/blob/master/docs/list-with-failure.png) + +This package can also sync your schedule with [Oh Dear](https://ohdear.app). Oh Dear will send you a notification whenever a scheduled task doesn't run on time or fails. + +## Support us + +Learn how to create a package like this one, by watching our premium video course: + +[![Laravel Package training](https://spatie.be/github/package-training.jpg)](https://laravelpackage.training) + +We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). + +We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). + +## Installation + +You can install the package via composer: + +```bash +composer require spatie/laravel-schedule-monitor +``` + +#### Preparing the database + +You must publish and run migrations: + +```bash +php artisan vendor:publish --provider="Spatie\ScheduleMonitor\ScheduleMonitorServiceProvider" --tag="migrations" +php artisan migrate +``` + +#### Publishing the config file + +You can publish the config file with: +```bash +php artisan vendor:publish --provider="Spatie\ScheduleMonitor\ScheduleMonitorServiceProvider" --tag="config" +``` + +This is the contents of the published config file: + +```php +return [ + /* + * The schedule monitor will log each start, finish and failure of all scheduled jobs. + * After a while the `monitored_scheduled_task_log_items` might become big. + * Here you can specify the amount of days log items should be kept. + */ + 'delete_log_items_older_than_days' => 30, + + /* + * The date format used for all dates displayed on the output of commands + * provided by this package. + */ + 'date_format' => 'Y-m-d H:i:s', + + /* + * Oh Dear can notify you via Mail, Slack, SMS, web hooks, ... when a + * scheduled task does not run on time. + * + * More info: https://ohdear.app/cron-checks + */ + 'oh_dear' => [ + /* + * You can generate an API token at the Oh Dear user settings screen + * + * https://ohdear.app/user-settings/api + */ + 'api_token' => env('OH_DEAR_API_TOKEN', ''), + + /* + * The id of the site you want to sync the schedule with. + * + * You'll find this id on the settings page of a site at Oh Dear. + */ + 'site_id' => env('OH_DEAR_SITE_ID'), + + /* + * To keep scheduled jobs as short as possible, Oh Dear will be pinged + * via a queued job. Here you can specify the name of the queue you wish to use. + */ + 'queue' => env('OH_DEAR_QUEUE'), + ], +]; +``` + +#### Cleaning the database + +You must register the `schedule-monitor:clean` tasks in your console kernel. This command will clean up old records from the schedule monitor log table. + +```php +// app/Console/Kernel.php + +class Kernel extends ConsoleKernel +{ + protected function schedule(Schedule $schedule) + { + $schedule->command('schedule-monitor:sync')->dailyAt('04:56'); + $schedule->command('schedule-monitor:clean')->daily(); + } +} +``` + +#### Syncing the schedule + +Every time you deploy your application, you should execute the `schedule-monitor:sync` command + +```bash +schedule-monitor:sync +``` + +This command is responsible for syncing your schedule with the database, and optionally Oh Dear. We highly recommend adding this command to the script that deploys your production environment. + +In a non-production environment you should manually run `schedule-monitor:sync`. You can verify if everything synced correctly using `schedule-monitor:list`. + +## Usage + +To monitor your schedule you should first run `schedule-monitor:sync`. This command will take a look at your schedule and create an entry for each task in the `monitored_scheduled_tasks` table. + +![screenshot](https://github.com/spatie/laravel-schedule-monitor/blob/master/docs/sync.png) + +To view all monitored scheduled tasks, you can run `schedule-monitor:list`. This command will list all monitored scheduled tasks. It will show you when a scheduled task has last started, finished, or failed. + +![screenshot](https://github.com/spatie/laravel-schedule-monitor/blob/master/docs/list.png) + +The package will write an entry to the `monitored_scheduled_task_log_items` table in the db each time a schedule tasks starts, end, fails or is skipped. Take a look at the contest of that table if you want to know when and how scheduled tasks did execute. The log items also hold other interesting metrics like memory usage, execution time, and more. + +### Naming tasks + +Schedule monitor will try to automatically determine a name for a scheduled task. For commands this is the command name, for anonymous jobs the class name of the first argument will be used. For some tasks, like scheduled closures, a name cannot be determined automatically. + +To manually set a name of the scheduled task, you can tack on `monitorName()`. + +Here's an example. + +```php +// in app/Console/Kernel.php + +protected function schedule(Schedule $schedule) +{ + $schedule->command('your-command')->daily()->monitorName('a-custom-name'); + $schedule->call(fn () => 1 + 1)->hourly()->monitorName('addition-closure'); +} +``` + +When you change the name of task, the schedule monitor will remove all log items of the monitor with the old name, and create a new monitor using the new name of the task. + +### Setting a grace time + +When the package detects that the last run of a scheduled task did not run in time, the `schedule-monitor` list will display that task using a red background color. In this screenshot the task named `your-command` ran too late. + +![screenshot](https://github.com/spatie/laravel-schedule-monitor/blob/master/docs/list-with-failure.png) + +The package will determine that a task ran too late if it was not finished at the time it was supposed to run + the grace time. You can think of the grace time as the number of minutes that a task under normal circumstances needs to finish. By default, the package grants a grace time of 5 minutes to each task. + +You can customize the grace time by using the `graceTimeInMinutes` method on a task. In this example a grace time of 10 minutes is used for the `your-command` task. + +```php +// in app/Console/Kernel.php + +protected function schedule(Schedule $schedule) +{ + $schedule->command('your-command')->daily()->graceTimeInMinutes(10); +} +``` + +### Ignoring scheduled tasks + +You can avoid a scheduled task being monitored by tacking on `doNotMonitor` when scheduling the task. + +```php +// in app/Console/Kernel.php + +protected function schedule(Schedule $schedule) +{ + $schedule->command('your-command')->daily()->doNotMonitor(); +} +``` + +### Getting notified when a scheduled task doesn't finish in time + +This package can sync your schedule with the [Oh Dear](https://ohdear.app) cron check. Oh Dear will send you a notification whenever a scheduled task does not finish on time. + +To get started you will first need to install the Oh Dear SDK. + +```bash +composer require ohdearapp/ohdear-php-sdk +``` + +Next you, need to make sure the `api_token` and `site_id` keys of the `schedule-monitor` are filled with an API token, and an Oh Dear site id. To verify that these values hold correct values you can run this command. + +```bash +php artisan schedule-monitor:verify +``` + +![screenshot](https://github.com/spatie/laravel-schedule-monitor/blob/master/docs/verify.png) + +To sync your schedule with Oh Dear run this command: + +```bash +php artisan schedule-monitor:sync +``` + +![screenshot](https://github.com/spatie/laravel-schedule-monitor/blob/master/docs/sync-oh-dear.png) + +After that, the `list` command should show that all the scheduled tasks in your app are registered on Oh Dear. + +![screenshot](https://github.com/spatie/laravel-schedule-monitor/blob/master/docs/list-oh-dear.png) + +To keep scheduled jobs as short as possible, Oh Dear will be pinged via queued jobs. To ensure speedy delivery to Oh Dear, and to avoid false positive notifications, we highly recommend creating a dedicated queue for these jobs. You can put the name of that queue in the `queue` key of the config file. + +Oh Dear will wait for the completion of a schedule tasks for a given amount of minutes. This is called the grace time. By default, all scheduled tasks will have a grace time of 5 minutes. To customize this value, you can tack on `graceTimeInMinutes` to your scheduled tasks. + +Here's an example where Oh Dear will send a notification if the task didn't finish by 00:10. + +```php +// in app/Console/Kernel.php + +protected function schedule(Schedule $schedule) +{ + $schedule->command('your-command')->daily()->graceTimeInMinutes(10); +} +``` + +## Unsupported methods + +Currently, this package does not work for tasks that use these methods: + +- `between` +- `unlessBetween` +- `when` +- `skip` + +## Third party scheduled task monitors + +We assume that, when your scheduled tasks do not run properly, a scheduled task that sends out notifications would probably not run either. That's why this package doesn't send out notifications by itself. + +These services can notify you when scheduled tasks do not run properly: + +- [Oh Dear](https://ohdear.app) +- [thenping.me](https://thenping.me) (in closed beta) +- [Cronbox](https://cronbox.app) +- [Healthchecks.io](https://healthchecks.io) +- [Cronitor](https://cronitor.io) +- [Cronhub](https://cronhub.io/) +- [DeadMansSnitch](https://deadmanssnitch.com/) +- [CronAlarm](https://www.cronalarm.com/) +- [PushMon](https://www.pushmon.com/) + +## Testing + +``` bash +composer test +``` + +## Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Security + +If you discover any security related issues, please email freek@spatie.be instead of using the issue tracker. + +## Credits + +- [Freek Van der Herten](https://github.com/freekmurze) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/vendor/spatie/laravel-schedule-monitor/UPGRADING.md b/vendor/spatie/laravel-schedule-monitor/UPGRADING.md new file mode 100644 index 000000000..a72f82160 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/UPGRADING.md @@ -0,0 +1,5 @@ +## Upgrading + +### From v1 to v2 + +Add a column `timezone` (string, nullable) to the `monitored_scheduled_tasks` table. In existing rows you should fill to column with the timezone in your app. diff --git a/vendor/spatie/laravel-schedule-monitor/composer.json b/vendor/spatie/laravel-schedule-monitor/composer.json new file mode 100644 index 000000000..34f8f68de --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/composer.json @@ -0,0 +1,64 @@ +{ + "name": "spatie/laravel-schedule-monitor", + "description": "Monitor scheduled tasks in a Laravel app", + "keywords": [ + "spatie", + "laravel-schedule-monitor" + ], + "homepage": "https://github.com/spatie/laravel-schedule-monitor", + "license": "MIT", + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "require": { + "php": "^7.4", + "illuminate/bus": "^7.19|^8.0", + "lorisleiva/cron-translator": "^0.1.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.16", + "laravel/legacy-factories": "^1.0.4", + "ohdearapp/ohdear-php-sdk": "^3.0", + "orchestra/testbench": "^5.0|^6.0", + "phpunit/phpunit": "^9.0", + "spatie/phpunit-snapshot-assertions": "^4.2", + "spatie/test-time": "^1.2", + "vimeo/psalm": "^3.11" + }, + "suggest": { + "ohdearapp/ohdear-php-sdk": "Needed to sync your schedule with Oh Dear" + }, + "autoload": { + "psr-4": { + "Spatie\\ScheduleMonitor\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Spatie\\ScheduleMonitor\\Tests\\": "tests" + } + }, + "scripts": { + "psalm": "vendor/bin/psalm", + "test": "vendor/bin/phpunit", + "test-coverage": "vendor/bin/phpunit --coverage-html coverage", + "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes" + }, + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "Spatie\\ScheduleMonitor\\ScheduleMonitorServiceProvider" + ] + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/vendor/spatie/laravel-schedule-monitor/config/schedule-monitor.php b/vendor/spatie/laravel-schedule-monitor/config/schedule-monitor.php new file mode 100644 index 000000000..8b4852219 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/config/schedule-monitor.php @@ -0,0 +1,44 @@ + 30, + + /* + * The date format used for all dates displayed on the output of commands + * provided by this package. + */ + 'date_format' => 'Y-m-d H:i:s', + + /* + * Oh Dear can notify you via Mail, Slack, SMS, web hooks, ... when a + * scheduled task does not run on time. + * + * More info: https://ohdear.app/cron-checks + */ + 'oh_dear' => [ + /* + * You can generate an API token at the Oh Dear user settings screen + * + * https://ohdear.app/user-settings/api + */ + 'api_token' => env('OH_DEAR_API_TOKEN', ''), + + /* + * The id of the site you want to sync the schedule with. + * + * You'll find this id on the settings page of a site at Oh Dear. + */ + 'site_id' => env('OH_DEAR_SITE_ID'), + + /* + * To keep scheduled jobs as short as possible, Oh Dear will be pinged + * via a queued job. Here you can specify the name of the queue you wish to use. + */ + 'queue' => env('OH_DEAR_QUEUE'), + ], +]; diff --git a/vendor/spatie/laravel-schedule-monitor/database/migrations/create_schedule_monitor_tables.php.stub b/vendor/spatie/laravel-schedule-monitor/database/migrations/create_schedule_monitor_tables.php.stub new file mode 100644 index 000000000..4cbe4da13 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/database/migrations/create_schedule_monitor_tables.php.stub @@ -0,0 +1,50 @@ +bigIncrements('id'); + + $table->string('name'); + $table->string('type')->nullable(); + $table->string('cron_expression'); + $table->string('timezone')->nullable(); + $table->string('ping_url')->nullable(); + + $table->dateTime('last_started_at')->nullable(); + $table->dateTime('last_finished_at')->nullable(); + $table->dateTime('last_failed_at')->nullable(); + $table->dateTime('last_skipped_at')->nullable(); + + $table->dateTime('registered_on_oh_dear_at')->nullable(); + $table->dateTime('last_pinged_at')->nullable(); + $table->integer('grace_time_in_minutes'); + + $table->timestamps(); + }); + + + Schema::create('monitored_scheduled_task_log_items', function (Blueprint $table) { + $table->bigIncrements('id'); + + $table->unsignedBigInteger('monitored_scheduled_task_id'); + $table + ->foreign('monitored_scheduled_task_id', 'fk_scheduled_task_id') + ->references('id') + ->on('monitored_scheduled_tasks') + ->cascadeOnDelete(); + + $table->string('type'); + + $table->json('meta')->nullable(); + + $table->timestamps(); + }); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/psalm.xml b/vendor/spatie/laravel-schedule-monitor/psalm.xml new file mode 100644 index 000000000..4d2cb1520 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/psalm.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + diff --git a/vendor/spatie/laravel-schedule-monitor/resources/views/.gitkeep b/vendor/spatie/laravel-schedule-monitor/resources/views/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/CleanLogCommand.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/CleanLogCommand.php new file mode 100644 index 000000000..a481def4e --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/CleanLogCommand.php @@ -0,0 +1,29 @@ +comment('Deleting all log items older than ' . $cutOffInDays .' '. Str::plural('day', $cutOffInDays) . '...'); + + $cutOff = now()->subDays(config('schedule-monitor.delete_log_items_older_than_days')); + + $numberOfRecordsDeleted = MonitoredScheduledTaskLogItem::query() + ->where('created_at', '<', $cutOff->toDateTimeString()) + ->delete(); + + $this->info('Deleted ' . $numberOfRecordsDeleted . ' '. Str::plural('log item', $numberOfRecordsDeleted) . '!'); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/ListCommand.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/ListCommand.php new file mode 100644 index 000000000..4768fa305 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/ListCommand.php @@ -0,0 +1,26 @@ +render(); + (new ReadyForMonitoringTasksTable($this))->render(); + (new UnnamedTasksTable($this))->render(); + (new DuplicateTasksTable($this))->render(); + + $this->line(''); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/SyncCommand.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/SyncCommand.php new file mode 100644 index 000000000..80a14d091 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/SyncCommand.php @@ -0,0 +1,107 @@ +info('Start syncing schedule...' . PHP_EOL); + + $this + ->syncScheduledTasksWithDatabase() + ->syncMonitoredScheduledTaskWithOhDear(); + + $monitoredScheduledTasksCount = MonitoredScheduledTask::count(); + $this->info(''); + $this->info('All done! Now monitoring ' . $monitoredScheduledTasksCount . ' ' . Str::plural('scheduled task', $monitoredScheduledTasksCount) . '.'); + $this->info(''); + $this->info('Run `php artisan schedule-monitor:list` to see which jobs are now monitored.'); + } + + protected function syncScheduledTasksWithDatabase(): self + { + $this->comment('Start syncing schedule with database...'); + + $monitoredScheduledTasks = ScheduledTasks::createForSchedule() + ->uniqueTasks() + ->map(function (Task $task) { + return MonitoredScheduledTask::updateOrCreate( + ['name' => $task->name()], + [ + 'type' => $task->type(), + 'cron_expression' => $task->cronExpression(), + 'timezone' => $task->timezone(), + 'grace_time_in_minutes' => $task->graceTimeInMinutes(), + ] + ); + }); + + MonitoredScheduledTask::query() + ->whereNotIn('id', $monitoredScheduledTasks->pluck('id')) + ->delete(); + + return $this; + } + + protected function syncMonitoredScheduledTaskWithOhDear(): self + { + if (! class_exists(OhDear::class)) { + return $this; + } + + $siteId = config('schedule-monitor.oh_dear.site_id'); + + if (! $siteId) { + $this->warn('Not syncing schedule with Oh Dear because not `site_id` is not set in the `oh-dear` config file. Learn how to set this up at https://ohdear.app/TODO-add-link.'); + + return $this; + } + + $this->comment('Start syncing schedule with Oh Dear...'); + + $monitoredScheduledTasks = MonitoredScheduledTask::get(); + + $cronChecks = $monitoredScheduledTasks + ->map(function (MonitoredScheduledTask $monitoredScheduledTask) { + return [ + 'name' => $monitoredScheduledTask->name, + 'type' => 'cron', + 'cron_expression' => $monitoredScheduledTask->cron_expression, + 'grace_time_in_minutes' => $monitoredScheduledTask->grace_time_in_minutes, + 'server_timezone' => $monitoredScheduledTask->timezone, + 'description' => '', + ]; + }) + ->toArray(); + + $cronChecks = app(OhDear::class)->site($siteId)->syncCronChecks($cronChecks); + $this->comment('Successfully synced schedule with Oh Dear!'); + + collect($cronChecks) + ->each( + function (CronCheck $cronCheck) { + if (! $monitoredScheduledTask = MonitoredScheduledTask::findForCronCheck($cronCheck)) { + return; + } + + $monitoredScheduledTask->update(['ping_url' => $cronCheck->pingUrl]); + $monitoredScheduledTask->markAsRegisteredOnOhDear(); + } + ); + + return $this; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/DuplicateTasksTable.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/DuplicateTasksTable.php new file mode 100644 index 000000000..ea327ba96 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/DuplicateTasksTable.php @@ -0,0 +1,38 @@ +duplicateTasks(); + + if ($duplicateTasks->isEmpty()) { + return; + } + + $this->command->line(''); + $this->command->line('Duplicate tasks'); + $this->command->line('---------------'); + $this->command->line('These tasks could not be monitored because they have a duplicate name.'); + $this->command->line(''); + + $headers = ['Type', 'Frequency']; + $rows = $duplicateTasks->map(function (Task $task) { + return [ + 'name' => $task->name(), + 'type' => ucfirst($task->type()), + 'cron_expression' => $task->humanReadableCron(), + ]; + }); + + $this->command->table($headers, $rows); + + $this->command->line(''); + $this->command->line('To monitor these tasks you should add `->monitorName()` in the schedule to manually specify a unique name.'); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/MonitoredTasksTable.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/MonitoredTasksTable.php new file mode 100644 index 000000000..f7c157da5 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/MonitoredTasksTable.php @@ -0,0 +1,125 @@ +command->line(''); + $this->command->line('Monitored tasks'); + $this->command->line('---------------'); + + $tasks = ScheduledTasks::createForSchedule() + ->uniqueTasks() + ->filter(fn (Task $task) => $task->isBeingMonitored()); + + if ($tasks->isEmpty()) { + $this->command->line(''); + $this->command->warn('There currently are no tasks being monitored!'); + + return; + } + + $headers = [ + 'Name', + 'Type', + 'Frequency', + 'Last started at', + 'Last finished at', + 'Last failed at', + 'Next run date', + 'Grace time', + ]; + + if ($this->usingOhDear()) { + $headers = array_merge($headers, [ + 'Registered at Oh Dear', + ]); + } + + $dateFormat = config('schedule-monitor.date_format'); + + $rows = $tasks->map(function (Task $task) use ($dateFormat) { + $row = [ + 'name' => $task->name(), + 'type' => ucfirst($task->type()), + 'cron_expression' => $task->humanReadableCron(), + 'started_at' => optional($task->lastRunStartedAt())->format($dateFormat) ?? 'Did not start yet', + 'finished_at' => $this->getLastRunFinishedAt($task), + 'failed_at' => $this->getLastRunFailedAt($task), + 'next_run' => $task->nextRunAt()->format($dateFormat), + 'grace_time' => $task->graceTimeInMinutes(), + ]; + + if ($this->usingOhDear()) { + $row = array_merge($row, [ + 'registered_at_oh_dear' => $task->isBeingMonitoredAtOhDear() ? '✅' : '❌', + ]); + } + + return $row; + }); + + $this->command->table($headers, $rows); + + if ($this->usingOhDear()) { + if ($tasks->contains(fn (Task $task) => ! $task->isBeingMonitoredAtOhDear())) { + $this->command->line(''); + $this->command->line('Some tasks are not registered on Oh Dear. You will not be notified when they do not run on time.'); + $this->command->line('Run `php artisan schedule-monitor:sync` to register them and receive notifications.'); + } + } + } + + public function getLastRunFinishedAt(Task $task) + { + $dateFormat = config('schedule-monitor.date_format'); + + $formattedLastRunFinishedAt = optional($task->lastRunFinishedAt())->format($dateFormat) ?? ''; + + if ($task->lastRunFinishedTooLate()) { + $formattedLastRunFinishedAt = "{$formattedLastRunFinishedAt}"; + } + + return $formattedLastRunFinishedAt; + } + + public function getLastRunFailedAt(Task $task): string + { + if (! $lastRunFailedAt = $task->lastRunFailedAt()) { + return ''; + } + + $dateFormat = config('schedule-monitor.date_format'); + + $formattedLastFailedAt = $lastRunFailedAt->format($dateFormat); + + if ($task->lastRunFailed()) { + $formattedLastFailedAt = "{$formattedLastFailedAt}"; + } + + return $formattedLastFailedAt; + } + + protected function usingOhDear(): bool + { + if (! class_exists(OhDear::class)) { + return false; + } + + if (empty(config('schedule-monitor.oh_dear.api_token'))) { + return false; + } + + if (empty(config('schedule-monitor.oh_dear.site_id'))) { + return false; + } + + return true; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/ReadyForMonitoringTasksTable.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/ReadyForMonitoringTasksTable.php new file mode 100644 index 000000000..92e18f2b8 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/ReadyForMonitoringTasksTable.php @@ -0,0 +1,41 @@ +uniqueTasks() + ->reject(fn (Task $task) => $task->isBeingMonitored()); + + if ($tasks->isEmpty()) { + return; + } + + $this->command->line(''); + $this->command->line('Run sync to start monitoring'); + $this->command->line('----------------------------'); + $this->command->line(''); + $this->command->line('These tasks will be monitored after running `php artisan schedule-monitor:sync`'); + $this->command->line(''); + + $tasks = ScheduledTasks::createForSchedule() + ->uniqueTasks() + ->reject(fn (Task $task) => $task->isBeingMonitored()); + + $headers = ['Name', 'Type', 'Frequency']; + $rows = $tasks->map(function (Task $task) { + return [ + 'name' => $task->name(), + 'type' => ucfirst($task->type()), + 'cron_expression' => $task->humanReadableCron(), + ]; + }); + $this->command->table($headers, $rows); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/ScheduledTasksTable.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/ScheduledTasksTable.php new file mode 100644 index 000000000..2bc26ff16 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/ScheduledTasksTable.php @@ -0,0 +1,17 @@ +command = $command; + } + + abstract public function render(): void; +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/UnnamedTasksTable.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/UnnamedTasksTable.php new file mode 100644 index 000000000..f4052ed43 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/Tables/UnnamedTasksTable.php @@ -0,0 +1,38 @@ +unnamedTasks(); + + if ($unnamedTasks->isEmpty()) { + return; + } + + $this->command->line(''); + $this->command->line('Unnamed tasks'); + $this->command->line('-------------'); + $this->command->line('These tasks cannot be monitored because no name could be determined for them.'); + $this->command->line(''); + + + $headers = ['Type', 'Frequency']; + $rows = $unnamedTasks->map(function (Task $task) { + return [ + 'type' => ucfirst($task->type()), + 'cron_expression' => $task->humanReadableCron(), + ]; + }); + + $this->command->table($headers, $rows); + + $this->command->line(''); + $this->command->line('To monitor these tasks you should add `->monitorName()` in the schedule to manually specify a name.'); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Commands/VerifyCommand.php b/vendor/spatie/laravel-schedule-monitor/src/Commands/VerifyCommand.php new file mode 100644 index 000000000..afe7d0c88 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Commands/VerifyCommand.php @@ -0,0 +1,76 @@ +info('Verifying if Oh Dear is configured correctly...'); + $this->line(''); + + $this + ->verifySdkInstalled() + ->verifyApiToken($ohDearConfig) + ->verifySiteId($ohDearConfig) + ->verifyConnection($ohDearConfig); + + $this->line(''); + $this->info('All ok!'); + $this->info('Run `php artisan schedule-monitor:sync` to sync your scheduled tasks with Oh Dear.'); + } + + public function verifySdkInstalled(): self + { + if (! class_exists(OhDear::class)) { + throw new Exception("You must install the Oh Dear SDK in order to sync your schedule with Oh Dear. Run `composer require ohdearapp/ohdear-php-sdk`."); + } + + $this->comment('The Oh Dear SDK is installed.'); + + return $this; + } + + protected function verifyApiToken(array $ohDearConfig): self + { + if (empty($ohDearConfig['api_token'])) { + throw new Exception('No API token found. Make sure you added an API token to the `api_token` key of the `server-monitor` config file. You can generate a new token here: https://ohdear.app/user-settings/api'); + } + + $this->comment('Oh Dear API token found.'); + + return $this; + } + + protected function verifySiteId(array $ohDearConfig): self + { + if (empty($ohDearConfig['site_id'])) { + throw new Exception('No site id found. Make sure you added an site id to the `site_id` key of the `server-monitor` config file. You can found your site id on the settings page of a site on Oh Dear.'); + } + + $this->comment('Oh Dear site id found.'); + + return $this; + } + + protected function verifyConnection(array $ohDearConfig) + { + $this->comment('Trying to reach Oh Dear...'); + + $site = app(OhDear::class)->site($ohDearConfig['site_id']); + + $this->comment("Successfully connected to Oh Dear. The configured site URL is: {$site->sortUrl}"); + + return $this; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/EventHandlers/BackgroundCommandListener.php b/vendor/spatie/laravel-schedule-monitor/src/EventHandlers/BackgroundCommandListener.php new file mode 100644 index 000000000..df0a63dfa --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/EventHandlers/BackgroundCommandListener.php @@ -0,0 +1,39 @@ +command !== 'schedule:finish') { + return; + } + + collect(app(Schedule::class)->events()) + ->filter(fn (Event $task) => $task->runInBackground) + ->each(function (Event $task) { + $task + ->then( + function () use ($task) { + if (! $monitoredTask = MonitoredScheduledTask::findForTask($task)) { + return; + } + + $event = new ScheduledTaskFinished( + $task, + 0 + ); + + $monitoredTask->markAsFinished($event); + } + ); + }); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/EventHandlers/ScheduledTaskEventSubscriber.php b/vendor/spatie/laravel-schedule-monitor/src/EventHandlers/ScheduledTaskEventSubscriber.php new file mode 100644 index 000000000..cc61608f5 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/EventHandlers/ScheduledTaskEventSubscriber.php @@ -0,0 +1,36 @@ +listen( + ScheduledTaskStarting::class, + fn (ScheduledTaskStarting $event) => optional(MonitoredScheduledTask::findForTask($event->task))->markAsStarting($event) + ); + + $events->listen( + ScheduledTaskFinished::class, + fn (ScheduledTaskFinished $event) => optional(MonitoredScheduledTask::findForTask($event->task))->markAsFinished($event) + ); + + $events->listen( + ScheduledTaskFailed::class, + fn (ScheduledTaskFailed $event) => optional(MonitoredScheduledTask::findForTask($event->task))->markAsFailed($event) + ); + + $events->listen( + ScheduledTaskSkipped::class, + fn (ScheduledTaskSkipped $event) => optional(MonitoredScheduledTask::findForTask($event->task))->markAsSkipped($event) + ); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Jobs/PingOhDearJob.php b/vendor/spatie/laravel-schedule-monitor/src/Jobs/PingOhDearJob.php new file mode 100644 index 000000000..f9ce09ecb --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Jobs/PingOhDearJob.php @@ -0,0 +1,41 @@ +logItem = $logItem; + + if ($queue = config('schedule-monitor.oh_dear.queue')) { + $this->onQueue($queue); + } + } + + public function handle() + { + if (! $payload = OhDearPayloadFactory::createForLogItem($this->logItem)) { + return; + } + + Http::post($payload->url(), $payload->data()); + + $this->logItem->monitoredScheduledTask->update(['last_pinged_at' => now()]); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTask.php b/vendor/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTask.php new file mode 100644 index 000000000..106e540d8 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTask.php @@ -0,0 +1,178 @@ + 'datetime', + 'last_pinged_at' => 'datetime', + 'last_started_at' => 'datetime', + 'last_finished_at' => 'datetime', + 'last_skipped_at' => 'datetime', + 'last_failed_at' => 'datetime', + 'grace_time_in_minutes' => 'integer', + ]; + + public function logItems(): HasMany + { + return $this->hasMany(MonitoredScheduledTaskLogItem::class)->orderByDesc('id'); + } + + public static function findByName(string $name): ?self + { + return MonitoredScheduledTask::where('name', $name)->first(); + } + + public static function findForTask(Event $event): ?self + { + $task = ScheduledTaskFactory::createForEvent($event); + + if (empty($task->name())) { + return null; + } + + return MonitoredScheduledTask::findByName($task->name()); + } + + public static function findForCronCheck(CronCheck $cronCheck): ?self + { + return MonitoredScheduledTask::findByName($cronCheck->name); + } + + public function markAsRegisteredOnOhDear(): self + { + if (is_null($this->registered_on_oh_dear_at)) { + $this->update(['registered_on_oh_dear_at' => now()]); + } + + return $this; + } + + public function markAsStarting(ScheduledTaskStarting $event): self + { + $logItem = $this->createLogItem(MonitoredScheduledTaskLogItem::TYPE_STARTING); + + $logItem->updateMeta([ + 'memory' => memory_get_usage(true), + ]); + + $this->update([ + 'last_started_at' => now(), + ]); + + return $this; + } + + public function markAsFinished(ScheduledTaskFinished $event): self + { + if ($this->eventConcernsBackgroundTaskThatCompletedInForeground($event)) { + return $this; + } + + if ($event->task->exitCode !== 0 && ! is_null($event->task->exitCode)) { + return $this->markAsFailed($event); + } + + $logItem = $this->createLogItem(MonitoredScheduledTaskLogItem::TYPE_FINISHED); + + $logItem->updateMeta([ + 'runtime' => $event->task->runInBackground ? null : $event->runtime, + 'exit_code' => $event->task->exitCode, + 'memory' => $event->task->runInBackground ? null : memory_get_usage(true), + ]); + + $this->update(['last_finished_at' => now()]); + + $this->pingOhDear($logItem); + + return $this; + } + + public function eventConcernsBackgroundTaskThatCompletedInForeground(ScheduledTaskFinished $event): bool + { + if (! $event->task->runInBackground) { + return false; + } + + return $event->task->exitCode === null; + } + + /** + * @param ScheduledTaskFailed|ScheduledTaskFinished $event + * + * @return $this + */ + public function markAsFailed($event): self + { + $logItem = $this->createLogItem(MonitoredScheduledTaskLogItem::TYPE_FAILED); + + if ($event instanceof ScheduledTaskFailed) { + $logItem->updateMeta([ + 'failure_message' => Str::limit(optional($event->exception)->getMessage(), 255), + ]); + } + + if ($event instanceof ScheduledTaskFinished) { + $logItem->updateMeta([ + 'runtime' => $event->runtime, + 'exit_code' => $event->task->exitCode, + 'memory' => memory_get_usage(true), + ]); + } + + $this->update(['last_failed_at' => now()]); + + $this->pingOhDear($logItem); + + return $this; + } + + public function markAsSkipped(ScheduledTaskSkipped $event): self + { + $this->createLogItem(MonitoredScheduledTaskLogItem::TYPE_SKIPPED); + + $this->update(['last_skipped_at' => now()]); + + return $this; + } + + protected function pingOhDear(MonitoredScheduledTaskLogItem $logItem): self + { + if (empty($this->ping_url)) { + return $this; + } + + if (! in_array($logItem->type, [ + MonitoredScheduledTaskLogItem::TYPE_FAILED, + MonitoredScheduledTaskLogItem::TYPE_FINISHED, + ])) { + return $this; + } + + dispatch(new PingOhDearJob($logItem)); + + return $this; + } + + protected function createLogItem(string $type): MonitoredScheduledTaskLogItem + { + return $this->logItems()->create([ + 'type' => $type, + ]); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTaskLogItem.php b/vendor/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTaskLogItem.php new file mode 100644 index 000000000..1f1dacde1 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Models/MonitoredScheduledTaskLogItem.php @@ -0,0 +1,32 @@ + 'array', + ]; + + public function monitoredScheduledTask(): BelongsTo + { + return $this->belongsTo(MonitoredScheduledTask::class); + } + + public function updateMeta(array $values): self + { + $this->update(['meta' => $values]); + + return $this; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/ScheduleMonitorServiceProvider.php b/vendor/spatie/laravel-schedule-monitor/src/ScheduleMonitorServiceProvider.php new file mode 100644 index 000000000..3fb3d9580 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/ScheduleMonitorServiceProvider.php @@ -0,0 +1,108 @@ +registerPublishables() + ->registerCommands() + ->configureOhDearApi() + ->registerEventHandlers() + ->registerSchedulerEventMacros(); + } + + public function register() + { + $this->mergeConfigFrom(__DIR__.'/../config/schedule-monitor.php', 'schedule-monitor'); + } + + protected function registerPublishables(): self + { + if ($this->app->runningInConsole()) { + $this->publishes([ + __DIR__ . '/../config/schedule-monitor.php' => config_path('schedule-monitor.php'), + ], 'config'); + + if (! class_exists('CreateScheduleMonitorTables')) { + $this->publishes([ + __DIR__ . '/../database/migrations/create_schedule_monitor_tables.php.stub' => database_path('migrations/' . date('Y_m_d_His', time()) . '_create_schedule_monitor_tables.php'), + ], 'migrations'); + } + } + + return $this; + } + + protected function registerCommands(): self + { + $this->commands([ + CleanLogCommand::class, + ListCommand::class, + SyncCommand::class, + VerifyCommand::class, + ]); + + return $this; + } + + protected function configureOhDearApi(): self + { + if (! class_exists(OhDear::class)) { + return $this; + } + + $this->app->bind(OhDear::class, function () { + $apiToken = config('schedule-monitor.oh_dear.api_token'); + + return new OhDear($apiToken, 'https://ohdear.app/api/'); + }); + + return $this; + } + + protected function registerEventHandlers(): self + { + Event::subscribe(ScheduledTaskEventSubscriber::class); + Event::listen(CommandStarting::class, BackgroundCommandListener::class); + + return $this; + } + + protected function registerSchedulerEventMacros(): self + { + SchedulerEvent::macro('monitorName', function (string $monitorName) { + $this->monitorName = $monitorName; + + return $this; + }); + + SchedulerEvent::macro('graceTimeInMinutes', function (int $graceTimeInMinutes) { + $this->graceTimeInMinutes = $graceTimeInMinutes; + + return $this; + }); + + SchedulerEvent::macro('doNotMonitor', function () { + $this->doNotMonitor = true; + + return $this; + }); + + return $this; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/OhDearPayloadFactory.php b/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/OhDearPayloadFactory.php new file mode 100644 index 000000000..9a370c276 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/OhDearPayloadFactory.php @@ -0,0 +1,28 @@ +first(fn (string $payloadClass) => $payloadClass::canHandle($logItem)); + + if (! $payloadClass) { + return null; + } + + return new $payloadClass($logItem); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FailedPayload.php b/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FailedPayload.php new file mode 100644 index 000000000..97d538452 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FailedPayload.php @@ -0,0 +1,26 @@ +type === MonitoredScheduledTaskLogItem::TYPE_FAILED; + } + + public function url() + { + return "{$this->baseUrl()}/failed"; + } + + public function data(): array + { + return Arr::only($this->logItem->meta ?? [], [ + 'failure_message', + ]); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FinishedPayload.php b/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FinishedPayload.php new file mode 100644 index 000000000..00060a260 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/FinishedPayload.php @@ -0,0 +1,28 @@ +type === MonitoredScheduledTaskLogItem::TYPE_FINISHED; + } + + public function url() + { + return "{$this->baseUrl()}/finished"; + } + + public function data(): array + { + return Arr::only($this->logItem->meta ?? [], [ + 'runtime', + 'exit_code', + 'memory', + ]); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/Payload.php b/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/Payload.php new file mode 100644 index 000000000..80e485019 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/OhDearPayload/Payloads/Payload.php @@ -0,0 +1,26 @@ +logItem = $logItem; + } + + abstract public function url(); + + abstract public function data(); + + protected function baseUrl(): string + { + return $this->logItem->monitoredScheduledTask->ping_url; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTaskFactory.php b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTaskFactory.php new file mode 100644 index 000000000..3b71f20bf --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTaskFactory.php @@ -0,0 +1,26 @@ +first(fn (string $taskClass) => $taskClass::canHandleEvent($event)); + + return new $taskClass($event); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTasks.php b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTasks.php new file mode 100644 index 000000000..c88abcc67 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/ScheduledTasks.php @@ -0,0 +1,66 @@ +schedule = $schedule; + + $this->tasks = collect($this->schedule->events()) + ->map( + fn (Event $event): Task => ScheduledTaskFactory::createForEvent($event) + ); + } + + public function uniqueTasks(): Collection + { + return $this->tasks + ->filter(fn (Task $task) => $task->shouldMonitor()) + ->reject(fn (Task $task) => empty($task->name())) + ->unique(fn (Task $task) => $task->name()) + ->values(); + } + + public function duplicateTasks(): Collection + { + $uniqueTasksIds = $this->uniqueTasks() + ->map(fn (Task $task) => $task->uniqueId()) + ->toArray(); + + return $this->tasks + ->filter(fn (Task $task) => $task->shouldMonitor()) + ->reject(fn (Task $task) => empty($task->name())) + ->reject(fn (Task $task) => in_array($task->uniqueId(), $uniqueTasksIds)) + ->values(); + } + + public function unmonitoredTasks(): Collection + { + return $this->tasks->reject(fn (Task $task) => $task->shouldMonitor()); + } + + public function unnamedTasks(): Collection + { + return $this->tasks + ->filter(fn (Task $task) => empty($task->name())) + ->values(); + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ClosureTask.php b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ClosureTask.php new file mode 100644 index 000000000..86761be0c --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ClosureTask.php @@ -0,0 +1,28 @@ +getSummaryForDisplay() === 'Closure'; + } + + public function type(): string + { + return 'closure'; + } + + public function defaultName(): ?string + { + return null; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/CommandTask.php b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/CommandTask.php new file mode 100644 index 000000000..6da468058 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/CommandTask.php @@ -0,0 +1,45 @@ +command, self::artisanString()); + } + + public function defaultName(): ?string + { + return Str::after($this->event->command, self::artisanString() . ' '); + } + + public function type(): string + { + return 'command'; + } + + public static function artisanString(): string + { + $baseString = 'artisan'; + + $quote = self::isRunningWindows() + ? '"' + : "'"; + + return "{$quote}{$baseString}{$quote}"; + } + + protected static function isRunningWindows() + { + return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/JobTask.php b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/JobTask.php new file mode 100644 index 000000000..44f53d952 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/JobTask.php @@ -0,0 +1,38 @@ +command)) { + return false; + } + + if (empty($event->description)) { + return false; + } + + return class_exists($event->description); + } + + public function defaultName(): ?string + { + return $this->event->description; + } + + public function type(): string + { + return 'job'; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ShellTask.php b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ShellTask.php new file mode 100644 index 000000000..0051b052c --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/ShellTask.php @@ -0,0 +1,29 @@ +event->command, 255); + } + + public function type(): string + { + return 'shell'; + } +} diff --git a/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/Task.php b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/Task.php new file mode 100644 index 000000000..f10524642 --- /dev/null +++ b/vendor/spatie/laravel-schedule-monitor/src/Support/ScheduledTasks/Tasks/Task.php @@ -0,0 +1,172 @@ +event = $event; + + $this->uniqueId = (string)Str::uuid(); + + if (! empty($this->name())) { + $this->monitoredScheduledTask = MonitoredScheduledTask::findByName($this->name()); + } + } + + public function uniqueId(): string + { + return $this->uniqueId; + } + + public function name(): ?string + { + return $this->event->monitorName ?? $this->defaultName(); + } + + public function shouldMonitor(): bool + { + if (! isset($this->event->doNotMonitor)) { + return true; + } + + return ! $this->event->doNotMonitor; + } + + public function isBeingMonitored(): bool + { + return ! is_null($this->monitoredScheduledTask); + } + + public function isBeingMonitoredAtOhDear(): bool + { + if (! $this->isBeingMonitored()) { + return false; + } + + return ! empty($this->monitoredScheduledTask->ping_url); + } + + public function previousRunAt(): CarbonInterface + { + $dateTime = CronExpression::factory($this->cronExpression())->getPreviousRunDate(now()); + + return Date::instance($dateTime); + } + + public function nextRunAt(CarbonInterface $now = null): CarbonInterface + { + $dateTime = CronExpression::factory($this->cronExpression())->getNextRunDate( + $now ?? now(), + 0, + false, + $this->timezone() + ); + + $date = Date::instance($dateTime); + + $date->setTimezone(config('app.timezone')); + + return $date; + } + + public function lastRunStartedAt(): ?CarbonInterface + { + return optional($this->monitoredScheduledTask)->last_started_at; + } + + public function lastRunFinishedAt(): ?CarbonInterface + { + return optional($this->monitoredScheduledTask)->last_finished_at; + } + + public function lastRunFailedAt(): ?CarbonInterface + { + return optional($this->monitoredScheduledTask)->last_failed_at; + } + + public function lastRunSkippedAt(): ?CarbonInterface + { + return optional($this->monitoredScheduledTask)->last_skipped_at; + } + + public function lastRunFinishedTooLate(): bool + { + if (! $this->isBeingMonitored()) { + return false; + } + + $lastFinishedAt = $this->lastRunFinishedAt() + ? $this->lastRunFinishedAt() + : $this->monitoredScheduledTask->created_at; + + $expectedNextRunStart = $this->nextRunAt($lastFinishedAt->subSecond()); + + $shouldHaveFinishedAt = $expectedNextRunStart->addMinutes($this->graceTimeInMinutes()); + + return $shouldHaveFinishedAt->isPast(); + } + + public function lastRunFailed(): bool + { + if (! $this->isBeingMonitored()) { + return false; + } + + if (! $lastRunFailedAt = $this->lastRunFailedAt()) { + return false; + } + + if (! $lastRunStartedAt = $this->lastRunStartedAt()) { + return true; + } + + return $lastRunFailedAt->isAfter($lastRunStartedAt->subSecond()); + } + + public function graceTimeInMinutes() + { + return $this->event->graceTimeInMinutes ?? 5; + } + + public function cronExpression(): string + { + return $this->event->getExpression(); + } + + public function timezone(): string + { + return (string)$this->event->timezone; + } + + public function humanReadableCron(): string + { + try { + return CronTranslator::translate($this->cronExpression()); + } catch (CronParsingException $exception) { + return $this->cronExpression(); + } + } +}