chore:little fixes and formating and linting and patches
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
export { getProjectAccess } from './src/access';
|
||||
export * from './src/root';
|
||||
export * from './src/trpc';
|
||||
export { getProjectAccess } from './src/access';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export {
|
||||
getClientAccess,
|
||||
getOrganizationAccess,
|
||||
getProjectAccess,
|
||||
getClientAccess,
|
||||
} from '@openpanel/db';
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db } from '@openpanel/db';
|
||||
|
||||
import { z } from 'zod';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
|
||||
export const chatRouter = createTRPCRouter({
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import crypto from 'node:crypto';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { hashPassword } from '@openpanel/common/server';
|
||||
import type { Prisma } from '@openpanel/db';
|
||||
import { db } from '@openpanel/db';
|
||||
|
||||
import { hashPassword } from '@openpanel/common/server';
|
||||
import { z } from 'zod';
|
||||
import { getClientAccess } from '../access';
|
||||
import { TRPCAccessError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
@@ -14,7 +12,7 @@ export const clientRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
return db.client.findMany({
|
||||
@@ -28,7 +26,7 @@ export const clientRouter = createTRPCRouter({
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const access = await getClientAccess({
|
||||
@@ -56,7 +54,7 @@ export const clientRouter = createTRPCRouter({
|
||||
projectId: z.string(),
|
||||
organizationId: z.string(),
|
||||
type: z.enum(['read', 'write', 'root']).optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
const secret = `sec_${crypto.randomBytes(10).toString('hex')}`;
|
||||
@@ -79,7 +77,7 @@ export const clientRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const access = await getClientAccess({
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { PrismaError } from 'prisma-error-enum';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { Prisma } from '@openpanel/db';
|
||||
import {
|
||||
db,
|
||||
getDashboardById,
|
||||
@@ -8,8 +6,8 @@ import {
|
||||
getId,
|
||||
getProjectById,
|
||||
} from '@openpanel/db';
|
||||
import type { Prisma } from '@openpanel/db';
|
||||
|
||||
import { PrismaError } from 'prisma-error-enum';
|
||||
import { z } from 'zod';
|
||||
import { getProjectAccess } from '../access';
|
||||
import { TRPCAccessError, TRPCNotFoundError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
@@ -19,7 +17,7 @@ export const dashboardRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(({ input }) => {
|
||||
return getDashboardsByProjectId(input.projectId);
|
||||
@@ -29,7 +27,7 @@ export const dashboardRouter = createTRPCRouter({
|
||||
z.object({
|
||||
id: z.string(),
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
@@ -54,7 +52,7 @@ export const dashboardRouter = createTRPCRouter({
|
||||
z.object({
|
||||
name: z.string(),
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
@@ -86,7 +84,7 @@ export const dashboardRouter = createTRPCRouter({
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const dashboard = await db.dashboard.findUniqueOrThrow({
|
||||
@@ -118,7 +116,7 @@ export const dashboardRouter = createTRPCRouter({
|
||||
z.object({
|
||||
id: z.string(),
|
||||
forceDelete: z.boolean().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const dashboard = await db.dashboard.findUniqueOrThrow({
|
||||
@@ -157,7 +155,7 @@ export const dashboardRouter = createTRPCRouter({
|
||||
switch (error.code) {
|
||||
case PrismaError.ForeignConstraintViolation:
|
||||
throw new Error(
|
||||
'Cannot delete dashboard with associated reports',
|
||||
'Cannot delete dashboard with associated reports'
|
||||
);
|
||||
default:
|
||||
throw new Error('Unknown error deleting dashboard');
|
||||
|
||||
@@ -12,7 +12,7 @@ export const emailRouter = createTRPCRouter({
|
||||
email: z.string().email(),
|
||||
category: z.string(),
|
||||
token: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
const { email, category, token } = input;
|
||||
@@ -41,7 +41,7 @@ export const emailRouter = createTRPCRouter({
|
||||
}),
|
||||
|
||||
getPreferences: protectedProcedure.query(async ({ ctx }) => {
|
||||
if (!ctx.session.userId || !ctx.session.user?.email) {
|
||||
if (!(ctx.session.userId && ctx.session.user?.email)) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
@@ -72,10 +72,10 @@ export const emailRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
categories: z.record(z.string(), z.boolean()),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (!ctx.session.userId || !ctx.session.user?.email) {
|
||||
if (!(ctx.session.userId && ctx.session.user?.email)) {
|
||||
throw new Error('User not authenticated');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import sqlstring from 'sqlstring';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
type IServiceProfile,
|
||||
type IServiceSession,
|
||||
TABLE_NAMES,
|
||||
chQuery,
|
||||
convertClickhouseDateToJs,
|
||||
db,
|
||||
@@ -15,16 +8,21 @@ import {
|
||||
getEventList,
|
||||
getEventMetasCached,
|
||||
getSettingsForProject,
|
||||
type IServiceProfile,
|
||||
type IServiceSession,
|
||||
pagesService,
|
||||
sessionService,
|
||||
TABLE_NAMES,
|
||||
} from '@openpanel/db';
|
||||
import {
|
||||
zChartEventFilter,
|
||||
zRange,
|
||||
zTimeInterval,
|
||||
} from '@openpanel/validation';
|
||||
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import { clone } from 'ramda';
|
||||
import sqlstring from 'sqlstring';
|
||||
import { z } from 'zod';
|
||||
import { getProjectAccess } from '../access';
|
||||
import { TRPCAccessError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
|
||||
@@ -38,7 +36,7 @@ export const eventRouter = createTRPCRouter({
|
||||
icon: z.string().optional(),
|
||||
color: z.string().optional(),
|
||||
conversion: z.boolean().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(
|
||||
async ({ input: { projectId, name, icon, color, conversion } }) => {
|
||||
@@ -53,7 +51,7 @@ export const eventRouter = createTRPCRouter({
|
||||
create: { projectId, name, icon, color, conversion },
|
||||
update: { icon, color, conversion },
|
||||
});
|
||||
},
|
||||
}
|
||||
),
|
||||
|
||||
byId: protectedProcedure
|
||||
@@ -62,7 +60,7 @@ export const eventRouter = createTRPCRouter({
|
||||
id: z.string(),
|
||||
projectId: z.string(),
|
||||
createdAt: z.date().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { id, projectId, createdAt } }) => {
|
||||
const res = await eventService.getById({
|
||||
@@ -87,7 +85,7 @@ export const eventRouter = createTRPCRouter({
|
||||
id: z.string(),
|
||||
projectId: z.string(),
|
||||
createdAt: z.date().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { id, projectId, createdAt } }) => {
|
||||
const res = await eventService.getById({
|
||||
@@ -129,7 +127,7 @@ export const eventRouter = createTRPCRouter({
|
||||
endDate: z.date().optional(),
|
||||
events: z.array(z.string()).optional(),
|
||||
columnVisibility: z.record(z.string(), z.boolean()).optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { columnVisibility, ...input } }) => {
|
||||
const items = await getEventList({
|
||||
@@ -191,7 +189,7 @@ export const eventRouter = createTRPCRouter({
|
||||
endDate: z.date().optional(),
|
||||
events: z.array(z.string()).optional(),
|
||||
columnVisibility: z.record(z.string(), z.boolean()).optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { columnVisibility, ...input } }) => {
|
||||
const conversions = await getConversionEventNames(input.projectId);
|
||||
@@ -266,7 +264,7 @@ export const eventRouter = createTRPCRouter({
|
||||
projectId: z.string(),
|
||||
cursor: z.number().optional(),
|
||||
limit: z.number().default(8),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { projectId, cursor, limit }, ctx }) => {
|
||||
if (ctx.session.userId) {
|
||||
@@ -298,12 +296,12 @@ export const eventRouter = createTRPCRouter({
|
||||
path: string;
|
||||
created_at: string;
|
||||
}>(
|
||||
`SELECT * FROM ${TABLE_NAMES.events_bots} WHERE project_id = ${sqlstring.escape(projectId)} ORDER BY created_at DESC LIMIT ${limit} OFFSET ${(cursor ?? 0) * limit}`,
|
||||
`SELECT * FROM ${TABLE_NAMES.events_bots} WHERE project_id = ${sqlstring.escape(projectId)} ORDER BY created_at DESC LIMIT ${limit} OFFSET ${(cursor ?? 0) * limit}`
|
||||
),
|
||||
chQuery<{
|
||||
count: number;
|
||||
}>(
|
||||
`SELECT count(*) as count FROM ${TABLE_NAMES.events_bots} WHERE project_id = ${sqlstring.escape(projectId)}`,
|
||||
`SELECT count(*) as count FROM ${TABLE_NAMES.events_bots} WHERE project_id = ${sqlstring.escape(projectId)}`
|
||||
),
|
||||
]);
|
||||
|
||||
@@ -325,7 +323,7 @@ export const eventRouter = createTRPCRouter({
|
||||
search: z.string().optional(),
|
||||
range: zRange,
|
||||
interval: zTimeInterval,
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const { timezone } = await getSettingsForProject(input.projectId);
|
||||
@@ -346,7 +344,7 @@ export const eventRouter = createTRPCRouter({
|
||||
projectId: z.string(),
|
||||
range: zRange,
|
||||
interval: zTimeInterval,
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const { timezone } = await getSettingsForProject(input.projectId);
|
||||
@@ -366,7 +364,7 @@ export const eventRouter = createTRPCRouter({
|
||||
projectId: z.string(),
|
||||
range: zRange,
|
||||
interval: zTimeInterval,
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const { timezone } = await getSettingsForProject(input.projectId);
|
||||
@@ -378,8 +376,7 @@ export const eventRouter = createTRPCRouter({
|
||||
|
||||
const prevEnd = new Date(startMs - 1);
|
||||
const prevStart = new Date(prevEnd.getTime() - duration);
|
||||
const fmt = (d: Date) =>
|
||||
d.toISOString().slice(0, 19).replace('T', ' ');
|
||||
const fmt = (d: Date) => d.toISOString().slice(0, 19).replace('T', ' ');
|
||||
|
||||
return pagesService.getTopPages({
|
||||
projectId: input.projectId,
|
||||
@@ -397,7 +394,7 @@ export const eventRouter = createTRPCRouter({
|
||||
interval: zTimeInterval,
|
||||
origin: z.string(),
|
||||
path: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const { timezone } = await getSettingsForProject(input.projectId);
|
||||
@@ -417,15 +414,17 @@ export const eventRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const res = await chQuery<{ origin: string }>(
|
||||
`SELECT DISTINCT origin, count(id) as count FROM ${TABLE_NAMES.events} WHERE project_id = ${sqlstring.escape(
|
||||
input.projectId,
|
||||
)} AND origin IS NOT NULL AND origin != '' AND toDate(created_at) > now() - INTERVAL 30 DAY GROUP BY origin ORDER BY count DESC LIMIT 3`,
|
||||
input.projectId
|
||||
)} AND origin IS NOT NULL AND origin != '' AND toDate(created_at) > now() - INTERVAL 30 DAY GROUP BY origin ORDER BY count DESC LIMIT 3`
|
||||
);
|
||||
|
||||
return res.filter((item) => item.origin && !item.origin.includes('localhost:'));
|
||||
return res.filter(
|
||||
(item) => item.origin && !item.origin.includes('localhost:')
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -55,11 +55,9 @@ export const groupRouter = createTRPCRouter({
|
||||
return getGroupById(id, projectId);
|
||||
}),
|
||||
|
||||
create: protectedProcedure
|
||||
.input(zCreateGroup)
|
||||
.mutation(({ input }) => {
|
||||
return createGroup(input);
|
||||
}),
|
||||
create: protectedProcedure.input(zCreateGroup).mutation(({ input }) => {
|
||||
return createGroup(input);
|
||||
}),
|
||||
|
||||
update: protectedProcedure
|
||||
.input(zUpdateGroup)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db } from '@openpanel/db';
|
||||
import { importQueue } from '@openpanel/queue';
|
||||
import { zCreateImport } from '@openpanel/validation';
|
||||
|
||||
import { z } from 'zod';
|
||||
import { getProjectAccess } from '../access';
|
||||
import {
|
||||
TRPCAccessError,
|
||||
@@ -69,7 +67,7 @@ export const importRouter = createTRPCRouter({
|
||||
|
||||
if (!access || (typeof access !== 'boolean' && access.level === 'read')) {
|
||||
throw TRPCAccessError(
|
||||
'You do not have permission to create imports for this project',
|
||||
'You do not have permission to create imports for this project'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -85,13 +83,13 @@ export const importRouter = createTRPCRouter({
|
||||
|
||||
if (!organization) {
|
||||
throw TRPCNotFoundError(
|
||||
'Could not start import, organization not found',
|
||||
'Could not start import, organization not found'
|
||||
);
|
||||
}
|
||||
|
||||
if (!organization.isActive) {
|
||||
throw TRPCBadRequestError(
|
||||
'You cannot start an import without an active subscription!',
|
||||
'You cannot start an import without an active subscription!'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -140,7 +138,7 @@ export const importRouter = createTRPCRouter({
|
||||
|
||||
if (!access || (typeof access !== 'boolean' && access.level === 'read')) {
|
||||
throw TRPCAccessError(
|
||||
'You do not have permission to delete imports for this project',
|
||||
'You do not have permission to delete imports for this project'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -174,7 +172,7 @@ export const importRouter = createTRPCRouter({
|
||||
|
||||
if (!access || (typeof access !== 'boolean' && access.level === 'read')) {
|
||||
throw TRPCAccessError(
|
||||
'You do not have permission to retry imports for this project',
|
||||
'You do not have permission to retry imports for this project'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ export const insightRouter = createTRPCRouter({
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
limit: z.number().min(1).max(100).optional().default(50),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { projectId, limit }, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
@@ -71,7 +71,7 @@ export const insightRouter = createTRPCRouter({
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
limit: z.number().min(1).max(500).optional().default(200),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { projectId, limit }, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { BASE_INTEGRATIONS, db } from '@openpanel/db';
|
||||
|
||||
import { getSlackInstallUrl } from '@openpanel/integrations/src/slack';
|
||||
import { validate as validateJavaScriptTemplate } from '@openpanel/js-runtime';
|
||||
import {
|
||||
type ISlackConfig,
|
||||
zCreateDiscordIntegration,
|
||||
zCreateSlackIntegration,
|
||||
zCreateWebhookIntegration,
|
||||
} from '@openpanel/validation';
|
||||
import { z } from 'zod';
|
||||
import { getOrganizationAccess } from '../access';
|
||||
import { TRPCAccessError, TRPCBadRequestError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
import { validate as validateJavaScriptTemplate } from '@openpanel/js-runtime';
|
||||
|
||||
export const integrationRouter = createTRPCRouter({
|
||||
get: protectedProcedure
|
||||
@@ -101,11 +99,11 @@ export const integrationRouter = createTRPCRouter({
|
||||
input.config.javascriptTemplate
|
||||
) {
|
||||
const validation = validateJavaScriptTemplate(
|
||||
input.config.javascriptTemplate,
|
||||
input.config.javascriptTemplate
|
||||
);
|
||||
if (!validation.valid) {
|
||||
throw TRPCBadRequestError(
|
||||
`Invalid JavaScript template: ${validation.error}`,
|
||||
`Invalid JavaScript template: ${validation.error}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
APP_NOTIFICATION_INTEGRATION_ID,
|
||||
BASE_INTEGRATIONS,
|
||||
EMAIL_NOTIFICATION_INTEGRATION_ID,
|
||||
db,
|
||||
EMAIL_NOTIFICATION_INTEGRATION_ID,
|
||||
getNotificationRulesByProjectId,
|
||||
isBaseIntegration,
|
||||
} from '@openpanel/db';
|
||||
import { zCreateNotificationRule } from '@openpanel/validation';
|
||||
|
||||
import { z } from 'zod';
|
||||
import { getProjectAccess } from '../access';
|
||||
import { TRPCAccessError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
@@ -89,10 +87,10 @@ export const notificationRouter = createTRPCRouter({
|
||||
name: input.name,
|
||||
projectId: input.projectId,
|
||||
sendToApp: !!input.integrations.find(
|
||||
(id) => id === APP_NOTIFICATION_INTEGRATION_ID,
|
||||
(id) => id === APP_NOTIFICATION_INTEGRATION_ID
|
||||
),
|
||||
sendToEmail: !!input.integrations.find(
|
||||
(id) => id === EMAIL_NOTIFICATION_INTEGRATION_ID,
|
||||
(id) => id === EMAIL_NOTIFICATION_INTEGRATION_ID
|
||||
),
|
||||
integrations: {
|
||||
set: input.integrations
|
||||
@@ -110,10 +108,10 @@ export const notificationRouter = createTRPCRouter({
|
||||
name: input.name,
|
||||
projectId: input.projectId,
|
||||
sendToApp: !!input.integrations.find(
|
||||
(id) => id === APP_NOTIFICATION_INTEGRATION_ID,
|
||||
(id) => id === APP_NOTIFICATION_INTEGRATION_ID
|
||||
),
|
||||
sendToEmail: !!input.integrations.find(
|
||||
(id) => id === EMAIL_NOTIFICATION_INTEGRATION_ID,
|
||||
(id) => id === EMAIL_NOTIFICATION_INTEGRATION_ID
|
||||
),
|
||||
integrations: {
|
||||
connect: input.integrations
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import crypto from 'node:crypto';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { stripTrailingSlash } from '@openpanel/common';
|
||||
import { db, getId, getOrganizationById, getUserById } from '@openpanel/db';
|
||||
import type { IServiceUser, ProjectType } from '@openpanel/db';
|
||||
import { zOnboardingProject } from '@openpanel/validation';
|
||||
|
||||
import { hashPassword } from '@openpanel/common/server';
|
||||
import type { IServiceUser, ProjectType } from '@openpanel/db';
|
||||
import { db, getId, getOrganizationById, getUserById } from '@openpanel/db';
|
||||
import { zOnboardingProject } from '@openpanel/validation';
|
||||
import { addDays } from 'date-fns';
|
||||
import type { z } from 'zod';
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
|
||||
|
||||
async function createOrGetOrganization(
|
||||
input: z.infer<typeof zOnboardingProject>,
|
||||
user: IServiceUser,
|
||||
user: IServiceUser
|
||||
) {
|
||||
if (input.organizationId) {
|
||||
return await getOrganizationById(input.organizationId);
|
||||
@@ -75,9 +73,15 @@ export const onboardingRouter = createTRPCRouter({
|
||||
.input(zOnboardingProject)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const types: ProjectType[] = [];
|
||||
if (input.website) types.push('website');
|
||||
if (input.app) types.push('app');
|
||||
if (input.backend) types.push('backend');
|
||||
if (input.website) {
|
||||
types.push('website');
|
||||
}
|
||||
if (input.app) {
|
||||
types.push('app');
|
||||
}
|
||||
if (input.backend) {
|
||||
types.push('backend');
|
||||
}
|
||||
|
||||
const user = await getUserById(ctx.session.userId);
|
||||
const organization = await createOrGetOrganization(input, user);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { generateSecureId } from '@openpanel/common/server';
|
||||
import {
|
||||
connectUserToOrganization,
|
||||
db,
|
||||
@@ -9,11 +8,10 @@ import {
|
||||
getOrganizationById,
|
||||
getOrganizations,
|
||||
} from '@openpanel/db';
|
||||
import { zEditOrganization, zInviteUser } from '@openpanel/validation';
|
||||
|
||||
import { generateSecureId } from '@openpanel/common/server';
|
||||
import { sendEmail } from '@openpanel/email';
|
||||
import { zEditOrganization, zInviteUser } from '@openpanel/validation';
|
||||
import { addDays } from 'date-fns';
|
||||
import { z } from 'zod';
|
||||
import { getOrganizationAccess } from '../access';
|
||||
import { TRPCAccessError, TRPCBadRequestError } from '../errors';
|
||||
import {
|
||||
@@ -88,7 +86,7 @@ export const organizationRouter = createTRPCRouter({
|
||||
|
||||
if (alreadyMember && userExists) {
|
||||
throw TRPCBadRequestError(
|
||||
'User is already a member of the organization',
|
||||
'User is already a member of the organization'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -101,7 +99,7 @@ export const organizationRouter = createTRPCRouter({
|
||||
|
||||
if (alreadyInvited) {
|
||||
throw TRPCBadRequestError(
|
||||
'User is already invited to the organization',
|
||||
'User is already invited to the organization'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -153,7 +151,7 @@ export const organizationRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
inviteId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const invite = await db.invite.findUniqueOrThrow({
|
||||
@@ -184,7 +182,7 @@ export const organizationRouter = createTRPCRouter({
|
||||
organizationId: z.string(),
|
||||
userId: z.string(),
|
||||
id: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const exists = await db.member.count({
|
||||
@@ -230,7 +228,7 @@ export const organizationRouter = createTRPCRouter({
|
||||
userId: z.string(),
|
||||
organizationId: z.string(),
|
||||
access: z.array(z.string()),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
if (input.userId === ctx.session.userId) {
|
||||
@@ -257,7 +255,7 @@ export const organizationRouter = createTRPCRouter({
|
||||
data: input.access.map((projectId) => ({
|
||||
userId: input.userId,
|
||||
organizationId: input.organizationId,
|
||||
projectId: projectId,
|
||||
projectId,
|
||||
level: 'read',
|
||||
})),
|
||||
}),
|
||||
@@ -281,7 +279,7 @@ export const organizationRouter = createTRPCRouter({
|
||||
rateLimitMiddleware({
|
||||
max: 5,
|
||||
windowMs: 30_000,
|
||||
}),
|
||||
})
|
||||
)
|
||||
.input(z.object({ inviteId: z.string().optional() }))
|
||||
.query(async ({ input }) => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
TABLE_NAMES,
|
||||
ch,
|
||||
clix,
|
||||
eventBuffer,
|
||||
@@ -9,6 +8,7 @@ import {
|
||||
getOrganizationSubscriptionChartEndDate,
|
||||
getSettingsForProject,
|
||||
overviewService,
|
||||
TABLE_NAMES,
|
||||
validateOverviewShareAccess,
|
||||
zGetMapDataInput,
|
||||
zGetMetricsInput,
|
||||
@@ -70,7 +70,7 @@ const overviewProcedure = publicProcedure.use(
|
||||
}
|
||||
|
||||
return next();
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
function getCurrentAndPrevious<
|
||||
@@ -85,14 +85,14 @@ function getCurrentAndPrevious<
|
||||
const previous = getChartPrevStartEndDate(current);
|
||||
|
||||
return async <R>(
|
||||
fn: (input: T & { startDate: string; endDate: string }) => Promise<R>,
|
||||
fn: (input: T & { startDate: string; endDate: string }) => Promise<R>
|
||||
): Promise<{
|
||||
current: R;
|
||||
previous: R | null;
|
||||
}> => {
|
||||
const endDate = await getOrganizationSubscriptionChartEndDate(
|
||||
input.projectId,
|
||||
current.endDate,
|
||||
current.endDate
|
||||
);
|
||||
if (endDate) {
|
||||
current.endDate = endDate;
|
||||
@@ -164,7 +164,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
.fill(
|
||||
clix.exp('toStartOfMinute(now() - INTERVAL 30 MINUTE)'),
|
||||
clix.exp('toStartOfMinute(now())'),
|
||||
clix.exp('INTERVAL 1 MINUTE'),
|
||||
clix.exp('INTERVAL 1 MINUTE')
|
||||
);
|
||||
|
||||
// Get referrers per minute for the last 30 minutes
|
||||
@@ -251,7 +251,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
endDate: z.string().nullish(),
|
||||
range: zRange,
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.use(cacher)
|
||||
.query(async ({ input }) => {
|
||||
@@ -259,7 +259,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
const { current, previous } = await getCurrentAndPrevious(
|
||||
{ ...input, timezone },
|
||||
true,
|
||||
timezone,
|
||||
timezone
|
||||
)(overviewService.getMetrics.bind(overviewService));
|
||||
return {
|
||||
metrics: {
|
||||
@@ -298,7 +298,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
range: zRange,
|
||||
mode: z.enum(['page', 'entry', 'exit', 'bot']),
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.use(cacher)
|
||||
.query(async ({ input }) => {
|
||||
@@ -306,7 +306,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
const { current } = await getCurrentAndPrevious(
|
||||
{ ...input },
|
||||
false,
|
||||
timezone,
|
||||
timezone
|
||||
)(async (input) => {
|
||||
if (input.mode === 'page') {
|
||||
return overviewService.getTopPages({ ...input, timezone });
|
||||
@@ -333,7 +333,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
endDate: z.string().nullish(),
|
||||
range: zRange,
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.use(cacher)
|
||||
.query(async ({ input }) => {
|
||||
@@ -343,7 +343,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
const { current } = await getCurrentAndPrevious(
|
||||
{ ...input, timezone },
|
||||
false,
|
||||
timezone,
|
||||
timezone
|
||||
)(overviewService.getTopGeneric.bind(overviewService));
|
||||
|
||||
return current;
|
||||
@@ -358,7 +358,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
endDate: z.string().nullish(),
|
||||
range: zRange,
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.use(cacher)
|
||||
.query(async ({ input }) => {
|
||||
@@ -366,7 +366,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
const { current } = await getCurrentAndPrevious(
|
||||
{ ...input, timezone },
|
||||
false,
|
||||
timezone,
|
||||
timezone
|
||||
)(overviewService.getTopGenericSeries.bind(overviewService));
|
||||
|
||||
return current;
|
||||
@@ -380,7 +380,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
range: zRange,
|
||||
steps: z.number().min(2).max(10).default(5).optional(),
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.use(cacher)
|
||||
.query(async ({ input }) => {
|
||||
@@ -388,7 +388,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
const { current } = await getCurrentAndPrevious(
|
||||
{ ...input, timezone },
|
||||
false,
|
||||
timezone,
|
||||
timezone
|
||||
)(async (input) => {
|
||||
return overviewService.getUserJourney({
|
||||
...input,
|
||||
@@ -407,7 +407,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
endDate: z.string().nullish(),
|
||||
range: zRange,
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.use(cacher)
|
||||
.query(async ({ input }) => {
|
||||
@@ -415,7 +415,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
const { current } = await getCurrentAndPrevious(
|
||||
{ ...input, timezone },
|
||||
false,
|
||||
timezone,
|
||||
timezone
|
||||
)(overviewService.getTopEvents.bind(overviewService));
|
||||
|
||||
return current;
|
||||
@@ -426,7 +426,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
return getConversionEventNames(input.projectId);
|
||||
@@ -439,7 +439,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
endDate: z.string().nullish(),
|
||||
range: zRange,
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.use(cacher)
|
||||
.query(async ({ input }) => {
|
||||
@@ -447,7 +447,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
const { current } = await getCurrentAndPrevious(
|
||||
{ ...input, timezone },
|
||||
false,
|
||||
timezone,
|
||||
timezone
|
||||
)(overviewService.getTopLinkOut.bind(overviewService));
|
||||
|
||||
return current;
|
||||
@@ -460,7 +460,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
endDate: z.string().nullish(),
|
||||
range: zRange,
|
||||
shareId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.use(cacher)
|
||||
.query(async ({ input }) => {
|
||||
@@ -468,7 +468,7 @@ export const overviewRouter = createTRPCRouter({
|
||||
const { current } = await getCurrentAndPrevious(
|
||||
{ ...input, timezone },
|
||||
false,
|
||||
timezone,
|
||||
timezone
|
||||
)(overviewService.getMapData.bind(overviewService));
|
||||
|
||||
return current;
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import { flatten, map, pipe, prop, sort, uniq } from 'ramda';
|
||||
import sqlstring from 'sqlstring';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
TABLE_NAMES,
|
||||
chQuery,
|
||||
createSqlBuilder,
|
||||
getProfileById,
|
||||
@@ -11,8 +6,11 @@ import {
|
||||
getProfileListCount,
|
||||
getProfileMetrics,
|
||||
getProfiles,
|
||||
TABLE_NAMES,
|
||||
} from '@openpanel/db';
|
||||
|
||||
import { flatten, map, pipe, prop, sort, uniq } from 'ramda';
|
||||
import sqlstring from 'sqlstring';
|
||||
import { z } from 'zod';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
|
||||
export const profileRouter = createTRPCRouter({
|
||||
@@ -32,7 +30,7 @@ export const profileRouter = createTRPCRouter({
|
||||
.input(z.object({ profileId: z.string(), projectId: z.string() }))
|
||||
.query(async ({ input: { profileId, projectId } }) => {
|
||||
return chQuery<{ count: number; date: string }>(
|
||||
`SELECT count(*) as count, toStartOfDay(created_at) as date FROM ${TABLE_NAMES.events} WHERE project_id = ${sqlstring.escape(projectId)} and profile_id = ${sqlstring.escape(profileId)} GROUP BY date ORDER BY date DESC`,
|
||||
`SELECT count(*) as count, toStartOfDay(created_at) as date FROM ${TABLE_NAMES.events} WHERE project_id = ${sqlstring.escape(projectId)} and profile_id = ${sqlstring.escape(profileId)} GROUP BY date ORDER BY date DESC`
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -40,7 +38,7 @@ export const profileRouter = createTRPCRouter({
|
||||
.input(z.object({ profileId: z.string(), projectId: z.string() }))
|
||||
.query(async ({ input: { profileId, projectId } }) => {
|
||||
return chQuery<{ count: number; name: string }>(
|
||||
`SELECT count(*) as count, name FROM ${TABLE_NAMES.events} WHERE name NOT IN ('screen_view', 'session_start', 'session_end') AND project_id = ${sqlstring.escape(projectId)} and profile_id = ${sqlstring.escape(profileId)} GROUP BY name ORDER BY count DESC`,
|
||||
`SELECT count(*) as count, name FROM ${TABLE_NAMES.events} WHERE name NOT IN ('screen_view', 'session_start', 'session_end') AND project_id = ${sqlstring.escape(projectId)} and profile_id = ${sqlstring.escape(profileId)} GROUP BY name ORDER BY count DESC`
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -48,7 +46,7 @@ export const profileRouter = createTRPCRouter({
|
||||
.input(z.object({ profileId: z.string(), projectId: z.string() }))
|
||||
.query(async ({ input: { profileId, projectId } }) => {
|
||||
return chQuery<{ count: number; path: string }>(
|
||||
`SELECT count(*) as count, path FROM ${TABLE_NAMES.events} WHERE name = 'screen_view' AND project_id = ${sqlstring.escape(projectId)} and profile_id = ${sqlstring.escape(profileId)} GROUP BY path ORDER BY count DESC LIMIT 10`,
|
||||
`SELECT count(*) as count, path FROM ${TABLE_NAMES.events} WHERE name = 'screen_view' AND project_id = ${sqlstring.escape(projectId)} and profile_id = ${sqlstring.escape(profileId)} GROUP BY path ORDER BY count DESC LIMIT 10`
|
||||
);
|
||||
}),
|
||||
|
||||
@@ -56,7 +54,7 @@ export const profileRouter = createTRPCRouter({
|
||||
.input(z.object({ projectId: z.string() }))
|
||||
.query(async ({ input: { projectId } }) => {
|
||||
const events = await chQuery<{ keys: string[] }>(
|
||||
`SELECT distinct mapKeys(properties) as keys from ${TABLE_NAMES.profiles} where project_id = ${sqlstring.escape(projectId)};`,
|
||||
`SELECT distinct mapKeys(properties) as keys from ${TABLE_NAMES.profiles} where project_id = ${sqlstring.escape(projectId)};`
|
||||
);
|
||||
|
||||
const properties = events
|
||||
@@ -69,7 +67,7 @@ export const profileRouter = createTRPCRouter({
|
||||
|
||||
return pipe(
|
||||
sort<string>((a, b) => a.length - b.length),
|
||||
uniq,
|
||||
uniq
|
||||
)(properties);
|
||||
}),
|
||||
|
||||
@@ -81,7 +79,7 @@ export const profileRouter = createTRPCRouter({
|
||||
take: z.number().default(50),
|
||||
search: z.string().optional(),
|
||||
isExternal: z.boolean().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const [data, count] = await Promise.all([
|
||||
@@ -103,7 +101,7 @@ export const profileRouter = createTRPCRouter({
|
||||
projectId: z.string(),
|
||||
cursor: z.number().optional(),
|
||||
take: z.number().default(50),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { projectId, cursor, take } }) => {
|
||||
const res = await chQuery<{ profile_id: string; count: number }>(
|
||||
@@ -115,11 +113,11 @@ export const profileRouter = createTRPCRouter({
|
||||
AND project_id = ${sqlstring.escape(projectId)}
|
||||
GROUP BY profile_id
|
||||
ORDER BY count() DESC
|
||||
LIMIT ${take} ${cursor ? `OFFSET ${cursor * take}` : ''}`,
|
||||
LIMIT ${take} ${cursor ? `OFFSET ${cursor * take}` : ''}`
|
||||
);
|
||||
const profiles = await getProfiles(
|
||||
res.map((r) => r.profile_id),
|
||||
projectId,
|
||||
projectId
|
||||
);
|
||||
|
||||
const data = res
|
||||
@@ -146,7 +144,7 @@ export const profileRouter = createTRPCRouter({
|
||||
z.object({
|
||||
property: z.string(),
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { property, projectId } }) => {
|
||||
const { sb, getSql } = createSqlBuilder();
|
||||
@@ -154,7 +152,7 @@ export const profileRouter = createTRPCRouter({
|
||||
sb.where.project_id = `project_id = ${sqlstring.escape(projectId)}`;
|
||||
if (property.startsWith('properties.')) {
|
||||
sb.select.values = `distinct arrayMap(x -> trim(x), mapValues(mapExtractKeyLike(properties, ${sqlstring.escape(
|
||||
property.replace(/^properties\./, '').replace('.*.', '.%.'),
|
||||
property.replace(/^properties\./, '').replace('.*.', '.%.')
|
||||
)}))) as values`;
|
||||
} else {
|
||||
sb.select.values = `${property} as values`;
|
||||
@@ -166,7 +164,7 @@ export const profileRouter = createTRPCRouter({
|
||||
(data: typeof profiles) => map(prop('values'), data),
|
||||
flatten,
|
||||
uniq,
|
||||
sort((a, b) => a.length - b.length),
|
||||
sort((a, b) => a.length - b.length)
|
||||
)(profiles);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import crypto from 'node:crypto';
|
||||
import { stripTrailingSlash } from '@openpanel/common';
|
||||
import { hashPassword } from '@openpanel/common/server';
|
||||
import {
|
||||
type Prisma,
|
||||
db,
|
||||
getClientByIdCached,
|
||||
getId,
|
||||
getProjectByIdCached,
|
||||
getProjectWithClients,
|
||||
getProjectsByOrganizationId,
|
||||
getProjectWithClients,
|
||||
type Prisma,
|
||||
} from '@openpanel/db';
|
||||
import { zOnboardingProject, zProject } from '@openpanel/validation';
|
||||
import { addHours } from 'date-fns';
|
||||
import { z } from 'zod';
|
||||
import { getProjectAccess } from '../access';
|
||||
import { TRPCAccessError, TRPCBadRequestError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
@@ -23,7 +22,7 @@ export const projectRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { projectId }, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
@@ -42,10 +41,12 @@ export const projectRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
organizationId: z.string().nullable(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { organizationId } }) => {
|
||||
if (organizationId === null) return [];
|
||||
if (organizationId === null) {
|
||||
return [];
|
||||
}
|
||||
return getProjectsByOrganizationId(organizationId);
|
||||
}),
|
||||
|
||||
@@ -151,7 +152,7 @@ export const projectRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
@@ -178,7 +179,7 @@ export const projectRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
|
||||
@@ -112,7 +112,7 @@ interface CoordinatePoint {
|
||||
long: number;
|
||||
lat: number;
|
||||
count: number;
|
||||
};
|
||||
}
|
||||
|
||||
function mergeByRadius(
|
||||
points: CoordinatePoint[],
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db, getChartStartEndDate, getSettingsForProject } from '@openpanel/db';
|
||||
import { zCreateReference, zRange } from '@openpanel/validation';
|
||||
|
||||
import { z } from 'zod';
|
||||
import { getProjectAccess } from '../access';
|
||||
import { TRPCAccessError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
|
||||
@@ -13,7 +11,7 @@ export const referenceRouter = createTRPCRouter({
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
cursor: z.number().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { projectId, cursor }, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
@@ -46,7 +44,7 @@ export const referenceRouter = createTRPCRouter({
|
||||
date: new Date(datetime),
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
),
|
||||
update: protectedProcedure
|
||||
.input(
|
||||
@@ -55,7 +53,7 @@ export const referenceRouter = createTRPCRouter({
|
||||
title: z.string(),
|
||||
description: z.string().nullish(),
|
||||
datetime: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const existing = await db.reference.findUniqueOrThrow({
|
||||
@@ -111,7 +109,7 @@ export const referenceRouter = createTRPCRouter({
|
||||
startDate: z.string().nullish(),
|
||||
endDate: z.string().nullish(),
|
||||
range: zRange,
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { projectId, ...input } }) => {
|
||||
const { timezone } = await getSettingsForProject(projectId);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db, getReportById, getReportsByDashboardId } from '@openpanel/db';
|
||||
import { zReport } from '@openpanel/validation';
|
||||
|
||||
import { z } from 'zod';
|
||||
import { getProjectAccess } from '../access';
|
||||
import { TRPCAccessError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
@@ -13,7 +11,7 @@ export const reportRouter = createTRPCRouter({
|
||||
z.object({
|
||||
dashboardId: z.string(),
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { dashboardId, projectId }, ctx }) => {
|
||||
return getReportsByDashboardId(dashboardId);
|
||||
@@ -23,7 +21,7 @@ export const reportRouter = createTRPCRouter({
|
||||
z.object({
|
||||
report: zReport.omit({ projectId: true }),
|
||||
dashboardId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { report, dashboardId }, ctx }) => {
|
||||
const dashboard = await db.dashboard.findUniqueOrThrow({
|
||||
@@ -65,7 +63,7 @@ export const reportRouter = createTRPCRouter({
|
||||
z.object({
|
||||
reportId: z.string(),
|
||||
report: zReport.omit({ projectId: true }),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { report, reportId }, ctx }) => {
|
||||
const dbReport = await db.report.findUniqueOrThrow({
|
||||
@@ -107,7 +105,7 @@ export const reportRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
reportId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { reportId }, ctx }) => {
|
||||
const report = await db.report.findUniqueOrThrow({
|
||||
@@ -135,7 +133,7 @@ export const reportRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
reportId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { reportId }, ctx }) => {
|
||||
const report = await db.report.findUniqueOrThrow({
|
||||
@@ -176,7 +174,7 @@ export const reportRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
reportId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { reportId }, ctx }) => {
|
||||
return getReportById(reportId);
|
||||
@@ -195,7 +193,7 @@ export const reportRouter = createTRPCRouter({
|
||||
maxW: z.number().optional(),
|
||||
maxH: z.number().optional(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { reportId, layout }, ctx }) => {
|
||||
const report = await db.report.findUniqueOrThrow({
|
||||
@@ -216,10 +214,10 @@ export const reportRouter = createTRPCRouter({
|
||||
// Upsert the layout (create if doesn't exist, update if it does)
|
||||
return db.reportLayout.upsert({
|
||||
where: {
|
||||
reportId: reportId,
|
||||
reportId,
|
||||
},
|
||||
create: {
|
||||
reportId: reportId,
|
||||
reportId,
|
||||
x: layout.x,
|
||||
y: layout.y,
|
||||
w: layout.w,
|
||||
@@ -246,12 +244,12 @@ export const reportRouter = createTRPCRouter({
|
||||
z.object({
|
||||
dashboardId: z.string(),
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { dashboardId, projectId }, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
userId: ctx.session.userId,
|
||||
projectId: projectId,
|
||||
projectId,
|
||||
});
|
||||
|
||||
if (!access) {
|
||||
@@ -261,7 +259,7 @@ export const reportRouter = createTRPCRouter({
|
||||
return db.reportLayout.findMany({
|
||||
where: {
|
||||
report: {
|
||||
dashboardId: dashboardId,
|
||||
dashboardId,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
@@ -274,12 +272,12 @@ export const reportRouter = createTRPCRouter({
|
||||
z.object({
|
||||
dashboardId: z.string(),
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { dashboardId, projectId }, ctx }) => {
|
||||
const access = await getProjectAccess({
|
||||
userId: ctx.session.userId,
|
||||
projectId: projectId,
|
||||
projectId,
|
||||
});
|
||||
|
||||
if (!access) {
|
||||
@@ -290,7 +288,7 @@ export const reportRouter = createTRPCRouter({
|
||||
return db.reportLayout.deleteMany({
|
||||
where: {
|
||||
report: {
|
||||
dashboardId: dashboardId,
|
||||
dashboardId,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
|
||||
import { hashPassword } from '@openpanel/auth';
|
||||
import {
|
||||
db,
|
||||
getReportById,
|
||||
getReportsByDashboardId,
|
||||
getShareDashboardById,
|
||||
getShareReportById,
|
||||
transformReport,
|
||||
} from '@openpanel/db';
|
||||
import {
|
||||
@@ -13,8 +10,7 @@ import {
|
||||
zShareOverview,
|
||||
zShareReport,
|
||||
} from '@openpanel/validation';
|
||||
|
||||
import { hashPassword } from '@openpanel/auth';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { z } from 'zod';
|
||||
import { getProjectAccess } from '../access';
|
||||
import { TRPCAccessError, TRPCNotFoundError } from '../errors';
|
||||
@@ -32,8 +28,8 @@ export const shareRouter = createTRPCRouter({
|
||||
.or(
|
||||
z.object({
|
||||
shareId: z.string(),
|
||||
}),
|
||||
),
|
||||
})
|
||||
)
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const share = await db.shareOverview.findUnique({
|
||||
@@ -108,8 +104,8 @@ export const shareRouter = createTRPCRouter({
|
||||
.or(
|
||||
z.object({
|
||||
shareId: z.string(),
|
||||
}),
|
||||
),
|
||||
})
|
||||
)
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const share = await db.shareDashboard.findUnique({
|
||||
@@ -192,12 +188,12 @@ export const shareRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
shareId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const share = await getShareDashboardById(input.shareId);
|
||||
|
||||
if (!share || !share.public) {
|
||||
if (!(share && share.public)) {
|
||||
throw TRPCNotFoundError('Dashboard share not found');
|
||||
}
|
||||
|
||||
@@ -220,8 +216,8 @@ export const shareRouter = createTRPCRouter({
|
||||
.or(
|
||||
z.object({
|
||||
shareId: z.string(),
|
||||
}),
|
||||
),
|
||||
})
|
||||
)
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
const share = await db.shareReport.findUnique({
|
||||
|
||||
@@ -12,9 +12,8 @@ import {
|
||||
getProducts,
|
||||
reactivateSubscription,
|
||||
} from '@openpanel/payments';
|
||||
import { zCheckout } from '@openpanel/validation';
|
||||
|
||||
import { getCache } from '@openpanel/redis';
|
||||
import { zCheckout } from '@openpanel/validation';
|
||||
import { subDays } from 'date-fns';
|
||||
import { z } from 'zod';
|
||||
import { TRPCBadRequestError } from '../errors';
|
||||
@@ -68,7 +67,7 @@ export const subscriptionRouter = createTRPCRouter({
|
||||
|
||||
await changeSubscription(
|
||||
organization.subscriptionId,
|
||||
input.productId,
|
||||
input.productId
|
||||
);
|
||||
return null;
|
||||
}
|
||||
@@ -117,7 +116,7 @@ export const subscriptionRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
organizationId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const organization = await db.organization.findUniqueOrThrow({
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db } from '@openpanel/db';
|
||||
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
|
||||
import { z } from 'zod';
|
||||
import { createTRPCRouter, protectedProcedure } from '../trpc';
|
||||
|
||||
export const userRouter = createTRPCRouter({
|
||||
update: protectedProcedure
|
||||
@@ -10,7 +8,7 @@ export const userRouter = createTRPCRouter({
|
||||
z.object({
|
||||
firstName: z.string(),
|
||||
lastName: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
return db.user.update({
|
||||
@@ -28,7 +26,7 @@ export const userRouter = createTRPCRouter({
|
||||
z.object({
|
||||
sameSite: z.enum(['lax', 'strict', 'none']),
|
||||
domain: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
ctx.setCookie('debugCookie', new Date().toISOString(), {
|
||||
@@ -44,7 +42,7 @@ export const userRouter = createTRPCRouter({
|
||||
z.object({
|
||||
sameSite: z.enum(['lax', 'strict', 'none']),
|
||||
domain: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
ctx.setCookie('debugCookie', new Date().toISOString(), {
|
||||
|
||||
@@ -1,22 +1,15 @@
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
TABLE_NAMES,
|
||||
ch,
|
||||
clix,
|
||||
db,
|
||||
eventBuffer,
|
||||
getSettingsForProject,
|
||||
TABLE_NAMES,
|
||||
} from '@openpanel/db';
|
||||
import { getCache } from '@openpanel/redis';
|
||||
import {
|
||||
zCounterWidgetOptions,
|
||||
zRealtimeWidgetOptions,
|
||||
zWidgetOptions,
|
||||
zWidgetType,
|
||||
} from '@openpanel/validation';
|
||||
|
||||
import { zWidgetOptions, zWidgetType } from '@openpanel/validation';
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { z } from 'zod';
|
||||
import { TRPCNotFoundError } from '../errors';
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from '../trpc';
|
||||
|
||||
@@ -28,7 +21,7 @@ async function findWidgetByType(projectId: string, type: string) {
|
||||
where: { projectId },
|
||||
});
|
||||
return widgets.find(
|
||||
(w) => (w.options as z.infer<typeof zWidgetOptions>)?.type === type,
|
||||
(w) => (w.options as z.infer<typeof zWidgetOptions>)?.type === type
|
||||
);
|
||||
}
|
||||
|
||||
@@ -54,7 +47,7 @@ export const widgetRouter = createTRPCRouter({
|
||||
organizationId: z.string(),
|
||||
type: zWidgetType,
|
||||
enabled: z.boolean(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
const existing = await findWidgetByType(input.projectId, input.type);
|
||||
@@ -95,12 +88,12 @@ export const widgetRouter = createTRPCRouter({
|
||||
projectId: z.string(),
|
||||
organizationId: z.string(),
|
||||
options: zWidgetOptions,
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
const existing = await findWidgetByType(
|
||||
input.projectId,
|
||||
input.options.type,
|
||||
input.options.type
|
||||
);
|
||||
|
||||
if (existing) {
|
||||
@@ -131,7 +124,7 @@ export const widgetRouter = createTRPCRouter({
|
||||
},
|
||||
});
|
||||
|
||||
if (!widget || !widget.public) {
|
||||
if (!(widget && widget.public)) {
|
||||
throw TRPCNotFoundError('Widget not found');
|
||||
}
|
||||
|
||||
@@ -154,7 +147,7 @@ export const widgetRouter = createTRPCRouter({
|
||||
},
|
||||
});
|
||||
|
||||
if (!widget || !widget.public) {
|
||||
if (!(widget && widget.public)) {
|
||||
throw TRPCNotFoundError('Widget not found');
|
||||
}
|
||||
|
||||
@@ -179,7 +172,7 @@ export const widgetRouter = createTRPCRouter({
|
||||
|
||||
const result = await uniqueVisitorsQuery.execute();
|
||||
return result[0]?.count || 0;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -206,7 +199,7 @@ export const widgetRouter = createTRPCRouter({
|
||||
},
|
||||
});
|
||||
|
||||
if (!widget || !widget.public) {
|
||||
if (!(widget && widget.public)) {
|
||||
throw TRPCNotFoundError('Widget not found');
|
||||
}
|
||||
|
||||
@@ -245,7 +238,7 @@ export const widgetRouter = createTRPCRouter({
|
||||
.fill(
|
||||
clix.exp('toStartOfMinute(now() - INTERVAL 30 MINUTE)'),
|
||||
clix.exp('toStartOfMinute(now())'),
|
||||
clix.exp('INTERVAL 1 MINUTE'),
|
||||
clix.exp('INTERVAL 1 MINUTE')
|
||||
);
|
||||
|
||||
// Conditionally fetch countries
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { TRPCError, initTRPC } from '@trpc/server';
|
||||
import type { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
|
||||
import { has } from 'ramda';
|
||||
import superjson from 'superjson';
|
||||
import { ZodError } from 'zod';
|
||||
|
||||
import { COOKIE_OPTIONS, type SessionValidationResult } from '@openpanel/auth';
|
||||
import { runWithAlsSession } from '@openpanel/db';
|
||||
import { getRedisCache } from '@openpanel/redis';
|
||||
import type { ISetCookie } from '@openpanel/validation';
|
||||
import { initTRPC, TRPCError } from '@trpc/server';
|
||||
import type { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
|
||||
import {
|
||||
createTrpcRedisLimiter,
|
||||
defaultFingerPrint,
|
||||
} from '@trpc-limiter/redis';
|
||||
import { has } from 'ramda';
|
||||
import superjson from 'superjson';
|
||||
import { ZodError } from 'zod';
|
||||
import { getOrganizationAccess, getProjectAccess } from './access';
|
||||
import { TRPCAccessError } from './errors';
|
||||
|
||||
@@ -34,8 +33,7 @@ export const rateLimitMiddleware = ({
|
||||
export async function createContext({ req, res }: CreateFastifyContextOptions) {
|
||||
const cookies = (req as any).cookies as Record<string, string | undefined>;
|
||||
const setCookie: ISetCookie = (key, value, options) => {
|
||||
// @ts-ignore
|
||||
res.setCookie(key, value, {
|
||||
(res as any).setCookie(key, value, {
|
||||
maxAge: options.maxAge,
|
||||
signed: options.signed,
|
||||
...COOKIE_OPTIONS,
|
||||
@@ -44,7 +42,7 @@ export async function createContext({ req, res }: CreateFastifyContextOptions) {
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
await new Promise((res) =>
|
||||
setTimeout(() => res(1), Math.min(Math.random() * 500, 200)),
|
||||
setTimeout(() => res(1), Math.min(Math.random() * 500, 200))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -151,7 +149,7 @@ const loggerMiddleware = t.middleware(
|
||||
});
|
||||
}
|
||||
return next();
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const sessionScopeMiddleware = t.middleware(async ({ ctx, next }) => {
|
||||
@@ -175,7 +173,7 @@ const middlewareMarker = 'middlewareMarker' as 'middlewareMarker' & {
|
||||
};
|
||||
|
||||
export const cacheMiddleware = (
|
||||
cbOrTtl: number | ((input: any, opts: { path: string }) => number),
|
||||
cbOrTtl: number | ((input: any, opts: { path: string }) => number)
|
||||
) =>
|
||||
t.middleware(async ({ ctx, next, path, type, getRawInput, input }) => {
|
||||
const ttl =
|
||||
@@ -189,7 +187,7 @@ export const cacheMiddleware = (
|
||||
}
|
||||
let key = `trpc:${path}:`;
|
||||
if (rawInput) {
|
||||
key += JSON.stringify(rawInput).replace(/\"/g, "'");
|
||||
key += JSON.stringify(rawInput).replace(/"/g, "'");
|
||||
}
|
||||
const cache = await getRedisCache().getJson(key);
|
||||
if (cache && process.env.NODE_ENV === 'production') {
|
||||
@@ -208,7 +206,7 @@ export const cacheMiddleware = (
|
||||
key,
|
||||
ttl,
|
||||
// @ts-expect-error
|
||||
result.data,
|
||||
result.data
|
||||
);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { getSharedVitestConfig } from '../../vitest.shared';
|
||||
|
||||
export default getSharedVitestConfig({ __dirname });
|
||||
export default getSharedVitestConfig({ __dirname: import.meta.dirname });
|
||||
|
||||
Reference in New Issue
Block a user