Skip to content

Commit

Permalink
Use NextAuth for private drive API
Browse files Browse the repository at this point in the history
  • Loading branch information
backkjon authored and backjonas committed Aug 21, 2023
1 parent a18eb66 commit 5aa4176
Show file tree
Hide file tree
Showing 18 changed files with 98 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ GOOGLE_PRIVATE_CREDS=''

# Origin of the next app
NEXTAUTH_URL=http://localhost:3000
# Random secret, generate with openssl rand -base64 32
# JWT secret, generate with openssl rand -base64 32. Should be the same as ADMIN_JWT_SECRET in strapi
NEXTAUTH_SECRET=

# Client secret, defined in keycloak
Expand Down
46 changes: 35 additions & 11 deletions components/FileExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,22 @@ import {
import ActivityIndicator from './ActivityIndicator'

const publicDownloadUrl = '/api/drive/public/'
const privateDownloadUrl = '/api/drive/private/'

type DriveExplorerProps = {
folderId: string
isPrivate: boolean
}

const DriveExplorer = ({ folderId }: DriveExplorerProps) => {
const DriveExplorer = ({ folderId, isPrivate }: DriveExplorerProps) => {
const [folderArray, setFolderArray] = useState<(Folder | File)[]>([])
const [isLoading, setLoading] = useState(true)

const downloadUrl = isPrivate ? privateDownloadUrl : publicDownloadUrl

useEffect(() => {
const fetchFolder = async () => {
const res = await fetch(
publicDownloadUrl + `listFiles?folderId=${folderId}`
)
const res = await fetch(downloadUrl + `listFiles?folderId=${folderId}`)
const data = await res.json()
if (data.error) {
console.error(data.error)
Expand All @@ -33,7 +35,7 @@ const DriveExplorer = ({ folderId }: DriveExplorerProps) => {
}

fetchFolder()
}, [folderId])
}, [folderId, downloadUrl])
return (
<div className="pl-4">
{isLoading ? (
Expand All @@ -43,20 +45,34 @@ const DriveExplorer = ({ folderId }: DriveExplorerProps) => {
) : (
folderArray.map((item) =>
item.mimeType === 'application/vnd.google-apps.folder' ? (
<FolderItem key={item.id} folder={item as Folder} />
<FolderItem
key={item.id}
folder={item as Folder}
isPrivate={isPrivate}
/>
) : (
<FileItem key={item.id} file={item as File} />
<FileItem
key={item.id}
file={item as File}
downloadUrl={downloadUrl}
/>
)
)
)}
</div>
)
}

const FileItem = ({ file }: { file: File }) => {
const FileItem = ({
file,
downloadUrl,
}: {
file: File
downloadUrl: string
}) => {
const downloadFile = () => {
window.location.href =
publicDownloadUrl + `download?fileId=${file.id}&fileName=${file.name}`
downloadUrl + `download?fileId=${file.id}&fileName=${file.name}`
}

return (
Expand All @@ -74,7 +90,13 @@ const FileItem = ({ file }: { file: File }) => {
)
}

const FolderItem = ({ folder }: { folder: Folder }) => {
const FolderItem = ({
folder,
isPrivate,
}: {
folder: Folder
isPrivate: boolean
}) => {
const [isExpanded, setExpanded] = useState(false)

const toggleExpanded = () => {
Expand All @@ -94,7 +116,9 @@ const FolderItem = ({ folder }: { folder: Folder }) => {
</div>
{folder.name}
</button>
{isExpanded && <DriveExplorer folderId={folder.id} />}
{isExpanded && (
<DriveExplorer folderId={folder.id} isPrivate={isPrivate} />
)}
</ItemWrapper>
)
}
Expand Down
15 changes: 9 additions & 6 deletions components/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,30 @@ const renderer: marked.RendererObject = {
marked.use({ renderer })

type PageProps = {
page: PageType
page: PageType | null
logos: NationLogo[]
navbarLinks: NavbarLink[]
isPrivate: boolean
}

const Page: NextPage<PageProps> = ({ page, navbarLinks, logos }) => {
const Page: NextPage<PageProps> = ({ page, navbarLinks, logos, isPrivate }) => {
return (
<div className="bg-white">
<Header navbarLinks={navbarLinks} />
{/* TODO: Fix formatting */}
<div className="prose prose-sm m-8 mx-auto min-h-[92vh] max-w-[85vw] rounded-lg bg-white p-[15px] xl:mt-6 xl:max-w-screen-lg">
<h1>{page.title}</h1>
{page.content && <p>{page.content}</p>}
{page.showTableOfContents && (
<h1>{page?.title}</h1>
{page?.content && <p>{page.content}</p>}
{page?.showTableOfContents && (
<TableOfContents sections={page.sections.data} />
)}
{page.sections.data.map((section, i) => (
{page?.sections.data.map((section, i) => (
<PageSection
key={i}
title={section.attributes.title}
content={section.attributes.content}
file_folders={section.attributes.file_folders.data}
isPrivate={isPrivate}
/>
))}
</div>
Expand Down
5 changes: 4 additions & 1 deletion components/PageSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ type PageSectionProps = {
title: string
content?: string
file_folders: FileFolder[]
isPrivate: boolean
}

const PageSection = ({
title,
content,
file_folders,
isPrivate,
}: PageSectionProps) => (
<div>
{/* TODO: Fix formatting */}
<h2 id={titleToAnchor(title)}>{title}</h2>
<div
dangerouslySetInnerHTML={{
Expand All @@ -26,7 +29,7 @@ const PageSection = ({
<div key={i}>
<h3>{attributes.title}</h3>
<p>{attributes.description}</p>
<DriveExplorer folderId={attributes.folderId} />
<DriveExplorer folderId={attributes.folderId} isPrivate={isPrivate} />
</div>
))}
</div>
Expand Down
1 change: 1 addition & 0 deletions components/TableOfContents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Section } from '@models/page'
import { titleToAnchor } from '@utils/helpers'

const TableOfContents = ({ sections }: { sections: Section[] }) => {
// TODO: Fix formatting
return (
<div>
<ul>
Expand Down
2 changes: 1 addition & 1 deletion components/header/navbar/DagsenLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Column from '../../Column'
import Column from '@components/Column'

const DagsenLogo = () => (
<Column>
Expand Down
2 changes: 1 addition & 1 deletion components/header/navbar/TaffaABLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Column from '../../Column'
import Column from '@components/Column'

const TaffaABLogo = () => (
<Column>
Expand Down
4 changes: 2 additions & 2 deletions components/header/navbar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { useState } from 'react'
import Link from 'next/link'
import Row from '../../Row'
import Row from '@components/Row'
import TFLogoSmall from './TFLogoSmall'
import TaffaABLogo from './TaffaABLogo'
import DagsenLogo from './DagsenLogo'
import links from '../../../utils/links'
import links from '@utils/links'
import classNames from 'classnames'
import { NavbarLink, NavbarMultipleLink } from '@lib/api/navbar'
import { useRouter } from 'next/router'
Expand Down
18 changes: 3 additions & 15 deletions middleware/checkAuth.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,12 @@
import { NextApiRequest, NextApiResponse } from 'next'

const checkIfLoggedIn = async (cookies?: string) => {
const fetchHeaders = new Headers()
fetchHeaders.append('Cookie', cookies || '') // Add the cookie header if cookies exist

const kcRes = await fetch(`${process.env.STRAPI_URL}/keycloak/isLoggedIn`, {
headers: fetchHeaders,
})
const isLoggedIn = await kcRes.json()

return isLoggedIn === true
}
import { getSession } from 'next-auth/react'

const requireAuthMiddleware =
(handler: (req: NextApiRequest, res: NextApiResponse) => Promise<void>) =>
async (req: NextApiRequest, res: NextApiResponse) => {
try {
const isLoggedIn = await checkIfLoggedIn(req.headers.cookie) // Pass the cookies from the request

if (isLoggedIn) {
const session = await getSession({ req }) // Pass the cookies from the request
if (session) {
// User is logged in, proceed to the next middleware or route handler
await handler(req, res)
} else {
Expand Down
11 changes: 1 addition & 10 deletions pages/[category]/[contentPage].tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
import { GetStaticPaths, GetStaticProps, NextPage } from 'next'
import { PageType } from '@models/page'
import { marked } from 'marked'
import { fetchContentPage, fetchContentPages } from '@lib/api/contentpage'
import { NavbarLink } from '@lib/api/navbar'
import { NationLogo } from '@components/footer/Logos'
import { getLayoutProps } from '@utils/helpers'
import Page from '@components/Page'

const renderer: marked.RendererObject = {
image(href: string | null): string {
return `<img class='event-page-image' src=${href} alt='bild' />`
},
}

marked.use({ renderer })

type ContentPageProps = {
page: PageType
logos: NationLogo[]
navbarLinks: NavbarLink[]
}

const ContentPage: NextPage<ContentPageProps> = (props) => {
return <Page {...props} />
return <Page {...props} isPrivate={false} />
}

export const getStaticPaths: GetStaticPaths = async () => {
Expand Down
8 changes: 4 additions & 4 deletions pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import NextAuth, { AuthOptions, Session } from 'next-auth'
import NextAuth, { NextAuthOptions } from 'next-auth'
import KeycloakProvider from 'next-auth/providers/keycloak'
import { NextApiRequest, NextApiResponse } from 'next'
import { JWT } from 'next-auth/jwt'

const options: AuthOptions = {
const options: NextAuthOptions = {
debug: false,
providers: [
KeycloakProvider({
Expand All @@ -16,7 +15,8 @@ const options: AuthOptions = {
strategy: 'jwt',
},
callbacks: {
async session({ session, token }: { session: Session; token: JWT }) {
async session({ session, token }) {
session.user.token = token.jwt
return { ...session, jwt: token.jwt, id: token.id }
},
async jwt({ token, user, account }) {
Expand Down
6 changes: 3 additions & 3 deletions pages/api/drive/private/download.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { getDriveInstance, getDriveFile } from '../../../../lib/api/driveFiles'
import requireAuthMiddleware from '../../../../middleware/checkAuth'
import { getDriveInstance, getDriveFile } from '@lib/api/driveFiles'
import requireAuthMiddleware from '@middleware/checkAuth'

const drive = getDriveInstance(process.env.GOOGLE_PRIVATE_CREDS)

Expand All @@ -20,4 +20,4 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
}
}

export default requireAuthMiddleware(handler)
export default requireAuthMiddleware(handler)
7 changes: 2 additions & 5 deletions pages/api/drive/private/listFiles.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { NextApiRequest, NextApiResponse } from 'next'
import {
getDriveFilesList,
getDriveInstance,
} from '../../../../lib/api/driveFiles'
import requireAuthMiddleware from '../../../../middleware/checkAuth'
import { getDriveFilesList, getDriveInstance } from '@lib/api/driveFiles'
import requireAuthMiddleware from '@middleware/checkAuth'

const drive = getDriveInstance(process.env.GOOGLE_PRIVATE_CREDS)

Expand Down
2 changes: 1 addition & 1 deletion pages/api/drive/public/download.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { getDriveInstance, getDriveFile } from '../../../../lib/api/driveFiles'
import { getDriveInstance, getDriveFile } from '@lib/api/driveFiles'

const drive = getDriveInstance()

Expand Down
5 changes: 1 addition & 4 deletions pages/api/drive/public/listFiles.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { NextApiRequest, NextApiResponse } from 'next'
import {
getDriveFilesList,
getDriveInstance,
} from '../../../../lib/api/driveFiles'
import { getDriveFilesList, getDriveInstance } from '@lib/api/driveFiles'

const drive = getDriveInstance()

Expand Down
22 changes: 5 additions & 17 deletions pages/medlem/[privatePage].tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { GetServerSideProps, NextPage } from 'next'
import { PageType } from '@models/page'
import { marked } from 'marked'
import { signIn } from 'next-auth/react'
import { useEffect } from 'react'
import { Session } from 'next-auth'
Expand All @@ -11,16 +10,8 @@ import { NationLogo } from '@components/footer/Logos'
import { getLayoutProps } from '@utils/helpers'
import Page from '@components/Page'

const renderer: marked.RendererObject = {
image(href: string | null): string {
return `<img class='event-page-image' src=${href} alt='bild' />`
},
}

marked.use({ renderer })

type PrivatePageProps = {
page: PageType
page: PageType | null
logos: NationLogo[]
navbarLinks: NavbarLink[]
session: Session
Expand All @@ -30,15 +21,13 @@ const PrivatePage: NextPage<PrivatePageProps> = ({
session,
...props
}: PrivatePageProps) => {
// TODO: Fix login redirect flow
useEffect(() => {
if (!session) {
void signIn('keycloak')
}
}, [session])

// TODO: Return something meaningful instead.. maybe empty page contents?
return session ? <Page {...props} /> : <></>
return <Page {...props} isPrivate={true} />
}

export const getServerSideProps: GetServerSideProps<{
Expand All @@ -47,10 +36,9 @@ export const getServerSideProps: GetServerSideProps<{
const query = context.query.privatePage
const slug = query instanceof Array ? query[0] : query
const session = await getSession(context)
// TODO: Fix types
const page = session?.jwt
? await fetchPrivatePage(session.jwt, slug)
: undefined
const page = session?.user.token
? await fetchPrivatePage(session?.user.token, slug)
: null
const { logos, navbarLinks } = await getLayoutProps()
return {
props: {
Expand Down
Loading

0 comments on commit 5aa4176

Please sign in to comment.