mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
GDPR Compliance (#796)
* add cookie utils * add gdpr metadata for ppc * add graphql typeDefs for GDPR metadata * add ppc variable to app config * add ppc user preference * add switch component * add ppc components * add cookie consent provider * add consent provider to wrapRootElement * add ppc to app component * add cookie button to footer component * add ppc to site metadata query * add styles for buttons in footer * add switch component unit tests * renewed siteMetadata json for testing * add gdpr metadata for testing * add cookie module unit test * add cookie module tests * add customizable format to time component * add english privacy policy * add privacy policy slugs to user preferences and appConfig * add privacy policy components * add autolink for policy md navigation * only show language select for multiple policies * add gatsby policy page creation * use new privacy slug user preference * add to top button styling for markdown pages * add policies for de, es & fr * add pointer events to toTop buttons css * add privacy policy basic unit test * outsource scroll button component * import cleanup * add customizable delay for debounce * add scroll button unit tests * add disclaimer component * add disclaimer fields as optional fields in PublishJsonData * add acces type disclaimer * adjusted help for desc and author fields * add disclaimer unit tests * minor adjustment to test * add print button to history page * naming changes for better readability * add cookies hash to policies * ppc disabled per default * fix react unknown prop for disclaimer * minor adjustments to cookie utils * add gdpr example file * change exposed gdpr metadata scope by useConsent * update README * readme fixes * emoji fix * added imprint * adjustments to gdpr.json structure and related graphql type * add default values for ppc * Update app.config.js Fixed typo. * change variable name for consistency, remove console logs * readability * adjust css selector order to be consistent * Update fr.md updated policy * Update es.md updated policy * Update en.md updated policy * Update de.md * fix type issue * replace language select input with links * remove scroll button from codebase * change privacy policy route to /privacy * remove Do Not Track detection * add size to checkbox / radio inputs * replace switch component with checkbox inputs * fix plain text links * remove console log * refactor privacy policy pages to use PageMarkdown template * setup useUserPreferences mock for unit tests * unit tests forprivacy policy components * setup discalimer to use alert component * Apply .env suggestions from code review Co-authored-by: Jamie Hewitt <jamie.hewitt15@gmail.com> * move gdpr example to gdpr.json * adjustments to address .env approach for appConfig.privacyPreferenceCenter * update readme * add small styling option to ppc * update README * add ppc unit tests * update comments * Update README.md Co-authored-by: Jamie Hewitt <jamie.hewitt15@gmail.com> * Merge print into profile history * add inifiniteApproval to UserPreference fixture * changed default styling of PPC to small Co-authored-by: Frederic Schwill <41265505+fr-3deric@users.noreply.github.com> Co-authored-by: MeikeMolitor <88214332+MeikeMolitor@users.noreply.github.com> Co-authored-by: Jamie Hewitt <jamie.hewitt15@gmail.com>
This commit is contained in:
parent
ef70d97ad3
commit
46a16a3043
@ -22,3 +22,6 @@
|
|||||||
|
|
||||||
# Allow/Deny Lists
|
# Allow/Deny Lists
|
||||||
#GATSBY_CREDENTIAL_TYPE="address"
|
#GATSBY_CREDENTIAL_TYPE="address"
|
||||||
|
|
||||||
|
# Privacy Preference Center
|
||||||
|
#GATSBY_PRIVACY_PREFERENCE_CENTER="true"
|
||||||
|
54
README.md
54
README.md
@ -27,6 +27,9 @@
|
|||||||
- [💖 Contributing](#-contributing)
|
- [💖 Contributing](#-contributing)
|
||||||
- [🍴 Forking](#-forking)
|
- [🍴 Forking](#-forking)
|
||||||
- [💻 Advanced Features](#-advanced-features)
|
- [💻 Advanced Features](#-advanced-features)
|
||||||
|
- [✅ GDPR Compliance](#-gdpr-compliance)
|
||||||
|
- [Multi-Language Privacy Policies](#multi-language-privacy-policies)
|
||||||
|
- [Privacy Preference Center](#privacy-preference-center)
|
||||||
- [🏛 License](#-license)
|
- [🏛 License](#-license)
|
||||||
|
|
||||||
## 🏄 Get Started
|
## 🏄 Get Started
|
||||||
@ -384,6 +387,57 @@ Ocean Market also includes a number of advanced features that are suitable for a
|
|||||||
|
|
||||||
[See our seperate guide on advanced features](docs/advancedSettings.md)
|
[See our seperate guide on advanced features](docs/advancedSettings.md)
|
||||||
|
|
||||||
|
## ✅ GDPR Compliance
|
||||||
|
|
||||||
|
Ocean Market comes with prebuilt components for you to customize to cover GDPR requirements. Find additional information on how to use them below.
|
||||||
|
|
||||||
|
### Multi-Language Privacy Policies
|
||||||
|
|
||||||
|
Feel free to adopt our provided privacy policies to your needs. Per default we cover four different languages: English, German, Spanish and French. Please be advised, that you will need to adjust some paragraphs in the policies depending on your market setup (e.g. the use of cookies). You can easily add or remove policies by providing your own markdown files in the `content/pages/privacy` directory. For guidelines on how to format your markdown files refer to our provided policies. The pre-linked content tables for these files are automatically generated.
|
||||||
|
|
||||||
|
### Privacy Preference Center
|
||||||
|
|
||||||
|
Additionally, Ocean Market provides a privacy preference center for you to use. This feature is disabled per default since we do not use cookies requiring consent on our deployment of the market. However, if you need to add some functionality depending on cookies, you can simply enable this feature by changing the value of the `GATSBY_PRIVACY_PREFERENCE_CENTER` environmental variable to `"true"` in your `.env` file. This will enable a customizable cookie banner stating the use of your individual cookies. The content of this banner can be adjusted within the `content/gdpr.json` file. If no `optionalCookies` are provided, the privacy preference center will be set to a simpler version displaying only the `title`, `text` and `close`-button. This can be used to inform the user about the use of essential cookies, where no consent is needed. The privacy preference center supports two different styling options: `'small'` and `'default'`. Setting the style propertie to `'small'` will display a smaller cookie banner to the user at first, only showing the default styled privacy preference center upon the user's customization request.
|
||||||
|
|
||||||
|
Now your market users will be provided with additional options to toggle the use of your configured cookie consent categories. You can always retrieve the current consent status per category with the provided `useConsent()` hook. See below, how you can set your own custom cookies depending on the market user's consent. Feel free to adjust the provided utility functions for cookie usage provided in the `src/utils/cookies.ts` file to your needs.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { CookieConsentStatus, useConsent } from '../../providers/CookieConsent'
|
||||||
|
import { deleteCookie, setCookie } from '../../utils/cookies'
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
const { cookies, cookieConsentStatus } = useConsent()
|
||||||
|
|
||||||
|
cookies.map((cookie) => {
|
||||||
|
const consent = cookieConsentStatus[cookie.cookieName]
|
||||||
|
|
||||||
|
switch (consent) {
|
||||||
|
case CookieConsentStatus.APPROVED:
|
||||||
|
// example logic
|
||||||
|
setCookie(`YOUR_COOKIE_NAME`, 'VALUE')
|
||||||
|
break
|
||||||
|
|
||||||
|
case CookieConsentStatus.REJECTED:
|
||||||
|
case CookieConsentStatus.NOT_AVAILABLE:
|
||||||
|
default:
|
||||||
|
// example logic
|
||||||
|
deleteCookie(`YOUR_COOKIE_NAME`)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Privacy Preference Centre Styling
|
||||||
|
|
||||||
|
The privacy preference centre has two styling options `default` and `small`. The default view shows all of the customization options on a full-height side banner. When the `small` setting is used, a much smaller banner is shown which only reveals all of the customization options when the user clicks "Customize".
|
||||||
|
|
||||||
|
The style can be changed by altering the `style` prop in the `PrivacyPreferenceCenter` component in `src/components/App.tsx`. For example:
|
||||||
|
|
||||||
|
```Typescript
|
||||||
|
<PrivacyPreferenceCenter style="small" />
|
||||||
|
```
|
||||||
|
|
||||||
## 🏛 License
|
## 🏛 License
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
@ -62,5 +62,17 @@ module.exports = {
|
|||||||
allowAdvancedSettings: process.env.GATSBY_ALLOW_ADVANCED_SETTINGS || 'false',
|
allowAdvancedSettings: process.env.GATSBY_ALLOW_ADVANCED_SETTINGS || 'false',
|
||||||
allowAdvancedPublishSettings:
|
allowAdvancedPublishSettings:
|
||||||
process.env.GATSBY_ALLOW_ADVANCED_PUBLISH_SETTINGS || 'false',
|
process.env.GATSBY_ALLOW_ADVANCED_PUBLISH_SETTINGS || 'false',
|
||||||
credentialType: process.env.GATSBY_CREDENTIAL_TYPE || 'address'
|
credentialType: process.env.GATSBY_CREDENTIAL_TYPE || 'address',
|
||||||
|
|
||||||
|
// Set the default privacy policy to initially display
|
||||||
|
// this should be the slug of your default policy markdown file
|
||||||
|
defaultPrivacyPolicySlug: '/privacy/en',
|
||||||
|
|
||||||
|
// This enables / disables the use of a GDPR compliant
|
||||||
|
// privacy preference center to manage cookies on the market
|
||||||
|
// If set to true a gdpr.json file inside the content directory
|
||||||
|
// is used to create and show a privacy preference center / cookie banner
|
||||||
|
// To learn more about how to configure and use this, please refer to the readme
|
||||||
|
privacyPreferenceCenter:
|
||||||
|
process.env.GATSBY_PRIVACY_PREFERENCE_CENTER || 'false'
|
||||||
}
|
}
|
||||||
|
20
content/gdpr.json
Normal file
20
content/gdpr.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"title": "Our use of cookies",
|
||||||
|
"text": "We use [cookies](/privacy/en#cookies) to optimize and continuously improve our website. You can accept or reject them, and you can change your settings at any time by clicking **Cookie Settings** at the bottom of the page.",
|
||||||
|
"close": "Save and close",
|
||||||
|
"accept": "Accept all",
|
||||||
|
"reject": "Only essential",
|
||||||
|
"configure": "Customize",
|
||||||
|
"optionalCookies": [
|
||||||
|
{
|
||||||
|
"title": "Marketing",
|
||||||
|
"desc": "We'd like to set Marketing related cookies to help us improve our services and personalize your experience. The cookies collect information in a way that does not directly identify anyone. Head over to our [Cookies page](/privacy/en#cookies) to find more detailed information about this process.",
|
||||||
|
"cookieName": "MarketingCookieConsent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Analytics",
|
||||||
|
"desc": "We'd like to set analytics related cookies to help us improve our website by collecting and reporting information on how you use it. For more information on how these cookies work please see our [Cookies page](/privacy/en#cookies).",
|
||||||
|
"cookieName": "AnalyticsCookieConsent"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
20
content/pages/imprint.md
Normal file
20
content/pages/imprint.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: Imprint
|
||||||
|
description: Thanks for using our product and services.
|
||||||
|
---
|
||||||
|
|
||||||
|
Ocean Protocol Foundation Ltd.<br/>
|
||||||
|
The Commerze @ Irving<br/>
|
||||||
|
1 Irving Place, 08-11<br/>
|
||||||
|
369546 Singapore<br/>
|
||||||
|
Singapore
|
||||||
|
|
||||||
|
E-mail: [gdpr@oceanprotocol.com](mailto:gdpr@oceanprotocol.com)<br/>
|
||||||
|
Phone: <br/>
|
||||||
|
|
||||||
|
Director: Bruce Pon
|
||||||
|
|
||||||
|
Company registered in Singapore<br/>
|
||||||
|
Company Registration No.: 201729912W<br/>
|
||||||
|
Commercial Register No.:<br/>
|
||||||
|
VAT ID:<br/>
|
259
content/pages/privacy/de.md
Normal file
259
content/pages/privacy/de.md
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
---
|
||||||
|
title: Datenschutzerklärung
|
||||||
|
description: Diese Datenschutzerklärung erläutert wie Ocean Protocol Foundation Ltd. (OPF) deine personenbezogenen Daten verarbeitet wenn du Ocean Market besuchst und wenn du eine unserer Ocean Market Funktionen nutzt. Darüberhinaus informiert dich diese Datenschutzerklärung über deine Rechte.
|
||||||
|
---
|
||||||
|
|
||||||
|
# 1. Verantwortlicher
|
||||||
|
|
||||||
|
Verantwortlicher für die Verarbeitung deiner personenbezogenen Daten ist:
|
||||||
|
|
||||||
|
Ocean Protocol Foundation Ltd.<br/>
|
||||||
|
The Commerze @ Irving<br/>
|
||||||
|
1 Irving Place, #08-11<br/>
|
||||||
|
369546 Singapore
|
||||||
|
|
||||||
|
E-mail: [gdpr@oceanprotocol.com](gdpr@oceanprotocol.com)
|
||||||
|
|
||||||
|
# 2. Was sind personenbezogene Daten?
|
||||||
|
|
||||||
|
Personenbezogene Daten sind alle Informationen, die man direkt oder indirekt auf dich beziehen kann. OPF verarbeitet eine minimale Menge an personenbezogenen Daten, denn wir denken, dass deine Daten alleine dir gehören. Wir verarbeiten die folgenden personenbezogenen Daten.
|
||||||
|
|
||||||
|
**IP Addresse** : Wir verarbeiten deine IP Adresse, wenn du unsere Website besuchst.
|
||||||
|
|
||||||
|
Wenn du eine unserer Markfunktionalitäten nutzt, verarbeiten wir außerdem die folgenden personenbezogenen Daten.
|
||||||
|
|
||||||
|
- **Deine Wallet Addresse**: Wir verarbeiten deine Wallet Addresse, wenn du unsere Publishing-, Consuming-, oder Staking-Funktionaliät nutzt.
|
||||||
|
|
||||||
|
- **Autor Name:** Wir verarbeiten deinen angegebenen Autornamen, wenn du ein Data Asset veröffentlichst. Es ist nicht notwendig deinen echten Namen zu benutzen. Du kannst dein Data Asset gerne unter einem Pseudonym veröffentlichen.
|
||||||
|
|
||||||
|
Wenn du uns per E-Mail kontaktierst, verarbeiten wir deine E-Mail Addresse und alle weiteren personenbezogenen Daten, die du in deiner E-Mail angibst (wie beispielsweise deinen Namen).
|
||||||
|
|
||||||
|
Detaillierte Informationen über unsere Verarbeitungsvorgänge, die Rechtmäßigkeit der Verarbeitung, Verarbeitungszwecke und den Nutzen deiner Daten diese Zwecke zu erfüllen, findest du im Kapitel „Verarbeitung von personenbezogenen Daten nach Artikel 13 GDPR".
|
||||||
|
|
||||||
|
# 3. Empfänger und Übermittlung von personenbezogenen Daten an Drittländer
|
||||||
|
|
||||||
|
**Visiting Ocean Market**
|
||||||
|
|
||||||
|
Wenn du Ocean Market besuchst, wird deine IP-Adresse von Netlify verarbeitet, ein Auftragsverarbeiter, der unseren Markt hostet. Ocean Market wird von Netlify über ein Content Delivery Network (ein geografisch verteiltes Netzwerk) bereitgestellt, deren Server sich innerhalb und außerhalb des Europäischen Wirtschaftsraums befinden. Wir verwenden Standardvertragsklauseln (SCC), um angemessene Schutzmaßnahmen für die Verarbeitung deiner personenbezogenen Daten zu gewährleisten. Du hast das Recht, eine Kopie dieser SCC zu erhalten.
|
||||||
|
|
||||||
|
- Hier findest du Netlify's [**SCC** ↗](https://www.netlify.com/v3/static/pdf/netlify-dpa.pdf).
|
||||||
|
- Hier findest du Netlify's [**Datenschutzerklärung** ↗](https://www.netlify.com/gdpr-ccpa).
|
||||||
|
|
||||||
|
**Nutzung von Ocean Market Funktionalitäten**
|
||||||
|
|
||||||
|
Wenn du Ocean Market Funktionalitäten nutzt, legen wir deine Wallet Addresse und deinen Autornamen (falls vorhanden) offen indem wir diese an einen Smart Contract übermitteln. Dieser Smart Contract wird in maschinenlesbarem Format auf einer öffentlichen Blockchain gespeichert, die redundant auf weltweit verteilten Knoten gespeichert ist. Aufgrund der weltweit verteilten Speicherung werden deine Wallet Adresse und gegebenenfalls dein Autorname in Ländern ohne Angemessenheitsbeschluss gemäß Art. 45 GDPR verarbeitet. Die der Blockchain zugrunde liegende Technologie gewährleistet die Sicherheit (Integrität, Verfügbarkeit, Authentizität und Nichtabstreitbarkeit) deiner personenbezogenen Daten by-design und by-default. Außerdem bleiben deine in Kapitel sieben beschriebenen Rechte durchsetzbar. Wenn du beispielsweise deinen Autornamen auf Ocean Market berichtigst, werden die Änderungen automatisch auch auf Knoten übernommen, die eine Kopie des Smart Contracts besitzen.
|
||||||
|
|
||||||
|
**Kontakt via E-mail**
|
||||||
|
|
||||||
|
Wenn du mit uns per E-Mail in Kontakt trittst, unterstützt uns der (Mail-)Dienstleister Google Workspace bei der Kommunikation mit dir. Dabei werden personenbezogene Daten verarbeitet, wie deine E-Mail-Adresse und alle anderen Informationen, die du in deiner Nachricht angibst, wie beispielsweise deinen Namen. Google Workspace befindet sich in den USA, daher werden deine Daten in ein Land ohne Angemessenheitsbeschluss gemäß Art. 45 GDPR verarbeitet. Wir verwenden Standardvertragsklauseln (SCC), um angemessene Garantien für die Verarbeitung deiner personenbezogenen Daten zu gewährleisten. Du hast das Recht, eine Kopie dieser SCC zu erhalten.
|
||||||
|
|
||||||
|
- Hier findest du die [**SCC** ↗](https://workspace.google.com/terms/mcc_terms.html) von Google Workspace.
|
||||||
|
- Hier findest du die [**Datenschutzerklärung** ↗](https://policies.google.com/) von Google Workspace.
|
||||||
|
|
||||||
|
# 4. Verarbeitung von personenbezogenen Daten nach Artikel 13 GDPR
|
||||||
|
|
||||||
|
Wir verarbeiten deine personenbezogene Daten zu folgenden Zwecken.
|
||||||
|
|
||||||
|
## 4.1 Bereitstellung der Website und Erstellung von Logfiles
|
||||||
|
|
||||||
|
Wir erheben und verwenden deine IP-Adresse für die Bereitstellung von Ocean Market. Ocean Market wird von unserem Auftragsverarbeiter Netlify gehostet. Außerdem nutzt OPF Netlify Analytics, um deine IP-Adresse zu erfassen und zu speichern. Deine persönlichen Daten verlassen niemals unseren Service, und wir verfolgen dich nicht über verschiedene Websites hinweg.
|
||||||
|
|
||||||
|
**Zwecke:**
|
||||||
|
|
||||||
|
Die Erhebung und Nutzung deiner IP-Adresse ist für die Bereitstellung von Ocean Market notwendig, da dies eine technische Voraussetzung ist, um die Kommunikation zwischen deinem Gerät und unserem Markt zu gewährleisten.
|
||||||
|
|
||||||
|
OPF verwendet Netlify Analytics, um einzelne Besucher anhand von IP-Adressen zu unterscheiden. Dieser Prozess hilft uns, besser zu verstehen, wie viele Nutzer Ocean Market besuchen und in welchen Ländern sich die Nutzer befinden. Wir verwenden diese Informationen, indem wir den Netwerkverkehr und die Beliebtheitstrends messen, um unseren Service zu verbessern.
|
||||||
|
|
||||||
|
**Rechtsgrundlage:**
|
||||||
|
|
||||||
|
Die Rechtsgrundlage für diese Verarbeitung ist unser berechtigtes Interesse, gemäß Art. 6(1)(f) DSGVO.
|
||||||
|
|
||||||
|
**Berechtigtes Interesse:**
|
||||||
|
|
||||||
|
Unser berechtigtes Interesse besteht darin, dir Ocean Market und seine Funktionalitäten zur Verfügung zu stellen und diese zu verbessern.
|
||||||
|
|
||||||
|
**Aufbewahrungsdauer:**
|
||||||
|
|
||||||
|
Wir speichern deine IP-Addresse für 30 Tage.
|
||||||
|
|
||||||
|
## 4.2 Consume- und Stake-Funktionalität
|
||||||
|
|
||||||
|
Wenn du die Consume- oder Stake-Funktionalität nutzt, erheben wir deine Wallet Addresse und legen diese offen, indem wir ihn an einen auf der Blockchain gespeicherten Smart Cotract übertragen.
|
||||||
|
|
||||||
|
**Zweck:**
|
||||||
|
|
||||||
|
Ocean Market verarbeitet deine Wallet Addresse, um dir zu ermöglichen eine Blockchain-Transaktionen zu signieren. Die Transaktion, die deine Wallet Adresse enthält, wird dauerhaft auf der Blockchain gespeichert, damit du und der Asset-Publisher den Erwerb und Konsum des Assets nachweisen können.
|
||||||
|
|
||||||
|
**Rechtsgrundlage:**
|
||||||
|
|
||||||
|
Die Rechtsgrundlage für diese Verarbeitung ist Artikel 6(1)(b) DSGVO, da die Verarbeitung für die Erfüllung eines Vertrags mit dir erforderlich ist.
|
||||||
|
|
||||||
|
**Aufbewahrungsdauer:**
|
||||||
|
|
||||||
|
OPF legt deine Wallet Addresse offen, indem diese an einen Smart Contract übermittelt wird, der in maschinenlesbarem Format dauerhaft auf der Blockchain gespeichert wird, um einen unveränderlichen Audit-Trail zu ermöglichen.
|
||||||
|
|
||||||
|
## 4.3 Publish-Funktionalität
|
||||||
|
|
||||||
|
Wenn du ein Data Asset veröffentlichst, erheben, wir deine Wallet Addresse und deinen Autornamen und transferieren diese zu einem Smart Contract, der auf der Blockchain gespeichert ist. Bitte beachte, dass deine Wallet Addresse mit deinem angegebenen Namen verknüpft wird. Bitte beachte außerdem, dass du ein Pseudonym als Autornamen benutzen kannst.
|
||||||
|
|
||||||
|
**Zweck:**
|
||||||
|
|
||||||
|
Wir verarbeiten deine Wallet Addresse, um dein Data Asset mit deiner Wallet Addresse zu verknüpfen. Wir verarbeiten deinen Autornamen, um Such- und Filterfunktionen auf Ocean Market zu ermöglichen. Die Transaktion, die deine Wallet Addresse und deinen Autorennamen enthält, wird dauerhaft auf der Blockchain gespeichert, damit du dein Eigentum und den Verkauf deines Assets nachweisen kannst.
|
||||||
|
|
||||||
|
**Rechtsgrundlage:**
|
||||||
|
|
||||||
|
Die Rechtsgrundlage für diese Verarbeitung ist Artikel 6(1)(b) DSGVO, da die Verarbeitung für die Erfüllung eines Vertrags mit dir erforderlich ist.
|
||||||
|
|
||||||
|
**Aufbewahrungsdauer:**
|
||||||
|
|
||||||
|
OPF legt deine Wallet Addresse und deinen Autornamen offen, indem diese an einen Smart Contract übermittelt werden, der in maschinenlesbarem Format dauerhaft auf der Blockchain gespeichert wird, um einen unveränderlichen Audit-Trail zu ermöglichen.
|
||||||
|
|
||||||
|
## 4.4 Anzeige deiner Data Assets
|
||||||
|
|
||||||
|
Wenn du ein Data Asset veröffentlicht hast, erheben, organisieren und speichern wir deine Wallet Addresse und deinen Autornamen auf einem von OPF betriebenen Metadaten-Cache und zeigen dein Asset auf Ocean Market an.
|
||||||
|
|
||||||
|
**Zweck:**
|
||||||
|
|
||||||
|
Das Abrufen von Daten, die auf der Blockchain gepeichert sind, ist zeitaufwändig. Deshalb erheben, organisieren und speichern wir deine personenbezogenen Daten in einem Cache, um die Performance von Ocean Market zu verbessern.
|
||||||
|
|
||||||
|
**Rechtsgrundlage:**
|
||||||
|
|
||||||
|
Die Rechtsgrundlage für diese Verarbeitung ist unser berechtigtes Interesse, gemäß Art. 6(1)(f) DSGVO.
|
||||||
|
|
||||||
|
**Berechtigtes Interesse:**
|
||||||
|
|
||||||
|
Unser berechtigtes Interesse ist es, das Nutzererlebnis durch Verbesserung der Performance von Ocean Market zu erhöhen.
|
||||||
|
|
||||||
|
**Aufbewahrungsdauer:**
|
||||||
|
|
||||||
|
Deine Wallet Addresse und dein Autorname werden permanent in unserem Metadaten Cache gespeichert.
|
||||||
|
|
||||||
|
## 4.5 History Table
|
||||||
|
|
||||||
|
Die History Table von Ocean Market ist ein Transparenz-Tool, mit dem du einen Überblick über deine auf Ocean Market getättigten Transaktion erhalten kannst. Wenn du die History Table nutzt, erheben wir deine Wallet Addresse. Danach rufen wir die relevanten und mit dir in Zusammenhang stehenden Transaktionen von der Blockchain ab (genauer gesagt, aus dem Metadaten Cache) und organisieren diese in der History Table.
|
||||||
|
|
||||||
|
**Zweck:**
|
||||||
|
|
||||||
|
Wir erheben deine Wallet Addresse, um jede Transaktion, die du auf Ocean Market getätigt hast, abrufen zu können. Wir rufen deine öffentlichen Transaktionsdaten ab und organisieren diese, damit du einen schnellen Überblick über alle Aktionen erhätst, die du auf Ocean Market durchgeführt hast.
|
||||||
|
|
||||||
|
**Rechtsgrundlage:**
|
||||||
|
|
||||||
|
Die Rechtsgrundlage für diese Verarbeitung ist unser berechtigtes Interesse, gemäß Art. 6(1)(f) DSGVO.
|
||||||
|
|
||||||
|
**Berechtigtes Interesse:**
|
||||||
|
|
||||||
|
Unser berechtigtes Interesse an der Bereitstellung der History Table besteht darin, dir die Möglichkeit zu bieten, einen Überblick über deine auf Ocean Market getätigten Transaktionen zu erhalten.
|
||||||
|
|
||||||
|
**Aufbewahrungsdauer:**
|
||||||
|
|
||||||
|
Sobald du die Verbindung zu deinem Wallet trennst, werden wir die History Table Einträge aus deinem Browser entfernen.
|
||||||
|
|
||||||
|
## 4.6 Kontakt via E-Mail
|
||||||
|
|
||||||
|
Wenn du uns per E-Mail kontaktierst, erheben, nutzen und speichern wir deine E-Mail addresse und alle anderen Informationen, die du uns in deiner Nachricht zukommen lässt, wie zum Beispiel dein Name.
|
||||||
|
|
||||||
|
**Zweck:**
|
||||||
|
|
||||||
|
Wir erheben, nutzen und speichern diese personenbezogenen Daten, um deine Anfragen zu beantworten.
|
||||||
|
|
||||||
|
**Rechtsgrundlage:**
|
||||||
|
|
||||||
|
Die Rechtsgrundlage für diese Verarbeitung ist unser berechtigtes Interesse, gemäß Art. 6(1)(f) DSGVO.
|
||||||
|
|
||||||
|
**Berechtigtes Interesse:**
|
||||||
|
|
||||||
|
Unser berechtigtes Interresse ist es deine Anfragen zu beantworten.
|
||||||
|
|
||||||
|
**Aufbewahrungsdauer:**
|
||||||
|
|
||||||
|
OPF löscht deine personenbezogenen Daten, sobald wir sie für die Bearbeitung deiner Anfrage nicht mehr benötigen, es sei den wir sind zur Einhaltunggesetzlicher Aufbewahrungsfristen verpflichtet oder im Falle eines Rechtsstreits.
|
||||||
|
<br/><i id="cookies"></i>
|
||||||
|
|
||||||
|
# 5. Cookies und Web Storage
|
||||||
|
|
||||||
|
Ein Cookie ist eine kleine Datei, die Interneteinstellungen speichert. Dein Webbrowser lädt diese beim ersten Besuch einer Website herunter. Wenn du diese Website das nächste Mal mit demselben Gerät öffnest, werden das Cookie und die darin gespeicherten Informationen entweder an die Website zurückgeschickt, die es erstellt hat (First-Party-Cookie) oder an eine andere Website, zu der es gehört (Third-Party-Cookie). Dadurch kann die Website erkennen, dass du sie zuvor mit diesem Browser geöffnet hast, und in einigen Fällen den angezeigten Inhalt variieren.
|
||||||
|
|
||||||
|
Ocean Market verwendet keine Cookies für Analyse- oder Marketingzwecke. Stattdessen verwenden wir ein funktionales First-Party-Cookie, das keine personenbezogenen Daten über dich übermittelt. Dieses Cookie wird verwendet, um dein Benutzererlebnis zu verbessern und wird entfernt, sobald du deinen Browser schließt.
|
||||||
|
|
||||||
|
Ocean Market verwendet auch lokalen Speicher und Sitzungsspeicher, die eine ähnliche Funktionalität wie Cookies haben. Wir verwenden den Webspeicher, um uns an deine Seitenpräferenzen zu erinnern und um dein Nutzererlebnis zu verbessern. Wir speichern im lokalen Speicher und im Sitzungsspeicher keine personenbezogenen Daten. Dein Browser entfernt den Sitzungsspeicher, sobald du deinen Browser schließt.
|
||||||
|
|
||||||
|
Du hast jederzeit die Möglichkeit, in den Einstellungen deines Browsers Cookies zu deaktivieren und Cookies und Webspeicher von der Festplatte deines Computers zu löschen.
|
||||||
|
|
||||||
|
# 6. Externe Links
|
||||||
|
|
||||||
|
Ocean Market enthält Links zu externen Webseiten, die außerhalb der Kontrolle und Verantwortung von OPF liegen. Wir kennzeichnen externe Links mit diesem Pfeil: ↗.
|
||||||
|
|
||||||
|
# 7. Deine Rechte
|
||||||
|
|
||||||
|
Wenn du deine im Folgenden beschriebenen Rechte geltend machen möchstest, zögere nicht uns zu kontaktieren.
|
||||||
|
|
||||||
|
## 7.1 Auskunftsrecht (Art. 15 GDPR)
|
||||||
|
|
||||||
|
Du hast das Recht eine Bestätigung darüber zu verlangen, ob wir dich betreffende personenbezogene Daten verarbeiten. Wenn wir personenbezogene Daten von dir verarbeiten, hast du das Recht Auskunft über diese personenbezogene Daten und die in Art. 15 DSGVO definierten Informationen zu erlangen.
|
||||||
|
|
||||||
|
## 7.2 Recht auf Berichtigung (Art. 16 GDPR)
|
||||||
|
|
||||||
|
Du hast das Recht, die Berichtigung dich betreffender unrichtiger personenbezogene Daten von uns zu verlangen. Darüberhinaus hast du das Recht darauf, dass unvollständige personenbezogene Daten vervollständigt werden.
|
||||||
|
|
||||||
|
Wenn du ein Data Asset veröffentlicht hast, kannst du deine bereitgestellten Metadaten (wie dein Autorname) jederzeit bearbeiten. Folgende Schritte werden dafür benötigt.
|
||||||
|
|
||||||
|
- Rufe dein dein Data Asset auf Ocean Market ([market.oceanprotocol.com/](https://market.oceanprotocol.com/)) auf.
|
||||||
|
- Validiere deine Identität mit deinem Private Key.
|
||||||
|
- Klicke "EDIT METADATA" und nehme deine Änderungen vor.
|
||||||
|
- Speichere deine Änderungen indem du "SUBMIT" klickst.
|
||||||
|
- Bestätige deine Änderungen mit deinem Private Key.
|
||||||
|
|
||||||
|
Bitte beachte, dass für deine Änderungen Gas Fees anfallen (da eine neue Transaktion initiiert wird). Nach der Änderung ist die vorherige Version der Metadaten deines Data Assets nicht mehr auf Ocean Market sichtbar. Außerdem kannst du den Inhalt deines Daten-Assets jederzeit ändern.
|
||||||
|
|
||||||
|
## 7.3 Recht auf Löschung (Art. 17 GDPR)
|
||||||
|
|
||||||
|
Du hast das Recht, ohne unangemessene Verzögerung die Löschung der dich betreffenden personenbezogenen Daten zu verlangen, wenn die definierten Rechtsgründe in Art. 17 DSGVO zutreffen.
|
||||||
|
|
||||||
|
Wenn du ein Daten-Asset veröffentlicht hast, kannst du deinen angegebenen Autorennamen mit einem Platzhalter überschreiben, indem du die in Kapitel 7.2 aufgeführten Schritte durchführst. Wenn du die Anzeige deines Data Assets auf Ocean Market deaktivieren möchten, kannst du die in Kapitel 7.4 geschilderten Schritte ausführen.
|
||||||
|
|
||||||
|
Beachten bitte, dass es aus technischen Gründen nicht möglich ist, die Transaktionshistorie der Blokchain, die den Smart Contract mit deinen Einträgen enthält, zu löschen. Der aktuelle Netzwerkstatus hingegen, wird die vorherigen Metadaten nicht mehr enthalten.
|
||||||
|
|
||||||
|
Außerdem kannst du aus technischen Gründen deine bereitgestellte Wallet Addresse nicht löschen. Die dauerhafte Speicherung deiner Wallet Addresse schützt dich sowohl als Asset-Publisher als auch als Asset-Consumer. Asset-Publisher können das Eigentum und den Verkäuf eines Assets nachweisen, während Asset-Consumer den Erwerb und Verbrauch von Assets nachweisen können.
|
||||||
|
|
||||||
|
## 7.4 Recht auf Einschränkung der Verarbeitung (Art. 18 GDPR)
|
||||||
|
|
||||||
|
Du hast das Recht, die Einschränkung der Verarbeitung deiner personenbezogenen Daten zu erwirken, wenn die in Artikel 18 DSGVO genannten Rechtsgründe vorliegen.
|
||||||
|
|
||||||
|
Wenn du ein Daten-Asset veröffentlicht hast und ein GitHub-Konto besitzt, kannst du „Purgatory" nutzen, einen Mechanismus, um deine Data Assets auf Ocean Market zu verbergen, indem du die folgenden Schritte durchführst.
|
||||||
|
|
||||||
|
- Besuche unser [**Purgatory** ↗](https://github.com/oceanprotocol/list-purgatory/blob/main/list-assets.json).
|
||||||
|
- Melde dich bei deinem GitHub Account an.
|
||||||
|
- Schlage eine Änderung vor, indem du die betroffene DID deines Assets angibst sowie deinen Grund, wie beispielsweise "Sensitive data".
|
||||||
|
- Bestätige deine Änderungen.
|
||||||
|
|
||||||
|
OPF wird deine Änderungen so schnell wie möglich übernehmen. Du kannst davon ausgehen, dass die Änderungen innerhalb von einer Woche bearbeitet werden. Für weitere Informationen besuche bitte unsere [**Purgatory-Dokumentation** ↗](https://github.com/oceanprotocol/list-purgatory/blob/main/policies/README.md).
|
||||||
|
|
||||||
|
Wenn du Fragen zu Purgatory hast oder wenn du kein GitHub-Konto besitzt und möchtest, dass wir die Anzeige des Datenassets deaktivieren, zögere nicht, uns zu kontaktieren.
|
||||||
|
|
||||||
|
## 7.5 Recht auf Datenübertragbarkeit (Art. 20 GDPR)
|
||||||
|
|
||||||
|
Du hast das Recht, deine personenbezogenen Daten in einem strukturierten, gängigen und maschinenlesbaren Format zu erhalten. Zusätzlich hast du das Recht, diese Daten ungehindert an einen anderen Verantwortlichen zu übermitteln, sofern die in Art. 20 DSGVO definierten Voraussetzungen zutreffen.
|
||||||
|
|
||||||
|
Sie können von Ihrem Recht auf Datenübertragbarkeit Gebrauch machen, indem Sie sich mit uns in Verbindung setzen oder die folgenden Schritte durchführen.
|
||||||
|
|
||||||
|
- Besuche die History Table auf Ocean Market ([market.oceanprotocol.com/history](https://market.oceanprotocol.com/history)).
|
||||||
|
- Validiere deine Identität mit deinem Private Key.
|
||||||
|
- Klicke den Download Button für jede Tabelle, die relevant für dich ist.
|
||||||
|
|
||||||
|
## 7.6 Widerspruchsrecht (Art. 21 GDPR)
|
||||||
|
|
||||||
|
Du hast das Recht, aus Gründen, die sich aus deiner besonderen Situation ergeben, gegen die Verarbeitung deiner personenbezogenen Daten Widerspruch einzulegen, wenn wir die Verarbeitung auf die Wahrung unseres berechtigten Interessens stützen (Art. 6(1)(f) GDPR). Wenn du Widerspruch einlegst, werden wir deine personenbezogenen Daten nicht mehr verarbeiten, es sei denn, wir können zwingende schutzwürdige Gründe für die Verarbeitung nachweisen, die deine Rechte, Freiheiten und Interessen überwiegen, oder wenn die Verarbeitung zur Begründung, Ausübung oder Verteidigung von Rechtsansprüchen erforderlich ist.
|
||||||
|
|
||||||
|
## 7.7 Recht auf Beschwerde bei einer Aufsichtsbehörde (Art. 77 GDPR)
|
||||||
|
|
||||||
|
Du hast das Recht, eine Beschwerde bei einer Aufsichtsbehörde einzureichen, wenn du der Ansicht bist, dass die Verarbeitung deiner personenbezogenen Daten durch OPF gegen die DSGVO verstößt. Du kannst eine Beschwerde insbesondere
|
||||||
|
|
||||||
|
- in dem Mitgliedstaat deines gewöhnlichen Aufenthaltsorts,
|
||||||
|
- in dem Mitgliedstaat deines Arbeitsplatzes und
|
||||||
|
- an dem Ort des mutmaßlichen Verstoßes
|
||||||
|
|
||||||
|
einreichen.
|
||||||
|
|
||||||
|
# 8. Fragen
|
||||||
|
|
||||||
|
Falls du Fragen zu unserer Datenschutzerklärung hast, kontaktiere uns gerne per E-Mail an [gdpr@oceanprotocol.com](mailto:gdpr@oceanprotocol.com).
|
256
content/pages/privacy/en.md
Normal file
256
content/pages/privacy/en.md
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
---
|
||||||
|
title: Privacy Policy
|
||||||
|
description: This privacy policy informs you about how Ocean Protocol Foundation Ltd. (OPF) processes your personal data when you visit Ocean Market and when you use one of our market functionalities. Moreover, this privacy policy informs you about your rights.
|
||||||
|
---
|
||||||
|
|
||||||
|
# 1. Controller
|
||||||
|
|
||||||
|
The controller of the processing of your personal data is:
|
||||||
|
|
||||||
|
Ocean Protocol Foundation Ltd.<br/>
|
||||||
|
The Commerze @ Irving<br/>
|
||||||
|
1 Irving Place, #08-11<br/>
|
||||||
|
369546 Singapore
|
||||||
|
|
||||||
|
E-mail: [gdpr@oceanprotocol.com](mailto:gdpr@oceanprotocol.com)
|
||||||
|
|
||||||
|
# 2. What's personal data?
|
||||||
|
|
||||||
|
Personal data is any information that can be (directly or indirectly) related to you. OPF processes a minimal amount of personal data, as we believe your personal data belongs to you. We process the following personal data.
|
||||||
|
|
||||||
|
**IP address** : Your IP address is processed when visiting Ocean Market.
|
||||||
|
|
||||||
|
If you are using one of our market functionalities, OPF also processes the following personal data.
|
||||||
|
|
||||||
|
- **Your wallet address**: Your wallet address is processed if you are publishing, consuming, or staking on a data asset.
|
||||||
|
- **Author name:** Your name is processed if you decide to publish a data asset. Adding your real name is not required. You are welcome to publish a data asset using a pseudonym.
|
||||||
|
|
||||||
|
If you contact OPF via e-mail, we process your e-mail address and any personal data you decide to provide in your message (such as your name).
|
||||||
|
|
||||||
|
For detailed information about the processing operations, lawfulness, purposes, and how your personal data serves to reach these purposes, please take a look at the chapter " Processing operations according to Article 13 GDPR".
|
||||||
|
|
||||||
|
# 3. Recipients and cross-border data transfer
|
||||||
|
|
||||||
|
**Visiting Ocean Market**
|
||||||
|
|
||||||
|
When you visit Ocean Market, your IP address is processed by Netlify, a service provider that hosts our market. Netlify serves our market using a Content Delivery Network (a geographically distributed network) with servers located out of and within the European Economic Area. We use Standard Contractual Clauses (SCC) to provide appropriate safeguards to the processing of your personal data. You have the right to receive a copy of these SCC.
|
||||||
|
|
||||||
|
- Here you can find Netlify's [**SCC** ↗](https://www.netlify.com/v3/static/pdf/netlify-dpa.pdf).
|
||||||
|
- Here you can find Netlify's [**privacy policy** ↗](https://www.netlify.com/gdpr-ccpa).
|
||||||
|
|
||||||
|
**Using Ocean Market functionalities**
|
||||||
|
|
||||||
|
If you use Ocean Market functionalities, we disclose your wallet address and author name (if applicable) by transmitting it to a smart contract. This smart contract is stored in machine-readable format on a public blockchain that is redundantly stored on nodes worldwide. Given the globally distributed storage, your wallet address and author name (if applicable) are processed in countries without an adequacy decision pursuant to Art. 45 GDPR. The blockchain's underlying technology ensures the security (integrity, availability, authenticity, and non-repudiation) of your personal data by design and by default. Also, your rights described in chapter seven stay enforceable. For instance, if you rectify your author's name on Ocean Market, the changes will also be automatically adopted on nodes that hold a copy of the smart contract.
|
||||||
|
|
||||||
|
**Contact via e-mail**
|
||||||
|
|
||||||
|
If you contact us per e-mail, our (mail) service provider Google Workspace, supports us in communicating with you. During this process, personal data about you are processed, such as your e-mail address and any other information you decide to provide in your message, like your name. Google Workspace is located in the US, so your data is transferred by us to a country without an adequacy decision pursuant to Art. 45 GDPR. We use Standard Contractual Clauses (SCC) to provide appropriate safeguards to the processing of your personal data. You have the right to receive a copy of these SCC.
|
||||||
|
|
||||||
|
- Here you can find the [**SCC** ↗](https://workspace.google.com/terms/mcc_terms.html) of Google Workspace.
|
||||||
|
- Here you can find the [**privacy policy** ↗](https://policies.google.com/) of Google Workspace.
|
||||||
|
|
||||||
|
# 4. Processing operations according to Article 13 GDPR
|
||||||
|
|
||||||
|
We process your personal data for the following purposes.
|
||||||
|
|
||||||
|
## 4.1 Providing Ocean Market and creating log files
|
||||||
|
|
||||||
|
We collect and use your IP address for providing Ocean Market hosted at Netlify. Moreover, OPF uses Netlify Analytics to collect and store your IP address. Your personal data will never leave our service, and we will not track you across sites.
|
||||||
|
|
||||||
|
**Purposes:**
|
||||||
|
|
||||||
|
Collecting and using your IP address is necessary for providing Ocean Market because it is a technical requirement for ensuring communication between your device and our market.
|
||||||
|
|
||||||
|
OPF uses Netlify Analytics to distinguish unique visitors based on IP addresses. This process helps us understand better how many users visit Ocean Market and in which countries the users are located. We use that information to measure traffic and popularity trends to improve our service.
|
||||||
|
|
||||||
|
**Legal basis:**
|
||||||
|
|
||||||
|
The legal basis for this processing is our legitimate interest, according to Art. 6(1)(f) GDPR.
|
||||||
|
|
||||||
|
**Legitimate interests:**
|
||||||
|
|
||||||
|
Our legitimate interest is to provide Ocean Market and its functionalities to you and to improve them.
|
||||||
|
|
||||||
|
**Retention period:**
|
||||||
|
|
||||||
|
We store your IP address for 30 days.
|
||||||
|
|
||||||
|
## 4.2 Consume and stake functionality
|
||||||
|
|
||||||
|
When consuming or staking on a data asset, we collect your wallet address and disclose it by transmitting it to a smart contract stored on the blockchain.
|
||||||
|
|
||||||
|
**Purpose:**
|
||||||
|
|
||||||
|
Ocean Market processes your wallet address to enable you to sign blockchain transactions. The transaction containing your wallet address will be stored permanently on-chain so that you and the asset provider can prove asset acquisition and consumption.
|
||||||
|
|
||||||
|
**Legal basis:**
|
||||||
|
|
||||||
|
The legal basis for this processing is Article 6(1)(b) GDPR, as the processing is necessary for the performance of a contract with you.
|
||||||
|
|
||||||
|
**Retention period:**
|
||||||
|
|
||||||
|
OPF discloses your wallet address by transmitting it to a smart contract stored in machine-readable format permanently on-chain to enable an immutable audit trail.
|
||||||
|
|
||||||
|
## 4.3 Publish functionality
|
||||||
|
|
||||||
|
When you publish a data asset, we collect your wallet address and author name and disclose it by transmitting it to a smart contract stored on the blockchain. Please note that your wallet address will be linked to your given name. Please also note that you can use a pseudonym as the author's name.
|
||||||
|
|
||||||
|
**Purpose:**
|
||||||
|
|
||||||
|
We need to process your wallet address to link your publication to your wallet address. We process your name to enable search and filtering functionality on Ocean Market. The transaction containing your wallet address and author name will be stored permanently on-chain so that you can prove asset ownership and asset sales.
|
||||||
|
|
||||||
|
**Legal basis:**
|
||||||
|
|
||||||
|
The legal basis for this processing is Article 6(1)(b) GDPR, as the processing is necessary for the performance of a contract with you.
|
||||||
|
|
||||||
|
**Retention period:**
|
||||||
|
|
||||||
|
OPF discloses your wallet address and author name by transmitting it to a smart contract stored in machine-readable format permanently on-chain to enable an audit trail.
|
||||||
|
|
||||||
|
## 4.4 Showing data assets
|
||||||
|
|
||||||
|
When you published a data asset, we retrieve, organize, and store your wallet address and author name on a metadata cache operated by OPF. Moreover, we show your asset on Ocean Market.
|
||||||
|
|
||||||
|
**Purposes:**
|
||||||
|
|
||||||
|
Retrieving data from the blockchain is time-consuming. Hence, we retrieve, organize, and store your personal data on a cache to improve the performance of Ocean Market. We show your data asset on Ocean Market, so visitors can find, consume and stake in it.
|
||||||
|
|
||||||
|
**Legal basis:**
|
||||||
|
|
||||||
|
The legal basis for this processing is our legitimate interest, according to Art. 6(1)(f) GDPR.
|
||||||
|
|
||||||
|
**Legitimate interests:**
|
||||||
|
|
||||||
|
Our legitimate interest is to enhance the user experience by improving the performance of Ocean Market.
|
||||||
|
|
||||||
|
**Retention period:**
|
||||||
|
|
||||||
|
Your wallet address and name are stored permanently on our metadata cache.
|
||||||
|
|
||||||
|
## 4.5 History table
|
||||||
|
|
||||||
|
Ocean Market's history table is a transparency tool that you can use to overview your transactions relating to Ocean Market. When you use the history table, we collect your wallet address. Then we retrieve the respective and relevant transactions stored on the blockchain (more precisely, from the metadata cache) and organize them in a table.
|
||||||
|
|
||||||
|
**Purpose:**
|
||||||
|
|
||||||
|
We need to collect your wallet address to retrieve every transaction you made on Ocean Market. We retrieve and organize your public transaction data so you can quickly overview all the actions you made on Ocean Market.
|
||||||
|
|
||||||
|
**Legal basis:**
|
||||||
|
|
||||||
|
The legal basis for this processing is our legitimate interest, according to Art. 6(1)(f) GDPR.
|
||||||
|
|
||||||
|
**Legitimate interests:**
|
||||||
|
|
||||||
|
Our legitimate interest in providing the history table is to offer you the possibility to overview your transactions made on Ocean Market.
|
||||||
|
|
||||||
|
**Retention period:**
|
||||||
|
|
||||||
|
As soon as you disconnect your wallet, we will remove the history table entries from your browser.
|
||||||
|
|
||||||
|
## 4.6 Contact via e-mail
|
||||||
|
|
||||||
|
If you contact us via e-mail, OPF will collect, use and store your e-mail address, and any other information you provide us is your message, such as your name.
|
||||||
|
|
||||||
|
**Purposes:**
|
||||||
|
|
||||||
|
We collect, use and store this personal data to respond to your inquiries.
|
||||||
|
|
||||||
|
**Legal basis:**
|
||||||
|
|
||||||
|
The legal basis for this processing is our legitimate interest, according to Art. 6(1)(f) GDPR.
|
||||||
|
|
||||||
|
**Legitimate interests:**
|
||||||
|
|
||||||
|
Our legitimate interest is to answer your inquiries.
|
||||||
|
|
||||||
|
**Retention period:**
|
||||||
|
|
||||||
|
OPF deletes your personal data as soon as we no longer require them for processing your inquiry, except OPF is obliged to comply with legal retention periods or in case of legal disputes.
|
||||||
|
<br/><i id="cookies"></i>
|
||||||
|
|
||||||
|
# 5. Cookies and web storage
|
||||||
|
|
||||||
|
A cookie is a small file that stores Internet settings. Your web browser downloads it on the first visit to a website. The next time you open this website with the same device, the cookie and the information stored in it are either sent back to the website that created it (first-party cookie) or sent to another website it belongs to (third-party cookie). This enables the website to detect that you have opened it previously with this browser and, in some cases, to vary the displayed content.
|
||||||
|
|
||||||
|
Ocean Market does not use cookies for analytics or marketing purposes. Instead, we use a functional first-party cookie that does not transmit personal data about you. This cookie is used to enhance your user experience and will be removed once you close your browser.
|
||||||
|
|
||||||
|
Ocean Market also uses local storage and session storage, which have similar functionality to cookies. We use your web storage to remember your page preferences and to enhance your user experience. We also do not store personal data in the local storage and session storage. Your browser will remove the session storage once you close your browser.
|
||||||
|
|
||||||
|
You have the option of disabling cookies and deleting cookies and web storage from your computer's hard disk at any time in your browser settings.
|
||||||
|
|
||||||
|
# 6. External links
|
||||||
|
|
||||||
|
Ocean Market contains links to external websites that are beyond the control and responsibility of OPF. We mark external links using this arrow: ↗.
|
||||||
|
|
||||||
|
# 7. Your rights
|
||||||
|
|
||||||
|
If you want to make use of your rights described below, do not hesitate to contact us.
|
||||||
|
|
||||||
|
## 7.1 Right of access (Art. 15 GDPR)
|
||||||
|
|
||||||
|
You have the right to obtain confirmation as to whether OPF processes personal data about you. If we are processing personal data about you, you have the right to access these personal data and to gain the information defined in Art. 15 GDPR.
|
||||||
|
|
||||||
|
## 7.2 Right to rectification (Art. 16 GDPR)
|
||||||
|
|
||||||
|
You have the right to obtain without undue delay the rectification of inaccurate personal data about you. Additionally, you have the right that incomplete personal data about you are completed.
|
||||||
|
|
||||||
|
If you published a data asset, please note that you can modify your provided metadata (like the author's name) at any time by conducting the following steps.
|
||||||
|
|
||||||
|
- Visit your published asset on Ocean Market ([market.oceanprotocol.com](https://market.oceanprotocol.com)).
|
||||||
|
- Validate your identity with your private key.
|
||||||
|
- Click "EDIT METADATA" and make your changes.
|
||||||
|
- Save your changes by clicking "SUBMIT".
|
||||||
|
- Confirm the changes with your private key.
|
||||||
|
|
||||||
|
Please note that you have to pay gas fees for the confirmation of the changes (as a new transaction is issued). After alteration, the previous version of your data asset metadata will no longer be visible on Ocean Market. Also, you can change the content of your data asset at any time.
|
||||||
|
|
||||||
|
## 7.3 Right to erasure (Art. 17 GDPR)
|
||||||
|
|
||||||
|
You have the right to obtain without undue delay the erasure of personal data about you, where the defined legal grounds in Art. 17 GDPR apply.
|
||||||
|
|
||||||
|
If you published a data asset, you could overwrite your provided author name with a placeholder by conducting the steps listed in chapter 7.2. If you want to disable displaying your data asset on Ocean Market, please read chapter 7.4.
|
||||||
|
|
||||||
|
Note that it is not possible to erase the blockchain's transaction history due to technical reasons. But the current network state will no longer hold the former metadata.
|
||||||
|
|
||||||
|
Moreover, due to technical reasons, you cannot erase your provided wallet address. The permanent storage of the wallet address protects you as an asset publisher as well as an asset consumer. Data publishers can prove asset ownership and asset sales, while data consumers can prove asset acquisition and consumption.
|
||||||
|
|
||||||
|
## 7.4 Right to restriction (Art. 18 GDPR)
|
||||||
|
|
||||||
|
Moreover, you have the right to obtain the restriction of processing your personal data where the defined legal grounds in Art. 18 GDPR apply.
|
||||||
|
|
||||||
|
If you published a data asset and have a GitHub account, you can use our Purgatory, a mechanism to hide any data asset from Ocean Market, by conducting the following steps.
|
||||||
|
|
||||||
|
- Visit [**Purgatory** ↗](https://github.com/oceanprotocol/list-purgatory/blob/main/list-assets.json).
|
||||||
|
- Sign in to your GitHub account.
|
||||||
|
- Propose a change by inserting the DID of the concerned asset and state a reason like "Sensitive data".
|
||||||
|
- Commit your changes.
|
||||||
|
|
||||||
|
OPF will accept your changes as soon as possible. You can expect the changes to be processed within a week. For more information, please visit our [**Purgatory documentation** ↗](https://github.com/oceanprotocol/list-purgatory/blob/main/policies/README.md).
|
||||||
|
|
||||||
|
If you have questions about Purgatory or do not have a GitHub account and want us to disable displaying the data asset, do not hesitate to contact us.
|
||||||
|
|
||||||
|
## 7.5 Right to data portability (Art. 20 GDPR)
|
||||||
|
|
||||||
|
You have the right to receive your personal data in a structured, commonly used, and machine-readable format. Additionally, you have the right to transmit those data to another controller without hindrance, where the defined legal grounds in Art. 20 GDPR apply.
|
||||||
|
|
||||||
|
You can make use of your right to data portability either by contacting us or by conducting the following steps.
|
||||||
|
|
||||||
|
- Visit the History Table on Ocean Market ([market.oceanprotocol.com/history](https://market.oceanprotocol.com/history)).
|
||||||
|
- Validate your identity with your private key.
|
||||||
|
- Click on the download button for each table of interest.
|
||||||
|
|
||||||
|
## 7.6 Right to object (Art. 21 GDPR)
|
||||||
|
|
||||||
|
On grounds relating to your particular situation, you have the right to object to the processing of your personal data where we based the processing on legitimate interests (Art. 6(1)(f) GDPR). If you object, OPF will no longer process your personal data unless we can demonstrate compelling legitimate grounds for the processing, overriding your rights, freedoms, and interests, or if the processing is required to establish, exercise, or defend legal claims.
|
||||||
|
|
||||||
|
## 7.7 Right to lodge a complaint (Art. 77 GDPR)
|
||||||
|
|
||||||
|
You have the right to lodge a complaint with a supervisory authority if you consider the processing of your personal data by OPF to infringe the GDPR. You can lodge a complaint in particular
|
||||||
|
|
||||||
|
- in the Member State of your habitual residence,
|
||||||
|
- in the Member State of your place of work, and
|
||||||
|
- in the place of the alleged infringement.
|
||||||
|
|
||||||
|
# 8. Questions
|
||||||
|
|
||||||
|
For any requests regarding our privacy policy, please send us an e-mail to [gdpr@oceanprotocol.com](mailto:gdpr@oceanprotocol.com).
|
257
content/pages/privacy/es.md
Normal file
257
content/pages/privacy/es.md
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
---
|
||||||
|
title: Política de privacidad
|
||||||
|
description: Esta política de privacidad le informa sobre cómo Ocean Protocol Foundation Ltd. procesa sus datos personales cuando visita Ocean Market y cuando utiliza una de nuestras funcionalidades de mercado. Además, esta política de privacidad le informa sobre sus derechos.
|
||||||
|
---
|
||||||
|
|
||||||
|
# 1. Controlador
|
||||||
|
|
||||||
|
El controlador del procesamiento de sus datos personales es:
|
||||||
|
|
||||||
|
Ocean Protocol Foundation Ltd.<br/>
|
||||||
|
The Commerze @ Irving<br/>
|
||||||
|
1 Irving Place, #08-11<br/>
|
||||||
|
369546 Singapore
|
||||||
|
|
||||||
|
E-mail: [gdpr@oceanprotocol.com](gdpr@oceanprotocol.com)
|
||||||
|
|
||||||
|
# 2. ¿Qué son los datos personales?
|
||||||
|
|
||||||
|
Los datos personales son cualquier información que pueda estar (directa o indirectamente) relacionada con usted. Ocean Protocol procesa una cantidad mínima de datos personales, ya que creemos que sus datos personales le pertenecen. Procesamos los siguientes datos personales:
|
||||||
|
|
||||||
|
**Dirección IP** : Su dirección IP se procesa cuando visita Ocean Market.
|
||||||
|
|
||||||
|
Si está utilizando una de nuestras funcionalidades de mercado, Ocean Protocol también procesa los siguientes datos personales:
|
||||||
|
|
||||||
|
- **Dirección de cartera:** Su dirección de cartera se procesa si está publicando, consumiendo o apostando por un activo de datos.
|
||||||
|
|
||||||
|
- **Nombre del autor:** Su nombre se procesa si decide publicar un activo de datos. No es necesario utilizar su nombre real. Puede publicar un activo de datos con un seudónimo.
|
||||||
|
|
||||||
|
Si se comunica con Ocean Protocol por correo electrónico, procesamos su dirección de correo electrónico y cualquier dato personal que decida proporcionar en su mensaje (como su nombre).
|
||||||
|
|
||||||
|
Para obtener información detallada sobre las operaciones de procesamiento, la legalidad, los fines y cómo sus datos personales sirven para alcanzar estos fines, consulte el capítulo "Operaciones de procesamiento de acuerdo con el Artículo 13 del GDPR".
|
||||||
|
|
||||||
|
# 3. Destinatarios y transferencia de datos transfronteriza
|
||||||
|
|
||||||
|
**Visitas al** **Ocean** **Market**
|
||||||
|
|
||||||
|
Cuando visita Ocean Market, su dirección IP es procesada por Netlify, un proveedor de servicios que aloja nuestro mercado. Netlify sirve a nuestro mercado mediante una red de distribución de contenidos (una red distribuida geográficamente) con servidores ubicados fuera y dentro del Espacio Económico Europeo. Usamos Cláusulas Contractuales Tipo (Standard Contractual Clauses o SCC e inglés) para brindar las garantías adecuadas para el procesamiento de sus datos personales. Tiene derecho a recibir una copia de estas SCC.
|
||||||
|
|
||||||
|
- Aquí puede encontrar las [**SCC** ↗](https://www.netlify.com/v3/static/pdf/netlify-dpa.pdf) de Netlify.
|
||||||
|
- Aquí puede encontrar la [**política de privacidad** ↗](https://www.netlify.com/gdpr-ccpa) de Netlify.
|
||||||
|
|
||||||
|
**Uso de las funciones de Ocean Market**
|
||||||
|
|
||||||
|
Si utiliza las funciones de Ocean Market, divulgamos su dirección de cartera y nombre de autor (si corresponde) transmitiéndolos a un contrato inteligente. Este contrato inteligente se almacena en formato legible por máquina en una blockchain o cadena de bloques pública que se almacena de forma redundante en nodos de todo el mundo. Dado que el almacenamiento se encuentra distribuido globalmente, su dirección de cartera y nombre de autor (si corresponde) se procesan en países que no poseen una decisión de adecuación de conformidad con el Art. 45 del GDPR. La tecnología subyacente de la blockchain garantiza la seguridad (integridad, disponibilidad, autenticidad y no repudio) de sus datos personales por diseño y por defecto. Además, sus derechos descritos en el capítulo siete siguen siendo válidos. Por ejemplo, si rectifica su nombre de autor en Ocean Market, los cambios también se adoptarán automáticamente en los nodos que contienen una copia del contrato inteligente.
|
||||||
|
|
||||||
|
**Contacto por correo electrónico**
|
||||||
|
|
||||||
|
Si se comunica con nosotros por correo electrónico, nuestro proveedor de servicios por correo, Google Workspace, nos ayudará a comunicarnos con usted. Durante este proceso, se procesan algunos de sus datos personales, como su dirección de correo electrónico, su nombre y cualquier otra información que decida proporcionar en su mensaje. Google Workspace se ubica en los EE. UU., por lo que sus datos son transferidos a un país que no posee una decisión de adecuación de conformidad con el Art. 45 del GDPR. Usamos Cláusulas Contractuales Tipo (SCC) para brindar las garantías adecuadas para el procesamiento de sus datos personales. Tiene derecho a recibir una copia de estas SCC.
|
||||||
|
|
||||||
|
- Aquí puede encontrar las [**SCC** ↗](https://workspace.google.com/terms/mcc_terms.html) de Google Workspace.
|
||||||
|
- Aquí puede encontrar la [**política de privacidad** ↗](https://policies.google.com/) de Google Workspace.
|
||||||
|
|
||||||
|
# 4. Operaciones de procesamiento de acuerdo con el Artículo 13 del GDPR
|
||||||
|
|
||||||
|
Procesamos sus datos personales para los siguientes fines:
|
||||||
|
|
||||||
|
## 4.1 Proporcionar Ocean Market y crear archivos de registro
|
||||||
|
|
||||||
|
Recopilamos y usamos su dirección IP para proporcionar Ocean Market alojado en Netlify. Además, Ocean Protocol utiliza Netlify Analytics para recopilar y almacenar su dirección IP. Sus datos personales nunca abandonarán nuestro servicio y no lo rastreamos a través de los sitios.
|
||||||
|
|
||||||
|
**Propósitos:**
|
||||||
|
|
||||||
|
La recopilación y el uso de su dirección IP es necesaria para proporcionar Ocean Market, ya que es un requisito técnico que hace posible garantizar la comunicación entre su dispositivo y nuestro mercado.
|
||||||
|
|
||||||
|
Ocean Protocol utiliza Netlify Analytics para distinguir visitantes únicos de acuerdo a sus direcciones IP. Este proceso nos ayuda a comprender mejor cuántos usuarios visitan Ocean Market y en qué países se encuentran los usuarios. Usamos esa información para medir el tráfico y las tendencias de popularidad para mejorar nuestro servicio.
|
||||||
|
|
||||||
|
**Base legal:**
|
||||||
|
|
||||||
|
La base legal para este procesamiento es nuestro interés legítimo, de acuerdo con el Art. 6(1)(f) del GDPR.
|
||||||
|
|
||||||
|
**Intereses legítimos:**
|
||||||
|
|
||||||
|
Nuestro interés legítimo es proporcionarle Ocean Market y sus funcionalidades y mejorarlas.
|
||||||
|
|
||||||
|
**Periodo de conservación:**
|
||||||
|
|
||||||
|
Almacenamos su dirección IP por 30 días.
|
||||||
|
|
||||||
|
## 4.2 Funcionalidad de consumo y participación
|
||||||
|
|
||||||
|
Al consumir o apostar por un activo de datos, recopilamos su dirección de cartera y la divulgamos transmitiéndola a un contrato inteligente almacenado en la blockchain.
|
||||||
|
|
||||||
|
**Propósito:**
|
||||||
|
|
||||||
|
Ocean Market procesa su dirección de cartera para permitirle firmar transacciones de blockchain. La transacción que contiene su dirección de cartera se almacenará permanentemente en cadena para que usted y el proveedor de activos puedan probar la adquisición y el consumo de activos.
|
||||||
|
|
||||||
|
**Base legal:**
|
||||||
|
|
||||||
|
La base legal para este procesamiento es el Artículo 6(1)(b) del GDPR, ya que el procesamiento es necesario para la ejecución de un contrato con usted.
|
||||||
|
|
||||||
|
**Período de retención:**
|
||||||
|
|
||||||
|
Ocean Protocol divulga su dirección de cartera transmitiéndola a un contrato inteligente (Smart Contract) almacenado en formato legible por máquina de forma permanente en cadena para permitir una pista de auditoría inmutable.
|
||||||
|
|
||||||
|
## 4.3 Funcionalidad de publicación
|
||||||
|
|
||||||
|
Cuando publica un activo de datos, recopilamos su dirección de cartera y nombre de autor y los divulgamos transmitiéndolos a un contrato inteligente almacenado en la blockchain. Tenga en cuenta que la dirección de su cartera estará vinculada a su nombre. Tenga en cuenta también que puede utilizar un seudónimo como nombre de autor.
|
||||||
|
|
||||||
|
**Propósito:**
|
||||||
|
|
||||||
|
Necesitamos procesar su dirección de cartera para vincular su publicación a su dirección de cartera. Procesamos su nombre para habilitar la función de búsqueda y filtrado en Ocean Market. La transacción que contiene su dirección de cartera pública y nombre de autor se almacenará permanentemente en cadena para que pueda demostrar la propiedad y las ventas de los activos.
|
||||||
|
|
||||||
|
**Base legal:**
|
||||||
|
|
||||||
|
La base legal para este procesamiento es el Artículo 6(1)(b) del GDPR, ya que el procesamiento es necesario para la ejecución de un contrato con usted.
|
||||||
|
|
||||||
|
**Período de retención:**
|
||||||
|
|
||||||
|
Ocean Protocol divulga su dirección de cartera y nombre de autor transmitiéndolos a un contrato inteligente almacenado en formato legible por máquina de forma permanente en cadena para habilitar una pista de auditoría.
|
||||||
|
|
||||||
|
## 4.4 Mostrar activos de datos
|
||||||
|
|
||||||
|
Cuando publica un activo de datos, recuperamos, organizamos y almacenamos su dirección de cartera y nombre de autor en una caché de metadatos operada por Ocean Protocol. Además, mostramos su activo en Ocean Market.
|
||||||
|
|
||||||
|
**Propósitos:**
|
||||||
|
|
||||||
|
Recuperar datos de la blockchain requiere mucho tiempo. Por lo tanto, recuperamos, organizamos y almacenamos sus datos personales en una caché para mejorar el rendimiento de Ocean Market. Mostramos su activo de datos en Ocean Market para que los visitantes puedan encontrarlo, consumirlo y participar en él.
|
||||||
|
|
||||||
|
**Base legal:**
|
||||||
|
|
||||||
|
La base legal para este procesamiento es nuestro interés legítimo, de acuerdo con el Art. 6(1)(f) del GDPR.
|
||||||
|
|
||||||
|
**Intereses legítimos:**
|
||||||
|
|
||||||
|
Nuestro interés legítimo es mejorar la experiencia del usuario optimizando el rendimiento de Ocean Market.
|
||||||
|
|
||||||
|
**Período de retención:**
|
||||||
|
|
||||||
|
Su dirección de cartera y nombre se almacenan permanentemente en nuestra caché de metadatos.
|
||||||
|
|
||||||
|
## 4.5 Tabla historial
|
||||||
|
|
||||||
|
La tabla de historial de Ocean Market es una herramienta de transparencia que puede utilizar para revisar sus transacciones relacionadas con Ocean Market. Cuando utiliza la tabla de historial, recopilamos su dirección de cartera. Luego, recuperamos las transacciones respectivas y relevantes almacenadas en la blockchain (más precisamente, en la caché de metadatos) y las organizamos en una tabla.
|
||||||
|
|
||||||
|
**Propósito:**
|
||||||
|
|
||||||
|
Necesitamos recopilar su dirección de cartera para recuperar cada transacción que realizó en Ocean Market. Recuperamos y organizamos sus datos de transacciones públicas para que pueda ver rápidamente todas las acciones que realizó en Ocean Market.
|
||||||
|
|
||||||
|
**Base legal:**
|
||||||
|
|
||||||
|
La base legal para este procesamiento es nuestro interés legítimo, de acuerdo con el Art. 6(1)(f) del GDPR.
|
||||||
|
|
||||||
|
**Intereses legítimos:**
|
||||||
|
|
||||||
|
Nuestro interés legítimo al proporcionar la tabla de historial es ofrecerle la posibilidad de revisar sus transacciones realizadas en Ocean Market.
|
||||||
|
|
||||||
|
**Período de retención:**
|
||||||
|
|
||||||
|
Tan pronto como desconecte su billetera, eliminaremos las entradas de la tabla de historial de su navegador.
|
||||||
|
|
||||||
|
## 4.6 Contacto por correo electrónico
|
||||||
|
|
||||||
|
Si se comunica con nosotros por correo electrónico, Ocean Protocol recopilará, utilizará y almacenará su dirección de correo electrónico y cualquier otra información que nos proporcione en su mensaje, como su nombre.
|
||||||
|
|
||||||
|
**Finalidades:**
|
||||||
|
|
||||||
|
Recopilamos, usamos y almacenamos estos datos personales para responder a sus consultas.
|
||||||
|
|
||||||
|
**Base legal:**
|
||||||
|
|
||||||
|
La base legal para este procesamiento es nuestro interés legítimo, de acuerdo con el Art. 6(1)(f) del GDPR.
|
||||||
|
|
||||||
|
**Intereses legítimos:**
|
||||||
|
|
||||||
|
Nuestro interés legítimo es responder a sus consultas.
|
||||||
|
|
||||||
|
**Período de conservación:**
|
||||||
|
|
||||||
|
Ocean Protocol elimina sus datos personales tan pronto como ya no los necesitemos para procesar su consulta, exceptuando el caso en el que Ocean Protocol esté obligada a cumplir con los períodos de retención legales o en caso de disputas legales.
|
||||||
|
<br/><i id="cookies"></i>
|
||||||
|
|
||||||
|
# 5. Cookies y almacenamiento web
|
||||||
|
|
||||||
|
Una cookie es un pequeño archivo que almacena la configuración de Internet. Su navegador web lo descarga en la primera visita a un sitio web. La próxima vez que abra ese sitio web con el mismo dispositivo, la cookie y la información almacenada en él se enviarán al sitio web que lo creó (cookie de origen) o a otro sitio web al que pertenece (cookie de terceros). Esto permite que el sitio web detecte que usted lo ha abierto previamente con ese navegador y, en algunos casos, variar el contenido mostrado.
|
||||||
|
|
||||||
|
Ocean Market no utiliza cookies con fines analíticos o de marketing. Por el contrario, utilizamos una cookie funcional propia que no transmite sus datos personales. Esta cookie se utiliza para mejorar su experiencia de usuario y se eliminará una vez que cierre su navegador.
|
||||||
|
|
||||||
|
Ocean Market también utiliza almacenamiento local y almacenamiento de sesiones, cuya funcionalidad es similar a la de las cookies. Usamos su almacenamiento web para recordar las preferencias de su página y mejorar su experiencia de usuario. Tampoco almacenamos datos personales en el almacenamiento local ni en el almacenamiento de sesiones. Su navegador eliminará el almacenamiento de la sesión una vez que cierre su navegador.
|
||||||
|
|
||||||
|
En la configuración de su navegador tiene la opción de deshabilitar las cookies o eliminar las cookies y el almacenamiento web del disco duro de su computadora en cualquier momento.
|
||||||
|
|
||||||
|
# 6. Enlaces externos
|
||||||
|
|
||||||
|
Ocean Market contiene enlaces a sitios web externos que están más allá del control y la responsabilidad de Ocean Protocol. Marcamos los enlaces externos con esta flecha: ↗.
|
||||||
|
|
||||||
|
# 7. Sus derechos
|
||||||
|
|
||||||
|
Si desea hacer uso de los derechos que se describen a continuación, no dude en ponerse en contacto con nosotros.
|
||||||
|
|
||||||
|
## 7.1 Derecho de acceso (Art. 15 del GDPR)
|
||||||
|
|
||||||
|
Tiene derecho a obtener confirmación sobre si Ocean Protocol procesa datos personales sobre usted. Si estamos procesando sus datos personales, tiene derecho a acceder a los mismos y obtener la información definida en el Art. 15 del GDPR.
|
||||||
|
|
||||||
|
## 7.2 Derecho de rectificación (Art. 16 del GDPR)
|
||||||
|
|
||||||
|
Tiene derecho a obtener sin dilación indebida la rectificación de los datos personales inexactos sobre usted. Además, tiene derecho a que se completen sus datos personales incompletos.
|
||||||
|
|
||||||
|
Si publicó un activo de datos, tenga en cuenta que puede modificar los metadatos proporcionados (como el nombre de autor) en cualquier momento mediante la realización de los siguientes pasos:
|
||||||
|
|
||||||
|
- Visite su activo publicado en Ocean Market ([market.oceanprotocol.com](https://market.oceanprotocol.com)).
|
||||||
|
- Valide su identidad.
|
||||||
|
- Haga clic en "EDIT METADATA" y realice los cambios.
|
||||||
|
- Guarde sus cambios haciendo clic en "SUBMIT".
|
||||||
|
- Confirme los cambios.
|
||||||
|
|
||||||
|
Tenga en cuenta que debe pagar tarifas de gas para la confirmación de los cambios (a medida que se emite una nueva transacción). Después de la modificación, la versión anterior de los metadatos de sus activos de datos ya no estará visible en Ocean Market. Además, puede cambiar el contenido de su activo de datos en cualquier momento.
|
||||||
|
|
||||||
|
## 7.3 Derecho de supresión (Art. 17 del GDPR)
|
||||||
|
|
||||||
|
Tiene derecho a obtener sin dilación indebida la supresión de sus datos personales, cuando los fundamentos legales definidos en el Art. 17 del GDPR se aplican.
|
||||||
|
|
||||||
|
Sí publicó un activo de datos, podría sobrescribir el nombre de autor proporcionado con un marcador de posición siguiendo los pasos que se enumeran en el capítulo 7.2. Si desea deshabilitar la visualización de su activo de datos en Ocean Market, lea el capítulo 7.4.
|
||||||
|
|
||||||
|
Tenga en cuenta que no es posible borrar el historial de transacciones de la blockchain debido a razones técnicas. Sin embargo, el estado actual de la red ya no contendrá los metadatos anteriores.
|
||||||
|
|
||||||
|
Además, debido a razones técnicas, no puede borrar la dirección de cartera proporcionada. El almacenamiento permanente de la dirección de cartera lo protege como editor de activos y como consumidor de activos. Los editores de datos pueden demostrar la propiedad y la venta de activos, mientras que los consumidores de datos pueden demostrar la adquisición y el consumo de activos.
|
||||||
|
|
||||||
|
## 7.4 Derecho a la limitación (Art. 18 del GDPR)
|
||||||
|
|
||||||
|
Además, tiene derecho a obtener la limitación del procesamiento de sus datos personales cuando los fundamentos legales definidos en el Art. 18 del GDPR se aplican.
|
||||||
|
|
||||||
|
Si publicó un activo de datos y tiene una cuenta de GitHub, puede utilizar nuestro Purgatory, un mecanismo para ocultar cualquier activo de datos de Ocean Market, realizando los siguientes pasos:
|
||||||
|
|
||||||
|
- Visite [**Purgatory** ↗](https://github.com/oceanprotocol/list-purgatory/blob/main/list-assets.json).
|
||||||
|
- Inicie sesión en su cuenta de GitHub.
|
||||||
|
- Proponga un cambio insertando el DID del activo en cuestión e indique una razón como "Datos sensibles".
|
||||||
|
- Confirme sus cambios.
|
||||||
|
|
||||||
|
Ocean Protocol aceptará sus cambios lo antes posible. Puede esperar que los cambios se procesen en una semana. Para obtener más información, visite nuestra [**documentación del Purgatory** ↗](https://github.com/oceanprotocol/list-purgatory/blob/main/policies/README.md).
|
||||||
|
|
||||||
|
Si tiene preguntas sobre el Purgatory o no tiene una cuenta de GitHub y desea que desactivemos la visualización del activo de datos, no dude en contactarnos.
|
||||||
|
|
||||||
|
## 7.5 Derecho a la portabilidad de los datos (Art. 20 del GDPR)
|
||||||
|
|
||||||
|
Tiene derecho a recibir sus datos personales en formato estructurado, de uso común y legible por máquina. Además, tiene derecho a transmitir esos datos a otro responsable del tratamiento sin impedimentos, cuando los fundamentos legales definidos en el Art. 20 del GDPR se aplican.
|
||||||
|
|
||||||
|
Puede hacer uso de su derecho a la portabilidad de los datos comunicándose con nosotros o realizando los siguientes pasos:
|
||||||
|
|
||||||
|
- Visite la tabla de historial en Ocean Market ([market.oceanprotocol.com/history](https://market.oceanprotocol.com/history)).
|
||||||
|
- Valide su identidad.
|
||||||
|
- Haga clic en el botón de descarga para cada tabla de interés.
|
||||||
|
|
||||||
|
## 7.6 Derecho de oposición (Art. 21 del GDPR)
|
||||||
|
|
||||||
|
Por motivos relacionados con su situación particular, tiene derecho a oponerse al procesamiento de sus datos personales cuando basamos el procesamiento en intereses legítimos (Art. 6(1)(f) del GDPR). Si se opone, Ocean Protocol ya no procesará sus datos personales, a menos que podamos demostrar motivos legítimos convincentes para el procesamiento, anulando sus derechos, libertades e intereses, o si el procesamiento es necesario para establecer, ejercer o defender reclamos legales.
|
||||||
|
|
||||||
|
## 7.7 Derecho a presentar una queja (Art. 77 del GDPR)
|
||||||
|
|
||||||
|
Tiene derecho a presentar una queja ante una autoridad supervisora si considera que el procesamiento de sus datos personales por parte Ocean Protocol infringe el GDPR. Puede presentar una reclamación, en particular,
|
||||||
|
|
||||||
|
- en el Estado miembro de su residencia habitual,
|
||||||
|
- en el Estado miembro de su lugar de trabajo y
|
||||||
|
- en el lugar de la presunta infracción.
|
||||||
|
|
||||||
|
# 8. Preguntas
|
||||||
|
|
||||||
|
Para cualquier solicitud relacionada con nuestra política de privacidad, envíenos un correo electrónico a [gdpr@oceanprotocol.com](gdpr@oceanprotocol.com).
|
257
content/pages/privacy/fr.md
Normal file
257
content/pages/privacy/fr.md
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
---
|
||||||
|
title: Politique de confidentialité
|
||||||
|
description: Cette politique de confidentialité vous informe sur la façon dont Ocean Protocol Foundation traite vos données personnelles lorsque vous visitez le Ocean Market et lorsque vous utilisez l'une de nos fonctionnalités de marché. De plus, cette politique de confidentialité vous informe de vos droits.
|
||||||
|
---
|
||||||
|
|
||||||
|
# 1. Contrôleur
|
||||||
|
|
||||||
|
Le responsable du traitement du traitement de vos données personnelles est :
|
||||||
|
|
||||||
|
Ocean Protocol Foundation Ltd.<br/>
|
||||||
|
The Commerze @ Irving<br/>
|
||||||
|
1 Irving Place, #08-11<br/>
|
||||||
|
369546 Singapore
|
||||||
|
|
||||||
|
Courriel : [gdpr@oceanprotocol.com](gdpr@oceanprotocol.com)
|
||||||
|
|
||||||
|
# 2. Qu'est-ce qu'une donnée personnelle?
|
||||||
|
|
||||||
|
Les données personnelles sont toutes les informations qui peuvent être (directement ou indirectement) liées à vous. Ocean traite une quantité minimale de données personnelles, car nous pensons que vos données personnelles vous appartiennent. Nous traitons les données personnelles suivantes.
|
||||||
|
|
||||||
|
**Adresse IP** : Votre adresse IP est traitée lors de la visite de Ocean Market.
|
||||||
|
|
||||||
|
Si vous utilisez l'une de nos fonctionnalités du marché, Ocean traite également les données personnelles suivantes.
|
||||||
|
|
||||||
|
- **Adresse de votre portefeuille** : Votre adresse de votre portefeuille est traitée si vous publiez, consommez ou stakez sur un set de données.
|
||||||
|
|
||||||
|
- **Nom de l'auteur :** Votre nom est traité si vous décidez de publier un set de données. L'ajout de votre vrai nom n'est pas nécessaire. Vous êtes invités à publier un set de données à l'aide d'un pseudonyme.
|
||||||
|
|
||||||
|
Si vous contactez Ocean par e-mail, nous traitons votre adresse e-mail et toutes les données personnelles que vous décidez de fournir dans votre message (telles que votre nom).
|
||||||
|
|
||||||
|
Pour des informations détaillées sur les opérations de traitement, la licéité,les finalités et la manière dont vos données personnelles servent à atteindre ces finalités, veuillez consulter le chapitre «Opérations de traitement conformément à l'article 13 du RGPD».
|
||||||
|
|
||||||
|
# 3. Destinataires et transfert de données transfrontalier
|
||||||
|
|
||||||
|
**Visiter le marché Ocean**
|
||||||
|
|
||||||
|
Lorsque vous visitez Ocean Market, votre adresse IP est traitée par Netlify, un fournisseur de services qui héberge notre marché. Netlify dessert notre marché en utilisant un Content Delivery Network (un réseau géographiquement distribué) avec des serveurs situés en dehors et à l'intérieur de l'Espace économique européen. Nous utilisons des clauses contractuelles types (CCT) pour fournir des garanties appropriées au traitement de vos données personnelles. Vous avez le droit de recevoir une copie des présentes CCT.
|
||||||
|
|
||||||
|
- Vous trouverez ici la [**CCT** ↗](https://www.netlify.com/v3/static/pdf/netlify-dpa.pdf) de Netlify.
|
||||||
|
- Vous trouverez ici la [**politique de confidentialité** ↗](https://www.netlify.com/) de Netlify.
|
||||||
|
|
||||||
|
**Utilisation des fonctionnalités du marché Ocean**
|
||||||
|
|
||||||
|
Si vous utilisez les fonctionnalités de Ocean Market, nous divulguons votre adresse de votre portefeuille et votre nom d'auteur (le cas échéant) en les transmettant à un contrat intelligent (smart contract). Ce contrat intelligent est stocké dans un format lisible par machine sur une blockchain publique qui est stockée de manière redondante sur des nœuds dans le monde entier. Compte tenu du stockage distribué à l'échelle mondiale, votre adresse de votre portefeuille et votre nom d'auteur (le cas échéant) sont traités dans des pays sans décision d'adéquation conformément à l'article 45 du RGPD. La technologie sous-jacente de la blockchain assure la sécurité (intégrité, disponibilité, authenticité et non-répudiation) de vos données personnelles par conception et par défaut. De plus, vos droits décrits au chapitre sept restent exécutoires. Par exemple, si vous rectifiez le nom de votre auteur sur Ocean Market, les modifications seront également automatiquement adoptées sur les nœuds qui contiennent une copie du contrat intelligent.
|
||||||
|
|
||||||
|
**Contact par e-mail**
|
||||||
|
|
||||||
|
Si vous nous contactez par e-mail, notre fournisseur de services (mail), Google Workspace, nous accompagne dans la communication avec vous. Au cours de ce processus, des données personnelles vous concernant sont traitées, telles que votre adresse e-mail et toute autre information que vous décidez de fournir dans votre message, comme votre nom. Google Workspace est situé aux États-Unis, de sorte que vos données soient transférées par nous vers un pays sans décision d'adéquation conformément à l'article 45 du RGPD. Nous utilisons des clauses contractuelles types (CCT) pour fournir des garanties appropriées au traitement de vos données personnelles. Vous avez le droit de recevoir une copie des présentes CCT.
|
||||||
|
|
||||||
|
- Vous trouverez ici la [**CCT** ↗](ttps://workspace.google.com/terms/mcc_terms.html) de Google Workspace.
|
||||||
|
- Vous trouverez ici la [**politique de confidentialité** ↗](https://policies.google.com/) de Google Workspace.
|
||||||
|
|
||||||
|
# 4. Opérations de traitement conformément à l'article 13 du RGPD
|
||||||
|
|
||||||
|
Nous traitons vos données personnelles aux finssuivantes.
|
||||||
|
|
||||||
|
## 4.1 Fourniture de Ocean Market et création de fichiers journaux
|
||||||
|
|
||||||
|
Nous collectons et utilisons votre adresse IP pour fournir l'accès à Ocean Market hébergé chez Netlify. De plus, Ocean utilise Netlify Analytics pour collecter et stocker votre adresse IP. Vos données personnelles ne quitteront jamais notre service et nous ne vous suivrons pas sur à travers d'autres sites.
|
||||||
|
|
||||||
|
**Fins:**
|
||||||
|
|
||||||
|
La collecte et l'utilisation de votre adresse IP sont nécessaires pour fournir l'accès à Ocean Market, car il s'agit d'une exigence technique pour assurer la communication entre votre appareil et notre marché.
|
||||||
|
|
||||||
|
Ocean utilise Netlify Analytics pour distinguer les visiteurs uniques en fonction des adresses IP. Ce processus nous aide à mieux comprendre combien d'utilisateurs visitent Ocean Market et dans quels pays se trouvent les utilisateurs. Nous utilisons ces informations pour mesurer les tendances du trafic et de la popularité afin d'améliorer notre service.
|
||||||
|
|
||||||
|
**Base juridique:**
|
||||||
|
|
||||||
|
La base juridique de ce traitement est notre intérêt légitime, conformément à Art. 6(1)(f) RGPD
|
||||||
|
|
||||||
|
**Intérêts légitimes :**
|
||||||
|
|
||||||
|
Notre intérêt légitime est de vous fournir Ocean Market et ses fonctionnalités, ainsi que de les améliorer.
|
||||||
|
|
||||||
|
**Période de conservation :**
|
||||||
|
|
||||||
|
Nous conservons votre adresse IP pendant 30 jours.
|
||||||
|
|
||||||
|
## 4.2 Consommation et staking
|
||||||
|
|
||||||
|
Lorsque vous consommez ou stakez sur set de données, nous collectons votre adresse de votre portefeuille et la divulguons en la transmettant à un contrat intelligent (smart contract) stocké sur la blockchain.
|
||||||
|
|
||||||
|
**Fins:**
|
||||||
|
|
||||||
|
Ocean Market traite votre adresse de votre portefeuille pour vous permettre de signer des transactions blockchain. La transaction contenant votre adresse de votre portefeuille sera stockée en permanence sur la chaîne afin que vous et le fournisseur d'actifs puissiez prouver l'acquisition et la consommation d'actifs.
|
||||||
|
|
||||||
|
**Base juridique:**
|
||||||
|
|
||||||
|
La base juridique de ce traitement est l'article 6, paragraphe 1, point b), du RGPD, car le traitement est nécessaire à l'exécution d'un contrat avec vous.
|
||||||
|
|
||||||
|
**Période de conservation :**
|
||||||
|
|
||||||
|
Ocean divulgue votre adresse de votre portefeuille en la transmettant à un contrat intelligent (smart contract) stocké dans un format lisible par machine en permanence sur la chaîne (on-chain) pour permettre une piste d'audit immuable.
|
||||||
|
|
||||||
|
## 4.3 Fonctionnalité de publication
|
||||||
|
|
||||||
|
Lorsque vous publiez un set de données, nous collectons votre adresse de votre portefeuille et votre nom d'auteur et les divulguons en les transmettant à un contrat intelligent (smart contract) stocké sur la Blockchain. Notez que l'adresse de votre portefeuille sera liée au nom que vous avez fourni. Notez également que vous pouvez utiliser un pseudonyme comme nom d'auteur.
|
||||||
|
|
||||||
|
**Fins:**
|
||||||
|
|
||||||
|
Nous devons traiter votre adresse de votre portefeuille pour lier votre publication à votre adresse. Nous traitons votre nom pour activer la fonctionnalité de recherche et de filtrage sur Ocean Market. La transaction contenant votre adresse de votre portefeuille et le nom de l'auteur sera stockée en permanence sur la chaîne afin que vous puissiez prouver la propriété et la vente des actifs.
|
||||||
|
|
||||||
|
**Base juridique:**
|
||||||
|
|
||||||
|
La base juridique de ce traitement est l'article 6, paragraphe 1, point b), du RGPD, car le traitement est nécessaire à l'exécution d'un contrat avec vous.
|
||||||
|
|
||||||
|
**Période de conservation:**
|
||||||
|
|
||||||
|
Ocean divulgue votre adresse de votre portefeuille et le nom de l'auteur en le transmettant à un contrat intelligent (smart contract) stocké dans un format lisible par machine en permanence sur la chaîne (on-chain) pour permettre une piste d'audit.
|
||||||
|
|
||||||
|
## 4.4 Affichage des ressources de données
|
||||||
|
|
||||||
|
Lorsque vous avez publié un set de données, nous récupérons, organisons et stockons votre adresse de votre portefeuille et votre nom d'auteur sur un cache de métadonnées géré par Ocean. De plus, nous montrons votre set données sur Ocean Market.
|
||||||
|
|
||||||
|
**Fins:**
|
||||||
|
|
||||||
|
La récupération de données à partir de la blockchain prend du temps. Par conséquent, nous récupérons, organisons et stockons vos données personnelles sur un cache pour améliorer les performances de Ocean Market. Nous montrons votre set de données sur Ocean Market, afin que les visiteurs puissent trouver, consommer et staker.
|
||||||
|
|
||||||
|
**Base juridique:**
|
||||||
|
|
||||||
|
La base juridique de ce traitement est notre intérêt légitime, conformément à l'article 6, paragraphe 1, point f), du RGPD.
|
||||||
|
|
||||||
|
**Intérêts légitimes:**
|
||||||
|
|
||||||
|
Notre intérêt légitime est d'améliorer l'expérience utilisateur en améliorant les performances de Ocean Market.
|
||||||
|
|
||||||
|
**Période de conservation:**
|
||||||
|
|
||||||
|
Votre adresse de votre portefeuille et votre nom sont stockés en permanence sur notre cache de métadonnées.
|
||||||
|
|
||||||
|
## 4.5 Historique
|
||||||
|
|
||||||
|
Lhistorique de Ocean Market est un outil de transparence que vous pouvez utiliser pour visualiser vos transactions relatives à Ocean Market. Lorsque vous utilisez l'historique, nous collectons votre adresse de votre portefeuille. Ensuite, nous récupérons les transactions respectives et pertinentes stockées sur la blockchain (plus précisément, à partir du cache de métadonnées) et les organisons dans une table.
|
||||||
|
|
||||||
|
**Fins:**
|
||||||
|
|
||||||
|
Nous devons collecter votre adresse de votre portefeuille pour récupérer chaque transaction que vous avez effectuée sur Ocean Market. Nous récupérons et organisons vos données de transaction publiques afin que vous puissiez rapidement avoir un aperçu de toutes les actions que vous avez effectuées sur Ocean Market.
|
||||||
|
|
||||||
|
**Base juridique:**
|
||||||
|
|
||||||
|
La base juridique de ce traitement est notre intérêt légitime, conformément à l'article 6, paragraphe 1, point f), du RGPD.
|
||||||
|
|
||||||
|
**Intérêts légitimes:**
|
||||||
|
|
||||||
|
Notre intérêt légitime à fournir l'historique est de vous offrir la possibilité de visualiser et avoir une vue d'ensemble de vos transactions effectuées sur Ocean Market.
|
||||||
|
|
||||||
|
**Période de conservation:**
|
||||||
|
|
||||||
|
Dès que vous déconnectez votre portefeuille, nous supprimons les entrées de la table d'historique de votre navigateur.
|
||||||
|
|
||||||
|
## 4.6 Contact par e-mail
|
||||||
|
|
||||||
|
Si vous nous contactez par e-mail, Ocean collectera, utilisera et stockera votre adresse e-mail, et toute autre information que vous nous fournissez dans votre message, tel que votre nom.
|
||||||
|
|
||||||
|
**Fins:**
|
||||||
|
|
||||||
|
Nous collectons, utilisons et stockons ces données personnelles pour répondre à vos demandes.
|
||||||
|
|
||||||
|
**Base juridique:**
|
||||||
|
|
||||||
|
La base juridique de ce traitement est notre intérêt légitime, conformément à l'article 6, paragraphe 1, point f), du RGPD.
|
||||||
|
|
||||||
|
**Intérêts légitimes :**
|
||||||
|
|
||||||
|
Notre intérêt légitime est de répondre à vos demandes.
|
||||||
|
|
||||||
|
**Période de conservation :**
|
||||||
|
|
||||||
|
Ocean supprime vos données personnelles dès que nous n'en avons plus besoin pour traiter votre demande, sauf si Ocean est tenu de respecter les délais de conservation légaux ou en cas de litiges juridiques.
|
||||||
|
<br/><i id="cookies"></i>
|
||||||
|
|
||||||
|
# 5. Cookies et stockage web
|
||||||
|
|
||||||
|
Un cookie est un petit fichier qui stocke les paramètres Internet. Votre navigateur Web le télécharge lors de la première visite sur un site Web. La prochaine fois que vous ouvrez ce site Web avec le même appareil, le cookie et les informations qui y sont stockées sont soit renvoyés au site Web qui l'a créé (cookie de première partie), soit envoyés à un autre site Web auquel il appartient (cookie tiers). Cela permet au site Web de détecter que vous l'avez déjà ouvert avec ce navigateur et, dans certains cas, de faire varier le contenu affiché.
|
||||||
|
|
||||||
|
Ocean Market n'utilise pas de cookies à des fins d'analyse ou de marketing. Au lieu de cela, nous utilisons un cookie de première partie fonctionnel qui ne transmet pas de données personnelles vous concernant. Son cookie est utilisé pour améliorer votre expérience utilisateur et sera supprimé une fois que vous aurez fermé votre navigateur.
|
||||||
|
|
||||||
|
Ocean Market utilise également le stockage local et le stockage de session, qui ont des fonctionnalités similaires aux cookies. Nous utilisons votre stockage Web pour mémoriser vos préférences de page et améliorer votre expérience utilisateur. Nous ne stockons pas non plus de données personnelles dans le stockage local et le stockage de session. Votre navigateur supprimera le stockage de session une fois que vous le fermerez.
|
||||||
|
|
||||||
|
Vous avez la possibilité de désactiver les cookies, supprimer les cookies et le stockage Web du disque dur de votre ordinateur à tout moment dans les paramètres de votre navigateur.
|
||||||
|
|
||||||
|
# 6. Liens externes
|
||||||
|
|
||||||
|
Ocean Market contient des liens vers des sites Web externes qui sont hors du contrôle et de la responsabilité de Ocean. Nous marquons les liens externes en utilisant ceci: ↗.
|
||||||
|
|
||||||
|
# 7. Vos droits
|
||||||
|
|
||||||
|
Si vous souhaitez faire usage de vos droits décrits ci-dessous, n'hésitez pas à nous contacter.
|
||||||
|
|
||||||
|
## 7.1 Droit d'accès (art. 15 du RGPD)
|
||||||
|
|
||||||
|
Vous avez le droit d'obtenir la confirmation que Ocean traite les données personnelles vous concernant. Si nous traitons des données personnelles vous concernant, vous avez le droit d'accéder à ces données personnelles et d'obtenir les informations définies à l'article 15 du RGPD.
|
||||||
|
|
||||||
|
## 7.2 Droit de rectification (art. 16 RGPD)
|
||||||
|
|
||||||
|
Vous avez le droit d'obtenir sans retard injustifié la rectification de données personnelles inexactes vous concernant. En outre, vous avez le droit de compléter les données personnelles incomplètes vous concernant.
|
||||||
|
|
||||||
|
Si vous avez publié un set de données, veuillez noter que vous pouvez modifier les métadonnées que vous avez fournies (comme le nom de l'auteur) à tout moment en procédant comme suit.
|
||||||
|
|
||||||
|
- Visitez votre actif publié sur Ocean Market ([market.oceanprotocol.com](https://market.oceanprotocol.com)).
|
||||||
|
- Validez votre identité avec votre clé privée.
|
||||||
|
- Cliquez sur « EDIT METADATA » et apportez vos modifications.
|
||||||
|
- Enregistrez vos modifications en cliquant sur « SUBMIT ».
|
||||||
|
- Confirmez les modifications avec votre clé privée.
|
||||||
|
|
||||||
|
Veuillez noter que vous devez payer des frais de gas (fees) pour la confirmation des changements (car une nouvelle transaction est émise). Après modification, la version précédente de vos métadonnées du set de données ne sera plus visible sur Ocean Market. En outre, vous pouvez modifier le contenu de votre set de données à tout moment.
|
||||||
|
|
||||||
|
## 7.3 Droit à l'effacement (art. 17 du RGPD)
|
||||||
|
|
||||||
|
Vous avez le droit d'obtenir sans retard injustifié l'effacement des données personnelles vous concernant, lorsque les fondements juridiques définis à l'article 17 du RGPD s'appliquent.
|
||||||
|
|
||||||
|
Si vous avez publié un set de données, vous devez remplacer le nom d'auteur fourni par un espace réservé en effectuant les étapes énumérées au chapitre 7.2. Si vous souhaitez désactiver l'affichage de votre set de données sur Ocean Market, veuillez lire le chapitre 7.4.
|
||||||
|
|
||||||
|
Notez qu'il n'est pas possible d'effacer l'historique des transactions de la blockchain pour des raisons techniques. Mais l'état actuel du réseau ne contiendra plus les anciennes métadonnées.
|
||||||
|
|
||||||
|
De plus, pour des raisons techniques, vous ne pouvez pas effacer votre adresse de votre portefeuille fournie. Le stockage permanent de la adresse de votre portefeuille vous protège en tant qu'éditeur de ressources ainsi qu'en tant que consommateur. Les publieurs de set de données peuvent prouver la propriété et la vente d'actifs, tandis que les consommateurs peuvent prouver l'acquisition et la consommation d'actifs.
|
||||||
|
|
||||||
|
## 7.4 Droit à la restriction (art. 18 du RGPD)
|
||||||
|
|
||||||
|
En outre, vous avez le droit d'obtenir la limitation du traitement de vos données personnelles lorsque les fondements juridiques définis à l'article 18 du RGPD s'appliquent.
|
||||||
|
|
||||||
|
Si vous avez publié un set de données et que vous avez un compte GitHub, vous pouvez utiliser notre Purgatoire, un mécanisme pour masquer tout set de données du marché Ocean, en procédant comme suit.
|
||||||
|
|
||||||
|
- Visitez [**Purgatory** ↗](https://github.com/oceanprotocol/list-purgatory/blob/main/list-assets.json).
|
||||||
|
- Connectez-vous à votre compte GitHub.
|
||||||
|
- Proposer une modification en insérant le DID de l'actif concerné et indiquer une raison comme « Données sensibles ».
|
||||||
|
- Validez vos modifications.
|
||||||
|
|
||||||
|
Ocean acceptera vos modifications dès que possible. Vous pouvez vous attendre à ce que les modifications soient traitées dans un délai d'une semaine. Pour plus d'informations, veuillez consulter notre [**documentation Purgatory** ↗](https://github.com/Ocean/list-purgatory/blob/main/policies/README.md).
|
||||||
|
|
||||||
|
Si vous avez des questions sur Purgatory ou si vous n'avez pas de compte GitHub et que vous souhaitez que nous désactivons l'affichage du set de données, n'hésitez pas à nous contacter.
|
||||||
|
|
||||||
|
## 7.5 Droit à la portabilité des données (art. 20 RGPD)
|
||||||
|
|
||||||
|
Vous avez le droit de recevoir vos données personnelles dans un format structuré, couramment utilisé et lisible par machine. En outre, vous avez le droit de transmettre ces données à un autre responsable du traitement sans entrave, lorsque les fondements juridiques définis à l'article 20 du RGPD s'appliquent.
|
||||||
|
|
||||||
|
Vous pouvez faire usage de votre droit à la portabilité des données en nous contactant ou en procédant comme suit.
|
||||||
|
|
||||||
|
- Visitez l'historique sur le marché Ocean ([market.oceanprotocol.com/history](https://market.oceanprotocol.com/history)).
|
||||||
|
- Validez votre identité avec votre clé privée.
|
||||||
|
- Cliquez sur le bouton de téléchargement pour chaque table d'intérêt.
|
||||||
|
|
||||||
|
## 7.6 Droit d'opposition (art. 21 du RGPD)
|
||||||
|
|
||||||
|
Pour des motifs liés à votre situation particulière, vous avez le droit de vous opposer au traitement de vos données personnelles lorsque nous avons basé le traitement sur des intérêts légitimes (art. 6(1)(f) du RGPD). Si vous vous y opposez, Ocean ne traitera plus vos données personnelles à moins que nous puissions démontrer des motifs légitimes impérieux pour le traitement, outrepassant vos droits, libertés et intérêts, ou si le traitement est nécessaire pour établir, exercer ou défendre des réclamations légales.
|
||||||
|
|
||||||
|
## 7.7 Droit de déposer une plainte (art. 77 RGPD)
|
||||||
|
|
||||||
|
Vous avez le droit de déposer une plainte auprès d'une autorité de contrôle si vous considérez que le traitement de vos données personnelles par Ocean enfreint le RGPD. Vous pouvez déposer une plainte en particulier
|
||||||
|
|
||||||
|
- dans l'État membre de votre résidence habituelle,
|
||||||
|
- dans l'État membre de votre lieu de travail, et
|
||||||
|
- à la place de l'infraction alléguée.
|
||||||
|
|
||||||
|
# 8. Questions
|
||||||
|
|
||||||
|
Pour toute question ou demande concernant notre politique de confidentialité, veuillez nous envoyer un e-mail à [gdpr@oceanprotocol.com](gdpr@oceanprotocol.com).
|
52
content/pages/privacy/policies.json
Normal file
52
content/pages/privacy/policies.json
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"policies": [
|
||||||
|
{
|
||||||
|
"policy": "en",
|
||||||
|
"language": "English",
|
||||||
|
"date": "2021-07-31",
|
||||||
|
"params": {
|
||||||
|
"languageLabel": "Language",
|
||||||
|
"languageHelp": "Language of the privacy policy",
|
||||||
|
"tocHeader": "Table of contents",
|
||||||
|
"updated": "Last updated on",
|
||||||
|
"dateFormat": "MM/dd/yyyy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"policy": "de",
|
||||||
|
"language": "Deutsch",
|
||||||
|
"date": "2021-07-31",
|
||||||
|
"params": {
|
||||||
|
"languageLabel": "Sprache",
|
||||||
|
"languageHelp": "Die Sprache der Datenschutzerklärung",
|
||||||
|
"tocHeader": "Inhalt",
|
||||||
|
"updated": "Letzte Aktualisierung am",
|
||||||
|
"dateFormat": "dd.MM.yyyy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"policy": "es",
|
||||||
|
"language": "Español",
|
||||||
|
"date": "2021-08-02",
|
||||||
|
"params": {
|
||||||
|
"languageLabel": "Idioma",
|
||||||
|
"languageHelp": "El idioma de la política de privacidad",
|
||||||
|
"tocHeader": "Índice",
|
||||||
|
"updated": "Última actualización",
|
||||||
|
"dateFormat": "dd.MM.yyyy"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"policy": "fr",
|
||||||
|
"language": "Français",
|
||||||
|
"date": "2021-08-02",
|
||||||
|
"params": {
|
||||||
|
"languageLabel": "Langue",
|
||||||
|
"languageHelp": "La langue de la politique de confidentialité",
|
||||||
|
"tocHeader": "Sommaire",
|
||||||
|
"updated": "Dernière mise à jour le",
|
||||||
|
"dateFormat": "dd.MM.yyyy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
{
|
{
|
||||||
"name": "description",
|
"name": "description",
|
||||||
"label": "Description",
|
"label": "Description",
|
||||||
"help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).",
|
"help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics). You can change the description at any time. If you provide personal data, please note that it will remain in the transaction history. For more information on how personal data is handled within the metadata, please refer to our [privacy policy](/privacy/en).",
|
||||||
"type": "textarea",
|
"type": "textarea",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
@ -82,7 +82,7 @@
|
|||||||
"name": "author",
|
"name": "author",
|
||||||
"label": "Author",
|
"label": "Author",
|
||||||
"placeholder": "e.g. Jelly McJellyfish",
|
"placeholder": "e.g. Jelly McJellyfish",
|
||||||
"help": "Give proper attribution for your algorithm.",
|
"help": "Give proper attribution for your data set. You are welcome to use a pseudonym, and you can change your author name at any time. Please note that it will remain in the transaction history. For more information on how personal data is handled within the metadata, please refer to our [privacy policy](/privacy/en).",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
{
|
{
|
||||||
"name": "description",
|
"name": "description",
|
||||||
"label": "Description",
|
"label": "Description",
|
||||||
"help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics).",
|
"help": "Add a thorough description with as much detail as possible. You can use [Markdown](https://daringfireball.net/projects/markdown/basics). You can change the description at any time. If you provide personal data, please note that it will remain in the transaction history. For more information on how personal data is handled within the metadata, please refer to our [privacy policy](/privacy/en).",
|
||||||
"type": "textarea",
|
"type": "textarea",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
@ -36,7 +36,9 @@
|
|||||||
"help": "Choose how you want your files to be accessible for the specified price.",
|
"help": "Choose how you want your files to be accessible for the specified price.",
|
||||||
"type": "boxSelection",
|
"type": "boxSelection",
|
||||||
"options": ["Download", "Compute"],
|
"options": ["Download", "Compute"],
|
||||||
"required": true
|
"required": true,
|
||||||
|
"disclaimer": "Please do not provide downloadable personal data without the consent of the data subjects.",
|
||||||
|
"disclaimerValues": ["Download"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "providerUri",
|
"name": "providerUri",
|
||||||
@ -66,7 +68,7 @@
|
|||||||
"name": "author",
|
"name": "author",
|
||||||
"label": "Author",
|
"label": "Author",
|
||||||
"placeholder": "e.g. Jelly McJellyfish",
|
"placeholder": "e.g. Jelly McJellyfish",
|
||||||
"help": "Give proper attribution for your data set.",
|
"help": "Give proper attribution for your data set. You are welcome to use a pseudonym, and you can change your author name at any time. Please note that it will remain in the transaction history. For more information on how personal data is handled within the metadata, please refer to our [privacy policy](/privacy/en).",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,12 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
'gatsby-transformer-sharp',
|
'gatsby-transformer-sharp',
|
||||||
'gatsby-transformer-json',
|
'gatsby-transformer-json',
|
||||||
'gatsby-transformer-remark',
|
{
|
||||||
|
resolve: `gatsby-transformer-remark`,
|
||||||
|
options: {
|
||||||
|
plugins: [`gatsby-remark-autolink-headers`]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
resolve: 'gatsby-plugin-svgr',
|
resolve: 'gatsby-plugin-svgr',
|
||||||
options: {
|
options: {
|
||||||
|
@ -21,6 +21,31 @@ execSync(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//Extend ContentJson to support optional field "optionalCookies" in gdpr.json
|
||||||
|
//Extend PublishJsonData to support optional fields for disclaimers
|
||||||
|
exports.sourceNodes = ({ actions }) => {
|
||||||
|
const { createTypes } = actions
|
||||||
|
const typeDefs = `
|
||||||
|
type ContentJson implements Node {
|
||||||
|
accept: String
|
||||||
|
reject: String
|
||||||
|
close: String
|
||||||
|
configure: String
|
||||||
|
optionalCookies: [Cookie!]
|
||||||
|
}
|
||||||
|
type Cookie {
|
||||||
|
title: String!
|
||||||
|
desc: String!
|
||||||
|
cookieName: String!
|
||||||
|
}
|
||||||
|
type PublishJsonData implements Node {
|
||||||
|
disclaimer: String
|
||||||
|
disclaimerValues: [String!]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
createTypes(typeDefs)
|
||||||
|
}
|
||||||
|
|
||||||
exports.onCreateNode = ({ node, actions, getNode }) => {
|
exports.onCreateNode = ({ node, actions, getNode }) => {
|
||||||
createFields(node, actions, getNode)
|
createFields(node, actions, getNode)
|
||||||
}
|
}
|
||||||
|
91
package-lock.json
generated
91
package-lock.json
generated
@ -41,6 +41,7 @@
|
|||||||
"gatsby-plugin-svgr": "^2.1.0",
|
"gatsby-plugin-svgr": "^2.1.0",
|
||||||
"gatsby-plugin-use-dark-mode": "^1.3.0",
|
"gatsby-plugin-use-dark-mode": "^1.3.0",
|
||||||
"gatsby-plugin-webpack-size": "^2.0.1",
|
"gatsby-plugin-webpack-size": "^2.0.1",
|
||||||
|
"gatsby-remark-autolink-headers": "^4.8.0",
|
||||||
"gatsby-source-filesystem": "^2.9.0",
|
"gatsby-source-filesystem": "^2.9.0",
|
||||||
"gatsby-source-graphql": "^2.12.0",
|
"gatsby-source-graphql": "^2.12.0",
|
||||||
"gatsby-transformer-json": "^2.9.0",
|
"gatsby-transformer-json": "^2.9.0",
|
||||||
@ -49,6 +50,7 @@
|
|||||||
"graphql": "14.7.0",
|
"graphql": "14.7.0",
|
||||||
"graphql-schema-typescript": "^1.5.2",
|
"graphql-schema-typescript": "^1.5.2",
|
||||||
"is-url-superb": "^6.0.0",
|
"is-url-superb": "^6.0.0",
|
||||||
|
"js-cookie": "^3.0.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.omit": "^4.5.0",
|
"lodash.omit": "^4.5.0",
|
||||||
@ -87,6 +89,7 @@
|
|||||||
"@testing-library/react": "^11.2.7",
|
"@testing-library/react": "^11.2.7",
|
||||||
"@types/chart.js": "^2.9.32",
|
"@types/chart.js": "^2.9.32",
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
|
"@types/js-cookie": "^2.2.7",
|
||||||
"@types/loadable__component": "^5.13.1",
|
"@types/loadable__component": "^5.13.1",
|
||||||
"@types/lodash.debounce": "^4.0.3",
|
"@types/lodash.debounce": "^4.0.3",
|
||||||
"@types/lodash.omit": "^4.5.6",
|
"@types/lodash.omit": "^4.5.6",
|
||||||
@ -1620,11 +1623,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.14.0",
|
"version": "7.14.8",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
|
||||||
"integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==",
|
"integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime-corejs3": {
|
"node_modules/@babel/runtime-corejs3": {
|
||||||
@ -10650,6 +10656,12 @@
|
|||||||
"npm": ">=6.0.0"
|
"npm": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/js-cookie": {
|
||||||
|
"version": "2.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
|
||||||
|
"integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@truffle/preserve-to-filecoin/node_modules/multicodec": {
|
"node_modules/@truffle/preserve-to-filecoin/node_modules/multicodec": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/multicodec/-/multicodec-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/multicodec/-/multicodec-3.2.1.tgz",
|
||||||
@ -28122,6 +28134,35 @@
|
|||||||
"uuid": "bin/uuid"
|
"uuid": "bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/gatsby-remark-autolink-headers": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gatsby-remark-autolink-headers/-/gatsby-remark-autolink-headers-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-N8LK92gPa/k+Ht3f33+GkBAXijrjdBZxxfLgVjnGpL1QTSJImhSDcgxsO1CAhc+vrChAJ7p8ZWTOO9TLnMaisg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.14.6",
|
||||||
|
"github-slugger": "^1.3.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"mdast-util-to-string": "^2.0.0",
|
||||||
|
"unist-util-visit": "^2.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.13.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"gatsby": "^3.0.0-next.0",
|
||||||
|
"react": "^16.9.0 || ^17.0.0",
|
||||||
|
"react-dom": "^16.9.0 || ^17.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/gatsby-remark-autolink-headers/node_modules/mdast-util-to-string": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/gatsby-source-filesystem": {
|
"node_modules/gatsby-source-filesystem": {
|
||||||
"version": "2.11.1",
|
"version": "2.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/gatsby-source-filesystem/-/gatsby-source-filesystem-2.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/gatsby-source-filesystem/-/gatsby-source-filesystem-2.11.1.tgz",
|
||||||
@ -36633,6 +36674,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz",
|
||||||
"integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q=="
|
"integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/js-cookie": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-oUbbplKuH07/XX2YD2+Q+GMiPpnVXaRz8npE7suhBH9QEkJe2W7mQ6rwuMXHue3fpfcftQwzgyvGzIHyfCSngQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/js-sha3": {
|
"node_modules/js-sha3": {
|
||||||
"version": "0.8.0",
|
"version": "0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
||||||
@ -60739,9 +60788,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.14.0",
|
"version": "7.14.8",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.8.tgz",
|
||||||
"integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==",
|
"integrity": "sha512-twj3L8Og5SaCRCErB4x4ajbvBIVV77CGeFglHpeg5WC5FF8TZzBWXtTJ4MqaD9QszLYTtr+IsaAL2rEUevb+eg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
}
|
}
|
||||||
@ -69109,6 +69158,12 @@
|
|||||||
"pretty-format": "^26.0.0"
|
"pretty-format": "^26.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/js-cookie": {
|
||||||
|
"version": "2.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz",
|
||||||
|
"integrity": "sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/js-yaml": {
|
"@types/js-yaml": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.2.tgz",
|
||||||
@ -82872,6 +82927,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"gatsby-remark-autolink-headers": {
|
||||||
|
"version": "4.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/gatsby-remark-autolink-headers/-/gatsby-remark-autolink-headers-4.8.0.tgz",
|
||||||
|
"integrity": "sha512-N8LK92gPa/k+Ht3f33+GkBAXijrjdBZxxfLgVjnGpL1QTSJImhSDcgxsO1CAhc+vrChAJ7p8ZWTOO9TLnMaisg==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.14.6",
|
||||||
|
"github-slugger": "^1.3.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"mdast-util-to-string": "^2.0.0",
|
||||||
|
"unist-util-visit": "^2.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mdast-util-to-string": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"gatsby-source-filesystem": {
|
"gatsby-source-filesystem": {
|
||||||
"version": "2.11.1",
|
"version": "2.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/gatsby-source-filesystem/-/gatsby-source-filesystem-2.11.1.tgz",
|
"resolved": "https://registry.npmjs.org/gatsby-source-filesystem/-/gatsby-source-filesystem-2.11.1.tgz",
|
||||||
@ -88923,6 +88997,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz",
|
||||||
"integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q=="
|
"integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q=="
|
||||||
},
|
},
|
||||||
|
"js-cookie": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-oUbbplKuH07/XX2YD2+Q+GMiPpnVXaRz8npE7suhBH9QEkJe2W7mQ6rwuMXHue3fpfcftQwzgyvGzIHyfCSngQ=="
|
||||||
|
},
|
||||||
"js-sha3": {
|
"js-sha3": {
|
||||||
"version": "0.8.0",
|
"version": "0.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
"gatsby-plugin-svgr": "^2.1.0",
|
"gatsby-plugin-svgr": "^2.1.0",
|
||||||
"gatsby-plugin-use-dark-mode": "^1.3.0",
|
"gatsby-plugin-use-dark-mode": "^1.3.0",
|
||||||
"gatsby-plugin-webpack-size": "^2.0.1",
|
"gatsby-plugin-webpack-size": "^2.0.1",
|
||||||
|
"gatsby-remark-autolink-headers": "^4.8.0",
|
||||||
"gatsby-source-filesystem": "^2.9.0",
|
"gatsby-source-filesystem": "^2.9.0",
|
||||||
"gatsby-source-graphql": "^2.12.0",
|
"gatsby-source-graphql": "^2.12.0",
|
||||||
"gatsby-transformer-json": "^2.9.0",
|
"gatsby-transformer-json": "^2.9.0",
|
||||||
@ -64,6 +65,7 @@
|
|||||||
"graphql": "14.7.0",
|
"graphql": "14.7.0",
|
||||||
"graphql-schema-typescript": "^1.5.2",
|
"graphql-schema-typescript": "^1.5.2",
|
||||||
"is-url-superb": "^6.0.0",
|
"is-url-superb": "^6.0.0",
|
||||||
|
"js-cookie": "^3.0.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.omit": "^4.5.0",
|
"lodash.omit": "^4.5.0",
|
||||||
@ -102,6 +104,7 @@
|
|||||||
"@testing-library/react": "^11.2.7",
|
"@testing-library/react": "^11.2.7",
|
||||||
"@types/chart.js": "^2.9.32",
|
"@types/chart.js": "^2.9.32",
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
|
"@types/js-cookie": "^2.2.7",
|
||||||
"@types/loadable__component": "^5.13.1",
|
"@types/loadable__component": "^5.13.1",
|
||||||
"@types/lodash.debounce": "^4.0.3",
|
"@types/lodash.debounce": "^4.0.3",
|
||||||
"@types/lodash.omit": "^4.5.6",
|
"@types/lodash.omit": "^4.5.6",
|
||||||
|
2
src/@types/Form.d.ts
vendored
2
src/@types/Form.d.ts
vendored
@ -13,6 +13,8 @@ export interface FormFieldProps {
|
|||||||
placeholder?: string
|
placeholder?: string
|
||||||
pattern?: string
|
pattern?: string
|
||||||
min?: string
|
min?: string
|
||||||
|
disclaimer?: string
|
||||||
|
disclaimerValues?: string[]
|
||||||
advanced?: boolean
|
advanced?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import { useSiteMetadata } from '../hooks/useSiteMetadata'
|
|||||||
import { useAccountPurgatory } from '../hooks/useAccountPurgatory'
|
import { useAccountPurgatory } from '../hooks/useAccountPurgatory'
|
||||||
import AnnouncementBanner from './atoms/AnnouncementBanner'
|
import AnnouncementBanner from './atoms/AnnouncementBanner'
|
||||||
import styles from './App.module.css'
|
import styles from './App.module.css'
|
||||||
|
import PrivacyPreferenceCenter from './organisms/PrivacyPreferenceCenter'
|
||||||
|
|
||||||
const contentQuery = graphql`
|
const contentQuery = graphql`
|
||||||
query AppQuery {
|
query AppQuery {
|
||||||
@ -36,7 +37,7 @@ export default function App({
|
|||||||
const data = useStaticQuery(contentQuery)
|
const data = useStaticQuery(contentQuery)
|
||||||
const purgatory = data.purgatory.edges[0].node.childContentJson.account
|
const purgatory = data.purgatory.edges[0].node.childContentJson.account
|
||||||
|
|
||||||
const { warning } = useSiteMetadata()
|
const { warning, appConfig } = useSiteMetadata()
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||||
|
|
||||||
@ -58,6 +59,10 @@ export default function App({
|
|||||||
)}
|
)}
|
||||||
<main className={styles.main}>{children}</main>
|
<main className={styles.main}>{children}</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
||||||
|
{appConfig.privacyPreferenceCenter === 'true' && (
|
||||||
|
<PrivacyPreferenceCenter style="small" />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Styles>
|
</Styles>
|
||||||
)
|
)
|
||||||
|
@ -5,7 +5,7 @@ import styles from './Button.module.css'
|
|||||||
|
|
||||||
const cx = classNames.bind(styles)
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
interface ButtonProps {
|
export interface ButtonProps {
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
href?: string
|
href?: string
|
||||||
|
12
src/components/atoms/Input/Disclaimer.module.css
Normal file
12
src/components/atoms/Input/Disclaimer.module.css
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.disclaimer {
|
||||||
|
margin-top: calc(var(--spacer) / 3);
|
||||||
|
transition: all 0.3s ease-in;
|
||||||
|
max-height: 100px;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disclaimer.hidden {
|
||||||
|
max-height: 0;
|
||||||
|
transition: all 0.2s ease-out;
|
||||||
|
}
|
30
src/components/atoms/Input/Disclaimer.tsx
Normal file
30
src/components/atoms/Input/Disclaimer.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import styles from './Disclaimer.module.css'
|
||||||
|
import classNames from 'classnames/bind'
|
||||||
|
import Alert from '../Alert'
|
||||||
|
|
||||||
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
|
const FormDisclaimer = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
visible
|
||||||
|
}: {
|
||||||
|
children: string
|
||||||
|
className?: string
|
||||||
|
visible?: boolean
|
||||||
|
}): ReactElement => {
|
||||||
|
const styleClasses = cx({
|
||||||
|
disclaimer: true,
|
||||||
|
hidden: !visible,
|
||||||
|
[className]: className
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styleClasses}>
|
||||||
|
<Alert text={children} state="info" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FormDisclaimer
|
@ -47,6 +47,8 @@ export default function InputElement({
|
|||||||
help,
|
help,
|
||||||
form,
|
form,
|
||||||
additionalComponent,
|
additionalComponent,
|
||||||
|
disclaimer,
|
||||||
|
disclaimerValues,
|
||||||
...props
|
...props
|
||||||
}: InputProps): ReactElement {
|
}: InputProps): ReactElement {
|
||||||
const styleClasses = cx({ select: true, [size]: size })
|
const styleClasses = cx({ select: true, [size]: size })
|
||||||
@ -99,7 +101,10 @@ export default function InputElement({
|
|||||||
defaultChecked={props.defaultChecked}
|
defaultChecked={props.defaultChecked}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
<label className={styles.radioLabel} htmlFor={slugify(option)}>
|
<label
|
||||||
|
className={cx({ [styles.radioLabel]: true, [size]: size })}
|
||||||
|
htmlFor={slugify(option)}
|
||||||
|
>
|
||||||
{option}
|
{option}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
import React, { FormEvent, ChangeEvent, ReactElement, ReactNode } from 'react'
|
import React, {
|
||||||
|
FormEvent,
|
||||||
|
ChangeEvent,
|
||||||
|
ReactElement,
|
||||||
|
ReactNode,
|
||||||
|
useEffect,
|
||||||
|
useState
|
||||||
|
} from 'react'
|
||||||
import InputElement from './InputElement'
|
import InputElement from './InputElement'
|
||||||
import Help from './Help'
|
import Help from './Help'
|
||||||
import Label from './Label'
|
import Label from './Label'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { ErrorMessage, FieldInputProps } from 'formik'
|
import { ErrorMessage, FieldInputProps } from 'formik'
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
|
import Disclaimer from './Disclaimer'
|
||||||
|
|
||||||
const cx = classNames.bind(styles)
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
@ -49,10 +57,21 @@ export interface InputProps {
|
|||||||
defaultChecked?: boolean
|
defaultChecked?: boolean
|
||||||
size?: 'mini' | 'small' | 'large' | 'default'
|
size?: 'mini' | 'small' | 'large' | 'default'
|
||||||
className?: string
|
className?: string
|
||||||
|
checked?: boolean
|
||||||
|
disclaimer?: string
|
||||||
|
disclaimerValues?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Input(props: Partial<InputProps>): ReactElement {
|
export default function Input(props: Partial<InputProps>): ReactElement {
|
||||||
const { label, help, additionalComponent, size, field } = props
|
const {
|
||||||
|
label,
|
||||||
|
help,
|
||||||
|
additionalComponent,
|
||||||
|
size,
|
||||||
|
field,
|
||||||
|
disclaimer,
|
||||||
|
disclaimerValues
|
||||||
|
} = props
|
||||||
|
|
||||||
const hasError =
|
const hasError =
|
||||||
props.form?.touched[field.name] && props.form?.errors[field.name]
|
props.form?.touched[field.name] && props.form?.errors[field.name]
|
||||||
@ -62,6 +81,16 @@ export default function Input(props: Partial<InputProps>): ReactElement {
|
|||||||
hasError: hasError
|
hasError: hasError
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [disclaimerVisible, setDisclaimerVisible] = useState(true)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (disclaimer && disclaimerValues) {
|
||||||
|
setDisclaimerVisible(
|
||||||
|
disclaimerValues.includes(props.form?.values[field.name])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}, [props.form?.values[field.name]])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styleClasses}
|
className={styleClasses}
|
||||||
@ -79,6 +108,10 @@ export default function Input(props: Partial<InputProps>): ReactElement {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{help && <Help>{help}</Help>}
|
{help && <Help>{help}</Help>}
|
||||||
|
|
||||||
|
{disclaimer && (
|
||||||
|
<Disclaimer visible={disclaimerVisible}>{disclaimer}</Disclaimer>
|
||||||
|
)}
|
||||||
{additionalComponent && additionalComponent}
|
{additionalComponent && additionalComponent}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
14
src/components/atoms/PrivacyLanguages.module.css
Normal file
14
src/components/atoms/PrivacyLanguages.module.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.langSelect {
|
||||||
|
background: var(--background-body);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
padding: calc(var(--spacer) / 2);
|
||||||
|
margin: var(--spacer) auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.langLabel {
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
color: var(--font-color-heading);
|
||||||
|
font-weight: var(--font-weight-bold);
|
||||||
|
}
|
38
src/components/atoms/PrivacyLanguages.tsx
Normal file
38
src/components/atoms/PrivacyLanguages.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import styles from './PrivacyLanguages.module.css'
|
||||||
|
import { usePrivacyMetadata } from '../../hooks/usePrivacyMetadata'
|
||||||
|
import { useUserPreferences } from '../../providers/UserPreferences'
|
||||||
|
import { Link } from '@reach/router'
|
||||||
|
|
||||||
|
export default function PrivacyLanguages({
|
||||||
|
label
|
||||||
|
}: {
|
||||||
|
label?: string
|
||||||
|
}): ReactElement {
|
||||||
|
const { policies } = usePrivacyMetadata()
|
||||||
|
const { setPrivacyPolicySlug } = useUserPreferences()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.langSelect}>
|
||||||
|
<span className={styles.langLabel}>{label || 'Language'}</span>
|
||||||
|
<div className={styles.langOptions}>
|
||||||
|
{policies.map((policy, i) => {
|
||||||
|
const slug = `/privacy/${policy.policy}`
|
||||||
|
return (
|
||||||
|
<React.Fragment key={policy.policy}>
|
||||||
|
{i > 0 && ' — '}
|
||||||
|
<Link
|
||||||
|
to={slug}
|
||||||
|
onClick={() => {
|
||||||
|
setPrivacyPolicySlug(slug)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{policy.language}
|
||||||
|
</Link>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -5,11 +5,13 @@ export default function Time({
|
|||||||
date,
|
date,
|
||||||
relative,
|
relative,
|
||||||
isUnix,
|
isUnix,
|
||||||
|
displayFormat,
|
||||||
className
|
className
|
||||||
}: {
|
}: {
|
||||||
date: string
|
date: string
|
||||||
relative?: boolean
|
relative?: boolean
|
||||||
isUnix?: boolean
|
isUnix?: boolean
|
||||||
|
displayFormat?: string
|
||||||
className?: string
|
className?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const [dateIso, setDateIso] = useState<string>()
|
const [dateIso, setDateIso] = useState<string>()
|
||||||
@ -27,13 +29,13 @@ export default function Time({
|
|||||||
<></>
|
<></>
|
||||||
) : (
|
) : (
|
||||||
<time
|
<time
|
||||||
title={format(dateNew, 'PPppp')}
|
title={format(dateNew, displayFormat || 'PPppp')}
|
||||||
dateTime={dateIso}
|
dateTime={dateIso}
|
||||||
className={className || undefined}
|
className={className || undefined}
|
||||||
>
|
>
|
||||||
{relative
|
{relative
|
||||||
? formatDistance(dateNew, Date.now(), { addSuffix: true })
|
? formatDistance(dateNew, Date.now(), { addSuffix: true })
|
||||||
: format(dateNew, 'PP')}
|
: format(dateNew, displayFormat || 'PP')}
|
||||||
</time>
|
</time>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
27
src/components/molecules/CookieModule.module.css
Normal file
27
src/components/molecules/CookieModule.module.css
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
.description {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: calc(var(--spacer) / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header div[class*='radioGroup'] {
|
||||||
|
width: 100%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header label {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
display: block;
|
||||||
|
margin: var(--spacer) 0;
|
||||||
|
}
|
44
src/components/molecules/CookieModule.tsx
Normal file
44
src/components/molecules/CookieModule.tsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import React, { ChangeEvent, ReactElement, useEffect, useState } from 'react'
|
||||||
|
import { CookieConsentStatus, useConsent } from '../../providers/CookieConsent'
|
||||||
|
import InputElement from '../atoms/Input/InputElement'
|
||||||
|
import Markdown from '../atoms/Markdown'
|
||||||
|
import styles from './CookieModule.module.css'
|
||||||
|
|
||||||
|
export interface CookieModuleProps {
|
||||||
|
title: string
|
||||||
|
desc: string
|
||||||
|
cookieName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CookieModule(props: CookieModuleProps): ReactElement {
|
||||||
|
const { cookieConsentStatus, setConsentStatus } = useConsent()
|
||||||
|
const { title, desc, cookieName } = props
|
||||||
|
const [checked, setChecked] = useState<boolean>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setConsentStatus(
|
||||||
|
cookieName,
|
||||||
|
checked ? CookieConsentStatus.APPROVED : CookieConsentStatus.REJECTED
|
||||||
|
)
|
||||||
|
}, [checked])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.wrapper}>
|
||||||
|
<div className={styles.header}>
|
||||||
|
<InputElement
|
||||||
|
type="checkbox"
|
||||||
|
name={cookieName}
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setChecked(e.target.checked)
|
||||||
|
}}
|
||||||
|
checked={
|
||||||
|
cookieConsentStatus[cookieName] === CookieConsentStatus.APPROVED
|
||||||
|
}
|
||||||
|
options={[title]}
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Markdown text={desc} className={styles.description} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
34
src/components/molecules/PrivacyHeader.tsx
Normal file
34
src/components/molecules/PrivacyHeader.tsx
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import Time from '../atoms/Time'
|
||||||
|
import styles from '../templates/PageMarkdown.module.css'
|
||||||
|
import { usePrivacyMetadata } from '../../hooks/usePrivacyMetadata'
|
||||||
|
import PrivacyLanguages from '../atoms/PrivacyLanguages'
|
||||||
|
|
||||||
|
export default function PrivacyPolicyHeader({
|
||||||
|
tableOfContents,
|
||||||
|
policy
|
||||||
|
}: {
|
||||||
|
tableOfContents: string
|
||||||
|
policy: string
|
||||||
|
}): ReactElement {
|
||||||
|
const { policies } = usePrivacyMetadata()
|
||||||
|
const policyMetadata = policies.find((p) => p.policy === policy)
|
||||||
|
const { date, params } = policyMetadata
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<PrivacyLanguages label={params.languageLabel} />
|
||||||
|
<p>
|
||||||
|
{params?.updated || 'Last updated on'}{' '}
|
||||||
|
<Time date={date} displayFormat={params?.dateFormat || 'MM-dd-yyyy'} />
|
||||||
|
</p>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<h1>{params?.tocHeader || 'Table of Contents'}</h1>
|
||||||
|
<div
|
||||||
|
className={styles.tocList}
|
||||||
|
dangerouslySetInnerHTML={{ __html: tableOfContents }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,9 +1,3 @@
|
|||||||
.footer {
|
|
||||||
color: var(--brand-grey-light);
|
|
||||||
font-size: var(--font-size-small);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: var(--spacer) calc(var(--spacer) / 2);
|
padding: var(--spacer) calc(var(--spacer) / 2);
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@ -11,19 +5,34 @@
|
|||||||
max-width: var(--layout-max-width);
|
max-width: var(--layout-max-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content p {
|
.content a,
|
||||||
display: inline;
|
.content button {
|
||||||
}
|
|
||||||
|
|
||||||
.content a {
|
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content button {
|
||||||
|
text-transform: none;
|
||||||
|
transform: none !important;
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
}
|
||||||
|
|
||||||
.content a:hover,
|
.content a:hover,
|
||||||
.content a:focus {
|
.content a:focus,
|
||||||
|
.content button:hover,
|
||||||
|
.content button:focus {
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content p {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
.copyright div {
|
.copyright div {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
color: var(--brand-grey-light);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
@ -5,10 +5,17 @@ import { useSiteMetadata } from '../../hooks/useSiteMetadata'
|
|||||||
import { Link } from 'gatsby'
|
import { Link } from 'gatsby'
|
||||||
import MarketStats from '../molecules/MarketStats'
|
import MarketStats from '../molecules/MarketStats'
|
||||||
import BuildId from '../atoms/BuildId'
|
import BuildId from '../atoms/BuildId'
|
||||||
import SyncStatus from '../molecules/SyncStatus'
|
import { useUserPreferences } from '../../providers/UserPreferences'
|
||||||
|
import Button from '../atoms/Button'
|
||||||
|
import { useGdprMetadata } from '../../hooks/useGdprMetadata'
|
||||||
|
|
||||||
export default function Footer(): ReactElement {
|
export default function Footer(): ReactElement {
|
||||||
const { copyright } = useSiteMetadata()
|
const { copyright, appConfig } = useSiteMetadata()
|
||||||
|
const { setShowPPC } = useUserPreferences()
|
||||||
|
const { privacyPolicySlug } = useUserPreferences()
|
||||||
|
|
||||||
|
const cookies = useGdprMetadata()
|
||||||
|
|
||||||
const year = new Date().getFullYear()
|
const year = new Date().getFullYear()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -18,10 +25,28 @@ export default function Footer(): ReactElement {
|
|||||||
<BuildId />
|
<BuildId />
|
||||||
<MarketStats />
|
<MarketStats />
|
||||||
<div className={styles.copyright}>
|
<div className={styles.copyright}>
|
||||||
© {year} <Markdown text={copyright} /> —{' '}
|
© {year} <Markdown text={copyright} />
|
||||||
|
<br />
|
||||||
|
<Link to="/imprint">Imprint</Link>
|
||||||
|
{' — '}
|
||||||
<Link to="/terms">Terms</Link>
|
<Link to="/terms">Terms</Link>
|
||||||
{' — '}
|
{' — '}
|
||||||
<a href="https://oceanprotocol.com/privacy">Privacy</a>
|
<Link to={privacyPolicySlug}>Privacy</Link>
|
||||||
|
{appConfig.privacyPreferenceCenter === 'true' && (
|
||||||
|
<>
|
||||||
|
{' — '}
|
||||||
|
<Button
|
||||||
|
style="text"
|
||||||
|
size="small"
|
||||||
|
className="link"
|
||||||
|
onClick={() => {
|
||||||
|
setShowPPC(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cookies.optionalCookies ? 'Cookie Settings' : 'Cookies'}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
122
src/components/organisms/PrivacyPreferenceCenter.module.css
Normal file
122
src/components/organisms/PrivacyPreferenceCenter.module.css
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
.banner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--background-body-transparent);
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
padding: calc(var(--spacer) / 2);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--spacer) 0;
|
||||||
|
border-bottom: 1px solid var(--brand-grey-lighter);
|
||||||
|
}
|
||||||
|
|
||||||
|
.configureButton {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.closeButton {
|
||||||
|
margin-top: var(--spacer);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
font-size: var(--font-size-large);
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: calc(var(--spacer) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
max-width: 90vw;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 10;
|
||||||
|
overflow-y: auto;
|
||||||
|
box-shadow: 6px 0 17px var(--box-shadow-color);
|
||||||
|
opacity: 1;
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small Cookie Banner Styles */
|
||||||
|
|
||||||
|
.wrapper.small {
|
||||||
|
bottom: var(--spacer);
|
||||||
|
left: var(--spacer);
|
||||||
|
top: auto;
|
||||||
|
width: calc(100vw - (var(--spacer) * 2));
|
||||||
|
max-width: 42rem;
|
||||||
|
overflow: hidden;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .banner {
|
||||||
|
display: block;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .header {
|
||||||
|
font-size: var(--font-size-normal);
|
||||||
|
margin-bottom: calc(var(--spacer) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.small p {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .buttons {
|
||||||
|
flex-direction: column;
|
||||||
|
border: none;
|
||||||
|
padding: calc(var(--spacer) / 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .buttons button {
|
||||||
|
margin: calc(var(--spacer) / 6);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .configureButton {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .optionals {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small .closeButton {
|
||||||
|
margin: calc(var(--spacer) / 4) auto 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide and show the Cookie Banner */
|
||||||
|
|
||||||
|
.wrapper.hidden {
|
||||||
|
left: -25rem;
|
||||||
|
opacity: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust for larger screen sizes */
|
||||||
|
|
||||||
|
@media screen and (min-width: 26rem) {
|
||||||
|
.wrapper {
|
||||||
|
max-width: 25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 38rem) {
|
||||||
|
.small .container {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
104
src/components/organisms/PrivacyPreferenceCenter.tsx
Normal file
104
src/components/organisms/PrivacyPreferenceCenter.tsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import React, { ReactElement, useState } from 'react'
|
||||||
|
import { useConsent, CookieConsentStatus } from '../../providers/CookieConsent'
|
||||||
|
import styles from './PrivacyPreferenceCenter.module.css'
|
||||||
|
import { useGdprMetadata } from '../../hooks/useGdprMetadata'
|
||||||
|
import Markdown from '../atoms/Markdown'
|
||||||
|
import CookieModule from '../molecules/CookieModule'
|
||||||
|
import Button from '../atoms/Button'
|
||||||
|
import { useUserPreferences } from '../../providers/UserPreferences'
|
||||||
|
import classNames from 'classnames/bind'
|
||||||
|
|
||||||
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
|
export default function CookieBanner({
|
||||||
|
style
|
||||||
|
}: {
|
||||||
|
style?: 'small' | 'default'
|
||||||
|
}): ReactElement {
|
||||||
|
const { resetConsentStatus } = useConsent()
|
||||||
|
const cookies = useGdprMetadata()
|
||||||
|
const { showPPC, setShowPPC } = useUserPreferences()
|
||||||
|
const [smallBanner, setSmallBanner] = useState<boolean>(style === 'small')
|
||||||
|
|
||||||
|
function closeBanner() {
|
||||||
|
setShowPPC(false)
|
||||||
|
|
||||||
|
// Wait for CSS animations to finish
|
||||||
|
setTimeout(() => {
|
||||||
|
setSmallBanner(style === 'small')
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAllCookies(accepted: boolean) {
|
||||||
|
resetConsentStatus(
|
||||||
|
accepted ? CookieConsentStatus.APPROVED : CookieConsentStatus.REJECTED
|
||||||
|
)
|
||||||
|
closeBanner()
|
||||||
|
}
|
||||||
|
|
||||||
|
const styleClasses = cx(styles.wrapper, {
|
||||||
|
hidden: !showPPC,
|
||||||
|
small: smallBanner // style === 'small'
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styleClasses}>
|
||||||
|
<div className={styles.banner}>
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.cookieInfo}>
|
||||||
|
<Markdown text={cookies.title} className={styles.header} />
|
||||||
|
<Markdown text={cookies.text} />
|
||||||
|
</div>
|
||||||
|
{cookies.optionalCookies && (
|
||||||
|
<>
|
||||||
|
<div className={styles.buttons}>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
handleAllCookies(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cookies.accept || 'Accept all'}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
handleAllCookies(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cookies.reject || 'Reject all'}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className={styles.configureButton}
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
setSmallBanner(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cookies.configure || 'Customize'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className={styles.optionals}>
|
||||||
|
{cookies.optionalCookies.map((cookie) => {
|
||||||
|
return <CookieModule {...cookie} key={cookie.cookieName} />
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{(!smallBanner || !cookies.optionalCookies) && (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
style="primary"
|
||||||
|
onClick={() => {
|
||||||
|
closeBanner()
|
||||||
|
}}
|
||||||
|
className={styles.closeButton}
|
||||||
|
>
|
||||||
|
{cookies.close || 'Save and close'}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
27
src/components/pages/Profile/index.module.css
Normal file
27
src/components/pages/Profile/index.module.css
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
.printButton {
|
||||||
|
display: block;
|
||||||
|
margin: calc(var(--spacer) / 2) auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
body * {
|
||||||
|
visibility: hidden;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.profile,
|
||||||
|
.profile *:not(.printButton) {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
.profile {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.profile div[class*='tabs'] li[class*='selected'] {
|
||||||
|
border: 2px solid var(--border-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@page {
|
||||||
|
size: landscape;
|
||||||
|
margin: 10mm;
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import HistoryPage from './History'
|
import HistoryPage from './History'
|
||||||
import AccountHeader from './Header'
|
import AccountHeader from './Header'
|
||||||
|
import Button from '../../atoms/Button'
|
||||||
|
import styles from './index.module.css'
|
||||||
|
|
||||||
export default function AccountPage({
|
export default function AccountPage({
|
||||||
accountId
|
accountId
|
||||||
@ -8,9 +10,19 @@ export default function AccountPage({
|
|||||||
accountId: string
|
accountId: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={styles.profile}>
|
||||||
<AccountHeader accountId={accountId} />
|
<AccountHeader accountId={accountId} />
|
||||||
<HistoryPage accountIdentifier={accountId} />
|
<HistoryPage accountIdentifier={accountId} />
|
||||||
</>
|
|
||||||
|
<Button
|
||||||
|
className={styles.printButton}
|
||||||
|
onClick={() => {
|
||||||
|
window.print()
|
||||||
|
}}
|
||||||
|
style="primary"
|
||||||
|
>
|
||||||
|
Print
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@ const query = graphql`
|
|||||||
required
|
required
|
||||||
sortOptions
|
sortOptions
|
||||||
options
|
options
|
||||||
|
disclaimer
|
||||||
|
disclaimerValues
|
||||||
advanced
|
advanced
|
||||||
}
|
}
|
||||||
warning
|
warning
|
||||||
|
@ -36,6 +36,8 @@ const query = graphql`
|
|||||||
required
|
required
|
||||||
sortOptions
|
sortOptions
|
||||||
options
|
options
|
||||||
|
disclaimer
|
||||||
|
disclaimerValues
|
||||||
advanced
|
advanced
|
||||||
}
|
}
|
||||||
warning
|
warning
|
||||||
|
@ -3,14 +3,25 @@ import { graphql, PageProps } from 'gatsby'
|
|||||||
import Page from './Page'
|
import Page from './Page'
|
||||||
import styles from './PageMarkdown.module.css'
|
import styles from './PageMarkdown.module.css'
|
||||||
import Container from '../atoms/Container'
|
import Container from '../atoms/Container'
|
||||||
|
import PrivacyPolicyHeader from '../molecules/PrivacyHeader'
|
||||||
|
|
||||||
export default function PageTemplateMarkdown(props: PageProps): ReactElement {
|
export default function PageTemplateMarkdown(props: PageProps): ReactElement {
|
||||||
const { html, frontmatter } = (props.data as any).markdownRemark
|
const { html, frontmatter, tableOfContents, fields } = (props.data as any)
|
||||||
|
.markdownRemark
|
||||||
const { title, description } = frontmatter
|
const { title, description } = frontmatter
|
||||||
|
const { slug } = fields
|
||||||
|
|
||||||
|
const isPrivacy = slug.includes('/privacy/')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page title={title} description={description} uri={props.uri} headerCenter>
|
<Page title={title} description={description} uri={props.uri} headerCenter>
|
||||||
<Container narrow>
|
<Container narrow>
|
||||||
|
{isPrivacy && (
|
||||||
|
<PrivacyPolicyHeader
|
||||||
|
tableOfContents={tableOfContents}
|
||||||
|
policy={slug.replace('/privacy/', '')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className={styles.content}
|
className={styles.content}
|
||||||
dangerouslySetInnerHTML={{ __html: html }}
|
dangerouslySetInnerHTML={{ __html: html }}
|
||||||
@ -24,6 +35,7 @@ export const pageQuery = graphql`
|
|||||||
query PageMarkdownBySlug($slug: String!) {
|
query PageMarkdownBySlug($slug: String!) {
|
||||||
markdownRemark(fields: { slug: { eq: $slug } }) {
|
markdownRemark(fields: { slug: { eq: $slug } }) {
|
||||||
html
|
html
|
||||||
|
tableOfContents(absolute: false)
|
||||||
frontmatter {
|
frontmatter {
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
@ -3,6 +3,7 @@ import Web3Provider from '../providers/Web3'
|
|||||||
import { UserPreferencesProvider } from '../providers/UserPreferences'
|
import { UserPreferencesProvider } from '../providers/UserPreferences'
|
||||||
import PricesProvider from '../providers/Prices'
|
import PricesProvider from '../providers/Prices'
|
||||||
import UrqlProvider from '../providers/UrqlProvider'
|
import UrqlProvider from '../providers/UrqlProvider'
|
||||||
|
import ConsentProvider from '../providers/CookieConsent'
|
||||||
|
|
||||||
export default function wrapRootElement({
|
export default function wrapRootElement({
|
||||||
element
|
element
|
||||||
@ -13,7 +14,9 @@ export default function wrapRootElement({
|
|||||||
<Web3Provider>
|
<Web3Provider>
|
||||||
<UrqlProvider>
|
<UrqlProvider>
|
||||||
<UserPreferencesProvider>
|
<UserPreferencesProvider>
|
||||||
<PricesProvider>{element}</PricesProvider>
|
<PricesProvider>
|
||||||
|
<ConsentProvider>{element}</ConsentProvider>
|
||||||
|
</PricesProvider>
|
||||||
</UserPreferencesProvider>
|
</UserPreferencesProvider>
|
||||||
</UrqlProvider>
|
</UrqlProvider>
|
||||||
</Web3Provider>
|
</Web3Provider>
|
||||||
|
46
src/hooks/useGdprMetadata.ts
Normal file
46
src/hooks/useGdprMetadata.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { useStaticQuery, graphql } from 'gatsby'
|
||||||
|
|
||||||
|
export interface UseGdprMetadata {
|
||||||
|
title: string
|
||||||
|
text: string
|
||||||
|
accept: string
|
||||||
|
reject: string
|
||||||
|
close: string
|
||||||
|
configure: string
|
||||||
|
placeholder: string
|
||||||
|
optionalCookies?: {
|
||||||
|
title: string
|
||||||
|
desc: string
|
||||||
|
cookieName: string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = graphql`
|
||||||
|
query GdprQuery {
|
||||||
|
gdpr: allFile(filter: { relativePath: { eq: "gdpr.json" } }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
childContentJson {
|
||||||
|
title
|
||||||
|
text
|
||||||
|
accept
|
||||||
|
reject
|
||||||
|
close
|
||||||
|
configure
|
||||||
|
optionalCookies {
|
||||||
|
title
|
||||||
|
desc
|
||||||
|
cookieName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export function useGdprMetadata(): UseGdprMetadata {
|
||||||
|
const data = useStaticQuery(query)
|
||||||
|
|
||||||
|
return { ...data.gdpr.edges[0].node.childContentJson }
|
||||||
|
}
|
39
src/hooks/usePrivacyMetadata.ts
Normal file
39
src/hooks/usePrivacyMetadata.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { useStaticQuery, graphql } from 'gatsby'
|
||||||
|
|
||||||
|
export interface UsePrivacyMetadata {
|
||||||
|
policies: {
|
||||||
|
policy: string
|
||||||
|
language: string
|
||||||
|
date: string
|
||||||
|
params: {
|
||||||
|
languageLabel: string
|
||||||
|
tocHeader: string
|
||||||
|
updated: string
|
||||||
|
dateFormat: string
|
||||||
|
}
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const query = graphql`
|
||||||
|
{
|
||||||
|
privacyJson {
|
||||||
|
policies {
|
||||||
|
policy
|
||||||
|
date
|
||||||
|
language
|
||||||
|
params {
|
||||||
|
updated
|
||||||
|
dateFormat
|
||||||
|
tocHeader
|
||||||
|
languageLabel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export function usePrivacyMetadata(): UsePrivacyMetadata {
|
||||||
|
const data = useStaticQuery(query)
|
||||||
|
|
||||||
|
return { ...data.privacyJson }
|
||||||
|
}
|
@ -32,6 +32,8 @@ interface UseSiteMetadata {
|
|||||||
allowFreePricing: string
|
allowFreePricing: string
|
||||||
allowAdvancedSettings: string
|
allowAdvancedSettings: string
|
||||||
credentialType: string
|
credentialType: string
|
||||||
|
defaultPrivacyPolicySlug: string
|
||||||
|
privacyPreferenceCenter: string
|
||||||
allowAdvancedPublishSettings: string
|
allowAdvancedPublishSettings: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,6 +73,8 @@ const query = graphql`
|
|||||||
allowAdvancedSettings
|
allowAdvancedSettings
|
||||||
allowAdvancedPublishSettings
|
allowAdvancedPublishSettings
|
||||||
credentialType
|
credentialType
|
||||||
|
defaultPrivacyPolicySlug
|
||||||
|
privacyPreferenceCenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
138
src/providers/CookieConsent.tsx
Normal file
138
src/providers/CookieConsent.tsx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import React, {
|
||||||
|
useContext,
|
||||||
|
useState,
|
||||||
|
createContext,
|
||||||
|
useEffect,
|
||||||
|
ReactNode,
|
||||||
|
ReactElement
|
||||||
|
} from 'react'
|
||||||
|
import { deleteCookie, getCookieValue, setCookie } from '../utils/cookies'
|
||||||
|
import { UseGdprMetadata, useGdprMetadata } from '../hooks/useGdprMetadata'
|
||||||
|
import { useSiteMetadata } from '../hooks/useSiteMetadata'
|
||||||
|
|
||||||
|
export enum CookieConsentStatus {
|
||||||
|
NOT_AVAILABLE = -1,
|
||||||
|
APPROVED = 0,
|
||||||
|
REJECTED = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConsentStatus {
|
||||||
|
[name: string]: CookieConsentStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConsentProviderValue {
|
||||||
|
cookies: UseGdprMetadata['optionalCookies']
|
||||||
|
cookieConsentStatus: ConsentStatus
|
||||||
|
setConsentStatus: (cookieName: string, status: CookieConsentStatus) => void
|
||||||
|
resetConsentStatus: (status?: CookieConsentStatus) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const ConsentContext = createContext({} as ConsentProviderValue)
|
||||||
|
|
||||||
|
function ConsentProvider({ children }: { children: ReactNode }): ReactElement {
|
||||||
|
const cookies = useGdprMetadata()
|
||||||
|
|
||||||
|
const { privacyPreferenceCenter } = useSiteMetadata().appConfig
|
||||||
|
|
||||||
|
const [consentStatus, setConsentStatus] = useState({} as ConsentStatus)
|
||||||
|
|
||||||
|
function resetConsentStatus(status = CookieConsentStatus.NOT_AVAILABLE) {
|
||||||
|
const resetCookieConsent = {} as ConsentStatus
|
||||||
|
cookies.optionalCookies?.map((cookie) => {
|
||||||
|
deleteCookie(cookie.cookieName)
|
||||||
|
resetCookieConsent[cookie.cookieName] = status
|
||||||
|
})
|
||||||
|
setConsentStatus(resetCookieConsent)
|
||||||
|
}
|
||||||
|
|
||||||
|
function setCookieConsentStatus(
|
||||||
|
cookieName: string,
|
||||||
|
status: CookieConsentStatus
|
||||||
|
) {
|
||||||
|
setConsentStatus({ ...consentStatus, [cookieName]: status })
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAccept(cookieName: string) {
|
||||||
|
setCookie(cookieName, true)
|
||||||
|
switch (cookieName) {
|
||||||
|
case 'AnalyticsCookieConsent':
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
// Add your specific logic here
|
||||||
|
// e.g.
|
||||||
|
/* function handleAnalytics() {
|
||||||
|
ReactGA.initialize(analyticsId)
|
||||||
|
ReactGA.pageview(window.location.pathname + window.location.search)
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReject(cookieName: string) {
|
||||||
|
setCookie(cookieName, false)
|
||||||
|
switch (cookieName) {
|
||||||
|
case 'AnalyticsCookieConsent':
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
// Add your specific logic here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (privacyPreferenceCenter !== 'true') return
|
||||||
|
|
||||||
|
const initialValues = {} as ConsentStatus
|
||||||
|
cookies.optionalCookies?.map((cookie) => {
|
||||||
|
const cookieValue = getCookieValue(cookie.cookieName)
|
||||||
|
|
||||||
|
switch (cookieValue) {
|
||||||
|
case 'true':
|
||||||
|
initialValues[cookie.cookieName] = CookieConsentStatus.APPROVED
|
||||||
|
break
|
||||||
|
case 'false':
|
||||||
|
initialValues[cookie.cookieName] = CookieConsentStatus.REJECTED
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
initialValues[cookie.cookieName] = CookieConsentStatus.NOT_AVAILABLE
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setConsentStatus(initialValues)
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Object.keys(consentStatus).map((cookieName) => {
|
||||||
|
switch (consentStatus[cookieName]) {
|
||||||
|
case CookieConsentStatus.APPROVED:
|
||||||
|
handleAccept(cookieName)
|
||||||
|
break
|
||||||
|
case CookieConsentStatus.REJECTED:
|
||||||
|
handleReject(cookieName)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [consentStatus])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConsentContext.Provider
|
||||||
|
value={
|
||||||
|
{
|
||||||
|
cookies: cookies.optionalCookies || [],
|
||||||
|
cookieConsentStatus: consentStatus,
|
||||||
|
setConsentStatus: setCookieConsentStatus,
|
||||||
|
resetConsentStatus
|
||||||
|
} as ConsentProviderValue
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ConsentContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const useConsent = (): ConsentProviderValue => useContext(ConsentContext)
|
||||||
|
|
||||||
|
export { ConsentProvider, useConsent, ConsentProviderValue, ConsentContext }
|
||||||
|
export default ConsentProvider
|
@ -16,10 +16,14 @@ interface UserPreferencesValue {
|
|||||||
currency: string
|
currency: string
|
||||||
setCurrency: (value: string) => void
|
setCurrency: (value: string) => void
|
||||||
chainIds: number[]
|
chainIds: number[]
|
||||||
|
privacyPolicySlug: string
|
||||||
|
showPPC: boolean
|
||||||
setChainIds: (chainIds: number[]) => void
|
setChainIds: (chainIds: number[]) => void
|
||||||
bookmarks: string[]
|
bookmarks: string[]
|
||||||
addBookmark: (did: string) => void
|
addBookmark: (did: string) => void
|
||||||
removeBookmark: (did: string) => void
|
removeBookmark: (did: string) => void
|
||||||
|
setPrivacyPolicySlug: (slug: string) => void
|
||||||
|
setShowPPC: (value: boolean) => void
|
||||||
infiniteApproval: boolean
|
infiniteApproval: boolean
|
||||||
setInfiniteApproval: (value: boolean) => void
|
setInfiniteApproval: (value: boolean) => void
|
||||||
locale: string
|
locale: string
|
||||||
@ -60,14 +64,40 @@ function UserPreferencesProvider({
|
|||||||
const [chainIds, setChainIds] = useState(
|
const [chainIds, setChainIds] = useState(
|
||||||
localStorage?.chainIds || appConfig.chainIds
|
localStorage?.chainIds || appConfig.chainIds
|
||||||
)
|
)
|
||||||
|
const { defaultPrivacyPolicySlug } = useSiteMetadata().appConfig
|
||||||
|
|
||||||
|
const [privacyPolicySlug, setPrivacyPolicySlug] = useState<string>(
|
||||||
|
localStorage?.privacyPolicySlug || defaultPrivacyPolicySlug
|
||||||
|
)
|
||||||
|
|
||||||
|
const [showPPC, setShowPPC] = useState<boolean>(
|
||||||
|
localStorage?.showPPC !== false
|
||||||
|
)
|
||||||
|
|
||||||
const [infiniteApproval, setInfiniteApproval] = useState(
|
const [infiniteApproval, setInfiniteApproval] = useState(
|
||||||
localStorage?.infiniteApproval || false
|
localStorage?.infiniteApproval || false
|
||||||
)
|
)
|
||||||
|
|
||||||
// Write values to localStorage on change
|
// Write values to localStorage on change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLocalStorage({ chainIds, debug, currency, bookmarks, infiniteApproval })
|
setLocalStorage({
|
||||||
}, [chainIds, debug, currency, bookmarks, infiniteApproval])
|
chainIds,
|
||||||
|
debug,
|
||||||
|
currency,
|
||||||
|
bookmarks,
|
||||||
|
privacyPolicySlug,
|
||||||
|
showPPC,
|
||||||
|
infiniteApproval
|
||||||
|
})
|
||||||
|
}, [
|
||||||
|
chainIds,
|
||||||
|
debug,
|
||||||
|
currency,
|
||||||
|
bookmarks,
|
||||||
|
privacyPolicySlug,
|
||||||
|
showPPC,
|
||||||
|
infiniteApproval
|
||||||
|
])
|
||||||
|
|
||||||
// Set ocean.js log levels, default: Error
|
// Set ocean.js log levels, default: Error
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -113,13 +143,17 @@ function UserPreferencesProvider({
|
|||||||
locale,
|
locale,
|
||||||
chainIds,
|
chainIds,
|
||||||
bookmarks,
|
bookmarks,
|
||||||
|
privacyPolicySlug,
|
||||||
|
showPPC,
|
||||||
infiniteApproval,
|
infiniteApproval,
|
||||||
setInfiniteApproval,
|
setInfiniteApproval,
|
||||||
setChainIds,
|
setChainIds,
|
||||||
setDebug,
|
setDebug,
|
||||||
setCurrency,
|
setCurrency,
|
||||||
addBookmark,
|
addBookmark,
|
||||||
removeBookmark
|
removeBookmark,
|
||||||
|
setPrivacyPolicySlug,
|
||||||
|
setShowPPC
|
||||||
} as UserPreferencesValue
|
} as UserPreferencesValue
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
57
src/utils/cookies.ts
Normal file
57
src/utils/cookies.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
|
export enum SAME_SITE_OPTIONS {
|
||||||
|
STRICT = 'strict',
|
||||||
|
LAX = 'lax',
|
||||||
|
NONE = 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_COOKIE_OPTIONS = {
|
||||||
|
expires: 365,
|
||||||
|
sameSite: SAME_SITE_OPTIONS.STRICT
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLegacyCookieName(cookieName: string): string {
|
||||||
|
return `${cookieName}-legacy`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cookie legacy system adopted from react-cookie-consent
|
||||||
|
// SEE: https://github.com/Mastermindzh/react-cookie-consent
|
||||||
|
export function getCookieValue(cookieName: string): string {
|
||||||
|
let cookieValue = Cookies.get(cookieName)
|
||||||
|
|
||||||
|
// if the cookieValue is undefined check for the legacy cookie
|
||||||
|
if (cookieValue === undefined) {
|
||||||
|
cookieValue = Cookies.get(getLegacyCookieName(cookieName))
|
||||||
|
}
|
||||||
|
return cookieValue
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCookie(
|
||||||
|
cookieName: string,
|
||||||
|
cookieValue: string | boolean,
|
||||||
|
cookieOptions = DEFAULT_COOKIE_OPTIONS
|
||||||
|
): void {
|
||||||
|
const cookieSecurity = location ? location.protocol === 'https:' : true
|
||||||
|
|
||||||
|
const options = { ...cookieOptions, security: cookieSecurity }
|
||||||
|
|
||||||
|
// Fallback for older browsers where can not set SameSite=None
|
||||||
|
// SEE: https://web.dev/samesite-cookie-recipes/#handling-incompatible-clients
|
||||||
|
if (cookieOptions.sameSite === SAME_SITE_OPTIONS.NONE)
|
||||||
|
Cookies.set(getLegacyCookieName(cookieName), cookieValue.toString(), {
|
||||||
|
...options,
|
||||||
|
sameSite: null
|
||||||
|
})
|
||||||
|
|
||||||
|
// set the regular cookie
|
||||||
|
Cookies.set(cookieName, cookieValue.toString(), options)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteCookie(cookieName: string): void {
|
||||||
|
const cookiesWithLegacy = [cookieName, getLegacyCookieName(cookieName)]
|
||||||
|
|
||||||
|
cookiesWithLegacy.forEach((cookie) => {
|
||||||
|
Cookies.remove(cookie)
|
||||||
|
})
|
||||||
|
}
|
20
tests/unit/__fixtures__/gdprMetadata.json
Normal file
20
tests/unit/__fixtures__/gdprMetadata.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"gdpr": {
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"node": {
|
||||||
|
"childContentJson": {
|
||||||
|
"title": "Our use of cookies",
|
||||||
|
"text": "We use [cookies](/privacy/en) to optimize and continuously improve our website. These cookies are only used to enable essential features on our website and do not track you in any third-party related context.",
|
||||||
|
"accept": null,
|
||||||
|
"reject": null,
|
||||||
|
"close": "Acknowledge",
|
||||||
|
"configure": "Customize",
|
||||||
|
"placeholder": null,
|
||||||
|
"optionalCookies": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
17
tests/unit/__fixtures__/privacyMetadata.json
Normal file
17
tests/unit/__fixtures__/privacyMetadata.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"privacyJson": {
|
||||||
|
"policies": [
|
||||||
|
{
|
||||||
|
"policy": "en",
|
||||||
|
"date": "2021-07-31",
|
||||||
|
"language": "English",
|
||||||
|
"params": {
|
||||||
|
"updated": "Last updated on",
|
||||||
|
"dateFormat": "MM/dd/yyyy",
|
||||||
|
"tocHeader": "Table of contents",
|
||||||
|
"languageLabel": "Language"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,66 @@
|
|||||||
{
|
{
|
||||||
"siteMetadata": {
|
"site": {
|
||||||
|
"siteMetadata": {
|
||||||
|
"siteTitle": "Ocean Market",
|
||||||
|
"siteTagline": "A marketplace to find, publish and trade data sets in the Ocean Network.",
|
||||||
|
"siteUrl": "https://market.oceanprotocol.com",
|
||||||
|
"siteIcon": "node_modules/@oceanprotocol/art/logo/favicon-white.png",
|
||||||
|
"copyright": "All Rights Reserved. Powered by [Ocean Protocol](https://oceanprotocol.com)",
|
||||||
|
"menu": [
|
||||||
|
{
|
||||||
|
"name": "Publish",
|
||||||
|
"link": "/publish"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "History",
|
||||||
|
"link": "/history"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"warning": {
|
||||||
|
"main": "We are in beta. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).",
|
||||||
|
"polygonPublish": "Only republish data sets with a pool from ETH Mainnet into Polygon/Matic if the liquidity is **less than or equal to 1000 OCEAN in the original pool**. Doing otherwise will lead to [purgatory](https://github.com/oceanprotocol/list-purgatory) for the data set in Polygon/Matic."
|
||||||
|
},
|
||||||
|
"announcement": {
|
||||||
|
"main": "Ocean Market is [available on Polygon](https://blog.oceanprotocol.com/ocean-on-polygon-network-8abad19cbf47).",
|
||||||
|
"polygon": "Polygon/Matic EVM support is in early stages. [Use the Polygon Bridge](https://docs.oceanprotocol.com/tutorials/polygon-bridge/) to get mOCEAN."
|
||||||
|
},
|
||||||
|
"appConfig": {
|
||||||
|
"metadataCacheUri": "https://aquarius.oceanprotocol.com",
|
||||||
|
"infuraProjectId": "xxx",
|
||||||
|
"chainIds": [1, 137, 56],
|
||||||
|
"chainIdsSupported": [1, 3, 4, 137, 80001, 1287, 56],
|
||||||
|
"marketFeeAddress": "0x903322C7E45A60d7c8C3EA236c5beA9Af86310c7",
|
||||||
|
"currencies": [
|
||||||
|
"EUR",
|
||||||
|
"USD",
|
||||||
|
"CAD",
|
||||||
|
"GBP",
|
||||||
|
"SGD",
|
||||||
|
"HKD",
|
||||||
|
"CNY",
|
||||||
|
"JPY",
|
||||||
|
"INR",
|
||||||
|
"RUB",
|
||||||
|
"ETH",
|
||||||
|
"BTC",
|
||||||
|
"LINK"
|
||||||
|
],
|
||||||
|
"portisId": "xxx",
|
||||||
|
"allowFixedPricing": "true",
|
||||||
|
"allowDynamicPricing": "true",
|
||||||
|
"allowFreePricing": "false",
|
||||||
|
"allowAdvancedSettings": "false",
|
||||||
|
"credentialType": "address",
|
||||||
|
"privacyPreferenceCenter": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"siteImage": {
|
||||||
"edges": [
|
"edges": [
|
||||||
{
|
{
|
||||||
"node": {
|
"node": {
|
||||||
"childContentJson": {
|
"childContentJson": {
|
||||||
"site": {
|
"site": {
|
||||||
"siteTitle": "Ocean Market",
|
|
||||||
"siteTagline": "A marketplace to find and publish open data sets in the Ocean Network.",
|
|
||||||
"siteUrl": "https://market.oceanprotocol.now.sh/",
|
|
||||||
"siteIcon": "node_modules/@oceanprotocol/art/logo/favicon-white.png",
|
|
||||||
"siteImage": {
|
"siteImage": {
|
||||||
"childImageSharp": {
|
"childImageSharp": {
|
||||||
"original": {
|
"original": {
|
||||||
|
22
tests/unit/__fixtures__/useUserPreferences.ts
Normal file
22
tests/unit/__fixtures__/useUserPreferences.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { UserPreferencesValue } from '../../../src/providers/UserPreferences'
|
||||||
|
|
||||||
|
const useUserPreferences: UserPreferencesValue = {
|
||||||
|
debug: false,
|
||||||
|
currency: 'EUR',
|
||||||
|
locale: 'de',
|
||||||
|
chainIds: [1],
|
||||||
|
bookmarks: [],
|
||||||
|
privacyPolicySlug: '/privacy/en',
|
||||||
|
showPPC: false,
|
||||||
|
infiniteApproval: false,
|
||||||
|
setChainIds: jest.fn(),
|
||||||
|
setCurrency: jest.fn(),
|
||||||
|
setPrivacyPolicySlug: jest.fn(),
|
||||||
|
setDebug: jest.fn(),
|
||||||
|
setShowPPC: jest.fn(),
|
||||||
|
addBookmark: jest.fn(),
|
||||||
|
removeBookmark: jest.fn(),
|
||||||
|
setInfiniteApproval: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useUserPreferences
|
60
tests/unit/components/CookieModule.test.tsx
Normal file
60
tests/unit/components/CookieModule.test.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { fireEvent, render, screen } from '@testing-library/react'
|
||||||
|
import CookieModule, {
|
||||||
|
CookieModuleProps
|
||||||
|
} from '../../../src/components/molecules/CookieModule'
|
||||||
|
import CookieConsent, {
|
||||||
|
ConsentContext,
|
||||||
|
ConsentProviderValue,
|
||||||
|
CookieConsentStatus
|
||||||
|
} from '../../../src/providers/CookieConsent'
|
||||||
|
import { useGdprMetadata } from '../../../src/hooks/useGdprMetadata'
|
||||||
|
|
||||||
|
const cookieProps: CookieModuleProps = {
|
||||||
|
title: 'Title',
|
||||||
|
desc: 'Description',
|
||||||
|
cookieName: 'CookieName'
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.resetModules()
|
||||||
|
|
||||||
|
describe('CookieModule', () => {
|
||||||
|
it('renders correctly without crashing', () => {
|
||||||
|
const { container } = render(
|
||||||
|
<CookieConsent>
|
||||||
|
<CookieModule {...cookieProps} />
|
||||||
|
</CookieConsent>
|
||||||
|
)
|
||||||
|
|
||||||
|
const moduleWrapper = container.querySelector('.wrapper')
|
||||||
|
const moduleHeader = moduleWrapper.querySelector('.header')
|
||||||
|
const moduleSwitch = moduleWrapper.querySelector('.switch')
|
||||||
|
const moduleDesc = moduleWrapper.querySelector('.description')
|
||||||
|
|
||||||
|
expect(moduleWrapper).toBeInTheDocument()
|
||||||
|
expect(moduleHeader).toBeInTheDocument()
|
||||||
|
expect(moduleSwitch).toBeInTheDocument()
|
||||||
|
expect(moduleDesc).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
const cookieConsentStatusApproved = {
|
||||||
|
[cookieProps.cookieName]: CookieConsentStatus.APPROVED
|
||||||
|
}
|
||||||
|
const testValue: ConsentProviderValue = {
|
||||||
|
cookies: useGdprMetadata().optionalCookies,
|
||||||
|
cookieConsentStatus: cookieConsentStatusApproved,
|
||||||
|
setConsentStatus: jest.fn(),
|
||||||
|
resetConsentStatus: jest.fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
it('initializes switch correctly', () => {
|
||||||
|
// CookieConsentStatus not available
|
||||||
|
const { container } = render(
|
||||||
|
<ConsentContext.Provider value={testValue}>
|
||||||
|
<CookieModule {...cookieProps} />
|
||||||
|
</ConsentContext.Provider>
|
||||||
|
)
|
||||||
|
const switchInput = container.querySelector('input')
|
||||||
|
expect(switchInput).toHaveProperty('checked', true)
|
||||||
|
})
|
||||||
|
})
|
19
tests/unit/components/Disclaimer.test.tsx
Normal file
19
tests/unit/components/Disclaimer.test.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { render } from '@testing-library/react'
|
||||||
|
import Disclaimer from '../../../src/components/atoms/Input/Disclaimer'
|
||||||
|
|
||||||
|
describe('Disclaimer', () => {
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
const disclaimerText = 'test'
|
||||||
|
const { container } = render(
|
||||||
|
<Disclaimer visible>{disclaimerText}</Disclaimer>
|
||||||
|
)
|
||||||
|
|
||||||
|
const disclaimerByClass = container.querySelector('.disclaimer')
|
||||||
|
const disclaimerByVisibility = container.querySelector('.hidden')
|
||||||
|
|
||||||
|
expect(disclaimerByClass).toBeInTheDocument()
|
||||||
|
expect(disclaimerByVisibility).not.toBeInTheDocument()
|
||||||
|
expect(container).toHaveTextContent(disclaimerText)
|
||||||
|
})
|
||||||
|
})
|
27
tests/unit/components/PrivacyPolicy.test.tsx
Normal file
27
tests/unit/components/PrivacyPolicy.test.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { render } from '@testing-library/react'
|
||||||
|
import PrivacyHeader from '../../../src/components/molecules/PrivacyHeader'
|
||||||
|
import PrivacyLanguages from '../../../src/components/atoms/PrivacyLanguages'
|
||||||
|
|
||||||
|
const privacyPolicy = {
|
||||||
|
tableOfContents: 'toc',
|
||||||
|
policy: 'en'
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('PrivacyLanguages', () => {
|
||||||
|
it('renders correctly without crashing', () => {
|
||||||
|
const label = 'TEST'
|
||||||
|
const { container } = render(<PrivacyLanguages label={label} />)
|
||||||
|
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
|
expect(container).toHaveTextContent(label)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('PrivacyHeader', () => {
|
||||||
|
it('renders correctly without crashing', () => {
|
||||||
|
const { container } = render(<PrivacyHeader {...privacyPolicy} />)
|
||||||
|
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
23
tests/unit/components/PrivacyPreferenceCenter.test.tsx
Normal file
23
tests/unit/components/PrivacyPreferenceCenter.test.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { render } from '@testing-library/react'
|
||||||
|
import PrivacyPreferenceCenter from '../../../src/components/organisms/PrivacyPreferenceCenter'
|
||||||
|
|
||||||
|
jest.resetModules()
|
||||||
|
|
||||||
|
describe('privacyPreferenceCenter', () => {
|
||||||
|
it('renders correctly without crashing', () => {
|
||||||
|
const { container } = render(<PrivacyPreferenceCenter />)
|
||||||
|
|
||||||
|
const moduleWrapper = container.querySelector('.wrapper')
|
||||||
|
|
||||||
|
expect(moduleWrapper).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('initializes small styling correctly', () => {
|
||||||
|
// CookieConsentStatus not available
|
||||||
|
const { container } = render(<PrivacyPreferenceCenter style="small" />)
|
||||||
|
|
||||||
|
const moduleWrapper = container.querySelector('.small.wrapper')
|
||||||
|
expect(moduleWrapper).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
@ -1,21 +1,26 @@
|
|||||||
import '@testing-library/jest-dom/extend-expect'
|
import '@testing-library/jest-dom/extend-expect'
|
||||||
import * as Gatsby from 'gatsby'
|
import * as Gatsby from 'gatsby'
|
||||||
import siteMetadata from './__fixtures__/siteMetadata.json'
|
import siteMetadata from './__fixtures__/siteMetadata.json'
|
||||||
|
import gdprMetadata from './__fixtures__/gdprMetadata.json'
|
||||||
|
import UserPreferences from './__fixtures__/useUserPreferences'
|
||||||
|
import * as UseUserPreferences from '../../src/providers/UserPreferences'
|
||||||
|
|
||||||
import('./__mocks__/matchMedia')
|
import('./__mocks__/matchMedia')
|
||||||
|
|
||||||
const useStaticQuery = jest.spyOn(Gatsby, 'useStaticQuery')
|
const useStaticQuery = jest.spyOn(Gatsby, 'useStaticQuery')
|
||||||
|
const useUserPreferences = jest.spyOn(UseUserPreferences, 'useUserPreferences')
|
||||||
// const useWeb3 = jest.spyOn(oceanReact, 'useWeb3')
|
// const useWeb3 = jest.spyOn(oceanReact, 'useWeb3')
|
||||||
// const useOcean = jest.spyOn(oceanReact, 'useOcean')
|
// const useOcean = jest.spyOn(oceanReact, 'useOcean')
|
||||||
|
|
||||||
export const globalMock = {
|
export const globalMock = {
|
||||||
...siteMetadata
|
...siteMetadata,
|
||||||
|
...gdprMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
jest.mock('web3')
|
jest.mock('web3')
|
||||||
jest.mock('@oceanprotocol/lib')
|
jest.mock('@oceanprotocol/lib')
|
||||||
|
|
||||||
// useOcean.mockImplementation(() => mockReact.useOcean())
|
// useOcean.mockImplementation(() => mockReact.useOcean())
|
||||||
useStaticQuery.mockImplementation(() => globalMock)
|
useStaticQuery.mockImplementation(() => globalMock)
|
||||||
|
useUserPreferences.mockImplementation(() => UserPreferences)
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user