From aceb904398b527658676879b11ff22135b7cbaf8 Mon Sep 17 00:00:00 2001 From: Mike Cao Date: Tue, 25 Oct 2022 16:50:12 -0700 Subject: [PATCH] v1.39.2 (#1599) * Fixed issue with realtime page rendering. * fix auth, add pg extension (#1596) * Fixed change password issue. API refactoring. Closes #1592. * Fixed account lookup. * Fixed issue with accessing user dashboards. Closes #1590 * fix sort on dashboard (#1600) Co-authored-by: Brian Cao --- components/forms/ChangePasswordForm.js | 6 ++-- components/forms/EventDataForm.js | 2 +- components/metrics/RealtimeHeader.js | 9 ++++-- components/pages/Dashboard.js | 6 +--- components/pages/DashboardEdit.js | 12 +++++--- components/pages/RealtimeDashboard.js | 28 ++++++++----------- components/settings/AccountSettings.js | 16 ++++++----- .../migrations/04_add_uuid/migration.sql | 2 ++ lib/auth.js | 16 +++++++---- lib/constants.js | 3 ++ lib/session.js | 4 +-- package.json | 2 +- pages/api/accounts/[id]/password.js | 14 +++++----- pages/api/accounts/index.js | 6 ++-- pages/api/auth/login.js | 4 +-- pages/api/realtime/init.js | 2 +- pages/api/share/[id].js | 4 +-- pages/api/websites/[id]/active.js | 3 +- pages/api/websites/[id]/eventdata.js | 3 +- pages/api/websites/[id]/events.js | 3 +- pages/api/websites/[id]/index.js | 15 +++++----- pages/api/websites/[id]/metrics.js | 8 +++--- pages/api/websites/[id]/pageviews.js | 3 +- pages/api/websites/[id]/reset.js | 3 +- pages/api/websites/[id]/stats.js | 3 +- pages/api/websites/index.js | 9 +++--- pages/dashboard/[[...id]].js | 14 ++++++++-- queries/admin/account/getAccountById.js | 9 ------ queries/admin/account/getAccountByUsername.js | 9 ------ queries/admin/account/getAccounts.js | 1 + queries/admin/website/deleteWebsite.js | 15 ++++------ queries/admin/website/getUserWebsites.js | 6 ++-- queries/admin/website/getWebsite.js | 15 ++++++++-- queries/admin/website/getWebsiteById.js | 9 ------ queries/admin/website/getWebsiteByShareId.js | 9 ------ queries/admin/website/getWebsiteByUuid.js | 18 ------------ queries/analytics/stats/getRealtimeData.js | 18 ++++++------ queries/index.js | 5 ---- 38 files changed, 145 insertions(+), 169 deletions(-) delete mode 100644 queries/admin/account/getAccountById.js delete mode 100644 queries/admin/account/getAccountByUsername.js delete mode 100644 queries/admin/website/getWebsiteById.js delete mode 100644 queries/admin/website/getWebsiteByShareId.js delete mode 100644 queries/admin/website/getWebsiteByUuid.js diff --git a/components/forms/ChangePasswordForm.js b/components/forms/ChangePasswordForm.js index 4ee657e6..dcad6f17 100644 --- a/components/forms/ChangePasswordForm.js +++ b/components/forms/ChangePasswordForm.js @@ -9,7 +9,7 @@ import FormLayout, { FormRow, } from 'components/layout/FormLayout'; import useApi from 'hooks/useApi'; -import useUser from '../../hooks/useUser'; +import useUser from 'hooks/useUser'; const initialValues = { current_password: '', @@ -43,13 +43,13 @@ export default function ChangePasswordForm({ values, onSave, onClose }) { const { user } = useUser(); const handleSubmit = async values => { - const { ok, data } = await post(`/accounts/${user.userId}/password`, values); + const { ok, error } = await post(`/accounts/${user.accountUuid}/password`, values); if (ok) { onSave(); } else { setMessage( - data || , + error || , ); } }; diff --git a/components/forms/EventDataForm.js b/components/forms/EventDataForm.js index db8e7fbb..e236aa3d 100644 --- a/components/forms/EventDataForm.js +++ b/components/forms/EventDataForm.js @@ -22,7 +22,7 @@ export const filterOptions = [ { label: 'Count', value: 'count' }, { label: 'Average', value: 'avg' }, { label: 'Minimum', value: 'min' }, - { label: 'Maxmimum', value: 'max' }, + { label: 'Maximum', value: 'max' }, { label: 'Sum', value: 'sum' }, ]; diff --git a/components/metrics/RealtimeHeader.js b/components/metrics/RealtimeHeader.js index 40881538..1b93cd2f 100644 --- a/components/metrics/RealtimeHeader.js +++ b/components/metrics/RealtimeHeader.js @@ -9,11 +9,14 @@ import styles from './RealtimeHeader.module.css'; export default function RealtimeHeader({ websites, data, websiteId, onSelect }) { const options = [ - { label: , value: 0 }, + { + label: , + value: null, + }, ].concat( - websites.map(({ name, id }, index) => ({ + websites.map(({ name, websiteUuid }, index) => ({ label: name, - value: id, + value: websiteUuid, divider: index === 0, })), ); diff --git a/components/pages/Dashboard.js b/components/pages/Dashboard.js index bd6a8b3a..70a4d624 100644 --- a/components/pages/Dashboard.js +++ b/components/pages/Dashboard.js @@ -1,6 +1,5 @@ import { useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useRouter } from 'next/router'; import Page from 'components/layout/Page'; import PageHeader from 'components/layout/PageHeader'; import WebsiteList from 'components/pages/WebsiteList'; @@ -16,10 +15,7 @@ const messages = defineMessages({ more: { id: 'label.more', defaultMessage: 'More' }, }); -export default function Dashboard() { - const router = useRouter(); - const { id } = router.query; - const userId = id?.[0]; +export default function Dashboard({ userId }) { const dashboard = useDashboard(); const { showCharts, limit, editing } = dashboard; const [max, setMax] = useState(limit); diff --git a/components/pages/DashboardEdit.js b/components/pages/DashboardEdit.js index 38b1d7d6..0cc6d4e7 100644 --- a/components/pages/DashboardEdit.js +++ b/components/pages/DashboardEdit.js @@ -24,7 +24,7 @@ export default function DashboardEdit({ websites }) { const ordered = useMemo( () => websites - .map(website => ({ ...website, order: order.indexOf(website.websiteId) })) + .map(website => ({ ...website, order: order.indexOf(website.websiteUuid) })) .sort(firstBy('order')), [websites, order], ); @@ -36,7 +36,7 @@ export default function DashboardEdit({ websites }) { const [removed] = orderedWebsites.splice(source.index, 1); orderedWebsites.splice(destination.index, 0, removed); - setOrder(orderedWebsites.map(website => website?.websiteId || 0)); + setOrder(orderedWebsites.map(website => website?.websiteUuid || 0)); } function handleSave() { @@ -76,8 +76,12 @@ export default function DashboardEdit({ websites }) { ref={provided.innerRef} style={{ marginBottom: snapshot.isDraggingOver ? 260 : null }} > - {ordered.map(({ websiteId, name, domain }, index) => ( - + {ordered.map(({ websiteUuid, name, domain }, index) => ( + {(provided, snapshot) => (
n.websiteUuid === websiteUuid); return { - pageviews: filterWebsite(pageviews, websiteId), - sessions: filterWebsite(sessions, websiteId), - events: filterWebsite(events, websiteId), + pageviews: filterWebsite(pageviews, id), + sessions: filterWebsite(sessions, id), + events: filterWebsite(events, id), }; } } return data; - }, [data, websiteId]); + }, [data, websiteUuid]); const countries = useMemo(() => { if (realtimeData?.sessions) { @@ -117,25 +118,20 @@ export default function RealtimeDashboard() {
- +
- + - + diff --git a/components/settings/AccountSettings.js b/components/settings/AccountSettings.js index 2ec378f1..eebdae40 100644 --- a/components/settings/AccountSettings.js +++ b/components/settings/AccountSettings.js @@ -29,13 +29,15 @@ export default function AccountSettings() { const Checkmark = ({ isAdmin }) => (isAdmin ? } size="medium" /> : null); - const DashboardLink = row => ( - - - } /> - - - ); + const DashboardLink = row => { + return ( + + + } /> + + + ); + }; const Buttons = row => ( diff --git a/db/postgresql/migrations/04_add_uuid/migration.sql b/db/postgresql/migrations/04_add_uuid/migration.sql index 21d4cf07..749cef6b 100644 --- a/db/postgresql/migrations/04_add_uuid/migration.sql +++ b/db/postgresql/migrations/04_add_uuid/migration.sql @@ -1,3 +1,5 @@ +-- CreateExtension +CREATE EXTENSION IF NOT EXISTS pgcrypto; -- AlterTable ALTER TABLE "account" ADD COLUMN "account_uuid" UUID NULL; diff --git a/lib/auth.js b/lib/auth.js index 446d5169..93027544 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -1,6 +1,6 @@ import { parseSecureToken, parseToken } from 'next-basics'; -import { getWebsite } from 'queries'; -import { SHARE_TOKEN_HEADER } from 'lib/constants'; +import { getAccount, getWebsite } from 'queries'; +import { SHARE_TOKEN_HEADER, TYPE_ACCOUNT, TYPE_WEBSITE } from 'lib/constants'; import { secret } from 'lib/crypto'; export function getAuthToken(req) { @@ -35,7 +35,7 @@ export function isValidToken(token, validation) { return false; } -export async function allowQuery(req) { +export async function allowQuery(req, type) { const { id } = req.query; const { userId, isAdmin, shareToken } = req.auth ?? {}; @@ -49,9 +49,15 @@ export async function allowQuery(req) { } if (userId) { - const website = await getWebsite({ id }); + if (type === TYPE_WEBSITE) { + const website = await getWebsite({ websiteUuid: id }); - return website && website.userId === userId; + return website && website.userId === userId; + } else if (type === TYPE_ACCOUNT) { + const account = await getAccount({ accountUuid: id }); + + return account && account.accountUuid === id; + } } return false; diff --git a/lib/constants.js b/lib/constants.js index feef540d..8b3ee8d0 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -21,6 +21,9 @@ export const DEFAULT_WEBSITE_LIMIT = 10; export const REALTIME_RANGE = 30; export const REALTIME_INTERVAL = 3000; +export const TYPE_WEBSITE = 'website'; +export const TYPE_ACCOUNT = 'account'; + export const THEME_COLORS = { light: { primary: '#2680eb', diff --git a/lib/session.js b/lib/session.js index acd5b6b0..d1a88768 100644 --- a/lib/session.js +++ b/lib/session.js @@ -4,7 +4,7 @@ import { secret, uuid } from 'lib/crypto'; import redis, { DELETED } from 'lib/redis'; import clickhouse from 'lib/clickhouse'; import { getClientInfo, getJsonBody } from 'lib/request'; -import { createSession, getSessionByUuid, getWebsiteByUuid } from 'queries'; +import { createSession, getSessionByUuid, getWebsite } from 'queries'; export async function getSession(req) { const { payload } = getJsonBody(req); @@ -38,7 +38,7 @@ export async function getSession(req) { // Check database if does not exists in Redis if (!websiteId) { - const website = await getWebsiteByUuid(websiteUuid); + const website = await getWebsite({ websiteUuid }); websiteId = website ? website.id : null; } diff --git a/package.json b/package.json index facf913a..e586774f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "1.39.1", + "version": "1.39.2", "description": "A simple, fast, privacy-focused alternative to Google Analytics.", "author": "Mike Cao ", "license": "MIT", diff --git a/pages/api/accounts/[id]/password.js b/pages/api/accounts/[id]/password.js index 3a46c56a..89649c20 100644 --- a/pages/api/accounts/[id]/password.js +++ b/pages/api/accounts/[id]/password.js @@ -1,4 +1,4 @@ -import { getAccountById, updateAccount } from 'queries'; +import { getAccount, updateAccount } from 'queries'; import { useAuth } from 'lib/middleware'; import { badRequest, @@ -8,21 +8,21 @@ import { checkPassword, hashPassword, } from 'next-basics'; +import { allowQuery } from 'lib/auth'; +import { TYPE_ACCOUNT } from 'lib/constants'; export default async (req, res) => { await useAuth(req, res); - const { userId: currentUserId, isAdmin: currentUserIsAdmin } = req.auth; const { current_password, new_password } = req.body; - const { id } = req.query; - const userId = +id; + const { id: accountUuid } = req.query; - if (!currentUserIsAdmin && userId !== currentUserId) { + if (!(await allowQuery(req, TYPE_ACCOUNT))) { return unauthorized(res); } if (req.method === 'POST') { - const account = await getAccountById(userId); + const account = await getAccount({ accountUuid }); if (!checkPassword(current_password, account.password)) { return badRequest(res, 'Current password is incorrect'); @@ -30,7 +30,7 @@ export default async (req, res) => { const password = hashPassword(new_password); - const updated = await updateAccount(userId, { password }); + const updated = await updateAccount({ password }, { accountUuid }); return ok(res, updated); } diff --git a/pages/api/accounts/index.js b/pages/api/accounts/index.js index aa52ca55..22248ed4 100644 --- a/pages/api/accounts/index.js +++ b/pages/api/accounts/index.js @@ -1,7 +1,7 @@ import { ok, unauthorized, methodNotAllowed, badRequest, hashPassword } from 'next-basics'; import { useAuth } from 'lib/middleware'; import { uuid } from 'lib/crypto'; -import { createAccount, getAccountByUsername, getAccounts } from 'queries'; +import { createAccount, getAccount, getAccounts } from 'queries'; export default async (req, res) => { await useAuth(req, res); @@ -21,9 +21,9 @@ export default async (req, res) => { if (req.method === 'POST') { const { username, password, account_uuid } = req.body; - const accountByUsername = await getAccountByUsername(username); + const account = await getAccount({ username }); - if (accountByUsername) { + if (account) { return badRequest(res, 'Account already exists'); } diff --git a/pages/api/auth/login.js b/pages/api/auth/login.js index d5379a22..aa4803d8 100644 --- a/pages/api/auth/login.js +++ b/pages/api/auth/login.js @@ -1,5 +1,5 @@ import { ok, unauthorized, badRequest, checkPassword, createSecureToken } from 'next-basics'; -import { getAccountByUsername } from 'queries/admin/account/getAccountByUsername'; +import { getAccount } from 'queries'; import { secret } from 'lib/crypto'; export default async (req, res) => { @@ -9,7 +9,7 @@ export default async (req, res) => { return badRequest(res); } - const account = await getAccountByUsername(username); + const account = await getAccount({ username }); if (account && checkPassword(password, account.password)) { const { id, username, isAdmin, accountUuid } = account; diff --git a/pages/api/realtime/init.js b/pages/api/realtime/init.js index a7e175a5..9a9a4297 100644 --- a/pages/api/realtime/init.js +++ b/pages/api/realtime/init.js @@ -10,7 +10,7 @@ export default async (req, res) => { if (req.method === 'GET') { const { userId } = req.auth; - const websites = await getUserWebsites(userId); + const websites = await getUserWebsites({ userId }); const ids = websites.map(({ websiteUuid }) => websiteUuid); const token = createToken({ websites: ids }, secret()); const data = await getRealtimeData(ids, subMinutes(new Date(), 30)); diff --git a/pages/api/share/[id].js b/pages/api/share/[id].js index a89829fa..4ff6b81c 100644 --- a/pages/api/share/[id].js +++ b/pages/api/share/[id].js @@ -1,4 +1,4 @@ -import { getWebsiteByShareId } from 'queries'; +import { getWebsite } from 'queries'; import { ok, notFound, methodNotAllowed, createToken } from 'next-basics'; import { secret } from 'lib/crypto'; @@ -6,7 +6,7 @@ export default async (req, res) => { const { id } = req.query; if (req.method === 'GET') { - const website = await getWebsiteByShareId(id); + const website = await getWebsite({ shareId: id }); if (website) { const { websiteUuid } = website; diff --git a/pages/api/websites/[id]/active.js b/pages/api/websites/[id]/active.js index 10e73ea8..59af938e 100644 --- a/pages/api/websites/[id]/active.js +++ b/pages/api/websites/[id]/active.js @@ -2,13 +2,14 @@ import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { allowQuery } from 'lib/auth'; import { useAuth, useCors } from 'lib/middleware'; import { getActiveVisitors } from 'queries'; +import { TYPE_WEBSITE } from 'lib/constants'; export default async (req, res) => { await useCors(req, res); await useAuth(req, res); if (req.method === 'GET') { - if (!(await allowQuery(req))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } diff --git a/pages/api/websites/[id]/eventdata.js b/pages/api/websites/[id]/eventdata.js index 86a17b77..0e6ad2e9 100644 --- a/pages/api/websites/[id]/eventdata.js +++ b/pages/api/websites/[id]/eventdata.js @@ -3,13 +3,14 @@ import { getEventData } from 'queries'; import { ok, badRequest, methodNotAllowed, unauthorized } from 'next-basics'; import { allowQuery } from 'lib/auth'; import { useAuth, useCors } from 'lib/middleware'; +import { TYPE_WEBSITE } from 'lib/constants'; export default async (req, res) => { await useCors(req, res); await useAuth(req, res); if (req.method === 'POST') { - if (!(await allowQuery(req))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } diff --git a/pages/api/websites/[id]/events.js b/pages/api/websites/[id]/events.js index 192e284a..da88794e 100644 --- a/pages/api/websites/[id]/events.js +++ b/pages/api/websites/[id]/events.js @@ -3,6 +3,7 @@ import { getEventMetrics } from 'queries'; import { ok, badRequest, methodNotAllowed, unauthorized } from 'next-basics'; import { allowQuery } from 'lib/auth'; import { useAuth, useCors } from 'lib/middleware'; +import { TYPE_WEBSITE } from 'lib/constants'; const unitTypes = ['year', 'month', 'hour', 'day']; @@ -11,7 +12,7 @@ export default async (req, res) => { await useAuth(req, res); if (req.method === 'GET') { - if (!(await allowQuery(req))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } diff --git a/pages/api/websites/[id]/index.js b/pages/api/websites/[id]/index.js index d802982a..539a3288 100644 --- a/pages/api/websites/[id]/index.js +++ b/pages/api/websites/[id]/index.js @@ -2,19 +2,20 @@ import { allowQuery } from 'lib/auth'; import { useAuth, useCors } from 'lib/middleware'; import { getRandomChars, methodNotAllowed, ok, serverError, unauthorized } from 'next-basics'; import { deleteWebsite, getAccount, getWebsite, updateWebsite } from 'queries'; +import { TYPE_WEBSITE } from 'lib/constants'; export default async (req, res) => { await useCors(req, res); await useAuth(req, res); - const { id: websiteId } = req.query; + const { id: websiteUuid } = req.query; - if (!(await allowQuery(req))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } if (req.method === 'GET') { - const website = await getWebsite({ websiteUuid: websiteId }); + const website = await getWebsite({ websiteUuid }); return ok(res, website); } @@ -32,7 +33,7 @@ export default async (req, res) => { } } - const website = await getWebsite({ websiteUuid: websiteId }); + const website = await getWebsite({ websiteUuid }); const newShareId = enableShareUrl ? website.shareId || getRandomChars(8) : null; @@ -44,7 +45,7 @@ export default async (req, res) => { shareId: shareId ? shareId : newShareId, userId: account ? account.id : +owner || undefined, }, - { websiteUuid: websiteId }, + { websiteUuid }, ); } catch (e) { if (e.message.includes('Unique constraint') && e.message.includes('share_id')) { @@ -56,11 +57,11 @@ export default async (req, res) => { } if (req.method === 'DELETE') { - if (!(await allowQuery(req, true))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } - await deleteWebsite(websiteId); + await deleteWebsite(websiteUuid); return ok(res); } diff --git a/pages/api/websites/[id]/metrics.js b/pages/api/websites/[id]/metrics.js index e0eab028..0aafe7d3 100644 --- a/pages/api/websites/[id]/metrics.js +++ b/pages/api/websites/[id]/metrics.js @@ -1,8 +1,8 @@ import { allowQuery } from 'lib/auth'; -import { FILTER_IGNORED } from 'lib/constants'; +import { FILTER_IGNORED, TYPE_WEBSITE } from 'lib/constants'; import { useAuth, useCors } from 'lib/middleware'; import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics'; -import { getPageviewMetrics, getSessionMetrics, getWebsiteByUuid } from 'queries'; +import { getPageviewMetrics, getSessionMetrics, getWebsite } from 'queries'; const sessionColumns = ['browser', 'os', 'device', 'screen', 'country', 'language']; const pageviewColumns = ['url', 'referrer', 'query']; @@ -38,7 +38,7 @@ export default async (req, res) => { await useAuth(req, res); if (req.method === 'GET') { - if (!(await allowQuery(req))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } @@ -94,7 +94,7 @@ export default async (req, res) => { let domain; if (type === 'referrer') { - const website = await getWebsiteByUuid(websiteId); + const website = await getWebsite({ websiteUuid: websiteId }); if (!website) { return badRequest(res); diff --git a/pages/api/websites/[id]/pageviews.js b/pages/api/websites/[id]/pageviews.js index 9e05417b..5b628e3a 100644 --- a/pages/api/websites/[id]/pageviews.js +++ b/pages/api/websites/[id]/pageviews.js @@ -3,6 +3,7 @@ import { getPageviewStats } from 'queries'; import { ok, badRequest, methodNotAllowed, unauthorized } from 'next-basics'; import { allowQuery } from 'lib/auth'; import { useAuth, useCors } from 'lib/middleware'; +import { TYPE_WEBSITE } from 'lib/constants'; const unitTypes = ['year', 'month', 'hour', 'day']; @@ -11,7 +12,7 @@ export default async (req, res) => { await useAuth(req, res); if (req.method === 'GET') { - if (!(await allowQuery(req))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } diff --git a/pages/api/websites/[id]/reset.js b/pages/api/websites/[id]/reset.js index fe527ad4..0dde02df 100644 --- a/pages/api/websites/[id]/reset.js +++ b/pages/api/websites/[id]/reset.js @@ -2,6 +2,7 @@ import { resetWebsite } from 'queries'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { allowQuery } from 'lib/auth'; import { useAuth, useCors } from 'lib/middleware'; +import { TYPE_WEBSITE } from 'lib/constants'; export default async (req, res) => { await useCors(req, res); @@ -10,7 +11,7 @@ export default async (req, res) => { const { id: websiteId } = req.query; if (req.method === 'POST') { - if (!(await allowQuery(req))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } diff --git a/pages/api/websites/[id]/stats.js b/pages/api/websites/[id]/stats.js index 596ebc90..2c5b0156 100644 --- a/pages/api/websites/[id]/stats.js +++ b/pages/api/websites/[id]/stats.js @@ -2,13 +2,14 @@ import { getWebsiteStats } from 'queries'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { allowQuery } from 'lib/auth'; import { useAuth, useCors } from 'lib/middleware'; +import { TYPE_WEBSITE } from 'lib/constants'; export default async (req, res) => { await useCors(req, res); await useAuth(req, res); if (req.method === 'GET') { - if (!(await allowQuery(req))) { + if (!(await allowQuery(req, TYPE_WEBSITE))) { return unauthorized(res); } diff --git a/pages/api/websites/index.js b/pages/api/websites/index.js index 9fade8c2..36d38660 100644 --- a/pages/api/websites/index.js +++ b/pages/api/websites/index.js @@ -6,15 +6,16 @@ import { uuid } from 'lib/crypto'; export default async (req, res) => { await useAuth(req, res); - const { userId: currentUserId, isAdmin, accountUuid } = req.auth; const { user_id, include_all } = req.query; + const { userId: currentUserId, isAdmin } = req.auth; + const accountUuid = user_id || req.auth.accountUuid; let account; if (accountUuid) { - account = await getAccount({ accountUuid: accountUuid }); + account = await getAccount({ accountUuid }); } - const userId = account ? account.id : +user_id; + const userId = account ? account.id : user_id; if (req.method === 'GET') { if (userId && userId !== currentUserId && !isAdmin) { @@ -24,7 +25,7 @@ export default async (req, res) => { const websites = isAdmin && include_all ? await getAllWebsites() - : await getUserWebsites(userId || currentUserId); + : await getUserWebsites({ userId: account.id }); return ok(res, websites); } diff --git a/pages/dashboard/[[...id]].js b/pages/dashboard/[[...id]].js index 452a425e..7c762097 100644 --- a/pages/dashboard/[[...id]].js +++ b/pages/dashboard/[[...id]].js @@ -2,17 +2,27 @@ import React from 'react'; import Layout from 'components/layout/Layout'; import Dashboard from 'components/pages/Dashboard'; import useRequireLogin from 'hooks/useRequireLogin'; +import { useRouter } from 'next/router'; +import useUser from 'hooks/useUser'; export default function DashboardPage() { + const { + query: { id }, + isReady, + asPath, + } = useRouter(); const { loading } = useRequireLogin(); + const user = useUser(); - if (loading) { + if (!user || !isReady || loading) { return null; } + const userId = id?.[0]; + return ( - + ); } diff --git a/queries/admin/account/getAccountById.js b/queries/admin/account/getAccountById.js deleted file mode 100644 index eee1b76a..00000000 --- a/queries/admin/account/getAccountById.js +++ /dev/null @@ -1,9 +0,0 @@ -import prisma from 'lib/prisma'; - -export async function getAccountById(userId) { - return prisma.client.account.findUnique({ - where: { - id: userId, - }, - }); -} diff --git a/queries/admin/account/getAccountByUsername.js b/queries/admin/account/getAccountByUsername.js deleted file mode 100644 index ff64c8ce..00000000 --- a/queries/admin/account/getAccountByUsername.js +++ /dev/null @@ -1,9 +0,0 @@ -import prisma from 'lib/prisma'; - -export async function getAccountByUsername(username) { - return prisma.client.account.findUnique({ - where: { - username, - }, - }); -} diff --git a/queries/admin/account/getAccounts.js b/queries/admin/account/getAccounts.js index 71d5e4c5..ceca2582 100644 --- a/queries/admin/account/getAccounts.js +++ b/queries/admin/account/getAccounts.js @@ -14,6 +14,7 @@ export async function getAccounts() { isAdmin: true, createdAt: true, updatedAt: true, + accountUuid: true, }, }); } diff --git a/queries/admin/website/deleteWebsite.js b/queries/admin/website/deleteWebsite.js index b5e2ff76..f08dc63e 100644 --- a/queries/admin/website/deleteWebsite.js +++ b/queries/admin/website/deleteWebsite.js @@ -1,27 +1,24 @@ import prisma from 'lib/prisma'; import redis, { DELETED } from 'lib/redis'; -import { getWebsiteByUuid } from 'queries'; -export async function deleteWebsite(websiteId) { +export async function deleteWebsite(websiteUuid) { const { client, transaction } = prisma; - const { websiteUuid } = await getWebsiteByUuid(websiteId); - return transaction([ client.pageview.deleteMany({ - where: { session: { website: { websiteUuid: websiteId } } }, + where: { session: { website: { websiteUuid } } }, }), client.eventData.deleteMany({ - where: { event: { session: { website: { websiteUuid: websiteId } } } }, + where: { event: { session: { website: { websiteUuid } } } }, }), client.event.deleteMany({ - where: { session: { website: { websiteUuid: websiteId } } }, + where: { session: { website: { websiteUuid } } }, }), client.session.deleteMany({ - where: { website: { websiteUuid: websiteId } }, + where: { website: { websiteUuid } }, }), client.website.delete({ - where: { websiteUuid: websiteId }, + where: { websiteUuid }, }), ]).then(async res => { if (redis.client) { diff --git a/queries/admin/website/getUserWebsites.js b/queries/admin/website/getUserWebsites.js index c1a9d559..9a725ec2 100644 --- a/queries/admin/website/getUserWebsites.js +++ b/queries/admin/website/getUserWebsites.js @@ -1,10 +1,8 @@ import prisma from 'lib/prisma'; -export async function getUserWebsites(userId) { +export async function getUserWebsites(where) { return prisma.client.website.findMany({ - where: { - userId, - }, + where, orderBy: { name: 'asc', }, diff --git a/queries/admin/website/getWebsite.js b/queries/admin/website/getWebsite.js index 83c3e83a..d33c9ead 100644 --- a/queries/admin/website/getWebsite.js +++ b/queries/admin/website/getWebsite.js @@ -1,7 +1,16 @@ import prisma from 'lib/prisma'; +import redis from 'lib/redis'; export async function getWebsite(where) { - return prisma.client.website.findUnique({ - where, - }); + return prisma.client.website + .findUnique({ + where, + }) + .then(async data => { + if (redis.enabled && data) { + await redis.client.set(`website:${data.websiteUuid}`, data.id); + } + + return data; + }); } diff --git a/queries/admin/website/getWebsiteById.js b/queries/admin/website/getWebsiteById.js deleted file mode 100644 index f486bd8f..00000000 --- a/queries/admin/website/getWebsiteById.js +++ /dev/null @@ -1,9 +0,0 @@ -import prisma from 'lib/prisma'; - -export async function getWebsiteById(websiteId) { - return prisma.client.website.findUnique({ - where: { - id: websiteId, - }, - }); -} diff --git a/queries/admin/website/getWebsiteByShareId.js b/queries/admin/website/getWebsiteByShareId.js deleted file mode 100644 index bfc99ce7..00000000 --- a/queries/admin/website/getWebsiteByShareId.js +++ /dev/null @@ -1,9 +0,0 @@ -import prisma from 'lib/prisma'; - -export async function getWebsiteByShareId(shareId) { - return prisma.client.website.findUnique({ - where: { - shareId, - }, - }); -} diff --git a/queries/admin/website/getWebsiteByUuid.js b/queries/admin/website/getWebsiteByUuid.js deleted file mode 100644 index 158d357a..00000000 --- a/queries/admin/website/getWebsiteByUuid.js +++ /dev/null @@ -1,18 +0,0 @@ -import prisma from 'lib/prisma'; -import redis from 'lib/redis'; - -export async function getWebsiteByUuid(websiteUuid) { - return prisma.client.website - .findUnique({ - where: { - websiteUuid, - }, - }) - .then(async res => { - if (redis.client && res) { - await redis.client.set(`website:${res.websiteUuid}`, res.id); - } - - return res; - }); -} diff --git a/queries/analytics/stats/getRealtimeData.js b/queries/analytics/stats/getRealtimeData.js index 9e7eb673..659f6145 100644 --- a/queries/analytics/stats/getRealtimeData.js +++ b/queries/analytics/stats/getRealtimeData.js @@ -10,19 +10,19 @@ export async function getRealtimeData(websites, time) { ]); return { - pageviews: pageviews.map(({ pageviewId, ...props }) => ({ - __id: `p${pageviewId}`, - pageviewId, + pageviews: pageviews.map(({ id, ...props }) => ({ + __id: `p${id}`, + pageviewId: id, ...props, })), - sessions: sessions.map(({ sessionId, ...props }) => ({ - __id: `s${sessionId}`, - sessionId, + sessions: sessions.map(({ id, ...props }) => ({ + __id: `s${id}`, + sessionId: id, ...props, })), - events: events.map(({ eventId, ...props }) => ({ - __id: `e${eventId}`, - eventId, + events: events.map(({ id, ...props }) => ({ + __id: `e${id}`, + eventId: id, ...props, })), timestamp: Date.now(), diff --git a/queries/index.js b/queries/index.js index abff147a..a570af65 100644 --- a/queries/index.js +++ b/queries/index.js @@ -1,8 +1,6 @@ export * from './admin/account/createAccount'; export * from './admin/account/deleteAccount'; export * from './admin/account/getAccount'; -export * from './admin/account/getAccountById'; -export * from './admin/account/getAccountByUsername'; export * from './admin/account/getAccounts'; export * from './admin/account/updateAccount'; export * from './admin/website/createWebsite'; @@ -10,9 +8,6 @@ export * from './admin/website/deleteWebsite'; export * from './admin/website/getAllWebsites'; export * from './admin/website/getUserWebsites'; export * from './admin/website/getWebsite'; -export * from './admin/website/getWebsiteById'; -export * from './admin/website/getWebsiteByShareId'; -export * from './admin/website/getWebsiteByUuid'; export * from './admin/website/resetWebsite'; export * from './admin/website/updateWebsite'; export * from './analytics/event/getEventMetrics';