diff --git a/.env.example b/.env.example index d3f13b3..9f4ac7a 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,7 @@ APP_DEBUG=true APP_URL=http://localhost LOG_CHANNEL=stack +LOG_LEVEL=debug BS_HOST=localhost diff --git a/.laravel-commit b/.laravel-commit index 05ff5ed..ad2be14 100644 --- a/.laravel-commit +++ b/.laravel-commit @@ -1 +1 @@ -fa43c0a333d623a393fa33c27a1376f69ef3f301 +0717bb0291a51ab63dd220ce4db8b7fa82e23787 diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 59c585d..f9644ad 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -27,29 +27,14 @@ class Handler extends ExceptionHandler ]; /** - * Report or log an exception. + * Register the exception handling callbacks for the application. * - * @param \Throwable $exception * @return void - * - * @throws \Exception */ - public function report(Throwable $exception) + public function register() { - parent::report($exception); - } - - /** - * Render an exception into an HTTP response. - * - * @param \Illuminate\Http\Request $request - * @param \Throwable $exception - * @return \Symfony\Component\HttpFoundation\Response - * - * @throws \Throwable - */ - public function render($request, Throwable $exception) - { - return parent::render($request, $exception); + $this->reportable(function (Throwable $e) { + // + }); } } diff --git a/app/Http/Controllers/Auth/RegisterController.php b/app/Http/Controllers/Auth/RegisterController.php index cfe50bf..9c40097 100644 --- a/app/Http/Controllers/Auth/RegisterController.php +++ b/app/Http/Controllers/Auth/RegisterController.php @@ -4,7 +4,7 @@ namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Providers\RouteServiceProvider; -use App\User; +use App\Models\User; use App\Dashboard; use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Support\Facades\Hash; @@ -61,7 +61,7 @@ class RegisterController extends Controller * Create a new user instance after a valid registration. * * @param array $data - * @return \App\User + * @return \App\Models\User */ protected function create(array $data) { diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 1bc76aa..0ab8be7 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -7,7 +7,7 @@ use PhpOffice\PhpSpreadsheet\Writer\Xlsx; use Auth; use File; use Image; -use App\User; +use App\Models\User; use App\Dashboard; class DashboardController extends Controller { diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 64891cb..21a8754 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -14,10 +14,10 @@ class Kernel extends HttpKernel * @var array */ protected $middleware = [ - // \App\Http\Middleware\TrustHosts::class, + \App\Http\Middleware\TrustHosts::class, \App\Http\Middleware\TrustProxies::class, \Fruitcake\Cors\HandleCors::class, - \App\Http\Middleware\CheckForMaintenanceMode::class, + \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, @@ -40,7 +40,7 @@ class Kernel extends HttpKernel ], 'api' => [ - 'throttle:120,1', + 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ]; @@ -55,7 +55,6 @@ class Kernel extends HttpKernel protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, - 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, diff --git a/app/Http/Middleware/CheckForMaintenanceMode.php b/app/Http/Middleware/PreventRequestsDuringMaintenance.php similarity index 58% rename from app/Http/Middleware/CheckForMaintenanceMode.php rename to app/Http/Middleware/PreventRequestsDuringMaintenance.php index 35b9824..e4956d0 100644 --- a/app/Http/Middleware/CheckForMaintenanceMode.php +++ b/app/Http/Middleware/PreventRequestsDuringMaintenance.php @@ -2,9 +2,9 @@ namespace App\Http\Middleware; -use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware; +use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance as Middleware; -class CheckForMaintenanceMode extends Middleware +class PreventRequestsDuringMaintenance extends Middleware { /** * The URIs that should be reachable while maintenance mode is enabled. diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index 2395ddc..362b48b 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -4,6 +4,7 @@ namespace App\Http\Middleware; use App\Providers\RouteServiceProvider; use Closure; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class RedirectIfAuthenticated @@ -13,13 +14,17 @@ class RedirectIfAuthenticated * * @param \Illuminate\Http\Request $request * @param \Closure $next - * @param string|null $guard + * @param string|null ...$guards * @return mixed */ - public function handle($request, Closure $next, $guard = null) + public function handle(Request $request, Closure $next, ...$guards) { - if (Auth::guard($guard)->check()) { - return redirect(RouteServiceProvider::HOME); + $guards = empty($guards) ? [null] : $guards; + + foreach ($guards as $guard) { + if (Auth::guard($guard)->check()) { + return redirect(RouteServiceProvider::HOME); + } } return $next($request); diff --git a/app/Models/Blog.php b/app/Models/Blog.php index 975c7e0..d305210 100644 --- a/app/Models/Blog.php +++ b/app/Models/Blog.php @@ -3,7 +3,7 @@ namespace App\Models; use Parsedown; -use App\User; +use App\Models\User; use App\Models\BlogTags; class Blog extends DashboardModel diff --git a/app/User.php b/app/Models/User.php similarity index 89% rename from app/User.php rename to app/Models/User.php index d9d74a2..888e19a 100644 --- a/app/User.php +++ b/app/Models/User.php @@ -1,8 +1,9 @@ 'App\Policies\ModelPolicy', + // 'App\Models\Model' => 'App\Policies\ModelPolicy', ]; /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 723a290..a9f10a6 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -27,8 +27,6 @@ class EventServiceProvider extends ServiceProvider */ public function boot() { - parent::boot(); - // } } diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 9e40829..ca027ea 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -2,27 +2,32 @@ namespace App\Providers; +use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\Route; class RouteServiceProvider extends ServiceProvider { - /** - * This namespace is applied to your controller routes. - * - * In addition, it is set as the URL generator's root namespace. - * - * @var string - */ - protected $namespace = 'App\Http\Controllers'; - /** * The path to the "home" route for your application. * + * This is used by Laravel authentication to redirect users after login. + * * @var string */ public const HOME = '/dashboard'; + /** + * The controller namespace for the application. + * + * When present, controller route declarations will automatically be prefixed with this namespace. + * + * @var string|null + */ + // protected $namespace = 'App\\Http\\Controllers'; + /** * Define your route model bindings, pattern filters, etc. * @@ -30,51 +35,29 @@ class RouteServiceProvider extends ServiceProvider */ public function boot() { - // + $this->configureRateLimiting(); - parent::boot(); + $this->routes(function () { + Route::prefix('api') + ->middleware('api') + ->namespace($this->namespace) + ->group(base_path('routes/api.php')); + + Route::middleware('web') + ->namespace($this->namespace) + ->group(base_path('routes/web.php')); + }); } /** - * Define the routes for the application. + * Configure the rate limiters for the application. * * @return void */ - public function map() + protected function configureRateLimiting() { - $this->mapApiRoutes(); - - $this->mapWebRoutes(); - - // - } - - /** - * Define the "web" routes for the application. - * - * These routes all receive session state, CSRF protection, etc. - * - * @return void - */ - protected function mapWebRoutes() - { - Route::middleware('web') - ->namespace($this->namespace) - ->group(base_path('routes/web.php')); - } - - /** - * Define the "api" routes for the application. - * - * These routes are typically stateless. - * - * @return void - */ - protected function mapApiRoutes() - { - Route::prefix('api') - ->middleware('api') - ->namespace($this->namespace) - ->group(base_path('routes/api.php')); + RateLimiter::for('api', function (Request $request) { + return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip()); + }); } } diff --git a/composer.json b/composer.json index ed9787e..87e62ba 100644 --- a/composer.json +++ b/composer.json @@ -8,27 +8,27 @@ ], "license": "MIT", "require": { - "php": "^7.2.5", + "php": "^7.3|^8.0", "doctrine/dbal": "^2.10", "erusev/parsedown": "^1.7", - "fideloper/proxy": "^4.2", + "fideloper/proxy": "^4.4", "fruitcake/laravel-cors": "^2.0", - "guzzlehttp/guzzle": "^6.3", + "guzzlehttp/guzzle": "^7.0.1", "intervention/image": "^2.5", - "laravel/framework": "^7.24", + "laravel/framework": "^8.12", "laravel/helpers": "^1.2", - "laravel/tinker": "^2.0", + "laravel/tinker": "^2.5", "laravel/ui": "^2.1", "phpoffice/phpspreadsheet": "^1.14", "radic/blade-extensions": "^7.4.0", "spatie/laravel-newsletter": "^4.8" }, "require-dev": { - "facade/ignition": "^2.0", - "fzaninotto/faker": "^1.9.1", - "mockery/mockery": "^1.3.1", - "nunomaduro/collision": "^4.1", - "phpunit/phpunit": "^8.5" + "facade/ignition": "^2.5", + "fakerphp/faker": "^1.9.1", + "mockery/mockery": "^1.4.2", + "nunomaduro/collision": "^5.0", + "phpunit/phpunit": "^9.3.3" }, "config": { "optimize-autoloader": true, @@ -42,12 +42,10 @@ }, "autoload": { "psr-4": { - "App\\": "app/" - }, - "classmap": [ - "database/seeds", - "database/factories" - ] + "App\\": "app/", + "Database\\Factories\\": "database/factories/", + "Database\\Seeders\\": "database/seeders/" + } }, "autoload-dev": { "psr-4": { diff --git a/config/app.php b/config/app.php index d059647..eed41d2 100644 --- a/config/app.php +++ b/config/app.php @@ -222,7 +222,7 @@ return [ 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, - 'Redis' => Illuminate\Support\Facades\Redis::class, + // 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, diff --git a/config/auth.php b/config/auth.php index aaf982b..ba1a4d8 100644 --- a/config/auth.php +++ b/config/auth.php @@ -68,7 +68,7 @@ return [ 'providers' => [ 'users' => [ 'driver' => 'eloquent', - 'model' => App\User::class, + 'model' => App\Models\User::class, ], // 'users' => [ diff --git a/config/broadcasting.php b/config/broadcasting.php index 3bba110..ef20859 100644 --- a/config/broadcasting.php +++ b/config/broadcasting.php @@ -41,6 +41,11 @@ return [ ], ], + 'ably' => [ + 'driver' => 'ably', + 'key' => env('ABLY_KEY'), + ], + 'redis' => [ 'driver' => 'redis', 'connection' => 'default', diff --git a/config/cache.php b/config/cache.php index 7e4253f..7f285ef 100644 --- a/config/cache.php +++ b/config/cache.php @@ -13,9 +13,6 @@ return [ | using this caching library. This connection is used when another is | not explicitly specified when executing a given caching function. | - | Supported: "apc", "array", "database", "file", - | "memcached", "redis", "dynamodb" - | */ 'default' => env('CACHE_DRIVER', 'file'), @@ -29,6 +26,9 @@ return [ | well as their drivers. You may even define multiple stores for the | same cache driver to group types of items stored in your caches. | + | Supported drivers: "apc", "array", "database", "file", + | "memcached", "redis", "dynamodb", "null" + | */ 'stores' => [ diff --git a/config/cors.php b/config/cors.php index 558369d..8a39e6d 100644 --- a/config/cors.php +++ b/config/cors.php @@ -15,7 +15,7 @@ return [ | */ - 'paths' => ['api/*'], + 'paths' => ['api/*', 'sanctum/csrf-cookie'], 'allowed_methods' => ['*'], diff --git a/config/filesystems.php b/config/filesystems.php index 94c8112..10c9d9b 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -15,19 +15,6 @@ return [ 'default' => env('FILESYSTEM_DRIVER', 'local'), - /* - |-------------------------------------------------------------------------- - | Default Cloud Filesystem Disk - |-------------------------------------------------------------------------- - | - | Many applications store files both locally and in the cloud. For this - | reason, you may specify a default "cloud" driver here. This driver - | will be bound as the Cloud disk implementation in the container. - | - */ - - 'cloud' => env('FILESYSTEM_CLOUD', 's3'), - /* |-------------------------------------------------------------------------- | Filesystem Disks diff --git a/config/logging.php b/config/logging.php index 088c204..6aa77fe 100644 --- a/config/logging.php +++ b/config/logging.php @@ -44,13 +44,13 @@ return [ 'single' => [ 'driver' => 'single', 'path' => storage_path('logs/laravel.log'), - 'level' => 'debug', + 'level' => env('LOG_LEVEL', 'debug'), ], 'daily' => [ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), - 'level' => 'debug', + 'level' => env('LOG_LEVEL', 'debug'), 'days' => 14, ], @@ -59,12 +59,12 @@ return [ 'url' => env('LOG_SLACK_WEBHOOK_URL'), 'username' => 'Laravel Log', 'emoji' => ':boom:', - 'level' => 'critical', + 'level' => env('LOG_LEVEL', 'critical'), ], 'papertrail' => [ 'driver' => 'monolog', - 'level' => 'debug', + 'level' => env('LOG_LEVEL', 'debug'), 'handler' => SyslogUdpHandler::class, 'handler_with' => [ 'host' => env('PAPERTRAIL_URL'), @@ -83,12 +83,12 @@ return [ 'syslog' => [ 'driver' => 'syslog', - 'level' => 'debug', + 'level' => env('LOG_LEVEL', 'debug'), ], 'errorlog' => [ 'driver' => 'errorlog', - 'level' => 'debug', + 'level' => env('LOG_LEVEL', 'debug'), ], 'null' => [ diff --git a/config/queue.php b/config/queue.php index 00b76d6..1222296 100644 --- a/config/queue.php +++ b/config/queue.php @@ -81,7 +81,7 @@ return [ */ 'failed' => [ - 'driver' => env('QUEUE_FAILED_DRIVER', 'database'), + 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), 'database' => env('DB_CONNECTION', 'mysql'), 'table' => 'failed_jobs', ], diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 741edea..bdea1a3 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -1,28 +1,33 @@ define(User::class, function (Faker $faker) { - return [ - 'name' => $faker->name, - 'email' => $faker->unique()->safeEmail, - 'email_verified_at' => now(), - 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password - 'remember_token' => Str::random(10), - ]; -}); + /** + * Define the model's default state. + * + * @return array + */ + public function definition() + { + return [ + 'name' => $this->faker->name, + 'email' => $this->faker->unique()->safeEmail, + 'email_verified_at' => now(), + 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password + 'remember_token' => Str::random(10), + ]; + } +} diff --git a/database/migrations/2019_08_19_000000_create_failed_jobs_table.php b/database/migrations/2019_08_19_000000_create_failed_jobs_table.php index 389bdf7..6aa6d74 100644 --- a/database/migrations/2019_08_19_000000_create_failed_jobs_table.php +++ b/database/migrations/2019_08_19_000000_create_failed_jobs_table.php @@ -14,7 +14,8 @@ class CreateFailedJobsTable extends Migration public function up() { Schema::create('failed_jobs', function (Blueprint $table) { - $table->bigIncrements('id'); + $table->id(); + $table->string('uuid')->unique(); $table->text('connection'); $table->text('queue'); $table->longText('payload'); diff --git a/database/seeds/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php similarity index 74% rename from database/seeds/DatabaseSeeder.php rename to database/seeders/DatabaseSeeder.php index afe3e77..a7a232c 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -1,5 +1,7 @@ create(); } } diff --git a/phpunit.xml b/phpunit.xml index 76f2246..4ae4d97 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -12,11 +12,11 @@ ./tests/Feature - - + + ./app - - + + diff --git a/public/index.php b/public/index.php index 4584cbc..a8137b1 100644 --- a/public/index.php +++ b/public/index.php @@ -1,23 +1,33 @@ - */ +use Illuminate\Contracts\Http\Kernel; +use Illuminate\Http\Request; define('LARAVEL_START', microtime(true)); +/* +|-------------------------------------------------------------------------- +| Check If Application Is Under Maintenance +|-------------------------------------------------------------------------- +| +| If the application is maintenance / demo mode via the "down" command we +| will require this file so that any prerendered template can be shown +| instead of starting the framework, which could cause an exception. +| +*/ + +if (file_exists(__DIR__.'/../storage/framework/maintenance.php')) { + require __DIR__.'/../storage/framework/maintenance.php'; +} + /* |-------------------------------------------------------------------------- | Register The Auto Loader |-------------------------------------------------------------------------- | | Composer provides a convenient, automatically generated class loader for -| our application. We just need to utilize it! We'll simply require it -| into the script here so that we don't have to worry about manual -| loading any of our classes later on. It feels great to relax. +| this application. We just need to utilize it! We'll simply require it +| into the script here so we don't need to manually load our classes. | */ @@ -25,36 +35,21 @@ require __DIR__.'/../vendor/autoload.php'; /* |-------------------------------------------------------------------------- -| Turn On The Lights +| Run The Application |-------------------------------------------------------------------------- | -| We need to illuminate PHP development, so let us turn on the lights. -| This bootstraps the framework and gets it ready for use, then it -| will load up this application so that we can run it and send -| the responses back to the browser and delight our users. +| Once we have the application, we can handle the incoming request using +| the application's HTTP kernel. Then, we will send the response back +| to this client's browser, allowing them to enjoy our application. | */ $app = require_once __DIR__.'/../bootstrap/app.php'; -/* -|-------------------------------------------------------------------------- -| Run The Application -|-------------------------------------------------------------------------- -| -| Once we have the application, we can handle the incoming request -| through the kernel, and send the associated response back to -| the client's browser allowing them to enjoy the creative -| and wonderful application we have prepared for them. -| -*/ +$kernel = $app->make(Kernel::class); -$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); - -$response = $kernel->handle( - $request = Illuminate\Http\Request::capture() -); - -$response->send(); +$response = tap($kernel->handle( + $request = Request::capture() +))->send(); $kernel->terminate($request, $response); diff --git a/readme.md b/readme.md index 76adade..4ddb975 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ A Hypothetical website template for bootstrapping new projects. * Written and maintained by Kevin MacMartin -* Based on Laravel 7.25.0 +* Based on Laravel 8.4.4 ## Setup diff --git a/resources/css/app.css b/resources/css/app.css new file mode 100644 index 0000000..e69de29 diff --git a/resources/lang/en/auth.php b/resources/lang/en/auth.php index e5506df..6598e2c 100644 --- a/resources/lang/en/auth.php +++ b/resources/lang/en/auth.php @@ -14,6 +14,7 @@ return [ */ 'failed' => 'These credentials do not match our records.', + 'password' => 'The provided password is incorrect.', 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', ]; diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index a65914f..2e2820b 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -90,6 +90,7 @@ return [ 'string' => 'The :attribute must be at least :min characters.', 'array' => 'The :attribute must have at least :min items.', ], + 'multiple_of' => 'The :attribute must be a multiple of :value', 'not_in' => 'The selected :attribute is invalid.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', diff --git a/resources/views/dashboard/pages/settings.blade.php b/resources/views/dashboard/pages/settings.blade.php index 7e424d5..e9ce98e 100644 --- a/resources/views/dashboard/pages/settings.blade.php +++ b/resources/views/dashboard/pages/settings.blade.php @@ -11,7 +11,7 @@