[...path].tsx (3815B)
1 import Hero from '@/components/layout/Hero' 2 import Section from '@/components/layout/Section' 3 import RevisionAlert from '@/components/wiki/RevisionAlert' 4 import WikiArticle from '@/components/wiki/WikiArticle' 5 import WikiBase from '@/components/wiki/WikiBase' 6 import { getPageCache, hasPageCache, putPageCache, refreshPageCache } from '@/lib/pagecache' 7 import { parse, render, Token } from '@/lib/markup' 8 import { withConnection } from '@/lib/model_helpers' 9 import { getWikiViaSlug } from '@/lib/models/wiki_info' 10 import { getWikiPage, getWikiPageRevision, WikiPage } from '@/lib/models/wiki_page' 11 import { getWikiText } from '@/lib/models/wiki_text' 12 import { ACL_ACTION_MANAGE, ACL_ACTION_READ, resolveACL } from '@/lib/security/acl' 13 import { authenticationFromCookies } from '@/lib/security/token' 14 import { getSlugAndPath, getStringFromWikiText } from '@/lib/utils/wiki' 15 import { GetServerSideProps } from 'next' 16 import Link from 'next/link' 17 import { useRouter } from 'next/router' 18 19 export type WikiViewPageProps = { 20 page?: WikiPage 21 tokens?: Token[] 22 enableManage?: boolean 23 } 24 25 export const getServerSideProps: GetServerSideProps<WikiViewPageProps> = async (context) => { 26 const { rev } = context.query 27 const [slug, path] = getSlugAndPath(context) 28 if (slug == null || path == null) { 29 return { notFound: true } 30 } 31 32 const revId = rev == null ? null : parseInt(rev as string) 33 if (revId != null && isNaN(revId)) { 34 return { notFound: true } 35 } 36 37 const token = await authenticationFromCookies(context.req.cookies) 38 39 return await withConnection(async (conn) => { 40 const wiki = await getWikiViaSlug(conn, [slug]) 41 if (wiki == null || !resolveACL(token, wiki.acl, ACL_ACTION_READ)) { 42 return { notFound: true } 43 } 44 45 // 매니징 권한 체크 (메뉴 표시용) 46 const enableManage = resolveACL(token, wiki.acl, ACL_ACTION_MANAGE) 47 48 const page = revId == null 49 ? await getWikiPage(conn, [wiki.id, path]) 50 : await getWikiPageRevision(conn, [wiki.id, path, revId]) 51 if (page == null) { 52 return { props: {} } 53 } 54 55 if (await hasPageCache(page.textId)) { 56 const pageTokens = await getPageCache(page.textId) 57 58 if (pageTokens != null) { 59 await refreshPageCache(page.textId) 60 return { 61 props: { 62 page: page, 63 tokens: pageTokens, 64 enableManage: enableManage, 65 }, 66 } 67 } 68 } 69 70 // Cache miss 71 const wikiText = await getWikiText(conn, [page.textId]) 72 if (wikiText == null) { 73 return { props: {} } 74 } 75 76 const source = await getStringFromWikiText(wikiText) 77 const pageTokens = parse(source) 78 79 await putPageCache(page.textId, pageTokens) 80 return { 81 props: { 82 page: page, 83 tokens: pageTokens, 84 enableManage: enableManage, 85 }, 86 } 87 }) 88 } 89 90 export default function WikiViewPage (props: WikiViewPageProps) { 91 const router = useRouter() 92 const [slug, path] = getSlugAndPath(router) 93 const { rev } = router.query 94 95 function linkRenderer (path: string, text: string) { 96 return <Link href={`/wiki/${slug}/${path}`}>{text}</Link> 97 } 98 99 if (props.page == null || props.tokens == null) { 100 return ( 101 <Hero> 102 <p>문서를 찾지 못했습니다.</p> 103 <p><Link href={`/edit/${slug}/${path}`}>새 문서 만들기</Link></p> 104 </Hero> 105 ) 106 } 107 108 return ( 109 <WikiBase pageKind={'wiki'} title={path ?? ''} enableManage={props.enableManage}> 110 <Section> 111 <WikiArticle> 112 {rev != null && ( 113 <RevisionAlert 114 page={props.page} 115 recentURL={`/wiki/${slug}/${path}`} 116 /> 117 )} 118 119 {render(props.tokens, { 120 linkRenderer: linkRenderer, 121 })} 122 </WikiArticle> 123 </Section> 124 </WikiBase> 125 ) 126 }