mirror of
https://github.com/umami-software/umami.git
synced 2026-02-06 13:47:15 +01:00
Merge branch 'dev' into jajaja
This commit is contained in:
commit
fdc73268b7
16 changed files with 142 additions and 59 deletions
39
src/app/api/batch/route.ts
Normal file
39
src/app/api/batch/route.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { z } from 'zod';
|
||||
import * as send from '@/app/api/send/route';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { json, serverError } from '@/lib/response';
|
||||
|
||||
const schema = z.array(z.object({}).passthrough());
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const { body, error } = await parseRequest(request, schema, { skipAuth: true });
|
||||
|
||||
if (error) {
|
||||
return error();
|
||||
}
|
||||
|
||||
const errors = [];
|
||||
|
||||
let index = 0;
|
||||
for (const data of body) {
|
||||
const newRequest = new Request(request, { body: JSON.stringify(data) });
|
||||
const response = await send.POST(newRequest);
|
||||
|
||||
if (!response.ok) {
|
||||
errors.push({ index, response: await response.json() });
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return json({
|
||||
size: body.length,
|
||||
processed: body.length - errors.length,
|
||||
errors: errors.length,
|
||||
details: errors,
|
||||
});
|
||||
} catch (e) {
|
||||
return serverError(e);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,33 @@
|
|||
import { z } from 'zod';
|
||||
import { isbot } from 'isbot';
|
||||
import { createToken, parseToken } from '@/lib/jwt';
|
||||
import { startOfHour, startOfMonth } from 'date-fns';
|
||||
import clickhouse from '@/lib/clickhouse';
|
||||
import { parseRequest } from '@/lib/request';
|
||||
import { badRequest, json, forbidden, serverError } from '@/lib/response';
|
||||
import { fetchSession, fetchWebsite } from '@/lib/load';
|
||||
import { getClientInfo, hasBlockedIp } from '@/lib/detect';
|
||||
import { secret, uuid, visitSalt } from '@/lib/crypto';
|
||||
import { COLLECTION_TYPE, DOMAIN_REGEX } from '@/lib/constants';
|
||||
import { createToken, parseToken } from '@/lib/jwt';
|
||||
import { secret, uuid, hash } from '@/lib/crypto';
|
||||
import { COLLECTION_TYPE } from '@/lib/constants';
|
||||
import { anyObjectParam, urlOrPathParam } from '@/lib/schema';
|
||||
import { createSession, saveEvent, saveSessionData } from '@/queries';
|
||||
import { urlOrPathParam } from '@/lib/schema';
|
||||
|
||||
const schema = z.object({
|
||||
type: z.enum(['event', 'identify']),
|
||||
payload: z.object({
|
||||
website: z.string().uuid(),
|
||||
data: z.object({}).passthrough().optional(),
|
||||
hostname: z.string().regex(DOMAIN_REGEX).max(100).optional(),
|
||||
data: anyObjectParam.optional(),
|
||||
hostname: z.string().max(100).optional(),
|
||||
language: z.string().max(35).optional(),
|
||||
referrer: urlOrPathParam.optional(),
|
||||
screen: z.string().max(11).optional(),
|
||||
title: z.string().optional(),
|
||||
url: urlOrPathParam,
|
||||
url: urlOrPathParam.optional(),
|
||||
name: z.string().max(50).optional(),
|
||||
tag: z.string().max(50).optional(),
|
||||
ip: z.string().ip().optional(),
|
||||
userAgent: z.string().optional(),
|
||||
timestamp: z.coerce.number().int().optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -55,6 +57,7 @@ export async function POST(request: Request) {
|
|||
data,
|
||||
title,
|
||||
tag,
|
||||
timestamp,
|
||||
} = payload;
|
||||
|
||||
// Cache check
|
||||
|
|
@ -87,7 +90,13 @@ export async function POST(request: Request) {
|
|||
return forbidden();
|
||||
}
|
||||
|
||||
const sessionId = uuid(websiteId, ip, userAgent);
|
||||
const createdAt = timestamp ? new Date(timestamp * 1000) : new Date();
|
||||
const now = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
const sessionSalt = hash(startOfMonth(createdAt).toUTCString());
|
||||
const visitSalt = hash(startOfHour(createdAt).toUTCString());
|
||||
|
||||
const sessionId = uuid(websiteId, ip, userAgent, sessionSalt);
|
||||
|
||||
// Find session
|
||||
if (!clickhouse.enabled && !cache?.sessionId) {
|
||||
|
|
@ -119,13 +128,12 @@ export async function POST(request: Request) {
|
|||
}
|
||||
|
||||
// Visit info
|
||||
const now = Math.floor(new Date().getTime() / 1000);
|
||||
let visitId = cache?.visitId || uuid(sessionId, visitSalt());
|
||||
let visitId = cache?.visitId || uuid(sessionId, visitSalt);
|
||||
let iat = cache?.iat || now;
|
||||
|
||||
// Expire visit after 30 minutes
|
||||
if (now - iat > 1800) {
|
||||
visitId = uuid(sessionId, visitSalt());
|
||||
if (!timestamp && now - iat > 1800) {
|
||||
visitId = uuid(sessionId, visitSalt);
|
||||
iat = now;
|
||||
}
|
||||
|
||||
|
|
@ -179,6 +187,7 @@ export async function POST(request: Request) {
|
|||
subdivision2,
|
||||
city,
|
||||
tag,
|
||||
createdAt,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -191,12 +200,13 @@ export async function POST(request: Request) {
|
|||
websiteId,
|
||||
sessionId,
|
||||
sessionData: data,
|
||||
createdAt,
|
||||
});
|
||||
}
|
||||
|
||||
const token = createToken({ websiteId, sessionId, visitId, iat }, secret());
|
||||
|
||||
return json({ cache: token });
|
||||
return json({ cache: token, sessionId, visitId });
|
||||
} catch (e) {
|
||||
return serverError(e);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { createUser, getUserByUsername } from '@/queries';
|
|||
|
||||
export async function POST(request: Request) {
|
||||
const schema = z.object({
|
||||
id: z.string().uuid().optional(),
|
||||
username: z.string().max(255),
|
||||
password: z.string(),
|
||||
role: z.string().regex(/admin|user|view-only/i),
|
||||
|
|
@ -23,7 +24,7 @@ export async function POST(request: Request) {
|
|||
return unauthorized();
|
||||
}
|
||||
|
||||
const { username, password, role } = body;
|
||||
const { id, username, password, role } = body;
|
||||
|
||||
const existingUser = await getUserByUsername(username, { showDeleted: true });
|
||||
|
||||
|
|
@ -32,7 +33,7 @@ export async function POST(request: Request) {
|
|||
}
|
||||
|
||||
const user = await createUser({
|
||||
id: uuid(),
|
||||
id: id || uuid(),
|
||||
username,
|
||||
password: hashPassword(password),
|
||||
role: role ?? ROLES.user,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue