diff --git a/components/common/ConfirmDeleteForm.js b/components/common/ConfirmDeleteForm.js
new file mode 100644
index 00000000..3496a305
--- /dev/null
+++ b/components/common/ConfirmDeleteForm.js
@@ -0,0 +1,29 @@
+import { useState } from 'react';
+import { Button, LoadingButton, Form, FormButtons } from 'react-basics';
+import useMessages from 'hooks/useMessages';
+
+export function ConfirmDeleteForm({ name, onConfirm, onClose }) {
+ const [loading, setLoading] = useState(false);
+ const { formatMessage, labels, messages, FormattedMessage } = useMessages();
+
+ const handleConfirm = () => {
+ setLoading(true);
+ onConfirm();
+ };
+
+ return (
+
+ );
+}
+
+export default ConfirmDeleteForm;
diff --git a/components/common/LinkButton.js b/components/common/LinkButton.js
new file mode 100644
index 00000000..8c050147
--- /dev/null
+++ b/components/common/LinkButton.js
@@ -0,0 +1,12 @@
+import Link from 'next/link';
+import { Icon, Icons, Text } from 'react-basics';
+import styles from './LinkButton.module.css';
+
+export default function LinkButton({ href, icon, children }) {
+ return (
+
+ {icon || }
+ {children}
+
+ );
+}
diff --git a/components/common/LinkButton.module.css b/components/common/LinkButton.module.css
new file mode 100644
index 00000000..ae8a3b62
--- /dev/null
+++ b/components/common/LinkButton.module.css
@@ -0,0 +1,28 @@
+.button {
+ display: flex;
+ align-items: center;
+ align-self: flex-start;
+ white-space: nowrap;
+ gap: var(--size200);
+ font-family: inherit;
+ color: var(--base900);
+ background: var(--base100);
+ border: 1px solid transparent;
+ border-radius: var(--border-radius);
+ min-height: var(--base-height);
+ padding: 0 var(--size600);
+ position: relative;
+ cursor: pointer;
+}
+
+.button:hover {
+ background: var(--base200);
+}
+
+.button:active {
+ background: var(--base300);
+}
+
+.button:visited {
+ color: var(--base900);
+}
diff --git a/components/pages/reports/ReportsTable.js b/components/pages/reports/ReportsTable.js
index bcc97204..244740e1 100644
--- a/components/pages/reports/ReportsTable.js
+++ b/components/pages/reports/ReportsTable.js
@@ -1,9 +1,12 @@
-import Link from 'next/link';
-import { Button, Text, Icon, Icons } from 'react-basics';
+import { useState } from 'react';
+import { Flexbox, Icon, Icons, Text, Button, Modal } from 'react-basics';
+import LinkButton from 'components/common/LinkButton';
import SettingsTable from 'components/common/SettingsTable';
-import useMessages from 'hooks/useMessages';
+import ConfirmDeleteForm from 'components/common/ConfirmDeleteForm';
+import { useMessages } from 'hooks';
-export function ReportsTable({ data = [] }) {
+export function ReportsTable({ data = [], onDelete = () => {} }) {
+ const [report, setReport] = useState(null);
const { formatMessage, labels } = useMessages();
const columns = [
@@ -13,23 +16,39 @@ export function ReportsTable({ data = [] }) {
{ name: 'action', label: ' ' },
];
- return (
-
- {row => {
- const { id } = row;
+ const handleConfirm = () => {
+ onDelete(report.id);
+ };
- return (
-
-
-
- );
- }}
-
+ return (
+ <>
+
+ {row => {
+ const { id } = row;
+
+ return (
+
+ {formatMessage(labels.view)}
+
+
+ );
+ }}
+
+ {report && (
+
+ setReport(null)}
+ />
+
+ )}
+ >
);
}
diff --git a/components/pages/websites/WebsiteReportsPage.js b/components/pages/websites/WebsiteReportsPage.js
index b6f41bac..56927028 100644
--- a/components/pages/websites/WebsiteReportsPage.js
+++ b/components/pages/websites/WebsiteReportsPage.js
@@ -7,7 +7,11 @@ import WebsiteHeader from './WebsiteHeader';
export function WebsiteReportsPage({ websiteId }) {
const { formatMessage, labels } = useMessages();
- const { reports, error, isLoading } = useReports(websiteId);
+ const { reports, error, isLoading, deleteReport } = useReports(websiteId);
+
+ const handleDelete = async id => {
+ await deleteReport(id);
+ };
return (
@@ -22,7 +26,7 @@ export function WebsiteReportsPage({ websiteId }) {
-
+
);
}
diff --git a/hooks/useReports.js b/hooks/useReports.js
index 90aa5cf5..f4369eec 100644
--- a/hooks/useReports.js
+++ b/hooks/useReports.js
@@ -1,10 +1,23 @@
+import { useState } from 'react';
import useApi from './useApi';
export function useReports(websiteId) {
- const { get, useQuery } = useApi();
- const { data, error, isLoading } = useQuery(['reports'], () => get(`/reports`, { websiteId }));
+ const [modified, setModified] = useState(Date.now());
+ const { get, useQuery, del, useMutation } = useApi();
+ const { mutate } = useMutation(reportId => del(`/reports/${reportId}`));
+ const { data, error, isLoading } = useQuery(['reports:website', { websiteId, modified }], () =>
+ get(`/reports`, { websiteId }),
+ );
- return { reports: data, error, isLoading };
+ const deleteReport = id => {
+ mutate(id, {
+ onSuccess: () => {
+ setModified(Date.now());
+ },
+ });
+ };
+
+ return { reports: data, error, isLoading, deleteReport };
}
export default useReports;
diff --git a/lib/auth.ts b/lib/auth.ts
index 04585943..10f7fbca 100644
--- a/lib/auth.ts
+++ b/lib/auth.ts
@@ -2,16 +2,9 @@ import { Report } from '@prisma/client';
import redis from '@umami/redis-client';
import debug from 'debug';
import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER } from 'lib/constants';
-import { secret, isUuid } from 'lib/crypto';
-import {
- createSecureToken,
- ensureArray,
- getRandomChars,
- parseSecureToken,
- parseToken,
-} from 'next-basics';
-import { getTeamUser } from 'queries';
-import { getTeamWebsite, getTeamWebsiteByTeamMemberId } from 'queries/admin/teamWebsite';
+import { secret } from 'lib/crypto';
+import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics';
+import { getTeamUser, getTeamWebsite, findTeamWebsiteByUserId } from 'queries';
import { loadWebsite } from './load';
import { Auth } from './types';
@@ -37,15 +30,6 @@ export function getAuthToken(req) {
}
}
-export function parseAuthToken(req) {
- try {
- return parseSecureToken(getAuthToken(req), secret());
- } catch (e) {
- log(e);
- return null;
- }
-}
-
export function parseShareToken(req) {
try {
return parseToken(req.headers[SHARE_TOKEN_HEADER], secret());
@@ -55,21 +39,6 @@ export function parseShareToken(req) {
}
}
-export function isValidToken(token, validation) {
- try {
- if (typeof validation === 'object') {
- return !Object.keys(validation).find(key => token[key] !== validation[key]);
- } else if (typeof validation === 'function') {
- return validation(token);
- }
- } catch (e) {
- log(e);
- return false;
- }
-
- return false;
-}
-
export async function canViewWebsite({ user, shareToken }: Auth, websiteId: string) {
if (user?.isAdmin) {
return true;
@@ -79,19 +48,13 @@ export async function canViewWebsite({ user, shareToken }: Auth, websiteId: stri
return true;
}
- const teamWebsite = await getTeamWebsiteByTeamMemberId(websiteId, user.id);
+ const website = await loadWebsite(websiteId);
- if (teamWebsite) {
+ if (user.id === website?.userId) {
return true;
}
- const website = await loadWebsite(websiteId);
-
- if (website.userId) {
- return user.id === website.userId;
- }
-
- return false;
+ return !!(await findTeamWebsiteByUserId(websiteId, user.id));
}
export async function canCreateWebsite({ user }: Auth) {
@@ -107,17 +70,9 @@ export async function canUpdateWebsite({ user }: Auth, websiteId: string) {
return true;
}
- if (!isUuid(websiteId)) {
- return false;
- }
-
const website = await loadWebsite(websiteId);
- if (website.userId) {
- return user.id === website.userId;
- }
-
- return false;
+ return user.id === website?.userId;
}
export async function canDeleteWebsite({ user }: Auth, websiteId: string) {
@@ -127,11 +82,7 @@ export async function canDeleteWebsite({ user }: Auth, websiteId: string) {
const website = await loadWebsite(websiteId);
- if (website.userId) {
- return user.id === website.userId;
- }
-
- return false;
+ return user.id === website?.userId;
}
export async function canViewReport(auth: Auth, report: Report) {
@@ -139,27 +90,23 @@ export async function canViewReport(auth: Auth, report: Report) {
return true;
}
- if ((auth.user.id = report.userId)) {
+ if (auth.user.id == report.userId) {
return true;
}
- if (await canViewWebsite(auth, report.websiteId)) {
- return true;
- }
-
- return false;
+ return !!(await canViewWebsite(auth, report.websiteId));
}
-export async function canUpdateReport(auth: Auth, report: Report) {
- if (auth.user.isAdmin) {
+export async function canUpdateReport({ user }: Auth, report: Report) {
+ if (user.isAdmin) {
return true;
}
- if ((auth.user.id = report.userId)) {
- return true;
- }
+ return user.id == report.userId;
+}
- return false;
+export async function canDeleteReport(auth: Auth, report: Report) {
+ return canUpdateReport(auth, report);
}
export async function canCreateTeam({ user }: Auth) {
@@ -183,13 +130,9 @@ export async function canUpdateTeam({ user }: Auth, teamId: string) {
return true;
}
- if (isUuid(teamId)) {
- const teamUser = await getTeamUser(teamId, user.id);
+ const teamUser = await getTeamUser(teamId, user.id);
- return hasPermission(teamUser.role, PERMISSIONS.teamUpdate);
- }
-
- return false;
+ return teamUser && hasPermission(teamUser.role, PERMISSIONS.teamUpdate);
}
export async function canDeleteTeam({ user }: Auth, teamId: string) {
@@ -197,13 +140,9 @@ export async function canDeleteTeam({ user }: Auth, teamId: string) {
return true;
}
- if (isUuid(teamId)) {
- const teamUser = await getTeamUser(teamId, user.id);
+ const teamUser = await getTeamUser(teamId, user.id);
- return hasPermission(teamUser.role, PERMISSIONS.teamDelete);
- }
-
- return false;
+ return teamUser && hasPermission(teamUser.role, PERMISSIONS.teamDelete);
}
export async function canDeleteTeamUser({ user }: Auth, teamId: string, removeUserId: string) {
@@ -211,17 +150,13 @@ export async function canDeleteTeamUser({ user }: Auth, teamId: string, removeUs
return true;
}
- if (isUuid(teamId) && isUuid(removeUserId)) {
- if (removeUserId === user.id) {
- return true;
- }
-
- const teamUser = await getTeamUser(teamId, user.id);
-
- return hasPermission(teamUser.role, PERMISSIONS.teamUpdate);
+ if (removeUserId === user.id) {
+ return true;
}
- return false;
+ const teamUser = await getTeamUser(teamId, user.id);
+
+ return teamUser && hasPermission(teamUser.role, PERMISSIONS.teamUpdate);
}
export async function canDeleteTeamWebsite({ user }: Auth, teamId: string, websiteId: string) {
@@ -229,13 +164,13 @@ export async function canDeleteTeamWebsite({ user }: Auth, teamId: string, websi
return true;
}
- if (isUuid(teamId) && isUuid(websiteId)) {
- const teamWebsite = await getTeamWebsite(teamId, websiteId);
+ const teamWebsite = await getTeamWebsite(teamId, websiteId);
- if (teamWebsite.website.userId === user.id) {
- return true;
- }
+ if (teamWebsite?.website?.userId === user.id) {
+ return true;
+ }
+ if (teamWebsite) {
const teamUser = await getTeamUser(teamWebsite.teamId, user.id);
return hasPermission(teamUser.role, PERMISSIONS.teamUpdate);
diff --git a/lib/cache.ts b/lib/cache.ts
index 7ee7bf28..bc46c23d 100644
--- a/lib/cache.ts
+++ b/lib/cache.ts
@@ -1,11 +1,11 @@
import { User, Website } from '@prisma/client';
import redis from '@umami/redis-client';
-import { getSession, getUser, getWebsite } from '../queries';
+import { getSession, getUserById, getWebsiteById } from '../queries';
const { fetchObject, storeObject, deleteObject } = redis;
async function fetchWebsite(id): Promise {
- return fetchObject(`website:${id}`, () => getWebsite({ id }));
+ return fetchObject(`website:${id}`, () => getWebsiteById(id));
}
async function storeWebsite(data) {
@@ -20,7 +20,7 @@ async function deleteWebsite(id) {
}
async function fetchUser(id): Promise {
- return fetchObject(`user:${id}`, () => getUser({ id }, { includePassword: true }));
+ return fetchObject(`user:${id}`, () => getUserById(id, { includePassword: true }));
}
async function storeUser(data) {
@@ -35,7 +35,7 @@ async function deleteUser(id) {
}
async function fetchSession(id) {
- return fetchObject(`session:${id}`, () => getSession({ id }));
+ return fetchObject(`session:${id}`, () => getSession(id));
}
async function storeSession(data) {
diff --git a/lib/dynamicData.ts b/lib/data.ts
similarity index 100%
rename from lib/dynamicData.ts
rename to lib/data.ts
diff --git a/lib/load.ts b/lib/load.ts
index 4ce18b09..d980f8e9 100644
--- a/lib/load.ts
+++ b/lib/load.ts
@@ -1,5 +1,5 @@
import cache from 'lib/cache';
-import { getWebsite, getSession, getUser } from 'queries';
+import { getSession, getUserById, getWebsiteById } from 'queries';
import { User, Website, Session } from '@prisma/client';
export async function loadWebsite(websiteId: string): Promise {
@@ -8,7 +8,7 @@ export async function loadWebsite(websiteId: string): Promise {
if (cache.enabled) {
website = await cache.fetchWebsite(websiteId);
} else {
- website = await getWebsite({ id: websiteId });
+ website = await getWebsiteById(websiteId);
}
if (!website || website.deletedAt) {
@@ -24,7 +24,7 @@ export async function loadSession(sessionId: string): Promise {
if (cache.enabled) {
session = await cache.fetchSession(sessionId);
} else {
- session = await getSession({ id: sessionId });
+ session = await getSession(sessionId);
}
if (!session) {
@@ -40,7 +40,7 @@ export async function loadUser(userId: string): Promise {
if (cache.enabled) {
user = await cache.fetchUser(userId);
} else {
- user = await getUser({ id: userId });
+ user = await getUserById(userId);
}
if (!user || user.deletedAt) {
diff --git a/lib/middleware.ts b/lib/middleware.ts
index bcab71ef..414cab23 100644
--- a/lib/middleware.ts
+++ b/lib/middleware.ts
@@ -12,7 +12,7 @@ import { findSession } from 'lib/session';
import { getAuthToken, parseShareToken } from 'lib/auth';
import { secret, isUuid } from 'lib/crypto';
import { ROLES } from 'lib/constants';
-import { getUser } from '../queries';
+import { getUserById } from '../queries';
import { NextApiRequestCollect } from 'pages/api/send';
const log = debug('umami:middleware');
@@ -53,7 +53,7 @@ export const useAuth = createMiddleware(async (req, res, next) => {
const { userId, authKey } = payload || {};
if (isUuid(userId)) {
- user = await getUser({ id: userId });
+ user = await getUserById(userId);
} else if (redis.enabled && authKey) {
user = await redis.get(authKey);
}
diff --git a/pages/api/auth/login.ts b/pages/api/auth/login.ts
index 64c2c26d..af206938 100644
--- a/pages/api/auth/login.ts
+++ b/pages/api/auth/login.ts
@@ -9,7 +9,7 @@ import {
methodNotAllowed,
} from 'next-basics';
import redis from '@umami/redis-client';
-import { getUser } from 'queries';
+import { getUserByUsername } from 'queries';
import { secret } from 'lib/crypto';
import { NextApiRequestQueryBody, User } from 'lib/types';
import { setAuthKey } from 'lib/auth';
@@ -37,7 +37,7 @@ export default async (
return badRequest(res);
}
- const user = await getUser({ username }, { includePassword: true });
+ const user = await getUserByUsername(username, { includePassword: true });
if (user && checkPassword(password, user.password)) {
if (redis.enabled) {
diff --git a/pages/api/me/password.ts b/pages/api/me/password.ts
index 70d8de5f..f9f60fc5 100644
--- a/pages/api/me/password.ts
+++ b/pages/api/me/password.ts
@@ -9,7 +9,7 @@ import {
forbidden,
ok,
} from 'next-basics';
-import { getUser, updateUser } from 'queries';
+import { getUserById, updateUser } from 'queries';
export interface UserPasswordRequestQuery {
id: string;
@@ -34,7 +34,7 @@ export default async (
const { id } = req.auth.user;
if (req.method === 'POST') {
- const user = await getUser({ id }, { includePassword: true });
+ const user = await getUserById(id, { includePassword: true });
if (!checkPassword(currentPassword, user.password)) {
return badRequest(res, 'Current password is incorrect');
diff --git a/pages/api/reports/[id].ts b/pages/api/reports/[id].ts
index bcd22b4e..85bc302c 100644
--- a/pages/api/reports/[id].ts
+++ b/pages/api/reports/[id].ts
@@ -1,9 +1,9 @@
-import { canUpdateReport, canViewReport } from 'lib/auth';
+import { canUpdateReport, canViewReport, canDeleteReport } from 'lib/auth';
import { useAuth, useCors } from 'lib/middleware';
import { NextApiRequestQueryBody } from 'lib/types';
import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
-import { getReportById, updateReport } from 'queries';
+import { getReportById, updateReport, deleteReport } from 'queries';
export interface ReportRequestQuery {
id: string;
@@ -24,50 +24,55 @@ export default async (
await useCors(req, res);
await useAuth(req, res);
+ const { id: reportId } = req.query;
+ const {
+ user: { id: userId },
+ } = req.auth;
+
if (req.method === 'GET') {
- const { id: reportId } = req.query;
+ const report = await getReportById(reportId);
- const data = await getReportById(reportId);
-
- if (!(await canViewReport(req.auth, data))) {
+ if (!(await canViewReport(req.auth, report))) {
return unauthorized(res);
}
- data.parameters = JSON.parse(data.parameters);
+ report.parameters = JSON.parse(report.parameters);
- return ok(res, data);
+ return ok(res, report);
}
if (req.method === 'POST') {
- const { id: reportId } = req.query;
- const {
- user: { id: userId },
- } = req.auth;
-
const { websiteId, type, name, description, parameters } = req.body;
- const data = await getReportById(reportId);
+ const report = await getReportById(reportId);
- if (!(await canUpdateReport(req.auth, data))) {
+ if (!(await canUpdateReport(req.auth, report))) {
return unauthorized(res);
}
- const result = await updateReport(
- {
- websiteId,
- userId,
- type,
- name,
- description,
- parameters: JSON.stringify(parameters),
- } as any,
- {
- id: reportId,
- },
- );
+ const result = await updateReport(reportId, {
+ websiteId,
+ userId,
+ type,
+ name,
+ description,
+ parameters: JSON.stringify(parameters),
+ } as any);
return ok(res, result);
}
+ if (req.method === 'DELETE') {
+ const report = await getReportById(reportId);
+
+ if (!(await canDeleteReport(req.auth, report))) {
+ return unauthorized(res);
+ }
+
+ await deleteReport(reportId);
+
+ return ok(res);
+ }
+
return methodNotAllowed(res);
};
diff --git a/pages/api/reports/index.ts b/pages/api/reports/index.ts
index fcd8fd37..c856b565 100644
--- a/pages/api/reports/index.ts
+++ b/pages/api/reports/index.ts
@@ -2,7 +2,7 @@ import { useAuth, useCors } from 'lib/middleware';
import { NextApiRequestQueryBody } from 'lib/types';
import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
-import { createReport, getReports } from 'queries';
+import { createReport, getWebsiteReports } from 'queries';
import { canViewWebsite } from 'lib/auth';
import { uuid } from 'lib/crypto';
@@ -35,7 +35,7 @@ export default async (
return unauthorized(res);
}
- const data = await getReports({ websiteId });
+ const data = await getWebsiteReports(websiteId);
return ok(res, data);
}
diff --git a/pages/api/share/[id].ts b/pages/api/share/[id].ts
index b5511f2d..0592d216 100644
--- a/pages/api/share/[id].ts
+++ b/pages/api/share/[id].ts
@@ -2,7 +2,7 @@ import { NextApiRequestQueryBody } from 'lib/types';
import { secret } from 'lib/crypto';
import { NextApiResponse } from 'next';
import { createToken, methodNotAllowed, notFound, ok } from 'next-basics';
-import { getWebsite } from 'queries';
+import { getWebsiteByShareId } from 'queries';
export interface ShareRequestQuery {
id: string;
@@ -20,7 +20,7 @@ export default async (
const { id: shareId } = req.query;
if (req.method === 'GET') {
- const website = await getWebsite({ shareId });
+ const website = await getWebsiteByShareId(shareId);
if (website) {
const data = { websiteId: website.id };
diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts
index 1c7dbb66..7fb664a0 100644
--- a/pages/api/teams/[id]/index.ts
+++ b/pages/api/teams/[id]/index.ts
@@ -4,7 +4,7 @@ import { canDeleteTeam, canUpdateTeam, canViewTeam } from 'lib/auth';
import { useAuth } from 'lib/middleware';
import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
-import { deleteTeam, getTeam, updateTeam } from 'queries';
+import { deleteTeam, getTeamById, updateTeam } from 'queries';
export interface TeamRequestQuery {
id: string;
@@ -28,7 +28,7 @@ export default async (
return unauthorized(res);
}
- const user = await getTeam({ id: teamId });
+ const user = await getTeamById(teamId, { includeTeamUser: true });
return ok(res, user);
}
@@ -41,7 +41,7 @@ export default async (
const { name, accessCode } = req.body;
const data = { name, accessCode };
- const updated = await updateTeam(data, { id: teamId });
+ const updated = await updateTeam(teamId, data);
return ok(res, updated);
}
diff --git a/pages/api/teams/[id]/users/index.ts b/pages/api/teams/[id]/users/index.ts
index af01d0ce..c73da683 100644
--- a/pages/api/teams/[id]/users/index.ts
+++ b/pages/api/teams/[id]/users/index.ts
@@ -3,7 +3,7 @@ import { useAuth } from 'lib/middleware';
import { NextApiRequestQueryBody } from 'lib/types';
import { NextApiResponse } from 'next';
import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
-import { createTeamUser, getTeamUsers, getUser } from 'queries';
+import { createTeamUser, getTeamUsers, getUserByUsername } from 'queries';
export interface TeamUserRequestQuery {
id: string;
@@ -40,7 +40,7 @@ export default async (
const { email, roleId: roleId } = req.body;
// Check for User
- const user = await getUser({ username: email });
+ const user = await getUserByUsername(email);
if (!user) {
return badRequest(res, 'The User does not exists.');
diff --git a/pages/api/teams/join.ts b/pages/api/teams/join.ts
index 17c9bf32..ce7367a0 100644
--- a/pages/api/teams/join.ts
+++ b/pages/api/teams/join.ts
@@ -3,7 +3,7 @@ import { NextApiRequestQueryBody } from 'lib/types';
import { useAuth } from 'lib/middleware';
import { NextApiResponse } from 'next';
import { methodNotAllowed, ok, notFound } from 'next-basics';
-import { createTeamUser, getTeam, getTeamUser } from 'queries';
+import { createTeamUser, getTeamByAccessCode, getTeamUser } from 'queries';
import { ROLES } from 'lib/constants';
export interface TeamsJoinRequestBody {
@@ -19,7 +19,7 @@ export default async (
if (req.method === 'POST') {
const { accessCode } = req.body;
- const team = await getTeam({ accessCode });
+ const team = await getTeamByAccessCode(accessCode);
if (!team) {
return notFound(res, 'message.team-not-found');
diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts
index a4ab05ff..e09b1b5f 100644
--- a/pages/api/users/[id]/index.ts
+++ b/pages/api/users/[id]/index.ts
@@ -3,7 +3,7 @@ import { canDeleteUser, canUpdateUser, canViewUser } from 'lib/auth';
import { useAuth } from 'lib/middleware';
import { NextApiResponse } from 'next';
import { badRequest, hashPassword, methodNotAllowed, ok, unauthorized } from 'next-basics';
-import { deleteUser, getUser, updateUser } from 'queries';
+import { deleteUser, getUserById, getUserByUsername, updateUser } from 'queries';
export interface UserRequestQuery {
id: string;
@@ -31,7 +31,7 @@ export default async (
return unauthorized(res);
}
- const user = await getUser({ id });
+ const user = await getUserById(id);
return ok(res, user);
}
@@ -43,7 +43,7 @@ export default async (
const { username, password, role } = req.body;
- const user = await getUser({ id });
+ const user = await getUserById(id);
const data: any = {};
@@ -62,9 +62,9 @@ export default async (
// Check when username changes
if (data.username && user.username !== data.username) {
- const userByUsername = await getUser({ username });
+ const user = await getUserByUsername(username);
- if (userByUsername) {
+ if (user) {
return badRequest(res, 'User already exists');
}
}
diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts
index c6103c35..6f6c205f 100644
--- a/pages/api/users/index.ts
+++ b/pages/api/users/index.ts
@@ -5,7 +5,7 @@ import { useAuth } from 'lib/middleware';
import { NextApiRequestQueryBody, Role, User } from 'lib/types';
import { NextApiResponse } from 'next';
import { badRequest, hashPassword, methodNotAllowed, ok, unauthorized } from 'next-basics';
-import { createUser, getUser, getUsers } from 'queries';
+import { createUser, getUserByUsername, getUsers } from 'queries';
export interface UsersRequestBody {
username: string;
@@ -37,7 +37,7 @@ export default async (
const { username, password, role, id } = req.body;
- const existingUser = await getUser({ username }, { showDeleted: true });
+ const existingUser = await getUserByUsername(username, { showDeleted: true });
if (existingUser) {
return badRequest(res, 'User already exists');
diff --git a/pages/api/websites/[id]/index.ts b/pages/api/websites/[id]/index.ts
index 1d7e4ac3..3d053d0e 100644
--- a/pages/api/websites/[id]/index.ts
+++ b/pages/api/websites/[id]/index.ts
@@ -3,7 +3,7 @@ import { methodNotAllowed, ok, serverError, unauthorized } from 'next-basics';
import { Website, NextApiRequestQueryBody } from 'lib/types';
import { canViewWebsite, canUpdateWebsite, canDeleteWebsite } from 'lib/auth';
import { useAuth, useCors } from 'lib/middleware';
-import { deleteWebsite, getWebsite, updateWebsite } from 'queries';
+import { deleteWebsite, getWebsiteById, updateWebsite } from 'queries';
import { SHARE_ID_REGEX } from 'lib/constants';
export interface WebsiteRequestQuery {
@@ -30,7 +30,7 @@ export default async (
return unauthorized(res);
}
- const website = await getWebsite({ id: websiteId });
+ const website = await getWebsiteById(websiteId);
return ok(res, website);
}
diff --git a/queries/admin/report.ts b/queries/admin/report.ts
index 6b557a7a..ee7a0592 100644
--- a/queries/admin/report.ts
+++ b/queries/admin/report.ts
@@ -13,19 +13,29 @@ export async function getReportById(reportId: string): Promise {
});
}
-export async function getReports(where: Prisma.ReportWhereInput): Promise {
+export async function getUserReports(userId: string): Promise {
return prisma.client.report.findMany({
- where,
+ where: {
+ userId,
+ },
+ });
+}
+
+export async function getWebsiteReports(websiteId: string): Promise {
+ return prisma.client.report.findMany({
+ where: {
+ websiteId,
+ },
});
}
export async function updateReport(
+ reportId: string,
data: Prisma.ReportUpdateInput,
- where: Prisma.ReportWhereUniqueInput,
): Promise {
- return prisma.client.report.update({ data, where });
+ return prisma.client.report.update({ where: { id: reportId }, data });
}
-export async function deleteReport(where: Prisma.ReportWhereUniqueInput): Promise {
- return prisma.client.report.delete({ where });
+export async function deleteReport(reportId: string): Promise {
+ return prisma.client.report.delete({ where: { id: reportId } });
}
diff --git a/queries/admin/team.ts b/queries/admin/team.ts
index 5c3b372f..a8b3385c 100644
--- a/queries/admin/team.ts
+++ b/queries/admin/team.ts
@@ -3,15 +3,29 @@ import prisma from 'lib/prisma';
import { ROLES } from 'lib/constants';
import { uuid } from 'lib/crypto';
-export async function getTeam(where: Prisma.TeamWhereInput): Promise {
+export interface GetTeamOptions {
+ includeTeamUser?: boolean;
+}
+
+async function getTeam(where: Prisma.TeamWhereInput, options: GetTeamOptions = {}): Promise {
+ const { includeTeamUser = false } = options;
+
return prisma.client.team.findFirst({
where,
include: {
- teamUser: true,
+ teamUser: includeTeamUser,
},
});
}
+export function getTeamById(teamId: string, options: GetTeamOptions = {}) {
+ return getTeam({ id: teamId }, options);
+}
+
+export function getTeamByAccessCode(accessCode: string, options: GetTeamOptions = {}) {
+ return getTeam({ accessCode }, options);
+}
+
export async function getTeams(where: Prisma.TeamWhereInput): Promise {
return prisma.client.team.findMany({
where,
@@ -36,16 +50,15 @@ export async function createTeam(data: Prisma.TeamCreateInput, userId: string):
]);
}
-export async function updateTeam(
- data: Prisma.TeamUpdateInput,
- where: Prisma.TeamWhereUniqueInput,
-): Promise {
+export async function updateTeam(teamId: string, data: Prisma.TeamUpdateInput): Promise {
return prisma.client.team.update({
+ where: {
+ id: teamId,
+ },
data: {
...data,
updatedAt: new Date(),
},
- where,
});
}
diff --git a/queries/admin/teamUser.ts b/queries/admin/teamUser.ts
index b1c295be..c5b27a02 100644
--- a/queries/admin/teamUser.ts
+++ b/queries/admin/teamUser.ts
@@ -53,12 +53,14 @@ export async function createTeamUser(
}
export async function updateTeamUser(
+ teamUserId: string,
data: Prisma.TeamUserUpdateInput,
- where: Prisma.TeamUserWhereUniqueInput,
): Promise {
return prisma.client.teamUser.update({
+ where: {
+ id: teamUserId,
+ },
data,
- where,
});
}
diff --git a/queries/admin/teamWebsite.ts b/queries/admin/teamWebsite.ts
index 0aedc3c7..169526dd 100644
--- a/queries/admin/teamWebsite.ts
+++ b/queries/admin/teamWebsite.ts
@@ -22,7 +22,7 @@ export async function getTeamWebsite(
});
}
-export async function getTeamWebsiteByTeamMemberId(
+export async function findTeamWebsiteByUserId(
websiteId: string,
userId: string,
): Promise {
diff --git a/queries/admin/user.ts b/queries/admin/user.ts
index cab8a562..f60c4801 100644
--- a/queries/admin/user.ts
+++ b/queries/admin/user.ts
@@ -5,9 +5,14 @@ import { ROLES } from 'lib/constants';
import prisma from 'lib/prisma';
import { Website, User, Role } from 'lib/types';
-export async function getUser(
+export interface GetUserOptions {
+ includePassword?: boolean;
+ showDeleted?: boolean;
+}
+
+async function getUser(
where: Prisma.UserWhereInput | Prisma.UserWhereUniqueInput,
- options: { includePassword?: boolean; showDeleted?: boolean } = {},
+ options: GetUserOptions = {},
): Promise {
const { includePassword = false, showDeleted = false } = options;
@@ -23,6 +28,14 @@ export async function getUser(
});
}
+export async function getUserById(userId: string, options: GetUserOptions = {}) {
+ return getUser({ id: userId }, options);
+}
+
+export async function getUserByUsername(username: string, options: GetUserOptions = {}) {
+ return getUser({ username }, options);
+}
+
export async function getUsers(): Promise {
return prisma.client.user.findMany({
take: 100,
diff --git a/queries/admin/website.ts b/queries/admin/website.ts
index 8714d8c9..35f32bac 100644
--- a/queries/admin/website.ts
+++ b/queries/admin/website.ts
@@ -2,12 +2,20 @@ import { Prisma, Website } from '@prisma/client';
import cache from 'lib/cache';
import prisma from 'lib/prisma';
-export async function getWebsite(where: Prisma.WebsiteWhereUniqueInput): Promise {
+async function getWebsite(where: Prisma.WebsiteWhereUniqueInput): Promise {
return prisma.client.website.findUnique({
where,
});
}
+export async function getWebsiteById(id: string) {
+ return getWebsite({ id });
+}
+
+export async function getWebsiteByShareId(shareId: string) {
+ return getWebsite({ shareId });
+}
+
export async function getWebsites(): Promise {
return prisma.client.website.findMany({
orderBy: {
diff --git a/queries/analytics/eventData/saveEventData.ts b/queries/analytics/eventData/saveEventData.ts
index 97b1c882..0f1ddb37 100644
--- a/queries/analytics/eventData/saveEventData.ts
+++ b/queries/analytics/eventData/saveEventData.ts
@@ -2,7 +2,7 @@ import { Prisma } from '@prisma/client';
import { DATA_TYPE } from 'lib/constants';
import { uuid } from 'lib/crypto';
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
-import { flattenJSON } from 'lib/dynamicData';
+import { flattenJSON } from 'lib/data';
import kafka from 'lib/kafka';
import prisma from 'lib/prisma';
import { DynamicData } from 'lib/types';
diff --git a/queries/analytics/events/getEventMetrics.ts b/queries/analytics/events/getEventMetrics.ts
index 37044d1b..11a5c690 100644
--- a/queries/analytics/events/getEventMetrics.ts
+++ b/queries/analytics/events/getEventMetrics.ts
@@ -2,24 +2,23 @@ import prisma from 'lib/prisma';
import clickhouse from 'lib/clickhouse';
import { runQuery, CLICKHOUSE, PRISMA } from 'lib/db';
import { WebsiteEventMetric } from 'lib/types';
-import { DEFAULT_RESET_DATE, EVENT_TYPE } from 'lib/constants';
+import { EVENT_TYPE } from 'lib/constants';
import { loadWebsite } from 'lib/load';
import { maxDate } from 'lib/date';
+export interface GetEventMetricsCriteria {
+ startDate: Date;
+ endDate: Date;
+ timezone: string;
+ unit: string;
+ filters: {
+ url: string;
+ eventName: string;
+ };
+}
+
export async function getEventMetrics(
- ...args: [
- websiteId: string,
- data: {
- startDate: Date;
- endDate: Date;
- timezone: string;
- unit: string;
- filters: {
- url: string;
- eventName: string;
- };
- },
- ]
+ ...args: [websiteId: string, criteria: GetEventMetricsCriteria]
): Promise {
return runQuery({
[PRISMA]: () => relationalQuery(...args),
@@ -27,25 +26,8 @@ export async function getEventMetrics(
});
}
-async function relationalQuery(
- websiteId: string,
- {
- startDate,
- endDate,
- timezone = 'utc',
- unit = 'day',
- filters,
- }: {
- startDate: Date;
- endDate: Date;
- timezone: string;
- unit: string;
- filters: {
- url: string;
- eventName: string;
- };
- },
-) {
+async function relationalQuery(websiteId: string, criteria: GetEventMetricsCriteria) {
+ const { startDate, endDate, timezone = 'utc', unit = 'day', filters } = criteria;
const { rawQuery, getDateQuery, getFilterQuery } = prisma;
const website = await loadWebsite(websiteId);
const filterQuery = getFilterQuery(filters);
@@ -74,25 +56,8 @@ async function relationalQuery(
);
}
-async function clickhouseQuery(
- websiteId: string,
- {
- startDate,
- endDate,
- timezone = 'utc',
- unit = 'day',
- filters,
- }: {
- startDate: Date;
- endDate: Date;
- timezone: string;
- unit: string;
- filters: {
- url: string;
- eventName: string;
- };
- },
-) {
+async function clickhouseQuery(websiteId: string, criteria: GetEventMetricsCriteria) {
+ const { startDate, endDate, timezone = 'utc', unit = 'day', filters } = criteria;
const { rawQuery, getDateQuery, getFilterQuery } = clickhouse;
const website = await loadWebsite(websiteId);
const filterQuery = getFilterQuery(filters);
diff --git a/queries/analytics/sessions/getSession.ts b/queries/analytics/sessions/getSession.ts
index 2fd8d18f..256ada4c 100644
--- a/queries/analytics/sessions/getSession.ts
+++ b/queries/analytics/sessions/getSession.ts
@@ -1,8 +1,9 @@
-import { Prisma } from '@prisma/client';
import prisma from 'lib/prisma';
-export async function getSession(where: Prisma.SessionWhereUniqueInput) {
+export async function getSession(id: string) {
return prisma.client.session.findUnique({
- where,
+ where: {
+ id,
+ },
});
}
diff --git a/queries/analytics/sessions/saveSessionData.ts b/queries/analytics/sessions/saveSessionData.ts
index 192053f1..ef32bcfb 100644
--- a/queries/analytics/sessions/saveSessionData.ts
+++ b/queries/analytics/sessions/saveSessionData.ts
@@ -1,6 +1,6 @@
import { DATA_TYPE } from 'lib/constants';
import { uuid } from 'lib/crypto';
-import { flattenJSON } from 'lib/dynamicData';
+import { flattenJSON } from 'lib/data';
import prisma from 'lib/prisma';
import { DynamicData } from 'lib/types';
diff --git a/queries/index.js b/queries/index.js
index f86551c4..f509e039 100644
--- a/queries/index.js
+++ b/queries/index.js
@@ -1,7 +1,8 @@
+export * from './admin/report';
export * from './admin/team';
export * from './admin/teamUser';
+export * from './admin/teamWebsite';
export * from './admin/user';
-export * from './admin/report';
export * from './admin/website';
export * from './analytics/events/getEventMetrics';
export * from './analytics/events/getEventUsage';