From bebbfec51088c2b993016b818f25dba3c602ee07 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Fri, 9 Jun 2023 18:31:53 +0100 Subject: [PATCH 001/481] chore: Refactor configuration files based on Laravel 10 skeleton --- .editorconfig | 9 --- .gitattributes | 14 +++- .gitignore | 23 +++--- .styleci.yml | 17 ++-- app/Console/Kernel.php | 14 +--- app/Http/Controllers/Controller.php | 5 +- app/Http/Controllers/FeedsController.php | 4 +- .../Controllers/TokenEndpointController.php | 2 +- app/Http/Kernel.php | 7 +- app/Http/Middleware/ActivityStreamLinks.php | 28 ------- app/Http/Middleware/ValidateSignature.php | 22 +++++ app/Jobs/SendWebMentions.php | 2 +- app/Models/Note.php | 2 +- app/Models/Place.php | 2 +- app/Providers/AuthServiceProvider.php | 3 +- app/Providers/RouteServiceProvider.php | 16 +--- composer.json | 68 ++++++++-------- config/app.php | 81 ++----------------- config/auth.php | 2 +- config/broadcasting.php | 1 + config/cache.php | 1 + config/mail.php | 1 + config/queue.php | 16 ++++ config/url.php | 36 ++++++++- phpunit.xml | 18 ++--- public/index.php | 18 ++--- public/web.config | 23 ------ resources/views/master.blade.php | 2 +- routes/api.php | 1 + routes/web.php | 22 ++--- storage/framework/.gitignore | 13 +-- tests/Feature/FeedsTest.php | 4 +- tests/Feature/ShortURLsControllerTest.php | 8 +- tests/Unit/NotesTest.php | 2 +- tests/Unit/PlacesTest.php | 2 +- 35 files changed, 205 insertions(+), 284 deletions(-) delete mode 100644 app/Http/Middleware/ActivityStreamLinks.php create mode 100644 app/Http/Middleware/ValidateSignature.php delete mode 100644 public/web.config diff --git a/.editorconfig b/.editorconfig index 0dede531..8f0de65c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,9 +1,5 @@ -# EditorConfig is awesome: http://EditorConfig.org - -# top-most EditorConfig file root = true -# Unix-style newlines with a newline ending every file [*] charset = utf-8 end_of_line = lf @@ -12,11 +8,6 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true -# Tab indentation -[Makefile] -indent_style = tab -tab_width = 4 - [*.md] trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes index 967315dd..fcb21d39 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,11 @@ -* text=auto -*.css linguist-vendored -*.scss linguist-vendored -*.js linguist-vendored +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore CHANGELOG.md export-ignore +.styleci.yml export-ignore diff --git a/.gitignore b/.gitignore index 9cf612ac..5a9b11c9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,23 @@ +/.phpunit.cache /node_modules +/public/build +/public/coverage +/public/hot +/public/files +/public/fonts +/public/storage /storage/*.key /vendor .env +.env.backup +.env.production .phpunit.result.cache Homestead.json Homestead.yaml +auth.json npm-debug.log yarn-error.log +/.fleet /.idea -/lsp -.phpstorm.meta.php -_ide_helper.php +/.vscode ray.php -# Custom paths in /public -/public/coverage -/public/hot -/public/storage -/public/fonts -/public/files -/public/keybase.txt -/public/assets/*.map diff --git a/.styleci.yml b/.styleci.yml index 0fb4a09b..9daadf16 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,8 +1,9 @@ -preset: laravel - -disabled: - - concat_without_spaces - - single_import_per_statement - -finder: - path: app/ +php: + preset: laravel + disabled: + - no_unused_imports + finder: + not-name: + - index.php +js: true +css: true diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 3ba67df6..432844ad 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -7,20 +7,8 @@ use Illuminate\Foundation\Console\Kernel as ConsoleKernel; class Kernel extends ConsoleKernel { - /** - * The Artisan commands provided by your application. - * - * @var array - */ - protected $commands = [ - Commands\ParseCachedWebMentions::class, - Commands\ReDownloadWebMentions::class, - ]; - /** * Define the application's command schedule. - * - * @codeCoverageIgnore */ protected function schedule(Schedule $schedule): void { @@ -33,7 +21,7 @@ class Kernel extends ConsoleKernel */ protected function commands(): void { - $this->load(__DIR__ . '/Commands'); + $this->load(__DIR__.'/Commands'); require base_path('routes/console.php'); } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index ce1176dd..77ec359a 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -3,13 +3,10 @@ namespace App\Http\Controllers; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; -use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; class Controller extends BaseController { - use AuthorizesRequests; - use DispatchesJobs; - use ValidatesRequests; + use AuthorizesRequests, ValidatesRequests; } diff --git a/app/Http/Controllers/FeedsController.php b/app/Http/Controllers/FeedsController.php index 01b6b3c0..3b483af8 100644 --- a/app/Http/Controllers/FeedsController.php +++ b/app/Http/Controllers/FeedsController.php @@ -152,7 +152,7 @@ class FeedsController extends Controller 'author' => [ 'type' => 'card', 'name' => config('user.displayname'), - 'url' => config('app.longurl'), + 'url' => config('url.longurl'), ], 'children' => $items, ], 200, [ @@ -188,7 +188,7 @@ class FeedsController extends Controller 'author' => [ 'type' => 'card', 'name' => config('user.displayname'), - 'url' => config('app.longurl'), + 'url' => config('url.longurl'), ], 'children' => $items, ], 200, [ diff --git a/app/Http/Controllers/TokenEndpointController.php b/app/Http/Controllers/TokenEndpointController.php index 73e86deb..c0bda71e 100644 --- a/app/Http/Controllers/TokenEndpointController.php +++ b/app/Http/Controllers/TokenEndpointController.php @@ -45,7 +45,7 @@ class TokenEndpointController extends Controller public function create(Request $request): JsonResponse { $auth = $this->verifyIndieAuthCode( - config('app.authorization_endpoint'), + config('url.authorization_endpoint'), $request->input('code'), $request->input('redirect_uri'), $request->input('client_id'), diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index d2be1cb7..3557e09c 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -33,13 +33,11 @@ class Kernel extends HttpKernel \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, - // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, \App\Http\Middleware\LinkHeadersMiddleware::class, \App\Http\Middleware\LocalhostSessionMiddleware::class, - \App\Http\Middleware\ActivityStreamLinks::class, \App\Http\Middleware\CSPHeader::class, ], @@ -53,7 +51,7 @@ class Kernel extends HttpKernel /** * The application's middleware aliases. * - * Aliases may be used to conveniently assign middleware to routes and groups. + * Aliases may be used instead of class names to conveniently assign middleware to routes and groups. * * @var array */ @@ -65,7 +63,8 @@ class Kernel extends HttpKernel 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, - 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, + 'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class, + 'signed' => \App\Http\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 'micropub.token' => \App\Http\Middleware\VerifyMicropubToken::class, diff --git a/app/Http/Middleware/ActivityStreamLinks.php b/app/Http/Middleware/ActivityStreamLinks.php deleted file mode 100644 index 47727d98..00000000 --- a/app/Http/Middleware/ActivityStreamLinks.php +++ /dev/null @@ -1,28 +0,0 @@ -path() === '/') { - $response->header('Link', '<' . config('app.url') . '>; rel="application/activity+json"', false); - } - if ($request->is('notes/*')) { - $response->header('Link', '<' . $request->url() . '>; rel="application/activity+json"', false); - } - - return $response; - } -} diff --git a/app/Http/Middleware/ValidateSignature.php b/app/Http/Middleware/ValidateSignature.php new file mode 100644 index 00000000..093bf64a --- /dev/null +++ b/app/Http/Middleware/ValidateSignature.php @@ -0,0 +1,22 @@ + + */ + protected $except = [ + // 'fbclid', + // 'utm_campaign', + // 'utm_content', + // 'utm_medium', + // 'utm_source', + // 'utm_term', + ]; +} diff --git a/app/Jobs/SendWebMentions.php b/app/Jobs/SendWebMentions.php index b481f69d..eda128a4 100644 --- a/app/Jobs/SendWebMentions.php +++ b/app/Jobs/SendWebMentions.php @@ -62,7 +62,7 @@ class SendWebMentions implements ShouldQueue public function discoverWebmentionEndpoint(string $url): ?string { // let’s not send webmentions to myself - if (parse_url($url, PHP_URL_HOST) === config('app.longurl')) { + if (parse_url($url, PHP_URL_HOST) === config('url.longurl')) { return null; } if (Str::startsWith($url, '/notes/tagged/')) { diff --git a/app/Models/Note.php b/app/Models/Note.php index a9778f0b..bbed5e62 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -179,7 +179,7 @@ class Note extends Model public function getShorturlAttribute(): string { - return config('app.shorturl') . '/notes/' . $this->nb60id; + return config('url.shorturl') . '/notes/' . $this->nb60id; } public function getIso8601Attribute(): string diff --git a/app/Models/Place.php b/app/Models/Place.php index dd8320d6..2a36aa32 100644 --- a/app/Models/Place.php +++ b/app/Models/Place.php @@ -84,7 +84,7 @@ class Place extends Model protected function shorturl(): Attribute { return Attribute::get( - get: fn ($value, $attributes) => config('app.shorturl') . '/places/' . $attributes['slug'], + get: fn ($value, $attributes) => config('url.shorturl') . '/places/' . $attributes['slug'], ); } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index faa84c0d..54756cd1 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +// use Illuminate\Support\Facades\Gate; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider @@ -12,7 +13,7 @@ class AuthServiceProvider extends ServiceProvider * @var array */ protected $policies = [ - // 'App\Models\Model' => 'App\Policies\ModelPolicy', + // ]; /** diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index caecf5f4..28da75d5 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -11,7 +11,7 @@ use Illuminate\Support\Facades\Route; class RouteServiceProvider extends ServiceProvider { /** - * The path to the "home" route for your application. + * The path to your application's "home" route. * * Typically, users are redirected here after authentication. * @@ -24,7 +24,9 @@ class RouteServiceProvider extends ServiceProvider */ public function boot(): void { - $this->configureRateLimiting(); + RateLimiter::for('api', function (Request $request) { + return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); + }); $this->routes(function () { Route::middleware('api') @@ -35,14 +37,4 @@ class RouteServiceProvider extends ServiceProvider ->group(base_path('routes/web.php')); }); } - - /** - * Configure the rate limiters for the application. - */ - protected function configureRateLimiting(): void - { - RateLimiter::for('api', function (Request $request) { - return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); - }); - } } diff --git a/composer.json b/composer.json index b2a23934..905fd1f3 100644 --- a/composer.json +++ b/composer.json @@ -1,30 +1,26 @@ { "name": "jonnybarnes/jonnybarnes.uk", "type": "project", - "description": "The code for jonnybarnes.uk, based on Laravel 8", - "keywords": [ - "framework", - "laravel", - "indieweb" - ], + "description": "The code for jonnybarnes.uk, based on Laravel 10", + "keywords": ["laravel", "framework", "indieweb"], "license": "CC0-1.0", "require": { - "php": "^8.0", + "php": "^8.1", "ext-dom": "*", "ext-intl": "*", "ext-json": "*", "cviebrock/eloquent-sluggable": "^10.0", - "guzzlehttp/guzzle": "^7.0.1", + "guzzlehttp/guzzle": "^7.2", "indieauth/client": "^1.1", "intervention/image": "^2.4", "jonnybarnes/indieweb": "~0.2", "jonnybarnes/webmentions-parser": "~0.5", "jublonet/codebird-php": "4.0.0-beta.1", - "laravel/framework": "^10.0", + "laravel/framework": "^10.10", "laravel/horizon": "^5.0", - "laravel/sanctum": "^3.0", + "laravel/sanctum": "^3.2", "laravel/scout": "^10.1", - "laravel/tinker": "^2.0", + "laravel/tinker": "^2.8", "lcobucci/jwt": "^5.0", "league/commonmark": "^2.0", "league/flysystem-aws-s3-v3": "^3.0", @@ -39,29 +35,15 @@ "beyondcode/laravel-dump-server": "^1.0", "fakerphp/faker": "^1.9.2", "laravel/dusk": "^7.0", - "laravel/pint": "^1.0.0", - "laravel/sail": "^1.15", - "mockery/mockery": "^1.0", + "laravel/pint": "^1.0", + "laravel/sail": "^1.18", + "mockery/mockery": "^1.4.4", "nunomaduro/collision": "^7.0", "phpunit/php-code-coverage": "^10.0", - "phpunit/phpunit": "^10.0", + "phpunit/phpunit": "^10.1", "spatie/laravel-ray": "^1.12", "vimeo/psalm": "^5.0" }, - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true, - "allow-plugins": { - "composer/package-versions-deprecated": false, - "composer/installers": false - } - }, - "extra": { - "laravel": { - "dont-discover": [] - } - }, "autoload": { "psr-4": { "App\\": "app/", @@ -74,24 +56,38 @@ }, "autoload-dev": { "psr-4": { - "Tests\\": "tests" + "Tests\\": "tests/" } }, - "minimum-stability": "stable", - "prefer-stable": true, "scripts": { "post-autoload-dump": [ "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "@php artisan package:discover --ansi" ], + "post-update-cmd": [ + "@php artisan vendor:publish --tag=laravel-assets --ansi --force" + ], "post-root-package-install": [ "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], "post-create-project-cmd": [ "@php artisan key:generate --ansi" - ], - "test": [ - "vendor/bin/phpunit --stop-on-failure" ] - } + }, + "extra": { + "laravel": { + "dont-discover": [] + } + }, + "config": { + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true, + "php-http/discovery": true + } + }, + "minimum-stability": "stable", + "prefer-stable": true } diff --git a/config/app.php b/config/app.php index 0c0fd785..2c80a4e3 100644 --- a/config/app.php +++ b/config/app.php @@ -1,6 +1,7 @@ env('ASSET_URL'), - /* - |-------------------------------------------------------------------------- - | Application Long URL - |-------------------------------------------------------------------------- - | - | The long URL for the application - | - */ - - 'longurl' => env('APP_LONGURL', 'longurl.local'), - - /* - |-------------------------------------------------------------------------- - | Application Short URL - |-------------------------------------------------------------------------- - | - | The short URL for the application - | - */ - - 'shorturl' => env('APP_SHORTURL', 'shorturl.local'), - - /* - |-------------------------------------------------------------------------- - | Authorization endpoint - |-------------------------------------------------------------------------- - | - | The authorization endpoint for the application, used primarily for Micropub - | - */ - - 'authorization_endpoint' => env('AUTHORIZATION_ENDPOINT', 'https://indieauth.com/auth'), - - /* - |-------------------------------------------------------------------------- - | Application Display Name - |-------------------------------------------------------------------------- - | - | The display name for the application, used for example in titles. - | - */ - - 'display_name' => env('DISPLAY_NAME', 'Joe Bloggs'), - /* |-------------------------------------------------------------------------- | Application Timezone @@ -209,34 +166,7 @@ return [ | */ - 'providers' => [ - - /* - * Laravel Framework Service Providers... - */ - Illuminate\Auth\AuthServiceProvider::class, - Illuminate\Broadcasting\BroadcastServiceProvider::class, - Illuminate\Bus\BusServiceProvider::class, - Illuminate\Cache\CacheServiceProvider::class, - Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, - Illuminate\Cookie\CookieServiceProvider::class, - Illuminate\Database\DatabaseServiceProvider::class, - Illuminate\Encryption\EncryptionServiceProvider::class, - Illuminate\Filesystem\FilesystemServiceProvider::class, - Illuminate\Foundation\Providers\FoundationServiceProvider::class, - Illuminate\Hashing\HashServiceProvider::class, - Illuminate\Mail\MailServiceProvider::class, - Illuminate\Notifications\NotificationServiceProvider::class, - Illuminate\Pagination\PaginationServiceProvider::class, - Illuminate\Pipeline\PipelineServiceProvider::class, - Illuminate\Queue\QueueServiceProvider::class, - Illuminate\Redis\RedisServiceProvider::class, - Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, - Illuminate\Session\SessionServiceProvider::class, - Illuminate\Translation\TranslationServiceProvider::class, - Illuminate\Validation\ValidationServiceProvider::class, - Illuminate\View\ViewServiceProvider::class, - + 'providers' => ServiceProvider::defaultProviders()->merge([ /* * Package Service Providers... */ @@ -248,10 +178,9 @@ return [ App\Providers\AuthServiceProvider::class, // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, - App\Providers\RouteServiceProvider::class, App\Providers\HorizonServiceProvider::class, - - ], + App\Providers\RouteServiceProvider::class, + ])->toArray(), /* |-------------------------------------------------------------------------- @@ -265,7 +194,7 @@ return [ */ 'aliases' => Facade::defaultAliases()->merge([ - // 'ExampleClass' => App\Example\ExampleClass::class, + // 'Example' => App\Facades\Example::class, ])->toArray(), ]; diff --git a/config/auth.php b/config/auth.php index cae00280..9548c15d 100644 --- a/config/auth.php +++ b/config/auth.php @@ -80,7 +80,7 @@ return [ | than one user table or model in the application and you want to have | separate password reset settings based on the specific user types. | - | The expire time is the number of minutes that each reset token will be + | The expiry time is the number of minutes that each reset token will be | considered valid. This security feature keeps tokens short-lived so | they have less time to be guessed. You may change this as needed. | diff --git a/config/broadcasting.php b/config/broadcasting.php index 9e4d4aa4..24104853 100644 --- a/config/broadcasting.php +++ b/config/broadcasting.php @@ -36,6 +36,7 @@ return [ 'secret' => env('PUSHER_APP_SECRET'), 'app_id' => env('PUSHER_APP_ID'), 'options' => [ + 'cluster' => env('PUSHER_APP_CLUSTER'), 'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com', 'port' => env('PUSHER_PORT', 443), 'scheme' => env('PUSHER_SCHEME', 'https'), diff --git a/config/cache.php b/config/cache.php index 33bb2954..d4171e22 100644 --- a/config/cache.php +++ b/config/cache.php @@ -52,6 +52,7 @@ return [ 'file' => [ 'driver' => 'file', 'path' => storage_path('framework/cache/data'), + 'lock_path' => storage_path('framework/cache/data'), ], 'memcached' => [ diff --git a/config/mail.php b/config/mail.php index 542d98c3..e652bd02 100644 --- a/config/mail.php +++ b/config/mail.php @@ -36,6 +36,7 @@ return [ 'mailers' => [ 'smtp' => [ 'transport' => 'smtp', + 'url' => env('MAIL_URL'), 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), 'port' => env('MAIL_PORT', 587), 'encryption' => env('MAIL_ENCRYPTION', 'tls'), diff --git a/config/queue.php b/config/queue.php index 25ea5a81..01c6b054 100644 --- a/config/queue.php +++ b/config/queue.php @@ -73,6 +73,22 @@ return [ ], + /* + |-------------------------------------------------------------------------- + | Job Batching + |-------------------------------------------------------------------------- + | + | The following options configure the database and table that store job + | batching information. These options can be updated to any database + | connection and table which has been defined by your application. + | + */ + + 'batching' => [ + 'database' => env('DB_CONNECTION', 'mysql'), + 'table' => 'job_batches', + ], + /* |-------------------------------------------------------------------------- | Failed Queue Jobs diff --git a/config/url.php b/config/url.php index c0fd5b48..a1962ade 100644 --- a/config/url.php +++ b/config/url.php @@ -6,6 +6,38 @@ */ return [ - 'longurl' => env('APP_LONGURL', 'jonnybarnes.uk'), - 'shorturl' => env('APP_SHORTURL', 'jmb.lv'), + + /* + |-------------------------------------------------------------------------- + | Application Long URL + |-------------------------------------------------------------------------- + | + | The long URL for the application + | + */ + + 'longurl' => env('APP_LONGURL', 'longurl.local'), + + /* + |-------------------------------------------------------------------------- + | Application Short URL + |-------------------------------------------------------------------------- + | + | The short URL for the application + | + */ + + 'shorturl' => env('APP_SHORTURL', 'shorturl.local'), + + /* + |-------------------------------------------------------------------------- + | Authorization endpoint + |-------------------------------------------------------------------------- + | + | The authorization endpoint for the application, used primarily for Micropub + | + */ + + 'authorization_endpoint' => env('AUTHORIZATION_ENDPOINT', 'https://indieauth.com/auth'), + ]; diff --git a/phpunit.xml b/phpunit.xml index 29e2843f..6a0ec00e 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -3,34 +3,30 @@ xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" - stopOnFailure="true" > - ./tests/Unit + ./tests/Unit - - ./tests/Feature + ./tests/Feature - + ./app - - - - + - + + + - diff --git a/public/index.php b/public/index.php index 0fbc0c43..1d69f3a2 100644 --- a/public/index.php +++ b/public/index.php @@ -7,17 +7,17 @@ define('LARAVEL_START', microtime(true)); /* |-------------------------------------------------------------------------- -| Check If Application Is Under Maintenance +| Check If The 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 +| If the application is in maintenance / demo mode via the "down" command +| we will load this file so that any pre-rendered content 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'; +if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) { + require $maintenance; } /* @@ -31,7 +31,7 @@ if (file_exists(__DIR__ . '/../storage/framework/maintenance.php')) { | */ -require __DIR__ . '/../vendor/autoload.php'; +require __DIR__.'/../vendor/autoload.php'; /* |-------------------------------------------------------------------------- @@ -44,12 +44,12 @@ require __DIR__ . '/../vendor/autoload.php'; | */ -$app = require_once __DIR__ . '/../bootstrap/app.php'; +$app = require_once __DIR__.'/../bootstrap/app.php'; $kernel = $app->make(Kernel::class); -$response = tap($kernel->handle( +$response = $kernel->handle( $request = Request::capture() -))->send(); +)->send(); $kernel->terminate($request, $response); diff --git a/public/web.config b/public/web.config deleted file mode 100644 index 624c1760..00000000 --- a/public/web.config +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/views/master.blade.php b/resources/views/master.blade.php index d387c93b..428ab0d0 100644 --- a/resources/views/master.blade.php +++ b/resources/views/master.blade.php @@ -21,7 +21,7 @@ - + diff --git a/routes/api.php b/routes/api.php index c9b0b965..415727bc 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,6 +1,7 @@ config('url.longurl')], function () { Route::get('/', [FrontPageController::class, 'index']); diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore index b02b700f..05c4471f 100644 --- a/storage/framework/.gitignore +++ b/storage/framework/.gitignore @@ -1,8 +1,9 @@ -config.php -routes.php -schedule-* compiled.php -services.json -events.scanned.php -routes.scanned.php +config.php down +events.scanned.php +maintenance.php +routes.php +routes.scanned.php +schedule-* +services.json diff --git a/tests/Feature/FeedsTest.php b/tests/Feature/FeedsTest.php index 6bc9cd9c..dd77bd66 100644 --- a/tests/Feature/FeedsTest.php +++ b/tests/Feature/FeedsTest.php @@ -65,7 +65,7 @@ class FeedsTest extends TestCase 'author' => [ 'type' => 'card', 'name' => config('user.displayname'), - 'url' => config('app.longurl'), + 'url' => config('url.longurl'), ], 'children' => [[ 'type' => 'entry', @@ -126,7 +126,7 @@ class FeedsTest extends TestCase 'author' => [ 'type' => 'card', 'name' => config('user.displayname'), - 'url' => config('app.longurl'), + 'url' => config('url.longurl'), ], 'children' => [[ 'type' => 'entry', diff --git a/tests/Feature/ShortURLsControllerTest.php b/tests/Feature/ShortURLsControllerTest.php index 0fbfff65..55774b91 100644 --- a/tests/Feature/ShortURLsControllerTest.php +++ b/tests/Feature/ShortURLsControllerTest.php @@ -11,28 +11,28 @@ class ShortURLsControllerTest extends TestCase /** @test */ public function shortDomainRedirectsToLongDomain(): void { - $response = $this->get('https://' . config('app.shorturl')); + $response = $this->get('https://' . config('url.shorturl')); $response->assertRedirect(config('app.url')); } /** @test */ public function shortDomainSlashAtRedirectsToTwitter(): void { - $response = $this->get('https://' . config('app.shorturl') . '/@'); + $response = $this->get('https://' . config('url.shorturl') . '/@'); $response->assertRedirect('https://twitter.com/jonnybarnes'); } /** @test */ public function shortDomainSlashTRedirectsToLongDomainSlashNotes(): void { - $response = $this->get('https://' . config('app.shorturl') . '/t/E'); + $response = $this->get('https://' . config('url.shorturl') . '/t/E'); $response->assertRedirect(config('app.url') . '/notes/E'); } /** @test */ public function shortDomainSlashBRedirectsToLongDomainSlashBlog(): void { - $response = $this->get('https://' . config('app.shorturl') . '/b/1'); + $response = $this->get('https://' . config('url.shorturl') . '/b/1'); $response->assertRedirect(config('app.url') . '/blog/s/1'); } } diff --git a/tests/Unit/NotesTest.php b/tests/Unit/NotesTest.php index 0a8d0725..990fe076 100644 --- a/tests/Unit/NotesTest.php +++ b/tests/Unit/NotesTest.php @@ -123,7 +123,7 @@ class NotesTest extends TestCase { $note = Note::factory()->make(); $note->id = 14; - $this->assertEquals(config('app.shorturl') . '/notes/E', $note->shorturl); + $this->assertEquals(config('url.shorturl') . '/notes/E', $note->shorturl); } /** @test */ diff --git a/tests/Unit/PlacesTest.php b/tests/Unit/PlacesTest.php index 192458dc..f5d73db0 100644 --- a/tests/Unit/PlacesTest.php +++ b/tests/Unit/PlacesTest.php @@ -54,7 +54,7 @@ class PlacesTest extends TestCase $place = Place::factory()->create([ 'name' => 'The Bridgewater Pub', ]); - $this->assertEquals(config('app.shorturl') . '/places/the-bridgewater-pub', $place->shorturl); + $this->assertEquals(config('url.shorturl') . '/places/the-bridgewater-pub', $place->shorturl); } /** @test */ From 3d336d5693a34801860fd7e08d58c99efce50f14 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Fri, 9 Jun 2023 19:00:57 +0100 Subject: [PATCH 002/481] chore: Add support for composer/installers package. --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 905fd1f3..fcfbf322 100644 --- a/composer.json +++ b/composer.json @@ -85,7 +85,8 @@ "sort-packages": true, "allow-plugins": { "pestphp/pest-plugin": true, - "php-http/discovery": true + "php-http/discovery": true, + "composer/installers": true } }, "minimum-stability": "stable", From 71cb15d007ffff9ca0aa5fe38df2c2b7a3fc2aa9 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Sun, 11 Jun 2023 12:52:07 +0100 Subject: [PATCH 003/481] refactor: Improve note ID validation and error handling - Improve input validation and error handling in Note model - Add test case for out-of-range note IDs in NotesController --- app/Models/Note.php | 8 ++++++++ public/assets/app.js.br | Bin 16694 -> 16618 bytes tests/Feature/NotesControllerTest.php | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/app/Models/Note.php b/app/Models/Note.php index bbed5e62..270bf58b 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -12,6 +12,7 @@ use GuzzleHttp\Client; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; @@ -286,6 +287,13 @@ class Note extends Model */ public function scopeNb60(Builder $query, string $nb60id): Builder { + $realId = resolve(Numbers::class)->b60tonum($nb60id); + + // Check nb60 does not translate to ID too big for database int4 column + if ($realId > 2_147_483_647) { + abort(404); + } + return $query->where('id', resolve(Numbers::class)->b60tonum($nb60id)); } diff --git a/public/assets/app.js.br b/public/assets/app.js.br index 961f6a0332b68f0ba0ac53e20328d3e031234540..eac06b5426ca72ff6f3a743c3ab89561721be8e5 100644 GIT binary patch literal 16618 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 Lv;HwX=41x|%A!5$ literal 16694 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 diff --git a/tests/Feature/NotesControllerTest.php b/tests/Feature/NotesControllerTest.php index ec550437..bf1c315f 100644 --- a/tests/Feature/NotesControllerTest.php +++ b/tests/Feature/NotesControllerTest.php @@ -73,4 +73,11 @@ class NotesControllerTest extends TestCase $response = $this->get('/notes/112233'); $response->assertNotFound(); } + + /** @test */ + public function checkNoteIdNotOutOfRange(): void + { + $response = $this->get('/notes/photou-photologo'); + $response->assertNotFound(); + } } From 795c25c19ce1a6596d3d46b2cb49912bf5d5697c Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Sun, 11 Jun 2023 13:05:14 +0100 Subject: [PATCH 004/481] refactor: Remove unnecessary import in Note model --- app/Models/Note.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Models/Note.php b/app/Models/Note.php index 270bf58b..99f2e193 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -12,7 +12,6 @@ use GuzzleHttp\Client; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; From 462c710295dcf0e28b659d4e9bfc5052d9a878ea Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Sun, 11 Jun 2023 16:52:37 +0100 Subject: [PATCH 005/481] fix: Use correct config variables post L10-config update Specifically the header name had disappeared. --- app/Http/Controllers/FeedsController.php | 12 ++++++------ config/user.php | 2 +- resources/views/articles/atom.blade.php | 4 ++-- resources/views/articles/rss.blade.php | 2 +- resources/views/master.blade.php | 4 ++-- resources/views/notes/atom.blade.php | 4 ++-- resources/views/notes/rss.blade.php | 2 +- tests/Feature/FeedsTest.php | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/Http/Controllers/FeedsController.php b/app/Http/Controllers/FeedsController.php index 3b483af8..d79c5e7f 100644 --- a/app/Http/Controllers/FeedsController.php +++ b/app/Http/Controllers/FeedsController.php @@ -71,7 +71,7 @@ class FeedsController extends Controller $articles = Article::where('published', '1')->latest('updated_at')->take(20)->get(); $data = [ 'version' => 'https://jsonfeed.org/version/1', - 'title' => 'The JSON Feed for ' . config('app.display_name') . '’s blog', + 'title' => 'The JSON Feed for ' . config('user.display_name') . '’s blog', 'home_page_url' => config('app.url') . '/blog', 'feed_url' => config('app.url') . '/blog/feed.json', 'items' => [], @@ -86,7 +86,7 @@ class FeedsController extends Controller 'date_published' => $article->created_at->tz('UTC')->toRfc3339String(), 'date_modified' => $article->updated_at->tz('UTC')->toRfc3339String(), 'author' => [ - 'name' => config('app.display_name'), + 'name' => config('user.display_name'), ], ]; } @@ -102,7 +102,7 @@ class FeedsController extends Controller $notes = Note::latest()->with('media')->take(20)->get(); $data = [ 'version' => 'https://jsonfeed.org/version/1', - 'title' => 'The JSON Feed for ' . config('app.display_name') . '’s notes', + 'title' => 'The JSON Feed for ' . config('user.display_name') . '’s notes', 'home_page_url' => config('app.url') . '/notes', 'feed_url' => config('app.url') . '/notes/feed.json', 'items' => [], @@ -116,7 +116,7 @@ class FeedsController extends Controller 'date_published' => $note->created_at->tz('UTC')->toRfc3339String(), 'date_modified' => $note->updated_at->tz('UTC')->toRfc3339String(), 'author' => [ - 'name' => config('app.display_name'), + 'name' => config('user.display_name'), ], ]; } @@ -151,7 +151,7 @@ class FeedsController extends Controller 'url' => url('/blog'), 'author' => [ 'type' => 'card', - 'name' => config('user.displayname'), + 'name' => config('user.display_name'), 'url' => config('url.longurl'), ], 'children' => $items, @@ -187,7 +187,7 @@ class FeedsController extends Controller 'url' => url('/notes'), 'author' => [ 'type' => 'card', - 'name' => config('user.displayname'), + 'name' => config('user.display_name'), 'url' => config('url.longurl'), ], 'children' => $items, diff --git a/config/user.php b/config/user.php index 89a7502e..39f73051 100644 --- a/config/user.php +++ b/config/user.php @@ -1,7 +1,7 @@ env('DISPLAY_NAME'), + 'display_name' => env('DISPLAY_NAME'), 'username' => env('USER_NAME'), ]; diff --git a/resources/views/articles/atom.blade.php b/resources/views/articles/atom.blade.php index 1a7e0c29..9892bcfb 100644 --- a/resources/views/articles/atom.blade.php +++ b/resources/views/articles/atom.blade.php @@ -1,6 +1,6 @@ - Atom feed for {{ config('app.display_name') }}’s blog + Atom feed for {{ config('user.display_name') }}’s blog {{ config('app.url')}}/blog {{ $articles[0]->updated_at->toAtomString() }} @@ -13,7 +13,7 @@ {{ $article->updated_at->toAtomString() }} {{ $article->main }} - {{ config('app.display_name') }} + {{ config('user.display_name') }} @endforeach diff --git a/resources/views/articles/rss.blade.php b/resources/views/articles/rss.blade.php index 7c961000..1f5f13d6 100644 --- a/resources/views/articles/rss.blade.php +++ b/resources/views/articles/rss.blade.php @@ -1,7 +1,7 @@ - {{ config('app.display_name') }} + {{ config('user.display_name') }} An RSS feed of the blog posts found on {{ config('url.longurl') }} {{ config('app.url') }}/blog diff --git a/resources/views/master.blade.php b/resources/views/master.blade.php index 428ab0d0..944627c9 100644 --- a/resources/views/master.blade.php +++ b/resources/views/master.blade.php @@ -2,7 +2,7 @@ - @yield('title'){{ config('app.display_name') }} + @yield('title'){{ config('app.name') }} @if (!empty(config('app.font_link'))) @@ -31,7 +31,7 @@ diff --git a/tests/Feature/FeedsTest.php b/tests/Feature/FeedsTest.php index 4ca49b90..481218b7 100644 --- a/tests/Feature/FeedsTest.php +++ b/tests/Feature/FeedsTest.php @@ -6,6 +6,7 @@ namespace Tests\Feature; use App\Models\Article; use App\Models\Note; +use App\Models\Place; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; @@ -159,4 +160,14 @@ class FeedsTest extends TestCase } } } + + /** @test */ + public function jsonNoteFeedLoadsPlaceDataWithoutLazyLoading(): void + { + $place = Place::factory()->create(); + Note::factory()->create(['note' => null, 'place_id' => $place->id]); + $response = $this->get('/notes/feed.json'); + + $response->assertOk(); + } } From 2aa60db54853ed3fb098418e7cb3fcc8a9a57c21 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Wed, 20 Dec 2023 14:44:11 +0000 Subject: [PATCH 255/481] Update JSON notes feed to version 1.1 --- app/Http/Controllers/FeedsController.php | 18 ++++++++++++------ app/Models/Note.php | 8 ++++---- database/seeders/NotesTableSeeder.php | 1 + tests/Unit/NotesTest.php | 6 +++--- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/app/Http/Controllers/FeedsController.php b/app/Http/Controllers/FeedsController.php index 5d0aa8d3..74e87be6 100644 --- a/app/Http/Controllers/FeedsController.php +++ b/app/Http/Controllers/FeedsController.php @@ -102,12 +102,18 @@ class FeedsController extends Controller */ public function notesJson(): array { - $notes = Note::latest()->with('media', 'place')->take(20)->get(); + $notes = Note::latest()->with('media', 'place', 'tags')->take(20)->get(); $data = [ - 'version' => 'https://jsonfeed.org/version/1', + 'version' => 'https://jsonfeed.org/version/1.1', 'title' => 'The JSON Feed for ' . config('user.display_name') . '’s notes', 'home_page_url' => config('app.url') . '/notes', 'feed_url' => config('app.url') . '/notes/feed.json', + 'authors' => [ + [ + 'name' => config('user.display_name'), + 'url' => config('app.url'), + ], + ], 'items' => [], ]; @@ -115,13 +121,13 @@ class FeedsController extends Controller $data['items'][$key] = [ 'id' => $note->longurl, 'url' => $note->longurl, - 'content_html' => $note->content, + 'content_text' => $note->content, 'date_published' => $note->created_at->tz('UTC')->toRfc3339String(), 'date_modified' => $note->updated_at->tz('UTC')->toRfc3339String(), - 'author' => [ - 'name' => config('user.display_name'), - ], ]; + if ($note->tags->count() > 0) { + $data['items'][$key]['tags'] = implode(',', $note->tags->pluck('tag')->toArray()); + } } return $data; diff --git a/app/Models/Note.php b/app/Models/Note.php index 39d0c5e1..f854b598 100644 --- a/app/Models/Note.php +++ b/app/Models/Note.php @@ -144,17 +144,17 @@ class Note extends Model */ public function getContentAttribute(): string { - $note = $this->note; + $note = $this->getRawOriginal('note'); foreach ($this->media as $media) { if ($media->type === 'image') { - $note .= ''; + $note .= PHP_EOL . ''; } if ($media->type === 'audio') { - $note .= '