mirror of
https://github.com/kremalicious/umami.git
synced 2024-11-22 09:57:00 +01:00
Refactor database queries.
This commit is contained in:
parent
a248f35db2
commit
f4ca353b5c
@ -5,7 +5,6 @@ import Button from 'components/common/Button';
|
||||
import Icon from 'components/common/Icon';
|
||||
import Table from 'components/common/Table';
|
||||
import Modal from 'components/common/Modal';
|
||||
import WebsiteEditForm from 'components/forms/WebsiteEditForm';
|
||||
import AccountEditForm from 'components/forms/AccountEditForm';
|
||||
import Pen from 'assets/pen.svg';
|
||||
import Plus from 'assets/plus.svg';
|
||||
@ -16,33 +15,36 @@ import styles from './AccountSettings.module.css';
|
||||
import DeleteForm from './forms/DeleteForm';
|
||||
|
||||
export default function AccountSettings() {
|
||||
const user = useSelector(state => state.user);
|
||||
const [data, setData] = useState();
|
||||
const [addAccount, setAddAccount] = useState();
|
||||
const [editAccount, setEditAccount] = useState();
|
||||
const [deleteAccount, setDeleteAccount] = useState();
|
||||
const [saved, setSaved] = useState(0);
|
||||
|
||||
const Checkmark = ({ is_admin }) => (is_admin ? <Icon icon={<Check />} size="medium" /> : null);
|
||||
|
||||
const Buttons = row =>
|
||||
row.username !== 'admin' ? (
|
||||
<>
|
||||
<Button icon={<Pen />} size="small" onClick={() => setEditAccount(row)}>
|
||||
<div>Edit</div>
|
||||
</Button>
|
||||
<Button icon={<Trash />} size="small" onClick={() => setDeleteAccount(row)}>
|
||||
<div>Delete</div>
|
||||
</Button>
|
||||
</>
|
||||
) : null;
|
||||
|
||||
const columns = [
|
||||
{ key: 'username', label: 'Username' },
|
||||
{
|
||||
key: 'is_admin',
|
||||
label: 'Administrator',
|
||||
render: ({ is_admin }) => (is_admin ? <Icon icon={<Check />} size="medium" /> : null),
|
||||
render: Checkmark,
|
||||
},
|
||||
{
|
||||
className: styles.buttons,
|
||||
render: row =>
|
||||
row.username !== 'admin' ? (
|
||||
<>
|
||||
<Button icon={<Pen />} size="small" onClick={() => setEditAccount(row)}>
|
||||
<div>Edit</div>
|
||||
</Button>
|
||||
<Button icon={<Trash />} size="small" onClick={() => setDeleteAccount(row)}>
|
||||
<div>Delete</div>
|
||||
</Button>
|
||||
</>
|
||||
) : null,
|
||||
render: Buttons,
|
||||
},
|
||||
];
|
||||
|
||||
@ -58,7 +60,7 @@ export default function AccountSettings() {
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
setData(await get(`/api/account`));
|
||||
setData(await get(`/api/accounts`));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import PageHeader from './layout/PageHeader';
|
||||
import Button from './common/Button';
|
||||
import PageHeader from 'components/layout/PageHeader';
|
||||
import Button from 'components/common/Button';
|
||||
import ChangePasswordForm from './forms/ChangePasswordForm';
|
||||
import Modal from './common/Modal';
|
||||
import Modal from 'components/common/Modal';
|
||||
|
||||
export default function ProfileSettings() {
|
||||
const user = useSelector(state => state.user);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import WebsiteChart from './charts/WebsiteChart';
|
||||
import RankingsChart from './charts/RankingsChart';
|
||||
import WorldMap from './common/WorldMap';
|
||||
import Page from './layout/Page';
|
||||
import PageHeader from './layout/PageHeader';
|
||||
import MenuLayout from './layout/MenuLayout';
|
||||
import Button from './common/Button';
|
||||
import WebsiteChart from 'components/charts/WebsiteChart';
|
||||
import RankingsChart from 'components/charts/RankingsChart';
|
||||
import WorldMap from 'components/common/WorldMap';
|
||||
import Page from 'components/layout/Page';
|
||||
import PageHeader from 'components/layout/PageHeader';
|
||||
import MenuLayout from 'components/layout/MenuLayout';
|
||||
import Button from 'components/common/Button';
|
||||
import { getDateRange } from 'lib/date';
|
||||
import { get } from 'lib/web';
|
||||
import { browserFilter, urlFilter, refFilter, deviceFilter, countryFilter } from 'lib/filters';
|
||||
|
@ -1,22 +1,21 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { get } from 'lib/web';
|
||||
import Link from './common/Link';
|
||||
import WebsiteChart from './charts/WebsiteChart';
|
||||
import Page from './layout/Page';
|
||||
import Icon from './common/Icon';
|
||||
import Button from './common/Button';
|
||||
import PageHeader from './layout/PageHeader';
|
||||
import Link from 'components/common/Link';
|
||||
import WebsiteChart from 'components/charts/WebsiteChart';
|
||||
import Page from 'components/layout/Page';
|
||||
import Button from 'components/common/Button';
|
||||
import PageHeader from 'components/layout/PageHeader';
|
||||
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
|
||||
import Arrow from 'assets/arrow-right.svg';
|
||||
import { get } from 'lib/web';
|
||||
import styles from './WebsiteList.module.css';
|
||||
import EmptyPlaceholder from './common/EmptyPlaceholder';
|
||||
|
||||
export default function WebsiteList() {
|
||||
const [data, setData] = useState();
|
||||
const router = useRouter();
|
||||
|
||||
async function loadData() {
|
||||
setData(await get(`/api/website`));
|
||||
setData(await get(`/api/websites`));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -1,19 +1,18 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Table from './common/Table';
|
||||
import Button from './common/Button';
|
||||
import PageHeader from './layout/PageHeader';
|
||||
import Table from 'components/common/Table';
|
||||
import Button from 'components/common/Button';
|
||||
import PageHeader from 'components/layout/PageHeader';
|
||||
import Modal from 'components/common/Modal';
|
||||
import WebsiteEditForm from './forms/WebsiteEditForm';
|
||||
import DeleteForm from './forms/DeleteForm';
|
||||
import WebsiteCodeForm from './forms/WebsiteCodeForm';
|
||||
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
|
||||
import Pen from 'assets/pen.svg';
|
||||
import Trash from 'assets/trash.svg';
|
||||
import Plus from 'assets/plus.svg';
|
||||
import Code from 'assets/code.svg';
|
||||
import { get } from 'lib/web';
|
||||
import Modal from './common/Modal';
|
||||
import WebsiteEditForm from './forms/WebsiteEditForm';
|
||||
import DeleteForm from './forms/DeleteForm';
|
||||
import WebsiteCodeForm from './forms/WebsiteCodeForm';
|
||||
import styles from './WebsiteSettings.module.css';
|
||||
import EmptyPlaceholder from './common/EmptyPlaceholder';
|
||||
import Arrow from '../assets/arrow-right.svg';
|
||||
|
||||
export default function WebsiteSettings() {
|
||||
const [data, setData] = useState();
|
||||
@ -23,25 +22,27 @@ export default function WebsiteSettings() {
|
||||
const [showCode, setShowCode] = useState();
|
||||
const [saved, setSaved] = useState(0);
|
||||
|
||||
const Buttons = row => (
|
||||
<>
|
||||
<Button icon={<Code />} size="small" onClick={() => setShowCode(row)}>
|
||||
<div>Get Code</div>
|
||||
</Button>
|
||||
<Button icon={<Pen />} size="small" onClick={() => setEditWebsite(row)}>
|
||||
<div>Edit</div>
|
||||
</Button>
|
||||
<Button icon={<Trash />} size="small" onClick={() => setDeleteWebsite(row)}>
|
||||
<div>Delete</div>
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
||||
const columns = [
|
||||
{ key: 'name', label: 'Name', className: styles.col },
|
||||
{ key: 'domain', label: 'Domain', className: styles.col },
|
||||
{
|
||||
key: 'action',
|
||||
className: styles.buttons,
|
||||
render: row => (
|
||||
<>
|
||||
<Button icon={<Code />} size="small" onClick={() => setShowCode(row)}>
|
||||
<div>Get Code</div>
|
||||
</Button>
|
||||
<Button icon={<Pen />} size="small" onClick={() => setEditWebsite(row)}>
|
||||
<div>Edit</div>
|
||||
</Button>
|
||||
<Button icon={<Trash />} size="small" onClick={() => setDeleteWebsite(row)}>
|
||||
<div>Delete</div>
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
render: Buttons,
|
||||
},
|
||||
];
|
||||
|
||||
@ -58,7 +59,7 @@ export default function WebsiteSettings() {
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
setData(await get(`/api/website`));
|
||||
setData(await get(`/api/websites`));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -2,8 +2,16 @@ import React, { useState } from 'react';
|
||||
import { Formik, Form, Field } from 'formik';
|
||||
import Router from 'next/router';
|
||||
import { post } from 'lib/web';
|
||||
import Button from '../common/Button';
|
||||
import FormLayout, { FormButtons, FormError, FormMessage, FormRow } from '../layout/FormLayout';
|
||||
import Button from 'components/common/Button';
|
||||
import FormLayout, {
|
||||
FormButtons,
|
||||
FormError,
|
||||
FormMessage,
|
||||
FormRow,
|
||||
} from 'components/layout/FormLayout';
|
||||
import Icon from 'components/common/Icon';
|
||||
import Logo from 'assets/logo.svg';
|
||||
import styles from './LoginForm.module.css';
|
||||
|
||||
const validate = ({ username, password }) => {
|
||||
const errors = {};
|
||||
@ -32,7 +40,7 @@ export default function LoginForm() {
|
||||
};
|
||||
|
||||
return (
|
||||
<FormLayout>
|
||||
<FormLayout className={styles.login}>
|
||||
<Formik
|
||||
initialValues={{
|
||||
username: '',
|
||||
@ -43,6 +51,7 @@ export default function LoginForm() {
|
||||
>
|
||||
{() => (
|
||||
<Form>
|
||||
<Icon icon={<Logo />} size="xlarge" className={styles.icon} />
|
||||
<h1 className="center">umami</h1>
|
||||
<FormRow>
|
||||
<label htmlFor="username">Username</label>
|
||||
|
11
components/forms/LoginForm.module.css
Normal file
11
components/forms/LoginForm.module.css
Normal file
@ -0,0 +1,11 @@
|
||||
.login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
}
|
@ -111,7 +111,5 @@ export function getDateArray(data, startDate, endDate, unit) {
|
||||
arr.push({ t, y });
|
||||
}
|
||||
|
||||
console.log({ unit, arr });
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
218
lib/db.js
218
lib/db.js
@ -1,6 +1,5 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import chalk from 'chalk';
|
||||
import { getMetricsQuery, getPageviewsQuery, getRankingsQuery } from 'lib/queries';
|
||||
|
||||
const options = {
|
||||
log: [
|
||||
@ -39,220 +38,3 @@ export async function runQuery(query) {
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
export async function getWebsite({ website_id, website_uuid }) {
|
||||
return runQuery(
|
||||
prisma.website.findOne({
|
||||
where: {
|
||||
...(website_id && { website_id }),
|
||||
...(website_uuid && { website_uuid }),
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getWebsites(user_id) {
|
||||
return runQuery(
|
||||
prisma.website.findMany({
|
||||
where: {
|
||||
user_id,
|
||||
},
|
||||
orderBy: {
|
||||
name: 'asc',
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function createWebsite(user_id, data) {
|
||||
return runQuery(
|
||||
prisma.website.create({
|
||||
data: {
|
||||
account: {
|
||||
connect: {
|
||||
user_id,
|
||||
},
|
||||
},
|
||||
...data,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateWebsite(website_id, data) {
|
||||
return runQuery(
|
||||
prisma.website.update({
|
||||
where: {
|
||||
website_id,
|
||||
},
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteWebsite(website_id) {
|
||||
return runQuery(
|
||||
/* Prisma bug, does not cascade on non-nullable foreign keys
|
||||
prisma.website.delete({
|
||||
where: {
|
||||
website_id,
|
||||
},
|
||||
}),
|
||||
*/
|
||||
prisma.queryRaw(`delete from website where website_id=$1`, website_id),
|
||||
);
|
||||
}
|
||||
|
||||
export async function createSession(website_id, data) {
|
||||
return runQuery(
|
||||
prisma.session.create({
|
||||
data: {
|
||||
website: {
|
||||
connect: {
|
||||
website_id,
|
||||
},
|
||||
},
|
||||
...data,
|
||||
},
|
||||
select: {
|
||||
session_id: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getSession({ session_id, session_uuid }) {
|
||||
return runQuery(
|
||||
prisma.session.findOne({
|
||||
where: {
|
||||
session_id,
|
||||
session_uuid,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function savePageView(website_id, session_id, url, referrer) {
|
||||
return runQuery(
|
||||
prisma.pageview.create({
|
||||
data: {
|
||||
website: {
|
||||
connect: {
|
||||
website_id,
|
||||
},
|
||||
},
|
||||
session: {
|
||||
connect: {
|
||||
session_id,
|
||||
},
|
||||
},
|
||||
url,
|
||||
referrer,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function saveEvent(website_id, session_id, url, event_type, event_value) {
|
||||
return runQuery(
|
||||
prisma.event.create({
|
||||
data: {
|
||||
website: {
|
||||
connect: {
|
||||
website_id,
|
||||
},
|
||||
},
|
||||
session: {
|
||||
connect: {
|
||||
session_id,
|
||||
},
|
||||
},
|
||||
url,
|
||||
event_type,
|
||||
event_value,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getAccounts() {
|
||||
return runQuery(prisma.account.findMany());
|
||||
}
|
||||
|
||||
export async function getAccount({ user_id, username }) {
|
||||
return runQuery(
|
||||
prisma.account.findOne({
|
||||
where: {
|
||||
username,
|
||||
user_id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateAccount(user_id, data) {
|
||||
return runQuery(
|
||||
prisma.account.update({
|
||||
where: {
|
||||
user_id,
|
||||
},
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteAccount(user_id) {
|
||||
return runQuery(
|
||||
/* Prisma bug, does not cascade on non-nullable foreign keys
|
||||
prisma.account.delete({
|
||||
where: {
|
||||
user_id,
|
||||
},
|
||||
}),
|
||||
*/
|
||||
prisma.queryRaw(`delete from account where user_id=$1`, user_id),
|
||||
);
|
||||
}
|
||||
|
||||
export async function createAccount(data) {
|
||||
return runQuery(
|
||||
prisma.account.create({
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getPageviews(website_id, start_at, end_at) {
|
||||
return runQuery(
|
||||
prisma.pageview.findMany({
|
||||
where: {
|
||||
website_id,
|
||||
created_at: {
|
||||
gte: start_at,
|
||||
lte: end_at,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getRankings(website_id, start_at, end_at, type, table) {
|
||||
return getRankingsQuery(prisma, { website_id, start_at, end_at, type, table });
|
||||
}
|
||||
|
||||
export async function getPageviewData(
|
||||
website_id,
|
||||
start_at,
|
||||
end_at,
|
||||
timezone = 'utc',
|
||||
unit = 'day',
|
||||
count = '*',
|
||||
) {
|
||||
return runQuery(
|
||||
getPageviewsQuery(prisma, { website_id, start_at, end_at, timezone, unit, count }),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getMetrics(website_id, start_at, end_at) {
|
||||
return getMetricsQuery(prisma, { website_id, start_at, end_at });
|
||||
}
|
||||
|
223
lib/queries.js
223
lib/queries.js
@ -1,4 +1,5 @@
|
||||
import moment from 'moment-timezone';
|
||||
import prisma, { runQuery } from 'lib/db';
|
||||
|
||||
const POSTGRESQL = 'postgresql';
|
||||
const MYSQL = 'mysql';
|
||||
@ -7,7 +8,216 @@ export function getDatabase() {
|
||||
return process.env.DATABASE_URL.split(':')[0];
|
||||
}
|
||||
|
||||
export function getMetricsQuery(prisma, { website_id, start_at, end_at }) {
|
||||
export async function getWebsiteById(website_id) {
|
||||
return runQuery(
|
||||
prisma.website.findOne({
|
||||
where: {
|
||||
website_id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getWebsiteByUuid(website_uuid) {
|
||||
return runQuery(
|
||||
prisma.website.findOne({
|
||||
where: {
|
||||
website_uuid,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getUserWebsites(user_id) {
|
||||
return runQuery(
|
||||
prisma.website.findMany({
|
||||
where: {
|
||||
user_id,
|
||||
},
|
||||
orderBy: {
|
||||
name: 'asc',
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function createWebsite(user_id, data) {
|
||||
return runQuery(
|
||||
prisma.website.create({
|
||||
data: {
|
||||
account: {
|
||||
connect: {
|
||||
user_id,
|
||||
},
|
||||
},
|
||||
...data,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateWebsite(website_id, data) {
|
||||
return runQuery(
|
||||
prisma.website.update({
|
||||
where: {
|
||||
website_id,
|
||||
},
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteWebsite(website_id) {
|
||||
return runQuery(
|
||||
/* Prisma bug, does not cascade on non-nullable foreign keys
|
||||
prisma.website.delete({
|
||||
where: {
|
||||
website_id,
|
||||
},
|
||||
}),
|
||||
*/
|
||||
prisma.$queryRaw`delete from website where website_id=${website_id}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function createSession(website_id, data) {
|
||||
return runQuery(
|
||||
prisma.session.create({
|
||||
data: {
|
||||
website: {
|
||||
connect: {
|
||||
website_id,
|
||||
},
|
||||
},
|
||||
...data,
|
||||
},
|
||||
select: {
|
||||
session_id: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getSessionById(session_id) {
|
||||
return runQuery(
|
||||
prisma.session.findOne({
|
||||
where: {
|
||||
session_id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getSessionByUuid(session_uuid) {
|
||||
return runQuery(
|
||||
prisma.session.findOne({
|
||||
where: {
|
||||
session_uuid,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function savePageView(website_id, session_id, url, referrer) {
|
||||
return runQuery(
|
||||
prisma.pageview.create({
|
||||
data: {
|
||||
website: {
|
||||
connect: {
|
||||
website_id,
|
||||
},
|
||||
},
|
||||
session: {
|
||||
connect: {
|
||||
session_id,
|
||||
},
|
||||
},
|
||||
url,
|
||||
referrer,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function saveEvent(website_id, session_id, url, event_type, event_value) {
|
||||
return runQuery(
|
||||
prisma.event.create({
|
||||
data: {
|
||||
website: {
|
||||
connect: {
|
||||
website_id,
|
||||
},
|
||||
},
|
||||
session: {
|
||||
connect: {
|
||||
session_id,
|
||||
},
|
||||
},
|
||||
url,
|
||||
event_type,
|
||||
event_value,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getAccounts() {
|
||||
return runQuery(prisma.account.findMany());
|
||||
}
|
||||
|
||||
export async function getAccountById(user_id) {
|
||||
return runQuery(
|
||||
prisma.account.findOne({
|
||||
where: {
|
||||
user_id,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function getAccountByUsername(username) {
|
||||
return runQuery(
|
||||
prisma.account.findOne({
|
||||
where: {
|
||||
username,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateAccount(user_id, data) {
|
||||
return runQuery(
|
||||
prisma.account.update({
|
||||
where: {
|
||||
user_id,
|
||||
},
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteAccount(user_id) {
|
||||
return runQuery(
|
||||
/* Prisma bug, does not cascade on non-nullable foreign keys
|
||||
prisma.account.delete({
|
||||
where: {
|
||||
user_id,
|
||||
},
|
||||
}),
|
||||
*/
|
||||
prisma.$queryRaw`delete from account where user_id=${user_id}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function createAccount(data) {
|
||||
return runQuery(
|
||||
prisma.account.create({
|
||||
data,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function getMetrics(website_id, start_at, end_at) {
|
||||
const db = getDatabase();
|
||||
|
||||
if (db === POSTGRESQL) {
|
||||
@ -61,7 +271,14 @@ export function getMetricsQuery(prisma, { website_id, start_at, end_at }) {
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
export function getPageviewsQuery(prisma, { website_id, start_at, end_at, unit, timezone, count }) {
|
||||
export function getPageviews(
|
||||
website_id,
|
||||
start_at,
|
||||
end_at,
|
||||
timezone = 'utc',
|
||||
unit = 'day',
|
||||
count = '*',
|
||||
) {
|
||||
const db = getDatabase();
|
||||
|
||||
if (db === POSTGRESQL) {
|
||||
@ -102,7 +319,7 @@ export function getPageviewsQuery(prisma, { website_id, start_at, end_at, unit,
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
export function getRankingsQuery(prisma, { website_id, start_at, end_at, type, table }) {
|
||||
export function getRankings(website_id, start_at, end_at, type, table) {
|
||||
const db = getDatabase();
|
||||
|
||||
if (db === POSTGRESQL) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getWebsite, getSession, createSession } from 'lib/db';
|
||||
import { getWebsiteByUuid, getSessionByUuid, createSession } from 'lib/queries';
|
||||
import { getClientInfo } from 'lib/request';
|
||||
import { uuid, isValidId, parseToken } from 'lib/crypto';
|
||||
|
||||
@ -19,7 +19,7 @@ export async function verifySession(req) {
|
||||
if (!token || token.website_uuid !== website_uuid) {
|
||||
const { userAgent, browser, os, ip, country, device } = await getClientInfo(req, payload);
|
||||
|
||||
const website = await getWebsite({ website_uuid });
|
||||
const website = await getWebsiteByUuid(website_uuid);
|
||||
|
||||
if (!website) {
|
||||
throw new Error(`Website not found: ${website_uuid}`);
|
||||
@ -28,7 +28,7 @@ export async function verifySession(req) {
|
||||
const { website_id } = website;
|
||||
const session_uuid = uuid(website_id, hostname, ip, userAgent, os);
|
||||
|
||||
let session = await getSession({ session_uuid });
|
||||
let session = await getSessionByUuid(session_uuid);
|
||||
|
||||
if (!session) {
|
||||
session = await createSession(website_id, {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getAccounts, getAccount, updateAccount, createAccount } from 'lib/db';
|
||||
import { getAccountById, getAccountByUsername, updateAccount, createAccount } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { hashPassword, uuid } from 'lib/crypto';
|
||||
import { hashPassword } from 'lib/crypto';
|
||||
import { ok, unauthorized, methodNotAllowed, badRequest } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
@ -8,24 +8,18 @@ export default async (req, res) => {
|
||||
|
||||
const { user_id: current_user_id, is_admin: current_user_is_admin } = req.auth;
|
||||
|
||||
if (req.method === 'GET') {
|
||||
if (current_user_is_admin) {
|
||||
const accounts = await getAccounts();
|
||||
|
||||
return ok(res, accounts);
|
||||
}
|
||||
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
if (req.method === 'POST') {
|
||||
const { user_id, username, password, is_admin } = req.body;
|
||||
|
||||
if (user_id) {
|
||||
const account = await getAccount({ user_id });
|
||||
const account = await getAccountById(user_id);
|
||||
|
||||
if (account.user_id === current_user_id || current_user_is_admin) {
|
||||
const data = { password: password ? await hashPassword(password) : undefined };
|
||||
const data = {};
|
||||
|
||||
if (password) {
|
||||
data.password = await hashPassword(password);
|
||||
}
|
||||
|
||||
// Only admin can change these fields
|
||||
if (current_user_is_admin) {
|
||||
@ -37,7 +31,7 @@ export default async (req, res) => {
|
||||
}
|
||||
|
||||
if (data.username && account.username !== data.username) {
|
||||
const accountByUsername = await getAccount({ username });
|
||||
const accountByUsername = await getAccountByUsername(username);
|
||||
|
||||
if (accountByUsername) {
|
||||
return badRequest(res, 'Account already exists');
|
||||
@ -51,7 +45,7 @@ export default async (req, res) => {
|
||||
|
||||
return unauthorized(res);
|
||||
} else {
|
||||
const accountByUsername = await getAccount({ username });
|
||||
const accountByUsername = await getAccountByUsername(username);
|
||||
|
||||
if (accountByUsername) {
|
||||
return badRequest(res, 'Account already exists');
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getAccount, deleteAccount } from 'lib/db';
|
||||
import { getAccountById, deleteAccount } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'lib/response';
|
||||
|
||||
@ -11,7 +11,7 @@ export default async (req, res) => {
|
||||
|
||||
if (req.method === 'GET') {
|
||||
if (is_admin) {
|
||||
const account = await getAccount({ user_id });
|
||||
const account = await getAccountById(user_id);
|
||||
|
||||
return ok(res, account);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getAccount, updateAccount } from 'lib/db';
|
||||
import { getAccountById, updateAccount } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { badRequest, methodNotAllowed, ok } from 'lib/response';
|
||||
import { checkPassword, hashPassword } from 'lib/crypto';
|
||||
@ -10,7 +10,7 @@ export default async (req, res) => {
|
||||
const { current_password, new_password } = req.body;
|
||||
|
||||
if (req.method === 'POST') {
|
||||
const account = await getAccount({ user_id });
|
||||
const account = await getAccountById(user_id);
|
||||
const valid = await checkPassword(current_password, account.password);
|
||||
|
||||
if (!valid) {
|
||||
|
21
pages/api/accounts.js
Normal file
21
pages/api/accounts.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { getAccounts } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, unauthorized, methodNotAllowed } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
const { is_admin: current_user_is_admin } = req.auth;
|
||||
|
||||
if (req.method === 'GET') {
|
||||
if (current_user_is_admin) {
|
||||
const accounts = await getAccounts();
|
||||
|
||||
return ok(res, accounts);
|
||||
}
|
||||
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
@ -1,13 +1,13 @@
|
||||
import { serialize } from 'cookie';
|
||||
import { checkPassword, createSecureToken } from 'lib/crypto';
|
||||
import { getAccount } from 'lib/db';
|
||||
import { getAccountByUsername } from 'lib/queries';
|
||||
import { AUTH_COOKIE_NAME } from 'lib/constants';
|
||||
import { ok, unauthorized } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
|
||||
const account = await getAccount({ username });
|
||||
const account = await getAccountByUsername(username);
|
||||
|
||||
if (account && (await checkPassword(password, account.password))) {
|
||||
const { user_id, username, is_admin } = account;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { savePageView, saveEvent } from 'lib/db';
|
||||
import { savePageView, saveEvent } from 'lib/queries';
|
||||
import { useCors, useSession } from 'lib/middleware';
|
||||
import { createToken } from 'lib/crypto';
|
||||
import { ok, badRequest } from 'lib/response';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getWebsites, updateWebsite, createWebsite, getWebsite } from 'lib/db';
|
||||
import { updateWebsite, createWebsite, getWebsiteById } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { uuid } from 'lib/crypto';
|
||||
import { ok, unauthorized, methodNotAllowed } from 'lib/response';
|
||||
@ -9,17 +9,11 @@ export default async (req, res) => {
|
||||
const { user_id, is_admin } = req.auth;
|
||||
const { website_id } = req.body;
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const websites = await getWebsites(user_id);
|
||||
|
||||
return ok(res, websites);
|
||||
}
|
||||
|
||||
if (req.method === 'POST') {
|
||||
const { name, domain } = req.body;
|
||||
|
||||
if (website_id) {
|
||||
const website = getWebsite(website_id);
|
||||
const website = getWebsiteById(website_id);
|
||||
|
||||
if (website.user_id === user_id || is_admin) {
|
||||
await updateWebsite(website_id, { name, domain });
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { deleteWebsite, getWebsite } from 'lib/db';
|
||||
import { deleteWebsite, getWebsiteById } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'lib/response';
|
||||
|
||||
@ -10,13 +10,13 @@ export default async (req, res) => {
|
||||
const website_id = +id;
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const website = await getWebsite({ website_id });
|
||||
const website = await getWebsiteById(website_id);
|
||||
|
||||
return ok(res, website);
|
||||
}
|
||||
|
||||
if (req.method === 'DELETE') {
|
||||
const website = await getWebsite({ website_id });
|
||||
const website = await getWebsiteById(website_id);
|
||||
|
||||
if (website.user_id === user_id || is_admin) {
|
||||
await deleteWebsite(website_id);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getMetrics } from 'lib/db';
|
||||
import { getMetrics } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { ok } from 'lib/response';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import moment from 'moment-timezone';
|
||||
import { getPageviewData } from 'lib/db';
|
||||
import { getPageviews } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, badRequest } from 'lib/response';
|
||||
|
||||
@ -18,8 +18,8 @@ export default async (req, res) => {
|
||||
const end = new Date(+end_at);
|
||||
|
||||
const [pageviews, uniques] = await Promise.all([
|
||||
getPageviewData(+id, start, end, tz, unit, '*'),
|
||||
getPageviewData(+id, start, end, tz, unit, 'distinct session_id'),
|
||||
getPageviews(+id, start, end, tz, unit, '*'),
|
||||
getPageviews(+id, start, end, tz, unit, 'distinct session_id'),
|
||||
]);
|
||||
|
||||
return ok(res, { pageviews, uniques });
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getRankings } from 'lib/db';
|
||||
import { getRankings } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, badRequest } from 'lib/response';
|
||||
|
||||
|
17
pages/api/websites.js
Normal file
17
pages/api/websites.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { getUserWebsites } from 'lib/queries';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { ok, methodNotAllowed } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
const { user_id } = req.auth;
|
||||
|
||||
if (req.method === 'GET') {
|
||||
const websites = await getUserWebsites(user_id);
|
||||
|
||||
return ok(res, websites);
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
@ -1,13 +1,10 @@
|
||||
import React from 'react';
|
||||
import Layout from 'components/layout/Layout';
|
||||
import LoginForm from 'components/forms/LoginForm';
|
||||
import Icon from 'components/common/Icon';
|
||||
import Logo from 'assets/logo.svg';
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<Layout title="login" header={false} footer={false} center middle>
|
||||
<Icon icon={<Logo />} size="xlarge" />
|
||||
<Layout title="login" header={false} footer={false} center>
|
||||
<LoginForm />
|
||||
</Layout>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user