diff --git a/client/app/(posts)/new/components/edit-document-list/edit-document/preview/index.tsx b/client/app/(posts)/components/preview/index.tsx similarity index 88% rename from client/app/(posts)/new/components/edit-document-list/edit-document/preview/index.tsx rename to client/app/(posts)/components/preview/index.tsx index 3ab0fb3a..1ae035b8 100644 --- a/client/app/(posts)/new/components/edit-document-list/edit-document/preview/index.tsx +++ b/client/app/(posts)/components/preview/index.tsx @@ -1,5 +1,3 @@ -import { TOKEN_COOKIE_NAME } from "@lib/constants" -import { getCookie } from "cookies-next" import { memo, useEffect, useState } from "react" import styles from "./preview.module.css" @@ -30,7 +28,7 @@ const MarkdownPreview = ({ height = 500, fileId, content, title }: Props) => { content }) - const resp = await fetch(`/api/files/get-html?${urlQuery}`, { + const resp = await fetch(`/api/file/get-html?${urlQuery}`, { method: "GET" }) diff --git a/client/app/(posts)/new/components/edit-document-list/edit-document/preview/preview.module.css b/client/app/(posts)/components/preview/preview.module.css similarity index 100% rename from client/app/(posts)/new/components/edit-document-list/edit-document/preview/preview.module.css rename to client/app/(posts)/components/preview/preview.module.css diff --git a/client/app/(posts)/new/components/edit-document-list/edit-document/index.tsx b/client/app/(posts)/new/components/edit-document-list/edit-document/index.tsx index ea57157b..962ef182 100644 --- a/client/app/(posts)/new/components/edit-document-list/edit-document/index.tsx +++ b/client/app/(posts)/new/components/edit-document-list/edit-document/index.tsx @@ -12,7 +12,7 @@ import FormattingIcons from "./formatting-icons" import TextareaMarkdown, { TextareaMarkdownRef } from "textarea-markdown-editor" import { Button, Input, Spacer, Tabs, Textarea } from "@geist-ui/core/dist" -import Preview from "./preview" +import Preview from "../../../../components/preview" // import Link from "next/link" type Props = { diff --git a/client/app/(posts)/post/[id]/components/post-page/view-document/index.tsx b/client/app/(posts)/post/[id]/components/post-page/view-document/index.tsx index 08a018ab..bf0036f0 100644 --- a/client/app/(posts)/post/[id]/components/post-page/view-document/index.tsx +++ b/client/app/(posts)/post/[id]/components/post-page/view-document/index.tsx @@ -14,7 +14,7 @@ import { Tooltip, Tag } from "@geist-ui/core/dist" -import HtmlPreview from "app/(posts)/new/components/edit-document-list/edit-document/preview" +import HtmlPreview from "app/(posts)/components/preview" import FadeIn from "@components/fade-in" // import Link from "next/link" diff --git a/client/app/components/home.tsx b/client/app/components/home.tsx index cbc69933..607c9b9a 100644 --- a/client/app/components/home.tsx +++ b/client/app/components/home.tsx @@ -4,7 +4,7 @@ import { Spacer, Tabs, Card, Textarea, Text } from "@geist-ui/core/dist" import Image from "next/image" import styles from "./home.module.css" // TODO:components/new-post/ move these styles -import markdownStyles from "app/(posts)/new/components/edit-document-list/edit-document/preview/preview.module.css"; +import markdownStyles from "app/(posts)/components/preview/preview.module.css"; const Home = ({ introTitle, introContent, diff --git a/client/app/mine/page.tsx b/client/app/mine/page.tsx index f35be304..52b3c511 100644 --- a/client/app/mine/page.tsx +++ b/client/app/mine/page.tsx @@ -9,7 +9,7 @@ export default async function Mine() { const userId = (await getCurrentUser())?.id if (!userId) { - redirect(authOptions.pages?.signIn || "/new") + return redirect(authOptions.pages?.signIn || "/new") } const posts = await getPostsByUser(userId, true) diff --git a/client/lib/code-wrapper.tsx b/client/lib/code-wrapper.tsx new file mode 100644 index 00000000..e69de29b diff --git a/client/lib/render-markdown.tsx b/client/lib/render-markdown.tsx index d03b9073..20b4127f 100644 --- a/client/lib/render-markdown.tsx +++ b/client/lib/render-markdown.tsx @@ -1,8 +1,6 @@ import { marked } from "marked" -// import Highlight, { defaultProps, Language } from "prism-react-renderer" -import { renderToStaticMarkup } from "react-dom/server" +import Highlight, { defaultProps, Language } from "prism-react-renderer" import Image from "next/image" -import Link from "next/link" // // image sizes. DDoS Safe? // const imageSizeLink = /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?)\]\(\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?(?:\s+=(?:[\w%]+)?x(?:[\w%]+)?)?)(?:\s+("(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)))?\s*\)/; @@ -14,7 +12,7 @@ import Link from "next/link" // Lexer.rules.inline.breaks.link = imageSizeLink; //@ts-ignore -// delete defaultProps.theme +delete defaultProps.theme // import linkStyles from '../components/link/link.module.css' const renderer = new marked.Renderer() @@ -33,20 +31,18 @@ const renderer = new marked.Renderer() // ) // } -// renderer.link = (href, _, text) => { -// const isHrefLocal = href?.startsWith('/') || href?.startsWith('#') -// if (isHrefLocal) { -// return renderToStaticMarkup( -// -// {text} -// -// ) -// } +renderer.link = (href, _, text) => { + const isHrefLocal = href?.startsWith('/') || href?.startsWith('#') + if (isHrefLocal) { + return + {text} + + } -// // dirty hack -// // if text contains elements, render as html -// return -// } + // dirty hack + // if text contains elements, render as html + return +} // @ts-ignore renderer.image = function (href, _, text) { @@ -71,21 +67,20 @@ renderer.listitem = (text, task, checked) => { return
- {/* {title &&- ) -} +// //@ts-ignore +// renderer.code = (code: string, language: string) => { +// return ({title}
} */} - {/* {language && title &&{language}
} */} --
+// {/* {title &&+// ) +// } marked.setOptions({ gfm: true, @@ -136,7 +131,7 @@ const Code = ({ // https://mdxjs.com/guides/syntax-harkedighlighting#all-together return ( <> - {/*{title}
} */} +// {/* {language && title &&{language}
} */} +//+//
>
diff --git a/client/next.config.mjs b/client/next.config.mjs
index b4fc3c6d..6d039b45 100644
--- a/client/next.config.mjs
+++ b/client/next.config.mjs
@@ -24,10 +24,6 @@ const nextConfig = {
},
async rewrites() {
return [
- {
- source: "/server-api/:path*",
- destination: `${process.env.API_URL}/:path*`
- },
{
source: "/file/raw/:id",
destination: `/api/raw/:id`
diff --git a/client/pages/api/file/get-html.ts b/client/pages/api/file/get-html.ts
index cfadb1a6..6749c0f6 100644
--- a/client/pages/api/file/get-html.ts
+++ b/client/pages/api/file/get-html.ts
@@ -4,44 +4,44 @@ import { parseQueryParam } from "@lib/server/parse-query-param"
import prisma from "@lib/server/prisma"
import { NextApiRequest, NextApiResponse } from "next"
-export default withMethods(["GET"], (
- req: NextApiRequest,
- res: NextApiResponse
-) => {
- const query = req.query
- const fileId = parseQueryParam(query.fileId)
- const content = parseQueryParam(query.content)
- const title = parseQueryParam(query.title)
+export default withMethods(
+ ["GET"],
+ async (req: NextApiRequest, res: NextApiResponse) => {
+ const query = req.query
+ const fileId = parseQueryParam(query.fileId)
+ const content = parseQueryParam(query.content)
+ const title = parseQueryParam(query.title)
- if (fileId && (content || title)) {
- return res.status(400).json({ error: "Too many arguments" })
- }
+ if (fileId && (content || title)) {
+ return res.status(400).json({ error: "Too many arguments" })
+ }
- if (fileId) {
- const file = await prisma.file.findUnique({
- where: {
- id: fileId
+ if (fileId) {
+ const file = await prisma.file.findUnique({
+ where: {
+ id: fileId
+ }
+ })
+
+ if (!file) {
+ return res.status(404).json({ error: "File not found" })
}
- })
- if (!file) {
- return res.status(404).json({ error: "File not found" })
+ return res.json(file.html)
+ } else {
+ if (!content || !title) {
+ return res.status(400).json({ error: "Missing arguments" })
+ }
+
+ const renderedHTML = getHtmlFromFile({
+ title,
+ content
+ })
+
+ res.setHeader("Content-Type", "text/plain")
+ res.status(200).write(renderedHTML)
+ res.end()
+ return
}
-
- return res.json(file.html)
- } else {
- if (!content || !title) {
- return res.status(400).json({ error: "Missing arguments" })
- }
-
- const renderedHTML = getHtmlFromFile({
- title,
- content
- })
-
- res.setHeader("Content-Type", "text/plain")
- res.status(200).write(renderedHTML)
- res.end()
- return
}
-}
+)
diff --git a/client/pages/api/file/html/[id].ts b/client/pages/api/file/html/[id].ts
index 8aad9f7b..a59caaad 100644
--- a/client/pages/api/file/html/[id].ts
+++ b/client/pages/api/file/html/[id].ts
@@ -9,6 +9,8 @@ const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => {
}
})
+ console.log("file", file, "id", req.query.id)
+
if (!file) {
return res.status(404).end()
}
diff --git a/client/pages/api/file/raw/[id].ts b/client/pages/api/file/raw/[id].ts
new file mode 100644
index 00000000..4e6a37e1
--- /dev/null
+++ b/client/pages/api/file/raw/[id].ts
@@ -0,0 +1,33 @@
+import { NextApiRequest, NextApiResponse } from "next"
+import prisma from "lib/server/prisma"
+import { parseQueryParam } from "@lib/server/parse-query-param"
+
+const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => {
+ const { id, download } = req.query
+
+ const file = await prisma.file.findUnique({
+ where: {
+ id: parseQueryParam(id)
+ }
+ })
+
+ if (!file) {
+ return res.status(404).json({ error: "File not found" })
+ }
+
+ res.setHeader("Content-Type", "text/plain; charset=utf-8")
+ res.setHeader("Cache-Control", "s-maxage=86400")
+
+ const { title, content } = file
+
+ if (download) {
+ res.setHeader("Content-Disposition", `attachment; filename="${title}"`)
+ } else {
+ res.setHeader("Content-Disposition", `inline; filename="${title}"`)
+ }
+
+ res.status(200).write(content, "utf-8")
+ res.end()
+}
+
+export default getRawFile
diff --git a/client/pages/api/post/index.ts b/client/pages/api/post/index.ts
index e105f974..97c50c2f 100644
--- a/client/pages/api/post/index.ts
+++ b/client/pages/api/post/index.ts
@@ -1,14 +1,8 @@
// nextjs typescript api handler
-import { withCurrentUser } from "@lib/api-middleware/with-current-user"
import { withMethods } from "@lib/api-middleware/with-methods"
-import {
- NextApiHandlerWithParsedBody,
- withValidation
-} from "@lib/api-middleware/with-validation"
+
import { authOptions } from "@lib/server/auth"
-import { CreatePostSchema } from "@lib/validations/post"
-import { Post } from "@prisma/client"
import prisma, { getPostById } from "@lib/server/prisma"
import { NextApiRequest, NextApiResponse } from "next"
import { unstable_getServerSession } from "next-auth/next"
diff --git a/client/pages/api/raw/[id].ts b/client/pages/api/raw/[id].ts
deleted file mode 100644
index 401e7803..00000000
--- a/client/pages/api/raw/[id].ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { NextApiRequest, NextApiResponse } from "next"
-
-const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => {
- const { id, download } = req.query
- const file = await fetch(`${process.env.API_URL}/files/raw/${id}`, {
- headers: {
- Accept: "text/plain",
- "x-secret-key": process.env.SECRET_KEY || "",
- Authorization: `Bearer ${req.cookies["drift-token"]}`
- }
- })
-
- res.setHeader("Content-Type", "text/plain; charset=utf-8")
- res.setHeader("Cache-Control", "s-maxage=86400")
- if (file.ok) {
- const json = await file.json()
- const data = json
- const { title, content } = data
- // serve the file raw as plain text
-
- if (download) {
- res.setHeader("Content-Disposition", `attachment; filename="${title}"`)
- } else {
- res.setHeader("Content-Disposition", `inline; filename="${title}"`)
- }
-
- res.status(200).write(content, "utf-8")
- res.end()
- } else {
- res.status(404).send("File not found")
- }
-}
-
-export default getRawFile
diff --git a/client/prisma/migrations/20221112095706_init/migration.sql b/client/prisma/migrations/20221112095706_init/migration.sql
new file mode 100644
index 00000000..9172c0b7
--- /dev/null
+++ b/client/prisma/migrations/20221112095706_init/migration.sql
@@ -0,0 +1,109 @@
+-- CreateTable
+CREATE TABLE "SequelizeMeta" (
+ "name" TEXT NOT NULL,
+
+ CONSTRAINT "SequelizeMeta_pkey" PRIMARY KEY ("name")
+);
+
+-- CreateTable
+CREATE TABLE "files" (
+ "id" TEXT NOT NULL,
+ "title" TEXT NOT NULL,
+ "content" TEXT NOT NULL,
+ "sha" TEXT NOT NULL,
+ "html" TEXT NOT NULL,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+ "deletedAt" TIMESTAMP(3),
+ "userId" TEXT NOT NULL,
+ "postId" TEXT NOT NULL,
+
+ CONSTRAINT "files_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "posts" (
+ "id" TEXT NOT NULL,
+ "title" TEXT NOT NULL,
+ "visibility" TEXT NOT NULL,
+ "password" TEXT,
+ "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" TIMESTAMP(3) NOT NULL,
+ "deletedAt" TIMESTAMP(3),
+ "expiresAt" TIMESTAMP(3),
+ "parentId" TEXT,
+ "description" TEXT,
+ "authorId" TEXT NOT NULL,
+
+ CONSTRAINT "posts_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "accounts" (
+ "id" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "type" TEXT NOT NULL,
+ "provider" TEXT NOT NULL,
+ "providerAccountId" TEXT NOT NULL,
+ "refresh_token" TEXT,
+ "access_token" TEXT,
+ "expires_at" INTEGER,
+ "token_type" TEXT,
+ "scope" TEXT,
+ "id_token" TEXT,
+ "session_state" TEXT,
+ "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "refresh_token_expires_in" INTEGER,
+
+ CONSTRAINT "accounts_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "Session" (
+ "id" TEXT NOT NULL,
+ "sessionToken" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "expires" TIMESTAMP(3) NOT NULL,
+
+ CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "users" (
+ "id" TEXT NOT NULL,
+ "name" TEXT,
+ "email" TEXT,
+ "emailVerified" TIMESTAMP(3),
+ "image" TEXT,
+ "username" TEXT,
+ "role" TEXT DEFAULT 'user',
+ "password" TEXT,
+
+ CONSTRAINT "users_pkey" PRIMARY KEY ("id")
+);
+
+-- CreateTable
+CREATE TABLE "verification_tokens" (
+ "identifier" TEXT NOT NULL,
+ "token" TEXT NOT NULL,
+ "expires" TIMESTAMP(3) NOT NULL
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "accounts_provider_providerAccountId_key" ON "accounts"("provider", "providerAccountId");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "users_username_key" ON "users"("username");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "verification_tokens_token_key" ON "verification_tokens"("token");
+
+-- CreateIndex
+CREATE UNIQUE INDEX "verification_tokens_identifier_token_key" ON "verification_tokens"("identifier", "token");
diff --git a/client/prisma/migrations/migration_lock.toml b/client/prisma/migrations/migration_lock.toml
new file mode 100644
index 00000000..fbffa92c
--- /dev/null
+++ b/client/prisma/migrations/migration_lock.toml
@@ -0,0 +1,3 @@
+# Please do not edit this file manually
+# It should be added in your version-control system (i.e. Git)
+provider = "postgresql"
\ No newline at end of file
diff --git a/client/prisma/schema.prisma b/client/prisma/schema.prisma
index c018046f..07dc4007 100644
--- a/client/prisma/schema.prisma
+++ b/client/prisma/schema.prisma
@@ -9,21 +9,6 @@ datasource db {
referentialIntegrity = "prisma"
}
-model AuthTokens {
- id String @default(cuid())
- token String
- expiredReason String?
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
- deletedAt DateTime?
- userId String
- // TODO: verify this isn't necessary / is replaced by an implicit m-n relation
- // users DriftUser[] @relation(fields: [userId], references: [id], onDelete: Cascade)
-
- @@id([id, token])
- // make id and token keys
- @@unique([id, token])
-}
model SequelizeMeta {
name String @id
@@ -33,7 +18,7 @@ model File {
id String @id @default(cuid())
title String
content String
- sha String @unique
+ sha String
html String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt