diff --git a/atlas/atlasRoutes.py b/atlas/atlasRoutes.py index 21b95163d..1335d50e9 100644 --- a/atlas/atlasRoutes.py +++ b/atlas/atlasRoutes.py @@ -207,12 +207,18 @@ def index(): connection.close() session.close() + personal_data = False + args_personal_data = request.args.get("personal_data") + if args_personal_data and args_personal_data.lower() == "true": + personal_data = True + return render_template( "templates/home/_main.html", observations=observations, mostViewTaxon=mostViewTaxon, customStatMedias=customStatMedias, lastDiscoveries=lastDiscoveries, + personal_data=personal_data, ) diff --git a/atlas/configuration/config.py.example b/atlas/configuration/config.py.example index bd7da925e..7d704d86a 100644 --- a/atlas/configuration/config.py.example +++ b/atlas/configuration/config.py.example @@ -84,9 +84,6 @@ LANGUAGES = { ##################### ##################### -# Code de suivi des statistiques Google Analytics (si AFFICHAGE_FOOTER = True) -ID_GOOGLE_ANALYTICS = "UA-xxxxxxx-xx" - # Utiliser et afficher le glossaire (static/custom/glossaire.json.sample) GLOSSAIRE = False @@ -261,6 +258,12 @@ PATRIMONIALITE = { } } +# liste des application dont "orejime" controle la dépose de cookie +OREJIME_APPS = [] + +# traduction orejime (voir la doc cookie et RGPD pour comment le remplir) +OREJIME_TRANSLATIONS = {} + ############################# #### Lien custom du logo #### ############################# diff --git a/atlas/configuration/config_schema.py b/atlas/configuration/config_schema.py index e1e292cd1..5e7469c94 100644 --- a/atlas/configuration/config_schema.py +++ b/atlas/configuration/config_schema.py @@ -77,6 +77,21 @@ }, } +orijime_default_translations = { + "fr": { + "consentModal": { + "description": "", + }, + "purposes": {"analytics": "Analyse", "security": "Sécurité"}, + }, + "en": { + "consentModal": { + "description": "This is an example of how to override an existing translation already used by Orejime", + }, + "purposes": {"analytics": "Analytics", "security": "Security"}, + }, +} + class SecretSchemaConf(Schema): class Meta: @@ -122,7 +137,6 @@ class Meta: URL_APPLICATION = fields.String(load_default="") DEFAULT_LANGUAGE = fields.String(load_default="fr") MULTILINGUAL = fields.Boolean(load_default=False) - ID_GOOGLE_ANALYTICS = fields.String(load_default="UA-xxxxxxx-xx") ORGANISM_MODULE = fields.Boolean(load_default=False) DISPLAY_OBSERVERS = fields.Boolean(load_default=True) GLOSSAIRE = fields.Boolean(load_default=False) @@ -131,6 +145,8 @@ class Meta: AFFICHAGE_LOGOS_HOME = fields.Boolean(load_default=True) AFFICHAGE_FOOTER = fields.Boolean(load_default=True) AFFICHAGE_RGPD = fields.Boolean(load_default=True) + OREJIME_APPS = fields.List(fields.Dict(), load_default=[]) + OREJIME_TRANSLATIONS = fields.Dict(load_default=orijime_default_translations) AFFICHAGE_STAT_GLOBALES = fields.Boolean(load_default=True) AFFICHAGE_DERNIERES_OBS = fields.Boolean(load_default=True) AFFICHAGE_EN_CE_MOMENT = fields.Boolean(load_default=True) diff --git a/atlas/static/custom/templates/footer.html.sample b/atlas/static/custom/templates/footer.html.sample index 4ce976035..f10b7a932 100644 --- a/atlas/static/custom/templates/footer.html.sample +++ b/atlas/static/custom/templates/footer.html.sample @@ -5,10 +5,11 @@ data-target="#modalCredits">{{ _('credits') }} | {{ _('legal') }} - {% if configuration.AFFICHAGE_RGPD %} + {% if configuration.AFFICHAGE_RGPD and configuration.OREJIME_APPS | length > 0 %} | {{ _('personal_data') }} + | {{ _('preferences_cookies') }} {% endif %} @@ -74,22 +75,5 @@ {% endif %} -{% if configuration.ID_GOOGLE_ANALYTICS != "UA-xxxxxxx-xx" %} - - -{% endif %} diff --git a/atlas/static/main.js b/atlas/static/main.js index 92fb2f89f..3149158c4 100644 --- a/atlas/static/main.js +++ b/atlas/static/main.js @@ -139,3 +139,24 @@ if (configuration.GLOSSAIRE) { }); }); } + +if (configuration.OREJIME_APPS.length > 0) { + var orejimeConfig = { + elementID: "orejime", + appElement: "main", + cookieName: "orejime", + cookieExpiresAfterDays: 365, + privacyPolicy: "/?personal_data=true", + default: true, + mustConsent: false, + mustNotice: false, + lang: configuration.DEFAULT_LANGUAGE, + logo: false, + debug: configuration.modeDebug, + apps: configuration.OREJIME_APPS, + categories: configuration.OREJIME_CATEGORIES + } + if (configuration.OREJIME_TRANSLATIONS && configuration.OREJIME_TRANSLATIONS != {}) { + orejimeConfig.translations = configuration.OREJIME_TRANSLATIONS + } +} diff --git a/atlas/static/package-lock.json b/atlas/static/package-lock.json index f8dfea67a..e41de16a2 100644 --- a/atlas/static/package-lock.json +++ b/atlas/static/package-lock.json @@ -398,6 +398,14 @@ "@babel/helper-plugin-utils": "^7.14.5" } }, + "@babel/runtime": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, "@babel/template": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", @@ -1443,6 +1451,11 @@ "strip-final-newline": "^2.0.0" } }, + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -2330,8 +2343,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.14.1", @@ -2462,6 +2474,14 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2586,6 +2606,11 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2618,6 +2643,15 @@ "word-wrap": "~1.2.3" } }, + "orejime": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/orejime/-/orejime-2.3.0.tgz", + "integrity": "sha512-eDUgd5yEF5pCIUHPNXVDKmgH+4k4GEwxU7eexBFeVESba3ZYDHSDq4ULXiF2LnZwxg+H6Qi28o8rGfGxNeOriA==", + "requires": { + "@babel/runtime": "^7.1.2", + "react-modal": "^3.13.1" + } + }, "p-each-series": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", @@ -2743,6 +2777,23 @@ "sisteransi": "^1.0.5" } }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -2769,6 +2820,27 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-modal": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", + "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==", + "requires": { + "exenv": "^1.2.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.0", + "warning": "^4.0.3" + } + }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3135,6 +3207,14 @@ "makeerror": "1.0.x" } }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", diff --git a/atlas/static/package.json b/atlas/static/package.json index 9a3650484..a2b435819 100644 --- a/atlas/static/package.json +++ b/atlas/static/package.json @@ -33,6 +33,7 @@ "leaflet.snogylop": "^0.4.0", "leaflet.zoomhome": "^1.0.0", "lightbox2": "^2.8.2", + "orejime": "^2.3.0", "popper.js": "^1.16.0", "raphael": "^2.2.0", "slick": "^1.12.2", diff --git a/atlas/templates/core/assets_header.html b/atlas/templates/core/assets_header.html index 83d4efc86..4ec8ba926 100644 --- a/atlas/templates/core/assets_header.html +++ b/atlas/templates/core/assets_header.html @@ -38,4 +38,8 @@ + + + + {% endblock %} diff --git a/atlas/templates/home/_main.html b/atlas/templates/home/_main.html index 3c8c4b5b5..f329ac3ab 100644 --- a/atlas/templates/home/_main.html +++ b/atlas/templates/home/_main.html @@ -28,6 +28,12 @@ + {% if personal_data %} + + {% endif %} + {% endblock %} diff --git a/atlas/translations/en/LC_MESSAGES/messages.mo b/atlas/translations/en/LC_MESSAGES/messages.mo index 39dcdca50..b562afd9b 100644 Binary files a/atlas/translations/en/LC_MESSAGES/messages.mo and b/atlas/translations/en/LC_MESSAGES/messages.mo differ diff --git a/atlas/translations/en/LC_MESSAGES/messages.po b/atlas/translations/en/LC_MESSAGES/messages.po index 8b6ec8e66..e355e67ad 100644 --- a/atlas/translations/en/LC_MESSAGES/messages.po +++ b/atlas/translations/en/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-09-27 10:32+0200\n" +"POT-Creation-Date: 2024-11-27 10:43+0100\n" "PO-Revision-Date: 2021-07-12 12:12+0200\n" "Last-Translator: FULL NAME \n" "Language: en\n" @@ -47,6 +47,10 @@ msgstr "Legal mentions" msgid "personal_data" msgstr "Personal data" +#: static/custom/templates/footer.html:12 +msgid "preferences_cookies" +msgstr "Changing cookie preferences" + #: static/custom/templates/footer.html:17 #: static/custom/templates/footer.html.sample:17 msgid "atlas.fauna.flora" diff --git a/atlas/translations/fr/LC_MESSAGES/messages.mo b/atlas/translations/fr/LC_MESSAGES/messages.mo index 388a3706a..2fa1099a7 100644 Binary files a/atlas/translations/fr/LC_MESSAGES/messages.mo and b/atlas/translations/fr/LC_MESSAGES/messages.mo differ diff --git a/atlas/translations/fr/LC_MESSAGES/messages.po b/atlas/translations/fr/LC_MESSAGES/messages.po index 0c0ede54e..897671cb3 100644 --- a/atlas/translations/fr/LC_MESSAGES/messages.po +++ b/atlas/translations/fr/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-09-27 10:32+0200\n" +"POT-Creation-Date: 2024-11-27 10:38+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: fr\n" @@ -47,7 +47,11 @@ msgstr "Mentions légales" msgid "personal_data" msgstr "Données personnelles" -#: static/custom/templates/footer.html:17 +#: static/custom/templates/footer.html:12 +msgid "preferences_cookies" +msgstr "Modifier les préférences de cookies" + +#: static/custom/templates/footer.html:18 #: static/custom/templates/footer.html.sample:17 msgid "atlas.fauna.flora" msgstr "Atlas de la faune et de la flore" diff --git a/atlas/translations/it/LC_MESSAGES/messages.mo b/atlas/translations/it/LC_MESSAGES/messages.mo index f23daef27..dfcc56cd9 100644 Binary files a/atlas/translations/it/LC_MESSAGES/messages.mo and b/atlas/translations/it/LC_MESSAGES/messages.mo differ diff --git a/atlas/translations/it/LC_MESSAGES/messages.po b/atlas/translations/it/LC_MESSAGES/messages.po index 9dcd3d1c7..1dd194803 100644 --- a/atlas/translations/it/LC_MESSAGES/messages.po +++ b/atlas/translations/it/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-09-27 10:32+0200\n" +"POT-Creation-Date: 2024-11-27 10:43+0100\n" "PO-Revision-Date: 2021-07-19 09:53+0200\n" "Last-Translator: FULL NAME \n" "Language: it\n" @@ -47,6 +47,10 @@ msgstr "Nota legale" msgid "personal_data" msgstr "Dati personali" +#: atlas/static/custom/templates/footer.html:12 +msgid "preferences_cookies" +msgstr "" + #: static/custom/templates/footer.html:17 #: static/custom/templates/footer.html.sample:17 msgid "atlas.fauna.flora" diff --git a/docs/changelog.rst b/docs/changelog.rst index ac203698d..e52a80065 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,6 +8,7 @@ CHANGELOG 🚀 **Nouveautés** - Ajout du lien "Données personelles" dans le pied de page (#527 @juggler31) +- Ajout de la librairie Orijeme pour recueillir le consentement de l'utilisateur sur l'utilisation des cookies - Suppression du support des installations sans TaxHub 🐛 **Corrections** @@ -26,6 +27,8 @@ CHANGELOG ⚠️ **Notes de version** +- Le paramètre `ID_GOOGLE_ANALYTICS` et la façon d'integrer un script google analytic sont dépréciés. Se référer à la documentation sur le RGPD et la collecte de cookies : https://github.com/PnX-SI/GeoNature-atlas/blob/master/docs/cookies_rgpd.rst + Si vous mettez à jour GeoNature-atlas : - Ajouter l'extension unaccent à la base de données `CREATE EXTENSION IF NOT EXISTS unaccent SCHEMA "public";` (#531, #532) diff --git a/docs/cookies_rgpd.rst b/docs/cookies_rgpd.rst new file mode 100644 index 000000000..63e9f5b56 --- /dev/null +++ b/docs/cookies_rgpd.rst @@ -0,0 +1,141 @@ +Gestion des cookies et RGPD +=========================== + +Cette section explique comment ajouter des outils de collectes de cookies (matomo, google analytics par ex) tout en respetant le RGPG. GeoNature-Atlas utilise pour cela une librairie permettant de receuillir le consentement de l'utilisateur: Orejime. + +À quoi sert le RGPD +------------------- + +Le règlement général sur la protection des données est utilisé afin de protéger les données à caractère personnel. + +Où configurer l'application +--------------------------- + +Dans le fichier : `atlas/configuration/config.py` + + +- Définir les applications pour lesquelles il faut demander l'autorisation de la collecte de cookies via la variable **OREJIME_APPS** + +En complément, se référer à la documentation officielle de l'outil orejim: https://github.com/empreinte-digitale/orejime + +:: + + OREJIME_APPS = [ + { + "name": "script-google", # ce nom devra être réutilisé dans la balise script (attribut `data-name`) du fichier `footer.html` ou le script d'analyse des cookies sera integré + "title": "Google Analytics", + "cookies": [ + "_ga", + "_gat", + "_gid", + "__utma", + "__utmb", + "__utmc", + "__utmt", + "__utmz", + ], + "purposes": ["analytics"], + "required": False, + "optOut": False, + "default": True, + "onlyOnce": True, + }, + { + "name": "second-script", + "title": "Deuxième script", + "cookies": [ + "_ga", + "_gat", + "_gid", + "__utma", + "__utmb", + "__utmc", + "__utmt", + "__utmz", + ], + "purposes": ["analytics"], + "required": False, + "optOut": False, + "default": True, + "onlyOnce": True, + } + ] + +- Il est possible de surcharger les traductions grâce à la variable : **OREJIME_TRANSLATIONS** +Voir toutes les possibilité de traduction : https://github.com/empreinte-digitale/orejime +:: + + OREJIME_TRANSLATIONS = { + "fr": { + "consentModal": { + "description": "", + }, + "purposes": { + "analytics": "Analyse", + "security": "Sécurité" + } + }, + "en": { + "consentModal": { + "description": "This is an example of how to override an existing translation already used by Orejime", + }, + "purposes": { + "analytics": "Analytics", + "security": "Security" + }, + + } + } + +- Il est possible de catégoriser les applications nécessaires afin de les intégrer dans les choix des utilisateurs. + +.. image :: images/choice_rgpd.png + +:: + + OREJIME_CATEGORIES = [ + { + "name": "analytics", + "title": "Analytics", + "apps": [ + "script-google", + ] + }, + { + "name": "security", + "title": "Secutiry", + "apps": [ + "second-script", + ] + } + ] + +A la fin du fichier : `atlas/static/custom/templates/footer.html`, copiez collez cette exemple en l'adaptant à votre contexte et à votre configuration. +La variable `AFFICHAGE_FOOTER` doit êtes mise à `True` si on souhaite ajouter des traceurs de cookies. + +Dans cet exemple, il s'agit d'un script de google analytics : +L'attribut `data-name` de la balise script doit correspondre a l'attribut `name` correspondant à l'application ORIJIME renseigné dans la variable de configuration `OREJIME_APPS`. Dans la configuration d'exemple, la première "l'app google" a pour attribut `name` : `scripts-google`, il faut donc mettre `scripts-google` dans l'attribut `data-name` de la balise script. C'est cet attribut qui permet à Orijeme de savoir quel cookies il va pouvoir accepter ou bloquer en fonction de la réponse de l'utilisateur. +Si vous souhaitez rajouter un deuxième traceur (matomo par exemple), faire un deuxième balise script séparée en respectant la même logique. + +:: + + + diff --git a/docs/images/choice_rgpd.png b/docs/images/choice_rgpd.png new file mode 100644 index 000000000..ac2224050 Binary files /dev/null and b/docs/images/choice_rgpd.png differ