Merge pull request #33 from atridadl/dev
1.2.6 🚧 New REST endpoints for counts and DB Warmer webhook 🚧 Events revamp 🐛 Enabled SSL for cache requests
This commit is contained in:
commit
719973f240
11 changed files with 306 additions and 405 deletions
20
package.json
20
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "sprintpadawan",
|
"name": "sprintpadawan",
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"description": "Plan. Sprint. Repeat.",
|
"description": "Plan. Sprint. Repeat.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
"@auth/prisma-adapter": "^1.0.1",
|
"@auth/prisma-adapter": "^1.0.1",
|
||||||
"@prisma/client": "5.1.1",
|
"@prisma/client": "5.1.1",
|
||||||
"@react-email/components": "^0.0.7",
|
"@react-email/components": "^0.0.7",
|
||||||
"@tanstack/react-query": "^4.32.1",
|
"@tanstack/react-query": "^4.32.6",
|
||||||
"@trpc/client": "10.37.1",
|
"@trpc/client": "10.37.1",
|
||||||
"@trpc/next": "10.37.1",
|
"@trpc/next": "10.37.1",
|
||||||
"@trpc/react-query": "10.37.1",
|
"@trpc/react-query": "10.37.1",
|
||||||
|
@ -27,8 +27,8 @@
|
||||||
"ably": "^1.2.42",
|
"ably": "^1.2.42",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"json2csv": "6.0.0-alpha.2",
|
"json2csv": "6.0.0-alpha.2",
|
||||||
"next": "^13.4.12",
|
"next": "^13.4.13",
|
||||||
"next-auth": "^4.22.3",
|
"next-auth": "^4.22.5",
|
||||||
"nextjs-cors": "^2.1.2",
|
"nextjs-cors": "^2.1.2",
|
||||||
"postcss": "^8.4.27",
|
"postcss": "^8.4.27",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
@ -42,15 +42,15 @@
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/eslint": "^8.44.1",
|
"@types/eslint": "^8.44.2",
|
||||||
"@types/json2csv": "^5.0.3",
|
"@types/json2csv": "^5.0.3",
|
||||||
"@types/node": "^20.4.6",
|
"@types/node": "^20.4.9",
|
||||||
"@types/react": "^18.2.18",
|
"@types/react": "^18.2.19",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
||||||
"@typescript-eslint/parser": "^6.2.1",
|
"@typescript-eslint/parser": "^6.3.0",
|
||||||
"daisyui": "^3.5.1",
|
"daisyui": "^3.5.1",
|
||||||
"eslint": "^8.46.0",
|
"eslint": "^8.46.0",
|
||||||
"eslint-config-next": "^13.4.12",
|
"eslint-config-next": "^13.4.13",
|
||||||
"prisma": "5.1.1",
|
"prisma": "5.1.1",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
|
|
490
pnpm-lock.yaml
generated
490
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -61,7 +61,7 @@ const AdminBody: React.FC = () => {
|
||||||
isLoading: usersCountLoading,
|
isLoading: usersCountLoading,
|
||||||
isFetching: usersCountFetching,
|
isFetching: usersCountFetching,
|
||||||
refetch: refetchUsersCount,
|
refetch: refetchUsersCount,
|
||||||
} = api.user.countAll.useQuery();
|
} = api.rest.userCount.useQuery();
|
||||||
const {
|
const {
|
||||||
data: users,
|
data: users,
|
||||||
isLoading: usersLoading,
|
isLoading: usersLoading,
|
||||||
|
@ -73,13 +73,13 @@ const AdminBody: React.FC = () => {
|
||||||
isLoading: roomsCountLoading,
|
isLoading: roomsCountLoading,
|
||||||
isFetching: roomsCountFetching,
|
isFetching: roomsCountFetching,
|
||||||
refetch: refetchRoomsCount,
|
refetch: refetchRoomsCount,
|
||||||
} = api.room.countAll.useQuery();
|
} = api.rest.roomCount.useQuery();
|
||||||
const {
|
const {
|
||||||
data: votesCount,
|
data: votesCount,
|
||||||
isLoading: votesCountLoading,
|
isLoading: votesCountLoading,
|
||||||
isFetching: votesCountFetching,
|
isFetching: votesCountFetching,
|
||||||
refetch: refetchVotesCount,
|
refetch: refetchVotesCount,
|
||||||
} = api.vote.countAll.useQuery();
|
} = api.rest.voteCount.useQuery();
|
||||||
|
|
||||||
const getProviders = (user: {
|
const getProviders = (user: {
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { type GetServerSideProps, type NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { EventTypes } from "~/utils/types";
|
||||||
|
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
@ -95,10 +96,10 @@ const RoomBody: React.FC = ({}) => {
|
||||||
channelName: `${env.NEXT_PUBLIC_APP_ENV}-${roomId}`,
|
channelName: `${env.NEXT_PUBLIC_APP_ENV}-${roomId}`,
|
||||||
},
|
},
|
||||||
({ name }) => {
|
({ name }) => {
|
||||||
if (name === "ROOM_UPDATE") {
|
if (name === EventTypes.ROOM_UPDATE) {
|
||||||
void refetchVotesFromDb();
|
void refetchVotesFromDb();
|
||||||
void refetchRoomFromDb();
|
void refetchRoomFromDb();
|
||||||
} else if (name === "VOTE_UPDATE") {
|
} else if (name === EventTypes.VOTE_UPDATE) {
|
||||||
void refetchVotesFromDb();
|
void refetchVotesFromDb();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { createTRPCRouter } from "~/server/api/trpc";
|
||||||
import { sessionRouter } from "./routers/session";
|
import { sessionRouter } from "./routers/session";
|
||||||
import { userRouter } from "./routers/user";
|
import { userRouter } from "./routers/user";
|
||||||
import { voteRouter } from "./routers/vote";
|
import { voteRouter } from "./routers/vote";
|
||||||
import { hookRouter } from "./routers/hook";
|
import { restRouter } from "./routers/rest";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the primary router for your server.
|
* This is the primary router for your server.
|
||||||
|
@ -15,7 +15,7 @@ export const appRouter = createTRPCRouter({
|
||||||
vote: voteRouter,
|
vote: voteRouter,
|
||||||
user: userRouter,
|
user: userRouter,
|
||||||
session: sessionRouter,
|
session: sessionRouter,
|
||||||
hook: hookRouter,
|
rest: restRouter,
|
||||||
});
|
});
|
||||||
|
|
||||||
// export type definition of API
|
// export type definition of API
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { validateApiKey } from "~/server/unkey";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";
|
|
||||||
import { TRPCError } from "@trpc/server";
|
|
||||||
|
|
||||||
export const hookRouter = createTRPCRouter({
|
|
||||||
dbWarmer: publicProcedure
|
|
||||||
.meta({ openapi: { method: "POST", path: "/rest/dbwarmer" } })
|
|
||||||
.input(z.object({ key: z.string() }))
|
|
||||||
.output(z.string())
|
|
||||||
.query(async ({ ctx, input }) => {
|
|
||||||
const isValidKey = await validateApiKey(input.key);
|
|
||||||
if (isValidKey) {
|
|
||||||
await ctx.prisma.verificationToken.findMany();
|
|
||||||
return "Toasted the DB";
|
|
||||||
} else {
|
|
||||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
});
|
|
76
src/server/api/routers/rest.ts
Normal file
76
src/server/api/routers/rest.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import { validateApiKey } from "~/server/unkey";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { createTRPCRouter, publicProcedure } from "~/server/api/trpc";
|
||||||
|
import { TRPCError } from "@trpc/server";
|
||||||
|
import { fetchCache, setCache } from "~/server/redis";
|
||||||
|
|
||||||
|
export const restRouter = createTRPCRouter({
|
||||||
|
dbWarmer: publicProcedure
|
||||||
|
.meta({ openapi: { method: "POST", path: "/rest/dbwarmer" } })
|
||||||
|
.input(z.object({ key: z.string() }))
|
||||||
|
.output(z.string())
|
||||||
|
.query(async ({ ctx, input }) => {
|
||||||
|
const isValidKey = await validateApiKey(input.key);
|
||||||
|
if (isValidKey) {
|
||||||
|
await ctx.prisma.verificationToken.findMany();
|
||||||
|
return "Toasted the DB";
|
||||||
|
} else {
|
||||||
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
voteCount: publicProcedure
|
||||||
|
.meta({ openapi: { method: "GET", path: "/rest/votes/count" } })
|
||||||
|
.input(z.void())
|
||||||
|
.output(z.number())
|
||||||
|
.query(async ({ ctx }) => {
|
||||||
|
const cachedResult = await fetchCache<number>(`kv_votecount_admin`);
|
||||||
|
|
||||||
|
if (cachedResult) {
|
||||||
|
return cachedResult;
|
||||||
|
} else {
|
||||||
|
const votesCount = await ctx.prisma.vote.count();
|
||||||
|
|
||||||
|
await setCache(`kv_votecount_admin`, votesCount);
|
||||||
|
|
||||||
|
return votesCount;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
userCount: publicProcedure
|
||||||
|
.meta({ openapi: { method: "GET", path: "/rest/users/count" } })
|
||||||
|
.input(z.void())
|
||||||
|
.output(z.number())
|
||||||
|
.query(async ({ ctx }) => {
|
||||||
|
const cachedResult = await fetchCache<number>(`kv_usercount`);
|
||||||
|
|
||||||
|
if (cachedResult) {
|
||||||
|
return cachedResult;
|
||||||
|
} else {
|
||||||
|
const usersCount = await ctx.prisma.user.count();
|
||||||
|
|
||||||
|
await setCache(`kv_usercount`, usersCount);
|
||||||
|
|
||||||
|
return usersCount;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
roomCount: publicProcedure
|
||||||
|
.meta({ openapi: { method: "GET", path: "/rest/rooms/count" } })
|
||||||
|
.input(z.void())
|
||||||
|
.output(z.number())
|
||||||
|
.query(async ({ ctx }) => {
|
||||||
|
const cachedResult = await fetchCache<number>(`kv_roomcount`);
|
||||||
|
|
||||||
|
if (cachedResult) {
|
||||||
|
return cachedResult;
|
||||||
|
} else {
|
||||||
|
const roomsCount = await ctx.prisma.room.count();
|
||||||
|
|
||||||
|
await setCache(`kv_roomcount`, roomsCount);
|
||||||
|
|
||||||
|
return roomsCount;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
});
|
|
@ -1,12 +1,9 @@
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { publishToChannel } from "~/server/ably";
|
import { publishToChannel } from "~/server/ably";
|
||||||
import {
|
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||||
createTRPCRouter,
|
|
||||||
protectedProcedure,
|
|
||||||
adminProcedure,
|
|
||||||
} from "~/server/api/trpc";
|
|
||||||
|
|
||||||
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
||||||
|
import { EventTypes } from "~/utils/types";
|
||||||
|
|
||||||
export const roomRouter = createTRPCRouter({
|
export const roomRouter = createTRPCRouter({
|
||||||
// Create
|
// Create
|
||||||
|
@ -33,8 +30,8 @@ export const roomRouter = createTRPCRouter({
|
||||||
|
|
||||||
await publishToChannel(
|
await publishToChannel(
|
||||||
`${ctx.session.user.id}`,
|
`${ctx.session.user.id}`,
|
||||||
"ROOM_LIST_UPDATE",
|
EventTypes.ROOM_LIST_UPDATE,
|
||||||
"CREATE"
|
JSON.stringify(room)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// happy path
|
// happy path
|
||||||
|
@ -96,20 +93,6 @@ export const roomRouter = createTRPCRouter({
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
countAll: adminProcedure.query(async ({ ctx }) => {
|
|
||||||
const cachedResult = await fetchCache<number>(`kv_roomcount_admin`);
|
|
||||||
|
|
||||||
if (cachedResult) {
|
|
||||||
return cachedResult;
|
|
||||||
} else {
|
|
||||||
const roomsCount = await ctx.prisma.room.count();
|
|
||||||
|
|
||||||
await setCache(`kv_roomcount_admin`, roomsCount);
|
|
||||||
|
|
||||||
return roomsCount;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
// Update One
|
// Update One
|
||||||
set: protectedProcedure
|
set: protectedProcedure
|
||||||
.input(
|
.input(
|
||||||
|
@ -205,7 +188,11 @@ export const roomRouter = createTRPCRouter({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newRoom) {
|
if (newRoom) {
|
||||||
await publishToChannel(`${newRoom.id}`, "ROOM_UPDATE", "UPDATE");
|
await publishToChannel(
|
||||||
|
`${newRoom.id}`,
|
||||||
|
EventTypes.ROOM_UPDATE,
|
||||||
|
JSON.stringify(newRoom)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!newRoom;
|
return !!newRoom;
|
||||||
|
@ -228,11 +215,15 @@ export const roomRouter = createTRPCRouter({
|
||||||
|
|
||||||
await publishToChannel(
|
await publishToChannel(
|
||||||
`${ctx.session.user.id}`,
|
`${ctx.session.user.id}`,
|
||||||
"ROOM_LIST_UPDATE",
|
EventTypes.ROOM_LIST_UPDATE,
|
||||||
"DELETE"
|
JSON.stringify(deletedRoom)
|
||||||
);
|
);
|
||||||
|
|
||||||
await publishToChannel(`${deletedRoom.id}`, "ROOM_UPDATE", "DELETE");
|
await publishToChannel(
|
||||||
|
`${deletedRoom.id}`,
|
||||||
|
EventTypes.ROOM_UPDATE,
|
||||||
|
JSON.stringify(deletedRoom)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!deletedRoom;
|
return !!deletedRoom;
|
||||||
|
|
|
@ -14,20 +14,6 @@ import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
||||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||||
|
|
||||||
export const userRouter = createTRPCRouter({
|
export const userRouter = createTRPCRouter({
|
||||||
countAll: adminProcedure.query(async ({ ctx }) => {
|
|
||||||
const cachedResult = await fetchCache<number>(`kv_usercount_admin`);
|
|
||||||
|
|
||||||
if (cachedResult) {
|
|
||||||
return cachedResult;
|
|
||||||
} else {
|
|
||||||
const usersCount = await ctx.prisma.user.count();
|
|
||||||
|
|
||||||
await setCache(`kv_usercount_admin`, usersCount);
|
|
||||||
|
|
||||||
return usersCount;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
getProviders: protectedProcedure.query(async ({ ctx }) => {
|
getProviders: protectedProcedure.query(async ({ ctx }) => {
|
||||||
const providers = await ctx.prisma.user.findUnique({
|
const providers = await ctx.prisma.user.findUnique({
|
||||||
where: {
|
where: {
|
||||||
|
|
|
@ -2,27 +2,11 @@ import { z } from "zod";
|
||||||
import { publishToChannel } from "~/server/ably";
|
import { publishToChannel } from "~/server/ably";
|
||||||
|
|
||||||
import type { Room } from "@prisma/client";
|
import type { Room } from "@prisma/client";
|
||||||
import {
|
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
||||||
adminProcedure,
|
|
||||||
createTRPCRouter,
|
|
||||||
protectedProcedure,
|
|
||||||
} from "~/server/api/trpc";
|
|
||||||
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
import { fetchCache, invalidateCache, setCache } from "~/server/redis";
|
||||||
|
import { EventTypes } from "~/utils/types";
|
||||||
|
|
||||||
export const voteRouter = createTRPCRouter({
|
export const voteRouter = createTRPCRouter({
|
||||||
countAll: adminProcedure.query(async ({ ctx }) => {
|
|
||||||
const cachedResult = await fetchCache<number>(`kv_votecount_admin`);
|
|
||||||
|
|
||||||
if (cachedResult) {
|
|
||||||
return cachedResult;
|
|
||||||
} else {
|
|
||||||
const votesCount = await ctx.prisma.vote.count();
|
|
||||||
|
|
||||||
await setCache(`kv_votecount_admin`, votesCount);
|
|
||||||
|
|
||||||
return votesCount;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
getAllByRoomId: protectedProcedure
|
getAllByRoomId: protectedProcedure
|
||||||
.input(z.object({ roomId: z.string() }))
|
.input(z.object({ roomId: z.string() }))
|
||||||
.query(async ({ ctx, input }) => {
|
.query(async ({ ctx, input }) => {
|
||||||
|
@ -104,7 +88,11 @@ export const voteRouter = createTRPCRouter({
|
||||||
await invalidateCache(`kv_votecount_admin`);
|
await invalidateCache(`kv_votecount_admin`);
|
||||||
await invalidateCache(`kv_votes_${input.roomId}`);
|
await invalidateCache(`kv_votes_${input.roomId}`);
|
||||||
|
|
||||||
await publishToChannel(`${vote.roomId}`, "VOTE_UPDATE", "UPDATE");
|
await publishToChannel(
|
||||||
|
`${vote.roomId}`,
|
||||||
|
EventTypes.VOTE_UPDATE,
|
||||||
|
input.value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return !!vote;
|
return !!vote;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
type BetterEnum<T> = T[keyof T];
|
type BetterEnum<T> = T[keyof T];
|
||||||
|
|
||||||
const EventTypes = {
|
export const EventTypes = {
|
||||||
ROOM_LIST_UPDATE: "ROOM_LIST_UPDATE",
|
ROOM_LIST_UPDATE: "room.list.update",
|
||||||
ROOM_UPDATE: "ROOM_UPDATE",
|
ROOM_UPDATE: "room.update",
|
||||||
VOTE_UPDATE: "VOTE_UPDATE",
|
VOTE_UPDATE: "vote.update",
|
||||||
} as const;
|
} as const;
|
||||||
export type EventType = BetterEnum<typeof EventTypes>;
|
export type EventType = BetterEnum<typeof EventTypes>;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue