added tooling (eslint, typescript and prettier)

This commit is contained in:
Carl-Gerhard Lindesvärd
2023-11-02 12:14:37 +01:00
parent 575b3c23bf
commit 493e1b7650
82 changed files with 1890 additions and 1363 deletions

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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({

View File

@@ -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({

View File

@@ -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,

View File

@@ -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),
},
});
}),

View File

@@ -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',
},
});
}),

View File

@@ -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({

View File

@@ -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({

View File

@@ -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),
}
})
},
});
}),
});

View File

@@ -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: {