From 2f3ce3cc5d952f8a26798be293403249f857f008 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Wed, 25 Apr 2018 08:50:53 +0200 Subject: [PATCH 01/33] Update Readme.md --- Readme.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 6badc27..ba09742 100644 --- a/Readme.md +++ b/Readme.md @@ -7,7 +7,13 @@ This extensions makes it easier for website owners and agencies to have the site ## Costs -It costs **€ 1450 excl. taxes** and a special price before 25th of May 2018 of **€ 990 excl. taxes**. Contact me - *Georg Ringer* via [mail](mail@ringer.it), [TYPO3 slack](https://forger.typo3.com/slack) or [twitter](https://twitter.com/georg_ringer). +- License for one site: *€ 1450 excl. taxes* +- Agency license for up to 25 sites: *€ 5000 excl. taxes* +- Agency license for unlimited sites: *€ 7500 excl. taxes* + +**Important: Get a 30% discount before 25th May 2018!** + +Contact me - *Georg Ringer* via [mail](mail@ringer.it), [TYPO3 slack](https://forger.typo3.com/slack) or [twitter](https://twitter.com/georg_ringer). Costs are **per** installation - discounts possible, ask me directly. From 4c589c6c5558b5e90cb35a790edbd04f98c16f19 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Sun, 29 Apr 2018 13:59:05 +0200 Subject: [PATCH 02/33] Update Readme.md --- Readme.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index ba09742..8e16666 100644 --- a/Readme.md +++ b/Readme.md @@ -7,11 +7,13 @@ This extensions makes it easier for website owners and agencies to have the site ## Costs -- License for one site: *€ 1450 excl. taxes* -- Agency license for up to 25 sites: *€ 5000 excl. taxes* -- Agency license for unlimited sites: *€ 7500 excl. taxes* +- Personal license for one site: *€ 240 excl. taxes* +- Professional license for one site: *€ 1450 excl. taxes* (*\**) +- Agency license for up to 25 sites: *€ 5000 excl. taxes* (*\**) +- Agency license for unlimited sites: *€ 7500 excl. taxes* (*\**) +- Academic license for universities, research Institutions, and colleges *€ 490 excl. taxes* -**Important: Get a 30% discount before 25th May 2018!** +**(*\**) Important: Get a 30% discount before 25th May 2018!** Contact me - *Georg Ringer* via [mail](mail@ringer.it), [TYPO3 slack](https://forger.typo3.com/slack) or [twitter](https://twitter.com/georg_ringer). From a08bf2d2fe43b3288a9e7993ef46bbddb428e85c Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:02:53 +0200 Subject: [PATCH 03/33] Set theme jekyll-theme-leap-day --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..b849713 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-leap-day \ No newline at end of file From de6c188f6380da24a82a5c479b53d1e08ec73b65 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:04:15 +0200 Subject: [PATCH 04/33] Set theme jekyll-theme-slate --- _config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index b849713..c741881 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1 @@ -theme: jekyll-theme-leap-day \ No newline at end of file +theme: jekyll-theme-slate \ No newline at end of file From 05f35ec38646d0538e7fd5a57b661bd5ae2830fa Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:20:26 +0200 Subject: [PATCH 05/33] setup docs --- Readme.md | 12 +++++------- Setup.md | 8 ++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 Setup.md diff --git a/Readme.md b/Readme.md index 8e16666..be2934c 100644 --- a/Readme.md +++ b/Readme.md @@ -29,20 +29,18 @@ Costs are **per** installation - discounts possible, ask me directly. ![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) ![Help](Resources/Public/Documentation/Screenshots/Help.png) -## Requirements - -- TYPO3 CMS 8 LTS & 9 LTS +[Setup](Setup) ## Drawbacks - -The limitation of the implementation is that only records having a TCA configuration are covered. + +The limitation of the implementation is that only records having a TCA configuration are covered. Furthermore direct access to the database without using the `QueryBuilder` of TYPO3 will still deliver every record. ## Features ### Hide sensitive data -The General Data Protection Regulation requires that people can revoke access to their data. +The General Data Protection Regulation requires that people can revoke access to their data. The extension makes it possible to exclude any record by activating a checkbox. After that, the record won't be accessible and available anymore, no matter if backend or frontend, editor or admin. A new administration module gives editors the possibility to handle those flagged records and react with one of the following options: @@ -74,7 +72,7 @@ Array [telephone] => +8747861395322 [fax] => +5484337015644 ) -``` +``` #### Using a CLI command diff --git a/Setup.md b/Setup.md new file mode 100644 index 0000000..9204c44 --- /dev/null +++ b/Setup.md @@ -0,0 +1,8 @@ +# Setup + +## Requirements + +- TYPO3 CMS 8 LTS & 9 LTS + +## Installation + From 01b8e2adeb381ad4c07c50eda7c2801ab347d139 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:26:00 +0200 Subject: [PATCH 06/33] [DOC] Move docs --- Setup.md | 8 -------- Readme.md => docs/Readme.md | 17 +++-------------- docs/Screenshots.md | 7 +++++++ docs/Setup.md | 12 ++++++++++++ 4 files changed, 22 insertions(+), 22 deletions(-) delete mode 100644 Setup.md rename Readme.md => docs/Readme.md (83%) create mode 100644 docs/Screenshots.md create mode 100644 docs/Setup.md diff --git a/Setup.md b/Setup.md deleted file mode 100644 index 9204c44..0000000 --- a/Setup.md +++ /dev/null @@ -1,8 +0,0 @@ -# Setup - -## Requirements - -- TYPO3 CMS 8 LTS & 9 LTS - -## Installation - diff --git a/Readme.md b/docs/Readme.md similarity index 83% rename from Readme.md rename to docs/Readme.md index be2934c..215b6af 100644 --- a/Readme.md +++ b/docs/Readme.md @@ -2,7 +2,6 @@ [![License](https://poser.pugx.org/georgringer/gdpr/license)](https://packagist.org/packages/georgringer/gdpr) - This extensions makes it easier for website owners and agencies to have the site compatible to the GDPR (German "DSGVO"). ## Costs @@ -15,24 +14,19 @@ This extensions makes it easier for website owners and agencies to have the site **(*\**) Important: Get a 30% discount before 25th May 2018!** -Contact me - *Georg Ringer* via [mail](mail@ringer.it), [TYPO3 slack](https://forger.typo3.com/slack) or [twitter](https://twitter.com/georg_ringer). +Contact me - *Georg Ringer* via [mail](mailto:mail@ringer.it), [TYPO3 slack](https://forger.typo3.com/slack) or [twitter](https://twitter.com/georg_ringer). Costs are **per** installation - discounts possible, ask me directly. ## Screenshots -**Be aware** that this extension does **not** cover every area of the GDPR - especially the frontend part is **not** covered! +[Screenshots](Screenshots) -![Overview](Resources/Public/Documentation/Screenshots/Overview.png) -![Record fields](Resources/Public/Documentation/Screenshots/Record-fields.png) -![Search](Resources/Public/Documentation/Screenshots/Search.png) -![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) -![Help](Resources/Public/Documentation/Screenshots/Help.png) [Setup](Setup) ## Drawbacks - + The limitation of the implementation is that only records having a TCA configuration are covered. Furthermore direct access to the database without using the `QueryBuilder` of TYPO3 will still deliver every record. @@ -124,11 +118,6 @@ By using a CLI command, existing IPs can be anonymized. Example: A report shows a short information about potential actions. -## Usage - -1. Install the extension -2. Enable the users who are allowed to work with the module in the `be_users` table. -3. By default, the table `fe_users` is defined as the one having sensitive information, therefore there is a checkbox to hide this record. ### Add restriction to custom tables diff --git a/docs/Screenshots.md b/docs/Screenshots.md new file mode 100644 index 0000000..121da1c --- /dev/null +++ b/docs/Screenshots.md @@ -0,0 +1,7 @@ +# Screenshots + +![Overview](../Resources/Public/Documentation/Screenshots/Overview.png) +![Record fields](../Resources/Public/Documentation/Screenshots/Record-fields.png) +![Search](../Resources/Public/Documentation/Screenshots/Search.png) +![Configuration](../Resources/Public/Documentation/Screenshots/Configuration.png) +![Help](../Resources/Public/Documentation/Screenshots/Help.png) \ No newline at end of file diff --git a/docs/Setup.md b/docs/Setup.md new file mode 100644 index 0000000..35dbb08 --- /dev/null +++ b/docs/Setup.md @@ -0,0 +1,12 @@ +# Setup + +## Requirements + +- TYPO3 CMS 8 LTS & 9 LTS + + +## Usage + +1. Install the extension +2. Enable the users who are allowed to work with the module in the `be_users` table. +3. By default, the tables `fe_users` & be_users` are defined as the one having sensitive information, therefore there is a checkbox to hide this record. From d507f77966c6694ddda578052f3b24293a7c8588 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:30:10 +0200 Subject: [PATCH 07/33] revert --- docs/Readme.md => Readme.md | 0 Screenshots.md | 7 +++++++ docs/Setup.md => Setup.md | 0 docs/Screenshots.md | 7 ------- 4 files changed, 7 insertions(+), 7 deletions(-) rename docs/Readme.md => Readme.md (100%) create mode 100644 Screenshots.md rename docs/Setup.md => Setup.md (100%) delete mode 100644 docs/Screenshots.md diff --git a/docs/Readme.md b/Readme.md similarity index 100% rename from docs/Readme.md rename to Readme.md diff --git a/Screenshots.md b/Screenshots.md new file mode 100644 index 0000000..7fbe284 --- /dev/null +++ b/Screenshots.md @@ -0,0 +1,7 @@ +# Screenshots + +![Overview](Resources/Public/Documentation/Screenshots/Overview.png) +![Record fields](Resources/Public/Documentation/Screenshots/Record-fields.png) +![Search](Resources/Public/Documentation/Screenshots/Search.png) +![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) +![Help](Resources/Public/Documentation/Screenshots/Help.png) \ No newline at end of file diff --git a/docs/Setup.md b/Setup.md similarity index 100% rename from docs/Setup.md rename to Setup.md diff --git a/docs/Screenshots.md b/docs/Screenshots.md deleted file mode 100644 index 121da1c..0000000 --- a/docs/Screenshots.md +++ /dev/null @@ -1,7 +0,0 @@ -# Screenshots - -![Overview](../Resources/Public/Documentation/Screenshots/Overview.png) -![Record fields](../Resources/Public/Documentation/Screenshots/Record-fields.png) -![Search](../Resources/Public/Documentation/Screenshots/Search.png) -![Configuration](../Resources/Public/Documentation/Screenshots/Configuration.png) -![Help](../Resources/Public/Documentation/Screenshots/Help.png) \ No newline at end of file From 29e000bea3dab4fe513cf7c355f3a22270956ae6 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:32:07 +0200 Subject: [PATCH 08/33] remove links --- Readme.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Readme.md b/Readme.md index 215b6af..f1d0384 100644 --- a/Readme.md +++ b/Readme.md @@ -18,12 +18,7 @@ Contact me - *Georg Ringer* via [mail](mailto:mail@ringer.it), [TYPO3 slack](htt Costs are **per** installation - discounts possible, ask me directly. -## Screenshots -[Screenshots](Screenshots) - - -[Setup](Setup) ## Drawbacks From b1294bd00116f34e9b038cb099b32a4dee2d4ceb Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:33:18 +0200 Subject: [PATCH 09/33] followup --- Readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Readme.md b/Readme.md index f1d0384..d6535f1 100644 --- a/Readme.md +++ b/Readme.md @@ -18,8 +18,12 @@ Contact me - *Georg Ringer* via [mail](mailto:mail@ringer.it), [TYPO3 slack](htt Costs are **per** installation - discounts possible, ask me directly. +## Screenshots +[Screenshots](Screenshots.md) +[Setup](Setup.md) + ## Drawbacks The limitation of the implementation is that only records having a TCA configuration are covered. From e15d51ce86c8938e3536a67b8f7cb620717c2726 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:39:32 +0200 Subject: [PATCH 10/33] further doc split --- Configuration.md | 33 ++++++++++++++ Features.md | 3 ++ Features/Randomization.md | 47 ++++++++++++++++++++ Features/SensitiveData.md | 14 ++++++ Readme.md | 92 +-------------------------------------- Screenshots.md | 7 ++- Setup.md | 4 ++ 7 files changed, 108 insertions(+), 92 deletions(-) create mode 100644 Configuration.md create mode 100644 Features.md create mode 100644 Features/Randomization.md create mode 100644 Features/SensitiveData.md diff --git a/Configuration.md b/Configuration.md new file mode 100644 index 0000000..5217d52 --- /dev/null +++ b/Configuration.md @@ -0,0 +1,33 @@ +# Configuration + + +### Add restriction to custom tables + +Example call how an own record can be added. + +``` +$tca = \GeorgRinger\Gdpr\Service\Tca::getInstance('fe_users'); +$tca + ->addRestriction('gdpr_restricted') + ->addRandomization('gdpr_randomized', [ + 'dateField' => 'tstamp', + 'expirePeriod' => 360, + 'mapping' => [ + 'username' => 'userName', + 'email' => 'email', + 'password' => 'password', + 'zip' => 'postcode', + 'address' => 'address', + 'city' => 'city', + 'first_name' => 'firstName', + 'last_name' => 'lastName', + 'telephone' => 'e164PhoneNumber', + 'fax' => 'e164PhoneNumber', + ] + ]) + ->add('after:disable'); +``` + +## Technical background + +The implementation is based on the `RestrictionContainers` of the TYPO3 core. diff --git a/Features.md b/Features.md new file mode 100644 index 0000000..384e5be --- /dev/null +++ b/Features.md @@ -0,0 +1,3 @@ +# Features + +- [Randomization](Features/Randomization.md) \ No newline at end of file diff --git a/Features/Randomization.md b/Features/Randomization.md new file mode 100644 index 0000000..c70ea35 --- /dev/null +++ b/Features/Randomization.md @@ -0,0 +1,47 @@ +# Randomization + + +### Randomize data + +Records can be randomized by using the `fzaninotto/faker`. By providing a mapping per table, is possible to exchange the data with dummy information which looks still ok and can be used in exports. An example would be + +``` +Array +( + [username] => martens.conny + [email] => gerhild.hartwig@yahoo.de + [password] => 94n3ifyp($+%u# + [zip] => 33781 + [address] => Hans-Jürgen-Sauer-Weg 21 +86788 Oberursel (Taunus) + [city] => Pfungstadt + [first_name] => Miriam + [last_name] => Sander + [telephone] => +8747861395322 + [fax] => +5484337015644 +) +``` + +#### Using a CLI command + +By using a CLI command, all data with a specific age can be randomized: `./web/typo3/sysext/core/bin/typo3 gdpr:randomize` + +Result can look like this + +``` +Randomize data +============== + +Starting with table "be_users" +------------------------------ + + // Randomization skipped as not enabled! + +Starting with table "fe_users" +------------------------------ + + // find all fields where value of field "tstamp" is older than 360 days + + [OK] 3 records randomized + +``` diff --git a/Features/SensitiveData.md b/Features/SensitiveData.md new file mode 100644 index 0000000..08da278 --- /dev/null +++ b/Features/SensitiveData.md @@ -0,0 +1,14 @@ +### Hide sensitive data + +The General Data Protection Regulation requires that people can revoke access to their data. +The extension makes it possible to exclude any record by activating a checkbox. After that, the record won't be accessible and available anymore, no matter if backend or frontend, editor or admin. + +A new administration module gives editors the possibility to handle those flagged records and react with one of the following options: + +- Completely remove the record from the database +- Reactivate the record +- Randomize content of the record (see below) + +Every action regarding those flags is logged on a central place. + +As additional security layer, this module must be explicitly enabled for every user - even for administrators. diff --git a/Readme.md b/Readme.md index d6535f1..6da9434 100644 --- a/Readme.md +++ b/Readme.md @@ -18,8 +18,6 @@ Contact me - *Georg Ringer* via [mail](mailto:mail@ringer.it), [TYPO3 slack](htt Costs are **per** installation - discounts possible, ask me directly. -## Screenshots - [Screenshots](Screenshots.md) [Setup](Setup.md) @@ -31,65 +29,8 @@ Furthermore direct access to the database without using the `QueryBuilder` of TY ## Features -### Hide sensitive data - -The General Data Protection Regulation requires that people can revoke access to their data. -The extension makes it possible to exclude any record by activating a checkbox. After that, the record won't be accessible and available anymore, no matter if backend or frontend, editor or admin. - -A new administration module gives editors the possibility to handle those flagged records and react with one of the following options: - -- Completely remove the record from the database -- Reactivate the record -- Randomize content of the record (see below) - -Every action regarding those flags is logged on a central place. - -As additional security layer, this module must be explicitly enabled for every user - even for administrators. - -### Randomize data - -Records can be randomized by using the `fzaninotto/faker`. By providing a mapping per table, is possible to exchange the data with dummy information which looks still ok and can be used in exports. An example would be +[Features](Features.md) -``` -Array -( - [username] => martens.conny - [email] => gerhild.hartwig@yahoo.de - [password] => 94n3ifyp($+%u# - [zip] => 33781 - [address] => Hans-Jürgen-Sauer-Weg 21 -86788 Oberursel (Taunus) - [city] => Pfungstadt - [first_name] => Miriam - [last_name] => Sander - [telephone] => +8747861395322 - [fax] => +5484337015644 -) -``` - -#### Using a CLI command - -By using a CLI command, all data with a specific age can be randomized: `./web/typo3/sysext/core/bin/typo3 gdpr:randomize` - -Result can look like this - -``` -Randomize data -============== - -Starting with table "be_users" ------------------------------- - - // Randomization skipped as not enabled! - -Starting with table "fe_users" ------------------------------- - - // find all fields where value of field "tstamp" is older than 360 days - - [OK] 3 records randomized - -``` ### Search @@ -117,34 +58,3 @@ By using a CLI command, existing IPs can be anonymized. Example: A report shows a short information about potential actions. - -### Add restriction to custom tables - -Example call how an own record can be added. - -``` -$tca = \GeorgRinger\Gdpr\Service\Tca::getInstance('fe_users'); -$tca - ->addRestriction('gdpr_restricted') - ->addRandomization('gdpr_randomized', [ - 'dateField' => 'tstamp', - 'expirePeriod' => 360, - 'mapping' => [ - 'username' => 'userName', - 'email' => 'email', - 'password' => 'password', - 'zip' => 'postcode', - 'address' => 'address', - 'city' => 'city', - 'first_name' => 'firstName', - 'last_name' => 'lastName', - 'telephone' => 'e164PhoneNumber', - 'fax' => 'e164PhoneNumber', - ] - ]) - ->add('after:disable'); -``` - -## Technical background - -The implementation is based on the `RestrictionContainers` of the TYPO3 core. diff --git a/Screenshots.md b/Screenshots.md index 7fbe284..a8bdbcb 100644 --- a/Screenshots.md +++ b/Screenshots.md @@ -1,7 +1,12 @@ + +[<- back](Readme.md) + # Screenshots ![Overview](Resources/Public/Documentation/Screenshots/Overview.png) ![Record fields](Resources/Public/Documentation/Screenshots/Record-fields.png) ![Search](Resources/Public/Documentation/Screenshots/Search.png) ![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) -![Help](Resources/Public/Documentation/Screenshots/Help.png) \ No newline at end of file +![Help](Resources/Public/Documentation/Screenshots/Help.png) + +[<- back](Readme.md) \ No newline at end of file diff --git a/Setup.md b/Setup.md index 35dbb08..6439512 100644 --- a/Setup.md +++ b/Setup.md @@ -1,3 +1,5 @@ +[<- back](Readme.md) + # Setup ## Requirements @@ -10,3 +12,5 @@ 1. Install the extension 2. Enable the users who are allowed to work with the module in the `be_users` table. 3. By default, the tables `fe_users` & be_users` are defined as the one having sensitive information, therefore there is a checkbox to hide this record. + +[<- back](Readme.md) \ No newline at end of file From e185f7e69e76d1a0dae9c249a70d316341f088f3 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 02:55:57 +0200 Subject: [PATCH 11/33] further --- Features.md | 5 ++++- Features/FormOverview.md | 3 +++ Features/{SensitiveData.md => PersonalData.md} | 11 ++++++----- Features/Randomization.md | 17 ++++++++++++++--- Features/Search.md | 3 +++ Readme.md | 12 ------------ Setup.md | 1 - notes.md | 11 ----------- 8 files changed, 30 insertions(+), 33 deletions(-) create mode 100644 Features/FormOverview.md rename Features/{SensitiveData.md => PersonalData.md} (71%) create mode 100644 Features/Search.md delete mode 100644 notes.md diff --git a/Features.md b/Features.md index 384e5be..0aa7679 100644 --- a/Features.md +++ b/Features.md @@ -1,3 +1,6 @@ # Features -- [Randomization](Features/Randomization.md) \ No newline at end of file +- [Form overview](Features/FormOverview.md) +- [Randomization](Features/Randomization.md) +- [SensitiveData](Features/PersonalData.md) +- [Search](Features/Search.md) diff --git a/Features/FormOverview.md b/Features/FormOverview.md new file mode 100644 index 0000000..570ea2a --- /dev/null +++ b/Features/FormOverview.md @@ -0,0 +1,3 @@ +[<- Back to Features](../Features.md) + +# Form overview diff --git a/Features/SensitiveData.md b/Features/PersonalData.md similarity index 71% rename from Features/SensitiveData.md rename to Features/PersonalData.md index 08da278..242e5b6 100644 --- a/Features/SensitiveData.md +++ b/Features/PersonalData.md @@ -1,14 +1,15 @@ -### Hide sensitive data +[<- Back to Features](../Features.md) + +# Working with personal data + +The General Data Protection Regulation requires that people can revoke access to their data and that this data must be removed. -The General Data Protection Regulation requires that people can revoke access to their data. The extension makes it possible to exclude any record by activating a checkbox. After that, the record won't be accessible and available anymore, no matter if backend or frontend, editor or admin. A new administration module gives editors the possibility to handle those flagged records and react with one of the following options: - Completely remove the record from the database - Reactivate the record -- Randomize content of the record (see below) +- Randomize content of the record [see Randomization](Randomization.md) Every action regarding those flags is logged on a central place. - -As additional security layer, this module must be explicitly enabled for every user - even for administrators. diff --git a/Features/Randomization.md b/Features/Randomization.md index c70ea35..0f5d648 100644 --- a/Features/Randomization.md +++ b/Features/Randomization.md @@ -1,9 +1,15 @@ +[<- Back to Features](../Features.md) + # Randomization +Randomization is a good way to remove the private data from a record and still be able to use the rest o the record. + +**Example**: A user wants his orders to be removed. After randomization the private data is removed but it is still possible to generate statistics from the order, e.g. orders from a country. -### Randomize data +## Randomize data -Records can be randomized by using the `fzaninotto/faker`. By providing a mapping per table, is possible to exchange the data with dummy information which looks still ok and can be used in exports. An example would be +Records can be randomized by using the `fzaninotto/faker` library. +By providing a mapping per table, is possible to exchange the data with dummy information which looks still ok and can be used in exports. An example would be ``` Array @@ -22,7 +28,12 @@ Array ) ``` -#### Using a CLI command +## Configuration + +See [Configuration](../Configuration.md) for the full configuration. + + +## Using a CLI command By using a CLI command, all data with a specific age can be randomized: `./web/typo3/sysext/core/bin/typo3 gdpr:randomize` diff --git a/Features/Search.md b/Features/Search.md new file mode 100644 index 0000000..2f2da97 --- /dev/null +++ b/Features/Search.md @@ -0,0 +1,3 @@ +[<- Back to Features](../Features.md) + +# Search \ No newline at end of file diff --git a/Readme.md b/Readme.md index 6da9434..3a81a0d 100644 --- a/Readme.md +++ b/Readme.md @@ -40,19 +40,7 @@ A search, similar to the one in the *DB Check* module allows to search within se See and filter any action of GDPR related actions -### Anonymize IP logging -IPs inserted into the table `sys_log` and `index_stat_search` are now anonymized. - -#### Anonymize existing data - -By using a CLI command, existing IPs can be anonymized. Example: - -``` -# parameters: -./web/typo3/sysext/core/bin/typo3 gdpr:anonymizeIp sys_log tstamp IP 365 -./web/typo3/sysext/core/bin/typo3 gdpr:anonymizeIp index_stat_search tstamp IP 180 -``` ### Report for report module diff --git a/Setup.md b/Setup.md index 6439512..0649d7e 100644 --- a/Setup.md +++ b/Setup.md @@ -6,7 +6,6 @@ - TYPO3 CMS 8 LTS & 9 LTS - ## Usage 1. Install the extension diff --git a/notes.md b/notes.md deleted file mode 100644 index 042fe4e..0000000 --- a/notes.md +++ /dev/null @@ -1,11 +0,0 @@ -- the site owner must make a list of the personal datas he has stored in the platform, why, and for how long (no longer than necessary). He must also secure this data and allow users to access and delete it. - -When the duration of a personal data storing is over, it is necessary to: - -- remove it -- or archive it (i. e. outside the website) -- or anonymize it - -https://www.cmswire.com/digital-experience/is-your-cms-gdpr-ready/ - -http://ec.europa.eu/justice/smedataprotect/index_en.htm \ No newline at end of file From 63fb7056a88a61cc3fdf60f87f956ab3c12f8190 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 03:05:29 +0200 Subject: [PATCH 12/33] configuration --- Configuration.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Configuration.md b/Configuration.md index 5217d52..feac463 100644 --- a/Configuration.md +++ b/Configuration.md @@ -1,11 +1,21 @@ -# Configuration +[<- back](Readme.md) +# Configuration -### Add restriction to custom tables +## Add restriction to custom tables Example call how an own record can be added. +```php +$tca = \GeorgRinger\Gdpr\Service\Tca::getInstance('be_users'); +$tca + ->addRestriction('gdpr_restricted') + -add('after:disable'); ``` + +## Add randomization + +```php $tca = \GeorgRinger\Gdpr\Service\Tca::getInstance('fe_users'); $tca ->addRestriction('gdpr_restricted') @@ -28,6 +38,9 @@ $tca ->add('after:disable'); ``` -## Technical background +Randomization uses [Faker](https://github.com/fzaninotto/Faker#formatters) and the mapping accepts any property of faker. + + +# Technical background The implementation is based on the `RestrictionContainers` of the TYPO3 core. From 8201795f3fd478f0883c3b915df51ff4222c9cd5 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 03:25:07 +0200 Subject: [PATCH 13/33] more --- Configuration.md | 5 +++++ Features.md | 1 + Features/Logs.md | 5 +++++ Features/ReportModule.md | 6 ++++++ Features/Search.md | 4 +++- Features/VideoEmbedPrivacy.md | 5 +++++ Readme.md | 39 ++++++++++++----------------------- 7 files changed, 38 insertions(+), 27 deletions(-) create mode 100644 Features/Logs.md create mode 100644 Features/ReportModule.md create mode 100644 Features/VideoEmbedPrivacy.md diff --git a/Configuration.md b/Configuration.md index feac463..26ba63c 100644 --- a/Configuration.md +++ b/Configuration.md @@ -44,3 +44,8 @@ Randomization uses [Faker](https://github.com/fzaninotto/Faker#formatters) and t # Technical background The implementation is based on the `RestrictionContainers` of the TYPO3 core. + +## Drawbacks + +The limitation of the implementation is that only records having a TCA configuration are covered. +Furthermore direct access to the database without using the `QueryBuilder` of TYPO3 will still deliver every record. diff --git a/Features.md b/Features.md index 0aa7679..cc651b4 100644 --- a/Features.md +++ b/Features.md @@ -4,3 +4,4 @@ - [Randomization](Features/Randomization.md) - [SensitiveData](Features/PersonalData.md) - [Search](Features/Search.md) +- [Logs](Features/Logs.md) \ No newline at end of file diff --git a/Features/Logs.md b/Features/Logs.md new file mode 100644 index 0000000..d4b38c1 --- /dev/null +++ b/Features/Logs.md @@ -0,0 +1,5 @@ +[<- Back to Features](../Features.md) + +# Logs + +See and filter any action of GDPR related actions diff --git a/Features/ReportModule.md b/Features/ReportModule.md new file mode 100644 index 0000000..104c3bc --- /dev/null +++ b/Features/ReportModule.md @@ -0,0 +1,6 @@ +[<- Back to Features](../Features.md) + +# Report module + +A report shows a short information about potential actions. + diff --git a/Features/Search.md b/Features/Search.md index 2f2da97..865264e 100644 --- a/Features/Search.md +++ b/Features/Search.md @@ -1,3 +1,5 @@ [<- Back to Features](../Features.md) -# Search \ No newline at end of file +# Search + +A search, similar to the one in the *DB Check* module allows to search within sensitive records. diff --git a/Features/VideoEmbedPrivacy.md b/Features/VideoEmbedPrivacy.md new file mode 100644 index 0000000..6425adc --- /dev/null +++ b/Features/VideoEmbedPrivacy.md @@ -0,0 +1,5 @@ +[<- Back to Features](../Features.md) + +# Improved privacy for embedded videos + +Before videos from the platforms YouTube and Vimeo are actually loaded, the user is asked for consent. This improves the privacy and as an additional benefit also the loading time. diff --git a/Readme.md b/Readme.md index 3a81a0d..d01ba06 100644 --- a/Readme.md +++ b/Readme.md @@ -18,31 +18,18 @@ Contact me - *Georg Ringer* via [mail](mailto:mail@ringer.it), [TYPO3 slack](htt Costs are **per** installation - discounts possible, ask me directly. +## Table of Contents + +- [Screenshots](Screenshots.md) +- [Setup](Setup.md) +- [Configuration](Configuration.md) +- [Features](Features.md) + - [Overview & Status of all forms](Features/FormOverview.md) + - [Improved privacy for embedded videos](Features/VideoEmbedPrivacy.md) + - [Acces restrictions for personal data](Features/PersonalData.md) + - [Randomization](Features/Randomization.md) + - [Search](Features/Search.md) + - [Logs](Features/Logs.md) + - [ReportModule](Features/ReportModule.md) -[Screenshots](Screenshots.md) -[Setup](Setup.md) - -## Drawbacks - -The limitation of the implementation is that only records having a TCA configuration are covered. -Furthermore direct access to the database without using the `QueryBuilder` of TYPO3 will still deliver every record. - -## Features - -[Features](Features.md) - - -### Search - -A search, similar to the one in the *DB Check* module allows to search within sensitive records. - -### Logs - -See and filter any action of GDPR related actions - - - -### Report for report module - -A report shows a short information about potential actions. From 09961692f436e8a5067a4fc92d7671ce8488b5b2 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 03:40:52 +0200 Subject: [PATCH 14/33] remove features page --- Features.md | 7 ------- Readme.md | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 Features.md diff --git a/Features.md b/Features.md deleted file mode 100644 index cc651b4..0000000 --- a/Features.md +++ /dev/null @@ -1,7 +0,0 @@ -# Features - -- [Form overview](Features/FormOverview.md) -- [Randomization](Features/Randomization.md) -- [SensitiveData](Features/PersonalData.md) -- [Search](Features/Search.md) -- [Logs](Features/Logs.md) \ No newline at end of file diff --git a/Readme.md b/Readme.md index d01ba06..8eb8cda 100644 --- a/Readme.md +++ b/Readme.md @@ -23,7 +23,7 @@ Costs are **per** installation - discounts possible, ask me directly. - [Screenshots](Screenshots.md) - [Setup](Setup.md) - [Configuration](Configuration.md) -- [Features](Features.md) +- Features - [Overview & Status of all forms](Features/FormOverview.md) - [Improved privacy for embedded videos](Features/VideoEmbedPrivacy.md) - [Acces restrictions for personal data](Features/PersonalData.md) From c08353aa7af981e771fa484eaa5a676a487df548 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 03:42:42 +0200 Subject: [PATCH 15/33] remove docs branch --- Documentation/Thoughts.rst | 47 -------------------------------------- Documentation/todos.md | 12 ---------- 2 files changed, 59 deletions(-) delete mode 100644 Documentation/Thoughts.rst delete mode 100644 Documentation/todos.md diff --git a/Documentation/Thoughts.rst b/Documentation/Thoughts.rst deleted file mode 100644 index 1afdf06..0000000 --- a/Documentation/Thoughts.rst +++ /dev/null @@ -1,47 +0,0 @@ -Thoughts on GDPR API --------------------- - -Goals -^^^^^ - -- Make default TYPO3 core GDPR compliant -- Enable website owners to be GDPR compliant -- Empower developers to create GDPR compliant extensions -- Enable integrators to configure extensions to be GDPR compliant - -Terms/Usages -^^^^^^^^^^^ -- Anonymization can happen: - - On persisting ☐ - - On recurring basis (scheduler) ✔ - - On manual interaction ✔ -- Randomization can happen: - - On recurring basis (scheduler) ✔ - - On manual interaction ✔ -- Hiding data can happen - - On manual interaction ✔ -- Data Removal can happen: - - On recurring basis (scheduler) ✔ - - On manual interaction ✔ -- Data Retrieval can happen: - - On manual interaction ✔ - -Stakeholders -^^^^^^^^^^^^ -- TYPO3 Core - - IP addresses need to be anonymized - - Logs - - Indexed_search - - Give overview over sensitive data & place for interaction (removal, retrieval, ...) - - Persisting “User last logged in” needs to be configurable -- Website owner - - As a website owner I want to be able to remove all personal data collected for a person. - - As a website owner I want to be able to extract all personal data collected for a person. - - As a website owner I want to be able to randomize all personal data collected for a person. - - As a website owner I want my data privacy guideline to be automatically created based on my current API configuration. - - As a website owner I want to know who has access to the data - - As a website owner I want to be able to decide on a per-user basis which backend user can see, access, randomize, export or release personalized data. -- Developers - - As a developer I want to be able to pipe my persistence through a dedicated API that can be configured to follow GDPR rules -- Integrators - - As an integrator I want to be able to configure each API usage to fit my current requirements. diff --git a/Documentation/todos.md b/Documentation/todos.md deleted file mode 100644 index 0f5b13e..0000000 --- a/Documentation/todos.md +++ /dev/null @@ -1,12 +0,0 @@ - -## Todos / Ideas - -- Randomization: - - API for mass randomization, e.g. all records of a page or - - Backend module -- Export relations -- Translations -- Support for TYPO3 CMS 8 - - Think about dropping `$GLOBALS['TYPO3_DB']` -- Tests -- Faker as phar file \ No newline at end of file From eec2ae3d4df4f4e57d42feaf76e7161def94a915 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 03:45:08 +0200 Subject: [PATCH 16/33] correct backlink --- Features/FormOverview.md | 2 +- Features/Logs.md | 2 +- Features/PersonalData.md | 2 +- Features/Randomization.md | 2 +- Features/ReportModule.md | 2 +- Features/Search.md | 2 +- Features/VideoEmbedPrivacy.md | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Features/FormOverview.md b/Features/FormOverview.md index 570ea2a..2495d9c 100644 --- a/Features/FormOverview.md +++ b/Features/FormOverview.md @@ -1,3 +1,3 @@ -[<- Back to Features](../Features.md) +[<- back](../Readme.md) # Form overview diff --git a/Features/Logs.md b/Features/Logs.md index d4b38c1..8b4fa9a 100644 --- a/Features/Logs.md +++ b/Features/Logs.md @@ -1,4 +1,4 @@ -[<- Back to Features](../Features.md) +[<- back](../Readme.md) # Logs diff --git a/Features/PersonalData.md b/Features/PersonalData.md index 242e5b6..f00cd4c 100644 --- a/Features/PersonalData.md +++ b/Features/PersonalData.md @@ -1,4 +1,4 @@ -[<- Back to Features](../Features.md) +[<- back](../Readme.md) # Working with personal data diff --git a/Features/Randomization.md b/Features/Randomization.md index 0f5d648..b8f086e 100644 --- a/Features/Randomization.md +++ b/Features/Randomization.md @@ -1,4 +1,4 @@ -[<- Back to Features](../Features.md) +[<- back](../Readme.md) # Randomization diff --git a/Features/ReportModule.md b/Features/ReportModule.md index 104c3bc..7f8857a 100644 --- a/Features/ReportModule.md +++ b/Features/ReportModule.md @@ -1,4 +1,4 @@ -[<- Back to Features](../Features.md) +[<- back](../Readme.md) # Report module diff --git a/Features/Search.md b/Features/Search.md index 865264e..a765364 100644 --- a/Features/Search.md +++ b/Features/Search.md @@ -1,4 +1,4 @@ -[<- Back to Features](../Features.md) +[<- back](../Readme.md) # Search diff --git a/Features/VideoEmbedPrivacy.md b/Features/VideoEmbedPrivacy.md index 6425adc..480fc91 100644 --- a/Features/VideoEmbedPrivacy.md +++ b/Features/VideoEmbedPrivacy.md @@ -1,4 +1,4 @@ -[<- Back to Features](../Features.md) +[<- back](../Readme.md) # Improved privacy for embedded videos From 3d540e466cb72f31bfbfecd7ae893e9919210a12 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 03:53:30 +0200 Subject: [PATCH 17/33] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..d47544e --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +gdpr.extension.support \ No newline at end of file From 1f3a8191ea5a6c54eaa57eafe0fefaf0737d49a9 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 04:25:35 +0200 Subject: [PATCH 18/33] form overview --- Features/FormOverview.md | 9 +++++++++ .../Documentation/Screenshots/FormOverview.png | Bin 0 -> 32720 bytes Screenshots.md | 1 + 3 files changed, 10 insertions(+) create mode 100644 Resources/Public/Documentation/Screenshots/FormOverview.png diff --git a/Features/FormOverview.md b/Features/FormOverview.md index 2495d9c..4f1fb7c 100644 --- a/Features/FormOverview.md +++ b/Features/FormOverview.md @@ -1,3 +1,12 @@ [<- back](../Readme.md) # Form overview + +![FormOverview.png](../Resources/Public/Documentation/Screenshots/FormOverview.png) + +Each form must be checked if it complies with the GDPR. This can't be done by the extension but it can help to ease the workflow. + +## Features + +- Listing of all forms, generated by the most popular form extensions `form` and `powermail`: +- Provide a state to know which forms have already been checked and which need to be done. diff --git a/Resources/Public/Documentation/Screenshots/FormOverview.png b/Resources/Public/Documentation/Screenshots/FormOverview.png new file mode 100644 index 0000000000000000000000000000000000000000..2aedc0a1a6f09cedfc14d59c1508424f5fc59f99 GIT binary patch literal 32720 zcma&NbyQp57d;rDKyfJUTD(ZH;uNQNaSd81PH~6Q7I(K&+@ZJ@XesV41p+0w2MvT| zLO=7J-~2OcP1YidynElh=iIaRIs2@G$v7-QC^O z)6+*sN1L0QLqkIc2L~e~Bkk?&0|NuQySv-l+oz|edwYA6laoC?J?rc1H#avh7;Joe z{N&`Mudna$@DK_4R^+g6Zk$W@cttSy^ReWvr~McXxM`Y8d ztgEX_N=kx4p`Si|ii(Pgh=>RX2zd4CRd{%KN=iyaMTLNX!13|1hK2?M0|ONm6)7nx z7Z;b2k&&>7$ola2-^m)i!E|jt{D$z^oFe_Pcav)zK6jqn$epPa}TvTD2X$(ph=GBQ?HRs9;9PiUC*FCDkf9kI$B4yl-Q zs@(8z*jhV+-aR0i=g+S09=;78dDd7ay{nLkt*c8y7?RwxdS=KoDD8S-QU(}%xHB>lcuQ1vx{*DnFkO)f{Cj=x*d;Os~M*ZdlxzX+~m>k>U z0F1C8R?WN3T(t)u&SR+n#@1-xbRnGp83;;w3T!dw$Az0CwGrxVu}1W)wYhI;u}D7N zCvjrA%4!ld?MgWzsa#bC&$gl;cV*H|;>Pd6M|!(Kd-ppx&FnMrtj8jqMQJk&>(kSI zluoAaPuo_oV;vX8T~@o$zx-LeVOk9X?z&ue##gmVz!*Dfk3OGtUv<8{f4FRF@>x~2 z+tB<_(2t-!{QQaW=|^_N&P}=Kr5p;=J;jyRtEeyd-}xemN_i3?Ww4_6ksEqJJ($;0;f&S>H5CsIxv@ZU4X-dpk#NQm z33dkwS*|;YzdaGs2P<9_%&{E|Pi18Zw_BNajqJZ0fl^&4g{~F>S`b=;%%4wRxZN`< zzQVx$#l_UOkJe8lH1EyG5*H9ytS!yB_2oq~FfJv3lNV&JFi;klIjr#XHWut_wV)gN zOU_33BJl~*^lj=bdd?pT;|d}U?F7flxt=P}h=V=; z@xeX)8Exop+OVWf$UFLf?P2LkG?ctcnEeJjEO%Rfk?yrauRHJ~*h+O&CNMTAb5~yL z>RV~VWL>VGZE)YSP==?4Fcah6Nf_OAyPodYml3uJJAuzh+=-B&+-BU~j&KxeX}fQZ z#+@)S!M6)V@xFk>`%rrr)~OXOWgXSmdj+<|BL6!!?Pfct3ZpHz?UWUF>nDN2(@H|I ztGmGvgWiaNOblY7h&KoPsCV3)lQ&L``WcKwPd_r$S*02FfLCze#|L;l50*4vT|h62 z&;DSrr1}$EaLP`MJz5*rQA@;xQY)7BY}itFt2W!m?nTA&*6%c+PKAxkY{f2Q$Fi@I zvbLQ{(p*Td5Lf=>jFj++C5Uk(#Cz9e=<^U3O{Dr=g2y(Xk3v<}cuk(8-B-p>iZ>)%mo2ul8+3Lkl`5BI!0C*Sj73uhfJ=Xi1CH}%+a(>4Q=M! zKh$}S-<1yBo0tV$ul+jux+vwRmAH{XJgc6mHj*zW$DqNZH}|Rfs9ofRh9~}P`AmmP z<|E;g*QuI+CFpumFO|zWk4JU~y|?Y?1{9}dW_+H{B%N2jyUxE+!jt=CD}AS@>ag%i zqRNO9oiSepI;V1H!8!2MDH~m;Uzc53QmKD|bg2#rgb_qpM$|WjciO>TqH|kAtvXUr zXv_Z4l#{<8&F2!UCn+ux$k==(eMkl&bOlpsQcOpV4%H;}r5DL*I{S3V_b6L;&L-=S z@nPi15!B3d5zT0sot58C3DNYk*ucT{;XE1|n{Cv7BNlH4y+#^Dyc7w2o*MqVS4c@R zSqm*e8;a#GWprL?3aNQe&l{9G=m2s*FJ3U$a zKfRuk_LuYp&x{JU1W%d$!tIx?WRSa~jQB(#q(?ME6redtss0CZN&LJLS=!bSRu&77 z!J3Q?9*+3irIHmSX6ShplK8bm3gL$RP1g43_aLy;GsFmzjk2ikpckc^ebNj@lY-jN z;=gzu(Z1wsqB=N*5^+u)`!zW}7!>Jq-0p_@FuWSYRgSeT;Mbzo<`2eKm0DUxe5>oS zpDVHM=^i1~7&me%H)BnlmLF0+_WqQk`5qI~KHqjaE>>*s0cBfcp#Eq{6qU?gT9d1W zEcKqhN~c05_ZUUDx(}{I_(U7-brDUHv94fW30b>17wKl$0=`O*!RMNOwk5-NAnF_o zHhkMSxM^e-=elPnF^yLs)QBot<6t#$t-a^yZ$NYu@|enQ#N0DVD&P2z>q)_6^V#u5 zKOU*}ciwf1G&%`swHygF6u*nh0)~ z`zJ1FGU7p&{SvN-^hT;#^bF;R%}(Ocg4%Y<=6&aFa9%wPqV1s(2fq_|zz?KZ`fr&B zc)e1uMOA`-Yq(*wP4ETIz4`Aji5^R)chG-~>emo++v0lbo|2|nvTfz|*Syb%5A$Iy z9<3g((%C(R(^u!$GI!+etFNm((D5_zB(}NZu6c7DKfl7?Gp-@ZL-V$>9OEOyQ!Fj1 zVr~9!9R~^Trpj=~^`)F61}{Qx2qq*IVx_aj8MR&Z#5WbmNOtuP+Z;5<=_2grWywio z+$+9ZIqRbtEgveX&&RA6sP%v~BD#OGKK+;o*zRNJsBLL9QRru@gN}$G6mB;gJBiEp zBY8zg61s&QT+Vvq&Y7}@#WlyN29xIr$}4KTolfSgfeSS9Hk#=;Ub;u2137a2Im-c< z-8nOh{tU=fpCVWNFtNKy%}(!cmpF?Ot1gwrdNO7i8!aRhkn5|@%QrCK2rIW1JVqWcH(6TsWP_^_+*lWQR6Rwu-e|MMm?ZfDz zdXG62P3dc zE_Cvj%x>#~!RB2Ec|3u4(=U1^P(%B7x4`oqTYFZYKT72B`B_ps4+%m3iq(Kn6hL;i zweufZ#~gz_bI0Rh$3J(cFE%rO2MCtDnBbn6Yfb2+{r@NN{=a91N@Mr5s2x$iN3i?o@|Q``{o~_2>K@ZB3e) z2&V@#ip}-a^Zp`;z)MBM>STJYt<7BCbIG8fG`6EWs2s8S%wSIAv#~oj3bNR+2=R|t zn+n9}la{9G9>2HWp|eCvaIKHTEdt@CrDe$~4nt$NFS|D;Zpf|5W_5(ju2f1oi9cf& zx=ZRxWF2t;&i2mSeq9N|yXF}74#-LbpJ>H|xT2)q#4vfGV2i`(AYNPd=u>!``j$g6 zzBipQFVnf)Fj{4T;9gw@Fxlq|fYP&{#Y(;B4yO1ze{R-2j~6Zfy!YhwA}%hK=ZFJ5 zIX}hd)pB=l!eKw!I24&4j|qk4oN%opq`=k#@NsIe&h**?;vSniLRuzqdDTwuxLJ9JvCf^k-NZaq)KKE$`HQ^GI5v-4Gip z!XGSME3r&O7nyJ<3fZdT8rAt2W#K3gS1W|`{pyQIrwp78P@)dgfLuMu?%5^Q&0zt_ zDWF6h8w#X9=ggam|Nh*~10%J7|cf z2>dEp)r_MCH%4af#)zJ*Z4;SWOWJ~SB_Z`3dn%}Yyg(@kh%qC9*UG%^_KN9ZoQ%Cz|~X{jLT5?MPQr17-{#w-}wXo^G}Eoo97u zZ4$nAF}SC9N_*n1v-!%ah(!)QKKv2oNGT^SW`E;~KFX=9CN+U(#|%vwhuV z=7`X{r4c-O90veNC^Kkok17TK#ZUamnO1Yk zYJ+w?dALj=IU>)(!BA%GeGuN1{cWVun@-EHwHff9p94GXSpMx_#W+s_5++r^?L3mWZ=c+za>mI4%fpC1lCxVG@jLGwgQl3{hGmtuiTtZd)Fx(c$ zeyBQaEv@k^E=IGKT+5UNpP`Pw;~;YJUo- zF}Q+9mEeP79^uip5fFn#Ys!KT?%Am^OVQ%k&3I-Xt4r(cgru_9u&h)Q8AIH`XNJ7F z0~{ew@gAOq<#!exK1;)e%4P8OOraF-3o%%<{@4gP%OVs=oJo3l5xpKz<~^_M;4r9b zYEqZCRCt5x2tKSdeH}p_(DquP+jLW}yQb6g(4|LA#zdplg$UOR`#8+}_d+*=K2Z{c z_0Z#z|M@4d5cdQ|M%rvrPfOwASKBdT>s2Uhd_ReGSwlT^AVvE!qLWyhyKqcT>Ob#H z44|u`N_yRxSe`9N+R)bqrd1w~3Cp`TGlsqY;mm-~tREIVz0f^f9=n8Y8i0Esbl}qB zc=WZpbX@)^gD%Gi~ebOWa}OM5|us$hU42FfuJlB-bp0I7TH_V)gJMoymB3%Y9$U{%N)k!K6dH;*S z`qYIJ?OPL0pr`3bNBXtVtDu_^7BMp8@PEs-_QZ_%ayF$ zq{eAk%TEE5@7rjbr)1(`-}l4S{0ClIkK!g9GD}~S$yD$*;7=M-%6F%}s<+-c0RnWb zy16ZBkJ*N-#pEDTKa9495SbH{%1!246(UOAetz%khn;HtR*A6jUWgyj$CqM^f|FVO5A*&TV zlL~<|DpZfFG{bdWbzY_@!P_`+_OYV^ZY2!X5?XqRv;4Q@)i~ZUC`oyq_pKE_d|B$d zQH&9S@KWZ9+ZK%AG69_ufxpb2{Ow>q6jKAzb!d`<FNuykN zNyoOIUE|42qduNQ#58rMGbG)RE9QT+Zbr8GJW+F^UFPwG2aqQmQl?rdrUCL4*`>9O zYp>x`uON~hkPFgF@Jd?u`EI+uSe!8nUx2jIn!Vl_a`jIYm*9U+e1BNMwkZn1BsJ}N zW8S(kptih&^^F2zWG5Cp{GW+4W>m{bUUQDB)rT z@k^5JTn?Urg%swKtiiL_G~BgLxFjEnaFnly$`0MaO_}pMRqNc}(Ow<2 zDo7>S_t8OZ-eG}b{3vPgC_}w-Dj5609ND@U2Fqs5`3fX*-2pxvznuSfF5u=sXoMgd z)C+f-)5qAEnJi$cop?sOJn=TPGS^o~;)o3D^=GL?xS>@i{k7Z>-R_V9L6~lyE1P3P z{J_^^QCT>EM@=An;wjYAe|25#pt-i=HN5nod<2NTBuWYmkH$aAX!CQF7P_=DU0o_c zrxzL8CF)N)T{olKq=Al!{`0;ok(VBNQWZ#7Z?*AIirO)-+}?Jcx~kcz2!D8x*Z3%3 z#tWw0Pc2cQVmCt}O&&+p)=-z_#{H3tkAdAJ z`%G3UXhDsMrwTc#-{pfuA*yi2*XrF)RPHV53EVbW%OL6+Os8+&M_4NUNkyE}Xfe*K z3_i%c-{RB+ESc;ETiSh%f4$5|?+zb(2K{~7-}361>5m2;txx;R)9(}>ae;K&G*F&3 zuln@Kyhge12rTg7Dr1Nk;RM&&hvzKW7n2z_q(tH~3MNgQ2M0-0@MolMfCZnF*nIIXDTAsC_Pn{-f# zLd9i9_0|)}Q@bI%NA@WFGg8`&LXYdA@C5=a_7GzeyaQv%->{a_4`eWvuNKZ9Vuo+Y zO#f^H)VO{C$4u@Z64~dUtNn7#I-$^{_@eu|Rt5JYIjnRxMjetikdf`bKJC#b#>Z}5 z1vwlAyio(jn|ofqvO>^*&_8s-KGwgl&-1Xnr8Xm14;ySs8q zx4#<|gs8o|c(#JS+ZLnL=jVhtv5UyZ=#U>O48UD{ zsP?#F_`q}HntDPgbGCg$u+iJdZV06BqVYR(inj;7fH$>te`nN^vZ5cabvo_jKwS=# z-rE3+&oC5pfcF*m8)x?I2Lm-9;(HZTf&&&K75x76Hmk>rJgZLSsFQJ=0*@ zeEj1MHURTyRkkhP@fLLUD41GN^rUT2C_p5Vv?2w=mFmgxg4uGza(1ryXCbA9imQPf z`2(UQhWvG#)U~rRYd}Aw%Fqm}3CBl5SRMK0C>={;okwRnaGl{<>y^@{K=G?6`EBS*cbZ*zn#nYS zGoxsN;n7p(i^-2!rdV%`Go+t-3_}uG^K=b!DX0hOE~nQn=Vn)^W-Z%Uq$+&{e{hSd zqN(@~ekT7Gvr#dI-y_-kWg&2YwdINpU*8%3eW7hiM*aqf*@aLE&faa|{r9&7GIE_- zXN?Zm3(eLStG2l>FozPH!q+A%@yyIwh4a4zW)IO0>d1k9y$m{8{;t?GE1b3dTyTccni3GWv>3J8^m zYY=OgO?cpp)6g%59aXEie4%Ea3}fNN?VDVu8k2^Wk1#GK?X_adIf~kPcW{aZ(>urZ z{h(I^-?l0W2w1Xo--8!Jjb499Q<~$sf3CiWq}FaveP8aDNG3CA^a;cZUKJ=OX%wyb zNuC?$)|_!(@qtbEE`M$@4jRX8qZIYD*$B8vKcN7uqS4He@Bj~9>?^xXq-bh@Kh>Ym!wUv8z>GY3IiC_J!MnI;M zJw+`*z52m(f@gcO!%FaA8b)cwQ3-9vXFeu$f34-x++XA{*8kjZSH5ni*1I=)nZCu| zG1upMTgI4|m_<$e>J=vwr!kZ!LkLn>Vm?>KC8`0cwEH$MOnA!qeKY z348H%jK(|bO}D#_@46d`f>1ll-2t1Is}|D&RO)0VqlwZS*Vg+H(oVQ9xx8KkrPb~% ztjUFb6F9sUHz~Ai?YBrk9RYy4^Y%~G%L3Lk+rul~myvonw#S#Zob{QH|LCk`UJcF; zu|&-adEgE3*_st@sSAKrkZP4eN=TFs%;mB?jV*}(_V%)jX?%)2(9Zew8;_BAe5X)V z^isDZx0{1HGt?V89Rl-R=1LT9niaJ}!wQm0Zcu|U6=d)(K$t8cYmQ7aXmdHk`Jp0Z z_*9Pj-p{rpBacwG;D&i9(XSyt?nY#Q;HPfp(YnqSfvVtM`M*}lby|n0w=qRzB0u_| zqEoY1$0-53^6H6mrl!vx4xi-(Ky=2n*+3K#_qtL<1Z;>RH-g_csLB;pz8-}%C_gr} zPZWKjYT#$dli-|JK9Xpzb|}S44}KuT(qK%$~Erp(Td;8cJ2;e>;%Gn`rYp*il~ zXj;jGMHYZ~3w)GqIG=#-K0W+`N%+|T=cXnn)GH76r5o0(rzVwBN8Y6bPw{A~R=Z^j zb*>LLjz&0;{KmE+a8*<#4Uge{ovP>NFnQ5UIvObUJgYOXImrSdKI-v9Y%5m*!S_qk z*CkiAunSaszkj9RFV*UBm@9#3i~-&v?|VIL@b#+uqxhu?#Fl2K;Wm8+^ZshiW&}CBz%tLaX1SGp#_tG1o>vJhS`{`AaO6raQ>j>+@EpgvxYF^ z#VWwRJ{hxR&5tbalyb9_V*|$BH5-2sUT9I)@&9&pP}NkoG%cP9n~;%LgL5DGX*Tbw4?(bf?q9P-a_8jo2Nf8n8L*?avgNccfJkbe>h>$nR|L^MBXXGR% zq;-**f&bl=8R&d+4StH8bcx3T47r*IdOh(`?vCb<hC-p0ww)s>s>+lDa1YvI?cE0ld5|1{J~ePqs(7c1n^m` z>J8OpOYEC8Q;!WV+dJNw(`F|`UiO>+j2SGv8r4LaoYG@sC0i^Or6rqaAXB`-$qAF=k=mTv#U)o+k3ELvNz&HW<=1eyHR7G$>K;FvtkEMaY^kG(db4)i0?M z@0E_^eQzvd5ha5FKYu$*K_r@ohI}Pu=4iuTlvcWK%1hw(bTQVVG=%QaJq{$V%Cenf zx24~}e|0JU)Wt+nizw*;SIa4XbP~-+9_+)w`4aoG@`7y>-<=2P@NBYcY+uky_d+Sn z^j4SrCSBwydZGiczA^O+Em3>TdhH4Yi7n;{oxu?yk(V*#IaY6c4Fcj0$wQHxpr)J; z0{&KHQig{$b>NZc-P(oYScQNtXb8#$kRhYZfMv(^x~n(wU5!tNoMZep@JbY8hW4Og z4Ws2)LYna(qnN_0c=`gfo3cm}TH^y%EPdbsO1C{k5Ysd!4IEj9d?VWL`gc4djq3(( z5ff_Nv3;fsjn~e@1_z;Nv5`ZVn2mY&pjIR#;GJLCRWeQN*bsDQMYpATi+Ye7Ff$h& zAzY8|UD$mgg%8Hua;q3S(lWJf?Ex#x01FR#^X((BYjIfp5GciRF(EW7d_Y%S;{{+S z`YkG9fT`oE*XkDv%8iwo9hV3eB+BxOjb6x66RY>HP`;uK_;wXNl#7`Uywt(m8O}op z3VQV_m%(mcJcj=-Bj-#`SOY>|gF>2t7)!|{jsS?RBtcrT0id7Utt;W@G9Lb7l`tMd z!GHU9Hy?@K0%*#8NuhY;SF@VbI;}K=!BFo+Ihhi$`z`_up>(q`W2T zCXGR|qz=s*g7;|LaNS9t={;GpCXy`Fb#=5@NJMzH7juRFj~$(q|8MrJCH$k<|HGbS z)#iGStv||-L81RFa;E-o&4eNeMBKmse7fWQMPe9V<#7toFmo(*bnyJe`P#4sEsxk& zk!mJ0b;S^_Sn;p3%-!?$ms5Lj3IPhmB3pjJDBK$#;$sCM}YEFQPWvNM*)2 znZf_;X@F+pEfMi!p!imhgq9CwziAPWz_Ks^KP|wb#8?eD91MlZT$`>w14T!?mJ7!G zu63Y-ro-exx4}}BrSZ=P=}W^@_e{svkW)$~bmH~gH{BV;Npu#%YVc#Ffvb`d!CWCC zBS7*2?uC~8fs9!!W#)q=V)WuA-fDE@kel5^zkty!Jn9aj%9eIu#SS^2|{3z2wUff8URfJVaO6fsA&N2!_{JpHTBO z*eCWPw+LOxX-osaM=v#%-aAMsWP^$IfbiAVT~VIZFFnkRw5dp_u=a?dfr1C1?9jzf zkVc9$iii4DS1s|$NmTON`V7l&EM} zXHK|>0I)w~2Qs6vq}wh&iN5ouixlDAxu#h#=gC|Ty#%bk1FpSJggqyA2}k1HWOCI+ z6(+kX-L2m!A#YYHIqzmXrrZ9Y$^4;I(fzd38H@CTcmz3AAyQtR1*q~IL`kS#x75zZ zz*HEc9_$Ct`NuGz%fr`|=fuRw95_v?-kn++5B@a$=c2F^NniOH^v81cudKm(`jerW zgvi?W85U*ZL>S`0hn!%RAGkf4LqBSQbx4fd#q6h8(su|yENee7gZwcQ7(9crz}2K& ziHNi_*nq>kSupSaQ#94!8CMF{-M5CriM%dNn@2daRJNfUgoBFNLRIY*+Nv_%GEss6`D$W3Kw&zMBfsQ@P<}vZCoTodu=XkD+>>PB@pF zab%h>dG(r+`r)-sp(DNcYYP90NuppQ2%FCQBwif6M4E&~j5R$hJ>vtv32kk_mms0U zl%-oeQ*Xo)l^%T&xBOQz1H^LIH_3Bj8=ZeE}SBb>tPhg^{8pWly;pKC{$FSsvN5=m z-rHM3JOBqZ`Ne))_LHKjbGLSeA=2|$I9TZtWepx`?69DB6PTuKfVERkW_zanf9%1(=CXiBF z`flwiE$z_plpDznL^Ml?`^{!wgip2b)f@Y@NA*{y4B7e- zZo43d%D(|`eYFqkBO^PoQlurs#HjAac+z0x3uTI&-6^X|4;Nbty9!&{K|;;$?~(Nq z=BP@#eWnz0ePC>cW~mX}S!gJQxO6S2R_r+zuX`NWC|z-;QoMM%dV1ZT(rG z<-O{f3>w9Dg|s%LUuigxDR@B)g7@j~tofJLm5qnLU6qv2R}C~*E6C5`4I}nf{9V*1 zlq~Izf2GjhhrDiBTxj7GgDw~lu)jC5$g zzn0{>WL)-JzlJoD5or&yfrbEXlP{p}=XfQc)@j$^!yt$va;_k+4GG$MUKIk4IR5BEHU^VtiBvDR<}FZ|uRBp)Ja-YDar<{m;|9kXg9) z4Mf#V1iV^p`UaA5RsEv@Zlzr&&PVR3u{%d5odW}9>)Z@Gdu7nuL8A5?SP&B|iIEDY zG0Lt37uON_QFWP+BpHVBmqt{cBtuEo1X`>akFvvbW)GQ zBtvqMNqNh^C<;nQ|r`Tv@bFX+e5lIabI7Ib3+ zxJEL0+HGIZ>B}Zes&&J23M8|ToI#ooEOkW{AWreIrEoi~p-0<6OL`@%Mx=kr1B7x{ z)zrF>ky2L{RfvpK>)1AL$!2xb5NaZBinKp_l}9jS&5P8wH<;sD{pQ$cRKZ{&Qs(0% z_iUVUWhzHXoNc6k9DQ8Ae>|V7pl@+g@}V+&22lj{do}r>c8{%JAQ5#7rvK?2IYj-*8NN{^FWJel;cjW34lbQ*0kwq5Zr&=Vy`7Z)zX~V$K zPPPy4AgBAIk`~CkCdLCrw~!cWrRw2<9z+BS#kU}nEz9LLQZy9et9B=$JR5CrMD4Fr zhYRxQ82Y;)dn zN$%ks`KN@=)%$3kmFzH7`ZQf`5LL!QeXI z)KST}A>iAwv<0w}wCj!w1w`*r#RT8H_?N_qk!dQV`G3v4kM#faO;z0g-G=ns|8EfJ z{y(u25|12oJ?hF3pyE?^+1qwjXJ*os4l!b4ZZi z**o48P(Sic9~hXv?<=AbyqE<$QADkp6C%Nabw;;(yf#SrQn93vJlnHz7n>AUt!3m$&RIGgK7Qk%}*<;$o#bb8iesE zTBgDYjczp&9r#@k(zF@A*55uszn@BJlx?6|)3YIzgvdhOh0^DS9#856L}Vt^tF2x% zreXm+in`%EAp|KcTim8cX}i{j{ICKBO%4H~Y?pfn;y<^oGOit&CbCBZimNd z2|ye0Eeteb<+73=#r`Auk$b~z`gY+Uy)De8i)Y=@y4E~_-ez=rhz=?_zSBB01YLJ4 z6K42X`{}3u_8}B1XBj;{O=tBNF@k`#30}Kt|!haqF8V?XywJNNBH-X^k%3A+p(m6hvAX}itzI~{x^+5<%J1jwja0|Pn>Dgv) zY7D76vP)^U={xUZ)B_!l!yKF%l3HvsI5D>cZN5{F&;_7c&f=8wH{Nn&F`}QEm z__VHv0hFz5re&30u6G`!Gf*v)9hm)*FgUt84uT@3a@TlwO+sb zc)0C?oqJ>!<8E^s^|X%rr;GyrCmd2v-}YBSli|p77?}jIQNcgl>FT7_sTPbzb4y2l zF~m$0RDkC9*`>L{VisOKE6^{%$26V7%wt(%yiI-cp^u4M<`~NcthyUO4blEd!2h)n zpOP3(Z_Ac$y;|{B<@wNL*yGaqt;+PAK*v&uZRvVNTZ`-Bdz~~*U=I-aL!CbH(s8U+L+?AEJui_ zjFX^Gs49e|Vv{&2pAe5Hp`p5qYkFV>G)yl6qF@eF8Q6)83w{R(Cyk2RY=>A&%ZSF4 zOK5eUlW~f?%nA`}zteI!E=kd!+3>doUncGlqQA@<6HF&=fwWQ!mVwl#ZCo-$Y*u-I zh<5vhVn}_#N?sN`oO8QX47&st7>YZvMa5_nQD1XkNOM2I@`;4(4q|&aW_pu& z$^V3)<0s;M@~fi2x(`qvxGeNId|U^<8+rd*qda&Sq>zL};Pc>07>n1%y#-nt@P(S& zNf*`+PY!93jkm#HJNCgfak2$1uAQp)-35SYtx5Ksmf)Adcq2U+(=XqM%g@9RI$x%c z&uT?I`w&{I$)EV}?rj;;&&S z$tURB^l!p%G{YeY+oJbR(BjeDpk!eJnNnj=f=R4tc}s{Vc6xE{I-O;)n1Rw|^`%7fE!w9(({t7Iye{ z_(U)G+mZRUv`Zau+j@Iy;@*|MOeJ^IFK@Smr})Ur3NvH!Sq8)`LCmix5O0N0uv#0( zOqj<58UcYC#fgsO2P&~r zB(i|<`vki=YHMN+Tr*EHe5(V4A9zzwR~W9qqba)@6GsE@4wX)8bfoCLg*?SZq!GD< zHvv;70rcVv`})BTJuaC@yB7@L9osA2=s7vg6W7Nyj2*gCd|}ir)#~Zoub-4kR4jwW zL+37}xe(qSX_FxZGK=Mb4ea>aFL)?wWt#(K(0hd7Y;Ohe$MQ?3QlzzWvYZ1kaE9o0 z-Hj(C8e4Po4X}W9Z&@oC;gV^`<5>=YB^i>lnl z`*Uj#8+E!=#-fJZBHU&O6r9E%+^tx6-VwTbfw)Kx^*p}@}(^o=;K+U z%61tR;{$r+fXcUwW!%?Xeu)_c1o`8#!XJG(@|5eT9Ldi6UcF{gHf@8D%3Y?S8nBaO zC_$A^C*Xs#EV21%Qt5nvZSp_yQt8Y2z71Jw!IRx@d=3`04XE$2X+PJ#>~!1a@;sO# z-NOF-H<_ac?iq*nb?F?xB+xaIJN;$_F*rf%#!84`K~raqML`kU$MF5B1=&5JW$3Rj z%})tKZvgZ224C?omCajQ113*z7~#HW+!?OCHw2`Kyu+9brbVJ+E?xK-lgS{RP%wE> zXWi5-4ZbwwjTC?pCz*f&`uGP>mXbMDkpd(WBuWosB7X;Xrw&13m&L#y#8`eRbuvN-#M}c28wTA}r)dFAvNwpN#?9ivC?y z50*n94sgoWD?2rj0_5n&@InE<+2{fPHb@Kvu+WDdB@^_*-Kv?>l2{wdE{8EKfP-9H zlB}9ifQUO^F(oLnT^jKwE7O2`nrb|L=#VPYgg0?Nr{8$_e^z54NG1pc zqy6Vi>pyS)`?$sm1(E9-px#=Z;vyd$SrMWOKMMtN52QxN?UB5BUz$jG8>w&jiEyKe zY^MDCtq}W>f#&c{n*03xDZIXQw@cE?e{b6AIDRybZFpruZSp?% zCKZ(HH|e<`2X~~IacyPI@BQMGVoHpkGGcPxRDM99nF7GntnH>sHRx+Uh zkwHct0(O|oA_kMaq5D>xmw67~3NFwJI;?4denW^WytDh82$;EoKbTslad{Y zOp8f9I-g)z*?&QeDvO0jEv6;QgpJ%DYmzCPz1l$+C zJ1bOj{uu?!lO}@x#Ql)^hNDX7wDspuneH6#f$qawy!ix}$}vC5A;qYilpXw!SmNmi zOS|>-A(4|m*UR-YJz}6#DlFIR-j7htuk%M&CUbFRA?bh1KB0bR9iOv{&FZ zWBz4^0=)D=i>c=d^S2@Cy zsr~!8!g%K1xtg8SD@JU)l<|k+UQA((m(w;QLP$Ae{@27e=loR;#*n!da>~V8XQgg* zh$alLx7n)*8!|Wx!2fzV{A(ik`{q!Hpb3YUC}YS()S_?J>LEHHp_5W4&gTTM;3<6Q z=-onC+hzrYUXMQck$tnx6nnKZVQgq@xL;Trgw^;1z|Bp5b7r#^AMH^my-1{js!X8E zfOwYRoL4Y=-g}KYDRdP;2*d;;tc&fTQLAjxyOdG49_7RHga)OL(>uI>{UFlWy5jo+pT+VIZL5F^@Ufh;sUYwdi- zqN#Die4*8$8ss8km{w0kX9TGBTTg1i{hmDDO*8#ltObd&N>ZqQ`zP2$#5Dmqnd%TI zsTkODJnWzD8YMPBr7SQlH$;!lp{bxL{ko=L=w_0$Qca#toYXguC+QxBs+^GNAn`Fd zaDwbtZ-4aLS6>A*SS=7Q>q^B9ymb=&J+Vy%E8=8E4%~c=)2OX!%GmeOOCH3k^#@-i ze#8s~@~xn1yn65!7EPy?rBoir_W$^MkWzpgCw5HTC(}afvQs&z|`*d=83W^*I7l(h<^FqCyTv$ch=@;)k$aObY~Sq zt{8mtof#+(Sq;zuW(54NT~ZJJr@SE%IzpE?1V;7mQu^LPhb|#3ZuOE`5s};%pThEG ziHq4mW7L1g%&>7{xsPf!AXt)iwx%+ICV<5s`}C^25#N0eM^SPme-WeidfRv?=90fc zr=Ns_TO&2NS3b3Q(6nJt#AwI#;q+Ga@k-N_nREbA?1_rr>fYJX4dpX`+x=QczGgE@ z{=ymH&8q=9Q4L=h!IP0!2P{;j|JDZzlbh$W{?v-&|$jqm3(*gEX&24A0XiH1Wb}cF{;o*C?`lMR> zuYP*=cVS;B6M?6WxBLN}xy77?Kuju+_*lOV26M=dgI8yoanS-3`1#pl53Hdo+CS^v zYz-N_*bJSHI9;UxpIgA?V-@D9ArM$d+O>8pP9*Ome?_gG998;r>xK#SC)hG?In(ebxBsiLw~mVA+1f@241qc>`yC%3h1b6qrLXhBY z0fr#KA-GG>nITAUg2P}z1_lBQ49q3J^PY3w@2>Bzb^q(G>aJaT*Y3Tmp00lS*xDgD zfaz4o{m~nWOgFEt^5HbZgmFtD{o07I7sbgDCXb<^ZTW+<>Mf$&6uu=n!xx9yysnVL z>Ssc{b%O{u-d^`lkqy3r& zfrcc~sbIV+*6G|rk%viD*a`TlYDMLmtI00EMM|%<`MysTDWzd(yfOr2-{vt?BYwrP zM5WA7IDYXSsh8X>f9E(Hs|Xh9X~;DgF`-4Qb=MVtOB?I>hzeM`AXs1UZHz_L6f;To zb}`Jn4gKX|(b-)tdMXPBJ<-3=c?|*G&?ZZA5i&!&4zqknwaK^jb+=~NOCw(;ACUv>5`gA%9ey*d7`J`~pQKI%H zRklvRs+7_E$>f*LP!5GYIw#xPs4#1Kt18!4~_-o5r#0_~631qcWnY@_tU4vw8KLy1=BZ@y{}ENJiQmz6TdL}IOXHBNHT;H`THmSJSyShK#Xad%I!QV zE69Df$R)_uiyu2)wH0Qs`>&8t&-QlW&53qIpe)c4lp@)k%Sl+1QxyeVF;M1b@+O_R z*K9c%Ju14+wR+qCed5oKQe=J;bC1Q{OxO)LD@pf&NRXljVm12%)8Yt+TVU71MNKw^XxUwX}Sn94r{J8y}BO8j7Riid>6D zY}*k{b5D{?)fuRWcQ2C|?6kU6DyeS#GE-!8r%7xGruJWOG3$WlRMLY6kf(_4NdxM( zEv2uqK$i0IAgefX1$$`qe)^_5OHFiL*Rlx=SN>^E;eFyBH9zvbIw&`@w{#=Lj`4z z!uZ#3K4_yo=Otc@kvK!;*0+4wIJG z?f_DddDT5EKB#QUl{3S|!ZtRJ=Rm7^BlxfE?nsHy?`V>?i>V?gWWlj}vsx*@ZtgG~ z`vcrSX7*_B{vp%@qlL`S2u_KRu*oHJ$*!T^B!h)d5$EcyDZO?}r7;v*ud~*y73aum zA93=Gy(Ta@wTY;2T6pHt-?GKdu1bPrt_*HXt`oy^x=TxQx%XoejCt-2DPCGg7}MZl zKXu6)<8k*sEgPkEi)qs5`>v$R%3E{p4lY-Q>^>D!FF|S64#wD~Sp@}leLjJw)C4Ug zj<&f&hr%1rq8kw3RYe@`-w5ocnIGHXn7qAn9Vs7_({y~LxRpr+R?YJk>dVMuqZ<)q z{5sE?Iy0B!HEs>;EzpQh|E7{*eqL7?78tIL>}mv zmCLFS{E7WdAvg+4%J9%7RKoFr2Fw1re~9yv(HJbja+EkcvpIqc}TX;XGNF&JIAp z_B*8{>_yNdaGH4ZEqbBd3D)-gO;~a1Oeqn+*VOe3;r@Pnt#*F?=_&ECA9wKhlWqkA z$B<1ocEg@CrZFbGv)x!Uk1{h|VKM}ydO=g2FVWUxZXlk$l>J#%EjH8(VVsp3T6FgRk@#toqj}%Rh+E{b?U;#`^-I4hjW}Ap!5+sjAuKqr73rx*zufuXL8r z+E^Fwv7^&Zkm@w_#(dgOqZfa{s5TV@#y@D(e}Jimd+ccTzR~;lsf1EEgK7T}`yY|8 z0wAEJ#ZQD`B0>Uq%ZUU8Ec})ePr6}50)!Wi550pJCP1OY%8CV{8Ne{=L+_4me}wGR zt{XEQJzl;VPXVfMcY=kEUg>`%7h*I22Nnw>{cmU9)_6e9UWdW-b!5-ND_MIz;yPH+ zXTk}?#luu10w-ax%QQ~hpnEQd)!^6sHwcOzZz1AvJdwg@*^%&W{y?JOf{@H< zx|?(1yb3&|@Usj@Qp6Hi66k)~QEu$gJgY~AlnVZ_3L%Ln$^=x#OzB;3`;wbMGQ zXY2wyJE}WF*Wn>CB0|i;ej-B$llBvM&lxuL19yyKQ9o>+objs%4$EON5_IwyPc%;# zwNQ)W9m8I>cY+BRDtPZe= zvy$xVn<}h#h2^J(_EOb{B{SOfOh*`rXI%o^ly6=v($88Tn6^!^?XCbjj!Yo_wHTm| zCTGf;VK{JihA2f+y^Qb{nyw)_&}dK<_$n$l5*6Pqa%S~StW@@55noeVJR9GWpcD)z z@BC8Q5!Dn#V2ZGVtCBTu)_P3RG&*?YQ6ufL;}XE1WiDnh#v|m^1ewh)@^Mq!lXBin zyxl4ax6<$@ZwoCxSc!VE9nrWQbBQHbtN#m}^&|A|My5yl5%SZrv7bWvdql~pNj~ef zkf-g7mIRbsW3oEw)7S|MvEr!1&El~IF{yz`OJdwPe!y+ntavc9GIuC%*d0@%R}16*>8PlMBv zLG2Z`IqxMcB0o-@G+WnfF^Vi-Z!v2Yw8bTGyovj%kEhflz-@LBC4lb~MiqDqhU4AM zm9JTV{mQ;^n|*nW=>0fH=V8g364ZL`jo_Bd?rDhwONP+()db~mfGUpX{4lmHHnM9{kWJmBBe7-ko7>a9p}8J)|SbWiE*pTJw(K-$71x zyr3g7xp+!d`2p97&t-#(UuvYO&_7^GiG;ww-1LZuKTDQs<@9QxIYF~bEaT9D9;sI6 zJ}R�y(x3`_<~!^0IU^tf_xiK|(tiEL4dE?=}Lptan@8o+J46zsx?VmAaEG%n)HL znX^RZh5_LoPY^5|oudnadh~v9Q~M!ozvaje4W;BoeWwkaZr!gOvGne^<12S>81=;<#br#K{IEnEbsnW{{@< zYfPmo=7d8#ai*{YcV|Sb9we&?XnR+v27?o_Fyb>y`1m6~L~)F&y%+SuNW=F5zcsH> zjC^J<0o3aFL1;r7nH&)i5y$e$Bqb%gIw7J-q4*PP!i;PyUG}I@a^7cMx;Cj_RN-?K z`sPa3<3IJzW)(u7ko$^6CDQujvC(viD%{1ZAB=sz&I@>Ckh16baAE!4$?1b_0|>6< z#9#5vGs8ORa+5=eV={>rf9&EYEaO#w`r-p1IlgjdO@6o5Bkso8{21pVAlOK)-S|0W zOLBarbcdfazc1bO2a}W%FCSbj8Y?<-Tx%T{SMLf=SA?=rf00wUqNN;S^H)Uhfu1EW ziXu5#QgX|WaD{z+uIWf3xk)>TE}^@MIwsTtW2@E8Jcn!?XMMT;E&`BPZ~Jnbaf`+k zq^HmcR&k9@^m&?TFC+5#L!KL`3*fyx?)S8uoc@%()+R=cArwDgB@iu9k{WDEKGVI1 z-zVbly!qnQ;OH@as;1r<+e48j1-ioxP3NId|@(fUQ@@9rV3mr9YD1 zP0xo5T^iLCR}G8W^VcT@t{{g`Kl8oxh?zrF;egee44U^|?RZ>cHl#%+-vQ#(7{u5O z3x2%O;t-F(L)|Blqz~0Qm4yT?)7{YnQ}fLz+BNc%A1s<`YRH$>x}$HUZgUzj_&pt` z5A?tIQ|JV~nO%5>CsY&WGgd;E?~b%ns9l8sfyLNr)WTv)s{X z69%)kS2BjiQ?n5n9x&JF4>`=WLulruc?mQvj>=W{rw2TvM`R#Opa?v-N|yvwzw3LT z0r9(E>7j;mY@%=bw(xT%1p}&SkYig7ijHqM9)TwwmQpDxR48(Md|e|{!{PvR&^z83 zV^br&b(qoYXr|Hg)b_5fdd0i?#pvf(1}T~i!dsJikfNeKQ)zfgH+H}RuN|>I=S}Ww zkufK=B#RW@2DN6rvH=zvj)}KsE6E)3du>OjW=6q6hQ&<~S$w3J12uAao5kn3W^Pb} z(G%qBj;A&{RLGKiMl}9On>?76&=0msY5y20@N4gph(JWq8wC8RdZ$PARqjXNlt&^^ zJd>_*@qqpIJ7$6;#VaWFU*+XuNC`85WnP5LG7gJCNHpQu}iy zX|clt8-hF@AgW@Xw5k`x9E3j`ONS0J`t+376`Y3XT_=Ty(}t5LOkc!3LRLS+g|Y5A zI_l3TgkIr?Rd^p$w`DNO?TpWyVwU?@F?D4zmikOD^U}Ajy#Ue0JoBS z{Sz#PZ#!D6$dFL__*MTuqnTj^#amB%Q?pTg7S8EDSDA>ymJO+V6UM*QH+C4MmBj`B zJ~A1*?~_0vz(1JtduxtZoD@u?D3kPyC~kD>ia~oP6lGG6C3< zC@D`>BNxJ)<#oi3U@79x?up&zDDcG>AMKrf1WSwJOa|r5&kqTpU_^wG@wwSkGMrv{ zwV99)7|469XCU#~*D^J;`9Qj-tnFLz4sgS>GhBRyy?nw%?rFW8A5|=hk!}3B9kOGQ zxlS(!B;K6j#wMJU=wl-jViWeGQdoo^QM!EhDFEPI^nWw1CdR!}g2kyBe%B zV<|bhulg)Rv(cyr-_A*q3)R)jR((93O82vsjVhO}QklP86<239Y1-f!|8GPL4a)9|FFIf$J=PzVeXV(`H}7x6Pl zN|gSjUQGq>{xg1`fPuwEHfHBD8wNXFA(y>wYYp!xCtZ{%WhJ}<@W8#v4!xQ+ zL@@Lk!Md;+Y9dKedOyqM<>5P$)2C;3O?wwd`OC&2(?{oSFwb_9A=2K_Q|aS0tJ@Iu zEpXBVV9wKG{W@(EyV~0G6RgZ~4c8)IkGENm0c2J)G~7cVrS}~ppLSQi{oNS#{Acmo zL@L?)S)SBx`J7{jyRi3kc25K+$nO%A-}BK3+vn<-*um%kMKG~4w8A>J3m zz~i7ReVOUF0Z4sb-Z z-D)0^gV#HAX^v$+8wX^Ra1lUP8GHn4*=bmED?(piBdjlgm`5{lbu4Q^Yh_9H>)A(?4ln-(v?0x4402n<>l&=p*sfysqELTO4f6rymCBS=!wXXSZp(jMqFn?L zz^mk^GPK_+XimuY_lsBT z&!+JNhXu=rtnF%av?$Vqn9yXHkZa8_J?$4Fk~%v3Bi(EauX9%Lh%MSV(PHpS$yk1D z8lXQD@r{Cfkk;X|Sf3+nF1yHWtcIWE4)ruqRd1;5S;y|JrR-wqy>)mI8SyDTNQLI# z0jGvd-elV5JHD%WZN07R#6kwzV7O*VC!1M;z@3c4F`vBoCQzC8oTS7iIg!&#^RF|k zG4%$bsp(;%r&K*_LU}hS19O@OZ8C*;el=9$1TJ`xs4v$i-dwg zajWHeWl^`aQeSsS_ru@8E!I_Krzm~fWqf)xYZ6eq%0t0i$~Wktvkr3KuN*OwvwW~t zvl_*_ZroL2Gs`cQIj;3NKK2{xcTWSn!fJRZyER=d&6C$K7x!7+8*B;bVoBfFDxl05YqE&{q%b(?(b9jR{+O-SsnSbGJ+8xj%JID1t{NPYB_s zA$WLh3KRQIc95jiZp!+-E8o^=~w+f6G! z*xibRNLDhVYp)b1@=&B9z`h1ZUAAg}{$|Hre`IXKRcQ~aIRXPhx7+BzD=ge4(%S`o ztD1)9Iu1o(F!!1TBdVC`*7yGx3|Nr%cZb}+Fv-8W@&2`8PJpU4A0^$yf&?7h05eOs zeA6Ts;(SH#(a^HRhNA5w?-U?FZDPtdt+%_A-zW=)H7Wo9MmO&PS{Vd}0bwffNfwM4 z!vI75e_^Tjho=ADqPO?{@p}pgUSXQYZrxuAc7`J3S)}r(TDU7bb~9W zCRjT?5MV{7Y4EzFqCj8fvNBV7ke{g_Wek(qu;|e2*GeG<>x*gVqTvo!v_Jn(lp+Qs z^y=2>PCz-t#EL5w9i7h)bYwI>a~H;xe4#xM`KHOS_%YcdeBsE#uz@`pZT`2`g)O@8 z0qKSh$*>QOe=oP;O4WhRohnf+x{XYYSjAP%tILw^X9YrdY90H67BXGBx4Bl2($6lgAac;wbx0ZeL3q%;+tE~zPnM$LwK1;8b6qB zxayqJ6=lYKUn)Akx`Kx0d)>i7pAk#cho!(EiQ+a=a>kU!ZAIi zi~TX~jkwREi-B&tBVjBIq{%NqoIwgID2|NCA#|l z6DHI9wLz6xU)S`+Gg+7_l}6@bAe}k#5XG3DBwk*Ez`}th+4&+Zd!goiE4aba%2LON z*+bw0immevHc7>!)$yc(*m^`x*6xrZ{$}F-OKJTOqx27Qn$RTYFNvL6mXYF{T%Cw^ zP6-;<^e4N~V5}R7In|9VZQSj&GxK0usNd!n6z8c2#5(%1RVbz1ohM+saVo%T4N6R% ziFn!{*`D~^m?PBQf+gg+)a1*rKfg9&V`ayxt7IAxYa#`uvK~Q<3VwL~;9uSRq z%>nO94#m^yKI6Tjg6n?DS4@%B2=QWV%tFj3cNZQAezQ6b_W{g*j&#SRRm0M|ZFZ`v z3B*_UPV;u@av$5Rrg}C0p{D6&O{Dd#5d}qe?yHgc@XGOJlHb+v?LHJtVWq+z&<8A$ zLI&%!{<-=$kK z;smj)A9xlJ0tN7x^YI+!ujj2 zc94GfJ)YE83~sEcKWA`jM@=iDeX&TBcL>$a46?KAmx1!=m_P!L8c(8!6l&%1a9kd*L$6x z54di1P2!tEP|cSBXzvqSMxiTE0NJ;lcpY*BACBIqeL6ml1pf3+fxb#mw}8D;6q&^y zw6)iE<<}*~fz~B%n6TaY7eI1eE~po%!1En&SHtpyx_CwBv9OSGbVPZj`KRfy9!+1B z#QSZVj};Hf&en*dfbB+j>$MPG51ePQzLyb?6v?|n;1g7O5~6GMF=2NSk4YGE+XkaJ zEaa0e7Z@i)O9FCOelfTRgT^rz30|IeEMZNT0DY!q?B-fWDv%sf2cJKaiHFJ?j4E<> zuWSDq|G}#%`6GX~T!4OlQvirzvim$)xbA*%ADDZ4e}4CZg{Tln*dVHEm3yAllc;D%kl}XOi1lL>rOynl1HS0W zLM)y*KhGEqRd~N$zbV2M3x7c+g0;KcR*a3+nVj>xoZ0hOJm9Y*+6TQL;T~y8Tj{MdN~Zs z!fqblOk4mL&JfAH_ib4!BpnH!W=P9fd`T|48LMydjmKyy5bI4*rkWkkeb~*}5zjEM z!&IVAnyp1Je^r6jy}{a55LS5=mg0E)sYT)!Nn;@wQmh_0fXQ1#3Wru5wsdwN)Qz5L zcBcUpcpxlI-Y!qVe)`s?sGCf!;eC~MSHtu7_S8=_Ny;c}AZ-lTPO=XHVWrCcq%}p} zlT%{k_(1hADkm}fe%h(h9FNbG9#%K`k?^?v)+RQeh{obIZ$(;GW9 zG3P@)`cr4iqx;-wM^uR-w5XAR>gS2&wv&?nSiqQr9SCFn;aTV;ihPR{%VxGcVFTLV z2cZ>c**69GF9^4@aCw_Vwr{XUc~skM-@BC>sTQ8&qUGOSmmdg@@Z4Ye{Wu;m54ios z{up9x`g^Bj&WdIS^3s2%c6L76bQ$WFgTs5Hs&uqz{5mm4Wbg|REA`X1Sq*2Nmah(U zG!Qo>e(ZZJ>@Y;#|8?vZldYH{a`QR!cgk5(j>(a-2Iv}76@MgkIF!Tur5#^@s^EFm zn7VO^va8ezhgV~T1~Mz1_b|jdh{zDhMZ5xqTdR68^QH|t3m#J@KEoQO3HK__WBEqp z(+{A{=7>(}>)x}dX>LVe5pCOLAlNMvsrG@PzB`Opr0+~7nc1Q%R3_`^!>y}NEXewr zXT@mLw&PA-WqUc!_a`E_uuY1AmMDPo>*|jF8lYWi5pH?@01ZDbwZksNGfClS&~EKg zucsU$Lt0oHB9rz=LgJ}@k7$zQ7!OAks@IOsv}-mKf?CkP+)gX{U?w>fdu+hlSB$#a zU<2WIrn~W2tjxTW7gaKE`jYGO)W8#`mXyB|yA>f!m0~3zS)T(0lX9vcdAaJJj1&`n zu_9_IJ##WBN+-V52%!|73;L7Mbgp{AS|1^c9IPLnVXLFqG)3W_R@7=rknDGOKktj_ zvQdK)`TlzYIk>y=?aib6$2_n5v36S8 zA&HsoJp&EoIc*3c{}ZQs0g*0?KU*l4!2;&a6`xw?Ie8gMn7+OWSp9(Yf^AY>*Lot5 zt(P$SDm+WC(%*)9kzf^S$EfSgTAZG=^oz+a4{BHBjn`+o@dc<`f$&Ql2CCQ&RA~kR zRSPM_(kC7Pwi;$l?`Iw}(9lbADbE{m&#v38`<(PhX?Lys-TN}p@BJdF5b7fmImWb{ zhPTBiG7X>bmD3VM{hoK^XP&Xj&B;Ro#EQsxZKTJx&o;?;7@l=hc68hZm&nNTE3xY2 zMr=Fo-YDErQ^2D|;2+tK@6+iXD)ZP;3As5xbl z{K(3;rYWaew2^PIWEu+7d5F8Z=>3KFNy-po8}Nl6#?03D!KpDXLkkh9-#-j6th6hB zBVi_IRC7xfH~mMDJcIVLNNw&bHGF!Gg^{unDB6e0Kk~?YwL2OXdYQ72qc@y2PFFj5 z?jq*3?QmdmeiMJ)?lSR~_Bcxhxg%mxiYr^=^R2%FfeaN{oFg&AIS9AI<17V+JjkBb z(gZkE@M6F3t`Xqhc#vm)A!L3#@7j%x^#BMlImqPMpLsK}jvE$d+AL_kZUt?n1y!lK zKj8Q(2pCP+*x7bIhQ0lkNfp%39;YyVJurgV{zPk# zl$W9zk`bSDs<#KV?Hz6aCk=~-LDH$dY#*0FUqW}Py7A?5aaKc#6%-@_&DPUCY?boVu}@vz9RU3s z#N~Nm&or?vV>->~W@ z3MpHz^;uW$kv^xyCDWmm+q_xegO zwIlpmd`9wrI4e=dvtv_Hf8J@p+0<+18thtLtdC)kt`0MZe+Z$Z)zv_v9>3aIbY+$m zlSrz^I8d!uT>r@h%Z8CILqTLoi|u^;a@;_BWlljJ=*LSj?$@y0sEO@P*B6pd)`S<) z)}`!Er;oTE-+EEVSqqOY)p$Z|WP<2?!39S$JD9Ue~X$RJyJxyRTw?zU&e7dDe%X9tPsZ7+qQD%dy`f;6 zY}KEfZ~L_e*Rs?ZDJOWp(0ISyE6*K-ey9Nry%p+ONkYIQo+o6;Bhfh{Z;|oO`HFsK zb3s1_^q12dJ`Vc1B=&la)tjRfrIcB7sO;?g^4Hc=f9Df_yetiB+q3NNwCBTs4mtmm zboRWD@xLUVs+7#NQSQKB9F(vTC1$l2%$wEt=zh=sVzO9CD_`Pt*tzxIEl}M=&~c1W zWV%zUPN5#bDsMe`tNfcPu3!pED-fTJmJGvchP1seUQ~`WtX9NlGwXWhC;$9cbrQW+A!`BFcF7@Kx3x#!`up=}Yoz1|`(uCDCa*@#8X7?`?W-3c>;7FR28EhQvL^!~-cL zfQ=5Yja3K?`-f}dZ}I5$Vkc_aUAzzoSUo^2wxYCYj`7lo`%;|4RjZk(=-D>?n-Kv6%F<5AZpy2DC6H zdTUj#oRIBLJkD|cFSq>vC<4wA-hZLylsNT{05G##ci2dW*SBa`j8Kg@#dygg{5ifJaxU6gUq8^Z5qH#q}ybP2(Q7)t@k7BO;jF#Xdfk5hGCU>5&u`X5VZrGL|FL4$$K98FWJc4+7Oj6`_>7wHS9x5S@HIdx=e8gH{KAX2 zjnMC_h08JMUC(0~C4`@mHJ2Gy8{4xrfv~jT#%90Vos6W3H`VVc~IE%s&NKztIn__<)Aiqj2(6Dc+n~4+M(3%IN?l8Z0wuL=f1{TBy87n z^(VF3)wAw)aScy02gvX-8HR_0prn*-7!Q|iSY?K(*2}OqHBl|N<-*3uyp!S?3rFr1 z3|Dz47eRT>9>9h3QQw-(-=#j48Za@pE#lY=tL(SyFaKoH%jmZQN_Dt`Q#>Kr^zABOeh`%|ot4*?T0Amyi<#)q74v|scD3&NN)7jpKt#BFYc&Vkj5nUhV)tcYKmpw5s&NQIrT6sHwf4%;(kXQi!s@7bdEkHd^M z6#y?yZ#!XCqpmNGtC`V>@ji^uoV(P17qgjseQDQWDl*ZBDJ_kimdyMdMA3EK|nCs8uQ}r`3s%)FC7)xE- z2!N`zhA<#y9xy<5dnmp~fduLacZOEo^T!jx=4~)jJo38$*}r)pJDY zm*7|i4z#Z6Kyj}L;Gg$5|2z(KJm6ef1x4229#OaCr)l+d7(VZY1AGKb-b&=J&DAXj zrI}w90?+yWILTDztLn(4r)J>Z#Y%POLzj5OwU5S9C0UC}IA}adD-WPa_{zX0{uR%p3pd~GWU^qu}_-? zP1MHV+-Hn8DFzo+C)&EvW5=$W? z08+?M02H*-;tC*ZX$ert=ye99x0XQHlFl9i9(Imfsb_@Z0k&5v5KKKo7>~aI0o$B( z|84mHjNQ-w(lPxzN&c@YrT<9+k{3tz#;P>2{U^Y-u0M>-j~TH6=KF0jQRI6Pl}kUX zkSmX6-v|E5(yMWHdFQe%nkV%2A^})PXj=U-W>589$N|QJ%d?-RFvVcJr!Y?3a)FR^ zVA3@soavrLjBx5)M!Duf!dtJ$l21x#B=9==o;m8iJPhfe{KwT3!A0;`?snjw?}`_x zF~$kGM2x}e5Gi+zq>^v{a_z$H=utVSIZ8mtV(71jGYo^$BP3xtHzpSOo?bEf^&ZD| zSThmeW~|4onpWi)TP|mBW?s-oJ^ngiIsXh%;G5_bwDi2#*b1{N&3Wolh#@%hFGpIh z)1%ZN=H80>oTU}3c0SF)_r*aayeAk!U;ePYavQL|Zs6z7y7@xWAV5p>*++%K-?YY9 zb+Pkz6F*xvD(Rlz&Rm~7<`Sk)lf2`EZLvM>kQ;oiS1ZzHgjEu9L;X6=7!kbi;@xDH z?42maD$(f#>)GqQ*k{3wqRv@B)9%d|^4$l6r(0yFyyGU<#@|evBD-QOGy;j|Vn{Tcs7(K-f-5{;4Rd1D4 zS9K1KdaMwV^7kZe!!xZ*8l&AYv3 zNUJH9-h0;5d%OAck@_syN1}Jxdk00_l*i6sZ=Zh4QUBLv1U<=rN5?$q*S4h(eE)jB z47EL0hWZ>wCG(+H;sx4&Aq~BNRQQLJ4T|-u^-JdRZO*nAVr%PcIV-iU^1;gy7#-0) z9rJMCd9T`Ed36Euv_|wTjC_>Lerh3BVa;+P;4>KU7oJ&(``1?4YD?;&h-f+ zmsY+Jt@!HO{ki7;+jHt~gcM|dn0MjZZ?`ocA+!*uXCtj61KffQy{x@c3shkc)*^LY zWREpJz?8Owh~v=n7uA*H5}$02`~@T_3BJvf)aokp;kWnk$-&Z@Wx|BCxsOu-t4#{! zEx+7y3B%f~VK*sB{wpNheY8OUQ5<4QJ`b%L_AwoyAfDDg4xR7uI0-$PktPAqKkEC2 z>>F|3Kt~fE=g!Dtyrct+;`JdgzM;?<1`>cw;;?Nj3nbwGI1JlfdjNPTiDf|^79-55 c?060^iaS8O^I}B&op>tCtI5^MSbX?@0L)omSpWb4 literal 0 HcmV?d00001 diff --git a/Screenshots.md b/Screenshots.md index a8bdbcb..d50f74e 100644 --- a/Screenshots.md +++ b/Screenshots.md @@ -7,6 +7,7 @@ ![Record fields](Resources/Public/Documentation/Screenshots/Record-fields.png) ![Search](Resources/Public/Documentation/Screenshots/Search.png) ![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) +![Form overview](Resources/Public/Documentation/Screenshots/FormOverview.png) ![Help](Resources/Public/Documentation/Screenshots/Help.png) [<- back](Readme.md) \ No newline at end of file From 9f6fc514ea24a4a9ae91a5169f4667c4a6a3ae6d Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 04:37:30 +0200 Subject: [PATCH 19/33] report module --- Features/ReportModule.md | 1 + .../Public/Documentation/Screenshots/Report.png | Bin 0 -> 14181 bytes Screenshots.md | 1 + 3 files changed, 2 insertions(+) create mode 100644 Resources/Public/Documentation/Screenshots/Report.png diff --git a/Features/ReportModule.md b/Features/ReportModule.md index 7f8857a..acff94c 100644 --- a/Features/ReportModule.md +++ b/Features/ReportModule.md @@ -4,3 +4,4 @@ A report shows a short information about potential actions. +![Report.png](../Resources/Public/Documentation/Screenshots/Report.png) \ No newline at end of file diff --git a/Resources/Public/Documentation/Screenshots/Report.png b/Resources/Public/Documentation/Screenshots/Report.png new file mode 100644 index 0000000000000000000000000000000000000000..07b40c2c05d86e546974fda4b0afe5ec72c753ff GIT binary patch literal 14181 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 Date: Tue, 8 May 2018 04:41:39 +0200 Subject: [PATCH 20/33] log screenshot --- Features/Logs.md | 2 ++ .../Public/Documentation/Screenshots/Logs.png | Bin 0 -> 19911 bytes Screenshots.md | 1 + 3 files changed, 3 insertions(+) create mode 100644 Resources/Public/Documentation/Screenshots/Logs.png diff --git a/Features/Logs.md b/Features/Logs.md index 8b4fa9a..edbaa08 100644 --- a/Features/Logs.md +++ b/Features/Logs.md @@ -3,3 +3,5 @@ # Logs See and filter any action of GDPR related actions + +![Logs.png](../Resources/Public/Documentation/Screenshots/Logs.png) \ No newline at end of file diff --git a/Resources/Public/Documentation/Screenshots/Logs.png b/Resources/Public/Documentation/Screenshots/Logs.png new file mode 100644 index 0000000000000000000000000000000000000000..e7d5506a213fb32de23a9fca2aa9cb2f2ac5a19a GIT binary patch literal 19911 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 G*Z%`tTSJNf literal 0 HcmV?d00001 diff --git a/Screenshots.md b/Screenshots.md index 6fe13f1..1641cd7 100644 --- a/Screenshots.md +++ b/Screenshots.md @@ -9,6 +9,7 @@ ![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) ![Form overview](Resources/Public/Documentation/Screenshots/FormOverview.png) ![Report module](Resources/Public/Documentation/Screenshots/Report.png) +![Logs](Resources/Public/Documentation/Screenshots/Logs.png) ![Help](Resources/Public/Documentation/Screenshots/Help.png) [<- back](Readme.md) \ No newline at end of file From f0cfe760607ad1380b9c6ba8b3ccbb2682b49fd2 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 04:56:15 +0200 Subject: [PATCH 21/33] more screenshots --- Configuration.md | 6 ++++++ Features/PersonalData.md | 4 ++++ .../Screenshots/record-randomization.png | Bin 0 -> 17616 bytes 3 files changed, 10 insertions(+) create mode 100644 Resources/Public/Documentation/Screenshots/record-randomization.png diff --git a/Configuration.md b/Configuration.md index 26ba63c..fd31938 100644 --- a/Configuration.md +++ b/Configuration.md @@ -40,6 +40,11 @@ $tca Randomization uses [Faker](https://github.com/fzaninotto/Faker#formatters) and the mapping accepts any property of faker. +## Screenshots + +The GDPR module shows the current configuration. + +![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) # Technical background @@ -49,3 +54,4 @@ The implementation is based on the `RestrictionContainers` of the TYPO3 core. The limitation of the implementation is that only records having a TCA configuration are covered. Furthermore direct access to the database without using the `QueryBuilder` of TYPO3 will still deliver every record. + diff --git a/Features/PersonalData.md b/Features/PersonalData.md index f00cd4c..25e1a78 100644 --- a/Features/PersonalData.md +++ b/Features/PersonalData.md @@ -6,10 +6,14 @@ The General Data Protection Regulation requires that people can revoke access to The extension makes it possible to exclude any record by activating a checkbox. After that, the record won't be accessible and available anymore, no matter if backend or frontend, editor or admin. +![Record-fields.png](../Resources/Public/Documentation/Screenshots/Record-fields.png) + A new administration module gives editors the possibility to handle those flagged records and react with one of the following options: - Completely remove the record from the database - Reactivate the record - Randomize content of the record [see Randomization](Randomization.md) +![record-randomization.png](../Resources/Public/Documentation/Screenshots/record-randomization.png) + Every action regarding those flags is logged on a central place. diff --git a/Resources/Public/Documentation/Screenshots/record-randomization.png b/Resources/Public/Documentation/Screenshots/record-randomization.png new file mode 100644 index 0000000000000000000000000000000000000000..3160d4bf08ecb0b8114207aa661d1a8687d3e47f GIT binary patch literal 17616 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 Date: Tue, 8 May 2018 07:19:12 +0200 Subject: [PATCH 22/33] move docs --- Features/Search.md | 2 ++ Screenshots.md | 15 --------------- Configuration.md => docs/Configuration.md | 2 +- Readme.md => docs/Readme.md | 20 ++++++++++---------- docs/Screenshots.md | 15 +++++++++++++++ Setup.md => docs/Setup.md | 0 _config.yml => docs/_config.yml | 0 7 files changed, 28 insertions(+), 26 deletions(-) delete mode 100644 Screenshots.md rename Configuration.md => docs/Configuration.md (94%) rename Readme.md => docs/Readme.md (65%) create mode 100644 docs/Screenshots.md rename Setup.md => docs/Setup.md (100%) rename _config.yml => docs/_config.yml (100%) diff --git a/Features/Search.md b/Features/Search.md index a765364..8bb67a9 100644 --- a/Features/Search.md +++ b/Features/Search.md @@ -3,3 +3,5 @@ # Search A search, similar to the one in the *DB Check* module allows to search within sensitive records. + +![Search](../Resources/Public/Documentation/Screenshots/Search.png) \ No newline at end of file diff --git a/Screenshots.md b/Screenshots.md deleted file mode 100644 index 1641cd7..0000000 --- a/Screenshots.md +++ /dev/null @@ -1,15 +0,0 @@ - -[<- back](Readme.md) - -# Screenshots - -![Overview](Resources/Public/Documentation/Screenshots/Overview.png) -![Record fields](Resources/Public/Documentation/Screenshots/Record-fields.png) -![Search](Resources/Public/Documentation/Screenshots/Search.png) -![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) -![Form overview](Resources/Public/Documentation/Screenshots/FormOverview.png) -![Report module](Resources/Public/Documentation/Screenshots/Report.png) -![Logs](Resources/Public/Documentation/Screenshots/Logs.png) -![Help](Resources/Public/Documentation/Screenshots/Help.png) - -[<- back](Readme.md) \ No newline at end of file diff --git a/Configuration.md b/docs/Configuration.md similarity index 94% rename from Configuration.md rename to docs/Configuration.md index fd31938..3f1dc99 100644 --- a/Configuration.md +++ b/docs/Configuration.md @@ -44,7 +44,7 @@ Randomization uses [Faker](https://github.com/fzaninotto/Faker#formatters) and t The GDPR module shows the current configuration. -![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) +![Configuration](../Resources/Public/Documentation/Screenshots/Configuration.png) # Technical background diff --git a/Readme.md b/docs/Readme.md similarity index 65% rename from Readme.md rename to docs/Readme.md index 8eb8cda..4b02126 100644 --- a/Readme.md +++ b/docs/Readme.md @@ -20,16 +20,16 @@ Costs are **per** installation - discounts possible, ask me directly. ## Table of Contents -- [Screenshots](Screenshots.md) -- [Setup](Setup.md) -- [Configuration](Configuration.md) +- [Screenshots](../Screenshots.md) +- [Setup](../Setup.md) +- [Configuration](../Configuration.md) - Features - - [Overview & Status of all forms](Features/FormOverview.md) - - [Improved privacy for embedded videos](Features/VideoEmbedPrivacy.md) - - [Acces restrictions for personal data](Features/PersonalData.md) - - [Randomization](Features/Randomization.md) - - [Search](Features/Search.md) - - [Logs](Features/Logs.md) - - [ReportModule](Features/ReportModule.md) + - [Overview & Status of all forms](../Features/FormOverview.md) + - [Improved privacy for embedded videos](../Features/VideoEmbedPrivacy.md) + - [Acces restrictions for personal data](../Features/PersonalData.md) + - [Randomization](../Features/Randomization.md) + - [Search](../Features/Search.md) + - [Logs](../Features/Logs.md) + - [ReportModule](../Features/ReportModule.md) diff --git a/docs/Screenshots.md b/docs/Screenshots.md new file mode 100644 index 0000000..30519ed --- /dev/null +++ b/docs/Screenshots.md @@ -0,0 +1,15 @@ + +[<- back](Readme.md) + +# Screenshots + +![Overview](../Resources/Public/Documentation/Screenshots/Overview.png) +![Record fields](../Resources/Public/Documentation/Screenshots/Record-fields.png) +![Search](../Resources/Public/Documentation/Screenshots/Search.png) +![Configuration](../Resources/Public/Documentation/Screenshots/Configuration.png) +![Form overview](../Resources/Public/Documentation/Screenshots/FormOverview.png) +![Report module](../Resources/Public/Documentation/Screenshots/Report.png) +![Logs](../Resources/Public/Documentation/Screenshots/Logs.png) +![Help](../Resources/Public/Documentation/Screenshots/Help.png) + +[<- back](Readme.md) \ No newline at end of file diff --git a/Setup.md b/docs/Setup.md similarity index 100% rename from Setup.md rename to docs/Setup.md diff --git a/_config.yml b/docs/_config.yml similarity index 100% rename from _config.yml rename to docs/_config.yml From aa7624106120bba9e9bb59c30c515582ae10bbb6 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 07:21:06 +0200 Subject: [PATCH 23/33] rev --- docs/Configuration.md => Configuration.md | 4 ++-- docs/Readme.md => Readme.md | 16 ++++++++-------- Screenshots.md | 15 +++++++++++++++ docs/Setup.md => Setup.md | 0 docs/_config.yml => _config.yml | 0 docs/Screenshots.md | 15 --------------- 6 files changed, 25 insertions(+), 25 deletions(-) rename docs/Configuration.md => Configuration.md (93%) rename docs/Readme.md => Readme.md (69%) create mode 100644 Screenshots.md rename docs/Setup.md => Setup.md (100%) rename docs/_config.yml => _config.yml (100%) delete mode 100644 docs/Screenshots.md diff --git a/docs/Configuration.md b/Configuration.md similarity index 93% rename from docs/Configuration.md rename to Configuration.md index 3f1dc99..1ba9df9 100644 --- a/docs/Configuration.md +++ b/Configuration.md @@ -1,4 +1,4 @@ -[<- back](Readme.md) +[<- back](docs/Readme.md) # Configuration @@ -44,7 +44,7 @@ Randomization uses [Faker](https://github.com/fzaninotto/Faker#formatters) and t The GDPR module shows the current configuration. -![Configuration](../Resources/Public/Documentation/Screenshots/Configuration.png) +![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) # Technical background diff --git a/docs/Readme.md b/Readme.md similarity index 69% rename from docs/Readme.md rename to Readme.md index 4b02126..0a1e9e7 100644 --- a/docs/Readme.md +++ b/Readme.md @@ -22,14 +22,14 @@ Costs are **per** installation - discounts possible, ask me directly. - [Screenshots](../Screenshots.md) - [Setup](../Setup.md) -- [Configuration](../Configuration.md) +- [Configuration](Configuration.md) - Features - - [Overview & Status of all forms](../Features/FormOverview.md) - - [Improved privacy for embedded videos](../Features/VideoEmbedPrivacy.md) - - [Acces restrictions for personal data](../Features/PersonalData.md) - - [Randomization](../Features/Randomization.md) - - [Search](../Features/Search.md) - - [Logs](../Features/Logs.md) - - [ReportModule](../Features/ReportModule.md) + - [Overview & Status of all forms](Features/FormOverview.md) + - [Improved privacy for embedded videos](Features/VideoEmbedPrivacy.md) + - [Acces restrictions for personal data](Features/PersonalData.md) + - [Randomization](Features/Randomization.md) + - [Search](Features/Search.md) + - [Logs](Features/Logs.md) + - [ReportModule](Features/ReportModule.md) diff --git a/Screenshots.md b/Screenshots.md new file mode 100644 index 0000000..1641cd7 --- /dev/null +++ b/Screenshots.md @@ -0,0 +1,15 @@ + +[<- back](Readme.md) + +# Screenshots + +![Overview](Resources/Public/Documentation/Screenshots/Overview.png) +![Record fields](Resources/Public/Documentation/Screenshots/Record-fields.png) +![Search](Resources/Public/Documentation/Screenshots/Search.png) +![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) +![Form overview](Resources/Public/Documentation/Screenshots/FormOverview.png) +![Report module](Resources/Public/Documentation/Screenshots/Report.png) +![Logs](Resources/Public/Documentation/Screenshots/Logs.png) +![Help](Resources/Public/Documentation/Screenshots/Help.png) + +[<- back](Readme.md) \ No newline at end of file diff --git a/docs/Setup.md b/Setup.md similarity index 100% rename from docs/Setup.md rename to Setup.md diff --git a/docs/_config.yml b/_config.yml similarity index 100% rename from docs/_config.yml rename to _config.yml diff --git a/docs/Screenshots.md b/docs/Screenshots.md deleted file mode 100644 index 30519ed..0000000 --- a/docs/Screenshots.md +++ /dev/null @@ -1,15 +0,0 @@ - -[<- back](Readme.md) - -# Screenshots - -![Overview](../Resources/Public/Documentation/Screenshots/Overview.png) -![Record fields](../Resources/Public/Documentation/Screenshots/Record-fields.png) -![Search](../Resources/Public/Documentation/Screenshots/Search.png) -![Configuration](../Resources/Public/Documentation/Screenshots/Configuration.png) -![Form overview](../Resources/Public/Documentation/Screenshots/FormOverview.png) -![Report module](../Resources/Public/Documentation/Screenshots/Report.png) -![Logs](../Resources/Public/Documentation/Screenshots/Logs.png) -![Help](../Resources/Public/Documentation/Screenshots/Help.png) - -[<- back](Readme.md) \ No newline at end of file From 0e8c2baaef3b2345bea2149cc336ffccecd7ccf0 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 07:43:19 +0200 Subject: [PATCH 24/33] [TASK] Add demo version --- .../Controller/AdministrationController.php | 267 ++++++++++++++++++ .../Query/Restriction/GdprOnlyRestriction.php | 56 ++++ .../Restriction/GdprRandomizedRestriction.php | 56 ++++ .../Query/Restriction/GdprRestriction.php | 56 ++++ .../Model/Dto/ExtensionConfiguration.php | 48 ++++ Classes/Domain/Model/Dto/LogFilter.php | 109 +++++++ Classes/Domain/Model/Dto/Search.php | 48 ++++ Classes/Domain/Model/Dto/Table.php | 155 ++++++++++ Classes/Domain/Repository/BaseRepository.php | 24 ++ Classes/Domain/Repository/FormRepository.php | 135 +++++++++ Classes/Domain/Repository/LogRepository.php | 41 +++ .../Domain/Repository/RecordRepository.php | 71 +++++ Classes/Hooks/DataHandlerHook.php | 56 ++++ Classes/Hooks/QueryBuilderHook.php | 21 ++ Classes/Log/LogManager.php | 72 +++++ Classes/Report/GdprStatusReport.php | 71 +++++ Classes/Service/TableInformation.php | 40 +++ Classes/Service/Tca.php | 86 ++++++ .../Xclass/DefaultRestrictionContainer.php | 30 ++ .../Xclass/FrontendRestrictionContainer.php | 30 ++ Configuration/Commands.php | 17 ++ Configuration/TCA/Overrides/be_users.php | 41 +++ Configuration/TCA/Overrides/fe_users.php | 23 ++ Resources/Private/Language/locallang.xlf | 21 ++ .../Language/locallang_modadministration.xlf | 17 ++ .../Private/Language/locallang_rendering.xlf | 14 + .../Private/Layouts/Backend/Default.html | 6 + Resources/Private/Partials/Forms/Listing.html | 44 +++ Resources/Private/Partials/TableListing.html | 118 ++++++++ .../Administration/Configuration.html | 43 +++ .../Templates/Administration/Delete.html | 1 + .../Administration/FormOverview.html | 27 ++ .../Administration/FormStatusUpdate.html | 1 + .../Templates/Administration/Help.html | 155 ++++++++++ .../Templates/Administration/Index.html | 28 ++ .../Private/Templates/Administration/Log.html | 131 +++++++++ .../Administration/ModuleNotEnabled.html | 14 + .../Templates/Administration/Randomize.html | 1 + .../Templates/Administration/Reenable.html | 1 + .../Templates/Administration/Search.html | 63 +++++ .../Private/Templates/Rendering/Youtube.html | 37 +++ Resources/Public/Icons/Extension.svg | 12 + Resources/Public/Icons/form-overview.svg | 1 + Resources/Public/Icons/module.svg | 13 +- ext_localconf.php | 23 ++ ext_tables.php | 32 +++ ext_tables.sql | 29 ++ 47 files changed, 2384 insertions(+), 1 deletion(-) create mode 100644 Classes/Controller/AdministrationController.php create mode 100644 Classes/Database/Query/Restriction/GdprOnlyRestriction.php create mode 100644 Classes/Database/Query/Restriction/GdprRandomizedRestriction.php create mode 100644 Classes/Database/Query/Restriction/GdprRestriction.php create mode 100644 Classes/Domain/Model/Dto/ExtensionConfiguration.php create mode 100644 Classes/Domain/Model/Dto/LogFilter.php create mode 100644 Classes/Domain/Model/Dto/Search.php create mode 100644 Classes/Domain/Model/Dto/Table.php create mode 100644 Classes/Domain/Repository/BaseRepository.php create mode 100644 Classes/Domain/Repository/FormRepository.php create mode 100644 Classes/Domain/Repository/LogRepository.php create mode 100644 Classes/Domain/Repository/RecordRepository.php create mode 100644 Classes/Hooks/DataHandlerHook.php create mode 100644 Classes/Hooks/QueryBuilderHook.php create mode 100644 Classes/Log/LogManager.php create mode 100644 Classes/Report/GdprStatusReport.php create mode 100644 Classes/Service/TableInformation.php create mode 100644 Classes/Service/Tca.php create mode 100644 Classes/Xclass/DefaultRestrictionContainer.php create mode 100644 Classes/Xclass/FrontendRestrictionContainer.php create mode 100644 Configuration/Commands.php create mode 100644 Configuration/TCA/Overrides/be_users.php create mode 100644 Configuration/TCA/Overrides/fe_users.php create mode 100644 Resources/Private/Language/locallang.xlf create mode 100644 Resources/Private/Language/locallang_modadministration.xlf create mode 100644 Resources/Private/Language/locallang_rendering.xlf create mode 100644 Resources/Private/Layouts/Backend/Default.html create mode 100644 Resources/Private/Partials/Forms/Listing.html create mode 100644 Resources/Private/Partials/TableListing.html create mode 100644 Resources/Private/Templates/Administration/Configuration.html create mode 100644 Resources/Private/Templates/Administration/Delete.html create mode 100644 Resources/Private/Templates/Administration/FormOverview.html create mode 100644 Resources/Private/Templates/Administration/FormStatusUpdate.html create mode 100644 Resources/Private/Templates/Administration/Help.html create mode 100644 Resources/Private/Templates/Administration/Index.html create mode 100644 Resources/Private/Templates/Administration/Log.html create mode 100644 Resources/Private/Templates/Administration/ModuleNotEnabled.html create mode 100644 Resources/Private/Templates/Administration/Randomize.html create mode 100644 Resources/Private/Templates/Administration/Reenable.html create mode 100644 Resources/Private/Templates/Administration/Search.html create mode 100644 Resources/Private/Templates/Rendering/Youtube.html create mode 100644 Resources/Public/Icons/Extension.svg create mode 100644 Resources/Public/Icons/form-overview.svg create mode 100644 ext_localconf.php create mode 100644 ext_tables.php create mode 100644 ext_tables.sql diff --git a/Classes/Controller/AdministrationController.php b/Classes/Controller/AdministrationController.php new file mode 100644 index 0000000..3d7dd9f --- /dev/null +++ b/Classes/Controller/AdministrationController.php @@ -0,0 +1,267 @@ +recordRepository = GeneralUtility::makeInstance(RecordRepository::class); + + if ($this->request->getControllerActionName() !== 'moduleNotEnabled' && (int)$this->getBackendUser()->user['gdpr_module_enable'] === 0) { + $this->redirect('moduleNotEnabled'); + } + } + + public function initializeView(ViewInterface $view) + { + $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class); + $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Modal'); + $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DateTimePicker'); + $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/jquery.clearable'); + $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip'); + + $dateFormat = ($GLOBALS['TYPO3_CONF_VARS']['SYS']['USdateFormat'] ? ['MM-DD-YYYY', 'HH:mm MM-DD-YYYY'] : ['DD-MM-YYYY', 'HH:mm DD-MM-YYYY']); + $pageRenderer->addInlineSetting('DateTimePicker', 'DateFormat', $dateFormat); + + $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar(); + + $uriBuilder = $this->objectManager->get(UriBuilder::class); + $uriBuilder->setRequest($this->request); + + $buttonList = [ + [ + 'action' => 'index', + 'icon' => 'actions-system-list-open', + 'position' => ButtonBar::BUTTON_POSITION_LEFT, + 'group' => 1 + ], + [ + 'action' => 'search', + 'icon' => 'actions-search', + 'position' => ButtonBar::BUTTON_POSITION_LEFT, + 'group' => 1 + ], + [ + 'action' => 'formOverview', + 'icon' => 'ext-gdpr-form-overview', + 'position' => ButtonBar::BUTTON_POSITION_LEFT, + 'group' => 1 + ], + [ + 'action' => 'log', + 'icon' => 'actions-document-open-read-only', + 'position' => ButtonBar::BUTTON_POSITION_LEFT, + 'group' => 2 + ], + [ + 'action' => 'configuration', + 'icon' => 'actions-system-extension-configure', + 'position' => ButtonBar::BUTTON_POSITION_RIGHT, + 'group' => 1 + ], + [ + 'action' => 'help', + 'icon' => 'actions-system-help-open', + 'position' => ButtonBar::BUTTON_POSITION_RIGHT, + 'group' => 2 + ], + ]; + + $iconFactory = GeneralUtility::makeInstance(IconFactory::class); + + foreach ($buttonList as $buttonDefinition) { + $button = $buttonBar->makeLinkButton() + ->setIcon($iconFactory->getIcon($buttonDefinition['icon'], Icon::SIZE_SMALL)) + ->setTitle($buttonDefinition['icon']) + ->setHref($uriBuilder + ->reset() + ->setRequest($this->request)->uriFor($buttonDefinition['action'], [], 'Administration')); + $buttonBar->addButton($button, $buttonDefinition['position'], $buttonDefinition['group']); + } + } + + public function indexAction() + { + $tables = TableInformation::getAllEnabledTables(); + + $collectedRows = []; + foreach ($tables as $table) { + $collectedRows[$table]['statistics'] = $this->recordRepository->getStatisticOfTable($table); + $collectedRows[$table]['rows'] = $this->recordRepository->getRestrictedRows($table); + $collectedRows[$table]['meta'] = Table::getInstance($table); + } + + $this->view->assignMultiple([ + 'tables' => $tables, + 'restrictedData' => $collectedRows + ]); + } + + /** + * @param string $table + * @param int $id + */ + public function deleteAction(string $table, int $id) + { + $this->addFlashMessage('deleted'); + $this->addFlashMessage('Only demo mode'); + $this->forward('index'); + } + + /** + * @param string $table + * @param int $id + */ + public function reenableAction(string $table, int $id) + { + $this->addFlashMessage('reenabled'); + $this->addFlashMessage('Only demo mode'); + $this->forward('index'); + + } + + /** + * @param string $table + * @param int $id + */ + public function disableAction(string $table, int $id) + { + $this->addFlashMessage('disabled'); + $this->addFlashMessage('Only demo mode'); + $this->forward('index'); + + } + + /** + * @param string $table + * @param int $id + */ + public function randomizeAction(string $table, int $id) + { + $this->addFlashMessage(sprintf('The record with id %d from table "%s" has been randomized', $id, $table)); + $this->addFlashMessage('Only demo mode'); + $this->forward('index'); + } + + /** + * @param \GeorgRinger\Gdpr\Domain\Model\Dto\Search $search + */ + public function searchAction(Search $search = null) + { + $this->addFlashMessage('Only demo mode'); + $searchPerformed = false; + if ($search === null) { + $search = $this->objectManager->get(Search::class); + } else { + $searchPerformed = true; + } + + $this->view->assignMultiple([ + 'search' => $search, + 'searchPerformed' => $searchPerformed, + ]); + } + + /** + * @param \GeorgRinger\Gdpr\Domain\Model\Dto\LogFilter $filter + */ + public function logAction(LogFilter $filter = null) + { + $this->addFlashMessage('Only demo mode'); + if ($filter === null) { + $filter = $this->objectManager->get(LogFilter::class); + } + + $allTableNames = []; + foreach (TableInformation::getAllEnabledTables() as $tableName) { + $allTableNames[$tableName] = $tableName; + } + + $this->view->assignMultiple([ + 'allTableNames' => $allTableNames, + 'filter' => $filter, + ]); + } + + public function formOverviewAction() + { + $formRepository = GeneralUtility::makeInstance(FormRepository::class); + $this->view->assignMultiple([ + 'forms' => $formRepository->getAllForms(), + ]); + } + + public function formStatusUpdateAction(string $type, int $formId, int $status) + { + $this->addFlashMessage(sprintf('The form of content element %s has been updated ', $formId)); + $this->addFlashMessage('Only demo mode'); + + $this->forward('formOverview'); + } + + + public function configurationAction() + { + $allTables = TableInformation::getAllEnabledTables(); + + $information = []; + foreach ($allTables as $tableName) { + $information[$tableName] = Table::getInstance($tableName); + } + + $this->view->assignMultiple([ + 'tables' => $information + ]); + } + + /** + * View which shows information if current user got no access + */ + public function moduleNotEnabledAction() + { + + } + + public function helpAction() + { + + } + + /** + * @return BackendUserAuthentication + */ + protected function getBackendUser(): BackendUserAuthentication + { + return $GLOBALS['BE_USER']; + } +} diff --git a/Classes/Database/Query/Restriction/GdprOnlyRestriction.php b/Classes/Database/Query/Restriction/GdprOnlyRestriction.php new file mode 100644 index 0000000..2eb0955 --- /dev/null +++ b/Classes/Database/Query/Restriction/GdprOnlyRestriction.php @@ -0,0 +1,56 @@ + $tableName) { + if (TableInformation::isTableEnabled($tableName)) { + $table = Table::getInstance($tableName); + $restrictionFieldName = $table->getGdprRestrictionField() ?? null; + if (!empty($restrictionFieldName)) { + $constraints[] = $expressionBuilder->eq( + $tableAlias . '.' . $restrictionFieldName, + 1 + ); + } + } + } + return $expressionBuilder->andX(...$constraints); + } +} diff --git a/Classes/Database/Query/Restriction/GdprRandomizedRestriction.php b/Classes/Database/Query/Restriction/GdprRandomizedRestriction.php new file mode 100644 index 0000000..9a568c2 --- /dev/null +++ b/Classes/Database/Query/Restriction/GdprRandomizedRestriction.php @@ -0,0 +1,56 @@ + $tableName) { + if (TableInformation::isTableEnabled($tableName)) { + $table = Table::getInstance($tableName); + $restrictionFieldName = $table->getGdprRandomizedField() ?? null; + if (!empty($restrictionFieldName)) { + $constraints[] = $expressionBuilder->eq( + $tableAlias . '.' . $restrictionFieldName, + 0 + ); + } + } + } + return $expressionBuilder->andX(...$constraints); + } +} diff --git a/Classes/Database/Query/Restriction/GdprRestriction.php b/Classes/Database/Query/Restriction/GdprRestriction.php new file mode 100644 index 0000000..f8b2b3e --- /dev/null +++ b/Classes/Database/Query/Restriction/GdprRestriction.php @@ -0,0 +1,56 @@ + $tableName) { + if (TableInformation::isTableEnabled($tableName)) { + $table = Table::getInstance($tableName); + $restrictionFieldName = $table->getGdprRestrictionField() ?? null; + if (!empty($restrictionFieldName)) { + $constraints[] = $expressionBuilder->eq( + $tableAlias . '.' . $restrictionFieldName, + 0 + ); + } + } + } + return $expressionBuilder->andX(...$constraints); + } +} diff --git a/Classes/Domain/Model/Dto/ExtensionConfiguration.php b/Classes/Domain/Model/Dto/ExtensionConfiguration.php new file mode 100644 index 0000000..97c5771 --- /dev/null +++ b/Classes/Domain/Model/Dto/ExtensionConfiguration.php @@ -0,0 +1,48 @@ + false]); + if (!empty($settings)) { + $this->randomizerLocale = $settings['randomizerLocale']; + $this->overloadMediaRenderer = isset($settings['overloadMediaRenderer']) ? (bool)$settings['overloadMediaRenderer'] : true; + } + } + + /** + * @return string + */ + public function getRandomizerLocale(): string + { + return $this->randomizerLocale; + } + + /** + * @return bool + */ + public function getOverloadMediaRenderer(): bool + { + return $this->overloadMediaRenderer; + } + + public static function getInstance(): ExtensionConfiguration + { + return GeneralUtility::makeInstance(__CLASS__); + } + +} diff --git a/Classes/Domain/Model/Dto/LogFilter.php b/Classes/Domain/Model/Dto/LogFilter.php new file mode 100644 index 0000000..e65fbd8 --- /dev/null +++ b/Classes/Domain/Model/Dto/LogFilter.php @@ -0,0 +1,109 @@ +tableName; + } + + /** + * @param string $tableName + */ + public function setTableName(string $tableName) + { + $this->tableName = $tableName; + } + + /** + * @return int + */ + public function getStatus(): int + { + return $this->status; + } + + /** + * @param int $status + */ + public function setStatus($status = 0) + { + $this->status = (int)$status; + } + + /** + * @return string + */ + public function getDateFrom(): string + { + return $this->dateFrom; + } + + /** + * @param string $dateFrom + */ + public function setDateFrom(string $dateFrom) + { + $this->dateFrom = $dateFrom; + } + + /** + * @return string + */ + public function getDateTo(): string + { + return $this->dateTo; + } + + /** + * @param string $dateTo + */ + public function setDateTo(string $dateTo) + { + $this->dateTo = $dateTo; + } + + /** + * @return int + */ + public function getLimit(): int + { + return MathUtility::forceIntegerInRange($this->limit, 10, self::MAX_LIMIT, self::DEFAULT_LIMIT); + } + + /** + * @param int $limit + */ + public function setLimit($limit) + { + $this->limit = (int)$limit; + } + +} diff --git a/Classes/Domain/Model/Dto/Search.php b/Classes/Domain/Model/Dto/Search.php new file mode 100644 index 0000000..56847bb --- /dev/null +++ b/Classes/Domain/Model/Dto/Search.php @@ -0,0 +1,48 @@ +searchWord; + } + + /** + * @param string $searchWord + */ + public function setSearchWord(string $searchWord) + { + $this->searchWord = $searchWord; + } + + /** + * @return bool + */ + public function isSensitiveOnly(): bool + { + return (bool)$this->sensitiveOnly; + } + + /** + * @param bool $sensitiveOnly + */ + public function setSensitiveOnly(bool $sensitiveOnly) + { + $this->sensitiveOnly = $sensitiveOnly; + } + + +} diff --git a/Classes/Domain/Model/Dto/Table.php b/Classes/Domain/Model/Dto/Table.php new file mode 100644 index 0000000..01a513e --- /dev/null +++ b/Classes/Domain/Model/Dto/Table.php @@ -0,0 +1,155 @@ +tableName = $tableName; + $this->title = $tcaCtrl['title']; + $this->titleField = $tcaCtrl['label']; + $this->deletedField = isset($tcaCtrl['delete']) ? $tcaCtrl['delete'] : ''; + $this->titleLabel = $GLOBALS['TCA'][$tableName]['columns'][$this->titleField]['label']; + $this->gdprRestrictionField = $tcaCtrl['gdpr']['restriction_field'] ?: ''; + $this->gdprRandomizedField = $tcaCtrl['gdpr']['randomized_field'] ?: ''; + $this->gdprRandomizeMapping = $tcaCtrl['gdpr']['randomize_mapping'] ?: []; + $this->gdprRandomizedDateField = $tcaCtrl['gdpr']['randomize_datefield'] ?: ''; + $this->gdprExpirePeriod = $tcaCtrl['gdpr']['randomize_expirePeriod'] ?: 365; + } + + /** + * @param string $tableName + * @return Table + */ + public static function getInstance(string $tableName): self + { + return GeneralUtility::makeInstance(__CLASS__, $tableName); + } + + /** + * @return string + */ + public function getTableName(): string + { + return $this->tableName; + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @return string + */ + public function getTitleField(): string + { + return $this->titleField; + } + + /** + * @return string + */ + public function getDeletedField(): string + { + return $this->deletedField; + } + + /** + * @return string + */ + public function getTitleLabel(): string + { + return $this->titleLabel; + } + + /** + * @return string + */ + public function getGdprRestrictionField(): string + { + return $this->gdprRestrictionField; + } + + /** + * @return string + */ + public function getGdprRandomizedField(): string + { + return $this->gdprRandomizedField; + } + + /** + * @return array + */ + public function getGdprRandomizeMapping(): array + { + return $this->gdprRandomizeMapping; + } + + /** + * @return string + */ + public function getGdprRandomizedDateField(): string + { + return $this->gdprRandomizedDateField; + } + + /** + * @return int + */ + public function getGdprExpirePeriod(): int + { + return $this->gdprExpirePeriod; + } + + public function randomizationEnabled(): bool + { + return !empty($this->gdprRandomizedField) && !empty($this->gdprRandomizeMapping); + } + +} diff --git a/Classes/Domain/Repository/BaseRepository.php b/Classes/Domain/Repository/BaseRepository.php new file mode 100644 index 0000000..7dab465 --- /dev/null +++ b/Classes/Domain/Repository/BaseRepository.php @@ -0,0 +1,24 @@ +getConnectionForTable($table); + } + + protected function getQueryBuilder(string $table): QueryBuilder + { + return $this->getConnection($table)->createQueryBuilder(); + } + +} diff --git a/Classes/Domain/Repository/FormRepository.php b/Classes/Domain/Repository/FormRepository.php new file mode 100644 index 0000000..3167e07 --- /dev/null +++ b/Classes/Domain/Repository/FormRepository.php @@ -0,0 +1,135 @@ +uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); + $this->registry = GeneralUtility::makeInstance(Registry::class); + } + + public function getAllForms() + { + $data = [ + 'ext-form' => $this->getFormForms(), + 'ext-powermail' => $this->getPowermailForms(), +// 'ext-formhandler' => $this->getFormhandlerForms() + ]; + + return $data; + } + + protected function getPowermailForms() + { + $queryBuilder = $this->getQueryBuilder('tt_content'); + $rows = $queryBuilder + ->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter('list', \PDO::PARAM_STR)), + $queryBuilder->expr()->eq('list_type', $queryBuilder->createNamedParameter('powermail_pi1', \PDO::PARAM_STR)) + ) + ->execute() + ->fetchAll(); + + $rows = $this->enhanceRows('powermail', $rows); + return $rows; + } + + protected function getFormhandlerForms() + { + return []; + } + + protected function getFormForms() + { + $queryBuilder = $this->getQueryBuilder('tt_content'); + $rows = $queryBuilder + ->select('*') + ->from('tt_content') + ->where( + $queryBuilder->expr()->eq('CType', $queryBuilder->createNamedParameter('form_formframework', \PDO::PARAM_STR)) + ) + ->execute() + ->fetchAll(); + + $rows = $this->enhanceRows('form', $rows); + return $rows; + } + + protected function enhanceRows(string $type, array $rows) + { + foreach ($rows as $key => $row) { + $status = $this->registry->get(self::REGISTRY_NAMESPACE, $this->getRegistryKey($type, $row['uid']), false); + $rows[$key]['_meta'] = [ + 'type' => $type, + 'isValidated' => $status, + 'links' => [ + 'editContentElement' => $this->createEditUri('tt_content', $row['uid']) + ], + 'page' => BackendUtility::getRecord('pages', $row['pid']), + 'path' => BackendUtility::getRecordPath($row['pid'], $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW), 1000) + ]; + } + + return $rows; + } + + protected function getRegistryKey(string $type, int $id): string + { + return sprintf('%s-%s', $type, $id); + } + + protected function createEditUri(string $table, int $id): string + { + $urlParameters = [ + 'edit' => [ + $table => [ + $id => 'edit' + ] + ], + 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI') + ]; + return (string)$this->uriBuilder->buildUriFromRoute('record_edit', $urlParameters); + } + + /** + * Returns the current BE user. + * + * @return BackendUserAuthentication + */ + protected function getBackendUser(): BackendUserAuthentication + { + return $GLOBALS['BE_USER']; + } +} diff --git a/Classes/Domain/Repository/LogRepository.php b/Classes/Domain/Repository/LogRepository.php new file mode 100644 index 0000000..5000039 --- /dev/null +++ b/Classes/Domain/Repository/LogRepository.php @@ -0,0 +1,41 @@ +getTimestamp(); + } else { + // try to check strtotime + $timeFromString = strtotime($timeInput); + + if ($timeFromString) { + $timeLimit = $timeFromString; + } + } + } + return $timeLimit; + } + +} diff --git a/Classes/Domain/Repository/RecordRepository.php b/Classes/Domain/Repository/RecordRepository.php new file mode 100644 index 0000000..8d2af15 --- /dev/null +++ b/Classes/Domain/Repository/RecordRepository.php @@ -0,0 +1,71 @@ +logger = GeneralUtility::makeInstance(LogManager::class); + } + + public function getRestrictedRows(string $table): array + { + $tableInformation = Table::getInstance($table); + + $queryBuilder = $this->getQueryBuilder($table); + $queryBuilder->getRestrictions() + ->removeByType(GdprRestriction::class) + ->removeByType(HiddenRestriction::class) + ->add(GeneralUtility::makeInstance(GdprOnlyRestriction::class)); + + return $queryBuilder + ->select('uid', $tableInformation->getTitleField(), $tableInformation->getGdprRestrictionField()) + ->from($table) + ->execute() + ->fetchAll(); + } + + public function getStatisticOfTable(string $table): array + { + $restrictionFieldName = Table::getInstance($table)->getGdprRestrictionField(); + + $queryBuilder = $this->getQueryBuilder($table); + $queryBuilder->getRestrictions() + ->removeAll() + ->removeByType(GdprRestriction::class); + + $rows = $queryBuilder + ->select($restrictionFieldName) + ->selectLiteral('count(' . $restrictionFieldName . ') as count') + ->from($table) + ->groupBy($restrictionFieldName) + ->execute() + ->fetchAll(); + + return [ + 'restricted' => (int)$rows[1]['count'], + 'public' => (int)$rows[0]['count'] + ]; + } + + + + +} diff --git a/Classes/Hooks/DataHandlerHook.php b/Classes/Hooks/DataHandlerHook.php new file mode 100644 index 0000000..3ee7aeb --- /dev/null +++ b/Classes/Hooks/DataHandlerHook.php @@ -0,0 +1,56 @@ +logManager = GeneralUtility::makeInstance(LogManager::class); + } + + /** + * Hooks into TCE Main and watches all record creations and updates. If it + * detects that the new/updated record belongs to a table configured for + * indexing through Solr, we add the record to the index queue. + * + * @param string $status Status of the current operation, 'new' or 'update' + * @param string $table The table the record belongs to + * @param mixed $uid The record's uid, [integer] or [string] (like 'NEW...') + * @param array $fields The record's data + * @param DataHandler $tceMain TYPO3 Core Engine parent object + * @return void + */ + public function processDatamap_afterDatabaseOperations( + $status, + $table, + $uid, + array $fields, + DataHandler $tceMain + ) + { + if (TableInformation::isTableEnabled($table)) { + $tableInformation = Table::getInstance($table); + + $restrictionField = $tableInformation->getGdprRestrictionField(); + if ($restrictionField && isset($fields[$restrictionField])) { + if ($fields[$restrictionField]) { + $this->logManager->log($table, $uid, LogManager::STATUS_RESTRICT); + } else { + $this->logManager->log($table, $uid, LogManager::STATUS_REENABLE); + } + } + } + } +} diff --git a/Classes/Hooks/QueryBuilderHook.php b/Classes/Hooks/QueryBuilderHook.php new file mode 100644 index 0000000..0c422b1 --- /dev/null +++ b/Classes/Hooks/QueryBuilderHook.php @@ -0,0 +1,21 @@ +getRestrictionContainer(); + $fo->add(GeneralUtility::makeInstance(GdprRestriction::class)); + } +} \ No newline at end of file diff --git a/Classes/Log/LogManager.php b/Classes/Log/LogManager.php new file mode 100644 index 0000000..91e071e --- /dev/null +++ b/Classes/Log/LogManager.php @@ -0,0 +1,72 @@ + 5) { + throw new \UnexpectedValueException(sprintf('Value "%s" is invalid, use one of [1,2,3,4]', $status)); + } + $backendUser = $this->getBackendUser()->user; + $fieldValues = [ + 'tstamp' => $GLOBALS['EXEC_TIME'], + 'table_name' => $tableName, + 'record_id' => $id, + 'status' => $status, + ]; + if (is_array($backendUser)) { + $fieldValues['user'] = $backendUser['uid']; + $fieldValues['user_name_text'] = $this->getUsernameText($backendUser); + } else { + // @todo CLI? + $fieldValues['user'] = -1; + $fieldValues['user_name_text'] = 'CLI'; + } + + + GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionForTable('tx_gdpr_domain_model_log') + ->insert('tx_gdpr_domain_model_log', $fieldValues); + } + + protected function getUsernameText(array $user): string + { + $data = [ + 'username' => $user['username'], + 'realName' => $user['realName'], + 'email' => $user['email'] + ]; + return json_encode($data); + } + + /** + * @return BackendUserAuthentication + */ + protected function getBackendUser(): BackendUserAuthentication + { + return $GLOBALS['BE_USER']; + } +} \ No newline at end of file diff --git a/Classes/Report/GdprStatusReport.php b/Classes/Report/GdprStatusReport.php new file mode 100644 index 0000000..6b3c4ed --- /dev/null +++ b/Classes/Report/GdprStatusReport.php @@ -0,0 +1,71 @@ + $this->getStatusOfGdpr(), + ]; + return $statuses; + } + + protected function getStatusOfGdpr(): ReportStatus + { + $recordRepository = GeneralUtility::makeInstance(RecordRepository::class); + + $messages = []; + $actionRequired = false; + $status = ReportStatus::OK; + foreach (TableInformation::getAllEnabledTables() as $table) { + $statistic = $recordRepository->getStatisticOfTable($table); + $countAction = $statistic['restricted']; + $countNoAction = $statistic['public']; + $sum = $countAction + $countNoAction; + if ($countAction > 0) { + $status = ReportStatus::WARNING; + $messages[] = sprintf('In Table "%s" are %s rows total, %s need an action!', $table, $sum, $countAction); + } else { + $messages[] = sprintf('In Table "%s" are %s rows total, no action required.', $table, $sum); + } + } + + $message = implode('
', $messages); + + + return GeneralUtility::makeInstance( + ReportStatus::class, + 'GDPR Handling', + 'Some information regarding GDPR related sensible information:', + $message, + $status + ); + } + + /** + * @return LanguageService + */ + protected function getLanguageService(): LanguageService + { + return $GLOBALS['LANG']; + } +} diff --git a/Classes/Service/TableInformation.php b/Classes/Service/TableInformation.php new file mode 100644 index 0000000..8c431fa --- /dev/null +++ b/Classes/Service/TableInformation.php @@ -0,0 +1,40 @@ + $tca['ctrl']['title'], + 'labelField' => $tca['ctrl']['label'] + ]; + } +} diff --git a/Classes/Service/Tca.php b/Classes/Service/Tca.php new file mode 100644 index 0000000..41ee161 --- /dev/null +++ b/Classes/Service/Tca.php @@ -0,0 +1,86 @@ +tableName = $tableName; + + $GLOBALS['TCA'][$this->tableName]['ctrl']['gdpr'] = [ + 'enabled' => true + ]; + } + + public static function getInstance(string $tableName): Tca + { + return GeneralUtility::makeInstance(self::class, $tableName); + } + + public function addRestriction(string $fieldName) + { + $GLOBALS['TCA'][$this->tableName]['ctrl']['gdpr']['restriction_field'] = $fieldName; + $this->fields[$fieldName] = [ + 'label' => 'LLL:EXT:gdpr/Resources/Private/Language/locallang.xlf:field.restriction_field', + 'exclude' => true, + 'config' => [ + 'type' => 'check', + 'default' => 0 + ] + ]; + + return $this; + } + + public function addRandomization(string $fieldName, array $randomizationOptions) + { + $GLOBALS['TCA'][$this->tableName]['ctrl']['gdpr']['randomized_field'] = $fieldName; + $GLOBALS['TCA'][$this->tableName]['ctrl']['gdpr']['randomize_mapping'] = $randomizationOptions['mapping']; + $GLOBALS['TCA'][$this->tableName]['ctrl']['gdpr']['randomize_datefield'] = $randomizationOptions['dateField']; + $GLOBALS['TCA'][$this->tableName]['ctrl']['gdpr']['randomize_expirePeriod'] = $randomizationOptions['expirePeriod']; + + $this->fields[$fieldName] = [ + 'label' => 'LLL:EXT:gdpr/Resources/Private/Language/locallang.xlf:field.randomized_field', + 'exclude' => true, + 'config' => [ + 'type' => 'check', + 'readOnly' => true, + 'default' => 0 + ] + ]; + return $this; + } + + public function add(string $position) + { + if (!empty($this->fields)) { + ExtensionManagementUtility::addTCAcolumns($this->tableName, $this->fields); + $GLOBALS['TCA'][$this->tableName]['palettes']['paletteGdpr'] = [ + 'showitem' => implode(', ', array_keys($this->fields)), + ]; + + ExtensionManagementUtility::addToAllTCAtypes( + $this->tableName, + '--palette--;LLL:EXT:gdpr/Resources/Private/Language/locallang.xlf:palette;paletteGdpr,', + '', + $position + ); + } + } + +} diff --git a/Classes/Xclass/DefaultRestrictionContainer.php b/Classes/Xclass/DefaultRestrictionContainer.php new file mode 100644 index 0000000..050b355 --- /dev/null +++ b/Classes/Xclass/DefaultRestrictionContainer.php @@ -0,0 +1,30 @@ +addGdprConstraints(); + } + + public function removeAll() + { + parent::removeAll(); + $this->addGdprConstraints(); + + return $this; + } + + protected function addGdprConstraints() + { + $this->add(GeneralUtility::makeInstance(GdprRestriction::class)); + } +} diff --git a/Classes/Xclass/FrontendRestrictionContainer.php b/Classes/Xclass/FrontendRestrictionContainer.php new file mode 100644 index 0000000..68e57cf --- /dev/null +++ b/Classes/Xclass/FrontendRestrictionContainer.php @@ -0,0 +1,30 @@ +addGdprConstraints(); + } + + public function removeAll() + { + parent::removeAll(); + $this->addGdprConstraints(); + + return $this; + } + + protected function addGdprConstraints() + { + $this->add(GeneralUtility::makeInstance(GdprRestriction::class)); + } +} diff --git a/Configuration/Commands.php b/Configuration/Commands.php new file mode 100644 index 0000000..c3f32a9 --- /dev/null +++ b/Configuration/Commands.php @@ -0,0 +1,17 @@ + [ + 'class' => \GeorgRinger\Gdpr\Command\RandomizeCommand::class + ], + 'gdpr:anonymizeIp' => [ + 'class' => \GeorgRinger\Gdpr\Command\AnonymizeIpCommand::class + ] +]; diff --git a/Configuration/TCA/Overrides/be_users.php b/Configuration/TCA/Overrides/be_users.php new file mode 100644 index 0000000..b3f63db --- /dev/null +++ b/Configuration/TCA/Overrides/be_users.php @@ -0,0 +1,41 @@ + [ + 'label' => 'LLL:EXT:gdpr/Resources/Private/Language/locallang.xlf:be_users.gdpr_module_enable', + 'config' => [ + 'type' => 'check', + 'default' => 0 + ] + ] +]; + +if (version_compare(TYPO3_branch, '9.2', '>=')) { + $fields['gdpr_module_enable']['config'] = [ + 'type' => 'check', + 'renderType' => 'checkboxLabeledToggle', + 'items' => [ + [ + 0 => '', + 1 => '', + 'labelChecked' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.enabled', + 'labelUnchecked' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.disabled' + ], + ], + ]; +} + +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('be_users', $fields); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes( + 'be_users', + 'gdpr_module_enable', + '', + 'before:disableIPlock' +); + +$tca = \GeorgRinger\Gdpr\Service\Tca::getInstance('be_users'); +$tca + ->addRestriction('gdpr_restricted') + ->add('after:disable'); \ No newline at end of file diff --git a/Configuration/TCA/Overrides/fe_users.php b/Configuration/TCA/Overrides/fe_users.php new file mode 100644 index 0000000..5669480 --- /dev/null +++ b/Configuration/TCA/Overrides/fe_users.php @@ -0,0 +1,23 @@ +addRestriction('gdpr_restricted') + ->addRandomization('gdpr_randomized', [ + 'dateField' => 'tstamp', + 'expirePeriod' => 360, + 'mapping' => [ + 'username' => 'userName', + 'email' => 'email', + 'password' => 'password', + 'zip' => 'postcode', + 'address' => 'address', + 'city' => 'city', + 'first_name' => 'firstName', + 'last_name' => 'lastName', + 'telephone' => 'e164PhoneNumber', + 'fax' => 'e164PhoneNumber', + ] + ]) + ->add('after:disable'); \ No newline at end of file diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf new file mode 100644 index 0000000..bccb890 --- /dev/null +++ b/Resources/Private/Language/locallang.xlf @@ -0,0 +1,21 @@ + + + +
+ + + GDPR + + + Enable GDPR module + + + Record is randomized + + + Record must be hidden everywhere + + + + + diff --git a/Resources/Private/Language/locallang_modadministration.xlf b/Resources/Private/Language/locallang_modadministration.xlf new file mode 100644 index 0000000..9e77493 --- /dev/null +++ b/Resources/Private/Language/locallang_modadministration.xlf @@ -0,0 +1,17 @@ + + + +
+ + + Gdpr Administration + + + Administrate for GDPR related content + + + This module provides an easy way to administrate records + + + + diff --git a/Resources/Private/Language/locallang_rendering.xlf b/Resources/Private/Language/locallang_rendering.xlf new file mode 100644 index 0000000..e5955ef --- /dev/null +++ b/Resources/Private/Language/locallang_rendering.xlf @@ -0,0 +1,14 @@ + + + +
+ + + Click to load video! + + + Load the video by clicking here. Only then data will be transferred to the video provider! + + + + diff --git a/Resources/Private/Layouts/Backend/Default.html b/Resources/Private/Layouts/Backend/Default.html new file mode 100644 index 0000000..74127b2 --- /dev/null +++ b/Resources/Private/Layouts/Backend/Default.html @@ -0,0 +1,6 @@ + +
+ + +
+ diff --git a/Resources/Private/Partials/Forms/Listing.html b/Resources/Private/Partials/Forms/Listing.html new file mode 100644 index 0000000..cbc6c80 --- /dev/null +++ b/Resources/Private/Partials/Forms/Listing.html @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + +
uidHeaderPage
+ + + {row.uid} + + {row.header} + + {row._meta.path} + +
+ + + + + + + + + + + + + + + +
+
diff --git a/Resources/Private/Partials/TableListing.html b/Resources/Private/Partials/TableListing.html new file mode 100644 index 0000000..46c47d0 --- /dev/null +++ b/Resources/Private/Partials/TableListing.html @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + +
Status{f:translate(key:meta.titleLabel,default:meta.titleField)}Actions
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
{row.{meta.titleField}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/Resources/Private/Templates/Administration/Configuration.html b/Resources/Private/Templates/Administration/Configuration.html new file mode 100644 index 0000000..fd221c2 --- /dev/null +++ b/Resources/Private/Templates/Administration/Configuration.html @@ -0,0 +1,43 @@ + + + + + +

Configuration

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{f:translate(key:table.title)} ({tableName})
Restriction field{table.gdprRestrictionField}
Randomization field{table.gdprRandomizedField}
Randomization mapping{table.gdprRandomizeMapping}
Randomization date field{table.gdprRandomizedDateField}
Randomization expire period{table.gdprExpirePeriod}
+
+
+ diff --git a/Resources/Private/Templates/Administration/Delete.html b/Resources/Private/Templates/Administration/Delete.html new file mode 100644 index 0000000..0ed053b --- /dev/null +++ b/Resources/Private/Templates/Administration/Delete.html @@ -0,0 +1 @@ +- empty - diff --git a/Resources/Private/Templates/Administration/FormOverview.html b/Resources/Private/Templates/Administration/FormOverview.html new file mode 100644 index 0000000..819a61a --- /dev/null +++ b/Resources/Private/Templates/Administration/FormOverview.html @@ -0,0 +1,27 @@ + + + + + +

Form overviews

+

Forms are acrusial part regarding privacy. Listing of all forms

+ + + + +
+
{extension}
+ + + + + +
No forms found.
+
+
+
+
+ +
+ diff --git a/Resources/Private/Templates/Administration/FormStatusUpdate.html b/Resources/Private/Templates/Administration/FormStatusUpdate.html new file mode 100644 index 0000000..55db4d2 --- /dev/null +++ b/Resources/Private/Templates/Administration/FormStatusUpdate.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Resources/Private/Templates/Administration/Help.html b/Resources/Private/Templates/Administration/Help.html new file mode 100644 index 0000000..0092e7b --- /dev/null +++ b/Resources/Private/Templates/Administration/Help.html @@ -0,0 +1,155 @@ + + + + + +

Help

+

Some words about GDPR

+ + +

A robust PIA should document the following information: Taken from www.smashingmagazine.com/2018/02/gdpr-for-web-developers/ +

+ +
+ + +
+
+
+ +
+
+

Data collection and retention

+
+
    +
  1. What personal data is processed
  2. +
  3. How is that data collected and retained?
  4. +
  5. Is the data stored locally, on our servers, or both?
  6. +
  7. For how long is data stored, and when is the data deleted?
  8. +
  9. Is the data collection and processing specified, explicit, and legitimate?
  10. +
  11. What is the process for granting consent for the data processing, and is consent + explicit + and + verifiable? +
  12. +
  13. What is the basis of the consent for the data processing?
  14. +
  15. If not based on consent, what is the legal basis for the data processing?
  16. +
  17. Is the data minimized to what is explicitly required?
  18. +
  19. Is the data accurate and kept up to date?
  20. +
  21. How are users informed about the data processing?
  22. +
  23. What controls do users have over the data collection and retention?
  24. +
+
+ +
+
+
+
+
+
+ +
+
+

Technical and security measures

+
+
    +
  1. Is the data encrypted?
  2. +
  3. Is the data anonymized or pseudonymized?
  4. +
  5. Is the data backed up?
  6. +
  7. What are the technical and security measures at the host location?
  8. +
+
+
+
+
+ +
+
+
+ +
+
+

Personnel

+
+
    +
  1. Who has access to the data?
  2. +
  3. What data protection training have those individuals received?
  4. +
  5. What security measures do those individuals work with?
  6. +
  7. What data breach notification and alert procedures are in place?
  8. +
  9. What procedures are in place for government requests?
  10. +
+
+
+
+
+ +
+
+
+ +
+
+

Subject access rights

+
+
    +
  1. How does the data subject exercise their access rights?
  2. +
  3. How does the data subject exercise their right to data portability?
  4. +
  5. How does the data subject exercise their rights to erasure and the right to be + forgotten? +
  6. +
  7. How does the data subject exercise their right to restrict and object?
  8. +
+
+
+
+
+ +
+
+
+ +
+
+

Legal

+
+
    +
  1. Are the obligations of all data processors, including subcontractors, covered by a + contract? +
  2. +
  3. If the data is transferred outside the European Union, what are the protective measures + and + safeguards? +
  4. +
+
+
+
+
+ +
+
+
+ +
+
+

Risks

+
+
    +
  1. What are the risks to the data subjects if the data is misused, mis-accessed, or + breached? +
  2. +
  3. What are the risks to the data subjects if the data is modified?
  4. +
  5. What are the risks to the data subjects if the data is lost?
  6. +
  7. What are the main sources of risk?
  8. +
  9. What steps have been taken to mitigate those risks?
  10. +
+
+
+
+
+
+ + + diff --git a/Resources/Private/Templates/Administration/Index.html b/Resources/Private/Templates/Administration/Index.html new file mode 100644 index 0000000..b2de136 --- /dev/null +++ b/Resources/Private/Templates/Administration/Index.html @@ -0,0 +1,28 @@ + + + + + +

GDPR

+

Overview over all records flagged as holding sensitive data.

+ +
+
{f:translate(key:data.meta.title,default:data.meta.title)} + ({data.statistics.public} / {data.statistics.restricted}) +
+ + + + + +
No flagged records.
+
+
+
+ +
+ +
+ diff --git a/Resources/Private/Templates/Administration/Log.html b/Resources/Private/Templates/Administration/Log.html new file mode 100644 index 0000000..b76c136 --- /dev/null +++ b/Resources/Private/Templates/Administration/Log.html @@ -0,0 +1,131 @@ + + + + + +

Logs

+

List of actions logged regarding GDPR.

+ + + +
+ + +
+ +
+
+ +
+ + +
+
+ + + + +
+
+
+
+ + + + +
+
+
+ + +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ + +
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
No results found!
+
+ + + + diff --git a/Resources/Private/Templates/Administration/ModuleNotEnabled.html b/Resources/Private/Templates/Administration/ModuleNotEnabled.html new file mode 100644 index 0000000..c7d0add --- /dev/null +++ b/Resources/Private/Templates/Administration/ModuleNotEnabled.html @@ -0,0 +1,14 @@ + + + + + +

GDPR

+ + This module must be explicitly enabled for your user account! +
- even if your user is already an administrator! +
+ +
+ diff --git a/Resources/Private/Templates/Administration/Randomize.html b/Resources/Private/Templates/Administration/Randomize.html new file mode 100644 index 0000000..0ed053b --- /dev/null +++ b/Resources/Private/Templates/Administration/Randomize.html @@ -0,0 +1 @@ +- empty - diff --git a/Resources/Private/Templates/Administration/Reenable.html b/Resources/Private/Templates/Administration/Reenable.html new file mode 100644 index 0000000..0ed053b --- /dev/null +++ b/Resources/Private/Templates/Administration/Reenable.html @@ -0,0 +1 @@ +- empty - diff --git a/Resources/Private/Templates/Administration/Search.html b/Resources/Private/Templates/Administration/Search.html new file mode 100644 index 0000000..ed9655c --- /dev/null +++ b/Resources/Private/Templates/Administration/Search.html @@ -0,0 +1,63 @@ + + + + + +

Search

+ + + +
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+
+ +
+
+
+ + + + + +
+
{f:translate(key:data.meta.title,default:data.meta.title)} + ({data.rows -> f:count()}) +
+ +
+
+
+ +
No results found
+
+ +
+
+ + +
+ diff --git a/Resources/Private/Templates/Rendering/Youtube.html b/Resources/Private/Templates/Rendering/Youtube.html new file mode 100644 index 0000000..f902cf1 --- /dev/null +++ b/Resources/Private/Templates/Rendering/Youtube.html @@ -0,0 +1,37 @@ +
+
+
+ {f:translate(key:'LLL:EXT:gdpr/Resources/Private/Language/locallang_rendering.xlf:overlay.title')} +
+

+ {f:translate(key:'LLL:EXT:gdpr/Resources/Private/Language/locallang_rendering.xlf:overlay.description')}

+
+
+ {html -> f:format.raw()} +
+ + + \ No newline at end of file diff --git a/Resources/Public/Icons/Extension.svg b/Resources/Public/Icons/Extension.svg new file mode 100644 index 0000000..465f232 --- /dev/null +++ b/Resources/Public/Icons/Extension.svg @@ -0,0 +1,12 @@ + + + + background + + + + Layer 1 + + + + \ No newline at end of file diff --git a/Resources/Public/Icons/form-overview.svg b/Resources/Public/Icons/form-overview.svg new file mode 100644 index 0000000..6c73ec0 --- /dev/null +++ b/Resources/Public/Icons/form-overview.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Resources/Public/Icons/module.svg b/Resources/Public/Icons/module.svg index bca7a17..465f232 100644 --- a/Resources/Public/Icons/module.svg +++ b/Resources/Public/Icons/module.svg @@ -1 +1,12 @@ - \ No newline at end of file + + + + background + + + + Layer 1 + + + + \ No newline at end of file diff --git a/ext_localconf.php b/ext_localconf.php new file mode 100644 index 0000000..395a313 --- /dev/null +++ b/ext_localconf.php @@ -0,0 +1,23 @@ + 'form-overview.svg', +]; +foreach ($icons as $identifier => $path) { + $iconRegistry->registerIcon( + $identifier, + \TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider::class, + ['source' => 'EXT:gdpr/Resources/Public/Icons/' . $path] + ); +} \ No newline at end of file diff --git a/ext_tables.php b/ext_tables.php new file mode 100644 index 0000000..5a6bc1c --- /dev/null +++ b/ext_tables.php @@ -0,0 +1,32 @@ + \GeorgRinger\Gdpr\Xclass\DefaultRestrictionContainer::class +); +$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer::class] = array( + 'className' => \GeorgRinger\Gdpr\Xclass\FrontendRestrictionContainer::class +); + + +$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] + = \GeorgRinger\Gdpr\Hooks\DataHandlerHook::class; + +if (TYPO3_MODE === 'BE') { + $isVersion9Up = \TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version) >= 9000000; + \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule( + 'GeorgRinger.gdpr', + $isVersion9Up ? 'site' : 'tools', + 'tx_gdpr_m1', + '', + ['Administration' => 'index,help,search,delete,disable,reenable,randomize,moduleNotEnabled,log,configuration,formOverview,formStatusUpdate'], + [ + 'access' => 'user,group', + 'icon' => 'EXT:gdpr/Resources/Public/Icons/module.svg', + 'labels' => 'LLL:EXT:gdpr/Resources/Private/Language/locallang_modadministration.xlf', + ] + ); + + + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['reports']['tx_reports']['status']['providers']['system'][] = \GeorgRinger\Gdpr\Report\GdprStatusReport::class; + +} diff --git a/ext_tables.sql b/ext_tables.sql new file mode 100644 index 0000000..84fbfcd --- /dev/null +++ b/ext_tables.sql @@ -0,0 +1,29 @@ +# +# Table structure for table 'tx_gdpr_domain_model_log' +# +CREATE TABLE tx_gdpr_domain_model_log ( + uid int(11) NOT NULL auto_increment, + pid int(11) DEFAULT '0' NOT NULL, + tstamp int(11) DEFAULT '0' NOT NULL, + table_name varchar(255) NOT NULL DEFAULT '', + record_id int(11) DEFAULT '0' NOT NULL, + status tinyint(4) DEFAULT '0' NOT NULL, + user int(11) DEFAULT '0' NOT NULL, + user_name_text varchar(255) NOT NULL DEFAULT '', + + PRIMARY KEY (uid), + KEY parent (pid) +); + +# +# Table structure for table 'fe_users' +# +CREATE TABLE fe_users ( + gdpr_restricted tinyint(4) DEFAULT '0' NOT NULL, + gdpr_randomized tinyint(4) DEFAULT '0' NOT NULL +); + +CREATE TABLE be_users ( + gdpr_restricted tinyint(4) DEFAULT '0' NOT NULL, + gdpr_module_enable tinyint(4) DEFAULT '0' NOT NULL +); \ No newline at end of file From 33c8de8b58389d8f06a5520d557a8977d555ab39 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Tue, 8 May 2018 07:54:05 +0200 Subject: [PATCH 25/33] comparison --- Readme.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Readme.md b/Readme.md index 0a1e9e7..5e6b473 100644 --- a/Readme.md +++ b/Readme.md @@ -18,6 +18,22 @@ Contact me - *Georg Ringer* via [mail](mailto:mail@ringer.it), [TYPO3 slack](htt Costs are **per** installation - discounts possible, ask me directly. +### Differences free <> paid version + +| | Free | Paid | +|:-----------------------------------|:-----|:-----| +| API to hide records | ✓ | ✓ | +| Form overview | ✓ | ✓ | +| Individual form status | | ✓ | +| Randomization | | ✓ | +| Custom icon for randomized records | | ✓ | +| CLI for randomization | | ✓ | +| Log module | | ✓ | +| Search module | | ✓ | +| Reports module | ✓ | ✓ | +| Improved privacy for YouTube | | ✓ | +| Support further development | | ✓ | + ## Table of Contents - [Screenshots](../Screenshots.md) From 6f5a33ac2bc364f140facfe92293a98d3b629162 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Wed, 9 May 2018 13:49:47 +0200 Subject: [PATCH 26/33] Update Readme.md --- Readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Readme.md b/Readme.md index 5e6b473..f2ea3f1 100644 --- a/Readme.md +++ b/Readme.md @@ -6,6 +6,8 @@ This extensions makes it easier for website owners and agencies to have the site ## Costs +*The license is a one time fee and includes every update until April 2019.* + - Personal license for one site: *€ 240 excl. taxes* - Professional license for one site: *€ 1450 excl. taxes* (*\**) - Agency license for up to 25 sites: *€ 5000 excl. taxes* (*\**) From 5274676409318e8bb4baa9cdb6a8008c97d3e320 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Fri, 11 May 2018 18:59:53 +0200 Subject: [PATCH 27/33] [DOC] More configuration examples --- Features/FormOverview.md | 4 +++ Features/Randomization.md | 9 ++++--- Features/VideoEmbedPrivacy.md | 49 +++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/Features/FormOverview.md b/Features/FormOverview.md index 4f1fb7c..0bfb796 100644 --- a/Features/FormOverview.md +++ b/Features/FormOverview.md @@ -10,3 +10,7 @@ Each form must be checked if it complies with the GDPR. This can't be done by th - Listing of all forms, generated by the most popular form extensions `form` and `powermail`: - Provide a state to know which forms have already been checked and which need to be done. + +## Configuration + +No configuration required. If one of the supported form extensions is installed, all content elements showing forms are rendered. \ No newline at end of file diff --git a/Features/Randomization.md b/Features/Randomization.md index b8f086e..e54e564 100644 --- a/Features/Randomization.md +++ b/Features/Randomization.md @@ -11,7 +11,7 @@ Randomization is a good way to remove the private data from a record and still b Records can be randomized by using the `fzaninotto/faker` library. By providing a mapping per table, is possible to exchange the data with dummy information which looks still ok and can be used in exports. An example would be -``` +```bash Array ( [username] => martens.conny @@ -35,11 +35,12 @@ See [Configuration](../Configuration.md) for the full configuration. ## Using a CLI command -By using a CLI command, all data with a specific age can be randomized: `./web/typo3/sysext/core/bin/typo3 gdpr:randomize` +By using a CLI command, all data with a specific age can be randomized. +An example call looks like `./web/typo3/sysext/core/bin/typo3 gdpr:randomize` -Result can look like this +The Result can look like this -``` +```bash Randomize data ============== diff --git a/Features/VideoEmbedPrivacy.md b/Features/VideoEmbedPrivacy.md index 480fc91..9641d2c 100644 --- a/Features/VideoEmbedPrivacy.md +++ b/Features/VideoEmbedPrivacy.md @@ -3,3 +3,52 @@ # Improved privacy for embedded videos Before videos from the platforms YouTube and Vimeo are actually loaded, the user is asked for consent. This improves the privacy and as an additional benefit also the loading time. + +## Configuration + +The template used to show the overlay can be configured with an additional setting +of the ViewHelper ``. + +Since the versions `8.7.14` and `7.6.28` the ViewHelper call in `fluid_styled_content` looks like this: + +```html + +``` + +This allows to override the template with the following TypoScript: + +``` +lib.contentElement { + settings { + media { + additionalConfig { + gdpr-vimeo-template = EXT:sitepackage/Resources/Private/Templates/Gdpr/Vimeo.html + gdpr-youtube-template = EXT:sitepackage/Resources/Private/Templates/Gdpr/Youtube.html + } + } + } +} +``` + +### Usage in custom extensions + +If the `` is used in custom extensions, use a configuration like `additionalConfig="{settings.mediaConfiguration}"` and a TS like + +``` +plugin.tx_yourExt { + settings { + mediaConfiguration { + gdpr-vimeo-template = EXT:sitepackage/Resources/Private/Templates/Gdpr/Vimeo.html + gdpr-youtube-template = EXT:sitepackage/Resources/Private/Templates/Gdpr/Youtube.html + } + } +} +``` + +### Templates + +The templates (default can be found at `EXT:gdpr/Resources/Private/Templates/Rendering/` contain +the styling and vanilla JS for exchanging the overlay with the actual video iframe. \ No newline at end of file From 83c9ad5563f560b19b44e35651a4a17b87b59cd7 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Fri, 11 May 2018 19:12:52 +0200 Subject: [PATCH 28/33] move configuration --- Configuration.md | 57 --------------------------------------- Features/PersonalData.md | 22 ++++++++++++++- Features/Randomization.md | 41 +++++++++++++++++++++------- Readme.md | 5 ++-- 4 files changed, 55 insertions(+), 70 deletions(-) delete mode 100644 Configuration.md diff --git a/Configuration.md b/Configuration.md deleted file mode 100644 index 1ba9df9..0000000 --- a/Configuration.md +++ /dev/null @@ -1,57 +0,0 @@ -[<- back](docs/Readme.md) - -# Configuration - -## Add restriction to custom tables - -Example call how an own record can be added. - -```php -$tca = \GeorgRinger\Gdpr\Service\Tca::getInstance('be_users'); -$tca - ->addRestriction('gdpr_restricted') - -add('after:disable'); -``` - -## Add randomization - -```php -$tca = \GeorgRinger\Gdpr\Service\Tca::getInstance('fe_users'); -$tca - ->addRestriction('gdpr_restricted') - ->addRandomization('gdpr_randomized', [ - 'dateField' => 'tstamp', - 'expirePeriod' => 360, - 'mapping' => [ - 'username' => 'userName', - 'email' => 'email', - 'password' => 'password', - 'zip' => 'postcode', - 'address' => 'address', - 'city' => 'city', - 'first_name' => 'firstName', - 'last_name' => 'lastName', - 'telephone' => 'e164PhoneNumber', - 'fax' => 'e164PhoneNumber', - ] - ]) - ->add('after:disable'); -``` - -Randomization uses [Faker](https://github.com/fzaninotto/Faker#formatters) and the mapping accepts any property of faker. - -## Screenshots - -The GDPR module shows the current configuration. - -![Configuration](Resources/Public/Documentation/Screenshots/Configuration.png) - -# Technical background - -The implementation is based on the `RestrictionContainers` of the TYPO3 core. - -## Drawbacks - -The limitation of the implementation is that only records having a TCA configuration are covered. -Furthermore direct access to the database without using the `QueryBuilder` of TYPO3 will still deliver every record. - diff --git a/Features/PersonalData.md b/Features/PersonalData.md index 25e1a78..468526e 100644 --- a/Features/PersonalData.md +++ b/Features/PersonalData.md @@ -16,4 +16,24 @@ A new administration module gives editors the possibility to handle those flagge ![record-randomization.png](../Resources/Public/Documentation/Screenshots/record-randomization.png) -Every action regarding those flags is logged on a central place. +Every action regarding those flags is loghttps://bitbucket.org/georgringer/gdpr/blob/master/Readme.mdtral place. + + +## Configuration + +The following code what is needed to add a custom table to the GDPR extension. +The code must be placed in the file `Configuration/TCA/Overrides/.php` + +```php +'); +$tca + ->addRestriction('gdpr_restricted') // name of the field used for the checkbox to flag records + https://bitbucket.org/georgringer/gdpr/raw/master/Resources/Public/Documentation/Screenshots/Record-fields.png## Technical background + +The implementation is based on the `RestrictionContainers` of the TYPO3 core. + +### Drawbacks + +The limitation of the implementation is that only records having a TCA configuration are covered. +Furthermore direct access to the database withouthttps://bitbucket.org/georgringer/gdpr/blob/master/Features/Randomization.mdyBuilder` of TYPO3 will still dhttps://bitbucket.org/georgringer/gdpr/raw/master/Resources/Public/Documentation/Screenshots/record-randomization.png \ No newline at end of file diff --git a/Features/Randomization.md b/Features/Randomization.md index e54e564..0b5dcef 100644 --- a/Features/Randomization.md +++ b/Features/Randomization.md @@ -11,10 +11,8 @@ Randomization is a good way to remove the private data from a record and still b Records can be randomized by using the `fzaninotto/faker` library. By providing a mapping per table, is possible to exchange the data with dummy information which looks still ok and can be used in exports. An example would be -```bash -Array -( - [username] => martens.conny +``` +Arrayhttps://bitbucket.org/georgringer/gdpr/blob/master/Readme.mdname] => martens.conny [email] => gerhild.hartwig@yahoo.de [password] => 94n3ifyp($+%u# [zip] => 33781 @@ -30,17 +28,42 @@ Array ## Configuration -See [Configuration](../Configuration.md) for the full configuration. +The code must be placed in the file `Configuration/TCA/Overrides/.php` + +```php +addRestriction('gdpr_restricted') + ->addRandomization('gdpr_randomized', [ + 'dateField' => 'tstamp', + 'expirePeriod' => 360, + 'mapping' => [ + 'username' => 'userName', + 'email' => 'email', + 'password' => 'password', + 'zip' => 'postcode', + 'address' => 'address', + 'city' => 'city', + 'first_name' => 'firstName', + 'last_name' => 'lastName', + 'telephone' => 'e164PhoneNumber', + 'fax' => 'e164PhoneNumber', + ] + ]) + ->add('after:disable'); +``` + +Randomization uses [Faker](https://github.com/fzaninotto/Faker#formatters) and the mapping accepts any property of faker. ## Using a CLI command -By using a CLI command, all data with a specific age can be randomized. -An example call looks like `./web/typo3/sysext/core/bin/typo3 gdpr:randomize` +By using a CLI command, all data with a specific age can be randomized: `./web/typo3/sysext/core/bin/typo3 gdpr:randomize` -The Result can look like this +Result can look like this -```bash +``` Randomize data ============== diff --git a/Readme.md b/Readme.md index f2ea3f1..253fe2b 100644 --- a/Readme.md +++ b/Readme.md @@ -40,14 +40,13 @@ Costs are **per** installation - discounts possible, ask me directly. - [Screenshots](../Screenshots.md) - [Setup](../Setup.md) -- [Configuration](Configuration.md) - Features - - [Overview & Status of all forms](Features/FormOverview.md) - - [Improved privacy for embedded videos](Features/VideoEmbedPrivacy.md) - [Acces restrictions for personal data](Features/PersonalData.md) - [Randomization](Features/Randomization.md) - [Search](Features/Search.md) - [Logs](Features/Logs.md) + - [Overview & Status of all forms](Features/FormOverview.md) + - [Improved privacy for embedded videos](Features/VideoEmbedPrivacy.md) - [ReportModule](Features/ReportModule.md) From a7f382246c6c0fdc7dca1b252abacfd44fa82fd0 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Fri, 11 May 2018 19:32:05 +0200 Subject: [PATCH 29/33] followup --- Features/PersonalData.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Features/PersonalData.md b/Features/PersonalData.md index 468526e..d4f7fb0 100644 --- a/Features/PersonalData.md +++ b/Features/PersonalData.md @@ -16,7 +16,7 @@ A new administration module gives editors the possibility to handle those flagge ![record-randomization.png](../Resources/Public/Documentation/Screenshots/record-randomization.png) -Every action regarding those flags is loghttps://bitbucket.org/georgringer/gdpr/blob/master/Readme.mdtral place. +Every action regarding those flags is logged in a central place. ## Configuration @@ -29,11 +29,15 @@ The code must be placed in the file `Configuration/TCA/Overrides/.ph $tca = \GeorgRinger\Gdpr\Service\Tca::getInstance(''); $tca ->addRestriction('gdpr_restricted') // name of the field used for the checkbox to flag records - https://bitbucket.org/georgringer/gdpr/raw/master/Resources/Public/Documentation/Screenshots/Record-fields.png## Technical background + -add('after:disable'); // positioning of the new field +```` + +## Technical background The implementation is based on the `RestrictionContainers` of the TYPO3 core. ### Drawbacks The limitation of the implementation is that only records having a TCA configuration are covered. -Furthermore direct access to the database withouthttps://bitbucket.org/georgringer/gdpr/blob/master/Features/Randomization.mdyBuilder` of TYPO3 will still dhttps://bitbucket.org/georgringer/gdpr/raw/master/Resources/Public/Documentation/Screenshots/record-randomization.png \ No newline at end of file +Furthermore direct access to the database without using the `QueryBuilder` of TYPO3 will still deliver every record. + From 3600198b919be97e6805253399a3190885aaf2c3 Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Fri, 18 May 2018 19:25:56 +0200 Subject: [PATCH 30/33] [DOCS] Imrove readme + FAQ --- FAQ.md | 24 ++++++++++++++++++++++++ Readme.md | 41 +++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 FAQ.md diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000..8e1b03d --- /dev/null +++ b/FAQ.md @@ -0,0 +1,24 @@ +[<- back](Readme.md) + +# FAQ + +## Why not add the GDPR extension to the core? + +It is a lot easier to maintain an extension. +Releases can happen a lot more often and it is possible to support 8.7 with new features which would not be possible if it would be in the core. + +## What about support for 7.6 or 6.2? + +Certain features like hiding records everywhere is not possible in 7.6 because there is no *Doctrine DBAL*. + +It would be possible to make a separate version for 7.6 or even for 6.2 covering the following features: + +- Randomization +- Form overview + +If you are interested in this version and can help sponsoring it, please contact me + +## What about the GDPR features in the core? + +All GDPR features which have been added to the latest versions of TYPO3 core have there beginning in this extension. +Those have been developed and tested as feature in the extension first and then have been moved to the core. \ No newline at end of file diff --git a/Readme.md b/Readme.md index 253fe2b..86807fd 100644 --- a/Readme.md +++ b/Readme.md @@ -2,11 +2,31 @@ [![License](https://poser.pugx.org/georgringer/gdpr/license)](https://packagist.org/packages/georgringer/gdpr) -This extensions makes it easier for website owners and agencies to have the site compatible to the GDPR (German "DSGVO"). +This extensions enables you as site owner and extension developer to comply with the GDPR by covering some of the important aspects: + +- Find and randomize or remove privacy related data +- CLI to randomize records after given time +- Logging of any privay related tasks +- Overview and status of forms provided by form extensions +- Improved privacy for included YouTube & Vimeo videos. + +## Table of Contents + +- [Screenshots](Screenshots.md) +- [Setup](Setup.md) +- Features + - [Acces restrictions for personal data](Features/PersonalData.md) + - [Randomization](Features/Randomization.md) + - [Search](Features/Search.md) + - [Logs](Features/Logs.md) + - [Overview & Status of all forms](Features/FormOverview.md) + - [Improved privacy for embedded videos](Features/VideoEmbedPrivacy.md) + - [ReportModule](Features/ReportModule.md) +- [FAQ](FAQ.md) ## Costs -*The license is a one time fee and includes every update until April 2019.* +*The license is a one time fee and includes every update until Mai 2019.* Renewal is possible after that. - Personal license for one site: *€ 240 excl. taxes* - Professional license for one site: *€ 1450 excl. taxes* (*\**) @@ -18,8 +38,6 @@ This extensions makes it easier for website owners and agencies to have the site Contact me - *Georg Ringer* via [mail](mailto:mail@ringer.it), [TYPO3 slack](https://forger.typo3.com/slack) or [twitter](https://twitter.com/georg_ringer). -Costs are **per** installation - discounts possible, ask me directly. - ### Differences free <> paid version | | Free | Paid | @@ -33,20 +51,11 @@ Costs are **per** installation - discounts possible, ask me directly. | Log module | | ✓ | | Search module | | ✓ | | Reports module | ✓ | ✓ | -| Improved privacy for YouTube | | ✓ | +| Privacy for YouTube & Vimeo videos | | ✓ | | Support further development | | ✓ | -## Table of Contents +### Access to paid version -- [Screenshots](../Screenshots.md) -- [Setup](../Setup.md) -- Features - - [Acces restrictions for personal data](Features/PersonalData.md) - - [Randomization](Features/Randomization.md) - - [Search](Features/Search.md) - - [Logs](Features/Logs.md) - - [Overview & Status of all forms](Features/FormOverview.md) - - [Improved privacy for embedded videos](Features/VideoEmbedPrivacy.md) - - [ReportModule](Features/ReportModule.md) +Access to a private GitHub repository will be granted. This makes it possible to include the extension in automated deployments. From bec858ef553447386827be1e5362f7a7602e187d Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Sun, 20 May 2018 18:51:16 +0200 Subject: [PATCH 31/33] [BUGFIX] Add php docs --- Classes/Controller/AdministrationController.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Classes/Controller/AdministrationController.php b/Classes/Controller/AdministrationController.php index 3d7dd9f..619e7d9 100644 --- a/Classes/Controller/AdministrationController.php +++ b/Classes/Controller/AdministrationController.php @@ -221,6 +221,11 @@ public function formOverviewAction() ]); } + /** + * @param string $type type + * @param int $formId form + * @param int $status status + */ public function formStatusUpdateAction(string $type, int $formId, int $status) { $this->addFlashMessage(sprintf('The form of content element %s has been updated ', $formId)); From 902993aba7ea93e7e4875c1239f9185d4a1b7ebd Mon Sep 17 00:00:00 2001 From: Georg Ringer Date: Sun, 20 May 2018 18:53:53 +0200 Subject: [PATCH 32/33] [TASK] Update ext_emconf --- ext_emconf.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext_emconf.php b/ext_emconf.php index 7bcf1ec..44a55ee 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -2,7 +2,7 @@ $EM_CONF[$_EXTKEY] = [ 'title' => 'Make TYPO3 compatible to GDPR', - 'description' => '', + 'description' => 'This extensions enables you as site owner and extension developer to comply with the GDPR by covering some of the important aspects', 'category' => 'module', 'author' => 'Georg Ringer', 'author_email' => 'mail@ringer.it', From 8f5f0ad2c441471491d278f1b11dab8bd25ec054 Mon Sep 17 00:00:00 2001 From: hiasl Date: Tue, 22 May 2018 12:58:06 +0200 Subject: [PATCH 33/33] fixed typo in readme --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 86807fd..21a5936 100644 --- a/Readme.md +++ b/Readme.md @@ -6,7 +6,7 @@ This extensions enables you as site owner and extension developer to comply with - Find and randomize or remove privacy related data - CLI to randomize records after given time -- Logging of any privay related tasks +- Logging of any privacy related tasks - Overview and status of forms provided by form extensions - Improved privacy for included YouTube & Vimeo videos.
TableRecordDateStatusUser
{row.table_name}{row.record_id} + @{row.tstamp} + + + delete + randomize + reenable + restrict + ip anonymize + + {row.user}