Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d1609dd52 | ||
|
|
f3380f302d | ||
|
|
3dba9c7ee1 | ||
|
|
e0e4f7a9d6 | ||
|
|
48293dc579 | ||
|
|
38ac6243a0 | ||
|
|
bd2f58e2a5 | ||
|
|
808e47c6b9 |
@@ -26,6 +26,8 @@ NEXT_PUBLIC_SOCKET_URL="http://localhost:3318"
|
||||
NEXTAUTH_SECRET="your_secret"
|
||||
NEXTAUTH_URL="http://localhost:3000"
|
||||
|
||||
NEXT_PUBLIC_HOST="http://localhost:3000"
|
||||
|
||||
# Next Auth Github Provider
|
||||
GITHUB_CLIENT_ID="your_client_id"
|
||||
GITHUB_CLIENT_SECRET="your_secret"
|
||||
|
||||
@@ -20,6 +20,7 @@ FROM base as builder
|
||||
# Include all NEXT_PUBLIC_* env vars here
|
||||
ARG NEXT_PUBLIC_POSTHOG_KEY
|
||||
ARG NEXT_PUBLIC_SOCKET_URL
|
||||
ARG NEXT_PUBLIC_HOST
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
|
||||
@@ -21,6 +21,13 @@ const config = {
|
||||
defaultLocale: "en",
|
||||
},
|
||||
|
||||
rewrites: async () => [
|
||||
{
|
||||
source: "/ingest/:path*",
|
||||
destination: "https://app.posthog.com/:path*",
|
||||
},
|
||||
],
|
||||
|
||||
webpack: (config) => {
|
||||
config.module.rules.push({
|
||||
test: /\.txt$/,
|
||||
|
||||
@@ -67,7 +67,8 @@
|
||||
"nextjs-routes": "^2.0.1",
|
||||
"openai": "4.0.0-beta.7",
|
||||
"pluralize": "^8.0.0",
|
||||
"posthog-js": "^1.68.4",
|
||||
"posthog-js": "^1.75.3",
|
||||
"posthog-node": "^3.1.1",
|
||||
"prettier": "^3.0.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "18.2.0",
|
||||
|
||||
108
pnpm-lock.yaml
generated
108
pnpm-lock.yaml
generated
@@ -1,4 +1,4 @@
|
||||
lockfileVersion: '6.1'
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
@@ -144,8 +144,11 @@ dependencies:
|
||||
specifier: ^8.0.0
|
||||
version: 8.0.0
|
||||
posthog-js:
|
||||
specifier: ^1.68.4
|
||||
version: 1.68.4
|
||||
specifier: ^1.75.3
|
||||
version: 1.75.3
|
||||
posthog-node:
|
||||
specifier: ^3.1.1
|
||||
version: 3.1.1
|
||||
prettier:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
@@ -2896,7 +2899,7 @@ packages:
|
||||
/@types/eslint-scope@3.7.4:
|
||||
resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==}
|
||||
dependencies:
|
||||
'@types/eslint': 8.37.0
|
||||
'@types/eslint': 8.44.1
|
||||
'@types/estree': 1.0.1
|
||||
dev: true
|
||||
|
||||
@@ -2907,6 +2910,13 @@ packages:
|
||||
'@types/json-schema': 7.0.12
|
||||
dev: true
|
||||
|
||||
/@types/eslint@8.44.1:
|
||||
resolution: {integrity: sha512-XpNDc4Z5Tb4x+SW1MriMVeIsMoONHCkWFMkR/aPJbzEsxqHy+4Glu/BqTdPrApfDeMaXbtNh6bseNgl5KaWrSg==}
|
||||
dependencies:
|
||||
'@types/estree': 1.0.1
|
||||
'@types/json-schema': 7.0.12
|
||||
dev: true
|
||||
|
||||
/@types/estree@1.0.1:
|
||||
resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==}
|
||||
dev: true
|
||||
@@ -3000,6 +3010,10 @@ packages:
|
||||
/@types/node@18.16.0:
|
||||
resolution: {integrity: sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==}
|
||||
|
||||
/@types/node@18.17.1:
|
||||
resolution: {integrity: sha512-xlR1jahfizdplZYRU59JlUx9uzF1ARa8jbhM11ccpCJya8kvos5jwdm2ZAgxSCwOl0fq21svP18EVwPBXMQudw==}
|
||||
dev: true
|
||||
|
||||
/@types/node@20.4.2:
|
||||
resolution: {integrity: sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==}
|
||||
dev: true
|
||||
@@ -3630,6 +3644,15 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/axios@0.27.2:
|
||||
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2
|
||||
form-data: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/axobject-query@3.2.1:
|
||||
resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
|
||||
dependencies:
|
||||
@@ -3750,6 +3773,17 @@ packages:
|
||||
dependencies:
|
||||
fill-range: 7.0.1
|
||||
|
||||
/browserslist@4.21.10:
|
||||
resolution: {integrity: sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==}
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001519
|
||||
electron-to-chromium: 1.4.482
|
||||
node-releases: 2.0.13
|
||||
update-browserslist-db: 1.0.11(browserslist@4.21.10)
|
||||
dev: true
|
||||
|
||||
/browserslist@4.21.9:
|
||||
resolution: {integrity: sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==}
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
@@ -3816,6 +3850,10 @@ packages:
|
||||
/caniuse-lite@1.0.30001517:
|
||||
resolution: {integrity: sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==}
|
||||
|
||||
/caniuse-lite@1.0.30001519:
|
||||
resolution: {integrity: sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==}
|
||||
dev: true
|
||||
|
||||
/chai@4.3.7:
|
||||
resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -4326,6 +4364,10 @@ packages:
|
||||
/electron-to-chromium@1.4.465:
|
||||
resolution: {integrity: sha512-XQcuHvEJRMU97UJ75e170mgcITZoz0lIyiaVjk6R+NMTJ8KBIvUHYd1779swgOppUlzxR+JsLpq59PumaXS1jQ==}
|
||||
|
||||
/electron-to-chromium@1.4.482:
|
||||
resolution: {integrity: sha512-h+UqpfmEr1Qkk0zp7ej/jid7CXoq4m4QzW6wNTb0ELJ/BZCpA4wgUylBIMGCe621tnr4l5VmoHjdoSx2lbnNJA==}
|
||||
dev: true
|
||||
|
||||
/emoji-regex@10.2.1:
|
||||
resolution: {integrity: sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==}
|
||||
dev: false
|
||||
@@ -5108,6 +5150,16 @@ packages:
|
||||
tslib: 2.6.0
|
||||
dev: false
|
||||
|
||||
/follow-redirects@1.15.2:
|
||||
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
debug: '*'
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/for-each@0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
dependencies:
|
||||
@@ -5126,6 +5178,15 @@ packages:
|
||||
mime-types: 2.1.35
|
||||
dev: false
|
||||
|
||||
/form-data@4.0.0:
|
||||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||
engines: {node: '>= 6'}
|
||||
dependencies:
|
||||
asynckit: 0.4.0
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.35
|
||||
dev: false
|
||||
|
||||
/format@0.2.2:
|
||||
resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==}
|
||||
engines: {node: '>=0.4.x'}
|
||||
@@ -5795,7 +5856,7 @@ packages:
|
||||
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
dependencies:
|
||||
'@types/node': 18.16.0
|
||||
'@types/node': 18.17.1
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
dev: true
|
||||
@@ -6778,12 +6839,22 @@ packages:
|
||||
resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==}
|
||||
dev: false
|
||||
|
||||
/posthog-js@1.68.4:
|
||||
resolution: {integrity: sha512-rHk4uk99nvWiDTU7P2mFdEfzFR6km0hvOpCR3tm/+F7kCJKs7QDkMblOZZHZultxM4wSNyB4neeohmnHjKYUhQ==}
|
||||
/posthog-js@1.75.3:
|
||||
resolution: {integrity: sha512-q5xP4R/Tx8E6H0goZQjY+URMLATFiYXc2raHA+31aNvpBs118fPTmExa4RK6MgRZDFhBiMUBZNT6aj7dM3SyUQ==}
|
||||
dependencies:
|
||||
fflate: 0.4.8
|
||||
dev: false
|
||||
|
||||
/posthog-node@3.1.1:
|
||||
resolution: {integrity: sha512-OUSYcnLHbzvY/dxNsbUGoYuTZz5XNx48BkfiCkOIJZMFvot5VPQ0KWEjX+kzYxEwHeXbjW9plqsOVcYCYfidgg==}
|
||||
engines: {node: '>=15.0.0'}
|
||||
dependencies:
|
||||
axios: 0.27.2
|
||||
rusha: 0.8.14
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
||||
/preact-render-to-string@5.2.6(preact@10.16.0):
|
||||
resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==}
|
||||
peerDependencies:
|
||||
@@ -7280,6 +7351,10 @@ packages:
|
||||
queue-microtask: 1.2.3
|
||||
dev: true
|
||||
|
||||
/rusha@0.8.14:
|
||||
resolution: {integrity: sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA==}
|
||||
dev: false
|
||||
|
||||
/rxjs@7.8.1:
|
||||
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||
dependencies:
|
||||
@@ -7737,12 +7812,12 @@ packages:
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 3.3.0
|
||||
serialize-javascript: 6.0.1
|
||||
terser: 5.19.1
|
||||
terser: 5.19.2
|
||||
webpack: 5.88.2
|
||||
dev: true
|
||||
|
||||
/terser@5.19.1:
|
||||
resolution: {integrity: sha512-27hxBUVdV6GoNg1pKQ7Z5cbR6V9txPVyBA+FQw3BaZ1Wuzvztce5p156DaP0NVZNrMZZ+6iG9Syf7WgMNKDg2Q==}
|
||||
/terser@5.19.2:
|
||||
resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
@@ -8021,6 +8096,17 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/update-browserslist-db@1.0.11(browserslist@4.21.10):
|
||||
resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
browserslist: '>= 4.21.0'
|
||||
dependencies:
|
||||
browserslist: 4.21.10
|
||||
escalade: 3.1.1
|
||||
picocolors: 1.0.0
|
||||
dev: true
|
||||
|
||||
/update-browserslist-db@1.0.11(browserslist@4.21.9):
|
||||
resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
|
||||
hasBin: true
|
||||
@@ -8341,7 +8427,7 @@ packages:
|
||||
'@webassemblyjs/wasm-parser': 1.11.6
|
||||
acorn: 8.10.0
|
||||
acorn-import-assertions: 1.9.0(acorn@8.10.0)
|
||||
browserslist: 4.21.9
|
||||
browserslist: 4.21.10
|
||||
chrome-trace-event: 1.0.3
|
||||
enhanced-resolve: 5.15.0
|
||||
es-module-lexer: 1.3.0
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "UserRole" AS ENUM ('ADMIN', 'USER');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "role" "UserRole" NOT NULL DEFAULT 'USER';
|
||||
@@ -249,12 +249,20 @@ model Session {
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
ADMIN
|
||||
USER
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
|
||||
role UserRole @default(USER)
|
||||
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
organizationUsers OrganizationUser[]
|
||||
|
||||
@@ -88,7 +88,7 @@ export default function OutputCell({
|
||||
)}
|
||||
</VStack>
|
||||
),
|
||||
[hardRefetching, hardRefetch, mostRecentResponse, scenario],
|
||||
[hardRefetching, hardRefetch, mostRecentResponse, scenario, cell],
|
||||
);
|
||||
|
||||
if (!vars) return null;
|
||||
|
||||
@@ -29,6 +29,7 @@ export const env = createEnv({
|
||||
client: {
|
||||
NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),
|
||||
NEXT_PUBLIC_SOCKET_URL: z.string().url().default("http://localhost:3318"),
|
||||
NEXT_PUBLIC_HOST: z.string().url().default("http://localhost:3000"),
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -42,6 +43,7 @@ export const env = createEnv({
|
||||
RESTRICT_PRISMA_LOGS: process.env.RESTRICT_PRISMA_LOGS,
|
||||
NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY,
|
||||
NEXT_PUBLIC_SOCKET_URL: process.env.NEXT_PUBLIC_SOCKET_URL,
|
||||
NEXT_PUBLIC_HOST: process.env.NEXT_PUBLIC_HOST,
|
||||
GITHUB_CLIENT_ID: process.env.GITHUB_CLIENT_ID,
|
||||
GITHUB_CLIENT_SECRET: process.env.GITHUB_CLIENT_SECRET,
|
||||
REPLICATE_API_TOKEN: process.env.REPLICATE_API_TOKEN,
|
||||
|
||||
@@ -3,12 +3,12 @@ import { SessionProvider } from "next-auth/react";
|
||||
import { type AppType } from "next/app";
|
||||
import { api } from "~/utils/api";
|
||||
import Favicon from "~/components/Favicon";
|
||||
import "~/utils/analytics";
|
||||
import Head from "next/head";
|
||||
import { ChakraThemeProvider } from "~/theme/ChakraThemeProvider";
|
||||
import { SyncAppStore } from "~/state/sync";
|
||||
import NextAdapterApp from "next-query-params/app";
|
||||
import { QueryParamProvider } from "use-query-params";
|
||||
import { SessionIdentifier } from "~/utils/analytics/clientAnalytics";
|
||||
|
||||
const MyApp: AppType<{ session: Session | null }> = ({
|
||||
Component,
|
||||
@@ -36,6 +36,7 @@ const MyApp: AppType<{ session: Session | null }> = ({
|
||||
<SessionProvider session={session}>
|
||||
<SyncAppStore />
|
||||
<Favicon />
|
||||
<SessionIdentifier />
|
||||
<ChakraThemeProvider>
|
||||
<QueryParamProvider adapter={NextAdapterApp}>
|
||||
<Component {...pageProps} />
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
VStack,
|
||||
useInterval,
|
||||
Image,
|
||||
Flex,
|
||||
} from "@chakra-ui/react";
|
||||
import { signIn, useSession } from "next-auth/react";
|
||||
import Head from "next/head";
|
||||
@@ -124,8 +125,16 @@ function ApplicationStatus(props: BoxProps) {
|
||||
} else if (user) {
|
||||
return (
|
||||
<Wrapper>
|
||||
<HStack spacing={8}>
|
||||
<UserMenu user={user} borderRadius={2} borderColor={"gray.700"} borderWidth={1} pr={6} />
|
||||
<Flex flexDirection={{ base: "column", md: "row" }} alignItems="center">
|
||||
<UserMenu
|
||||
user={user}
|
||||
borderRadius={2}
|
||||
borderColor={"gray.700"}
|
||||
borderWidth={1}
|
||||
pr={6}
|
||||
mr={{ base: 0, md: 8 }}
|
||||
mb={{ base: 8, md: 0 }}
|
||||
/>
|
||||
<Box flex={1}>
|
||||
{entrant?.approved ? (
|
||||
<Text fontSize="sm">
|
||||
@@ -145,7 +154,7 @@ function ApplicationStatus(props: BoxProps) {
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
</HStack>
|
||||
</Flex>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
@@ -192,7 +201,14 @@ export default function Signup() {
|
||||
Event Details
|
||||
</Heading>
|
||||
<Table variant="simple">
|
||||
<Tbody>
|
||||
<Tbody
|
||||
sx={{
|
||||
th: {
|
||||
base: { px: 0 },
|
||||
md: { px: 6 },
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Tr>
|
||||
<Th>Kickoff</Th>
|
||||
<Td>August 14</Td>
|
||||
|
||||
@@ -14,6 +14,7 @@ import superjson from "superjson";
|
||||
import { ZodError } from "zod";
|
||||
import { getServerAuthSession } from "~/server/auth";
|
||||
import { prisma } from "~/server/db";
|
||||
import { capturePath } from "~/utils/analytics/serverAnalytics";
|
||||
|
||||
/**
|
||||
* 1. CONTEXT
|
||||
@@ -112,7 +113,7 @@ export const createTRPCRouter = t.router;
|
||||
export const publicProcedure = t.procedure;
|
||||
|
||||
/** Reusable middleware that enforces users are logged in before running the procedure. */
|
||||
const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
|
||||
const enforceUserIsAuthed = t.middleware(async ({ ctx, next, path }) => {
|
||||
if (!ctx.session || !ctx.session.user) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
@@ -134,6 +135,8 @@ const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
|
||||
"Protected routes must perform access control checks then explicitly invoke the `ctx.markAccessControlRun()` function to ensure we don't forget access control on a route.",
|
||||
});
|
||||
|
||||
capturePath(ctx.session, path);
|
||||
|
||||
return resp;
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,14 @@ import { TRPCError } from "@trpc/server";
|
||||
import { type TRPCContext } from "~/server/api/trpc";
|
||||
import { prisma } from "~/server/db";
|
||||
|
||||
const isAdmin = async (userId: string) => {
|
||||
const user = await prisma.user.findFirst({
|
||||
where: { id: userId, role: "ADMIN" },
|
||||
});
|
||||
|
||||
return !!user;
|
||||
};
|
||||
|
||||
// No-op method for protected routes that really should be accessible to anyone.
|
||||
export const requireNothing = (ctx: TRPCContext) => {
|
||||
ctx.markAccessControlRun();
|
||||
@@ -18,21 +26,24 @@ export const requireCanViewExperiment = async (experimentId: string, ctx: TRPCCo
|
||||
};
|
||||
|
||||
export const canModifyExperiment = async (experimentId: string, userId: string) => {
|
||||
const experiment = await prisma.experiment.findFirst({
|
||||
where: {
|
||||
id: experimentId,
|
||||
organization: {
|
||||
organizationUsers: {
|
||||
some: {
|
||||
role: { in: [OrganizationUserRole.ADMIN, OrganizationUserRole.MEMBER] },
|
||||
userId,
|
||||
const [adminUser, experiment] = await Promise.all([
|
||||
isAdmin(userId),
|
||||
prisma.experiment.findFirst({
|
||||
where: {
|
||||
id: experimentId,
|
||||
organization: {
|
||||
organizationUsers: {
|
||||
some: {
|
||||
role: { in: [OrganizationUserRole.ADMIN, OrganizationUserRole.MEMBER] },
|
||||
userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}),
|
||||
]);
|
||||
|
||||
return !!experiment;
|
||||
return adminUser || !!experiment;
|
||||
};
|
||||
|
||||
export const requireCanModifyExperiment = async (experimentId: string, ctx: TRPCContext) => {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// Make sure we're in the browser
|
||||
import posthog from "posthog-js";
|
||||
import { env } from "~/env.mjs";
|
||||
|
||||
const enableAnalytics = typeof window !== "undefined";
|
||||
|
||||
if (enableAnalytics) {
|
||||
if (env.NEXT_PUBLIC_POSTHOG_KEY) {
|
||||
posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
||||
api_host: "https://app.posthog.com",
|
||||
});
|
||||
}
|
||||
}
|
||||
31
src/utils/analytics/clientAnalytics.ts
Normal file
31
src/utils/analytics/clientAnalytics.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { type Session } from "next-auth";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import posthog from "posthog-js";
|
||||
import { env } from "~/env.mjs";
|
||||
|
||||
// Make sure we're in the browser
|
||||
const enableBrowserAnalytics = typeof window !== "undefined";
|
||||
|
||||
if (env.NEXT_PUBLIC_POSTHOG_KEY && enableBrowserAnalytics) {
|
||||
posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
||||
api_host: `${env.NEXT_PUBLIC_HOST}/ingest`,
|
||||
});
|
||||
}
|
||||
|
||||
export const identifySession = (session: Session) => {
|
||||
if (!session.user) return;
|
||||
posthog.identify(session.user.id, {
|
||||
name: session.user.name,
|
||||
email: session.user.email,
|
||||
});
|
||||
};
|
||||
|
||||
export const SessionIdentifier = () => {
|
||||
const session = useSession().data;
|
||||
useEffect(() => {
|
||||
if (session && enableBrowserAnalytics) identifySession(session);
|
||||
}, [session]);
|
||||
return null;
|
||||
};
|
||||
14
src/utils/analytics/serverAnalytics.ts
Normal file
14
src/utils/analytics/serverAnalytics.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { type Session } from "next-auth";
|
||||
import { PostHog } from "posthog-node";
|
||||
import { env } from "~/env.mjs";
|
||||
|
||||
export const posthogServerClient = env.NEXT_PUBLIC_POSTHOG_KEY
|
||||
? new PostHog(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
||||
host: "https://app.posthog.com",
|
||||
})
|
||||
: null;
|
||||
|
||||
export const capturePath = (session: Session, path: string) => {
|
||||
if (!session.user || !posthogServerClient) return;
|
||||
posthogServerClient?.capture({ distinctId: session.user.id, event: path });
|
||||
};
|
||||
Reference in New Issue
Block a user