chore: refactor overview access

This commit is contained in:
Carl-Gerhard Lindesvärd
2026-02-05 21:31:34 +00:00
parent c978904815
commit 19a48e86c1

View File

@@ -42,6 +42,37 @@ const cacher = cacheMiddleware((input, opts) => {
} }
}); });
const overviewProcedure = publicProcedure.use(
async ({ ctx, next, getRawInput }) => {
const rawInput = (await getRawInput()) as {
projectId: string;
shareId?: string;
};
if (rawInput.shareId) {
await validateOverviewShareAccess(rawInput.shareId, rawInput.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: rawInput.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
return next();
},
);
function getCurrentAndPrevious< function getCurrentAndPrevious<
T extends { T extends {
startDate?: string | null; startDate?: string | null;
@@ -93,59 +124,16 @@ function getCurrentAndPrevious<
} }
export const overviewRouter = createTRPCRouter({ export const overviewRouter = createTRPCRouter({
liveVisitors: publicProcedure liveVisitors: overviewProcedure
.input(z.object({ projectId: z.string(), shareId: z.string().optional() })) .input(z.object({ projectId: z.string(), shareId: z.string().optional() }))
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
return eventBuffer.getActiveVisitorCount(input.projectId); return eventBuffer.getActiveVisitorCount(input.projectId);
}), }),
liveData: publicProcedure liveData: overviewProcedure
.input(z.object({ projectId: z.string(), shareId: z.string().optional() })) .input(z.object({ projectId: z.string(), shareId: z.string().optional() }))
.use(cacher) .use(cacher)
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
// Get total unique sessions in the last 30 minutes // Get total unique sessions in the last 30 minutes
@@ -256,7 +244,7 @@ export const overviewRouter = createTRPCRouter({
})), })),
}; };
}), }),
stats: publicProcedure stats: overviewProcedure
.input( .input(
zGetMetricsInput.omit({ startDate: true, endDate: true }).extend({ zGetMetricsInput.omit({ startDate: true, endDate: true }).extend({
startDate: z.string().nullish(), startDate: z.string().nullish(),
@@ -266,28 +254,7 @@ export const overviewRouter = createTRPCRouter({
}), }),
) )
.use(cacher) .use(cacher)
.query(async ({ ctx, input }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
const { current, previous } = await getCurrentAndPrevious( const { current, previous } = await getCurrentAndPrevious(
{ ...input, timezone }, { ...input, timezone },
@@ -323,7 +290,7 @@ export const overviewRouter = createTRPCRouter({
}; };
}), }),
topPages: publicProcedure topPages: overviewProcedure
.input( .input(
zGetTopPagesInput.omit({ startDate: true, endDate: true }).extend({ zGetTopPagesInput.omit({ startDate: true, endDate: true }).extend({
startDate: z.string().nullish(), startDate: z.string().nullish(),
@@ -334,28 +301,7 @@ export const overviewRouter = createTRPCRouter({
}), }),
) )
.use(cacher) .use(cacher)
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
const { current } = await getCurrentAndPrevious( const { current } = await getCurrentAndPrevious(
{ ...input }, { ...input },
@@ -380,7 +326,7 @@ export const overviewRouter = createTRPCRouter({
return current; return current;
}), }),
topGeneric: publicProcedure topGeneric: overviewProcedure
.input( .input(
zGetTopGenericInput.omit({ startDate: true, endDate: true }).extend({ zGetTopGenericInput.omit({ startDate: true, endDate: true }).extend({
startDate: z.string().nullish(), startDate: z.string().nullish(),
@@ -390,30 +336,9 @@ export const overviewRouter = createTRPCRouter({
}), }),
) )
.use(cacher) .use(cacher)
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
console.log('input', input); console.log('input', input);
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
const { current } = await getCurrentAndPrevious( const { current } = await getCurrentAndPrevious(
{ ...input, timezone }, { ...input, timezone },
@@ -424,7 +349,7 @@ export const overviewRouter = createTRPCRouter({
return current; return current;
}), }),
topGenericSeries: publicProcedure topGenericSeries: overviewProcedure
.input( .input(
zGetTopGenericSeriesInput zGetTopGenericSeriesInput
.omit({ startDate: true, endDate: true }) .omit({ startDate: true, endDate: true })
@@ -436,28 +361,7 @@ export const overviewRouter = createTRPCRouter({
}), }),
) )
.use(cacher) .use(cacher)
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
const { current } = await getCurrentAndPrevious( const { current } = await getCurrentAndPrevious(
{ ...input, timezone }, { ...input, timezone },
@@ -468,7 +372,7 @@ export const overviewRouter = createTRPCRouter({
return current; return current;
}), }),
userJourney: publicProcedure userJourney: overviewProcedure
.input( .input(
zGetUserJourneyInput.omit({ startDate: true, endDate: true }).extend({ zGetUserJourneyInput.omit({ startDate: true, endDate: true }).extend({
startDate: z.string().nullish(), startDate: z.string().nullish(),
@@ -479,28 +383,7 @@ export const overviewRouter = createTRPCRouter({
}), }),
) )
.use(cacher) .use(cacher)
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
const { current } = await getCurrentAndPrevious( const { current } = await getCurrentAndPrevious(
{ ...input, timezone }, { ...input, timezone },
@@ -517,7 +400,7 @@ export const overviewRouter = createTRPCRouter({
return current; return current;
}), }),
topEvents: publicProcedure topEvents: overviewProcedure
.input( .input(
zGetTopEventsInput.omit({ startDate: true, endDate: true }).extend({ zGetTopEventsInput.omit({ startDate: true, endDate: true }).extend({
startDate: z.string().nullish(), startDate: z.string().nullish(),
@@ -527,29 +410,7 @@ export const overviewRouter = createTRPCRouter({
}), }),
) )
.use(cacher) .use(cacher)
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
const { current } = await getCurrentAndPrevious( const { current } = await getCurrentAndPrevious(
{ ...input, timezone }, { ...input, timezone },
@@ -560,40 +421,18 @@ export const overviewRouter = createTRPCRouter({
return current; return current;
}), }),
topConversions: publicProcedure topConversions: overviewProcedure
.input( .input(
z.object({ z.object({
projectId: z.string(), projectId: z.string(),
shareId: z.string().optional(), shareId: z.string().optional(),
}), }),
) )
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
return getConversionEventNames(input.projectId); return getConversionEventNames(input.projectId);
}), }),
topLinkOut: publicProcedure topLinkOut: overviewProcedure
.input( .input(
zGetTopLinkOutInput.omit({ startDate: true, endDate: true }).extend({ zGetTopLinkOutInput.omit({ startDate: true, endDate: true }).extend({
startDate: z.string().nullish(), startDate: z.string().nullish(),
@@ -603,29 +442,7 @@ export const overviewRouter = createTRPCRouter({
}), }),
) )
.use(cacher) .use(cacher)
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
const { current } = await getCurrentAndPrevious( const { current } = await getCurrentAndPrevious(
{ ...input, timezone }, { ...input, timezone },
@@ -636,7 +453,7 @@ export const overviewRouter = createTRPCRouter({
return current; return current;
}), }),
map: publicProcedure map: overviewProcedure
.input( .input(
zGetMapDataInput.omit({ startDate: true, endDate: true }).extend({ zGetMapDataInput.omit({ startDate: true, endDate: true }).extend({
startDate: z.string().nullish(), startDate: z.string().nullish(),
@@ -646,29 +463,7 @@ export const overviewRouter = createTRPCRouter({
}), }),
) )
.use(cacher) .use(cacher)
.query(async ({ input, ctx }) => { .query(async ({ input }) => {
// Validate share access if shareId provided
if (input.shareId) {
await validateOverviewShareAccess(input.shareId, input.projectId, {
cookies: ctx.cookies,
session: ctx.session?.userId
? { userId: ctx.session.userId }
: undefined,
});
} else {
// Regular member access check
if (!ctx.session?.userId) {
throw TRPCAccessError('Authentication required');
}
const access = await getProjectAccess({
projectId: input.projectId,
userId: ctx.session.userId,
});
if (!access) {
throw TRPCAccessError('You do not have access to this project');
}
}
const { timezone } = await getSettingsForProject(input.projectId); const { timezone } = await getSettingsForProject(input.projectId);
const { current } = await getCurrentAndPrevious( const { current } = await getCurrentAndPrevious(
{ ...input, timezone }, { ...input, timezone },