gen prisma migration, fix up rendering html (somewhat) in RSC
This commit is contained in:
parent
86b9172527
commit
096cf41eee
17 changed files with 218 additions and 137 deletions
|
@ -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"
|
||||
})
|
||||
|
|
@ -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 = {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
0
client/lib/code-wrapper.tsx
Normal file
0
client/lib/code-wrapper.tsx
Normal file
|
@ -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(
|
||||
// <a href={href || ''}>
|
||||
// {text}
|
||||
// </a>
|
||||
// )
|
||||
// }
|
||||
renderer.link = (href, _, text) => {
|
||||
const isHrefLocal = href?.startsWith('/') || href?.startsWith('#')
|
||||
if (isHrefLocal) {
|
||||
return <a href={href || ''}>
|
||||
{text}
|
||||
</a>
|
||||
}
|
||||
|
||||
// // dirty hack
|
||||
// // if text contains elements, render as html
|
||||
// return <a href={href || ""} target="_blank" rel="noopener noreferrer" dangerouslySetInnerHTML={{ __html: convertHtmlEntities(text) }} ></a>
|
||||
// }
|
||||
// dirty hack
|
||||
// if text contains elements, render as html
|
||||
return <a href={href || ""} target="_blank" rel="noopener noreferrer" dangerouslySetInnerHTML={{ __html: convertHtmlEntities(text) }} ></a>
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
renderer.image = function (href, _, text) {
|
||||
|
@ -71,21 +67,20 @@ renderer.listitem = (text, task, checked) => {
|
|||
return <li>{text}</li>
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
renderer.code = (code: string, language: string) => {
|
||||
return (
|
||||
<pre>
|
||||
{/* {title && <code>{title} </code>} */}
|
||||
{/* {language && title && <code style={{}}> {language} </code>} */}
|
||||
<Code
|
||||
language={language}
|
||||
// title={title}
|
||||
code={code}
|
||||
// highlight={highlight}
|
||||
/>
|
||||
</pre>
|
||||
)
|
||||
}
|
||||
// //@ts-ignore
|
||||
// renderer.code = (code: string, language: string) => {
|
||||
// return (<pre>
|
||||
// {/* {title && <code>{title} </code>} */}
|
||||
// {/* {language && title && <code style={{}}> {language} </code>} */}
|
||||
// <Code
|
||||
// language={language}
|
||||
// // title={title}
|
||||
// code={code}
|
||||
// // highlight={highlight}
|
||||
// />
|
||||
// </pre>
|
||||
// )
|
||||
// }
|
||||
|
||||
marked.setOptions({
|
||||
gfm: true,
|
||||
|
@ -136,7 +131,7 @@ const Code = ({
|
|||
// https://mdxjs.com/guides/syntax-harkedighlighting#all-together
|
||||
return (
|
||||
<>
|
||||
{/* <Highlight
|
||||
<Highlight
|
||||
{...defaultProps}
|
||||
code={code.trim()}
|
||||
language={language as Language}
|
||||
|
@ -177,7 +172,7 @@ const Code = ({
|
|||
))}
|
||||
</code>
|
||||
)}
|
||||
</Highlight> */}
|
||||
</Highlight>
|
||||
<>
|
||||
<code {...props} dangerouslySetInnerHTML={{ __html: code }} />
|
||||
</>
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
33
client/pages/api/file/raw/[id].ts
Normal file
33
client/pages/api/file/raw/[id].ts
Normal file
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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
|
109
client/prisma/migrations/20221112095706_init/migration.sql
Normal file
109
client/prisma/migrations/20221112095706_init/migration.sql
Normal file
|
@ -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");
|
3
client/prisma/migrations/migration_lock.toml
Normal file
3
client/prisma/migrations/migration_lock.toml
Normal file
|
@ -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"
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue