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 { memo, useEffect, useState } from "react"
|
||||||
import styles from "./preview.module.css"
|
import styles from "./preview.module.css"
|
||||||
|
|
||||||
|
@ -30,7 +28,7 @@ const MarkdownPreview = ({ height = 500, fileId, content, title }: Props) => {
|
||||||
content
|
content
|
||||||
})
|
})
|
||||||
|
|
||||||
const resp = await fetch(`/api/files/get-html?${urlQuery}`, {
|
const resp = await fetch(`/api/file/get-html?${urlQuery}`, {
|
||||||
method: "GET"
|
method: "GET"
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,7 +12,7 @@ import FormattingIcons from "./formatting-icons"
|
||||||
import TextareaMarkdown, { TextareaMarkdownRef } from "textarea-markdown-editor"
|
import TextareaMarkdown, { TextareaMarkdownRef } from "textarea-markdown-editor"
|
||||||
|
|
||||||
import { Button, Input, Spacer, Tabs, Textarea } from "@geist-ui/core/dist"
|
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"
|
// import Link from "next/link"
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Tag
|
Tag
|
||||||
} from "@geist-ui/core/dist"
|
} 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 FadeIn from "@components/fade-in"
|
||||||
|
|
||||||
// import Link from "next/link"
|
// 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 Image from "next/image"
|
||||||
import styles from "./home.module.css"
|
import styles from "./home.module.css"
|
||||||
// TODO:components/new-post/ move these styles
|
// 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 = ({
|
const Home = ({
|
||||||
introTitle,
|
introTitle,
|
||||||
introContent,
|
introContent,
|
||||||
|
|
|
@ -9,7 +9,7 @@ export default async function Mine() {
|
||||||
const userId = (await getCurrentUser())?.id
|
const userId = (await getCurrentUser())?.id
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
redirect(authOptions.pages?.signIn || "/new")
|
return redirect(authOptions.pages?.signIn || "/new")
|
||||||
}
|
}
|
||||||
|
|
||||||
const posts = await getPostsByUser(userId, true)
|
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 { marked } from "marked"
|
||||||
// import Highlight, { defaultProps, Language } from "prism-react-renderer"
|
import Highlight, { defaultProps, Language } from "prism-react-renderer"
|
||||||
import { renderToStaticMarkup } from "react-dom/server"
|
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
import Link from "next/link"
|
|
||||||
|
|
||||||
// // image sizes. DDoS Safe?
|
// // image sizes. DDoS Safe?
|
||||||
// const imageSizeLink = /^!?\[((?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?)\]\(\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?(?:\s+=(?:[\w%]+)?x(?:[\w%]+)?)?)(?:\s+("(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)))?\s*\)/;
|
// 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;
|
// Lexer.rules.inline.breaks.link = imageSizeLink;
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
// delete defaultProps.theme
|
delete defaultProps.theme
|
||||||
// import linkStyles from '../components/link/link.module.css'
|
// import linkStyles from '../components/link/link.module.css'
|
||||||
|
|
||||||
const renderer = new marked.Renderer()
|
const renderer = new marked.Renderer()
|
||||||
|
@ -33,20 +31,18 @@ const renderer = new marked.Renderer()
|
||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// renderer.link = (href, _, text) => {
|
renderer.link = (href, _, text) => {
|
||||||
// const isHrefLocal = href?.startsWith('/') || href?.startsWith('#')
|
const isHrefLocal = href?.startsWith('/') || href?.startsWith('#')
|
||||||
// if (isHrefLocal) {
|
if (isHrefLocal) {
|
||||||
// return renderToStaticMarkup(
|
return <a href={href || ''}>
|
||||||
// <a href={href || ''}>
|
{text}
|
||||||
// {text}
|
</a>
|
||||||
// </a>
|
}
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // dirty hack
|
// dirty hack
|
||||||
// // if text contains elements, render as html
|
// if text contains elements, render as html
|
||||||
// return <a href={href || ""} target="_blank" rel="noopener noreferrer" dangerouslySetInnerHTML={{ __html: convertHtmlEntities(text) }} ></a>
|
return <a href={href || ""} target="_blank" rel="noopener noreferrer" dangerouslySetInnerHTML={{ __html: convertHtmlEntities(text) }} ></a>
|
||||||
// }
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
renderer.image = function (href, _, text) {
|
renderer.image = function (href, _, text) {
|
||||||
|
@ -71,21 +67,20 @@ renderer.listitem = (text, task, checked) => {
|
||||||
return <li>{text}</li>
|
return <li>{text}</li>
|
||||||
}
|
}
|
||||||
|
|
||||||
//@ts-ignore
|
// //@ts-ignore
|
||||||
renderer.code = (code: string, language: string) => {
|
// renderer.code = (code: string, language: string) => {
|
||||||
return (
|
// return (<pre>
|
||||||
<pre>
|
// {/* {title && <code>{title} </code>} */}
|
||||||
{/* {title && <code>{title} </code>} */}
|
// {/* {language && title && <code style={{}}> {language} </code>} */}
|
||||||
{/* {language && title && <code style={{}}> {language} </code>} */}
|
// <Code
|
||||||
<Code
|
// language={language}
|
||||||
language={language}
|
// // title={title}
|
||||||
// title={title}
|
// code={code}
|
||||||
code={code}
|
// // highlight={highlight}
|
||||||
// highlight={highlight}
|
// />
|
||||||
/>
|
// </pre>
|
||||||
</pre>
|
// )
|
||||||
)
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
marked.setOptions({
|
marked.setOptions({
|
||||||
gfm: true,
|
gfm: true,
|
||||||
|
@ -136,7 +131,7 @@ const Code = ({
|
||||||
// https://mdxjs.com/guides/syntax-harkedighlighting#all-together
|
// https://mdxjs.com/guides/syntax-harkedighlighting#all-together
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* <Highlight
|
<Highlight
|
||||||
{...defaultProps}
|
{...defaultProps}
|
||||||
code={code.trim()}
|
code={code.trim()}
|
||||||
language={language as Language}
|
language={language as Language}
|
||||||
|
@ -177,7 +172,7 @@ const Code = ({
|
||||||
))}
|
))}
|
||||||
</code>
|
</code>
|
||||||
)}
|
)}
|
||||||
</Highlight> */}
|
</Highlight>
|
||||||
<>
|
<>
|
||||||
<code {...props} dangerouslySetInnerHTML={{ __html: code }} />
|
<code {...props} dangerouslySetInnerHTML={{ __html: code }} />
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -24,10 +24,6 @@ const nextConfig = {
|
||||||
},
|
},
|
||||||
async rewrites() {
|
async rewrites() {
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
source: "/server-api/:path*",
|
|
||||||
destination: `${process.env.API_URL}/:path*`
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
source: "/file/raw/:id",
|
source: "/file/raw/:id",
|
||||||
destination: `/api/raw/:id`
|
destination: `/api/raw/:id`
|
||||||
|
|
|
@ -4,10 +4,9 @@ import { parseQueryParam } from "@lib/server/parse-query-param"
|
||||||
import prisma from "@lib/server/prisma"
|
import prisma from "@lib/server/prisma"
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
export default withMethods(["GET"], (
|
export default withMethods(
|
||||||
req: NextApiRequest,
|
["GET"],
|
||||||
res: NextApiResponse
|
async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
) => {
|
|
||||||
const query = req.query
|
const query = req.query
|
||||||
const fileId = parseQueryParam(query.fileId)
|
const fileId = parseQueryParam(query.fileId)
|
||||||
const content = parseQueryParam(query.content)
|
const content = parseQueryParam(query.content)
|
||||||
|
@ -45,3 +44,4 @@ export default withMethods(["GET"], (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
|
@ -9,6 +9,8 @@ const getRawFile = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log("file", file, "id", req.query.id)
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return res.status(404).end()
|
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
|
// nextjs typescript api handler
|
||||||
|
|
||||||
import { withCurrentUser } from "@lib/api-middleware/with-current-user"
|
|
||||||
import { withMethods } from "@lib/api-middleware/with-methods"
|
import { withMethods } from "@lib/api-middleware/with-methods"
|
||||||
import {
|
|
||||||
NextApiHandlerWithParsedBody,
|
|
||||||
withValidation
|
|
||||||
} from "@lib/api-middleware/with-validation"
|
|
||||||
import { authOptions } from "@lib/server/auth"
|
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 prisma, { getPostById } from "@lib/server/prisma"
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
import { unstable_getServerSession } from "next-auth/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"
|
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 {
|
model SequelizeMeta {
|
||||||
name String @id
|
name String @id
|
||||||
|
@ -33,7 +18,7 @@ model File {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
title String
|
title String
|
||||||
content String
|
content String
|
||||||
sha String @unique
|
sha String
|
||||||
html String
|
html String
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
Loading…
Reference in a new issue