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:
Atridad Lahiji 2023-08-08 17:26:07 -06:00 committed by GitHub
commit 719973f240
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 306 additions and 405 deletions

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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