├── .php-cs-fixer.dist.php ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── art ├── socialcard-dark.png └── socialcard-light.png ├── composer.json ├── config └── legal-consent.php ├── database ├── factories │ ├── AdminFactory.php │ ├── LegalDocumentFactory.php │ └── UserFactory.php └── migrations │ └── create_legal_consent_tables.php.stub ├── routes └── routes.php └── src ├── DefaultLegalDocumentFinder.php ├── Exceptions └── InvalidDocumentTypeException.php ├── HasLegalConsent.php ├── Http ├── Controllers │ ├── LegalConsentController.php │ └── LegalDocumentController.php └── Resources │ └── LegalDocumentResource.php ├── LegalConsentServiceProvider.php ├── LegalDocumentFinder.php ├── Listeners └── AcceptLegalDocumentListener.php └── Models ├── LegalConsent.php └── LegalDocument.php /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in([ 5 | __DIR__ . '/src', 6 | __DIR__ . '/tests', 7 | ]) 8 | ->name('*.php') 9 | ->notName('*.blade.php') 10 | ->ignoreDotFiles(true) 11 | ->ignoreVCS(true); 12 | 13 | return (new PhpCsFixer\Config()) 14 | ->setRules([ 15 | '@PSR12' => true, 16 | 'array_syntax' => ['syntax' => 'short'], 17 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 18 | 'no_unused_imports' => true, 19 | 'not_operator_with_successor_space' => true, 20 | 'trailing_comma_in_multiline' => true, 21 | 'phpdoc_scalar' => true, 22 | 'unary_operator_spaces' => true, 23 | 'binary_operator_spaces' => true, 24 | 'blank_line_before_statement' => [ 25 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 26 | ], 27 | 'phpdoc_single_line_var_spacing' => true, 28 | 'phpdoc_var_without_name' => true, 29 | 'method_argument_space' => [ 30 | 'on_multiline' => 'ensure_fully_multiline', 31 | 'keep_multiple_spaces_after_comma' => true, 32 | ], 33 | 'single_trait_insert_per_statement' => true, 34 | ]) 35 | ->setFinder($finder); 36 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-legal-consent` will be documented in this file. 4 | 5 | ## 3.2.0 - 2024-03-27 6 | 7 | ### What's Changed 8 | 9 | * UPDATE php8.3 by @enricodelazzari in https://github.com/maize-tech/laravel-legal-consent/pull/20 10 | * Laravel 11 by @enricodelazzari in https://github.com/maize-tech/laravel-legal-consent/pull/23 11 | 12 | ## 3.1.0 - 2023-02-13 13 | 14 | ### What's Changed 15 | 16 | - Add support to Laravel 10.x 17 | 18 | ## 3.0.0 - 2023-01-12 19 | 20 | ADD polymorphic relation to legal consent model and migration to allow multiple user types 21 | 22 | ## 2.0.0 - 2022-02-16 23 | 24 | - add laravel 9 support 25 | - drop support to older laravel versions 26 | 27 | ## 1.0.0 - 2022-02-16 28 | 29 | First release 🚀 30 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 MAIZE SRL 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | Social Card of Laravel Legal Consent 6 | 7 |

8 | 9 | # Laravel Legal Consent 10 | 11 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/maize-tech/laravel-legal-consent.svg?style=flat-square)](https://packagist.org/packages/maize-tech/laravel-legal-consent) 12 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/maize-tech/laravel-legal-consent/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/maize-tech/laravel-legal-consent/actions?query=workflow%3Arun-tests+branch%3Amain) 13 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/maize-tech/laravel-legal-consent/php-cs-fixer.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/maize-tech/laravel-legal-consent/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain) 14 | [![Total Downloads](https://img.shields.io/packagist/dt/maize-tech/laravel-legal-consent.svg?style=flat-square)](https://packagist.org/packages/maize-tech/laravel-legal-consent) 15 | 16 | Easily integrate legal documents (like privacy policies, terms of use, etc.) to your application. 17 | 18 | ## Installation 19 | 20 | You can install the package via composer: 21 | 22 | ```bash 23 | composer require maize-tech/laravel-legal-consent 24 | ``` 25 | 26 | You can publish and run the migrations with: 27 | 28 | ```bash 29 | php artisan vendor:publish --tag="legal-consent-migrations" 30 | php artisan migrate 31 | ``` 32 | 33 | You can publish the config file with: 34 | ```bash 35 | php artisan vendor:publish --tag="legal-consent-config" 36 | ``` 37 | 38 | This is the content of the published config file: 39 | 40 | ```php 41 | return [ 42 | /* 43 | |-------------------------------------------------------------------------- 44 | | Legal document model 45 | |-------------------------------------------------------------------------- 46 | | 47 | | Here you may specify the fully qualified class name of the legal document model. 48 | | 49 | */ 50 | 51 | 'legal_document_model' => Maize\LegalConsent\Models\LegalDocument::class, 52 | 53 | /* 54 | |-------------------------------------------------------------------------- 55 | | Legal consent model 56 | |-------------------------------------------------------------------------- 57 | | 58 | | Here you may specify the fully qualified class name of the legal consent model. 59 | | 60 | */ 61 | 62 | 'legal_consent_model' => Maize\LegalConsent\Models\LegalConsent::class, 63 | 64 | /* 65 | |-------------------------------------------------------------------------- 66 | | Legal document finder 67 | |-------------------------------------------------------------------------- 68 | | 69 | | Here you may specify the fully qualified class name of the legal document finder class. 70 | | 71 | */ 72 | 73 | 'legal_document_finder' => Maize\LegalConsent\DefaultLegalDocumentFinder::class, 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Route configurations 78 | |-------------------------------------------------------------------------- 79 | | 80 | | Here you may specify whether routes should be enabled or not. 81 | | You can also customize the routes prefix and middlewares. 82 | | 83 | */ 84 | 85 | 'routes' => [ 86 | 'enabled' => true, 87 | 'prefix' => 'legal', 88 | 'name' => 'legal', 89 | 'middleware' => ['api'], 90 | 'endpoints' => [ 91 | 'show' => [ 92 | 'middleware' => [], 93 | ], 94 | 'consent' => [ 95 | 'middleware' => ['auth:api'], 96 | ], 97 | ], 98 | ], 99 | 100 | /* 101 | |-------------------------------------------------------------------------- 102 | | Allowed document types 103 | |-------------------------------------------------------------------------- 104 | | 105 | | Here you may specify the list of accepted legal document types 106 | | for all requests. 107 | | 108 | */ 109 | 110 | 'allowed_document_types' => [ 111 | // 112 | ], 113 | 114 | /* 115 | |-------------------------------------------------------------------------- 116 | | Allowed acceptable values 117 | |-------------------------------------------------------------------------- 118 | | 119 | | Here you may specify the list of accepted values for each legal document 120 | | consent request. 121 | | 122 | */ 123 | 124 | 'allowed_acceptable_values' => [ 125 | 'yes', 126 | 'on', 127 | '1', 128 | 1, 129 | true, 130 | 'true', 131 | ], 132 | 133 | /* 134 | |-------------------------------------------------------------------------- 135 | | Cache 136 | |-------------------------------------------------------------------------- 137 | | 138 | | Here you may specify the amount of time, in seconds, where each legal 139 | | document is cached to avoid multiple database queries. 140 | | 141 | */ 142 | 143 | 'cache' => [ 144 | 'document_ttl' => 3600, 145 | 'document_user_ttl' => 3600, 146 | ], 147 | ]; 148 | ``` 149 | 150 | ## Usage 151 | 152 | ### Basic 153 | 154 | To use the package, add the `Maize\LegalConsent\HasLegalConsent` trait to the all Authenticatable models you want to handle. 155 | 156 | Here's an example including the `HasLegalConsent` trait to both User and Admin models: 157 | 158 | ``` php 159 | [ 202 | 'privacy-policy', 203 | 'terms-of-use', 204 | ], 205 | ``` 206 | 207 | You can then create one or multiple documents from the DB or, if you wish, you could handle the creation with a CMS. 208 | 209 | Here are the fields who should be filled: 210 | - **type**: the document type name 211 | - **body**: the content of the document 212 | - **noted**: additional notes to show for the document 213 | - **published_at**: the date of publication for the given document 214 | 215 | Let's say we create a privacy policy document with the publication on 2021-01-01: here's the model entity we would have: 216 | 217 | ``` php 218 | $legalDocument = [ 219 | "id" => 1, 220 | "type" => "privacy-policy", 221 | "body" => "The privacy policy's very long text", 222 | "notes" => "", 223 | "published_at" => "2021-01-01", 224 | "updated_at" => "2021-01-01", 225 | "created_at" => "2021-01-01", 226 | ]; 227 | ``` 228 | 229 | You can now call the custom API to retrieve and accept the current document, which can be customized in `config/legal-consent.php`: 230 | 231 | #### GET - **/legal/documents/privacy-policy** 232 | 233 | This endpoint retrieves the current legal document using the given criteria: 234 | - the document type must be `privacy-policy` 235 | - the published_at date must be earlier than `now()` 236 | 237 | The document entries are then ordered by their published_at date in order to pick the latest one published. 238 | 239 | The response contains the document id (used for the POST route) along with all its information useful for rendering. 240 | Here is a sample response body: 241 | 242 | ``` json 243 | { 244 | "data": { 245 | "id": 1, 246 | "type": "privacy-policy", 247 | "body": "The privacy policy's very long text", 248 | "notes": "", 249 | "published_at": "2021-01-01" 250 | } 251 | } 252 | ``` 253 | 254 | #### POST - **/legal/documents/{id}** 255 | 256 | This endpoint stores the consent for the given document from the currently authenticated user. 257 | 258 | ### Legal Document Listener 259 | 260 | You can eventually accept all active legal documents using our listener. 261 | 262 | This can be useful, for example, when your application handles the registration of users, and they must accept all legal documents through a checkbox before proceeding. 263 | 264 | In this case, all you should do is add the listener to the `Registered` event in `EventServiceProvider`: 265 | 266 | ``` php 267 | use Maize\LegalConsent\Listeners\AcceptLegalDocumentListener; 268 | 269 | /** 270 | * The event listener mappings for the application. 271 | * 272 | * @var array 273 | */ 274 | protected $listen = [ 275 | Registered::class => [ 276 | AcceptLegalDocumentListener::class, // all currently active legal documents will be accepted 277 | SendEmailVerificationNotification::class, 278 | ], 279 | ]; 280 | ``` 281 | 282 | ## Testing 283 | 284 | ```bash 285 | composer test 286 | ``` 287 | 288 | ## Changelog 289 | 290 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 291 | 292 | ## Contributing 293 | 294 | Please see [CONTRIBUTING](https://github.com/maize-tech/.github/blob/main/CONTRIBUTING.md) for details. 295 | 296 | ## Security Vulnerabilities 297 | 298 | Please review [our security policy](https://github.com/maize-tech/.github/security/policy) on how to report security vulnerabilities. 299 | 300 | ## Credits 301 | 302 | - [Enrico De Lazzari](https://github.com/enricodelazzari) 303 | - [All Contributors](../../contributors) 304 | 305 | ## License 306 | 307 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 308 | -------------------------------------------------------------------------------- /art/socialcard-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maize-tech/laravel-legal-consent/6dbb10b085541c65388c4bb70f9b803681cd275e/art/socialcard-dark.png -------------------------------------------------------------------------------- /art/socialcard-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maize-tech/laravel-legal-consent/6dbb10b085541c65388c4bb70f9b803681cd275e/art/socialcard-light.png -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "maize-tech/laravel-legal-consent", 3 | "description": "Laravel Legal Consent", 4 | "keywords": [ 5 | "maize-tech", 6 | "laravel", 7 | "legal", 8 | "consent" 9 | ], 10 | "homepage": "https://github.com/maize-tech/laravel-legal-consent", 11 | "license": "MIT", 12 | "authors": [ 13 | { 14 | "name": "Enrico De Lazzari", 15 | "email": "enrico.delazzari@maize.io", 16 | "role": "Developer" 17 | } 18 | ], 19 | "require": { 20 | "php": "^8.0", 21 | "ext-json": "*", 22 | "illuminate/database": "^9.0|^10.0|^11.0", 23 | "illuminate/http": "^9.0|^10.0|^11.0", 24 | "illuminate/routing": "^9.0|^10.0|^11.0", 25 | "illuminate/support": "^9.0|^10.0|^11.0", 26 | "spatie/laravel-package-tools": "^1.14.1" 27 | }, 28 | "require-dev": { 29 | "friendsofphp/php-cs-fixer": "^3.4", 30 | "orchestra/testbench": "^7.0|^8.0|^9.0", 31 | "phpunit/phpunit": "^9.5|^10.5", 32 | "vimeo/psalm": "^4.20|^5.22" 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "Maize\\LegalConsent\\": "src", 37 | "Maize\\LegalConsent\\Database\\Factories\\": "database/factories" 38 | } 39 | }, 40 | "autoload-dev": { 41 | "psr-4": { 42 | "Maize\\LegalConsent\\Tests\\": "tests" 43 | } 44 | }, 45 | "scripts": { 46 | "format": "vendor/bin/php-cs-fixer fix --allow-risky=yes", 47 | "psalm": "vendor/bin/psalm", 48 | "test": "vendor/bin/phpunit --colors=always", 49 | "test-coverage": "vendor/bin/phpunit --coverage-html coverage" 50 | }, 51 | "config": { 52 | "sort-packages": true 53 | }, 54 | "extra": { 55 | "laravel": { 56 | "providers": [ 57 | "Maize\\LegalConsent\\LegalConsentServiceProvider" 58 | ] 59 | } 60 | }, 61 | "minimum-stability": "dev", 62 | "prefer-stable": true 63 | } 64 | -------------------------------------------------------------------------------- /config/legal-consent.php: -------------------------------------------------------------------------------- 1 | Maize\LegalConsent\Models\LegalDocument::class, 14 | 15 | /* 16 | |-------------------------------------------------------------------------- 17 | | Legal consent model 18 | |-------------------------------------------------------------------------- 19 | | 20 | | Here you may specify the fully qualified class name of the legal consent model. 21 | | 22 | */ 23 | 24 | 'legal_consent_model' => Maize\LegalConsent\Models\LegalConsent::class, 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Legal document finder 29 | |-------------------------------------------------------------------------- 30 | | 31 | | Here you may specify the fully qualified class name of the legal document finder class. 32 | | 33 | */ 34 | 35 | 'legal_document_finder' => Maize\LegalConsent\DefaultLegalDocumentFinder::class, 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Route configurations 40 | |-------------------------------------------------------------------------- 41 | | 42 | | Here you may specify whether routes should be enabled or not. 43 | | You can also customize the routes prefix and middlewares. 44 | | 45 | */ 46 | 47 | 'routes' => [ 48 | 'enabled' => true, 49 | 'prefix' => 'legal', 50 | 'name' => 'legal', 51 | 'middleware' => ['api'], 52 | 'endpoints' => [ 53 | 'show' => [ 54 | 'middleware' => [], 55 | ], 56 | 'consent' => [ 57 | 'middleware' => ['auth:api'], 58 | ], 59 | ], 60 | ], 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Allowed document types 65 | |-------------------------------------------------------------------------- 66 | | 67 | | Here you may specify the list of accepted legal document types 68 | | for all requests. 69 | | 70 | */ 71 | 72 | 'allowed_document_types' => [ 73 | // 74 | ], 75 | 76 | /* 77 | |-------------------------------------------------------------------------- 78 | | Allowed acceptable values 79 | |-------------------------------------------------------------------------- 80 | | 81 | | Here you may specify the list of accepted values for each legal document 82 | | consent request. 83 | | 84 | */ 85 | 86 | 'allowed_acceptable_values' => [ 87 | 'yes', 88 | 'on', 89 | '1', 90 | 1, 91 | true, 92 | 'true', 93 | ], 94 | 95 | /* 96 | |-------------------------------------------------------------------------- 97 | | Cache 98 | |-------------------------------------------------------------------------- 99 | | 100 | | Here you may specify the amount of time, in seconds, where each legal 101 | | document is cached to avoid multiple database queries. 102 | | 103 | */ 104 | 105 | 'cache' => [ 106 | 'document_ttl' => 3600, 107 | 'document_user_ttl' => 3600, 108 | ], 109 | ]; 110 | -------------------------------------------------------------------------------- /database/factories/AdminFactory.php: -------------------------------------------------------------------------------- 1 | 'tos', 16 | 'body' => $this->faker->randomHtml(), 17 | 'notes' => $this->faker->randomHtml(), 18 | 'published_at' => null, 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | id(); 13 | $table->string('type'); 14 | $table->mediumText('body'); 15 | $table->string('notes'); 16 | $table->dateTime('published_at')->nullable(); 17 | $table->timestamps(); 18 | }); 19 | 20 | Schema::create('legal_consents', function (Blueprint $table) { 21 | $table->foreignId('document_id')->constrained('legal_documents')->cascadeOnUpdate()->cascadeOnDelete(); 22 | $table->morphs('user'); 23 | $table->timestamps(); 24 | }); 25 | } 26 | 27 | public function down() 28 | { 29 | Schema::dropIfExists('legal_consents'); 30 | Schema::dropIfExists('legal_documents'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /routes/routes.php: -------------------------------------------------------------------------------- 1 | $prefix, 15 | 'as' => Str::finish($name, '.'), 16 | 'middleware' => $middleware, 17 | ], function () { 18 | 19 | Route::get('documents/{type}', LegalDocumentController::class) 20 | ->name('documents.show') 21 | ->middleware( 22 | config('legal-consent.routes.endpoints.show.middleware') 23 | ); 24 | 25 | Route::post('documents/{document}', LegalConsentController::class) 26 | ->name('documents.consent') 27 | ->middleware( 28 | config('legal-consent.routes.endpoints.consent.middleware') 29 | ); 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /src/DefaultLegalDocumentFinder.php: -------------------------------------------------------------------------------- 1 | where('type', $type) 14 | ->whereDate('published_at', '<=', Carbon::now()) 15 | ->latest('published_at'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidDocumentTypeException.php: -------------------------------------------------------------------------------- 1 | $model->legalConsents()->delete() 15 | ); 16 | } 17 | 18 | public function legalConsents(): MorphMany 19 | { 20 | return $this->morphMany( 21 | config('legal-consent.legal_consent_model'), 22 | 'user' 23 | ); 24 | } 25 | 26 | public function hasAcceptedDefaultLegalDocument(string $type): bool 27 | { 28 | $document = $this->findDefaultLegalDocumentForType($type); 29 | 30 | if (is_null($document)) { 31 | return true; 32 | } 33 | 34 | return $this->hasAcceptedLegalDocument($document); 35 | } 36 | 37 | public function hasAcceptedLegalDocument(LegalDocument $document): bool 38 | { 39 | return Cache::remember( 40 | $this->legalCacheKey($document), 41 | config('legal-consent.cache.document_user_ttl'), 42 | fn () => $this 43 | ->legalConsents() 44 | ->where('document_id', $document->getKey()) 45 | ->exists() 46 | ); 47 | } 48 | 49 | protected function legalCacheKey(LegalDocument $document): string 50 | { 51 | return "legal.documents.{$document->getKey()}.{$this->getMorphClass()}.{$this->getKey()}"; 52 | } 53 | 54 | public function acceptDefaultLegalDocument(string $type): void 55 | { 56 | $document = $this->findDefaultLegalDocumentForType($type); 57 | 58 | $this->acceptLegalDocument($document); 59 | } 60 | 61 | public function acceptLegalDocument(LegalDocument $document): void 62 | { 63 | $this->legalConsents()->firstOrCreate([ 64 | 'document_id' => $document->getKey(), 65 | ]); 66 | 67 | Cache::forget( 68 | $this->legalCacheKey($document) 69 | ); 70 | } 71 | 72 | protected function findDefaultLegalDocumentForType(string $type): ?LegalDocument 73 | { 74 | $finderClass = config('legal-consent.legal_document_finder'); 75 | 76 | return app($finderClass)->findForType($type); 77 | } 78 | 79 | public function acceptDefaultLegalDocumentsFromRequest(): void 80 | { 81 | $types = config('legal-consent.allowed_document_types'); 82 | 83 | foreach ($types as $type) { 84 | $this->acceptDefaultLegalDocumentFromRequest($type); 85 | } 86 | } 87 | 88 | public function acceptDefaultLegalDocumentFromRequest(string $type): void 89 | { 90 | if ($this->hasAcceptedFromRequest($type)) { 91 | $this->acceptDefaultLegalDocument($type); 92 | } 93 | } 94 | 95 | protected function hasAcceptedFromRequest(string $type): bool 96 | { 97 | $value = request()->get("{$type}_accepted"); 98 | 99 | return in_array( 100 | $value, 101 | config('legal-consent.allowed_acceptable_values'), 102 | true 103 | ); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/Http/Controllers/LegalConsentController.php: -------------------------------------------------------------------------------- 1 | user() 15 | ->acceptLegalDocument($document); 16 | 17 | return response()->noContent(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Http/Controllers/LegalDocumentController.php: -------------------------------------------------------------------------------- 1 | findForType($type, true); 15 | 16 | return new LegalDocumentResource($document); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Http/Resources/LegalDocumentResource.php: -------------------------------------------------------------------------------- 1 | $this->id, 20 | 'type' => $this->type, 21 | 'body' => $this->body, 22 | 'notes' => $this->notes, 23 | 'published_at' => $this->published_at, 24 | ]; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/LegalConsentServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('laravel-legal-consent') 14 | ->hasConfigFile() 15 | ->hasRoute('routes') 16 | ->hasMigration('create_legal_consent_tables'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/LegalDocumentFinder.php: -------------------------------------------------------------------------------- 1 | validateType($type); 17 | 18 | $model = $this->getLegalDocumentModel(); 19 | $builder = $model::query(); 20 | 21 | $first = $fail ? 'firstOrFail' : 'first'; 22 | 23 | return Cache::remember( 24 | $model::legalCacheKey($type), 25 | config('legal-consent.cache.document_ttl'), 26 | fn () => $this 27 | ->query($builder, $type) 28 | ->$first() 29 | ); 30 | } 31 | 32 | protected function getLegalDocumentModel(): LegalDocument 33 | { 34 | $legalDocumentModelClass = (string) config('legal-consent.legal_document_model'); 35 | 36 | return new $legalDocumentModelClass(); 37 | } 38 | 39 | protected function validateType(string $type): void 40 | { 41 | if (! in_array($type, config('legal-consent.allowed_document_types'))) { 42 | throw new InvalidDocumentTypeException(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Listeners/AcceptLegalDocumentListener.php: -------------------------------------------------------------------------------- 1 | user; 10 | 11 | optional($user) 12 | ->acceptDefaultLegalDocumentsFromRequest(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Models/LegalConsent.php: -------------------------------------------------------------------------------- 1 | 'datetime', 24 | ]; 25 | 26 | public static function legalCacheKey(string $type): string 27 | { 28 | return "legal.documents.{$type}"; 29 | } 30 | 31 | protected static function booted() 32 | { 33 | $flushCache = fn (self $document) => Cache::forget( 34 | static::legalCacheKey($document->type) 35 | ); 36 | 37 | static::created($flushCache); 38 | static::updated($flushCache); 39 | static::saved($flushCache); 40 | static::deleted($flushCache); 41 | } 42 | } 43 | --------------------------------------------------------------------------------