mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
Added parseDateRangeQuery function.
This commit is contained in:
parent
09af33c77e
commit
1648707fc7
@ -62,10 +62,10 @@ export function parseDateRange(value, locale = 'en-US') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (value?.startsWith?.('range')) {
|
if (value?.startsWith?.('range')) {
|
||||||
const [, startAt, endAt] = value.split(':');
|
const [, startTime, endTime] = value.split(':');
|
||||||
|
|
||||||
const startDate = new Date(+startAt);
|
const startDate = new Date(+startTime);
|
||||||
const endDate = new Date(+endAt);
|
const endDate = new Date(+endTime);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...getDateRangeValues(startDate, endDate),
|
...getDateRangeValues(startDate, endDate),
|
||||||
|
@ -10,7 +10,6 @@ export async function parseDateRangeQuery(req: NextApiRequest) {
|
|||||||
const { min, max } = await getWebsiteDateRange(websiteId as string);
|
const { min, max } = await getWebsiteDateRange(websiteId as string);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
websiteId,
|
|
||||||
startDate: min,
|
startDate: min,
|
||||||
endDate: max,
|
endDate: max,
|
||||||
unit: getMinimumUnit(min, max),
|
unit: getMinimumUnit(min, max),
|
||||||
@ -22,9 +21,8 @@ export async function parseDateRangeQuery(req: NextApiRequest) {
|
|||||||
const minUnit = getMinimumUnit(startDate, endDate);
|
const minUnit = getMinimumUnit(startDate, endDate);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
websiteId,
|
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
unit: getAllowedUnits(startDate, endDate).includes(unit as string) ? unit : minUnit,
|
unit: (getAllowedUnits(startDate, endDate).includes(unit as string) ? unit : minUnit) as string,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import moment from 'moment-timezone';
|
|||||||
import { NextApiResponse } from 'next';
|
import { NextApiResponse } from 'next';
|
||||||
import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
|
import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||||
import { getEventMetrics } from 'queries';
|
import { getEventMetrics } from 'queries';
|
||||||
|
import { parseDateRangeQuery } from 'lib/query';
|
||||||
|
|
||||||
const unitTypes = ['year', 'month', 'hour', 'day'];
|
const unitTypes = ['year', 'month', 'hour', 'day'];
|
||||||
|
|
||||||
@ -25,7 +26,8 @@ export default async (
|
|||||||
await useCors(req, res);
|
await useCors(req, res);
|
||||||
await useAuth(req, res);
|
await useAuth(req, res);
|
||||||
|
|
||||||
const { id: websiteId, startAt, endAt, unit, timezone, url, eventName } = req.query;
|
const { id: websiteId, timezone, url, eventName } = req.query;
|
||||||
|
const { startDate, endDate, unit } = await parseDateRangeQuery(req);
|
||||||
|
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
if (!(await canViewWebsite(req.auth, websiteId))) {
|
if (!(await canViewWebsite(req.auth, websiteId))) {
|
||||||
@ -35,8 +37,6 @@ export default async (
|
|||||||
if (!moment.tz.zone(timezone) || !unitTypes.includes(unit)) {
|
if (!moment.tz.zone(timezone) || !unitTypes.includes(unit)) {
|
||||||
return badRequest(res);
|
return badRequest(res);
|
||||||
}
|
}
|
||||||
const startDate = new Date(+startAt);
|
|
||||||
const endDate = new Date(+endAt);
|
|
||||||
|
|
||||||
const events = await getEventMetrics(websiteId, {
|
const events = await getEventMetrics(websiteId, {
|
||||||
startDate,
|
startDate,
|
||||||
|
@ -3,9 +3,9 @@ import { NextApiResponse } from 'next';
|
|||||||
import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
|
import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||||
import { NextApiRequestQueryBody, WebsitePageviews } from 'lib/types';
|
import { NextApiRequestQueryBody, WebsitePageviews } from 'lib/types';
|
||||||
import { canViewWebsite } from 'lib/auth';
|
import { canViewWebsite } from 'lib/auth';
|
||||||
import { getAllowedUnits } from 'lib/date';
|
|
||||||
import { useAuth, useCors } from 'lib/middleware';
|
import { useAuth, useCors } from 'lib/middleware';
|
||||||
import { getPageviewStats } from 'queries';
|
import { getPageviewStats } from 'queries';
|
||||||
|
import { parseDateRangeQuery } from 'lib/query';
|
||||||
|
|
||||||
export interface WebsitePageviewRequestQuery {
|
export interface WebsitePageviewRequestQuery {
|
||||||
id: string;
|
id: string;
|
||||||
@ -33,9 +33,6 @@ export default async (
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
id: websiteId,
|
id: websiteId,
|
||||||
startAt,
|
|
||||||
endAt,
|
|
||||||
unit,
|
|
||||||
timezone,
|
timezone,
|
||||||
url,
|
url,
|
||||||
referrer,
|
referrer,
|
||||||
@ -53,10 +50,9 @@ export default async (
|
|||||||
return unauthorized(res);
|
return unauthorized(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
const startDate = new Date(+startAt);
|
const { startDate, endDate, unit } = await parseDateRangeQuery(req);
|
||||||
const endDate = new Date(+endAt);
|
|
||||||
|
|
||||||
if (!moment.tz.zone(timezone) || !getAllowedUnits(unit).includes(unit)) {
|
if (!moment.tz.zone(timezone)) {
|
||||||
return badRequest(res);
|
return badRequest(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
|
import { addMinutes, differenceInMinutes } from 'date-fns';
|
||||||
|
import { NextApiResponse } from 'next';
|
||||||
|
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||||
import { canViewWebsite } from 'lib/auth';
|
import { canViewWebsite } from 'lib/auth';
|
||||||
import { useAuth, useCors } from 'lib/middleware';
|
import { useAuth, useCors } from 'lib/middleware';
|
||||||
import { NextApiRequestQueryBody, WebsiteStats } from 'lib/types';
|
import { NextApiRequestQueryBody, WebsiteStats } from 'lib/types';
|
||||||
import { NextApiResponse } from 'next';
|
import { parseDateRangeQuery } from 'lib/query';
|
||||||
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
|
||||||
import { getWebsiteStats } from 'queries';
|
import { getWebsiteStats } from 'queries';
|
||||||
|
|
||||||
export interface WebsiteStatsRequestQuery {
|
export interface WebsiteStatsRequestQuery {
|
||||||
@ -31,8 +33,6 @@ export default async (
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
id: websiteId,
|
id: websiteId,
|
||||||
startAt,
|
|
||||||
endAt,
|
|
||||||
url,
|
url,
|
||||||
referrer,
|
referrer,
|
||||||
title,
|
title,
|
||||||
@ -51,12 +51,10 @@ export default async (
|
|||||||
return unauthorized(res);
|
return unauthorized(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
const startDate = new Date(+startAt);
|
const { startDate, endDate } = await parseDateRangeQuery(req);
|
||||||
const endDate = new Date(+endAt);
|
const diff = differenceInMinutes(endDate, startDate);
|
||||||
|
const prevStartDate = addMinutes(startDate, -diff);
|
||||||
const distance = endAt - startAt;
|
const prevEndDate = addMinutes(endDate, -diff);
|
||||||
const prevStartDate = new Date(+startAt - distance);
|
|
||||||
const prevEndDate = new Date(+endAt - distance);
|
|
||||||
|
|
||||||
const metrics = await getWebsiteStats(websiteId, {
|
const metrics = await getWebsiteStats(websiteId, {
|
||||||
startDate,
|
startDate,
|
||||||
|
@ -2,26 +2,26 @@ import clickhouse from 'lib/clickhouse';
|
|||||||
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
||||||
import prisma from 'lib/prisma';
|
import prisma from 'lib/prisma';
|
||||||
|
|
||||||
export function getEvents(...args: [websiteId: string, startAt: Date, eventType: number]) {
|
export function getEvents(...args: [websiteId: string, startDate: Date, eventType: number]) {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(...args),
|
[PRISMA]: () => relationalQuery(...args),
|
||||||
[CLICKHOUSE]: () => clickhouseQuery(...args),
|
[CLICKHOUSE]: () => clickhouseQuery(...args),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function relationalQuery(websiteId: string, startAt: Date, eventType: number) {
|
function relationalQuery(websiteId: string, startDate: Date, eventType: number) {
|
||||||
return prisma.client.websiteEvent.findMany({
|
return prisma.client.websiteEvent.findMany({
|
||||||
where: {
|
where: {
|
||||||
websiteId,
|
websiteId,
|
||||||
eventType,
|
eventType,
|
||||||
createdAt: {
|
createdAt: {
|
||||||
gte: startAt,
|
gte: startDate,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickhouseQuery(websiteId: string, startAt: Date, eventType: number) {
|
function clickhouseQuery(websiteId: string, startDate: Date, eventType: number) {
|
||||||
const { rawQuery } = clickhouse;
|
const { rawQuery } = clickhouse;
|
||||||
|
|
||||||
return rawQuery(
|
return rawQuery(
|
||||||
@ -37,12 +37,12 @@ function clickhouseQuery(websiteId: string, startAt: Date, eventType: number) {
|
|||||||
event_name as eventName
|
event_name as eventName
|
||||||
from website_event
|
from website_event
|
||||||
where website_id = {websiteId:UUID}
|
where website_id = {websiteId:UUID}
|
||||||
and created_at >= {startAt:DateTime}
|
and created_at >= {startDate:DateTime}
|
||||||
and event_type = {eventType:UInt32}
|
and event_type = {eventType:UInt32}
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
websiteId,
|
websiteId,
|
||||||
startAt,
|
startDate,
|
||||||
eventType,
|
eventType,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
import clickhouse from 'lib/clickhouse';
|
import clickhouse from 'lib/clickhouse';
|
||||||
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
|
||||||
import prisma from 'lib/prisma';
|
import prisma from 'lib/prisma';
|
||||||
import { DEFAULT_RESET_DATE, EVENT_TYPE } from 'lib/constants';
|
import { EVENT_TYPE } from 'lib/constants';
|
||||||
import { loadWebsite } from 'lib/load';
|
import { loadWebsite } from 'lib/load';
|
||||||
import { maxDate } from 'lib/date';
|
import { maxDate } from 'lib/date';
|
||||||
|
|
||||||
|
export interface PageviewStatsCriteria {
|
||||||
|
startDate: Date;
|
||||||
|
endDate: Date;
|
||||||
|
timezone?: string;
|
||||||
|
unit?: string;
|
||||||
|
count?: string;
|
||||||
|
filters: object;
|
||||||
|
sessionKey?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getPageviewStats(
|
export async function getPageviewStats(
|
||||||
...args: [
|
...args: [websiteId: string, criteria: PageviewStatsCriteria]
|
||||||
websiteId: string,
|
|
||||||
criteria: {
|
|
||||||
startDate: Date;
|
|
||||||
endDate: Date;
|
|
||||||
timezone?: string;
|
|
||||||
unit?: string;
|
|
||||||
count?: string;
|
|
||||||
filters: object;
|
|
||||||
sessionKey?: string;
|
|
||||||
},
|
|
||||||
]
|
|
||||||
) {
|
) {
|
||||||
return runQuery({
|
return runQuery({
|
||||||
[PRISMA]: () => relationalQuery(...args),
|
[PRISMA]: () => relationalQuery(...args),
|
||||||
@ -25,18 +24,7 @@ export async function getPageviewStats(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function relationalQuery(
|
async function relationalQuery(websiteId: string, criteria: PageviewStatsCriteria) {
|
||||||
websiteId: string,
|
|
||||||
criteria: {
|
|
||||||
startDate: Date;
|
|
||||||
endDate: Date;
|
|
||||||
timezone?: string;
|
|
||||||
unit?: string;
|
|
||||||
count?: string;
|
|
||||||
filters: object;
|
|
||||||
sessionKey?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const {
|
const {
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
@ -73,18 +61,7 @@ async function relationalQuery(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clickhouseQuery(
|
async function clickhouseQuery(websiteId: string, criteria: PageviewStatsCriteria) {
|
||||||
websiteId: string,
|
|
||||||
criteria: {
|
|
||||||
startDate: Date;
|
|
||||||
endDate: Date;
|
|
||||||
timezone?: string;
|
|
||||||
unit?: string;
|
|
||||||
count?: string;
|
|
||||||
filters: object;
|
|
||||||
sessionKey?: string;
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
const {
|
const {
|
||||||
startDate,
|
startDate,
|
||||||
endDate,
|
endDate,
|
||||||
|
@ -9,18 +9,18 @@ export async function getSessions(...args: [websiteId: string, startAt: Date]) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function relationalQuery(websiteId: string, startAt: Date) {
|
async function relationalQuery(websiteId: string, startDate: Date) {
|
||||||
return prisma.client.session.findMany({
|
return prisma.client.session.findMany({
|
||||||
where: {
|
where: {
|
||||||
websiteId,
|
websiteId,
|
||||||
createdAt: {
|
createdAt: {
|
||||||
gte: startAt,
|
gte: startDate,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clickhouseQuery(websiteId: string, startAt: Date) {
|
async function clickhouseQuery(websiteId: string, startDate: Date) {
|
||||||
const { rawQuery } = clickhouse;
|
const { rawQuery } = clickhouse;
|
||||||
|
|
||||||
return rawQuery(
|
return rawQuery(
|
||||||
@ -42,11 +42,11 @@ async function clickhouseQuery(websiteId: string, startAt: Date) {
|
|||||||
city
|
city
|
||||||
from website_event
|
from website_event
|
||||||
where website_id = {websiteId:UUID}
|
where website_id = {websiteId:UUID}
|
||||||
and created_at >= {startAt:DateTime}
|
and created_at >= {startDate:DateTime}
|
||||||
`,
|
`,
|
||||||
{
|
{
|
||||||
websiteId,
|
websiteId,
|
||||||
startAt,
|
startDate,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ export async function getWebsiteDateRange(...args: [websiteId: string]) {
|
|||||||
|
|
||||||
async function relationalQuery(websiteId: string) {
|
async function relationalQuery(websiteId: string) {
|
||||||
const { rawQuery } = prisma;
|
const { rawQuery } = prisma;
|
||||||
|
const website = await loadWebsite(websiteId);
|
||||||
|
|
||||||
return rawQuery(
|
return rawQuery(
|
||||||
`
|
`
|
||||||
@ -21,12 +22,10 @@ async function relationalQuery(websiteId: string) {
|
|||||||
min(created_at) as min,
|
min(created_at) as min,
|
||||||
max(created_at) as max
|
max(created_at) as max
|
||||||
from website_event
|
from website_event
|
||||||
join website
|
where website_id = {{websiteId::uuid}}
|
||||||
on website_event.website_id = website.website_id
|
and created_at >= {{startDate}}
|
||||||
where website.website_id = {{websiteId::uuid}}
|
|
||||||
and website_event.created_at >= coalesce(website.reset_at, website.created_at)
|
|
||||||
`,
|
`,
|
||||||
{ websiteId },
|
{ websiteId, startDate: maxDate(new Date(DEFAULT_RESET_DATE), new Date(website.resetAt)) },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +42,6 @@ async function clickhouseQuery(websiteId: string) {
|
|||||||
where website_id = {websiteId:UUID}
|
where website_id = {websiteId:UUID}
|
||||||
and created_at >= {startDate:DateTime}
|
and created_at >= {startDate:DateTime}
|
||||||
`,
|
`,
|
||||||
{ websiteId, startDate: maxDate(new Date(DEFAULT_RESET_DATE), website.resetAt) },
|
{ websiteId, startDate: maxDate(new Date(DEFAULT_RESET_DATE), new Date(website.resetAt)) },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user