added tooling (eslint, typescript and prettier)
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
import { createTRPCRouter } from "@/server/api/trpc";
|
||||
import { chartRouter } from "./routers/chart";
|
||||
import { reportRouter } from "./routers/report";
|
||||
import { organizationRouter } from "./routers/organization";
|
||||
import { userRouter } from "./routers/user";
|
||||
import { projectRouter } from "./routers/project";
|
||||
import { clientRouter } from "./routers/client";
|
||||
import { dashboardRouter } from "./routers/dashboard";
|
||||
import { eventRouter } from "./routers/event";
|
||||
import { profileRouter } from "./routers/profile";
|
||||
import { createTRPCRouter } from '@/server/api/trpc';
|
||||
|
||||
import { chartRouter } from './routers/chart';
|
||||
import { clientRouter } from './routers/client';
|
||||
import { dashboardRouter } from './routers/dashboard';
|
||||
import { eventRouter } from './routers/event';
|
||||
import { organizationRouter } from './routers/organization';
|
||||
import { profileRouter } from './routers/profile';
|
||||
import { projectRouter } from './routers/project';
|
||||
import { reportRouter } from './routers/report';
|
||||
import { userRouter } from './routers/user';
|
||||
|
||||
/**
|
||||
* This is the primary router for your server.
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { last, pipe, sort, uniq } from "ramda";
|
||||
import { toDots } from "@/utils/object";
|
||||
import { zChartInputWithDates } from "@/utils/validation";
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import {
|
||||
type IChartInputWithDates,
|
||||
type IChartEvent,
|
||||
type IChartInputWithDates,
|
||||
type IChartRange,
|
||||
} from "@/types";
|
||||
import { getDaysOldDate } from "@/utils/date";
|
||||
} from '@/types';
|
||||
import { getDaysOldDate } from '@/utils/date';
|
||||
import { toDots } from '@/utils/object';
|
||||
import { zChartInputWithDates } from '@/utils/validation';
|
||||
import { last, pipe, sort, uniq } from 'ramda';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
@@ -21,7 +21,7 @@ export const chartRouter = createTRPCRouter({
|
||||
events: protectedProcedure.query(async () => {
|
||||
const events = await db.event.findMany({
|
||||
take: 500,
|
||||
distinct: ["name"],
|
||||
distinct: ['name'],
|
||||
});
|
||||
|
||||
return events;
|
||||
@@ -47,12 +47,12 @@ export const chartRouter = createTRPCRouter({
|
||||
const dotNotation = toDots(properties);
|
||||
return [...acc, ...Object.keys(dotNotation)];
|
||||
}, [] as string[])
|
||||
.map((item) => item.replace(/\.([0-9]+)\./g, ".*."))
|
||||
.map((item) => item.replace(/\.([0-9]+)/g, "[*]"));
|
||||
.map((item) => item.replace(/\.([0-9]+)\./g, '.*.'))
|
||||
.map((item) => item.replace(/\.([0-9]+)/g, '[*]'));
|
||||
|
||||
return pipe(
|
||||
sort<string>((a, b) => a.length - b.length),
|
||||
uniq,
|
||||
uniq
|
||||
)(properties);
|
||||
}),
|
||||
|
||||
@@ -62,10 +62,10 @@ export const chartRouter = createTRPCRouter({
|
||||
if (isJsonPath(input.property)) {
|
||||
const events = await db.$queryRawUnsafe<{ value: string }[]>(
|
||||
`SELECT ${selectJsonPath(
|
||||
input.property,
|
||||
input.property
|
||||
)} AS value from events WHERE name = '${
|
||||
input.event
|
||||
}' AND "createdAt" >= NOW() - INTERVAL '30 days'`,
|
||||
}' AND "createdAt" >= NOW() - INTERVAL '30 days'`
|
||||
);
|
||||
return {
|
||||
values: uniq(events.map((item) => item.value)),
|
||||
@@ -102,12 +102,12 @@ export const chartRouter = createTRPCRouter({
|
||||
...(await getChartData({
|
||||
...input,
|
||||
event,
|
||||
})),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
const sorted = [...series].sort((a, b) => {
|
||||
if (input.chartType === "linear") {
|
||||
if (input.chartType === 'linear') {
|
||||
const sumA = a.data.reduce((acc, item) => acc + item.count, 0);
|
||||
const sumB = b.data.reduce((acc, item) => acc + item.count, 0);
|
||||
return sumB - sumA;
|
||||
@@ -132,8 +132,8 @@ export const chartRouter = createTRPCRouter({
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{} as Record<(typeof series)[number]["event"]["id"], number>,
|
||||
),
|
||||
{} as Record<(typeof series)[number]['event']['id'], number>
|
||||
)
|
||||
).map(([id, count]) => ({
|
||||
count,
|
||||
...events.find((event) => event.id === id)!,
|
||||
@@ -148,13 +148,13 @@ export const chartRouter = createTRPCRouter({
|
||||
|
||||
function selectJsonPath(property: string) {
|
||||
const jsonPath = property
|
||||
.replace(/^properties\./, "")
|
||||
.replace(/\.\*\./g, ".**.");
|
||||
.replace(/^properties\./, '')
|
||||
.replace(/\.\*\./g, '.**.');
|
||||
return `jsonb_path_query(properties, '$.${jsonPath}')`;
|
||||
}
|
||||
|
||||
function isJsonPath(property: string) {
|
||||
return property.startsWith("properties");
|
||||
return property.startsWith('properties');
|
||||
}
|
||||
|
||||
type ResultItem = {
|
||||
@@ -164,12 +164,12 @@ type ResultItem = {
|
||||
};
|
||||
|
||||
function propertyNameToSql(name: string) {
|
||||
if (name.includes(".")) {
|
||||
if (name.includes('.')) {
|
||||
const str = name
|
||||
.split(".")
|
||||
.split('.')
|
||||
.map((item, index) => (index === 0 ? item : `'${item}'`))
|
||||
.join("->");
|
||||
const findLastOf = "->";
|
||||
.join('->');
|
||||
const findLastOf = '->';
|
||||
const lastArrow = str.lastIndexOf(findLastOf);
|
||||
if (lastArrow === -1) {
|
||||
return str;
|
||||
@@ -224,27 +224,34 @@ function getDatesFromRange(range: IChartRange) {
|
||||
};
|
||||
}
|
||||
|
||||
function getChartSql({ event, chartType, breakdowns, interval, startDate, endDate }: Omit<IGetChartDataInput, 'range'>) {
|
||||
function getChartSql({
|
||||
event,
|
||||
chartType,
|
||||
breakdowns,
|
||||
interval,
|
||||
startDate,
|
||||
endDate,
|
||||
}: Omit<IGetChartDataInput, 'range'>) {
|
||||
const select = [];
|
||||
const where = [];
|
||||
const groupBy = [];
|
||||
const orderBy = [];
|
||||
|
||||
if (event.segment === "event") {
|
||||
if (event.segment === 'event') {
|
||||
select.push(`count(*)::int as count`);
|
||||
} else {
|
||||
select.push(`count(DISTINCT profile_id)::int as count`);
|
||||
}
|
||||
|
||||
switch (chartType) {
|
||||
case "bar": {
|
||||
orderBy.push("count DESC");
|
||||
case 'bar': {
|
||||
orderBy.push('count DESC');
|
||||
break;
|
||||
}
|
||||
case "linear": {
|
||||
case 'linear': {
|
||||
select.push(`date_trunc('${interval}', "createdAt") as date`);
|
||||
groupBy.push("date");
|
||||
orderBy.push("date");
|
||||
groupBy.push('date');
|
||||
orderBy.push('date');
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -256,38 +263,38 @@ function getChartSql({ event, chartType, breakdowns, interval, startDate, endDat
|
||||
filters.forEach((filter) => {
|
||||
const { name, value } = filter;
|
||||
switch (filter.operator) {
|
||||
case "is": {
|
||||
if (name.includes(".*.") || name.endsWith("[*]")) {
|
||||
case 'is': {
|
||||
if (name.includes('.*.') || name.endsWith('[*]')) {
|
||||
where.push(
|
||||
`properties @? '$.${name
|
||||
.replace(/^properties\./, "")
|
||||
.replace(/\.\*\./g, "[*].")} ? (${value
|
||||
.replace(/^properties\./, '')
|
||||
.replace(/\.\*\./g, '[*].')} ? (${value
|
||||
.map((val) => `@ == "${val}"`)
|
||||
.join(" || ")})'`,
|
||||
.join(' || ')})'`
|
||||
);
|
||||
} else {
|
||||
where.push(
|
||||
`${propertyNameToSql(name)} in (${value
|
||||
.map((val) => `'${val}'`)
|
||||
.join(", ")})`,
|
||||
.join(', ')})`
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "isNot": {
|
||||
if (name.includes(".*.") || name.endsWith("[*]")) {
|
||||
case 'isNot': {
|
||||
if (name.includes('.*.') || name.endsWith('[*]')) {
|
||||
where.push(
|
||||
`properties @? '$.${name
|
||||
.replace(/^properties\./, "")
|
||||
.replace(/\.\*\./g, "[*].")} ? (${value
|
||||
.replace(/^properties\./, '')
|
||||
.replace(/\.\*\./g, '[*].')} ? (${value
|
||||
.map((val) => `@ != "${val}"`)
|
||||
.join(" && ")})'`,
|
||||
.join(' && ')})'`
|
||||
);
|
||||
} else if (name.includes(".")) {
|
||||
} else if (name.includes('.')) {
|
||||
where.push(
|
||||
`${propertyNameToSql(name)} not in (${value
|
||||
.map((val) => `'${val}'`)
|
||||
.join(", ")})`,
|
||||
.join(', ')})`
|
||||
);
|
||||
}
|
||||
break;
|
||||
@@ -322,24 +329,24 @@ function getChartSql({ event, chartType, breakdowns, interval, startDate, endDat
|
||||
}
|
||||
|
||||
const sql = [
|
||||
`SELECT ${select.join(", ")}`,
|
||||
`SELECT ${select.join(', ')}`,
|
||||
`FROM events`,
|
||||
`WHERE ${where.join(" AND ")}`,
|
||||
`WHERE ${where.join(' AND ')}`,
|
||||
];
|
||||
|
||||
if (groupBy.length) {
|
||||
sql.push(`GROUP BY ${groupBy.join(", ")}`);
|
||||
sql.push(`GROUP BY ${groupBy.join(', ')}`);
|
||||
}
|
||||
if (orderBy.length) {
|
||||
sql.push(`ORDER BY ${orderBy.join(", ")}`);
|
||||
sql.push(`ORDER BY ${orderBy.join(', ')}`);
|
||||
}
|
||||
|
||||
return sql.join("\n");
|
||||
return sql.join('\n');
|
||||
}
|
||||
|
||||
type IGetChartDataInput = {
|
||||
event: IChartEvent;
|
||||
} & Omit<IChartInputWithDates, "events" | 'name'>
|
||||
} & Omit<IChartInputWithDates, 'events' | 'name'>;
|
||||
|
||||
async function getChartData({
|
||||
chartType,
|
||||
@@ -365,23 +372,24 @@ async function getChartData({
|
||||
interval,
|
||||
startDate,
|
||||
endDate,
|
||||
})
|
||||
});
|
||||
|
||||
let result = await db.$queryRawUnsafe<ResultItem[]>(sql);
|
||||
|
||||
if(result.length === 0 && breakdowns.length > 0) {
|
||||
result = await db.$queryRawUnsafe<ResultItem[]>(getChartSql({
|
||||
chartType,
|
||||
event,
|
||||
breakdowns: [],
|
||||
interval,
|
||||
startDate,
|
||||
endDate,
|
||||
}));
|
||||
if (result.length === 0 && breakdowns.length > 0) {
|
||||
result = await db.$queryRawUnsafe<ResultItem[]>(
|
||||
getChartSql({
|
||||
chartType,
|
||||
event,
|
||||
breakdowns: [],
|
||||
interval,
|
||||
startDate,
|
||||
endDate,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
console.log(sql);
|
||||
|
||||
|
||||
// group by sql label
|
||||
const series = result.reduce(
|
||||
@@ -401,7 +409,7 @@ async function getChartData({
|
||||
...acc,
|
||||
};
|
||||
},
|
||||
{} as Record<string, ResultItem[]>,
|
||||
{} as Record<string, ResultItem[]>
|
||||
);
|
||||
|
||||
return Object.keys(series).map((key) => {
|
||||
@@ -416,7 +424,7 @@ async function getChartData({
|
||||
},
|
||||
totalCount: getTotalCount(data),
|
||||
data:
|
||||
chartType === "linear"
|
||||
chartType === 'linear'
|
||||
? fillEmptySpotsInTimeline(data, interval, startDate, endDate).map(
|
||||
(item) => {
|
||||
return {
|
||||
@@ -424,7 +432,7 @@ async function getChartData({
|
||||
count: item.count,
|
||||
date: new Date(item.date).toISOString(),
|
||||
};
|
||||
},
|
||||
}
|
||||
)
|
||||
: [],
|
||||
};
|
||||
@@ -435,17 +443,17 @@ function fillEmptySpotsInTimeline(
|
||||
items: ResultItem[],
|
||||
interval: string,
|
||||
startDate: string,
|
||||
endDate: string,
|
||||
endDate: string
|
||||
) {
|
||||
const result = [];
|
||||
const clonedStartDate = new Date(startDate);
|
||||
const clonedEndDate = new Date(endDate);
|
||||
const today = new Date();
|
||||
|
||||
if(interval === 'minute') {
|
||||
clonedStartDate.setSeconds(0, 0)
|
||||
if (interval === 'minute') {
|
||||
clonedStartDate.setSeconds(0, 0);
|
||||
clonedEndDate.setMinutes(clonedEndDate.getMinutes() + 1, 0, 0);
|
||||
} else if (interval === "hour") {
|
||||
} else if (interval === 'hour') {
|
||||
clonedStartDate.setMinutes(0, 0, 0);
|
||||
clonedEndDate.setMinutes(0, 0, 0);
|
||||
} else {
|
||||
@@ -455,7 +463,7 @@ function fillEmptySpotsInTimeline(
|
||||
|
||||
// Force if interval is month and the start date is the same month as today
|
||||
const shouldForce = () =>
|
||||
interval === "month" &&
|
||||
interval === 'month' &&
|
||||
clonedStartDate.getFullYear() === today.getFullYear() &&
|
||||
clonedStartDate.getMonth() === today.getMonth();
|
||||
|
||||
@@ -472,20 +480,20 @@ function fillEmptySpotsInTimeline(
|
||||
const item = items.find((item) => {
|
||||
const date = new Date(item.date);
|
||||
|
||||
if (interval === "month") {
|
||||
if (interval === 'month') {
|
||||
return (
|
||||
getYear(date) === getYear(clonedStartDate) &&
|
||||
getMonth(date) === getMonth(clonedStartDate)
|
||||
);
|
||||
}
|
||||
if (interval === "day") {
|
||||
if (interval === 'day') {
|
||||
return (
|
||||
getYear(date) === getYear(clonedStartDate) &&
|
||||
getMonth(date) === getMonth(clonedStartDate) &&
|
||||
getDay(date) === getDay(clonedStartDate)
|
||||
);
|
||||
}
|
||||
if (interval === "hour") {
|
||||
if (interval === 'hour') {
|
||||
return (
|
||||
getYear(date) === getYear(clonedStartDate) &&
|
||||
getMonth(date) === getMonth(clonedStartDate) &&
|
||||
@@ -493,7 +501,7 @@ function fillEmptySpotsInTimeline(
|
||||
getHour(date) === getHour(clonedStartDate)
|
||||
);
|
||||
}
|
||||
if (interval === "minute") {
|
||||
if (interval === 'minute') {
|
||||
return (
|
||||
getYear(date) === getYear(clonedStartDate) &&
|
||||
getMonth(date) === getMonth(clonedStartDate) &&
|
||||
@@ -515,19 +523,19 @@ function fillEmptySpotsInTimeline(
|
||||
}
|
||||
|
||||
switch (interval) {
|
||||
case "day": {
|
||||
case 'day': {
|
||||
clonedStartDate.setDate(clonedStartDate.getDate() + 1);
|
||||
break;
|
||||
}
|
||||
case "hour": {
|
||||
case 'hour': {
|
||||
clonedStartDate.setHours(clonedStartDate.getHours() + 1);
|
||||
break;
|
||||
}
|
||||
case "minute": {
|
||||
case 'minute': {
|
||||
clonedStartDate.setMinutes(clonedStartDate.getMinutes() + 1);
|
||||
break;
|
||||
}
|
||||
case "month": {
|
||||
case 'month': {
|
||||
clonedStartDate.setMonth(clonedStartDate.getMonth() + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { hashPassword } from "@/server/services/hash.service";
|
||||
import { randomUUID } from "crypto";
|
||||
import { getOrganizationBySlug } from "@/server/services/organization.service";
|
||||
import { randomUUID } from 'crypto';
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import { hashPassword } from '@/server/services/hash.service';
|
||||
import { getOrganizationBySlug } from '@/server/services/organization.service';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const clientRouter = createTRPCRouter({
|
||||
list: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
organizationSlug: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const organization = await getOrganizationBySlug(input.organizationSlug);
|
||||
@@ -28,7 +27,7 @@ export const clientRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(({ input }) => {
|
||||
return db.client.findUniqueOrThrow({
|
||||
@@ -42,7 +41,7 @@ export const clientRouter = createTRPCRouter({
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(({ input }) => {
|
||||
return db.client.update({
|
||||
@@ -60,7 +59,7 @@ export const clientRouter = createTRPCRouter({
|
||||
name: z.string(),
|
||||
projectId: z.string(),
|
||||
organizationSlug: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
const organization = await getOrganizationBySlug(input.organizationSlug);
|
||||
@@ -83,7 +82,7 @@ export const clientRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
await db.client.delete({
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { getProjectBySlug } from "@/server/services/project.service";
|
||||
import { slug } from "@/utils/slug";
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import { getProjectBySlug } from '@/server/services/project.service';
|
||||
import { slug } from '@/utils/slug';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const dashboardRouter = createTRPCRouter({
|
||||
list: protectedProcedure
|
||||
@@ -15,12 +14,12 @@ export const dashboardRouter = createTRPCRouter({
|
||||
.or(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
}),
|
||||
),
|
||||
})
|
||||
)
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
let projectId = null;
|
||||
if ("projectId" in input) {
|
||||
if ('projectId' in input) {
|
||||
projectId = input.projectId;
|
||||
} else {
|
||||
projectId = (await getProjectBySlug(input.projectSlug)).id;
|
||||
@@ -37,7 +36,7 @@ export const dashboardRouter = createTRPCRouter({
|
||||
z.object({
|
||||
name: z.string(),
|
||||
projectId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { projectId, name } }) => {
|
||||
return db.dashboard.create({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
@@ -16,7 +16,7 @@ export const eventRouter = createTRPCRouter({
|
||||
take: z.number().default(100),
|
||||
skip: z.number().default(0),
|
||||
profileId: z.string().optional(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { take, skip, projectSlug, profileId } }) => {
|
||||
const project = await db.project.findUniqueOrThrow({
|
||||
@@ -29,10 +29,10 @@ export const eventRouter = createTRPCRouter({
|
||||
skip,
|
||||
where: {
|
||||
project_id: project.id,
|
||||
profile_id: profileId
|
||||
profile_id: profileId,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
createdAt: 'desc',
|
||||
},
|
||||
include: {
|
||||
profile: true,
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { getOrganizationBySlug } from "@/server/services/organization.service";
|
||||
import { slug } from "@/utils/slug";
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import { getOrganizationBySlug } from '@/server/services/organization.service';
|
||||
import { slug } from '@/utils/slug';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const organizationRouter = createTRPCRouter({
|
||||
first: protectedProcedure.query(({ ctx }) => {
|
||||
@@ -21,17 +20,17 @@ export const organizationRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
slug: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(({ input }) => {
|
||||
return getOrganizationBySlug(input.slug)
|
||||
return getOrganizationBySlug(input.slug);
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(({ input }) => {
|
||||
return db.organization.update({
|
||||
@@ -40,7 +39,7 @@ export const organizationRouter = createTRPCRouter({
|
||||
},
|
||||
data: {
|
||||
name: input.name,
|
||||
slug: slug(input.name)
|
||||
slug: slug(input.name),
|
||||
},
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
@@ -15,7 +15,7 @@ export const profileRouter = createTRPCRouter({
|
||||
projectSlug: z.string(),
|
||||
take: z.number().default(100),
|
||||
skip: z.number().default(0),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { take, skip, projectSlug } }) => {
|
||||
const project = await db.project.findUniqueOrThrow({
|
||||
@@ -30,7 +30,7 @@ export const profileRouter = createTRPCRouter({
|
||||
project_id: project.id,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
createdAt: 'desc',
|
||||
},
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { getOrganizationBySlug } from "@/server/services/organization.service";
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import { getOrganizationBySlug } from '@/server/services/organization.service';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const projectRouter = createTRPCRouter({
|
||||
list: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
organizationSlug: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const organization = await getOrganizationBySlug(input.organizationSlug);
|
||||
@@ -23,7 +22,7 @@ export const projectRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(({ input }) => {
|
||||
return db.project.findUniqueOrThrow({
|
||||
@@ -37,7 +36,7 @@ export const projectRouter = createTRPCRouter({
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(({ input }) => {
|
||||
return db.project.update({
|
||||
@@ -54,7 +53,7 @@ export const projectRouter = createTRPCRouter({
|
||||
z.object({
|
||||
name: z.string(),
|
||||
organizationSlug: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
const organization = await getOrganizationBySlug(input.organizationSlug);
|
||||
@@ -69,7 +68,7 @@ export const projectRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
await db.project.delete({
|
||||
|
||||
@@ -1,48 +1,54 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc";
|
||||
import { zChartInput } from "@/utils/validation";
|
||||
import { db } from "@/server/db";
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import { getDashboardBySlug } from '@/server/services/dashboard.service';
|
||||
import { getProjectBySlug } from '@/server/services/project.service';
|
||||
import {
|
||||
type IChartInput,
|
||||
type IChartBreakdown,
|
||||
type IChartEvent,
|
||||
type IChartEventFilter,
|
||||
type IChartInput,
|
||||
type IChartRange,
|
||||
} from "@/types";
|
||||
import { type Report as DbReport } from "@prisma/client";
|
||||
import { getProjectBySlug } from "@/server/services/project.service";
|
||||
import { getDashboardBySlug } from "@/server/services/dashboard.service";
|
||||
import { alphabetIds } from "@/utils/constants";
|
||||
} from '@/types';
|
||||
import { alphabetIds } from '@/utils/constants';
|
||||
import { zChartInput } from '@/utils/validation';
|
||||
import { type Report as DbReport } from '@prisma/client';
|
||||
import { z } from 'zod';
|
||||
|
||||
function transformFilter(filter: Partial<IChartEventFilter>, index: number): IChartEventFilter {
|
||||
function transformFilter(
|
||||
filter: Partial<IChartEventFilter>,
|
||||
index: number
|
||||
): IChartEventFilter {
|
||||
return {
|
||||
id: filter.id ?? alphabetIds[index]!,
|
||||
name: filter.name ?? 'Unknown Filter',
|
||||
operator: filter.operator ?? 'is',
|
||||
value: typeof filter.value === 'string' ? [filter.value] : filter.value ?? [],
|
||||
}
|
||||
value:
|
||||
typeof filter.value === 'string' ? [filter.value] : filter.value ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
function transformEvent(event: Partial<IChartEvent>, index: number): IChartEvent {
|
||||
function transformEvent(
|
||||
event: Partial<IChartEvent>,
|
||||
index: number
|
||||
): IChartEvent {
|
||||
return {
|
||||
segment: event.segment ?? 'event',
|
||||
filters: (event.filters ?? []).map(transformFilter),
|
||||
id: event.id ?? alphabetIds[index]!,
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
name: event.name || 'Untitled',
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function transformReport(report: DbReport): IChartInput & { id: string } {
|
||||
return {
|
||||
id: report.id,
|
||||
events: (report.events as IChartEvent[]).map(transformEvent),
|
||||
events: (report.events as IChartEvent[]).map(transformEvent),
|
||||
breakdowns: report.breakdowns as IChartBreakdown[],
|
||||
chartType: report.chart_type,
|
||||
interval: report.interval,
|
||||
name: report.name || 'Untitled',
|
||||
range: report.range as IChartRange ?? 30,
|
||||
range: (report.range as IChartRange) ?? 30,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -51,7 +57,7 @@ export const reportRouter = createTRPCRouter({
|
||||
.input(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(({ input: { id } }) => {
|
||||
return db.report
|
||||
@@ -67,7 +73,7 @@ export const reportRouter = createTRPCRouter({
|
||||
z.object({
|
||||
projectSlug: z.string(),
|
||||
dashboardSlug: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { projectSlug, dashboardSlug } }) => {
|
||||
const project = await getProjectBySlug(projectSlug);
|
||||
@@ -82,7 +88,7 @@ export const reportRouter = createTRPCRouter({
|
||||
return {
|
||||
reports: reports.map(transformReport),
|
||||
dashboard,
|
||||
}
|
||||
};
|
||||
}),
|
||||
save: protectedProcedure
|
||||
.input(
|
||||
@@ -90,7 +96,7 @@ export const reportRouter = createTRPCRouter({
|
||||
report: zChartInput,
|
||||
projectId: z.string(),
|
||||
dashboardId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(({ input: { report, projectId, dashboardId } }) => {
|
||||
return db.report.create({
|
||||
@@ -105,7 +111,6 @@ export const reportRouter = createTRPCRouter({
|
||||
range: report.range,
|
||||
},
|
||||
});
|
||||
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(
|
||||
@@ -114,7 +119,7 @@ export const reportRouter = createTRPCRouter({
|
||||
report: zChartInput,
|
||||
projectId: z.string(),
|
||||
dashboardId: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(({ input: { report, projectId, dashboardId, reportId } }) => {
|
||||
return db.report.update({
|
||||
|
||||
@@ -1,63 +1,59 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
createTRPCRouter,
|
||||
protectedProcedure,
|
||||
} from "@/server/api/trpc";
|
||||
import { db } from "@/server/db";
|
||||
import { hashPassword, verifyPassword } from "@/server/services/hash.service";
|
||||
import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
|
||||
import { db } from '@/server/db';
|
||||
import { hashPassword, verifyPassword } from '@/server/services/hash.service';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const userRouter = createTRPCRouter({
|
||||
current: protectedProcedure.query(({ ctx }) => {
|
||||
return db.user.findUniqueOrThrow({
|
||||
where: {
|
||||
id: ctx.session.user.id
|
||||
}
|
||||
})
|
||||
id: ctx.session.user.id,
|
||||
},
|
||||
});
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
email: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(({ input, ctx }) => {
|
||||
return db.user.update({
|
||||
where: {
|
||||
id: ctx.session.user.id
|
||||
id: ctx.session.user.id,
|
||||
},
|
||||
data: {
|
||||
name: input.name,
|
||||
email: input.email,
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
}),
|
||||
changePassword: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
password: z.string(),
|
||||
oldPassword: z.string(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const user = await db.user.findUniqueOrThrow({
|
||||
where: {
|
||||
id: ctx.session.user.id
|
||||
}
|
||||
})
|
||||
id: ctx.session.user.id,
|
||||
},
|
||||
});
|
||||
|
||||
if(!(await verifyPassword(input.oldPassword, user.password))) {
|
||||
throw new Error('Old password is incorrect')
|
||||
if (!(await verifyPassword(input.oldPassword, user.password))) {
|
||||
throw new Error('Old password is incorrect');
|
||||
}
|
||||
|
||||
|
||||
return db.user.update({
|
||||
where: {
|
||||
id: ctx.session.user.id
|
||||
id: ctx.session.user.id,
|
||||
},
|
||||
data: {
|
||||
password: await hashPassword(input.password),
|
||||
}
|
||||
})
|
||||
},
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
* need to use are documented accordingly near the end.
|
||||
*/
|
||||
|
||||
import { initTRPC, TRPCError } from "@trpc/server";
|
||||
import { type CreateNextContextOptions } from "@trpc/server/adapters/next";
|
||||
import { type Session } from "next-auth";
|
||||
import superjson from "superjson";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import { getServerAuthSession } from "@/server/auth";
|
||||
import { db } from "@/server/db";
|
||||
import { getServerAuthSession } from '@/server/auth';
|
||||
import { db } from '@/server/db';
|
||||
import { initTRPC, TRPCError } from '@trpc/server';
|
||||
import { type CreateNextContextOptions } from '@trpc/server/adapters/next';
|
||||
import { type Session } from 'next-auth';
|
||||
import superjson from 'superjson';
|
||||
import { ZodError } from 'zod';
|
||||
|
||||
/**
|
||||
* 1. CONTEXT
|
||||
@@ -109,7 +108,7 @@ export const publicProcedure = t.procedure;
|
||||
/** Reusable middleware that enforces users are logged in before running the procedure. */
|
||||
const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
|
||||
if (!ctx.session?.user) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
throw new TRPCError({ code: 'UNAUTHORIZED' });
|
||||
}
|
||||
return next({
|
||||
ctx: {
|
||||
|
||||
Reference in New Issue
Block a user