From 34098bd0b48d62d5772a36a195593118946ea263 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 3 Oct 2020 18:05:46 -0700 Subject: [PATCH 1/8] Small prop change. --- components/common/MenuButton.js | 7 ++++--- components/settings/LanguageButton.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/components/common/MenuButton.js b/components/common/MenuButton.js index 4f3f2584..f3de66d0 100644 --- a/components/common/MenuButton.js +++ b/components/common/MenuButton.js @@ -9,7 +9,8 @@ export default function MenuButton({ icon, value, options, - menuClassname, + buttonClassName, + menuClassName, menuPosition = 'bottom', menuAlign = 'right', onSelect, @@ -38,7 +39,7 @@ export default function MenuButton({
{showMenu && ( } options={menuOptions} value={locale} - menuClassname={styles.menu} + menuClassName={styles.menu} renderValue={option => option?.display} onSelect={handleSelect} /> From fc22f5969ce586995256b7c83b59e2393f5442c1 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 3 Oct 2020 19:07:56 -0700 Subject: [PATCH 2/8] Added IP address ignore list. --- package.json | 2 +- pages/api/collect.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9c6e899e..c5553e41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "0.74.0", + "version": "0.75.0", "description": "A simple, fast, website analytics alternative to Google Analytics. ", "author": "Mike Cao ", "license": "MIT", diff --git a/pages/api/collect.js b/pages/api/collect.js index e6b3e0ca..4f01b225 100644 --- a/pages/api/collect.js +++ b/pages/api/collect.js @@ -3,12 +3,22 @@ import { savePageView, saveEvent } from 'lib/queries'; import { useCors, useSession } from 'lib/middleware'; import { ok, badRequest } from 'lib/response'; import { createToken } from 'lib/crypto'; +import { getIpAddress } from '../../lib/request'; export default async (req, res) => { if (isBot(req.headers['user-agent'])) { return ok(res); } + if (process.env.IGNORE_IP) { + const ips = process.env.IGNORE_IP.split(',').map(n => n.trim()); + const ip = getIpAddress(req); + + if (ips.includes(ip)) { + return ok(res); + } + } + await useCors(req, res); await useSession(req, res); From 4cafa68e23d4fe693b095d9c4a4b4b1e0b6aab9c Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 3 Oct 2020 21:54:21 -0700 Subject: [PATCH 3/8] Add force SSL check. --- hooks/useForceSSL.js | 14 ++++++++++++++ next.config.js | 4 +--- package.json | 2 +- pages/_app.js | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 hooks/useForceSSL.js diff --git a/hooks/useForceSSL.js b/hooks/useForceSSL.js new file mode 100644 index 00000000..b9d95e19 --- /dev/null +++ b/hooks/useForceSSL.js @@ -0,0 +1,14 @@ +import { useEffect } from 'react'; +import { useRouter } from 'next/router'; + +export default function useForceSSL(enabled) { + const router = useRouter(); + + useEffect(() => { + if (enabled && typeof window !== 'undefined' && /^http:\/\//.test(location.href)) { + router.push(location.href.replace(/^http:\/\//, 'https://')); + } + }, [enabled]); + + return null; +} diff --git a/next.config.js b/next.config.js index c1e31d7b..9d7d8e99 100644 --- a/next.config.js +++ b/next.config.js @@ -4,9 +4,7 @@ const pkg = require('./package.json'); module.exports = { env: { VERSION: pkg.version, - }, - serverRuntimeConfig: { - PROJECT_ROOT: __dirname, + FORCE_SSL: !!process.env.FORCE_SSL, }, webpack(config) { config.module.rules.push({ diff --git a/package.json b/package.json index c5553e41..f5fe6909 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "0.75.0", + "version": "0.76.0", "description": "A simple, fast, website analytics alternative to Google Analytics. ", "author": "Mike Cao ", "license": "MIT", diff --git a/pages/_app.js b/pages/_app.js index 9aad4339..2849d2f0 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -3,6 +3,7 @@ import { IntlProvider } from 'react-intl'; import { Provider } from 'react-redux'; import { useStore } from 'redux/store'; import useLocale from 'hooks/useLocale'; +import useForceSSL from 'hooks/useForceSSL'; import { messages } from 'lib/lang'; import 'styles/variables.css'; import 'styles/bootstrap-grid.css'; @@ -21,6 +22,7 @@ const Intl = ({ children }) => { }; export default function App({ Component, pageProps }) { + useForceSSL(process.env.FORCE_SSL); const store = useStore(); return ( From ca8a6fe049c1b0adb599d0ee68bcecdfe22a8aaf Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sat, 3 Oct 2020 22:36:51 -0700 Subject: [PATCH 4/8] Added error message component. Update fetch hook. --- assets/exclamation-triangle.svg | 1 + components/common/ErrorMessage.js | 14 ++++++++++++++ components/common/ErrorMessage.module.css | 13 +++++++++++++ components/metrics/MetricsBar.js | 9 +++++---- components/metrics/MetricsTable.js | 10 ++++++---- components/metrics/WebsiteChart.js | 4 +++- hooks/useFetch.js | 8 +++++++- package.json | 2 +- 8 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 assets/exclamation-triangle.svg create mode 100644 components/common/ErrorMessage.js create mode 100644 components/common/ErrorMessage.module.css diff --git a/assets/exclamation-triangle.svg b/assets/exclamation-triangle.svg new file mode 100644 index 00000000..46bef5bc --- /dev/null +++ b/assets/exclamation-triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/components/common/ErrorMessage.js b/components/common/ErrorMessage.js new file mode 100644 index 00000000..5747f226 --- /dev/null +++ b/components/common/ErrorMessage.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { FormattedMessage } from 'react-intl'; +import Icon from './Icon'; +import Exclamation from 'assets/exclamation-triangle.svg'; +import styles from './ErrorMessage.module.css'; + +export default function ErrorMessage() { + return ( +
+ } className={styles.icon} size="large" /> + +
+ ); +} diff --git a/components/common/ErrorMessage.module.css b/components/common/ErrorMessage.module.css new file mode 100644 index 00000000..232b5f84 --- /dev/null +++ b/components/common/ErrorMessage.module.css @@ -0,0 +1,13 @@ +.error { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + margin: auto; + display: flex; + z-index: 1; +} + +.icon { + margin-right: 10px; +} diff --git a/components/metrics/MetricsBar.js b/components/metrics/MetricsBar.js index f5d888d4..b7a47a10 100644 --- a/components/metrics/MetricsBar.js +++ b/components/metrics/MetricsBar.js @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; import Loading from 'components/common/Loading'; +import ErrorMessage from 'components/common/ErrorMessage'; import useFetch from 'hooks/useFetch'; import useDateRange from 'hooks/useDateRange'; import { formatShortTime, formatNumber, formatLongNumber } from 'lib/format'; @@ -17,7 +18,7 @@ export default function MetricsBar({ websiteId, token, className }) { query: { url }, } = usePageQuery(); - const { data } = useFetch( + const { data, error, loading } = useFetch( `/api/website/${websiteId}/metrics`, { start_at: +startDate, @@ -40,9 +41,9 @@ export default function MetricsBar({ websiteId, token, className }) { return (
- {!data ? ( - - ) : ( + {!data && loading && } + {error && } + {data && !error && ( <> } diff --git a/components/metrics/MetricsTable.js b/components/metrics/MetricsTable.js index 3ac8a395..6850a3bf 100644 --- a/components/metrics/MetricsTable.js +++ b/components/metrics/MetricsTable.js @@ -13,6 +13,7 @@ import { formatNumber, formatLongNumber } from 'lib/format'; import useDateRange from 'hooks/useDateRange'; import usePageQuery from 'hooks/usePageQuery'; import styles from './MetricsTable.module.css'; +import ErrorMessage from '../common/ErrorMessage'; export default function MetricsTable({ websiteId, @@ -36,7 +37,7 @@ export default function MetricsTable({ query: { url }, } = usePageQuery(); - const { data } = useFetch( + const { data, loading, error } = useFetch( `/api/website/${websiteId}/rankings`, { type, @@ -61,7 +62,7 @@ export default function MetricsTable({ return items; } return []; - }, [data, dataFilter, filterOptions]); + }, [data, error, dataFilter, filterOptions]); const handleSetFormat = () => setFormat(state => !state); @@ -86,8 +87,9 @@ export default function MetricsTable({ return (
- {!data && } - {data && ( + {!data && loading && } + {error && } + {data && !error && ( <>
{title}
diff --git a/components/metrics/WebsiteChart.js b/components/metrics/WebsiteChart.js index ea86ad3e..6a07afe5 100644 --- a/components/metrics/WebsiteChart.js +++ b/components/metrics/WebsiteChart.js @@ -13,6 +13,7 @@ import usePageQuery from 'hooks/usePageQuery'; import { getDateArray, getDateLength } from 'lib/date'; import Times from 'assets/times.svg'; import styles from './WebsiteChart.module.css'; +import ErrorMessage from '../common/ErrorMessage'; export default function WebsiteChart({ websiteId, @@ -31,7 +32,7 @@ export default function WebsiteChart({ query: { url }, } = usePageQuery(); - const { data, loading } = useFetch( + const { data, loading, error } = useFetch( `/api/website/${websiteId}/pageviews`, { start_at: +startDate, @@ -83,6 +84,7 @@ export default function WebsiteChart({
+ {error && } = 400) { + setError(data); + setData(null); + } else { + setData(data); + } + setStatus(status); onDataLoad(data); } catch (e) { diff --git a/package.json b/package.json index f5fe6909..0d602350 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "0.76.0", + "version": "0.77.0", "description": "A simple, fast, website analytics alternative to Google Analytics. ", "author": "Mike Cao ", "license": "MIT", From 195eb06a02916f3bc93f471264d074b6abfc639b Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Sun, 4 Oct 2020 22:27:59 -0700 Subject: [PATCH 5/8] Add domain filter to tracker. --- package.json | 2 +- tracker/index.js | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0d602350..c21f3076 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "0.77.0", + "version": "0.78.0", "description": "A simple, fast, website analytics alternative to Google Analytics. ", "author": "Mike Cao ", "license": "MIT", diff --git a/tracker/index.js b/tracker/index.js index 154e0034..df4c5216 100644 --- a/tracker/index.js +++ b/tracker/index.js @@ -19,8 +19,19 @@ import { removeTrailingSlash } from '../lib/url'; const autoTrack = attr('data-auto-track') !== 'false'; const dnt = attr('data-do-not-track'); const useCache = attr('data-cache'); + const domains = attr('data-domains'); - if (!script || (dnt && doNotTrack())) return; + if ( + !script || + (dnt && doNotTrack()) || + (domains && + !domains + .split(',') + .map(n => n.trim()) + .includes(hostname)) + ) { + return; + } const root = hostUrl ? removeTrailingSlash(hostUrl) From cc612cb831b8f13df2686303de32a57dca45dff0 Mon Sep 17 00:00:00 2001 From: Frans Allen Date: Mon, 5 Oct 2020 14:45:24 +0700 Subject: [PATCH 6/8] Implement Cache-Control header for umami.js --- next.config.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/next.config.js b/next.config.js index c1e31d7b..e386c04e 100644 --- a/next.config.js +++ b/next.config.js @@ -19,4 +19,17 @@ module.exports = { return config; }, + async headers() { + return [ + { + source: '/umami.js', + headers: [ + { + key: 'Cache-Control', + value: 'public, max-age=2592000', // 30 days + }, + ], + }, + ] + }, }; From d09d469bf4e1bc3b81a23cd7260c28689f53b67b Mon Sep 17 00:00:00 2001 From: Bram <24355695+brams-dev@users.noreply.github.com> Date: Wed, 7 Oct 2020 11:54:45 +0000 Subject: [PATCH 7/8] Add missing dutch translations --- lang/nl-NL.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lang/nl-NL.json b/lang/nl-NL.json index 148fd32e..54f7894f 100644 --- a/lang/nl-NL.json +++ b/lang/nl-NL.json @@ -7,22 +7,22 @@ "button.copy-to-clipboard": "Kopiƫer naar klembord", "button.date-range": "Datumbereik", "button.delete": "Verwijderen", - "button.dismiss": "Dismiss", + "button.dismiss": "Negeren", "button.edit": "Bewerken", "button.login": "Inloggen", "button.more": "Toon meer", "button.refresh": "Vernieuwen", - "button.reset": "Reset", + "button.reset": "Resetten", "button.save": "Opslaan", "button.single-day": "Enkele dag", "button.view-details": "Meer details", - "label.accounts": "Accounts", + "label.accounts": "Gebruikers", "label.administrator": "Administrator", "label.confirm-password": "Wachtwoord bevestigen", "label.current-password": "Huidig wachtwoord", "label.custom-range": "Aangepast bereik", - "label.dashboard": "Dashboard", - "label.default-date-range": "Default date range", + "label.dashboard": "Overzicht", + "label.default-date-range": "Standaard bereik", "label.domain": "Domein", "label.enable-share-url": "Sta delen via openbare URL toe", "label.invalid": "Ongeldig", @@ -41,7 +41,7 @@ "label.this-month": "Deze maand", "label.this-week": "Deze week", "label.this-year": "Dit jaar", - "label.timezone": "Timezone", + "label.timezone": "Tijdzone", "label.today": "Vandaag", "label.unknown": "Onbekend", "label.username": "Gebruikersnaam", @@ -55,7 +55,7 @@ "message.get-tracking-code": "Tracking code", "message.go-to-settings": "Naar instellingen", "message.incorrect-username-password": "Incorrecte gebruikersnaam/wachtwoord.", - "message.new-version-available": "A new version of umami {version} is available!", + "message.new-version-available": "Een nieuwe versie van umami {version} is beschikbaar!", "message.no-data-available": "Geen gegevens beschikbaar.", "message.no-websites-configured": "Je hebt geen websites ingesteld.", "message.page-not-found": "Pagina niet gevonden.", From dca51050e8b8aa91c1271af6567bca29af4716e7 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Wed, 7 Oct 2020 08:31:44 -0700 Subject: [PATCH 8/8] Removed disconnect code. --- lib/queries.js | 10 +++------- package.json | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/queries.js b/lib/queries.js index 7c0bb6e7..3b138faa 100644 --- a/lib/queries.js +++ b/lib/queries.js @@ -16,13 +16,9 @@ export function getDatabase() { } export async function runQuery(query) { - return query - .catch(e => { - throw e; - }) - .finally(async () => { - await prisma.$disconnect(); - }); + return query.catch(e => { + throw e; + }); } export async function rawQuery(query, params = []) { diff --git a/package.json b/package.json index c21f3076..aca8f8c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "0.78.0", + "version": "0.80.0", "description": "A simple, fast, website analytics alternative to Google Analytics. ", "author": "Mike Cao ", "license": "MIT",