diff --git a/dashboard/composables/useCustomFetch.ts b/dashboard/composables/useCustomFetch.ts index 9c25f7a..6460f3c 100644 --- a/dashboard/composables/useCustomFetch.ts +++ b/dashboard/composables/useCustomFetch.ts @@ -3,16 +3,18 @@ type RefOrPrimitive = T | Ref | ComputedRef export type CustomOptions = { useSnapshotDates?: boolean, + useActiveDomain?: boolean, useActivePid?: boolean, useTimeOffset?: boolean, slice?: RefOrPrimitive, limit?: RefOrPrimitive, - custom?: Record> + custom?: Record>, } const { token } = useAccessToken(); const { projectId } = useProject(); const { safeSnapshotDates } = useSnapshot() +const { domain } = useDomain(); function getValueFromRefOrPrimitive(data?: T | Ref | ComputedRef) { if (!data) return; @@ -24,6 +26,7 @@ export function useComputedHeaders(customOptions?: CustomOptions) { const useSnapshotDates = customOptions?.useSnapshotDates || true; const useActivePid = customOptions?.useActivePid || true; const useTimeOffset = customOptions?.useTimeOffset || true; + const useActiveDomain = customOptions?.useActiveDomain || true; const headers = computed>(() => { // console.trace('Computed recalculated'); @@ -41,6 +44,7 @@ export function useComputedHeaders(customOptions?: CustomOptions) { 'x-time-offset': useTimeOffset ? (new Date().getTimezoneOffset().toString()) : '', 'x-slice': getValueFromRefOrPrimitive(customOptions?.slice) ?? '', 'x-limit': getValueFromRefOrPrimitive(customOptions?.limit)?.toString() ?? '', + 'x-domain': useActiveDomain ? (domain.value ?? '') : '', ...parsedCustom } }) diff --git a/dashboard/pages/index.vue b/dashboard/pages/index.vue index dc8ca35..faea57a 100644 --- a/dashboard/pages/index.vue +++ b/dashboard/pages/index.vue @@ -55,6 +55,7 @@ const selfhosted = useSelfhosted(); +
@@ -65,7 +66,7 @@ const selfhosted = useSelfhosted();
- +
@@ -77,6 +78,7 @@ const selfhosted = useSelfhosted();
+
@@ -86,7 +88,7 @@ const selfhosted = useSelfhosted();
-
+
diff --git a/dashboard/server/api/data/countries.ts b/dashboard/server/api/data/countries.ts index 843b3e4..615dace 100644 --- a/dashboard/server/api/data/countries.ts +++ b/dashboard/server/api/data/countries.ts @@ -1,16 +1,15 @@ import { VisitModel } from "@schema/metrics/VisitSchema"; import { Redis } from "~/server/services/CacheService"; -import { getRequestDataOld } from "~/server/utils/getRequestData"; export default defineEventHandler(async event => { - const data = await getRequestDataOld(event, { requireSchema: false }); + const data = await getRequestData(event, ['GUEST', 'RANGE', 'GUEST', 'DOMAIN']); if (!data) return; - const { pid, from, to, project_id, limit } = data; + const { pid, from, to, project_id, limit, domain } = data; - const cacheKey = `countries:${pid}:${limit}:${from}:${to}`; + const cacheKey = `countries:${pid}:${limit}:${from}:${to}:${domain}`; const cacheExp = 60; return await Redis.useCacheV2(cacheKey, cacheExp, async () => { @@ -19,7 +18,8 @@ export default defineEventHandler(async event => { { $match: { project_id, - created_at: { $gte: new Date(from), $lte: new Date(to) } + created_at: { $gte: new Date(from), $lte: new Date(to) }, + website: domain } }, { $group: { _id: "$country", count: { $sum: 1, } } }, diff --git a/dashboard/server/api/data/devices.ts b/dashboard/server/api/data/devices.ts index c1b1bc8..f0df1f4 100644 --- a/dashboard/server/api/data/devices.ts +++ b/dashboard/server/api/data/devices.ts @@ -1,16 +1,15 @@ import { VisitModel } from "@schema/metrics/VisitSchema"; import { Redis } from "~/server/services/CacheService"; -import { getRequestDataOld } from "~/server/utils/getRequestData"; export default defineEventHandler(async event => { - const data = await getRequestDataOld(event, { requireSchema: false }); + const data = await getRequestData(event, ['GUEST', 'RANGE', 'GUEST', 'DOMAIN']); if (!data) return; - const { pid, from, to, project_id, limit } = data; + const { pid, from, to, project_id, limit, domain } = data; - const cacheKey = `devices:${pid}:${limit}:${from}:${to}`; + const cacheKey = `devices:${pid}:${limit}:${from}:${to}:${domain}`; const cacheExp = 60; return await Redis.useCacheV2(cacheKey, cacheExp, async () => { @@ -19,7 +18,8 @@ export default defineEventHandler(async event => { { $match: { project_id, - created_at: { $gte: new Date(from), $lte: new Date(to) } + created_at: { $gte: new Date(from), $lte: new Date(to) }, + website: domain } }, { $group: { _id: "$device", count: { $sum: 1, } } }, diff --git a/dashboard/server/api/data/referrers.ts b/dashboard/server/api/data/referrers.ts index adfefcb..b5852e9 100644 --- a/dashboard/server/api/data/referrers.ts +++ b/dashboard/server/api/data/referrers.ts @@ -1,16 +1,15 @@ import { VisitModel } from "@schema/metrics/VisitSchema"; import { Redis } from "~/server/services/CacheService"; -import { getRequestDataOld } from "~/server/utils/getRequestData"; export default defineEventHandler(async event => { - const data = await getRequestDataOld(event, { requireSchema: false }); + const data = await getRequestData(event, ['OFFSET', 'RANGE', 'GUEST', 'DOMAIN']); if (!data) return; - const { pid, from, to, project_id, limit } = data; + const { pid, from, to, project_id, limit, domain } = data; - const cacheKey = `referrers:${pid}:${limit}:${from}:${to}`; + const cacheKey = `referrers:${pid}:${limit}:${from}:${to}:${domain}`; const cacheExp = 60; return await Redis.useCacheV2(cacheKey, cacheExp, async () => { @@ -19,7 +18,8 @@ export default defineEventHandler(async event => { { $match: { project_id, - created_at: { $gte: new Date(from), $lte: new Date(to) } + created_at: { $gte: new Date(from), $lte: new Date(to) }, + website: domain, } }, { $group: { _id: "$referrer", count: { $sum: 1, } } }, @@ -27,6 +27,7 @@ export default defineEventHandler(async event => { { $limit: limit } ]); + return result as { _id: string, count: number }[]; }); diff --git a/dashboard/server/api/domains/list.ts b/dashboard/server/api/domains/list.ts index fd58d2e..99bf6d2 100644 --- a/dashboard/server/api/domains/list.ts +++ b/dashboard/server/api/domains/list.ts @@ -3,7 +3,7 @@ import { VisitModel } from "@schema/metrics/VisitSchema"; export default defineEventHandler(async event => { - const data = await getRequestData(event, ['GUEST', 'LIVEMODE']); + const data = await getRequestData(event, ['GUEST']); if (!data) return; const { project_id } = data; diff --git a/dashboard/server/utils/getRequestData.ts b/dashboard/server/utils/getRequestData.ts index 86021ed..c5a7c14 100644 --- a/dashboard/server/utils/getRequestData.ts +++ b/dashboard/server/utils/getRequestData.ts @@ -32,7 +32,7 @@ export type GetRequestDataOptions = { /** @default false */ requireOffset?: boolean, } -export type RequestDataScope = 'GUEST' | 'SCHEMA' | 'LIVEMODE' | 'SLICE' | 'RANGE' | 'OFFSET'; +export type RequestDataScope = 'GUEST' | 'SCHEMA' | 'ANON' | 'SLICE' | 'RANGE' | 'OFFSET' | 'DOMAIN'; async function hasAccessToProject(user_id: string, project: TProject) { if (!project) return [false, 'NONE']; @@ -48,14 +48,20 @@ export async function getRequestData(event: H3Event, requir const requireSchema = required_scopes.includes('SCHEMA'); const allowGuests = required_scopes.includes('GUEST'); - const allowLitlyx = required_scopes.includes('LIVEMODE'); + const allowAnon = required_scopes.includes('ANON'); const requireSlice = required_scopes.includes('SLICE'); const requireRange = required_scopes.includes('RANGE'); const requireOffset = required_scopes.includes('OFFSET'); + const requireDomain = required_scopes.includes('DOMAIN'); const pid = getHeader(event, 'x-pid'); if (!pid) return setResponseStatus(event, 400, 'x-pid is required'); + const domain = getHeader(event, 'x-domain'); + if (requireDomain) { + if (domain == null || domain == undefined || domain.length == 0) return setResponseStatus(event, 400, 'x-domain is required'); + } + const slice = getHeader(event, 'x-slice') as Slice; if (!slice && requireSlice) return setResponseStatus(event, 400, 'x-slice is required'); @@ -95,18 +101,16 @@ export async function getRequestData(event: H3Event, requir const project = await ProjectModel.findById(project_id); if (!project) return setResponseStatus(event, 400, 'project not found'); - - if (pid !== LITLYX_PROJECT_ID) { + if (!allowAnon) { const [hasAccess, role] = await hasAccessToProject(user.id, project); if (!hasAccess) return setResponseStatus(event, 400, 'no access to project'); if (role === 'GUEST' && !allowGuests) return setResponseStatus(event, 403, 'only owner can access this'); - } else { - if (!allowLitlyx) return setResponseStatus(event, 400, 'no access to project'); } return { from: from as string, to: to as string, + domain: domain as string, pid, project_id, project, user, limit, slice, schemaName, model, timeOffset: offset } }