diff --git a/.eslintrc.json b/.eslintrc.json
index f279e226..de639b85 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -20,7 +20,7 @@
"next"
],
- "plugins": ["@typescript-eslint","prettier"],
+ "plugins": ["@typescript-eslint", "prettier"],
"settings": {
"import/resolver": {
"alias": {
@@ -46,7 +46,9 @@
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"import/no-anonymous-default-export": "off",
- "@next/next/no-img-element": "off"
+ "@next/next/no-img-element": "off",
+ "@typescript-eslint/no-empty-function": "off",
+ "@typescript-eslint/no-explicit-any": "off"
},
"globals": {
"React": "writable"
diff --git a/components/input/RefreshButton.js b/components/input/RefreshButton.js
index b223fecf..635a6270 100644
--- a/components/input/RefreshButton.js
+++ b/components/input/RefreshButton.js
@@ -1,6 +1,6 @@
import { useState, useEffect, useCallback } from 'react';
import { useIntl } from 'react-intl';
-import { Button, Icon, Tooltip } from '../react-basics';
+import { Button, Icon, Tooltip } from 'react-basics';
import useStore from 'store/queries';
import { setDateRange } from 'store/websites';
import useDateRange from 'hooks/useDateRange';
diff --git a/components/pages/websites/WebsiteDetails.js b/components/pages/websites/WebsiteDetails.js
index 33cc179b..3e758599 100644
--- a/components/pages/websites/WebsiteDetails.js
+++ b/components/pages/websites/WebsiteDetails.js
@@ -3,13 +3,12 @@ import { Icons, Loading } from 'react-basics';
import { useIntl } from 'react-intl';
import Link from 'next/link';
import classNames from 'classnames';
-import MenuLayout from 'components/layout/MenuLayout';
import Page from 'components/layout/Page';
import WebsiteChart from 'components/metrics/WebsiteChart';
import useApi from 'hooks/useApi';
import usePageQuery from 'hooks/usePageQuery';
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
-import { labels, messages } from 'components/messages';
+import { labels } from 'components/messages';
import styles from './WebsiteDetails.module.css';
import WebsiteTableView from './WebsiteTableView';
import WebsiteMenuView from './WebsiteMenuView';
@@ -27,19 +26,6 @@ export default function WebsiteDetails({ websiteId }) {
query: { view },
} = usePageQuery();
- const BackButton = () => (
-
- }
- sizes="small"
- >
- {formatMessage(labels.back)}
-
-
- );
-
function handleDataLoad() {
if (!chartLoaded) {
setTimeout(() => setChartLoaded(true), DEFAULT_ANIMATION_DURATION);
diff --git a/components/pages/websites/WebsiteMenuView.js b/components/pages/websites/WebsiteMenuView.js
index f1a1b7fb..6b1f6627 100644
--- a/components/pages/websites/WebsiteMenuView.js
+++ b/components/pages/websites/WebsiteMenuView.js
@@ -1,4 +1,4 @@
-import { Row, Column, Menu, Item, Icon, Text, Button } from 'react-basics';
+import { Row, Column, Menu, Item, Icon, Button } from 'react-basics';
import Link from 'next/link';
import BrowsersTable from 'components/metrics/BrowsersTable';
import CountriesTable from 'components/metrics/CountriesTable';
diff --git a/lib/types.ts b/lib/types.ts
index 9dc01719..8b08a343 100644
--- a/lib/types.ts
+++ b/lib/types.ts
@@ -39,8 +39,6 @@ export interface Share {
token: string;
}
-export interface Empty {}
-
export interface WebsiteActive {
x: number;
}
diff --git a/pages/api/collect.ts b/pages/api/collect.ts
index 68c4afb2..63bbdf1b 100644
--- a/pages/api/collect.ts
+++ b/pages/api/collect.ts
@@ -1,12 +1,12 @@
-const { Resolver } = require('dns').promises;
import isbot from 'isbot';
import ipaddr from 'ipaddr.js';
-import { createToken, unauthorized, send, badRequest, forbidden } from 'next-basics';
+import { createToken, ok, send, badRequest, forbidden } from 'next-basics';
import { savePageView, saveEvent } from 'queries';
import { useCors, useSession } from 'lib/middleware';
import { getJsonBody, getIpAddress } from 'lib/detect';
import { secret } from 'lib/crypto';
import { NextApiRequest, NextApiResponse } from 'next';
+import { Resolver } from 'dns/promises';
export interface NextApiRequestCollect extends NextApiRequest {
session: {
@@ -26,7 +26,7 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
await useCors(req, res);
if (isbot(req.headers['user-agent']) && !process.env.DISABLE_BOT_CHECK) {
- return unauthorized(res);
+ return ok(res);
}
const { type, payload } = getJsonBody(req);
@@ -61,7 +61,7 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
.map(n => resolver.resolve4(n.trim()).catch(() => {}));
await Promise.all(promises).then(resolvedIps => {
- ips.push(...resolvedIps.filter(n => n).flatMap(n => n));
+ ips.push(...resolvedIps.filter(n => n).flatMap(n => n as string[]));
});
}
diff --git a/pages/api/me/websites.ts b/pages/api/me/websites.ts
index e69de29b..15ea2485 100644
--- a/pages/api/me/websites.ts
+++ b/pages/api/me/websites.ts
@@ -0,0 +1,31 @@
+import { useAuth, useCors } from 'lib/middleware';
+import { NextApiRequestQueryBody } from 'lib/types';
+import { NextApiResponse } from 'next';
+import { methodNotAllowed, ok } from 'next-basics';
+import { getUserWebsites } from 'queries';
+
+export interface WebsitesRequestBody {
+ name: string;
+ domain: string;
+ shareId: string;
+}
+
+export default async (
+ req: NextApiRequestQueryBody,
+ res: NextApiResponse,
+) => {
+ await useCors(req, res);
+ await useAuth(req, res);
+
+ const {
+ user: { id: userId },
+ } = req.auth;
+
+ if (req.method === 'GET') {
+ const websites = await getUserWebsites(userId);
+
+ return ok(res, websites);
+ }
+
+ return methodNotAllowed(res);
+};
diff --git a/pages/api/users/[id]/websites.ts b/pages/api/users/[id]/websites.ts
index 7a6f7dc1..c8b874bb 100644
--- a/pages/api/users/[id]/websites.ts
+++ b/pages/api/users/[id]/websites.ts
@@ -1,63 +1,34 @@
-import { Prisma } from '@prisma/client';
-import { canCreateWebsite } from 'lib/auth';
-import { uuid } from 'lib/crypto';
import { useAuth, useCors } from 'lib/middleware';
import { NextApiRequestQueryBody } from 'lib/types';
import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
-import { createWebsite, getUserWebsites } from 'queries';
-
-export interface WebsitesRequestQuery {}
+import { getUserWebsites } from 'queries';
export interface WebsitesRequestBody {
name: string;
domain: string;
shareId: string;
- teamId?: string;
}
export default async (
- req: NextApiRequestQueryBody,
+ req: NextApiRequestQueryBody,
res: NextApiResponse,
) => {
await useCors(req, res);
await useAuth(req, res);
- const {
- user: { id: userId },
- } = req.auth;
- const { id } = req.query;
+ const { user } = req.auth;
+ const { id: userId } = req.query;
if (req.method === 'GET') {
- const websites = await getUserWebsites(id as string);
+ if (!user.isAdmin && user.id !== userId) {
+ return unauthorized(res);
+ }
+
+ const websites = await getUserWebsites(userId);
return ok(res, websites);
}
- if (req.method === 'POST') {
- const { name, domain, shareId, teamId } = req.body;
-
- if (!(await canCreateWebsite(req.auth, teamId))) {
- return unauthorized(res);
- }
-
- const data: Prisma.WebsiteUncheckedCreateInput = {
- id: uuid(),
- name,
- domain,
- shareId,
- };
-
- if (teamId) {
- data.teamId = teamId;
- } else {
- data.userId = userId;
- }
-
- const website = await createWebsite(data);
-
- return ok(res, website);
- }
-
return methodNotAllowed(res);
};
diff --git a/pages/api/websites/[id]/metrics.ts b/pages/api/websites/[id]/metrics.ts
index c6375f08..94358076 100644
--- a/pages/api/websites/[id]/metrics.ts
+++ b/pages/api/websites/[id]/metrics.ts
@@ -90,15 +90,15 @@ export default async (
});
if (type === 'language') {
- let combined = {};
+ const combined = {};
- for (let { x, y } of data) {
- x = String(x).toLowerCase().split('-')[0];
+ for (const { x, y } of data) {
+ const key = String(x).toLowerCase().split('-')[0];
- if (!combined[x]) {
- combined[x] = { x, y };
+ if (!combined[key]) {
+ combined[key] = { x, y };
} else {
- combined[x].y += y;
+ combined[key].y += y;
}
}
diff --git a/pages/api/websites/index.ts b/pages/api/websites/index.ts
index b1e3204d..52c3ba35 100644
--- a/pages/api/websites/index.ts
+++ b/pages/api/websites/index.ts
@@ -6,8 +6,6 @@ import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
import { createWebsite, getUserWebsites } from 'queries';
-export interface WebsitesRequestQuery {}
-
export interface WebsitesRequestBody {
name: string;
domain: string;
@@ -16,7 +14,7 @@ export interface WebsitesRequestBody {
}
export default async (
- req: NextApiRequestQueryBody,
+ req: NextApiRequestQueryBody,
res: NextApiResponse,
) => {
await useCors(req, res);