From caa855777d1813b98a85ceea7c6e395147dbe28f Mon Sep 17 00:00:00 2001 From: Markus Scheidgen <markus.scheidgen@gmail.com> Date: Thu, 18 Jun 2020 17:20:35 +0200 Subject: [PATCH] Adapted consent in GUI for use of matomo. #199 --- gui/public/env.js | 2 +- gui/src/components/App.js | 135 ++++++++++--------- gui/src/config.js | 8 +- gui/src/index.js | 8 +- ops/helm/nomad/templates/api-deployment.yaml | 2 +- ops/helm/nomad/values.yaml | 4 +- 6 files changed, 87 insertions(+), 72 deletions(-) diff --git a/gui/public/env.js b/gui/public/env.js index 505a0d4b48..88fc04f4ae 100644 --- a/gui/public/env.js +++ b/gui/public/env.js @@ -4,7 +4,7 @@ window.nomadEnv = { 'keycloakClientId': 'nomad_gui_dev', 'appBase': 'http://localhost:8000/fairdi/nomad/latest', 'debug': false, - 'sendTrackingData': true, + 'matomoEnabled': true, 'matomoUrl': 'https://repository.nomad-coe.eu/fairdi/stat', 'matomoSiteId': '2' } diff --git a/gui/src/components/App.js b/gui/src/components/App.js index 9b5e8cf726..715d971ade 100644 --- a/gui/src/components/App.js +++ b/gui/src/components/App.js @@ -1,13 +1,13 @@ // trigger rebuild import React, { useEffect, useState, useContext, useCallback, useRef } from 'react' -import PropTypes, { instanceOf } from 'prop-types' +import PropTypes from 'prop-types' import { compose } from 'recompose' import classNames from 'classnames' import { MuiThemeProvider, withStyles, makeStyles } from '@material-ui/core/styles' import { LinearProgress, MenuList, Typography, AppBar, Toolbar, Button, DialogContent, DialogTitle, DialogActions, Dialog, Tooltip, - Snackbar, SnackbarContent } from '@material-ui/core' + Snackbar, SnackbarContent, FormGroup, FormControlLabel, Switch } from '@material-ui/core' import { Route, Link, withRouter, useLocation } from 'react-router-dom' import BackupIcon from '@material-ui/icons/Backup' import SearchIcon from '@material-ui/icons/Search' @@ -17,6 +17,7 @@ import FAQIcon from '@material-ui/icons/QuestionAnswer' import MetainfoIcon from '@material-ui/icons/Info' import DocIcon from '@material-ui/icons/Help' import CodeIcon from '@material-ui/icons/Code' +import TermsIcon from '@material-ui/icons/Assignment' import {help as searchHelp, default as SearchPage} from './search/SearchPage' import HelpDialog from './Help' import { ApiProvider, withApi, apiContext } from './api' @@ -27,8 +28,6 @@ import LoginLogout from './LoginLogout' import { guiBase, consent, nomadTheme, appBase } from '../config' import {help as metainfoHelp, default as MetaInfoBrowser} from './metaInfoBrowser/MetaInfoBrowser' import packageJson from '../../package.json' -import { Cookies, withCookies } from 'react-cookie' -import Markdown from './Markdown' import {help as uploadHelp, default as UploadPage} from './uploads/UploadPage' import ResolvePID from './entry/ResolvePID' import DatasetPage from './DatasetPage' @@ -37,6 +36,9 @@ import {help as userdataHelp, default as UserdataPage} from './UserdataPage' import ResolveDOI from './dataset/ResolveDOI' import FAQ from './FAQ' import EntryQuery from './entry/EntryQuery' +import {matomo} from '../index' +import { useCookies } from 'react-cookie' +import Markdown from './Markdown' export const ScrollContext = React.createContext({scrollParentRef: null}) @@ -80,7 +82,7 @@ const useMainMenuItemStyles = makeStyles(theme => ({ } })) -function MainMenuItem({tooltip, title, path, href, icon}) { +function MainMenuItem({tooltip, title, path, href, onClick, icon}) { const {pathname} = useLocation() const classes = useMainMenuItemStyles() const selected = path === pathname || (path !== '/' && pathname.startsWith(path)) @@ -91,6 +93,7 @@ function MainMenuItem({tooltip, title, path, href, icon}) { color={selected ? 'primary' : 'default'} size="small" startIcon={icon} + onClick={onClick} {...rest} > {title} @@ -102,9 +105,73 @@ MainMenuItem.propTypes = { 'title': PropTypes.string.isRequired, 'path': PropTypes.string, 'href': PropTypes.string, + 'onClick': PropTypes.func, 'icon': PropTypes.element.isRequired } +function Consent() { + const [cookies, setCookie] = useCookies() + const [accepted, setAccepted] = useState(cookies['terms-accepted']) + const [optOut, setOptOut] = useState(cookies['tracking-enabled'] === 'false') + + useEffect(() => { + if (!optOut) { + matomo.push(['setConsentGiven']) + } else { + matomo.push(['requireConsent']) + } + }) + + const handleClosed = accepted => { + if (accepted) { + setCookie('terms-accepted', true) + setCookie('tracking-enabled', !optOut) + setAccepted(true) + } + } + const handleOpen = () => { + setCookie('terms-accepted', false) + setAccepted(false) + } + + return ( + <React.Fragment> + <MainMenuItem + title="Terms" + onClick={handleOpen} + tooltip="NOMAD's terms" + icon={<TermsIcon/>} + /> + <Dialog + disableBackdropClick disableEscapeKeyDown + open={!accepted} + > + <DialogTitle>Terms of Use</DialogTitle> + <DialogContent> + <Markdown>{consent}</Markdown> + <FormGroup> + <FormControlLabel + control={<Switch + checked={optOut} + onChange={(e) => { + setOptOut(!optOut) + }} + color="primary" + />} + label="Do not provide information about your use of NOMAD (opt-out)." + /> + </FormGroup> + </DialogContent> + <DialogActions> + <Button onClick={() => handleClosed(true)} color="primary"> + Accept + </Button> + </DialogActions> + </Dialog> + </React.Fragment> + ) +} + const useMainMenuStyles = makeStyles(theme => ({ root: { display: 'inline-flex', @@ -186,6 +253,7 @@ function MainMenu() { tooltip="NOMAD's Gitlab project" icon={<CodeIcon/>} /> + <Consent /> </MenuList> } @@ -378,62 +446,6 @@ class NavigationUnstyled extends React.Component { const Navigation = compose(withRouter, withErrors, withApi(false), withStyles(NavigationUnstyled.styles))(NavigationUnstyled) -class LicenseAgreementUnstyled extends React.Component { - static propTypes = { - classes: PropTypes.object.isRequired, - cookies: instanceOf(Cookies).isRequired - } - - static styles = theme => ({ - content: { - backgroundColor: theme.palette.primary.main - }, - button: { - color: 'white' - } - }) - - constructor(props) { - super(props) - - this.handleClosed = this.handleClosed.bind(this) - } - - state = { - accepted: this.props.cookies.get('terms-accepted') - } - - handleClosed(accepted) { - if (accepted) { - this.props.cookies.set('terms-accepted', true) - this.setState({accepted: true}) - } - } - - render() { - return ( - <div> - <Dialog - disableBackdropClick disableEscapeKeyDown - open={!this.state.accepted} - > - <DialogTitle>Terms of Use</DialogTitle> - <DialogContent> - <Markdown>{consent}</Markdown> - </DialogContent> - <DialogActions> - <Button onClick={() => this.handleClosed(true)} color="primary"> - Accept - </Button> - </DialogActions> - </Dialog> - </div> - ) - } -} - -const LicenseAgreement = compose(withCookies, withStyles(LicenseAgreementUnstyled.styles))(LicenseAgreementUnstyled) - const routes = { 'about': { exact: true, @@ -518,7 +530,6 @@ class App extends React.PureComponent { </Navigation> </ApiProvider> </ErrorSnacks> - <LicenseAgreement /> </MuiThemeProvider> ) } diff --git a/gui/src/config.js b/gui/src/config.js index 756adab388..7b3f7c9f17 100644 --- a/gui/src/config.js +++ b/gui/src/config.js @@ -12,7 +12,7 @@ export const keycloakBase = window.nomadEnv.keycloakBase export const keycloakRealm = window.nomadEnv.keycloakRealm export const keycloakClientId = window.nomadEnv.keycloakClientId export const debug = window.nomadEnv.debug || false -export const sendTrackingData = window.nomadEnv.sendTrackingData +export const matomoEnabled = window.nomadEnv.matomoEnabled export const email = 'webmaster@nomad-coe.eu' export const maxLogsToShow = 50 @@ -27,8 +27,10 @@ you and users you share your data with. The *embargo period* lasts up to 36 mont After the *embargo* your published data will be public. **Note that public data is visible to others and files become downloadable by everyone.** -This web-site uses *cookies*. By using this web-site you agree to our use -of *cookies*. [Learn more](https://www.cookiesandyou.com/). +This web-site uses *cookies*. We use cookies to track you login status for all NOMAD services +and optionally to store information about your use of NOMAD. None of this information is +shared with other parties. By using this web-site you agree to the described use of *cookies*. +[Learn more](https://www.cookiesandyou.com/). ` export const nomadPrimaryColor = { main: '#008DC3', diff --git a/gui/src/index.js b/gui/src/index.js index f3e72b28f4..e204c5f483 100644 --- a/gui/src/index.js +++ b/gui/src/index.js @@ -8,12 +8,12 @@ import { Router, Route } from 'react-router-dom' import { QueryParamProvider } from 'use-query-params' import history from './history' import PiwikReactRouter from 'piwik-react-router' -import { sendTrackingData, matomoUrl, matomoSiteId, keycloakBase, keycloakRealm, keycloakClientId } from './config' +import { matomoEnabled, matomoUrl, matomoSiteId, keycloakBase, keycloakRealm, keycloakClientId } from './config' import Keycloak from 'keycloak-js' import { KeycloakProvider } from 'react-keycloak' import * as serviceWorker from './serviceWorker' -const matomo = sendTrackingData ? PiwikReactRouter({ +export const matomo = matomoEnabled ? PiwikReactRouter({ url: matomoUrl, siteId: matomoSiteId, clientTrackerName: 'stat.js', @@ -26,9 +26,11 @@ const keycloak = Keycloak({ clientId: keycloakClientId }) +// matomo.push('requireConsent') + ReactDOM.render( <KeycloakProvider keycloak={keycloak} initConfig={{onLoad: 'check-sso'}} LoadingComponent={<div />}> - <Router history={sendTrackingData ? matomo.connectToHistory(history) : history}> + <Router history={matomoEnabled ? matomo.connectToHistory(history) : history}> <QueryParamProvider ReactRouterRoute={Route}> <App /> </QueryParamProvider> diff --git a/ops/helm/nomad/templates/api-deployment.yaml b/ops/helm/nomad/templates/api-deployment.yaml index 156728abbc..b76dc30ad6 100644 --- a/ops/helm/nomad/templates/api-deployment.yaml +++ b/ops/helm/nomad/templates/api-deployment.yaml @@ -92,7 +92,7 @@ data: "keycloakClientId": "{{ .Values.keycloak.guiClientId }}", "matomoSiteId": {{ .Values.gui.matomoSiteId }}, "matomoUrl": "{{ .Values.gui.matomoUrl }}", - "sendTrackingData": {{ .Values.gui.sendTrackingData }}, + "matomoEnabled": {{ .Values.gui.matomoEnabled }}, "debug": {{ .Values.gui.debug }} }; --- diff --git a/ops/helm/nomad/values.yaml b/ops/helm/nomad/values.yaml index 47ff4191fa..65051d5653 100644 --- a/ops/helm/nomad/values.yaml +++ b/ops/helm/nomad/values.yaml @@ -68,11 +68,11 @@ gui: ## This variable is used in the GUI to show or hide additional information debug: false ## URL for matomo(piwik) user tracking - matomoUrl: 'http://nowhere.no' + matomoUrl: 'https://repository.nomad-coe.eu/fairdi/stat' ## site id for matomo(piwik) user tracking matomoSiteId: 1 ## send matomo(piwik) user tracking data - sendTrackingData: false + matomoEnabled: false ## Everything concerning the nginx that serves the gui, proxies the api # It is run via NodePort service -- GitLab