From 9e79c746c00ca19b9cf5cb36434972cae876a8c8 Mon Sep 17 00:00:00 2001 From: carlobeltrame Date: Tue, 14 May 2024 17:18:30 +0200 Subject: [PATCH] Apply changes from laravel template --- .env.cypress | 25 ++- .env.example | 25 ++- .env.testing | 27 +++- .github/actions/deploy/action.yml | 1 - .github/actions/deploy/deploy.sh | 1 - .github/workflows/ci.yml | 1 - .gitignore | 1 + README.md | 1 - app/Exceptions/Handler.php | 98 ------------ app/Http/Controllers/BlockController.php | 3 +- app/Http/Controllers/Controller.php | 4 +- .../Controllers/ErrorReportController.php | 46 ------ app/Http/Controllers/NameGameController.php | 19 --- .../Controllers/ParticipantController.php | 4 +- app/Http/Kernel.php | 76 --------- app/Http/Middleware/Authenticate.php | 17 -- app/Http/Middleware/EncryptCookies.php | 17 -- .../PreventRequestsDuringMaintenance.php | 17 -- .../Middleware/RedirectIfAuthenticated.php | 1 - .../RestoreFormDataFromExpiredSession.php | 2 - app/Http/Middleware/TrustHosts.php | 18 --- app/Http/Middleware/TrustProxies.php | 23 --- app/Http/Middleware/VerifyCsrfToken.php | 17 -- app/Providers/AppServiceProvider.php | 78 ++++++++++ app/Providers/AuthServiceProvider.php | 59 ------- app/Providers/BroadcastServiceProvider.php | 19 --- app/Providers/EventServiceProvider.php | 41 ----- app/Providers/RouteServiceProvider.php | 113 -------------- app/Providers/ViewServiceProvider.php | 27 ---- app/Services/Hashing/NullableBcryptHasher.php | 25 +++ artisan | 50 +----- bootstrap/app.php | 115 ++++++++------ bootstrap/providers.php | 8 + config/app.php | 145 +++--------------- config/auth.php | 43 +++--- config/broadcasting.php | 43 ------ config/cache.php | 22 +-- config/cors.php | 34 ---- config/database.php | 27 ++-- config/filesystems.php | 8 +- config/hashing.php | 52 ------- config/logging.php | 24 +-- config/mail.php | 54 +++---- config/queue.php | 25 +-- config/services.php | 21 +-- config/session.php | 76 +++++---- config/view.php | 36 ----- database/factories/NativeUserFactory.php | 2 +- database/factories/UserFactory.php | 2 +- database/seeders/DatabaseSeeder.php | 5 +- lang/de/t.php | 10 +- lang/fr/t.php | 11 +- phpunit.xml | 3 +- public/index.php | 52 +------ resources/js/bootstrap.js | 23 --- resources/views/errors/500.blade.php | 34 +--- .../views/pages/after-error-submit.blade.php | 16 -- routes/api.php | 18 --- routes/channels.php | 18 --- routes/console.php | 13 +- routes/web.php | 17 +- tests/CreatesApplication.php | 21 --- tests/Feature/Admin/Block/CreateBlockTest.php | 2 +- .../Feature/Admin/Block/GenerateBlockTest.php | 2 +- .../Feature/Admin/Block/ImportBlocksTest.php | 26 ++-- .../Participant/ImportParticipantsTest.php | 11 +- .../RestoreFormDataWhenSessionExpiredTest.php | 6 +- tests/Feature/Auth/HitobitoOAuthTest.php | 14 ++ tests/Feature/ErrorReports/SentryTest.php | 32 ++-- .../ErrorReports/SubmitErrorReportTest.php | 39 ----- tests/TestCase.php | 1 - 71 files changed, 497 insertions(+), 1470 deletions(-) delete mode 100644 app/Exceptions/Handler.php delete mode 100644 app/Http/Controllers/ErrorReportController.php delete mode 100644 app/Http/Kernel.php delete mode 100644 app/Http/Middleware/Authenticate.php delete mode 100644 app/Http/Middleware/EncryptCookies.php delete mode 100644 app/Http/Middleware/PreventRequestsDuringMaintenance.php delete mode 100644 app/Http/Middleware/TrustHosts.php delete mode 100644 app/Http/Middleware/TrustProxies.php delete mode 100644 app/Http/Middleware/VerifyCsrfToken.php delete mode 100644 app/Providers/AuthServiceProvider.php delete mode 100644 app/Providers/BroadcastServiceProvider.php delete mode 100644 app/Providers/EventServiceProvider.php delete mode 100644 app/Providers/RouteServiceProvider.php delete mode 100644 app/Providers/ViewServiceProvider.php create mode 100755 app/Services/Hashing/NullableBcryptHasher.php create mode 100644 bootstrap/providers.php delete mode 100644 config/broadcasting.php delete mode 100644 config/cors.php delete mode 100644 config/hashing.php delete mode 100644 config/view.php delete mode 100644 resources/views/pages/after-error-submit.blade.php delete mode 100644 routes/api.php delete mode 100644 routes/channels.php delete mode 100644 tests/CreatesApplication.php delete mode 100644 tests/Feature/ErrorReports/SubmitErrorReportTest.php diff --git a/.env.cypress b/.env.cypress index cb069752..45dbec24 100644 --- a/.env.cypress +++ b/.env.cypress @@ -2,12 +2,23 @@ APP_NAME=Qualix APP_ENV=testing APP_KEY=base64:DoNotReuseThisKeyThisIsOnlyADummyForTesting= APP_DEBUG=true +APP_TIMEZONE=UTC APP_URL=http://qualix +APP_LOCALE=de +APP_FALLBACK_LOCALE=de +APP_FAKER_LOCALE=de_CH + +APP_MAINTENANCE_DRIVER=file +APP_MAINTENANCE_STORE=database + +BCRYPT_ROUNDS=12 + APP_CONTACT_LINK= # Enable contactlink in footer by adding mailto:example@mail.com or a link #APP_CONTACT_TEXT="CUSTOM TEXT" #Override contact text LOG_CHANNEL=stack +LOG_STACK=daily LOG_LEVEL=debug DB_CONNECTION=mysql @@ -17,12 +28,19 @@ DB_DATABASE=qualix DB_USERNAME=qualix DB_PASSWORD=qualix -BROADCAST_DRIVER=log -CACHE_DRIVER=file -QUEUE_CONNECTION=sync SESSION_DRIVER=file SESSION_LIFETIME=120 SESSION_SECURE_COOKIE=false +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=sync + +CACHE_STORE=file +CACHE_PREFIX= #MAIL_MAILER=log MAIL_MAILER=smtp @@ -45,6 +63,5 @@ COLLABORATION_SIGNALING_SERVERS="wss://signaling.yjs.dev wss://y-webrtc-signalin SENTRY_RELEASE= SENTRY_LARAVEL_DSN=https://123412341234123412341234@sentry.io/12345 -SENTRY_USER_FEEDBACK_URL=https://sentry.io/api/0/projects/xyz/xyz/user-feedback/ SENTRY_CSP_REPORT_URI=http://localhost/dummy MIX_SENTRY_VUE_DSN=https://567856785678567856785678@sentry.io/56789 diff --git a/.env.example b/.env.example index 025a5b18..3d996586 100644 --- a/.env.example +++ b/.env.example @@ -2,12 +2,23 @@ APP_NAME=Qualix APP_ENV=local APP_KEY= APP_DEBUG=true +APP_TIMEZONE=UTC APP_URL=http://localhost +APP_LOCALE=de +APP_FALLBACK_LOCALE=de +APP_FAKER_LOCALE=de_CH + +APP_MAINTENANCE_DRIVER=file +APP_MAINTENANCE_STORE=database + +BCRYPT_ROUNDS=12 + APP_CONTACT_LINK= # Enable contactlink in footer by adding mailto:example@mail.com or a link #APP_CONTACT_TEXT="CUSTOM TEXT" #Override contact text LOG_CHANNEL=stack +LOG_STACK=daily LOG_LEVEL=debug DB_CONNECTION=mysql @@ -17,13 +28,20 @@ DB_DATABASE=qualix DB_USERNAME=qualix DB_PASSWORD=qualix -BROADCAST_DRIVER=log -CACHE_DRIVER=file -QUEUE_CONNECTION=sync SESSION_DRIVER=file SESSION_LIFETIME=120 # Set this to true if you use https (e.g. in production) SESSION_SECURE_COOKIE=false +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=sync + +CACHE_STORE=file +CACHE_PREFIX= #MAIL_MAILER=log MAIL_MAILER=smtp @@ -47,6 +65,5 @@ COLLABORATION_SIGNALING_SERVERS="wss://signaling.yjs.dev wss://y-webrtc-signalin SENTRY_RELEASE= SENTRY_LARAVEL_DSN= -SENTRY_USER_FEEDBACK_URL= SENTRY_CSP_REPORT_URI= MIX_SENTRY_VUE_DSN= diff --git a/.env.testing b/.env.testing index 28e348d1..dace1b3a 100644 --- a/.env.testing +++ b/.env.testing @@ -2,12 +2,23 @@ APP_NAME=Qualix APP_ENV=testing APP_KEY=base64:DoNotReuseThisKeyThisIsOnlyADummyForTesting= APP_DEBUG=false +APP_TIMEZONE=UTC APP_URL=http://localhost -#APP_CONTACT_LINK=# Enable contactlink in footer by adding mailto:example@mail.com or a link +APP_LOCALE=de +APP_FALLBACK_LOCALE=de +APP_FAKER_LOCALE=de_CH + +APP_MAINTENANCE_DRIVER=file +APP_MAINTENANCE_STORE=database + +BCRYPT_ROUNDS=12 + +APP_CONTACT_LINK=# Enable contactlink in footer by adding mailto:example@mail.com or a link #APP_CONTACT_TEXT="CUSTOM TEXT" #Override contact text LOG_CHANNEL=stack +LOG_STACK=daily LOG_LEVEL=debug DB_CONNECTION=mysql @@ -17,12 +28,19 @@ DB_DATABASE=qualix DB_USERNAME=qualix DB_PASSWORD=qualix -BROADCAST_DRIVER=log -CACHE_DRIVER=file -QUEUE_CONNECTION=sync SESSION_DRIVER=file SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=sync + +CACHE_STORE=file +CACHE_PREFIX= MAIL_MAILER=log #MAIL_HOST=smtp.mailtrap.io #MAIL_PORT=2525 @@ -43,6 +61,5 @@ COLLABORATION_SIGNALING_SERVERS="wss://signaling.yjs.dev wss://y-webrtc-signalin SENTRY_RELEASE= SENTRY_LARAVEL_DSN=https://123412341234123412341234@sentry.io/12345 -SENTRY_USER_FEEDBACK_URL=https://sentry.io/api/0/projects/xyz/xyz/user-feedback/ SENTRY_CSP_REPORT_URI= MIX_SENTRY_VUE_DSN=https://567856785678567856785678@sentry.io/56789 diff --git a/.github/actions/deploy/action.yml b/.github/actions/deploy/action.yml index b37e7889..eb97634d 100644 --- a/.github/actions/deploy/action.yml +++ b/.github/actions/deploy/action.yml @@ -176,6 +176,5 @@ runs: COLLABORATION_ENABLED: ${{ inputs.collaboration-enabled }} COLLABORATION_SIGNALING_SERVERS: ${{ inputs.collaboration-signaling-servers }} SENTRY_LARAVEL_DSN: ${{ inputs.sentry-laravel-dsn }} - SENTRY_USER_FEEDBACK_URL: ${{ inputs.sentry-user-feedback-url }} SENTRY_CSP_REPORT_URI: ${{ inputs.sentry-csp-report-uri }} SENTRY_VUE_DSN: ${{ inputs.sentry-vue-dsn }} diff --git a/.github/actions/deploy/deploy.sh b/.github/actions/deploy/deploy.sh index 26886e87..0f9237ce 100755 --- a/.github/actions/deploy/deploy.sh +++ b/.github/actions/deploy/deploy.sh @@ -52,7 +52,6 @@ sed -ri "s~^COLLABORATION_SIGNALING_SERVERS=.*$~COLLABORATION_SIGNALING_SERVERS= sed -ri "s~^SENTRY_RELEASE=.*$~SENTRY_RELEASE=$(git rev-parse HEAD)~" .env sed -ri "s~^SENTRY_LARAVEL_DSN=.*$~SENTRY_LARAVEL_DSN=$SENTRY_LARAVEL_DSN~" .env -sed -ri "s~^SENTRY_USER_FEEDBACK_URL=.*$~SENTRY_USER_FEEDBACK_URL=$SENTRY_USER_FEEDBACK_URL~" .env sed -ri "s~^SENTRY_CSP_REPORT_URI=.*$~SENTRY_CSP_REPORT_URI=$SENTRY_CSP_REPORT_URI~" .env sed -ri "s~^MIX_SENTRY_VUE_DSN=.*$~MIX_SENTRY_VUE_DSN=$SENTRY_VUE_DSN~" .env diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38158b16..e2b44e74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,7 +135,6 @@ jobs: collaboration-enabled: ${{ secrets.COLLABORATION_ENABLED }} collaboration-signaling-servers: ${{ secrets.COLLABORATION_SIGNALING_SERVERS }} sentry-laravel-dsn: ${{ secrets.SENTRY_LARAVEL_DSN }} - sentry-user-feedback-url: ${{ secrets.SENTRY_USER_FEEDBACK_URL }} sentry-csp-report-uri: ${{ secrets.SENTRY_CSP_REPORT_URI }} sentry-vue-dsn: ${{ secrets.SENTRY_VUE_DSN }} diff --git a/.gitignore b/.gitignore index b2db28ba..e725a225 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /vendor .env .ready +.phpactor.json .phpunit.result.cache .phpunit.cache Homestead.json diff --git a/README.md b/README.md index 5eac41f6..bb4ad430 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,6 @@ COLLABORATION_ENABLED=true COLLABORATION_SIGNALING_SERVERS="wss://signaling.yjs.dev wss://y-webrtc-signaling-eu.herokuapp.com wss://y-webrtc-signaling-us.herokuapp.com" SENTRY_LARAVEL_DSN= -SENTRY_USER_FEEDBACK_URL= SENTRY_CSP_REPORT_URI= MIX_SENTRY_VUE_DSN= ``` diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php deleted file mode 100644 index ca16dee1..00000000 --- a/app/Exceptions/Handler.php +++ /dev/null @@ -1,98 +0,0 @@ -, \Psr\Log\LogLevel::*> - */ - protected $levels = [ - // - ]; - - /** - * A list of the exception types that are not reported. - * - * @var array> - */ - protected $dontReport = [ - // - ]; - - /** - * A list of the inputs that are never flashed to the session on validation exceptions. - * - * @var array - */ - protected $dontFlash = [ - 'password', - 'password_confirmation', - ]; - - /** - * Report or log an exception. - * - * @param Throwable $exception - * @return void - * @throws Throwable - */ - public function report(Throwable $exception) { - if (!config('app.debug') && app()->bound('sentry') && $this->shouldReport($exception)) { - app('sentry')->captureException($exception); - } - - 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) - { - if ($exception instanceof TokenMismatchException && !Auth::check() && $request->method() != 'GET' && !$request->get('noFormRestoring')) { - return $this->preserveSubmittedFormData($request); - } - if ($exception instanceof ValidationException || $exception instanceof AuthenticationException) { - // needed for remembering the active filters while editing an observation - // and for displaying a flash message when the session expired - session()->reflash(); - } - return parent::render($request, $exception); - } - - /** - * The user submitted a form but wasn't authenticated. Probably the session expired. - * Preserve the form data so it can be restored once the user logs back in. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\RedirectResponse - */ - protected function preserveSubmittedFormData($request) { - session()->put(RestoreFormDataFromExpiredSession::KEY, array_filter($request->except($this->dontFlash), function($input) { - // File inputs are not serializable and therefore cannot be saved into the session - return !($input instanceof UploadedFile); - })); - session()->flash('alert-warning', __('t.errors.session_expired_try_again')); - - return Redirect::back(302, [], app(Authenticate::class)->redirectTo($request)); - } -} diff --git a/app/Http/Controllers/BlockController.php b/app/Http/Controllers/BlockController.php index c6959bf7..2be731c9 100644 --- a/app/Http/Controllers/BlockController.php +++ b/app/Http/Controllers/BlockController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers; use App\Exceptions\ECamp2BlockOverviewParsingException; -use App\Exceptions\Handler; use App\Exceptions\UnsupportedFormatException; use App\Http\Requests\BlockGenerateRequest; use App\Http\Requests\BlockImportRequest; @@ -88,7 +87,7 @@ public function import(BlockImportRequest $request, Course $course) { } catch (UnsupportedFormatException $e) { throw ValidationException::withMessages(['file' => trans('t.views.admin.block_import.error_unsupported_format')]); } catch (Exception $e) { - app(Handler::class)->report($e); + report($e); return Redirect::back()->with('alert-danger', trans('t.views.admin.block_import.unknown_error')); } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 77ec359a..3584dcdb 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -2,11 +2,9 @@ namespace App\Http\Controllers; -use Illuminate\Foundation\Auth\Access\AuthorizesRequests; -use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; class Controller extends BaseController { - use AuthorizesRequests, ValidatesRequests; + // } diff --git a/app/Http/Controllers/ErrorReportController.php b/app/Http/Controllers/ErrorReportController.php deleted file mode 100644 index 85fd9ae3..00000000 --- a/app/Http/Controllers/ErrorReportController.php +++ /dev/null @@ -1,46 +0,0 @@ -validated(); - $request->session()->flash('previousUrl', $params['previousUrl']); - $client = app(GuzzleHttp\Client::class); - $url = config('app.sentry.user_feedback_url'); - $dsn = config('sentry.dsn'); - $client->post($url, [ - 'headers' => ['Authorization' => 'DSN ' . $dsn], - 'form_params' => [ - 'event_id' => $params['eventId'], - 'name' => $params['name'], - 'email' => $params['email'], - 'comments' => $params['description'], - ], - ]); - return Redirect::route('errorReport.after'); - } - - /** - * Display a message to the user to thank him for submitting a report. - * - * @return View - */ - public function after(Request $request) { - return view('pages.after-error-submit', ['previousUrl' => $request->session()->get('previousUrl', '/')]); - } -} diff --git a/app/Http/Controllers/NameGameController.php b/app/Http/Controllers/NameGameController.php index db010b6b..0618cac3 100644 --- a/app/Http/Controllers/NameGameController.php +++ b/app/Http/Controllers/NameGameController.php @@ -2,26 +2,7 @@ namespace App\Http\Controllers; -use App\Exceptions\Handler; -use App\Exceptions\MiDataParticipantsListsParsingException; -use App\Exceptions\UnsupportedFormatException; -use App\Http\Requests\ParticipantImportRequest; -use App\Http\Requests\ParticipantRequest; -use App\Models\Course; -use App\Models\Participant; -use App\Util\HtmlString; -use Exception; -use Illuminate\Http\RedirectResponse; -use Illuminate\Http\Request; use Illuminate\Http\Response; -use Illuminate\Routing\RouteCollectionInterface; -use Illuminate\Support\Collection; -use Illuminate\Support\Facades\Redirect; -use Illuminate\Support\Facades\Route; -use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Facades\URL; -use Illuminate\Validation\ValidationException; -use Illuminate\View\View; class NameGameController extends Controller { diff --git a/app/Http/Controllers/ParticipantController.php b/app/Http/Controllers/ParticipantController.php index f36f02f8..937c8b8e 100644 --- a/app/Http/Controllers/ParticipantController.php +++ b/app/Http/Controllers/ParticipantController.php @@ -2,8 +2,6 @@ namespace App\Http\Controllers; - -use App\Exceptions\Handler; use App\Exceptions\MiDataParticipantsListsParsingException; use App\Exceptions\UnsupportedFormatException; use App\Http\Requests\ParticipantImportRequest; @@ -88,7 +86,7 @@ public function import(ParticipantImportRequest $request, Course $course) { } catch (UnsupportedFormatException $e) { throw ValidationException::withMessages(['file' => trans('t.views.admin.participant_import.error_unsupported_format')]); } catch (Exception $e) { - app(Handler::class)->report($e); + report($e); return Redirect::back()->with('alert-danger', trans('t.views.admin.participant_import.unknown_error')); } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php deleted file mode 100644 index 5df84bd8..00000000 --- a/app/Http/Kernel.php +++ /dev/null @@ -1,76 +0,0 @@ - [ - \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, - Localization::class, - UpdateLeiterLastAccessed::class, - ], - - 'api' => [ - \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', - \Illuminate\Routing\Middleware\SubstituteBindings::class, - ], - ]; - - /** - * The application's middleware aliases. - * - * Aliases may be used to conveniently assign middleware to routes and groups. - * - * @var array - */ - protected $middlewareAliases = [ - 'auth' => \App\Http\Middleware\Authenticate::class, - 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, - 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, - 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, - 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, - 'can' => \Illuminate\Auth\Middleware\Authorize::class, - 'courseNotArchived' => CourseMustNotBeArchived::class, - 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, - 'restoreFormData' => \App\Http\Middleware\RestoreFormDataFromExpiredSession::class, - 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, - 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, - 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, - ]; -} diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php deleted file mode 100644 index 8c2acacd..00000000 --- a/app/Http/Middleware/Authenticate.php +++ /dev/null @@ -1,17 +0,0 @@ -expectsJson() ? null : route('login'); - } -} diff --git a/app/Http/Middleware/EncryptCookies.php b/app/Http/Middleware/EncryptCookies.php deleted file mode 100644 index 033136ad..00000000 --- a/app/Http/Middleware/EncryptCookies.php +++ /dev/null @@ -1,17 +0,0 @@ -allSubdomainsOfApplicationUrl(), - ]; - } -} diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php deleted file mode 100644 index d11dd5f0..00000000 --- a/app/Http/Middleware/TrustProxies.php +++ /dev/null @@ -1,23 +0,0 @@ -app->make('hash')->extend('bcrypt', function () { + return new NullableBcryptHasher(config('hashing.bcrypt') ?? []); + }); + $this->app->singleton('csp-nonce', function () { return Str::random(32); }); + + Route::bind('course', function($id) { + /** @var User $user */ + $user = Auth::user(); + return $user->courses()->findOrFail($id); + }); + + Route::bind('requirement', function($id, \Illuminate\Routing\Route $route) { + /** @var Course $course */ + $course = $route->parameter('course'); + return $course->requirements()->findOrFail($id); + }); + + Route::bind('feedback_data', function($id, \Illuminate\Routing\Route $route) { + /** @var Course $course */ + $course = $route->parameter('course'); + return $course->feedback_datas() + ->with('feedbacks') + ->with('feedbacks.participant') + ->with('feedbacks.requirements') + ->with('feedbacks.users') + ->findOrFail($id); + }); + + Participant::observe(DeleteOrphanObservationsOnParticipantDelete::class); + + View::composer('*', CurrentCourseViewComposer::class); + + $this->bootHitobitoSocialite(); + } + + private function bootHitobitoSocialite() + { + $socialite = $this->app->make('Laravel\Socialite\Contracts\Factory'); + $socialite->extend( + 'hitobito', + function ($app) { + $config = config('services.hitobito'); + return new HitobitoProvider( + $this->app['request'], $config['base_url'], $config['client_id'], + $config['client_secret'], $this->formatRedirectUrl($config), + Arr::get($config, 'guzzle', []) + ); + } + ); + } + + /** + * Format the callback URL, resolving a relative URI if needed. + * + * @param array $config + * @return string + */ + protected function formatRedirectUrl(array $config) + { + $redirect = value($config['redirect']); + + return Str::startsWith($redirect, '/') + ? $this->app['url']->to($redirect) + : $redirect; } } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php deleted file mode 100644 index b9c07534..00000000 --- a/app/Providers/AuthServiceProvider.php +++ /dev/null @@ -1,59 +0,0 @@ - 'App\Policies\ModelPolicy', - ]; - - /** - * Register any authentication / authorization services. - */ - public function boot(): void - { - $this->bootHitobitoSocialite(); - } - - private function bootHitobitoSocialite() - { - $socialite = $this->app->make('Laravel\Socialite\Contracts\Factory'); - $socialite->extend( - 'hitobito', - function ($app) { - $config = config('services.hitobito'); - return new HitobitoProvider( - $this->app['request'], $config['base_url'], $config['client_id'], - $config['client_secret'], $this->formatRedirectUrl($config), - Arr::get($config, 'guzzle', []) - ); - } - ); - } - - /** - * Format the callback URL, resolving a relative URI if needed. - * - * @param array $config - * @return string - */ - protected function formatRedirectUrl(array $config) - { - $redirect = value($config['redirect']); - - return Str::startsWith($redirect, '/') - ? $this->app['url']->to($redirect) - : $redirect; - } -} diff --git a/app/Providers/BroadcastServiceProvider.php b/app/Providers/BroadcastServiceProvider.php deleted file mode 100644 index 2be04f5d..00000000 --- a/app/Providers/BroadcastServiceProvider.php +++ /dev/null @@ -1,19 +0,0 @@ - [ - SendEmailVerificationNotification::class, - ], - ]; - - /** - * Register any events for your application. - */ - public function boot(): void - { - parent::boot(); - - Participant::observe(DeleteOrphanObservationsOnParticipantDelete::class); - } - - /** - * Determine if events and listeners should be automatically discovered. - */ - public function shouldDiscoverEvents(): bool - { - return false; - } -} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php deleted file mode 100644 index c84a1c1f..00000000 --- a/app/Providers/RouteServiceProvider.php +++ /dev/null @@ -1,113 +0,0 @@ -configureRateLimiting(); - - $this->routes(function () { - Route::middleware('api') - ->prefix('api') - ->group(base_path('routes/api.php')); - - Route::middleware('web') - ->namespace($this->namespace) - ->group(base_path('routes/web.php')); - }); - - Route::bind('course', function($id) { - /** @var User $user */ - $user = Auth::user(); - return $user->courses()->findOrFail($id); - }); - Route::bind('category', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->categories()->findOrFail($id); - }); - Route::bind('requirement', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->requirements()->findOrFail($id); - }); - Route::bind('block', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->blocks()->findOrFail($id); - }); - Route::bind('user', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->users()->findOrFail($id); - }); - Route::bind('participant', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->participants()->findOrFail($id); - }); - Route::bind('observation', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->observations()->findOrFail($id); - }); - Route::bind('participantGroup', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->participantGroups()->findOrFail($id); - }); - Route::bind('observationAssignment', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->observationAssignments()->findOrFail($id); - }); - Route::bind('feedback_data', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->feedback_datas() - ->with('feedbacks') - ->with('feedbacks.participant') - ->with('feedbacks.requirements') - ->with('feedbacks.users') - ->findOrFail($id); - }); - Route::bind('feedback', function($id, \Illuminate\Routing\Route $route) { - /** @var Participant $participant */ - $participant = $route->parameter('participant'); - return $participant->feedbacks()->findOrFail($id); - }); - Route::bind('requirement_status', function($id, \Illuminate\Routing\Route $route) { - /** @var Course $course */ - $course = $route->parameter('course'); - return $course->requirement_statuses()->findOrFail($id); - }); - - parent::boot(); - } - - /** - * 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/app/Providers/ViewServiceProvider.php b/app/Providers/ViewServiceProvider.php deleted file mode 100644 index 392c1af9..00000000 --- a/app/Providers/ViewServiceProvider.php +++ /dev/null @@ -1,27 +0,0 @@ -info($hashedValue)['algoName'] === 'bcrypt'; + } +} diff --git a/artisan b/artisan index 5c23e2e2..8e04b422 100644 --- a/artisan +++ b/artisan @@ -1,53 +1,15 @@ #!/usr/bin/env php make(Illuminate\Contracts\Console\Kernel::class); - -$status = $kernel->handle( - $input = new Symfony\Component\Console\Input\ArgvInput, - new Symfony\Component\Console\Output\ConsoleOutput -); - -/* -|-------------------------------------------------------------------------- -| Shutdown The Application -|-------------------------------------------------------------------------- -| -| Once Artisan has finished running, we will fire off the shutdown events -| so that any final work may be done by the application before we shut -| down the process. This is the last thing to happen to the request. -| -*/ - -$kernel->terminate($input, $status); +// Bootstrap Laravel and handle the command... +$status = (require_once __DIR__.'/bootstrap/app.php') + ->handleCommand(new ArgvInput); exit($status); diff --git a/bootstrap/app.php b/bootstrap/app.php index 037e17df..e7cf6cf2 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -1,55 +1,70 @@ withRouting( + web: __DIR__.'/../routes/web.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware) { + $middleware->replace( + \Illuminate\Foundation\Http\Middleware\TrimStrings::class, TrimStrings::class + ); + $middleware->replace( + \Illuminate\Auth\Middleware\RedirectIfAuthenticated::class, RedirectIfAuthenticated::class + ); + $middleware->append([ + SecurityHeaders::class, + ]); + $middleware->web(append: [ + Localization::class, + UpdateLeiterLastAccessed::class, + ]); + $middleware->alias([ + 'courseNotArchived' => CourseMustNotBeArchived::class, + 'guest' => RedirectIfAuthenticated::class, + 'restoreFormData' => RestoreFormDataFromExpiredSession::class, + ]); + }) + ->withExceptions(function (Exceptions $exceptions) { -/* -|-------------------------------------------------------------------------- -| Bind Important Interfaces -|-------------------------------------------------------------------------- -| -| Next, we need to bind some important interfaces into the container so -| we will be able to resolve them when needed. The kernels serve the -| incoming requests to this application from both the web and CLI. -| -*/ + $exceptions->reportable(function (Throwable $exception) { + if (!config('app.debug') && app()->bound('sentry')) { + Integration::captureUnhandledException($exception); + } + }); -$app->singleton( - Illuminate\Contracts\Http\Kernel::class, - App\Http\Kernel::class -); - -$app->singleton( - Illuminate\Contracts\Console\Kernel::class, - App\Console\Kernel::class -); - -$app->singleton( - Illuminate\Contracts\Debug\ExceptionHandler::class, - App\Exceptions\Handler::class -); - -/* -|-------------------------------------------------------------------------- -| Return The Application -|-------------------------------------------------------------------------- -| -| This script returns the application instance. The instance is given to -| the calling script so we can separate the building of the instances -| from the actual running of the application and sending responses. -| -*/ - -return $app; + $exceptions->render(function(Throwable $exception, Request $request) { + if ($exception instanceof Symfony\Component\HttpKernel\Exception\HttpException && $exception->getMessage() == 'CSRF token mismatch.' && !Auth::check() && $request->method() != 'GET' && !$request->get('noFormRestoring')) { + $dontFlash = ['password', 'password_confirmation']; + session()->put(RestoreFormDataFromExpiredSession::KEY, array_filter($request->except($dontFlash), function($input) { + // File inputs are not serializable and therefore cannot be saved into the session + return !($input instanceof UploadedFile); + })); + session()->flash('alert-warning', __('t.errors.session_expired_try_again')); + return back(302, [], route('login')); + } else if ($exception instanceof ValidationException || $exception instanceof AuthenticationException) { + // needed for remembering the active filters while editing an observation + // and for displaying a flash message when the session expired + session()->reflash(); + } + return null; + }); + })->create(); diff --git a/bootstrap/providers.php b/bootstrap/providers.php new file mode 100644 index 00000000..83a61ad6 --- /dev/null +++ b/bootstrap/providers.php @@ -0,0 +1,8 @@ + 'UTC', + 'timezone' => env('APP_TIMEZONE', 'UTC'), /* |-------------------------------------------------------------------------- @@ -77,67 +77,42 @@ |-------------------------------------------------------------------------- | | The application locale determines the default locale that will be used - | by the translation service provider. You are free to set this value - | to any of the locales which will be supported by the application. + | by Laravel's translation / localization methods. This option can be + | set to any locale for which you plan to have translation strings. | */ - 'locale' => 'de', + 'locale' => env('APP_LOCALE', 'de'), - /* - |-------------------------------------------------------------------------- - | Application Fallback Locale - |-------------------------------------------------------------------------- - | - | The fallback locale determines the locale to use when the current one - | is not available. You may change the value to correspond to any of - | the language folders that are provided through your application. - | - */ + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'de'), - 'fallback_locale' => 'de', - - /* - |-------------------------------------------------------------------------- - | List of locales supported by the application - |-------------------------------------------------------------------------- - | - | The locale of each request will be set to one of these locales, - | depending on the settings from the session and the request. - | - */ 'supported_locales' => [ 'de', 'fr', ], - /* - |-------------------------------------------------------------------------- - | Faker Locale - |-------------------------------------------------------------------------- - | - | This locale will be used by the Faker PHP library when generating fake - | data for your database seeds. For example, this will be used to get - | localized telephone numbers, street address information and more. - | - */ - - 'faker_locale' => 'de_CH', + 'faker_locale' => env('APP_FAKER_LOCALE', 'de_CH'), /* |-------------------------------------------------------------------------- | Encryption Key |-------------------------------------------------------------------------- | - | This key is used by the Illuminate encrypter service and should be set - | to a random, 32 character string, otherwise these encrypted strings - | will not be safe. Please do this before deploying an application! + | This key is utilized by Laravel's encryption services and should be set + | to a random, 32 character string to ensure that all encrypted values + | are secure. You should do this prior to deploying the application. | */ + 'cipher' => 'AES-256-CBC', + 'key' => env('APP_KEY'), - 'cipher' => 'AES-256-CBC', + 'previous_keys' => [ + ...array_filter( + explode(',', env('APP_PREVIOUS_KEYS', '')) + ), + ], /* |-------------------------------------------------------------------------- @@ -153,83 +128,10 @@ */ 'maintenance' => [ - 'driver' => 'file', - // 'store' => 'redis', + 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), + 'store' => env('APP_MAINTENANCE_STORE', 'database'), ], - - /* - |-------------------------------------------------------------------------- - | Autoloaded Service Providers - |-------------------------------------------------------------------------- - | - | The service providers listed here will be automatically loaded on the - | request to your application. Feel free to add your own services to - | this array to grant expanded functionality to your applications. - | - */ - - '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\Auth\Passwords\PasswordResetServiceProvider::class, - Illuminate\Session\SessionServiceProvider::class, - Illuminate\Translation\TranslationServiceProvider::class, - Illuminate\Validation\ValidationServiceProvider::class, - Illuminate\View\ViewServiceProvider::class, - - /* - * Package Service Providers... - */ - - /* - * Application Service Providers... - */ - App\Providers\AppServiceProvider::class, - App\Providers\AuthServiceProvider::class, - // App\Providers\BroadcastServiceProvider::class, - App\Providers\CypressServiceProvider::class, - App\Providers\EventServiceProvider::class, - App\Providers\ImportServiceProvider::class, - App\Providers\RouteServiceProvider::class, - App\Providers\ValidationServiceProvider::class, - App\Providers\ViewServiceProvider::class, - - ], - - /* - |-------------------------------------------------------------------------- - | Class Aliases - |-------------------------------------------------------------------------- - | - | This array of class aliases will be registered when this application - | is started. However, feel free to register as many as you wish as - | the aliases are "lazy" loaded so they don't hinder performance. - | - */ - - 'aliases' => Facade::defaultAliases()->merge([ - // 'ExampleClass' => App\Example\ExampleClass::class, - ])->toArray(), - 'collaboration' => [ 'enabled' => (bool) env('COLLABORATION_ENABLED', false), 'signaling_servers' => env('COLLABORATION_SIGNALING_SERVERS', false) @@ -241,7 +143,6 @@ ], 'sentry' => [ - 'user_feedback_url' => env('SENTRY_USER_FEEDBACK_URL'), 'mix' => [ 'vue_dsn' => env('MIX_SENTRY_VUE_DSN'), ], diff --git a/config/auth.php b/config/auth.php index 082ef7cf..2e806f7a 100644 --- a/config/auth.php +++ b/config/auth.php @@ -7,14 +7,14 @@ | Authentication Defaults |-------------------------------------------------------------------------- | - | This option controls the default authentication "guard" and password - | reset options for your application. You may change these defaults + | This option defines the default authentication "guard" and password + | reset "broker" for your application. You may change these values | as required, but they're a perfect start for most applications. | */ 'defaults' => [ - 'guard' => 'web', + 'guard' => env('AUTH_GUARD', 'web'), 'passwords' => 'nativeUsers', ], @@ -25,13 +25,13 @@ | | Next, you may define every authentication guard for your application. | Of course, a great default configuration has been defined for you - | here which uses session storage and the Eloquent user provider. + | which utilizes session storage plus the Eloquent user provider. | - | All authentication drivers have a user provider. This defines how the + | All authentication guards have a user provider, which defines how the | users are actually retrieved out of your database or other storage - | mechanisms used by this application to persist your user's data. + | system used by the application. Typically, Eloquent is utilized. | - | Supported: "session", "token" + | Supported: "session" | */ @@ -53,12 +53,12 @@ | User Providers |-------------------------------------------------------------------------- | - | All authentication drivers have a user provider. This defines how the + | All authentication guards have a user provider, which defines how the | users are actually retrieved out of your database or other storage - | mechanisms used by this application to persist your user's data. + | system used by the application. Typically, Eloquent is utilized. | | If you have multiple user tables or models you may configure multiple - | sources which represent each model / table. These sources may then + | providers to represent the model / table. These providers may then | be assigned to any extra authentication guards you have defined. | | Supported: "database", "eloquent" @@ -68,7 +68,7 @@ 'providers' => [ 'users' => [ 'driver' => 'eloquent', - 'model' => App\Models\User::class, + 'model' => env('AUTH_MODEL', App\Models\User::class), ], 'nativeUsers' => [ @@ -82,21 +82,26 @@ | Resetting Passwords |-------------------------------------------------------------------------- | - | You may specify multiple password reset configurations if you have more - | than one user table or model in the application and you want to have - | separate password reset settings based on the specific user types. + | These configuration options specify the behavior of Laravel's password + | reset functionality, including the table utilized for token storage + | and the user provider that is invoked to actually retrieve users. | - | The expire time is the number of minutes that the reset token should 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. | - */ + | The throttle setting is the number of seconds a user must wait before + | generating more password reset tokens. This prevents the user from + | quickly generating a very large amount of password reset tokens. + | +*/ 'passwords' => [ 'nativeUsers' => [ 'provider' => 'nativeUsers', - 'table' => 'password_resets', + 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_resets'), 'expire' => 60, + 'throttle' => 60, ], ], @@ -106,11 +111,11 @@ |-------------------------------------------------------------------------- | | Here you may define the amount of seconds before a password confirmation - | times out and the user is prompted to re-enter their password via the + | window expires and users are asked to re-enter their password via the | confirmation screen. By default, the timeout lasts for three hours. | */ - 'password_timeout' => 10800, + 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), ]; diff --git a/config/broadcasting.php b/config/broadcasting.php deleted file mode 100644 index c61bc9e2..00000000 --- a/config/broadcasting.php +++ /dev/null @@ -1,43 +0,0 @@ - env('BROADCAST_DRIVER', 'null'), - - /* - |-------------------------------------------------------------------------- - | Broadcast Connections - |-------------------------------------------------------------------------- - | - | Here you may define all of the broadcast connections that will be used - | to broadcast events to other systems or over websockets. Samples of - | each available type of connection are provided inside this array. - | - */ - - 'connections' => [ - - 'log' => [ - 'driver' => 'log', - ], - - 'null' => [ - 'driver' => 'null', - ], - - ], - -]; diff --git a/config/cache.php b/config/cache.php index a76fb9d3..9e41a302 100644 --- a/config/cache.php +++ b/config/cache.php @@ -9,13 +9,13 @@ | Default Cache Store |-------------------------------------------------------------------------- | - | This option controls the default cache connection that gets used while - | using this caching library. This connection is used when another is - | not explicitly specified when executing a given caching function. + | This option controls the default cache store that will be used by the + | framework. This connection is utilized if another isn't explicitly + | specified when running a cache operation inside the application. | */ - 'default' => env('CACHE_DRIVER', 'file'), + 'default' => env('CACHE_STORE', 'file'), /* |-------------------------------------------------------------------------- @@ -26,8 +26,8 @@ | 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" + | Supported drivers: "array", "database", "file", "memcached", + | "redis", "dynamodb", "octane", "null" | */ @@ -44,9 +44,9 @@ 'database' => [ 'driver' => 'database', - 'table' => 'cache', - 'connection' => null, - 'lock_connection' => null, + 'table' => env('DB_CACHE_TABLE', 'cache'), + 'connection' => env('DB_CACHE_CONNECTION'), + 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), ], 'file' => [ @@ -80,8 +80,8 @@ | Cache Key Prefix |-------------------------------------------------------------------------- | - | When utilizing the APC, database, memcached, Redis, or DynamoDB cache - | stores there might be other applications using the same cache. For + | When utilizing the APC, database, memcached, Redis, and DynamoDB cache + | stores, there might be other applications using the same cache. For | that reason, you may prefix every cache key to avoid collisions. | */ diff --git a/config/cors.php b/config/cors.php deleted file mode 100644 index 8a39e6da..00000000 --- a/config/cors.php +++ /dev/null @@ -1,34 +0,0 @@ - ['api/*', 'sanctum/csrf-cookie'], - - 'allowed_methods' => ['*'], - - 'allowed_origins' => ['*'], - - 'allowed_origins_patterns' => [], - - 'allowed_headers' => ['*'], - - 'exposed_headers' => [], - - 'max_age' => 0, - - 'supports_credentials' => false, - -]; diff --git a/config/database.php b/config/database.php index e6cdcbd9..4ce94d3d 100644 --- a/config/database.php +++ b/config/database.php @@ -8,8 +8,9 @@ |-------------------------------------------------------------------------- | | Here you may specify which of the database connections below you wish - | to use as your default connection for all database work. Of course - | you may use many connections at once using the Database library. + | to use as your default connection for database operations. This is + | the connection which will be utilized unless another connection + | is explicitly specified when you execute a query / statement. | */ @@ -20,14 +21,9 @@ | Database Connections |-------------------------------------------------------------------------- | - | Here are each of the database connections setup for your application. - | Of course, examples of configuring each database platform that is - | supported by Laravel is shown below to make development simple. - | - | - | All database work in Laravel is done through the PHP PDO facilities - | so make sure you have the driver for your particular database of - | choice installed on your machine before you begin development. + | Below are all of the database connections defined for your application. + | An example configuration is provided for each database system which + | is supported by Laravel. You're free to add / remove connections. | */ @@ -37,8 +33,8 @@ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), - 'database' => env('DB_DATABASE', 'forge'), - 'username' => env('DB_USERNAME', 'forge'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', @@ -61,10 +57,13 @@ | | This table keeps track of all the migrations that have already run for | your application. Using this information, we can determine which of - | the migrations on disk haven't actually been run in the database. + | the migrations on disk haven't actually been run on the database. | */ - 'migrations' => 'migrations', + 'migrations' => [ + 'table' => 'migrations', + 'update_date_on_publish' => true, + ], ]; diff --git a/config/filesystems.php b/config/filesystems.php index 15f46b03..0c2f80fc 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -9,7 +9,7 @@ | | Here you may specify the default filesystem disk that should be used | by the framework. The "local" disk, as well as a variety of cloud - | based disks are available to your application. Just store away! + | based disks are available to your application for file storage. | */ @@ -20,9 +20,9 @@ | Filesystem Disks |-------------------------------------------------------------------------- | - | Here you may configure as many filesystem "disks" as you wish, and you - | may even configure multiple disks of the same driver. Defaults have - | been set up for each driver as an example of the required values. + | Below you may configure as many filesystem disks as necessary, and you + | may even configure multiple disks for the same driver. Examples for + | most supported storage drivers are configured here for reference. | | Supported Drivers: "local", "ftp", "sftp", "s3", "rackspace" | diff --git a/config/hashing.php b/config/hashing.php deleted file mode 100644 index 84257708..00000000 --- a/config/hashing.php +++ /dev/null @@ -1,52 +0,0 @@ - 'bcrypt', - - /* - |-------------------------------------------------------------------------- - | Bcrypt Options - |-------------------------------------------------------------------------- - | - | Here you may specify the configuration options that should be used when - | passwords are hashed using the Bcrypt algorithm. This will allow you - | to control the amount of time it takes to hash the given password. - | - */ - - 'bcrypt' => [ - 'rounds' => env('BCRYPT_ROUNDS', 10), - ], - - /* - |-------------------------------------------------------------------------- - | Argon Options - |-------------------------------------------------------------------------- - | - | Here you may specify the configuration options that should be used when - | passwords are hashed using the Argon algorithm. These will allow you - | to control the amount of time it takes to hash the given password. - | - */ - - 'argon' => [ - 'memory' => 1024, - 'threads' => 2, - 'time' => 2, - ], - -]; diff --git a/config/logging.php b/config/logging.php index edd7f6ae..36aede05 100644 --- a/config/logging.php +++ b/config/logging.php @@ -10,9 +10,9 @@ | Default Log Channel |-------------------------------------------------------------------------- | - | This option defines the default log channel that gets used when writing - | messages to the logs. The name specified in this option should match - | one of the channels defined in the "channels" configuration array. + | This option defines the default log channel that is utilized to write + | messages to your logs. The value provided here should match one of + | the channels present in the list of "channels" configured below. | */ @@ -30,7 +30,7 @@ */ 'deprecations' => [ 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), - 'trace' => false, + 'trace' => env('LOG_DEPRECATIONS_TRACE', false), ], /* @@ -38,20 +38,20 @@ | Log Channels |-------------------------------------------------------------------------- | - | Here you may configure the log channels for your application. Out of - | the box, Laravel uses the Monolog PHP logging library. This gives - | you a variety of powerful log handlers / formatters to utilize. + | Here you may configure the log channels for your application. Laravel + | utilizes the Monolog PHP logging library, which includes a variety + | of powerful log handlers and formatters that you're free to use. | | Available Drivers: "single", "daily", "slack", "syslog", - | "errorlog", "monolog", - | "custom", "stack" + | "errorlog", "monolog", "custom", "stack" | */ 'channels' => [ + 'stack' => [ 'driver' => 'stack', - 'channels' => ['daily'], + 'channels' => explode(',', env('LOG_STACK', 'daily')), 'ignore_exceptions' => false, ], @@ -65,7 +65,7 @@ 'driver' => 'daily', 'path' => storage_path('logs/laravel.log'), 'level' => env('LOG_LEVEL', 'debug'), - 'days' => 14, + 'days' => env('LOG_DAILY_DAYS', 14), ], 'stderr' => [ @@ -80,6 +80,7 @@ 'syslog' => [ 'driver' => 'syslog', 'level' => env('LOG_LEVEL', 'debug'), + 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), ], 'errorlog' => [ @@ -95,6 +96,7 @@ 'emergency' => [ 'path' => storage_path('logs/laravel.log'), ], + ], ]; diff --git a/config/mail.php b/config/mail.php index d2e32cb1..cab47c15 100644 --- a/config/mail.php +++ b/config/mail.php @@ -7,9 +7,10 @@ | Default Mailer |-------------------------------------------------------------------------- | - | This option controls the default mailer that is used to send any email - | messages sent by your application. Alternative mailers may be setup - | and used as needed; however, this mailer will be used by default. + | This option controls the default mailer that is used to send all email + | messages unless another mailer is explicitly specified when sending + | the message. All additional mailers can be configured within the + | "mailers" array. Examples of each type of mailer are provided. | */ @@ -24,20 +25,22 @@ | their respective settings. Several examples have been configured for | you and you are free to add your own as your application requires. | - | Laravel supports a variety of mail "transport" drivers to be used while - | sending an e-mail. You will specify which one you are using for your - | mailers below. You are free to add additional mailers as required. + | Laravel supports a variety of mail "transport" drivers that can be used + | when delivering an email. You may specify which one you're using for + | your mailers below. You may also add additional mailers if needed. | | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", - | "postmark", "log", "array" + | "postmark", "resend", "log", "array", + | "failover", "roundrobin" | */ 'mailers' => [ + 'smtp' => [ 'transport' => 'smtp', - 'host' => env('MAIL_HOST', 'smtp.mailgun.org'), - 'port' => env('MAIL_PORT', 587), + 'host' => env('MAIL_HOST', '127.0.0.1'), + 'port' => env('MAIL_PORT', 2525), 'encryption' => env('MAIL_ENCRYPTION', 'tls'), 'username' => env('MAIL_USERNAME'), 'password' => env('MAIL_PASSWORD'), @@ -49,11 +52,8 @@ 'transport' => 'ses', ], - 'mailgun' => [ - 'transport' => 'mailgun', - // 'client' => [ - // 'timeout' => 5, - // ], + 'resend' => [ + 'transport' => 'resend', ], 'postmark' => [ @@ -76,6 +76,7 @@ 'array' => [ 'transport' => 'array', ], + ], /* @@ -83,9 +84,9 @@ | Global "From" Address |-------------------------------------------------------------------------- | - | You may wish for all e-mails sent by your application to be sent from - | the same address. Here, you may specify a name and address that is - | used globally for all e-mails that are sent by your application. + | You may wish for all emails sent by your application to be sent from + | the same address. Here you may specify a name and address that is + | used globally for all emails that are sent by your application. | */ @@ -94,23 +95,4 @@ 'name' => env('MAIL_FROM_NAME', 'Qualix'), ], - /* - |-------------------------------------------------------------------------- - | Markdown Mail Settings - |-------------------------------------------------------------------------- - | - | If you are using Markdown based email rendering, you may configure your - | theme and component paths here, allowing you to customize the design - | of the emails. Or, you may simply stick with the Laravel defaults! - | - */ - - 'markdown' => [ - 'theme' => 'default', - - 'paths' => [ - resource_path('views/vendor/mail'), - ], - ], - ]; diff --git a/config/queue.php b/config/queue.php index 6be0a0e0..177b298c 100644 --- a/config/queue.php +++ b/config/queue.php @@ -7,9 +7,9 @@ | Default Queue Connection Name |-------------------------------------------------------------------------- | - | Laravel's queue API supports an assortment of back-ends via a single - | API, giving you convenient access to each back-end using the same - | syntax for every one. Here you may define a default connection. + | Laravel's queue supports a variety of backends via a single, unified + | API, giving you convenient access to each backend using identical + | syntax for each. The default queue connection is defined below. | */ @@ -20,9 +20,9 @@ | Queue Connections |-------------------------------------------------------------------------- | - | Here you may configure the connection information for each server that - | is used by your application. A default configuration has been added - | for each back-end shipped with Laravel. You are free to add more. + | Here you may configure the connection options for every queue backend + | used by your application. An example configuration is provided for + | each backend supported by Laravel. You're also free to add more. | | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" | @@ -36,9 +36,10 @@ 'database' => [ 'driver' => 'database', - 'table' => 'jobs', - 'queue' => 'default', - 'retry_after' => 90, + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', 'jobs'), + 'queue' => env('DB_QUEUE', 'default'), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), ], ], @@ -49,8 +50,10 @@ |-------------------------------------------------------------------------- | | These options configure the behavior of failed queue job logging so you - | can control which database and table are used to store the jobs that - | have failed. You may change them to any database / table you wish. + | can control how and where failed jobs are stored. Laravel ships with + | support for storing failed jobs in a simple file or in a database. + | + | Supported drivers: "database-uuids", "dynamodb", "file", "null" | */ diff --git a/config/services.php b/config/services.php index 1127f8be..b4c0c57d 100644 --- a/config/services.php +++ b/config/services.php @@ -21,13 +21,6 @@ 'redirect' => env('HITOBITO_CALLBACK_URI', 'https://qualix.flamberg.ch/login/hitobito/callback'), ], - 'mailgun' => [ - 'domain' => env('MAILGUN_DOMAIN'), - 'secret' => env('MAILGUN_SECRET'), - 'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'), - 'scheme' => 'https', - ], - 'postmark' => [ 'token' => env('POSTMARK_TOKEN'), ], @@ -38,18 +31,8 @@ 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), ], - 'sparkpost' => [ - 'secret' => env('SPARKPOST_SECRET'), - ], - - 'stripe' => [ - 'model' => App\User::class, - 'key' => env('STRIPE_KEY'), - 'secret' => env('STRIPE_SECRET'), - 'webhook' => [ - 'secret' => env('STRIPE_WEBHOOK_SECRET'), - 'tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300), - ], + 'resend' => [ + 'key' => env('RESEND_KEY'), ], ]; diff --git a/config/session.php b/config/session.php index cb41e386..2b03d568 100644 --- a/config/session.php +++ b/config/session.php @@ -9,9 +9,9 @@ | Default Session Driver |-------------------------------------------------------------------------- | - | This option controls the default session "driver" that will be used on - | requests. By default, we will use the lightweight native driver but - | you may specify any of the other wonderful drivers provided here. + | This option determines the default session driver that is utilized for + | incoming requests. Laravel supports a variety of storage options to + | persist session data. Database storage is a great default choice. | | Supported: "file", "cookie", "database", "apc", | "memcached", "redis", "dynamodb", "array" @@ -27,13 +27,14 @@ | | Here you may specify the number of minutes that you wish the session | to be allowed to remain idle before it expires. If you want them - | to immediately expire on the browser closing, set that option. + | to expire immediately when the browser is closed then you may + | indicate that via the expire_on_close configuration option. | */ 'lifetime' => env('SESSION_LIFETIME', 120), - 'expire_on_close' => false, + 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), /* |-------------------------------------------------------------------------- @@ -41,21 +42,21 @@ |-------------------------------------------------------------------------- | | This option allows you to easily specify that all of your session data - | should be encrypted before it is stored. All encryption will be run - | automatically by Laravel and you can use the Session like normal. + | should be encrypted before it's stored. All encryption is performed + | automatically by Laravel and you may use the session like normal. | */ - 'encrypt' => false, + 'encrypt' => env('SESSION_ENCRYPT', false), /* |-------------------------------------------------------------------------- | Session File Location |-------------------------------------------------------------------------- | - | When using the native session driver, we need a location where session - | files may be stored. A default has been set for you but a different - | location may be specified. This is only needed for file sessions. + | When utilizing the "file" session driver, the session files are placed + | on disk. The default storage location is defined here; however, you + | are free to provide another location where they should be stored. | */ @@ -79,23 +80,24 @@ | Session Database Table |-------------------------------------------------------------------------- | - | When using the "database" session driver, you may specify the table we - | should use to manage the sessions. Of course, a sensible default is - | provided for you; however, you are free to change this as needed. + | When using the "database" session driver, you may specify the table to + | be used to store sessions. Of course, a sensible default is defined + | for you; however, you're welcome to change this to another table. | */ - 'table' => 'sessions', + 'table' => env('SESSION_TABLE', 'sessions'), /* |-------------------------------------------------------------------------- | Session Cache Store |-------------------------------------------------------------------------- | - | When using the "apc", "memcached", or "dynamodb" session drivers you may - | list a cache store that should be used for these sessions. This value - | must match with one of the application's configured cache "stores". + | When using one of the framework's cache driven session backends, you may + | define the cache store which should be used to store the session data + | between requests. This must match one of your defined cache stores. | + | Affects: "apc", "dynamodb", "memcached", "redis" */ 'store' => env('SESSION_STORE'), @@ -118,9 +120,9 @@ | Session Cookie Name |-------------------------------------------------------------------------- | - | Here you may change the name of the cookie used to identify a session - | instance by ID. The name specified here will get used every time a - | new session cookie is created by the framework for every driver. + | Here you may change the name of the session cookie that is created by + | the framework. Typically, you should not need to change this value + | since doing so does not grant a meaningful security improvement. | */ @@ -138,20 +140,20 @@ | | The session cookie path determines the path for which the cookie will | be regarded as available. Typically, this will be the root path of - | your application but you are free to change this when necessary. + | your application, but you're free to change this when necessary. | */ - 'path' => '/', + 'path' => env('SESSION_PATH', '/'), /* |-------------------------------------------------------------------------- | Session Cookie Domain |-------------------------------------------------------------------------- | - | Here you may change the domain of the cookie used to identify a session - | in your application. This will determine which domains the cookie is - | available to in your application. A sensible default has been set. + | This value determines the domain and subdomains the session cookie is + | available to. By default, the cookie will be available to the root + | domain and all subdomains. Typically, this shouldn't be changed. | */ @@ -177,11 +179,11 @@ | | Setting this value to true will prevent JavaScript from accessing the | value of the cookie and the cookie will only be accessible through - | the HTTP protocol. You are free to modify this option if needed. + | the HTTP protocol. It's unlikely you should disable this option. | */ - 'http_only' => true, + 'http_only' => env('SESSION_HTTP_ONLY', true), /* |-------------------------------------------------------------------------- @@ -190,12 +192,26 @@ | | This option determines how your cookies behave when cross-site requests | take place, and can be used to mitigate CSRF attacks. By default, we - | will set this value to "lax" since this is a secure default value. + | will set this value to "lax" to permit secure cross-site requests. + | + | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value | | Supported: "lax", "strict", "none", null | */ - 'same_site' => 'lax', + 'same_site' => env('SESSION_SAME_SITE', 'lax'), + + /* + |-------------------------------------------------------------------------- + | Partitioned Cookies + |-------------------------------------------------------------------------- + | + | Setting this value to true will tie the cookie to the top-level site for + | a cross-site context. Partitioned cookies are accepted by the browser + | when flagged "secure" and the Same-Site attribute is set to "none". + | + */ + 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), ]; diff --git a/config/view.php b/config/view.php deleted file mode 100644 index 22b8a18d..00000000 --- a/config/view.php +++ /dev/null @@ -1,36 +0,0 @@ - [ - resource_path('views'), - ], - - /* - |-------------------------------------------------------------------------- - | Compiled View Path - |-------------------------------------------------------------------------- - | - | This option determines where all the compiled Blade templates will be - | stored for your application. Typically, this is within the storage - | directory. However, as usual, you are free to change this value. - | - */ - - 'compiled' => env( - 'VIEW_COMPILED_PATH', - realpath(storage_path('framework/views')) - ), - -]; diff --git a/database/factories/NativeUserFactory.php b/database/factories/NativeUserFactory.php index 9b26227d..6ffa3f91 100644 --- a/database/factories/NativeUserFactory.php +++ b/database/factories/NativeUserFactory.php @@ -24,7 +24,7 @@ public function definition() { 'name' => ucfirst($this->faker->word), 'email' => $this->faker->unique()->safeEmail, 'email_verified_at' => now(), - 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password + 'password' => bcrypt('password'), 'remember_token' => Str::random(10), ]; } diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 9c2aa736..aa67240d 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -24,7 +24,7 @@ public function definition(): array { 'name' => ucfirst($this->faker->word), 'email' => $this->faker->unique()->safeEmail, 'email_verified_at' => now(), - 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password + 'password' => bcrypt('password'), 'remember_token' => Str::random(10), ]; } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index cf8374da..46f4f09d 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -2,6 +2,7 @@ namespace Database\Seeders; +// use App\Models\User; use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder @@ -13,9 +14,9 @@ class DatabaseSeeder extends Seeder */ public function run() { - // \App\Models\User::factory(10)->create(); + // User::factory(10)->create(); - // \App\Models\User::factory()->create([ + // User::factory()->create([ // 'name' => 'Test User', // 'email' => 'test@example.com', // ]); diff --git a/lang/de/t.php b/lang/de/t.php index 663a4247..6338f554 100644 --- a/lang/de/t.php +++ b/lang/de/t.php @@ -492,18 +492,10 @@ "title" => "Was kann ich heute beobachten?", "view_as" => "Aus Sicht von", ), - "error_form" => array( + "error_page" => array( "back" => "Zurück zu wo ich gerade noch war...", - "back_without_sending_report" => "Zurück ohne eine Beschreibung zu senden", - "error_report_has_been_submitted" => "Deine Beschreibung wurde abgesendet. Vielen Dank!", - "it_looks_like_we_are_having_issues" => "Es sieht so aus als hätten wir ein Problem.", - "our_team_has_been_notified" => "Das Qualix-Team wurde bereits informiert. Wenn du uns helfen möchtest, teile uns bitte unten mit, was geschehen ist.", "page_title" => "Technischer Fehler", "please_try_again_later" => "Bitte versuche es später nochmals.", - "send_description" => "Beschreibung absenden", - "thank_you" => "Danke", - "what_happened" => "Was ist passiert?", - "what_happened_example" => "Ich habe auf das \"X\" und dann auf \"Bestätigen\" geklickt.", ), "feedback" => array( "print" => array( diff --git a/lang/fr/t.php b/lang/fr/t.php index b31946d3..417a8659 100644 --- a/lang/fr/t.php +++ b/lang/fr/t.php @@ -254,17 +254,10 @@ ), "title_with_requirements" => "Que puis-je observer aujourd'hui?", ), - "error_form" => array( + "error_page" => array( "back" => "Retour à ce que j'étais il y a une minute...", - "back_without_sending_report" => "Retour sans envoyer de description", - "error_report_has_been_submitted" => "Ta description a été saisie. Merci beaucoup.", - "it_looks_like_we_are_having_issues" => "Il semble que nous ayons un problème.", - "our_team_has_been_notified" => "L'équipe Qualix a déjà été informée. Si tu veux nous aider, dis-nous ci-dessous ce qui s'est passé.", + "page_title" => "Erreur technique", "please_try_again_later" => "Essaye à nouveau plus tard.", - "send_description" => "Envoyer la description", - "thank_you" => "Merci", - "what_happened" => "Que s'est-il passé?", - "what_happened_example" => "J'ai cliqué sur le \"X\" et ensuite sur \"Confirmer\".", ), "invitation" => array( "accept_invitation" => "Oui, accepter l'invitation", diff --git a/phpunit.xml b/phpunit.xml index e56aa05d..65db8b36 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -15,7 +15,8 @@ - + + diff --git a/public/index.php b/public/index.php index a8137b13..947d9896 100644 --- a/public/index.php +++ b/public/index.php @@ -1,55 +1,17 @@ make(Kernel::class); - -$response = tap($kernel->handle( - $request = Request::capture() -))->send(); - -$kernel->terminate($request, $response); +// Bootstrap Laravel and handle the request... +(require_once __DIR__.'/../bootstrap/app.php') + ->handleRequest(Request::capture()); diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js index c2f82db8..d2d28eca 100644 --- a/resources/js/bootstrap.js +++ b/resources/js/bootstrap.js @@ -2,12 +2,6 @@ try { window.Popper = require('popper.js').default; } catch (e) {} -/** - * We'll load the axios HTTP library which allows us to easily issue requests - * to our Laravel back-end. This library automatically handles sending the - * CSRF token as a header based on the value of the "XSRF" token cookie. - */ - window.axios = require('axios'); window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; @@ -25,20 +19,3 @@ if (token) { } else { console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token'); } - -/** - * Echo exposes an expressive API for subscribing to channels and listening - * for events that are broadcast by Laravel. Echo and event broadcasting - * allows your team to easily build robust real-time web applications. - */ - -// import Echo from 'laravel-echo' - -// window.Pusher = require('pusher-js'); - -// window.Echo = new Echo({ -// broadcaster: 'pusher', -// key: process.env.MIX_PUSHER_APP_KEY, -// cluster: process.env.MIX_PUSHER_APP_CLUSTER, -// forceTLS: true -// }); diff --git a/resources/views/errors/500.blade.php b/resources/views/errors/500.blade.php index 26902058..362d490b 100644 --- a/resources/views/errors/500.blade.php +++ b/resources/views/errors/500.blade.php @@ -1,41 +1,17 @@ @extends('layouts.default') -@section('pagetitle'){{__('t.views.error_form.page_title') }}@endsection +@section('pagetitle'){{__('t.views.error_page.page_title') }}@endsection @section('content') - @if(app()->bound('sentry') && app('sentry')->getLastEventId() && config('app.sentry.user_feedback_url')) +

{{__('t.views.error_page.please_try_again_later')}}

-
{{__('t.views.error_form.it_looks_like_we_are_having_issues')}}
- -

{{__('t.views.error_form.our_team_has_been_notified')}}

- - - - - - - - - - - - - - - - {{ __('t.views.error_form.back_without_sending_report') }} - - - - - - @else -

{{__('t.views.error_form.please_try_again_later')}}

- @endif + + {{ __('t.views.error_page.back') }} +
diff --git a/resources/views/pages/after-error-submit.blade.php b/resources/views/pages/after-error-submit.blade.php deleted file mode 100644 index 43bfc634..00000000 --- a/resources/views/pages/after-error-submit.blade.php +++ /dev/null @@ -1,16 +0,0 @@ -@extends('layouts.default') - -@section('content') - - - - -

{{__('t.views.error_form.error_report_has_been_submitted')}}

- - - {{ __('t.views.error_form.back') }} - - -
- -@endsection diff --git a/routes/api.php b/routes/api.php deleted file mode 100644 index bcc24958..00000000 --- a/routes/api.php +++ /dev/null @@ -1,18 +0,0 @@ -get('/user', function (Request $request) { - return $request->user(); -}); -*/ diff --git a/routes/channels.php b/routes/channels.php deleted file mode 100644 index 963b0d21..00000000 --- a/routes/channels.php +++ /dev/null @@ -1,18 +0,0 @@ -id === (int) $id; -}); diff --git a/routes/console.php b/routes/console.php index e05f4c9a..eff2ed24 100644 --- a/routes/console.php +++ b/routes/console.php @@ -3,17 +3,6 @@ use Illuminate\Foundation\Inspiring; use Illuminate\Support\Facades\Artisan; -/* -|-------------------------------------------------------------------------- -| Console Routes -|-------------------------------------------------------------------------- -| -| This file is where you may define all of your Closure based console -| commands. Each Closure is bound to a command instance allowing a -| simple approach to interacting with each command's IO methods. -| -*/ - Artisan::command('inspire', function () { $this->comment(Inspiring::quote()); -})->purpose('Display an inspiring quote'); +})->purpose('Display an inspiring quote')->hourly(); diff --git a/routes/web.php b/routes/web.php index 9317e44e..cfca10cb 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,23 +1,11 @@ group(function () { +Route::middleware(['auth', 'verified', 'restoreFormData'])->scopeBindings()->group(function () { Route::get('/', [CourseController::class, 'noCourse'])->name('home'); Route::get('/course', [CourseController::class, 'noCourse']); @@ -152,6 +140,3 @@ Route::get('login/hitobito', [LoginController::class, 'redirectToHitobitoOAuth'])->name('login.hitobito'); Route::get('login/hitobito/callback', [LoginController::class, 'handleHitobitoOAuthCallback'])->name('login.hitobito.callback'); Route::get('locale/{locale}', [LocalizationController::class, 'select'])->name('locale.select'); - -Route::post('/error-report', [ErrorReportController::class, 'submit'])->name('errorReport.submit'); -Route::get('/error-report', [ErrorReportController::class, 'after'])->name('errorReport.after'); diff --git a/tests/CreatesApplication.php b/tests/CreatesApplication.php deleted file mode 100644 index cc683011..00000000 --- a/tests/CreatesApplication.php +++ /dev/null @@ -1,21 +0,0 @@ -make(Kernel::class)->bootstrap(); - - return $app; - } -} diff --git a/tests/Feature/Admin/Block/CreateBlockTest.php b/tests/Feature/Admin/Block/CreateBlockTest.php index ee20e8d4..205ac443 100644 --- a/tests/Feature/Admin/Block/CreateBlockTest.php +++ b/tests/Feature/Admin/Block/CreateBlockTest.php @@ -15,7 +15,7 @@ class CreateBlockTest extends TestCaseWithCourse { public function setUp(): void { parent::setUp(); - $this->payload = ['full_block_number' => '1.1', 'name' => 'Block 1', 'block_date' => '01.01.2019', 'requirements' => null]; + $this->payload = ['full_block_number' => '1.1', 'name' => 'Block 1', 'block_date' => '1.1.2019', 'requirements' => null]; } public function test_shouldRequireLogin() { diff --git a/tests/Feature/Admin/Block/GenerateBlockTest.php b/tests/Feature/Admin/Block/GenerateBlockTest.php index d9c4786b..9bc50891 100644 --- a/tests/Feature/Admin/Block/GenerateBlockTest.php +++ b/tests/Feature/Admin/Block/GenerateBlockTest.php @@ -15,7 +15,7 @@ class GenerateBlockTest extends TestCaseWithCourse { public function setUp(): void { parent::setUp(); - $this->payload = ['name' => 'SonstigesBlockGenTest', 'blocks_startdate' => '01.10.2023', 'blocks_enddate' => '07.10.2023', 'requirements' => null]; + $this->payload = ['name' => 'SonstigesBlockGenTest', 'blocks_startdate' => '1.10.2023', 'blocks_enddate' => '7.10.2023', 'requirements' => null]; } public function test_shouldRequireLogin() { diff --git a/tests/Feature/Admin/Block/ImportBlocksTest.php b/tests/Feature/Admin/Block/ImportBlocksTest.php index ae14870a..b7e5b8fb 100644 --- a/tests/Feature/Admin/Block/ImportBlocksTest.php +++ b/tests/Feature/Admin/Block/ImportBlocksTest.php @@ -3,16 +3,16 @@ namespace Tests\Feature\Admin\Block; use App\Exceptions\ECamp2BlockOverviewParsingException; -use App\Exceptions\Handler; use App\Exceptions\UnsupportedFormatException; use App\Models\Block; use App\Models\Observation; use App\Services\Import\SpreadsheetReaderFactory; -use Illuminate\Http\UploadedFile; use Illuminate\Testing\TestResponse; use Mockery; use PhpOffice\PhpSpreadsheet\Reader\Csv; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; +use Sentry\SentrySdk; +use Sentry\State\Hub; use Tests\ReadsSpreadsheets; use Tests\TestCaseWithCourse; @@ -63,10 +63,10 @@ public function test_shouldImportBlocks() { $response = $response->followRedirects(); $response->assertSeeInOrder([ 'In der importierten Datei wurden 4 Blöcke gefunden.', - 'Samstag 21.03.2026', + 'Samstag 21.3.2026', '1.1', 'Erster Block', '1.2', 'Zweiter Block am gleichen Tag', - 'Sonntag 22.03.2026', + 'Sonntag 22.3.2026', '2.1', 'Dritter Block am n\u00e4chsten Tag', '10.10', 'Mehrstellige Blocknummer' ]); @@ -122,7 +122,7 @@ public function test_shouldUpdateExistingBlocks_whenBlockNumberMatches() { $response = $response->followRedirects(); $response->assertDontSee('Existierender Block'); $response->assertDontSee('09.09.2009'); - $response->assertSeeInOrder(['Samstag 21.03.2026', '1.1', 'Erster Block', '1', '1.2', 'Zweiter Block am gleichen Tag', '0']); + $response->assertSeeInOrder(['Samstag 21.3.2026', '1.1', 'Erster Block', '1', '1.2', 'Zweiter Block am gleichen Tag', '0']); $connectedObservations = Block::where('day_number', '=', '1') ->where('block_number', '=', '1') ->where('course_id', '=', $this->courseId) @@ -169,10 +169,10 @@ public function test_shouldSupportXLSX() { $response = $response->followRedirects(); $response->assertSeeInOrder([ 'In der importierten Datei wurden 4 Blöcke gefunden.', - 'Samstag 21.03.2026', + 'Samstag 21.3.2026', '1.1', 'Erster Block', '1.2', 'Zweiter Block am gleichen Tag', - 'Sonntag 22.03.2026', + 'Sonntag 22.3.2026', '2.1', 'Dritter Block am n\u00e4chsten Tag', '10.10', 'Mehrstellige Blocknummer' ]); @@ -194,10 +194,10 @@ public function test_shouldSupportCSV() { $response = $response->followRedirects(); $response->assertSeeInOrder([ 'In der importierten Datei wurden 4 Blöcke gefunden.', - 'Samstag 21.03.2026', + 'Samstag 21.3.2026', '1.1', 'Erster Block', '1.2', 'Zweiter Block am gleichen Tag', - 'Sonntag 22.03.2026', + 'Sonntag 22.3.2026', '2.1', 'Dritter Block am n\u00e4chsten Tag', '10.10', 'Mehrstellige Blocknummer' ]); @@ -257,9 +257,11 @@ public function test_shouldReportUnknownErrorToTheUserAndToSentry() { $this->payload = ['file' => $uploadedFile, 'source' => 'eCamp2BlockOverview']; $this->instance(SpreadsheetReaderFactory::class, $factoryMock); - $this->mock(Handler::class, function ($mock) { - $mock->shouldReceive('report')->once(); - }); + + // Spy on Sentry to check the exception is reported + $sentryHubMock = $this->createMock(Hub::class); + $sentryHubMock->expects(self::once())->method('captureException')->willReturn(null); + SentrySdk::setCurrentHub($sentryHubMock); // when $response = $this->post('/course/' . $this->courseId . '/admin/blocks/import', $this->payload); diff --git a/tests/Feature/Admin/Participant/ImportParticipantsTest.php b/tests/Feature/Admin/Participant/ImportParticipantsTest.php index 161c6409..6c45510b 100644 --- a/tests/Feature/Admin/Participant/ImportParticipantsTest.php +++ b/tests/Feature/Admin/Participant/ImportParticipantsTest.php @@ -2,7 +2,6 @@ namespace Tests\Feature\Admin\Participant; -use App\Exceptions\Handler; use App\Exceptions\MiDataParticipantsListsParsingException; use App\Exceptions\UnsupportedFormatException; use App\Services\Import\SpreadsheetReaderFactory; @@ -11,6 +10,8 @@ use Mockery; use PhpOffice\PhpSpreadsheet\Reader\Csv; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; +use Sentry\SentrySdk; +use Sentry\State\Hub; use Tests\ReadsSpreadsheets; use Tests\TestCaseWithCourse; @@ -279,9 +280,11 @@ public function test_shouldReportUnknownErrorToTheUserAndToSentry() { $this->payload = ['file' => $uploadedFile, 'source' => 'MiDataParticipantList']; $this->instance(SpreadsheetReaderFactory::class, $factoryMock); - $this->mock(Handler::class, function ($mock) { - $mock->shouldReceive('report')->once(); - }); + + // Spy on Sentry to check the exception is reported + $sentryHubMock = $this->createMock(Hub::class); + $sentryHubMock->expects(self::once())->method('captureException')->willReturn(null); + SentrySdk::setCurrentHub($sentryHubMock); // when $response = $this->post('/course/' . $this->courseId . '/admin/participants/import', $this->payload); diff --git a/tests/Feature/App/RestoreFormDataWhenSessionExpiredTest.php b/tests/Feature/App/RestoreFormDataWhenSessionExpiredTest.php index 90a3f8ff..f0cf717f 100644 --- a/tests/Feature/App/RestoreFormDataWhenSessionExpiredTest.php +++ b/tests/Feature/App/RestoreFormDataWhenSessionExpiredTest.php @@ -2,9 +2,9 @@ namespace Tests\Feature\App; -use App\Http\Middleware\VerifyCsrfToken; use App\Models\HitobitoUser; use Closure; +use Illuminate\Foundation\Http\Middleware\ValidateCsrfToken; use Illuminate\Http\UploadedFile; use Illuminate\Testing\TestResponse; use Tests\Feature\Auth\HitobitoOAuthTest; @@ -200,11 +200,11 @@ public function checkRestorationOfFormData(Closure $logBackIn, bool $shouldResto } protected function fakeCSRFMiddleware() { - $this->app->bind(VerifyCsrfToken::class, TestVerifyCsrfToken::class); + $this->app->bind(ValidateCsrfToken::class, TestValidateCsrfToken::class); } } -class TestVerifyCsrfToken extends VerifyCsrfToken { +class TestValidateCsrfToken extends ValidateCsrfToken { /** * In this test, we want the CSRF protection to be active. diff --git a/tests/Feature/Auth/HitobitoOAuthTest.php b/tests/Feature/Auth/HitobitoOAuthTest.php index 1104d9c0..0660d916 100644 --- a/tests/Feature/Auth/HitobitoOAuthTest.php +++ b/tests/Feature/Auth/HitobitoOAuthTest.php @@ -251,6 +251,20 @@ public function test_nativeLogin_shouldFail_whenEmailBelongsToHitobitoUser() { $response->followRedirects()->assertSee('Dieses Login ist uns nicht bekannt. Meldest du dich vielleicht normalerweise mit MiData an?'); } + public function test_nativeLogin_shouldFail_whenEmailBelongsToHitobitoUser_andTinkeringWithSubmittedPassword() { + // given + $email = 'cosinus@hitobito.com'; + HitobitoUser::factory()->create(['name' => 'Cosinus', 'email' => $email]); + $this->get('/login'); + + // when + $response = $this->post('/login', ['email' => $email, 'password' => null]); + + // then + $response->assertRedirect('/login'); + $response->followRedirects()->assertSee('Passwort muss ausgefüllt sein.'); + } + public function test_passwordReset_shouldFail_whenEmailBelongsToHitobitoUser() { // given $email = 'cosinus@hitobito.com'; diff --git a/tests/Feature/ErrorReports/SentryTest.php b/tests/Feature/ErrorReports/SentryTest.php index 84404316..0d80503b 100644 --- a/tests/Feature/ErrorReports/SentryTest.php +++ b/tests/Feature/ErrorReports/SentryTest.php @@ -4,22 +4,18 @@ use App\Http\Requests\UserRequest; use Illuminate\Validation\ValidationException; -use Mockery; -use Sentry\EventId; use Sentry\SentrySdk; +use Sentry\State\Hub; use Tests\TestCase; class SentryTest extends TestCase { - public function test_shouldReportErrorToSentry_andDisplayErrorForm_when500ErrorOccurs() { + public function test_shouldReportErrorToSentry_when500ErrorOccurs() { // given - $sentryMock = Mockery::mock(app('sentry')); - // Stupid fix because mockery ->passthru() doesn't work here for some reason - $sentryMock->shouldReceive('captureException')->once()->andReturnUsing(function(...$args) use($sentryMock) { - SentrySdk::getCurrentHub()->captureException(...$args); - $sentryMock->shouldReceive('getLastEventId')->andReturn(new EventId('12341234123412341234123412341234')); - }); - $this->instance('sentry', $sentryMock); + // Spy on Sentry to check the exception is reported + $sentryHubMock = $this->createMock(Hub::class); + $sentryHubMock->expects(self::once())->method('captureException')->willReturn(null); + SentrySdk::setCurrentHub($sentryHubMock); // Force an exception $requestMock = $this->createPartialMock(UserRequest::class, [ 'validated', 'file' ]); @@ -32,14 +28,15 @@ public function test_shouldReportErrorToSentry_andDisplayErrorForm_when500ErrorO // then $response->assertStatus(500); - $response->assertSeeText('Es sieht so aus als hätten wir ein Problem.'); + $response->assertSeeText('Bitte versuche es später nochmals.'); } public function test_shouldNotReportErrorToSentry_orDisplayErrorForm_whenValidationErrorOccurs() { // given - $sentryMock = Mockery::mock(app('sentry')); - $sentryMock->shouldNotReceive('captureException'); - $this->instance('sentry', $sentryMock); + // Spy on Sentry to check the exception isn't reported + $sentryHubMock = $this->createMock(Hub::class); + $sentryHubMock->expects(self::never())->method('captureException'); + SentrySdk::setCurrentHub($sentryHubMock); // Force an exception $requestMock = $this->createPartialMock(UserRequest::class, [ 'validated', 'file' ]); @@ -57,9 +54,10 @@ public function test_shouldNotReportErrorToSentry_orDisplayErrorForm_whenValidat public function test_shouldNotReportErrorToSentry_orDisplayErrorForm_whenNoErrorOccurs() { // given - $sentryMock = Mockery::mock(app('sentry')); - $sentryMock->shouldNotReceive('captureException'); - $this->instance('sentry', $sentryMock); + // Spy on Sentry to check the exception isn't reported + $sentryHubMock = $this->createMock(Hub::class); + $sentryHubMock->expects(self::never())->method('captureException'); + SentrySdk::setCurrentHub($sentryHubMock); // when $response = $this->get('/'); diff --git a/tests/Feature/ErrorReports/SubmitErrorReportTest.php b/tests/Feature/ErrorReports/SubmitErrorReportTest.php deleted file mode 100644 index 80f622fb..00000000 --- a/tests/Feature/ErrorReports/SubmitErrorReportTest.php +++ /dev/null @@ -1,39 +0,0 @@ -mock(GuzzleHttp\Client::class, function ($mock) { - $mock->shouldReceive('post')->with('https://sentry.io/api/0/projects/xyz/xyz/user-feedback/', [ - 'headers' => ['Authorization' => 'DSN https://123412341234123412341234@sentry.io/12345'], - 'form_params' => [ - 'event_id' => '1234', - 'name' => 'Bari', - 'email' => 'email@email.com', - 'comments' => 'Ich habe so ein bitzli im Qualix herumgeklickt, und dann BÄM!', - ] - ]); - }); - - // when - $response = $this->post('/error-report', [ - 'eventId' => '1234', - 'previousUrl' => 'https://previous.com', - 'name' => 'Bari', - 'email' => 'email@email.com', - 'description' => 'Ich habe so ein bitzli im Qualix herumgeklickt, und dann BÄM!', - ]); - - // then - $response->assertStatus(302); - $response->assertLocation('/error-report'); - $response = $response->followRedirects(); - $response->assertSeeText('Deine Beschreibung wurde abgesendet. Vielen Dank!'); - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php index 1cac857a..da80abb8 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -18,7 +18,6 @@ use Symfony\Component\DomCrawler\Crawler; abstract class TestCase extends BaseTestCase { - use CreatesApplication; use DatabaseTransactions; /** @var Crawler $crawler */