mirror of
https://github.com/umami-software/umami.git
synced 2026-02-05 05:07:15 +01:00
Merge branch 'master' into hosts-support
This commit is contained in:
commit
e11c2e452c
69 changed files with 3783 additions and 2197 deletions
|
|
@ -1,13 +1,13 @@
|
|||
import { canViewUsers } from 'lib/auth';
|
||||
import { useAuth, useValidate } from 'lib/middleware';
|
||||
import { NextApiRequestQueryBody, Role, SearchFilter, User } from 'lib/types';
|
||||
import { NextApiRequestQueryBody, Role, PageParams, User } from 'lib/types';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||
import { getUsers } from 'queries';
|
||||
import * as yup from 'yup';
|
||||
|
||||
export interface UsersRequestQuery extends SearchFilter {}
|
||||
export interface UsersRequestQuery extends PageParams {}
|
||||
export interface UsersRequestBody {
|
||||
userId: string;
|
||||
username: string;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
import { canViewAllWebsites } from 'lib/auth';
|
||||
import { ROLES } from 'lib/constants';
|
||||
import { useAuth, useCors, useValidate } from 'lib/middleware';
|
||||
import { NextApiRequestQueryBody, SearchFilter } from 'lib/types';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
import { NextApiRequestQueryBody, PageParams } from 'lib/types';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||
import { getWebsites } from 'queries';
|
||||
import * as yup from 'yup';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
|
||||
export interface WebsitesRequestQuery extends SearchFilter {}
|
||||
export interface WebsitesRequestQuery extends PageParams {
|
||||
userId?: string;
|
||||
includeTeams?: boolean;
|
||||
}
|
||||
|
||||
export interface WebsitesRequestBody {
|
||||
name: string;
|
||||
|
|
@ -39,8 +43,29 @@ export default async (
|
|||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const { userId, includeOwnedTeams } = req.query;
|
||||
|
||||
const websites = await getWebsites(
|
||||
{
|
||||
where: {
|
||||
OR: [
|
||||
...(userId && [{ userId }]),
|
||||
...(userId &&
|
||||
includeOwnedTeams && [
|
||||
{
|
||||
team: {
|
||||
deletedAt: null,
|
||||
teamUser: {
|
||||
some: {
|
||||
role: ROLES.teamOwner,
|
||||
userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
},
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
|
|
@ -48,6 +73,18 @@ export default async (
|
|||
id: true,
|
||||
},
|
||||
},
|
||||
team: {
|
||||
where: {
|
||||
deletedAt: null,
|
||||
},
|
||||
include: {
|
||||
teamUser: {
|
||||
where: {
|
||||
role: ROLES.teamOwner,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
req.query,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const schema = {
|
|||
GET: yup.object().shape({
|
||||
websiteId: yup.string().uuid().required(),
|
||||
startAt: yup.number().integer().required(),
|
||||
endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(),
|
||||
endAt: yup.number().integer().min(yup.ref('startAt')).required(),
|
||||
event: yup.string(),
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const schema = {
|
|||
GET: yup.object().shape({
|
||||
websiteId: yup.string().uuid().required(),
|
||||
startAt: yup.number().integer().required(),
|
||||
endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(),
|
||||
endAt: yup.number().integer().min(yup.ref('startAt')).required(),
|
||||
field: yup.string(),
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const schema = {
|
|||
GET: yup.object().shape({
|
||||
websiteId: yup.string().uuid().required(),
|
||||
startAt: yup.number().integer().required(),
|
||||
endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(),
|
||||
endAt: yup.number().integer().min(yup.ref('startAt')).required(),
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,5 @@
|
|||
import ipaddr from 'ipaddr.js';
|
||||
import { isbot } from 'isbot';
|
||||
import { COLLECTION_TYPE, HOSTNAME_REGEX, IP_REGEX } from 'lib/constants';
|
||||
import { secret, visitSalt, uuid } from 'lib/crypto';
|
||||
import { getIpAddress } from 'lib/detect';
|
||||
import { useCors, useSession, useValidate } from 'lib/middleware';
|
||||
import { CollectionType, YupRequest } from 'lib/types';
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import {
|
||||
badRequest,
|
||||
|
|
@ -15,6 +10,11 @@ import {
|
|||
safeDecodeURI,
|
||||
send,
|
||||
} from 'next-basics';
|
||||
import { COLLECTION_TYPE, HOSTNAME_REGEX, IP_REGEX } from 'lib/constants';
|
||||
import { secret, visitSalt, uuid } from 'lib/crypto';
|
||||
import { getIpAddress } from 'lib/detect';
|
||||
import { useCors, useSession, useValidate } from 'lib/middleware';
|
||||
import { CollectionType, YupRequest } from 'lib/types';
|
||||
import { saveEvent, saveSessionData } from 'queries';
|
||||
import * as yup from 'yup';
|
||||
|
||||
|
|
@ -41,7 +41,6 @@ export interface NextApiRequestCollect extends NextApiRequest {
|
|||
id: string;
|
||||
websiteId: string;
|
||||
visitId: string;
|
||||
ownerId: string;
|
||||
hostname: string;
|
||||
browser: string;
|
||||
os: string;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const schema = {
|
|||
POST: yup.object().shape({
|
||||
role: yup
|
||||
.string()
|
||||
.matches(/team-member|team-view-only/i)
|
||||
.matches(/team-member|team-view-only|team-manager/i)
|
||||
.required(),
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { canAddUserToTeam, canViewTeam } from 'lib/auth';
|
||||
import { useAuth, useValidate } from 'lib/middleware';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
import { NextApiRequestQueryBody, SearchFilter } from 'lib/types';
|
||||
import { NextApiRequestQueryBody, PageParams } from 'lib/types';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { badRequest, methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||
import { createTeamUser, getTeamUser, getTeamUsers } from 'queries';
|
||||
import * as yup from 'yup';
|
||||
|
||||
export interface TeamUserRequestQuery extends SearchFilter {
|
||||
export interface TeamUserRequestQuery extends PageParams {
|
||||
teamId: string;
|
||||
}
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ const schema = {
|
|||
userId: yup.string().uuid().required(),
|
||||
role: yup
|
||||
.string()
|
||||
.matches(/team-member|team-view-only/i)
|
||||
.matches(/team-member|team-view-only|team-manager/i)
|
||||
.required(),
|
||||
}),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import * as yup from 'yup';
|
||||
import { canViewTeam } from 'lib/auth';
|
||||
import { useAuth, useValidate } from 'lib/middleware';
|
||||
import { NextApiRequestQueryBody, SearchFilter } from 'lib/types';
|
||||
import { NextApiRequestQueryBody, PageParams } from 'lib/types';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { ok, unauthorized } from 'next-basics';
|
||||
import { getTeamWebsites } from 'queries';
|
||||
|
||||
export interface TeamWebsiteRequestQuery extends SearchFilter {
|
||||
export interface TeamWebsiteRequestQuery extends PageParams {
|
||||
teamId: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ import { Team } from '@prisma/client';
|
|||
import { canCreateTeam } from 'lib/auth';
|
||||
import { uuid } from 'lib/crypto';
|
||||
import { useAuth, useValidate } from 'lib/middleware';
|
||||
import { NextApiRequestQueryBody, SearchFilter } from 'lib/types';
|
||||
import { NextApiRequestQueryBody, PageParams } from 'lib/types';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { getRandomChars, methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||
import { createTeam } from 'queries';
|
||||
|
||||
export interface TeamsRequestQuery extends SearchFilter {}
|
||||
export interface TeamsRequestQuery extends PageParams {}
|
||||
export interface TeamsRequestBody {
|
||||
name: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import * as yup from 'yup';
|
||||
import { useAuth, useCors, useValidate } from 'lib/middleware';
|
||||
import { NextApiRequestQueryBody, SearchFilter } from 'lib/types';
|
||||
import { NextApiRequestQueryBody, PageParams } from 'lib/types';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||
import { getUserTeams } from 'queries';
|
||||
|
||||
export interface UserTeamsRequestQuery extends SearchFilter {
|
||||
export interface UserTeamsRequestQuery extends PageParams {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const schema = {
|
|||
GET: yup.object().shape({
|
||||
id: yup.string().uuid().required(),
|
||||
startAt: yup.number().integer().required(),
|
||||
endAt: yup.number().integer().moreThan(yup.ref<number>('startAt')).required(),
|
||||
endAt: yup.number().integer().min(yup.ref<number>('startAt')).required(),
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import { canCreateUser } from 'lib/auth';
|
|||
import { ROLES } from 'lib/constants';
|
||||
import { uuid } from 'lib/crypto';
|
||||
import { useAuth, useValidate } from 'lib/middleware';
|
||||
import { NextApiRequestQueryBody, Role, SearchFilter, User } from 'lib/types';
|
||||
import { NextApiRequestQueryBody, Role, PageParams, User } from 'lib/types';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { badRequest, hashPassword, methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||
import { createUser, getUserByUsername } from 'queries';
|
||||
import * as yup from 'yup';
|
||||
|
||||
export interface UsersRequestQuery extends SearchFilter {}
|
||||
export interface UsersRequestQuery extends PageParams {}
|
||||
export interface UsersRequestBody {
|
||||
username: string;
|
||||
password: string;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { canViewWebsite } from 'lib/auth';
|
||||
import { useAuth, useCors, useValidate } from 'lib/middleware';
|
||||
import { getRequestDateRange } from 'lib/request';
|
||||
import { getRequestFilters, getRequestDateRange } from 'lib/request';
|
||||
import { NextApiRequestQueryBody, WebsiteMetric } from 'lib/types';
|
||||
import { TimezoneTest, UnitTypeTest } from 'lib/yup';
|
||||
import { NextApiResponse } from 'next';
|
||||
|
|
@ -15,16 +15,32 @@ export interface WebsiteEventsRequestQuery {
|
|||
unit?: string;
|
||||
timezone?: string;
|
||||
url: string;
|
||||
referrer?: string;
|
||||
title?: string;
|
||||
os?: string;
|
||||
browser?: string;
|
||||
device?: string;
|
||||
country?: string;
|
||||
region: string;
|
||||
city?: string;
|
||||
}
|
||||
|
||||
const schema = {
|
||||
GET: yup.object().shape({
|
||||
websiteId: yup.string().uuid().required(),
|
||||
startAt: yup.number().integer().required(),
|
||||
endAt: yup.number().integer().moreThan(yup.ref('startAt')).required(),
|
||||
endAt: yup.number().integer().min(yup.ref('startAt')).required(),
|
||||
unit: UnitTypeTest,
|
||||
timezone: TimezoneTest,
|
||||
url: yup.string(),
|
||||
referrer: yup.string(),
|
||||
title: yup.string(),
|
||||
os: yup.string(),
|
||||
browser: yup.string(),
|
||||
device: yup.string(),
|
||||
country: yup.string(),
|
||||
region: yup.string(),
|
||||
city: yup.string(),
|
||||
}),
|
||||
};
|
||||
|
||||
|
|
@ -36,7 +52,7 @@ export default async (
|
|||
await useAuth(req, res);
|
||||
await useValidate(schema, req, res);
|
||||
|
||||
const { websiteId, timezone, url } = req.query;
|
||||
const { websiteId, timezone } = req.query;
|
||||
const { startDate, endDate, unit } = await getRequestDateRange(req);
|
||||
|
||||
if (req.method === 'GET') {
|
||||
|
|
@ -44,13 +60,15 @@ export default async (
|
|||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const events = await getEventMetrics(websiteId, {
|
||||
const filters = {
|
||||
...getRequestFilters(req),
|
||||
startDate,
|
||||
endDate,
|
||||
timezone,
|
||||
unit,
|
||||
url,
|
||||
});
|
||||
};
|
||||
|
||||
const events = await getEventMetrics(websiteId, filters);
|
||||
|
||||
return ok(res, events);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import * as yup from 'yup';
|
||||
import { canViewWebsite } from 'lib/auth';
|
||||
import { useAuth, useCors, useValidate } from 'lib/middleware';
|
||||
import { NextApiRequestQueryBody, SearchFilter } from 'lib/types';
|
||||
import { NextApiRequestQueryBody, PageParams } from 'lib/types';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||
import { getWebsiteReports } from 'queries';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
|
||||
export interface ReportsRequestQuery extends SearchFilter {
|
||||
export interface ReportsRequestQuery extends PageParams {
|
||||
websiteId: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { canCreateTeamWebsite, canCreateWebsite } from 'lib/auth';
|
||||
import { uuid } from 'lib/crypto';
|
||||
import { useAuth, useCors, useValidate } from 'lib/middleware';
|
||||
import { NextApiRequestQueryBody, SearchFilter } from 'lib/types';
|
||||
import { NextApiRequestQueryBody, PageParams } from 'lib/types';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { methodNotAllowed, ok, unauthorized } from 'next-basics';
|
||||
import { createWebsite } from 'queries';
|
||||
|
|
@ -9,7 +9,7 @@ import userWebsitesRoute from 'pages/api/users/[userId]/websites';
|
|||
import * as yup from 'yup';
|
||||
import { pageInfo } from 'lib/schema';
|
||||
|
||||
export interface WebsitesRequestQuery extends SearchFilter {}
|
||||
export interface WebsitesRequestQuery extends PageParams {}
|
||||
|
||||
export interface WebsitesRequestBody {
|
||||
name: string;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue