From b48c689d313331c3ef042a831b9121e331c9532e Mon Sep 17 00:00:00 2001 From: Bandie Date: Mon, 6 Apr 2026 15:03:15 +0200 Subject: [PATCH] =?UTF-8?q?PDF-Generator=20f=C3=BCr=20Eventschluss;=20CSRF?= =?UTF-8?q?-Protection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/PreApplicationController.php | 37 +- app/Http/Middleware/ForceCsrfOnLocalhost.php | 38 ++ bootstrap/app.php | 4 + composer.json | 1 + composer.lock | 447 +++++++++++++++++- lang/de/app.php | 7 +- lang/en/app.php | 7 +- resources/views/application/edit.blade.php | 16 + resources/views/layout/app.blade.php | 8 + resources/views/pdf/pre_application.blade.php | 93 ++++ routes/web.php | 1 + 11 files changed, 654 insertions(+), 5 deletions(-) create mode 100644 app/Http/Middleware/ForceCsrfOnLocalhost.php create mode 100644 resources/views/pdf/pre_application.blade.php diff --git a/app/Http/Controllers/PreApplicationController.php b/app/Http/Controllers/PreApplicationController.php index 6f29a7f..f1e14fc 100644 --- a/app/Http/Controllers/PreApplicationController.php +++ b/app/Http/Controllers/PreApplicationController.php @@ -10,8 +10,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Mail; -use Log; -use Nette\Utils\Random; +use Dompdf\Dompdf; class PreApplicationController extends Controller { @@ -159,4 +158,38 @@ class PreApplicationController extends Controller } abort(404); } + + public function generatePDF(Request $request){ + if(Auth::check()){ + if(!$request->has('event_id')){ + return ["messageStatus" => "failure", "errorMessage" => __("controller_messages.PreApplicationController.event_id_missing")]; + } + + $event = ChaosEvents::find($request->input('event_id')); + + if(!$event){ + return ["messageStatus" => "failure", "errorMessage" => __("controller_messages.PreApplicationController.event_not_found")]; + } + if($event->active == 0 || $event->to_date_internal < today()){ + return ["messageStatus" => "failure", "errorMessage" => __("controller_messages.PreApplicationController.event_not_active")]; + } + + + $options = new \Dompdf\Options(); + $options->set('isRemoteEnabled', true); + $options->set('isHtml5ParserEnabled', true); + $options->set('chroot', public_path()); + $dompdf = new Dompdf($options); + $dompdf->setPaper('A4', 'portrait'); + + $applications = PreApplications::where('event_id', $request->input('event_id'))->get(); + $dompdf->loadHtml(view('pdf.pre_application', ['applications' => $applications, 'event' => $event])); + + $dompdf->render(); + + $dompdf->stream('Voranträge_' . $event->shortname . '_' . $event->from_date_visible->format('Y') . '.pdf', ['Attachment' => 0]); + exit; + } + abort(404); + } } diff --git a/app/Http/Middleware/ForceCsrfOnLocalhost.php b/app/Http/Middleware/ForceCsrfOnLocalhost.php new file mode 100644 index 0000000..eafb999 --- /dev/null +++ b/app/Http/Middleware/ForceCsrfOnLocalhost.php @@ -0,0 +1,38 @@ +isLocalhost($request)) { + return false; + } + + return parent::hasValidOrigin($request); + } + + /** + * Determine if the request is from localhost. + * + * @param \Illuminate\Http\Request $request + * @return bool + */ + protected function isLocalhost($request) + { + $host = $request->getHost(); + + return in_array($host, ['localhost', '127.0.0.1', '::1']) || str_ends_with($host, '.localhost'); + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index 95b6d22..7ce9104 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -3,6 +3,7 @@ use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; +use Illuminate\Foundation\Http\Middleware\PreventRequestsDuringMaintenance; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( @@ -11,6 +12,9 @@ return Application::configure(basePath: dirname(__DIR__)) health: '/up', ) ->withMiddleware(function (Middleware $middleware): void { + $middleware->web(replace: [ + \Illuminate\Foundation\Http\Middleware\PreventRequestForgery::class => \App\Http\Middleware\ForceCsrfOnLocalhost::class, + ]); $middleware->append(\App\Http\Middleware\SetLocale::class); }) ->withExceptions(function (Exceptions $exceptions): void { diff --git a/composer.json b/composer.json index c869916..e2e1068 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "license": "MIT", "require": { "php": "^8.3", + "dompdf/dompdf": "v3.1.5", "laravel/framework": "^13.0", "laravel/tinker": "^3.0" }, diff --git a/composer.lock b/composer.lock index 6ae3caa..6e42bbe 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "41c3f2f807c63a47595eaa4e14742655", + "content-hash": "574a1d636a4f2db2df7b156d94d141bb", "packages": [ { "name": "brick/math", @@ -377,6 +377,161 @@ ], "time": "2024-02-05T11:56:58+00:00" }, + { + "name": "dompdf/dompdf", + "version": "v3.1.5", + "source": { + "type": "git", + "url": "https://github.com/dompdf/dompdf.git", + "reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496", + "reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496", + "shasum": "" + }, + "require": { + "dompdf/php-font-lib": "^1.0.0", + "dompdf/php-svg-lib": "^1.0.0", + "ext-dom": "*", + "ext-mbstring": "*", + "masterminds/html5": "^2.0", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "ext-gd": "*", + "ext-json": "*", + "ext-zip": "*", + "mockery/mockery": "^1.3", + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0" + }, + "suggest": { + "ext-gd": "Needed to process images", + "ext-gmagick": "Improves image processing performance", + "ext-imagick": "Improves image processing performance", + "ext-zlib": "Needed for pdf stream compression" + }, + "type": "library", + "autoload": { + "psr-4": { + "Dompdf\\": "src/" + }, + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "The Dompdf Community", + "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" + } + ], + "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", + "homepage": "https://github.com/dompdf/dompdf", + "support": { + "issues": "https://github.com/dompdf/dompdf/issues", + "source": "https://github.com/dompdf/dompdf/tree/v3.1.5" + }, + "time": "2026-03-03T13:54:37+00:00" + }, + { + "name": "dompdf/php-font-lib", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-font-lib.git", + "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a", + "reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12" + }, + "type": "library", + "autoload": { + "psr-4": { + "FontLib\\": "src/FontLib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "The FontLib Community", + "homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse, export and make subsets of different types of font files.", + "homepage": "https://github.com/dompdf/php-font-lib", + "support": { + "issues": "https://github.com/dompdf/php-font-lib/issues", + "source": "https://github.com/dompdf/php-font-lib/tree/1.0.2" + }, + "time": "2026-01-20T14:10:26+00:00" + }, + { + "name": "dompdf/php-svg-lib", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/dompdf/php-svg-lib.git", + "reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8259ffb930817e72b1ff1caef5d226501f3dfeb1", + "reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0", + "sabberworm/php-css-parser": "^8.4 || ^9.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11" + }, + "type": "library", + "autoload": { + "psr-4": { + "Svg\\": "src/Svg" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "The SvgLib Community", + "homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md" + } + ], + "description": "A library to read, parse and export to PDF SVG files.", + "homepage": "https://github.com/dompdf/php-svg-lib", + "support": { + "issues": "https://github.com/dompdf/php-svg-lib/issues", + "source": "https://github.com/dompdf/php-svg-lib/tree/1.0.2" + }, + "time": "2026-01-02T16:01:13+00:00" + }, { "name": "dragonmantank/cron-expression", "version": "v3.6.0", @@ -2022,6 +2177,73 @@ ], "time": "2026-03-08T20:05:35+00:00" }, + { + "name": "masterminds/html5", + "version": "2.10.0", + "source": { + "type": "git", + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "fcf91eb64359852f00d921887b219479b4f21251" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Masterminds\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matt Butcher", + "email": "technosophos@gmail.com" + }, + { + "name": "Matt Farina", + "email": "matt@mattfarina.com" + }, + { + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" + } + ], + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], + "support": { + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" + }, + "time": "2025-07-25T09:04:22+00:00" + }, { "name": "monolog/monolog", "version": "3.10.0", @@ -3297,6 +3519,86 @@ }, "time": "2025-12-14T04:43:48+00:00" }, + { + "name": "sabberworm/php-css-parser", + "version": "v9.3.0", + "source": { + "type": "git", + "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", + "reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/extension-installer": "1.4.3", + "phpstan/phpstan": "1.12.32 || 2.1.32", + "phpstan/phpstan-phpunit": "1.4.2 || 2.0.8", + "phpstan/phpstan-strict-rules": "1.6.2 || 2.0.7", + "phpunit/phpunit": "8.5.52", + "rawr/phpunit-data-provider": "3.3.1", + "rector/rector": "1.2.10 || 2.2.8", + "rector/type-perfect": "1.0.0 || 2.1.0", + "squizlabs/php_codesniffer": "4.0.1", + "thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.1" + }, + "suggest": { + "ext-mbstring": "for parsing UTF-8 CSS" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "9.4.x-dev" + } + }, + "autoload": { + "files": [ + "src/Rule/Rule.php", + "src/RuleSet/RuleContainer.php" + ], + "psr-4": { + "Sabberworm\\CSS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Raphael Schweikert" + }, + { + "name": "Oliver Klee", + "email": "github@oliverklee.de" + }, + { + "name": "Jake Hotson", + "email": "jake.github@qzdesign.co.uk" + } + ], + "description": "Parser for CSS Files written in PHP", + "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", + "keywords": [ + "css", + "parser", + "stylesheet" + ], + "support": { + "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.3.0" + }, + "time": "2026-03-03T17:31:43+00:00" + }, { "name": "symfony/clock", "version": "v8.0.0", @@ -5666,6 +5968,149 @@ ], "time": "2026-02-15T10:53:29+00:00" }, + { + "name": "thecodingmachine/safe", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19", + "reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "^10", + "squizlabs/php_codesniffer": "^3.2" + }, + "type": "library", + "autoload": { + "files": [ + "lib/special_cases.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gettext.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/mysql.php", + "generated/mysqli.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rnp.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "classmap": [ + "lib/DateTime.php", + "lib/DateTimeImmutable.php", + "lib/Exceptions/", + "generated/Exceptions/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/OskarStark", + "type": "github" + }, + { + "url": "https://github.com/shish", + "type": "github" + }, + { + "url": "https://github.com/silasjoisten", + "type": "github" + }, + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2026-02-04T18:08:13+00:00" + }, { "name": "tijsverkoyen/css-to-inline-styles", "version": "v2.4.0", diff --git a/lang/de/app.php b/lang/de/app.php index 113c9f6..76f156f 100644 --- a/lang/de/app.php +++ b/lang/de/app.php @@ -146,7 +146,12 @@ return [ 'add' => 'Antrag hinzufügen', 'save' => 'Speichern', 'delete' => 'Löschen', - 'generated' => 'Wird generiert' + 'generated' => 'Wird generiert', + 'download' => [ + 'title' => 'Voranträge herunterladen', + 'description' => 'Hier können Sie alle Voranträge eines Bezirksregion-Termines als PDF herunterladen.', + 'button' => 'PDF generieren' + ] ] ], 'common' => [ diff --git a/lang/en/app.php b/lang/en/app.php index 5bfa88b..888c710 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -146,7 +146,12 @@ return [ 'add' => 'Add application', 'save' => 'Save', 'delete' => 'Delete', - 'generated' => 'Generated' + 'generated' => 'Generated', + 'download' => [ + 'title' => 'Download pre-applications', + 'description' => 'Here you can download all pre-applications of a district region appointment as a PDF.', + 'button' => 'Generate PDF' + ] ] ], 'common' => [ diff --git a/resources/views/application/edit.blade.php b/resources/views/application/edit.blade.php index 37b6e8f..ded2fb5 100644 --- a/resources/views/application/edit.blade.php +++ b/resources/views/application/edit.blade.php @@ -21,6 +21,22 @@ @endsection @section('content') +

{{ __('app.preapplication.edit.download.title') }}

+

{{ __('app.preapplication.edit.download.description') }}

+
+
+ + +

+ +
+
+

+

{{ __("app.preapplication.edit.title") }}

{{ __("app.preapplication.edit.description") }}

diff --git a/resources/views/layout/app.blade.php b/resources/views/layout/app.blade.php index a1c5b6a..b99fa74 100644 --- a/resources/views/layout/app.blade.php +++ b/resources/views/layout/app.blade.php @@ -4,10 +4,18 @@ C3Gov - {{ __('app.subtitle') }} + + @yield('scripts') diff --git a/resources/views/pdf/pre_application.blade.php b/resources/views/pdf/pre_application.blade.php new file mode 100644 index 0000000..5313f7b --- /dev/null +++ b/resources/views/pdf/pre_application.blade.php @@ -0,0 +1,93 @@ +@php + $logoPath = public_path('Dokumente/c3govsticker.png'); + $logoData = base64_encode(file_get_contents($logoPath)); + $logoSrc = 'data:image/png;base64,' . $logoData; +@endphp + + + + Voranträge + + + + +
+

Voranträge gem. § 5 C3GovVerwV für die (temporäre) Bz.Reg.-Erw.

+

{{ $event->name }}

+

der Bezirksregion CCC

+

Gültig vom {{ $event->from_date_visible->toDateString() }} bis einschließlich dem {{ $event->to_date_visible->toDateString() }}

+ +
+ @foreach($applications as $application) +
+
+ +

Vorantrag {{ $application->reference_number }}

+

+

Folgende Entität hat einen Vorantrag gemäß § 5 C3GovVerwV gestellt:

+

+ + + + + + + + + + + + + + + + + + + + + +
Vorname:{{ $application->first_name }}
Nachname:{{ $application->last_name }}
Ort/Hackspace:{{ $application->location }}
Datenbankerfassung am:{{ $application->created_at }}
Interne Notizen:{{ $application->notes }}
+

+

Obige Angaben sind vor Ausstellung zu prüfen und mittels Formblatt 5 zu genehmigen.

+


+
+
Bearbeitungsvermerke
+ +
+
+
+ @endforeach + + diff --git a/routes/web.php b/routes/web.php index b773eee..1833c95 100644 --- a/routes/web.php +++ b/routes/web.php @@ -43,6 +43,7 @@ Route::delete('/intern/nachrichten/delete', [BlogController::class, 'deleteBlog' Route::put('/intern/nachrichten/edit', [BlogController::class, 'editBlog']); Route::get('/intern/antraege', [WebsiteController::class, 'editApplications'])->name('editApplications'); +Route::get('/intern/antraege/generate-pdf', [PreApplicationController::class, 'generatePDF'])->name('generatePDF'); Route::post('/intern/antraege/hinzufuegen', [PreApplicationController::class, 'addApplication']); Route::delete('/intern/antraege/loeschen', [PreApplicationController::class, 'deleteApplication']); Route::put('/intern/antraege/bearbeiten', [PreApplicationController::class, 'editApplication']);