From 8e7828d56274110eec514b3419d080bb8cbe839b Mon Sep 17 00:00:00 2001 From: Max Leiter Date: Mon, 14 Nov 2022 18:39:42 -0800 Subject: [PATCH] fix middleware, migrate gist importing --- .../new/components/description/index.tsx | 2 +- client/app/(posts)/new/from/[id]/page.tsx | 8 ++- client/app/(posts)/post/[id]/page.tsx | 5 +- client/app/admin/components/admin.tsx | 11 +++ client/app/admin/components/post-table.tsx | 6 +- .../badges/visibility-badge/index.tsx | 5 +- .../badges/visibility-control/index.tsx | 3 +- client/app/components/post-list/list-item.tsx | 3 +- .../settings/components/sections/profile.tsx | 2 +- .../new => styles}/react-datepicker.css | 0 .../lib/gist/__tests__/index.ts | 0 {server/src => client}/lib/gist/fetch.ts | 2 - {server/src => client}/lib/gist/index.ts | 0 client/lib/gist/transform.ts | 68 +++++++++++++++++++ {server/src => client}/lib/gist/types.d.ts | 0 client/lib/server/auth.ts | 2 +- client/middleware.ts | 2 +- client/pages/api/gist.ts | 0 server/src/lib/gist/transform.ts | 65 ------------------ 19 files changed, 98 insertions(+), 86 deletions(-) create mode 100644 client/app/admin/components/admin.tsx rename client/app/{(posts)/new => styles}/react-datepicker.css (100%) rename {server/src => client}/lib/gist/__tests__/index.ts (100%) rename {server/src => client}/lib/gist/fetch.ts (95%) rename {server/src => client}/lib/gist/index.ts (100%) create mode 100644 client/lib/gist/transform.ts rename {server/src => client}/lib/gist/types.d.ts (100%) create mode 100644 client/pages/api/gist.ts delete mode 100644 server/src/lib/gist/transform.ts diff --git a/client/app/(posts)/new/components/description/index.tsx b/client/app/(posts)/new/components/description/index.tsx index b5bde981..374ee6ee 100644 --- a/client/app/(posts)/new/components/description/index.tsx +++ b/client/app/(posts)/new/components/description/index.tsx @@ -17,7 +17,7 @@ const Description = ({ onChange, description }: props) => { label="Description" maxLength={256} width="100%" - placeholder="A short description of your post" + placeholder="An optional description of your post" /> ) diff --git a/client/app/(posts)/new/from/[id]/page.tsx b/client/app/(posts)/new/from/[id]/page.tsx index fb782c65..c3c7477d 100644 --- a/client/app/(posts)/new/from/[id]/page.tsx +++ b/client/app/(posts)/new/from/[id]/page.tsx @@ -1,6 +1,7 @@ import NewPost from "../../components/new" -import { notFound } from "next/navigation" +import { notFound, redirect } from "next/navigation" import { getPostById } from "@lib/server/prisma" +import { getSession } from "@lib/server/session" const NewFromExisting = async ({ params @@ -9,6 +10,11 @@ const NewFromExisting = async ({ id: string } }) => { + const session = await getSession() + if (!session?.user) { + return redirect("/signin") + } + const { id } = params if (!id) { diff --git a/client/app/(posts)/post/[id]/page.tsx b/client/app/(posts)/post/[id]/page.tsx index aeec2963..3f1313b3 100644 --- a/client/app/(posts)/post/[id]/page.tsx +++ b/client/app/(posts)/post/[id]/page.tsx @@ -37,10 +37,9 @@ const getPost = async (id: string) => { return { post, isAuthor: isAuthorOrAdmin } } - // must be authed to see unlisted/private if ( - (post.visibility === "unlisted" || post.visibility === "private") && - !user + (post.visibility === "private") && + !isAuthorOrAdmin ) { return notFound() } diff --git a/client/app/admin/components/admin.tsx b/client/app/admin/components/admin.tsx new file mode 100644 index 00000000..43624ecd --- /dev/null +++ b/client/app/admin/components/admin.tsx @@ -0,0 +1,11 @@ +import { getAllPosts, getAllUsers } from "@lib/server/prisma" +import styles from "./admin.module.css" +import PostTable from "./post-table" +import UserTable from "./user-table" + +const Admin = async () => { + + ) +} + +export default Admin diff --git a/client/app/admin/components/post-table.tsx b/client/app/admin/components/post-table.tsx index dc8f810e..329879ea 100644 --- a/client/app/admin/components/post-table.tsx +++ b/client/app/admin/components/post-table.tsx @@ -2,15 +2,15 @@ import SettingsGroup from "@components/settings-group" import { Fieldset, useToasts } from "@geist-ui/core/dist" import byteToMB from "@lib/byte-to-mb" -import { Post } from "@lib/server/prisma"; +import { PostWithFiles } from "@lib/server/prisma"; import Table from "rc-table" -import { useEffect, useMemo, useState } from "react" +import { useMemo } from "react" import ActionDropdown from "./action-dropdown" const PostTable = ({ posts, }: { - posts: Post[] + posts: PostWithFiles[] }) => { const tablePosts = useMemo( () => diff --git a/client/app/components/badges/visibility-badge/index.tsx b/client/app/components/badges/visibility-badge/index.tsx index 04e81f3f..60cfc8db 100644 --- a/client/app/components/badges/visibility-badge/index.tsx +++ b/client/app/components/badges/visibility-badge/index.tsx @@ -1,10 +1,7 @@ -import type { PostVisibility } from "@lib/types" import Badge from "../badge" -type CastPostVisibility = PostVisibility | string - type Props = { - visibility: CastPostVisibility + visibility: string } const VisibilityBadge = ({ visibility }: Props) => { diff --git a/client/app/components/badges/visibility-control/index.tsx b/client/app/components/badges/visibility-control/index.tsx index 2a730089..fca83ebb 100644 --- a/client/app/components/badges/visibility-control/index.tsx +++ b/client/app/components/badges/visibility-control/index.tsx @@ -1,5 +1,4 @@ import { Button, ButtonGroup, Loading, useToasts } from "@geist-ui/core/dist" -import type { PostVisibility } from "@lib/types" import PasswordModal from "@components/password-modal" import { useCallback, useState } from "react" @@ -39,7 +38,7 @@ const VisibilityControl = ({ postId, visibility, setVisibility }: Props) => { ) const onSubmit = useCallback( - async (visibility: PostVisibility, password?: string) => { + async (visibility: string, password?: string) => { if (visibility === "protected" && !password) { setPasswordModalVisible(true) return diff --git a/client/app/components/post-list/list-item.tsx b/client/app/components/post-list/list-item.tsx index d74c8a28..054410ca 100644 --- a/client/app/components/post-list/list-item.tsx +++ b/client/app/components/post-list/list-item.tsx @@ -10,7 +10,6 @@ import Parent from "@geist-ui/icons/arrowUpCircle" import styles from "./list-item.module.css" import Link from "@components/link" import type { PostWithFiles } from "@lib/server/prisma" -import type { PostVisibility } from "@lib/types" import type { File } from "@lib/server/prisma" import Tooltip from "@components/tooltip" import Badge from "@components/badges/badge" @@ -76,7 +75,7 @@ const ListItem = ({ )}
- + {post.files?.length === 1 ? "1 file" diff --git a/client/app/settings/components/sections/profile.tsx b/client/app/settings/components/sections/profile.tsx index f1645a96..116b0527 100644 --- a/client/app/settings/components/sections/profile.tsx +++ b/client/app/settings/components/sections/profile.tsx @@ -1,7 +1,7 @@ "use client" import { Note, Input, Textarea, Button, useToasts } from "@geist-ui/core/dist" -import { User } from "@lib/server/prisma" +import { User } from "next-auth" import { useState } from "react" const Profile = ({ user }: { user: User }) => { diff --git a/client/app/(posts)/new/react-datepicker.css b/client/app/styles/react-datepicker.css similarity index 100% rename from client/app/(posts)/new/react-datepicker.css rename to client/app/styles/react-datepicker.css diff --git a/server/src/lib/gist/__tests__/index.ts b/client/lib/gist/__tests__/index.ts similarity index 100% rename from server/src/lib/gist/__tests__/index.ts rename to client/lib/gist/__tests__/index.ts diff --git a/server/src/lib/gist/fetch.ts b/client/lib/gist/fetch.ts similarity index 95% rename from server/src/lib/gist/fetch.ts rename to client/lib/gist/fetch.ts index 901259c0..694b6c9c 100644 --- a/server/src/lib/gist/fetch.ts +++ b/client/lib/gist/fetch.ts @@ -1,5 +1,3 @@ -import fetch from "node-fetch" -import { Response } from "node-fetch" import { Gist, GistFile } from "./types" async function fetchHelper(response: Response): Promise { diff --git a/server/src/lib/gist/index.ts b/client/lib/gist/index.ts similarity index 100% rename from server/src/lib/gist/index.ts rename to client/lib/gist/index.ts diff --git a/client/lib/gist/transform.ts b/client/lib/gist/transform.ts new file mode 100644 index 00000000..aba9add3 --- /dev/null +++ b/client/lib/gist/transform.ts @@ -0,0 +1,68 @@ +import { Gist } from "./types" +import * as crypto from "crypto" +import type { Post } from "@lib/server/prisma" +import { getHtmlFromFile } from "@lib/server/get-html-from-drift-file" +import { prisma } from "@lib/server/prisma" + +export type AdditionalPostInformation = Pick< + Post, + "visibility" | "password" | "expiresAt" +> & { + userId: string +} + +export async function createPostFromGist( + { userId, visibility, password, expiresAt }: AdditionalPostInformation, + gist: Gist +): Promise { + const files = Object.values(gist.files) + const [title, description] = gist.description.split("\n", 1) + + if (files.length === 0) { + throw new Error("The gist did not have any files") + } + + const newPost = await prisma.post.create({ + data: { + title, + description, + visibility, + password, + expiresAt, + createdAt: new Date(gist.created_at), + author: { + connect: { + id: userId + } + }, + files: { + createMany: { + data: await Promise.all( + files.map(async (file) => { + const content = await file.content() + const html = await getHtmlFromFile({ + content, + title: file.filename + }) + + return { + title: file.filename, + content: content, + sha: crypto + .createHash("sha256") + .update(content) + .digest("hex") + .toString(), + // TODO: shouldn't need this cast + html: html as string, + userId: userId + } + }) + ) + } + } + } + }) + + return newPost +} diff --git a/server/src/lib/gist/types.d.ts b/client/lib/gist/types.d.ts similarity index 100% rename from server/src/lib/gist/types.d.ts rename to client/lib/gist/types.d.ts diff --git a/client/lib/server/auth.ts b/client/lib/server/auth.ts index 5dc41f81..02b7a5a1 100644 --- a/client/lib/server/auth.ts +++ b/client/lib/server/auth.ts @@ -51,7 +51,7 @@ export const authOptions: NextAuthOptions = { return { id: dbUser.id, - name: dbUser.username, + name: dbUser.displayName, email: dbUser.email, picture: dbUser.image, role: dbUser.role || "user", diff --git a/client/middleware.ts b/client/middleware.ts index 86a2b20c..e4c349c0 100644 --- a/client/middleware.ts +++ b/client/middleware.ts @@ -36,7 +36,7 @@ export default withAuth( ) export const config = { - match: [ + matcher: [ // "/signout", // "/", "/signin", diff --git a/client/pages/api/gist.ts b/client/pages/api/gist.ts new file mode 100644 index 00000000..e69de29b diff --git a/server/src/lib/gist/transform.ts b/server/src/lib/gist/transform.ts deleted file mode 100644 index c02b2f6b..00000000 --- a/server/src/lib/gist/transform.ts +++ /dev/null @@ -1,65 +0,0 @@ -import getHtmlFromFile from "@lib/get-html-from-drift-file" -import { Post } from "@lib/models/Post" -import { File } from "@lib/models/File" -import { Gist } from "./types" -import * as crypto from "crypto" - -export type AdditionalPostInformation = Pick< - Post, - "visibility" | "password" | "expiresAt" -> & { - userId: string -} - -export async function createPostFromGist( - { userId, visibility, password, expiresAt }: AdditionalPostInformation, - gist: Gist -): Promise { - const files = Object.values(gist.files) - const [title, description] = gist.description.split("\n", 1) - - if (files.length === 0) { - throw new Error("The gist did not have any files") - } - - const newPost = new Post({ - title, - description, - visibility, - password, - expiresAt, - createdAt: new Date(gist.created_at) - }) - - await newPost.save() - await newPost.$add("users", userId) - const newFiles = await Promise.all( - files.map(async (file) => { - const content = await file.content() - const html = getHtmlFromFile({ content, title: file.filename }) - const newFile = new File({ - title: file.filename, - content, - sha: crypto - .createHash("sha256") - .update(content) - .digest("hex") - .toString(), - html: html || "", - userId: userId, - postId: newPost.id - }) - await newFile.save() - return newFile - }) - ) - - await Promise.all( - newFiles.map(async (file) => { - await newPost.$add("files", file.id) - await newPost.save() - }) - ) - - return newPost -}