diff --git a/.env.local.example b/.env.local.example index a400f9d..33e2441 100644 --- a/.env.local.example +++ b/.env.local.example @@ -5,5 +5,20 @@ NEXT_PUBLIC_BASE_URL=https://cms.tf.fi # Google calendar id for events to be displayed NEXT_PUBLIC_GOOGLE_CALENDAR_ID='' -# Google account credentials in JSON form for authenticating to google calendar API -GOOGLE_CREDS='' \ No newline at end of file +# Google account credentials in JSON form for authenticating to google calendar & drive API +GOOGLE_CREDS='' + +# Google account credentials for private drive API +GOOGLE_PRIVATE_CREDS='' + +# Origin of the next app +NEXTAUTH_URL=http://localhost:3000 +# Random secret, generate with openssl rand -base64 32 +NEXTAUTH_SECRET= + +# Client secret, defined in keycloak +KEYCLOAK_CLIENT_SECRET= +# Client id, defined in keycloak +KEYCLOAK_CLIENT_ID=strapi +# Full path to the keycloak issuer, including realm +KEYCLOAK_ISSUER=https://keycloak-provider/realms/some-realm diff --git a/components/Page.tsx b/components/Page.tsx index 67c72c2..0384f69 100644 --- a/components/Page.tsx +++ b/components/Page.tsx @@ -22,11 +22,7 @@ type PageProps = { navbarLinks: NavbarLink[] } -const Page: NextPage = ({ - page, - navbarLinks, - logos, -}) => { +const Page: NextPage = ({ page, navbarLinks, logos }) => { return (
@@ -50,4 +46,4 @@ const Page: NextPage = ({ ) } -export default Page \ No newline at end of file +export default Page diff --git a/lib/api/privatepage.ts b/lib/api/privatepage.ts index b0dc375..6524511 100644 --- a/lib/api/privatepage.ts +++ b/lib/api/privatepage.ts @@ -1,8 +1,9 @@ import qs from 'qs' import { PageType } from '@models/page' -import { fetchCollection, fetchCollectionSingle } from '@lib/api/strapi' +import strapi from '@lib/api/strapi' export async function fetchPrivatePage( + sessionToken: string, slug?: string ): Promise { if (slug === undefined) return null @@ -15,13 +16,22 @@ export async function fetchPrivatePage( }, }) - const res = await fetchCollectionSingle('/private-pages', slug, { - query, - }) + const res = await strapi.fetchCollectionSingle( + '/private-pages', + slug, + { + query, + headers: { Authorization: `Bearer ${sessionToken}` }, + } + ) return res?.data?.attributes ?? null } -export async function fetchPrivatePages(): Promise { - const res = await fetchCollection('/private-pages') +export async function fetchPrivatePages( + sessionToken: string +): Promise { + const res = await strapi.fetchCollection('/private-pages', { + headers: { Authorization: `Bearer ${sessionToken}` }, + }) return res?.data?.map((c) => c.attributes) ?? [] } diff --git a/lib/api/strapi.ts b/lib/api/strapi.ts index 9943f4d..c8961ca 100644 --- a/lib/api/strapi.ts +++ b/lib/api/strapi.ts @@ -5,6 +5,7 @@ export const API_URL = `${process.env.NEXT_PUBLIC_BASE_URL}/api` export type StrapiFetchOptions = { query?: string url?: string + headers?: HeadersInit } export type SingleResponse = { @@ -69,7 +70,10 @@ async function fetchSingle( const url = options?.url ?? API_URL const query = options?.query ?? '' - return fetchFromStrapi>(`${url}${path}?${query}`) + return fetchFromStrapi>( + `${url}${path}?${query}`, + options?.headers + ) } async function fetchCollectionSingle( @@ -88,7 +92,8 @@ async function fetchCollectionSingle( }) const res = await fetchFromStrapi>( - `${url}${path}?${query}&${slugQuery}` + `${url}${path}?${query}&${slugQuery}`, + options?.headers ) if (!res?.data?.[0]) { @@ -111,15 +116,16 @@ async function fetchCollection( : '' const query = options?.query ?? '' return fetchFromStrapi>( - `${url}${path}?${query}&${paginationQuery}` + `${url}${path}?${query}&${paginationQuery}`, + options?.headers ) } async function fetchFromStrapi< T, S extends CollectionResponse | SingleResponse ->(url: string): Promise | null> { - const res = await fetch(url) +>(url: string, headers?: HeadersInit): Promise | null> { + const res = await fetch(url, { headers }) const json = (await res.json()) as StrapiResponse if (json.error !== undefined) { console.error(`Error fetching ${url}: ${JSON.stringify(json.error)}`) diff --git a/pages/[category]/[contentPage].tsx b/pages/[category]/[contentPage].tsx index fcddb76..ba126cf 100644 --- a/pages/[category]/[contentPage].tsx +++ b/pages/[category]/[contentPage].tsx @@ -22,7 +22,7 @@ type ContentPageProps = { } const ContentPage: NextPage = (props) => { - return + return } export const getStaticPaths: GetStaticPaths = async () => { @@ -30,12 +30,14 @@ export const getStaticPaths: GetStaticPaths = async () => { const contentPages = await fetchContentPages() // Create a path for each page - const paths = contentPages.filter(category => category).map((contentpage) => ({ - params: { - category: contentpage.category?.data.attributes.slug, - contentPage: contentpage.slug, - }, - })) + const paths = contentPages + .filter((category) => category) + .map((contentpage) => ({ + params: { + category: contentpage.category?.data.attributes.slug, + contentPage: contentpage.slug, + }, + })) return { paths, @@ -48,11 +50,11 @@ export const getStaticProps: GetStaticProps = async ({ params }) => { params?.contentPage instanceof Array ? params?.contentPage[0] : params?.contentPage - const contentPage = await fetchContentPage(slug) + const page = await fetchContentPage(slug) const { logos, navbarLinks } = await getLayoutProps() return { props: { - contentPage, + page, navbarLinks, logos, }, diff --git a/pages/index.tsx b/pages/index.tsx index 9cc535a..f7c11e9 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,7 +1,5 @@ -import type { GetServerSideProps, NextPage } from 'next' +import type { GetStaticProps, NextPage } from 'next' import Image from 'next/image' -import { getSession } from 'next-auth/react' -import { Session } from 'next-auth' import { fetchEvents } from '@lib/api/event' import { fetchHomepage } from '@lib/api/homepage' import Column from '@components/Column' @@ -80,9 +78,7 @@ const Home: NextPage = ({ ) -export const getServerSideProps: GetServerSideProps<{ - session: Session | null -}> = async (context) => { +export const getStaticProps: GetStaticProps = async () => { const events = await fetchEvents(1) const homepage = await fetchHomepage() const navbarLinks = await fetchNavbar() @@ -93,7 +89,6 @@ export const getServerSideProps: GetServerSideProps<{ events: events?.data ?? [], logos: homepage?.footer?.nationlogos ?? [], bannerImages: homepage?.banner?.bannerImages?.data ?? [], - session: await getSession(context), }, } } diff --git a/pages/medlem/[privatePage].tsx b/pages/medlem/[privatePage].tsx index 81a462e..51a3224 100644 --- a/pages/medlem/[privatePage].tsx +++ b/pages/medlem/[privatePage].tsx @@ -1,7 +1,11 @@ -import { GetStaticPaths, GetStaticProps, NextPage } from 'next' +import { GetServerSideProps, NextPage } from 'next' import { PageType } from '@models/page' import { marked } from 'marked' -import { fetchPrivatePage, fetchPrivatePages } from '@lib/api/privatepage' +import { signIn } from 'next-auth/react' +import { useEffect } from 'react' +import { Session } from 'next-auth' +import { getSession } from 'next-auth/react' +import { fetchPrivatePage } from '@lib/api/privatepage' import { NavbarLink } from '@lib/api/navbar' import { NationLogo } from '@components/footer/Logos' import { getLayoutProps } from '@utils/helpers' @@ -19,41 +23,41 @@ type PrivatePageProps = { page: PageType logos: NationLogo[] navbarLinks: NavbarLink[] + session: Session } -const PrivatePage: NextPage = (props) => { - return -} - -export const getStaticPaths: GetStaticPaths = async () => { - // Get all content pages - const privatePages = await fetchPrivatePages() - - // Create a path for each page - const paths = privatePages.map((page) => ({ - params: { - privatePage: page.slug, - }, - })) +const PrivatePage: NextPage = ({ + session, + ...props +}: PrivatePageProps) => { + // TODO: Fix login redirect flow + useEffect(() => { + if (!session) { + void signIn('keycloak') + } + }, [session]) - return { - paths, - fallback: 'blocking', - } + // TODO: Return something meaningful instead.. maybe empty page contents? + return session ? : <> } -export const getStaticProps: GetStaticProps = async ({ params }) => { - const slug = - params?.contentPage instanceof Array - ? params?.contentPage[0] - : params?.contentPage - const page = await fetchPrivatePage(slug) +export const getServerSideProps: GetServerSideProps<{ + session: Session | null +}> = async (context) => { + 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 { logos, navbarLinks } = await getLayoutProps() return { props: { page, navbarLinks, logos, + session, }, } }