mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Fix #3699: Prevent exporting empty datasets
This commit is contained in:
parent
b4599e78b2
commit
d9927a0489
1 changed files with 92 additions and 47 deletions
|
|
@ -1,23 +1,26 @@
|
|||
import { z } from 'zod';
|
||||
import JSZip from 'jszip';
|
||||
import Papa from 'papaparse';
|
||||
import { getQueryFilters, parseRequest } from '@/lib/request';
|
||||
import { unauthorized, json } from '@/lib/response';
|
||||
import { canViewWebsite } from '@/permissions';
|
||||
import { pagingParams, dateRangeParams } from '@/lib/schema';
|
||||
import { getEventMetrics, getPageviewMetrics, getSessionMetrics } from '@/queries/sql';
|
||||
import { badRequest, json, methodNotAllowed, unauthorized } from '@/lib/response';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { getDateRangeValues, parseDateRange } from '@/lib/date';
|
||||
import {
|
||||
getEvents,
|
||||
getPageviews,
|
||||
getReferrers,
|
||||
getBrowsers,
|
||||
getOS,
|
||||
getDevices,
|
||||
getCountries,
|
||||
getRegions,
|
||||
getCities,
|
||||
} from '@/queries/sql';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Promise<{ websiteId: string }> },
|
||||
) {
|
||||
const schema = z.object({
|
||||
export async function GET(request: Request, { params }: { params: Promise<{ websiteId: string }> }) {
|
||||
const { auth, query, error } = await parseRequest(request, {
|
||||
type: z.enum(['events', 'pageviews', 'referrers', 'browsers', 'os', 'devices', 'countries', 'regions', 'cities']),
|
||||
...dateRangeParams,
|
||||
...pagingParams,
|
||||
...filterParams,
|
||||
});
|
||||
|
||||
const { auth, query, error } = await parseRequest(request, schema);
|
||||
|
||||
if (error) {
|
||||
return error();
|
||||
}
|
||||
|
|
@ -28,17 +31,67 @@ export async function GET(
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const { type } = query;
|
||||
const { startDate, endDate } = parseDateRange(query);
|
||||
|
||||
const filters = await getQueryFilters(query, websiteId);
|
||||
|
||||
const [events, pages, referrers, browsers, os, devices, countries] = await Promise.all([
|
||||
getEventMetrics(websiteId, { type: 'event' }, filters),
|
||||
getPageviewMetrics(websiteId, { type: 'path' }, filters),
|
||||
getPageviewMetrics(websiteId, { type: 'referrer' }, filters),
|
||||
getSessionMetrics(websiteId, { type: 'browser' }, filters),
|
||||
getSessionMetrics(websiteId, { type: 'os' }, filters),
|
||||
getSessionMetrics(websiteId, { type: 'device' }, filters),
|
||||
getSessionMetrics(websiteId, { type: 'country' }, filters),
|
||||
]);
|
||||
switch (type) {
|
||||
case 'events':
|
||||
return json(await getEvents(websiteId, { startDate, endDate }, filters));
|
||||
case 'pageviews':
|
||||
return json(await getPageviews(websiteId, { startDate, endDate }, filters));
|
||||
case 'referrers':
|
||||
return json(await getReferrers(websiteId, { startDate, endDate }, filters));
|
||||
case 'browsers':
|
||||
return json(await getBrowsers(websiteId, { startDate, endDate }, filters));
|
||||
case 'os':
|
||||
return json(await getOS(websiteId, { startDate, endDate }, filters));
|
||||
case 'devices':
|
||||
return json(await getDevices(websiteId, { startDate, endDate }, filters));
|
||||
case 'countries':
|
||||
return json(await getCountries(websiteId, { startDate, endDate }, filters));
|
||||
case 'regions':
|
||||
return json(await getRegions(websiteId, { startDate, endDate }, filters));
|
||||
case 'cities':
|
||||
return json(await getCities(websiteId, { startDate, endDate }, filters));
|
||||
default:
|
||||
return badRequest('Invalid type');
|
||||
}
|
||||
}
|
||||
|
||||
// Add the export function
|
||||
export async function POST(request: Request, { params }: { params: Promise<{ websiteId: string }> }) {
|
||||
const { auth, query, error } = await parseRequest(request, {
|
||||
...dateRangeParams,
|
||||
...filterParams,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return error();
|
||||
}
|
||||
|
||||
const { websiteId } = await params;
|
||||
|
||||
if (!(await canViewWebsite(auth, websiteId))) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
const { startDate, endDate } = parseDateRange(query);
|
||||
const filters = await getQueryFilters(query, websiteId);
|
||||
|
||||
const [events, pages, referrers, browsers, os, devices, countries, regions, cities] =
|
||||
await Promise.all([
|
||||
getEvents(websiteId, { startDate, endDate }, filters),
|
||||
getPageviews(websiteId, { startDate, endDate }, filters),
|
||||
getReferrers(websiteId, { startDate, endDate }, filters),
|
||||
getBrowsers(websiteId, { startDate, endDate }, filters),
|
||||
getOS(websiteId, { startDate, endDate }, filters),
|
||||
getDevices(websiteId, { startDate, endDate }, filters),
|
||||
getCountries(websiteId, { startDate, endDate }, filters),
|
||||
getRegions(websiteId, { startDate, endDate }, filters),
|
||||
getCities(websiteId, { startDate, endDate }, filters),
|
||||
]);
|
||||
|
||||
// Check if all datasets are empty
|
||||
const hasData = [
|
||||
|
|
@ -48,32 +101,24 @@ export async function GET(
|
|||
browsers,
|
||||
os,
|
||||
devices,
|
||||
countries
|
||||
countries,
|
||||
regions,
|
||||
cities
|
||||
].some(dataset => dataset && dataset.length > 0);
|
||||
|
||||
if (!hasData) {
|
||||
return json({ error: 'no_data' });
|
||||
}
|
||||
|
||||
const zip = new JSZip();
|
||||
|
||||
const parse = (data: any) => {
|
||||
return Papa.unparse(data, {
|
||||
header: true,
|
||||
skipEmptyLines: true,
|
||||
});
|
||||
};
|
||||
|
||||
zip.file('events.csv', parse(events));
|
||||
zip.file('pages.csv', parse(pages));
|
||||
zip.file('referrers.csv', parse(referrers));
|
||||
zip.file('browsers.csv', parse(browsers));
|
||||
zip.file('os.csv', parse(os));
|
||||
zip.file('devices.csv', parse(devices));
|
||||
zip.file('countries.csv', parse(countries));
|
||||
|
||||
const content = await zip.generateAsync({ type: 'nodebuffer' });
|
||||
const base64 = content.toString('base64');
|
||||
|
||||
return json({ zip: base64 });
|
||||
}
|
||||
return json({
|
||||
events,
|
||||
pages,
|
||||
referrers,
|
||||
browsers,
|
||||
os,
|
||||
devices,
|
||||
countries,
|
||||
regions,
|
||||
cities,
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue