Skip to content

Commit

Permalink
Make events pages work without auth
Browse files Browse the repository at this point in the history
  • Loading branch information
SheepTester committed Apr 14, 2024
1 parent 8d6a69a commit 9abc321
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 63 deletions.
5 changes: 3 additions & 2 deletions src/lib/api/EventAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ import axios from 'axios';
/**
* Get a single event by UUID
* @param uuid Search query uuid
* @param token Bearer token
* @param token Bearer token. Optional, but should be provided if you need to
* see attendance codes.
* @returns Event info
*/
export const getEvent = async (uuid: UUID, token: string): Promise<PublicEvent> => {
export const getEvent = async (uuid: UUID, token?: string): Promise<PublicEvent> => {
const requestUrl = `${config.api.baseUrl}${config.api.endpoints.event.event}/${uuid}`;

const response = await axios.get<GetOneEventResponse>(requestUrl, {
Expand Down
47 changes: 29 additions & 18 deletions src/lib/hoc/withAccessType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,33 @@ import type {
} from 'next';
import { ParsedUrlQuery } from 'querystring';

/**
* Tries to read the user object from the cookie. If the user object doesn't
* exist or is invalid, then it will try to fetch a new one with the auth token.
*/
export async function getCurrentUser(
{ req, res }: Pick<GetServerSidePropsContext, 'req' | 'res'>,
authToken: string
): Promise<PrivateProfile> {
const userCookie = CookieService.getServerCookie(CookieType.USER, { req, res });
let user: PrivateProfile | undefined;

if (userCookie) {
// Standard flow will use the existing user cookie as src data unless it's corrupted or missing keys, then try to refresh user otherwise redirect on fail
try {
user = JSON.parse(userCookie);
} catch {
user = undefined;
}
}

if (!user?.accessType) {
user = await UserAPI.getCurrentUserAndRefreshCookie(authToken, { req, res });
}

return user;
}

export type GetServerSidePropsWithAuth<
Props extends { [key: string]: any } = { [key: string]: any },
Params extends ParsedUrlQuery = ParsedUrlQuery,
Expand Down Expand Up @@ -42,7 +69,6 @@ export default function withAccessType(
// Generate a new getServerSideProps function by taking the return value of the original function and appending the user prop onto it if the user cookie exists, otherwise force user to login page
const modified: GetServerSideProps = async (context: GetServerSidePropsContext) => {
const { req, res } = context;
const userCookie = CookieService.getServerCookie(CookieType.USER, { req, res });
const authTokenCookie = CookieService.getServerCookie(CookieType.ACCESS_TOKEN, { req, res });

const { homeRoute, loginRoute } = config;
Expand Down Expand Up @@ -73,23 +99,8 @@ export default function withAccessType(
return loginRedirect;
}

let user: PrivateProfile | undefined;
let userAccessLevel: UserAccessType | undefined;

if (userCookie) {
// Standard flow will use the existing user cookie as src data unless it's corrupted or missing keys, then try to refresh user otherwise redirect on fail
try {
user = JSON.parse(userCookie);
userAccessLevel = user?.accessType;
} catch {
user = undefined;
}
}

if (!user || !userAccessLevel) {
user = await UserAPI.getCurrentUserAndRefreshCookie(authTokenCookie, { req, res });
userAccessLevel = user.accessType;
}
const user = await getCurrentUser({ req, res }, authTokenCookie);
const userAccessLevel = user.accessType;

// This block should be impossible to hit assuming the portal API doesn't go down
if (!userAccessLevel) throw new Error('User access level is not defined');
Expand Down
30 changes: 20 additions & 10 deletions src/pages/events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import { DIVIDER } from '@/components/common/Dropdown';
import { EventDisplay } from '@/components/events';
import { config } from '@/lib';
import { EventAPI, UserAPI } from '@/lib/api';
import withAccessType, { GetServerSidePropsWithAuth } from '@/lib/hoc/withAccessType';
import { getCurrentUser } from '@/lib/hoc/withAccessType';
import useQueryState from '@/lib/hooks/useQueryState';
import { PermissionService } from '@/lib/services';
import { CookieService } from '@/lib/services';
import type { PublicAttendance, PublicEvent } from '@/lib/types/apiResponses';
import {
FilterEventOptions,
isValidAttendanceFilter,
isValidCommunityFilter,
isValidDateFilter,
} from '@/lib/types/client';
import { CookieType } from '@/lib/types/enums';
import { formatSearch, getDateRange, getYears } from '@/lib/utils';
import styles from '@/styles/pages/events.module.scss';
import { GetServerSideProps } from 'next';
import { useMemo, useState } from 'react';

interface EventsPageProps {
Expand Down Expand Up @@ -214,9 +216,13 @@ const EventsPage = ({ events, attendances, initialFilters }: EventsPageProps) =>

export default EventsPage;

const getServerSidePropsFunc: GetServerSidePropsWithAuth = async ({ query, authToken }) => {
export const getServerSideProps: GetServerSideProps = async ({ req, res, query }) => {
const authToken: string | null =
CookieService.getServerCookie(CookieType.ACCESS_TOKEN, { req, res }) ?? null;
const user = authToken !== null ? await getCurrentUser({ req, res }, authToken) : null;

const getEventsPromise = EventAPI.getAllEvents();
const getAttendancesPromise = UserAPI.getAttendancesForCurrentUser(authToken);
const getAttendancesPromise = authToken ? UserAPI.getAttendancesForCurrentUser(authToken) : [];

const [events, attendances] = await Promise.all([getEventsPromise, getAttendancesPromise]);

Expand All @@ -229,10 +235,14 @@ const getServerSidePropsFunc: GetServerSidePropsWithAuth = async ({ query, authT

const initialFilters = { community, date, attendance, search };

return { props: { title: 'Events', events, attendances, initialFilters } };
return {
props: {
title: 'Events',
events,
attendances,
initialFilters,
// For navbar
user,
},
};
};

export const getServerSideProps = withAccessType(
getServerSidePropsFunc,
PermissionService.loggedInUser
);
69 changes: 36 additions & 33 deletions src/pages/events/[uuid].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import { Typography } from '@/components/common';
import EventDetail from '@/components/events/EventDetail';
import { Feedback, FeedbackForm } from '@/components/feedback';
import { EventAPI, FeedbackAPI, UserAPI } from '@/lib/api';
import { GetServerSidePropsWithAuth } from '@/lib/hoc/withAccessType';
import { getCurrentUser } from '@/lib/hoc/withAccessType';
import { CookieService } from '@/lib/services';
import type { PublicEvent, PublicFeedback } from '@/lib/types/apiResponses';
import { CookieType } from '@/lib/types/enums';
import { formatEventDate } from '@/lib/utils';
import styles from '@/styles/pages/event.module.scss';
import { GetServerSideProps } from 'next';
import { useMemo, useState } from 'react';

interface EventPageProps {
token: string;
token: string | null;
event: PublicEvent;
attended: boolean;
feedback: PublicFeedback | null;
Expand All @@ -28,7 +31,7 @@ const EventPage = ({ token, event, attended, feedback: initFeedback }: EventPage
<Feedback feedback={feedback} />
</div>
);
} else if (started) {
} else if (started && token) {
feedbackForm = (
<FeedbackForm event={event} attended={attended} authToken={token} onSubmit={setFeedback} />
);
Expand All @@ -44,36 +47,36 @@ const EventPage = ({ token, event, attended, feedback: initFeedback }: EventPage

export default EventPage;

const getServerSidePropsFunc: GetServerSidePropsWithAuth = async ({
params,
user,
authToken: token,
}) => {
export const getServerSideProps: GetServerSideProps = async ({ params, req, res }) => {
const uuid = params?.uuid as string;

// try {
const [event, attendances, [feedback = null]] = await Promise.all([
EventAPI.getEvent(uuid, token),
user ? UserAPI.getAttendancesForCurrentUser(token) : [],
user ? FeedbackAPI.getFeedback(token, { user: user.uuid, event: uuid }) : [],
]);
return {
props: {
title: event.title,
description: `${formatEventDate(event.start, event.end, true)} at ${event.location}\n\n${
event.description
}`,
previewImage: event.cover,
bigPreviewImage: true,
token,
event,
attended: attendances.some(attendance => attendance.event.uuid === uuid),
feedback,
},
};
// } catch {
// return { notFound: true };
// }
};
const token: string | null =
CookieService.getServerCookie(CookieType.ACCESS_TOKEN, { req, res }) ?? null;
const user = token !== null ? await getCurrentUser({ req, res }, token) : null;

export const getServerSideProps = getServerSidePropsFunc;
try {
const [event, attendances, [feedback = null]] = await Promise.all([
EventAPI.getEvent(uuid, token),
token ? UserAPI.getAttendancesForCurrentUser(token) : [],
user ? FeedbackAPI.getFeedback(token, { user: user.uuid, event: uuid }) : [],
]);
return {
props: {
title: event.title,
description: `${formatEventDate(event.start, event.end, true)} at ${event.location}\n\n${
event.description
}`,
previewImage: event.cover,
bigPreviewImage: true,
token,
event,
attended: attendances.some(attendance => attendance.event.uuid === uuid),
feedback,
// For navbar
user,
},
};
} catch {
return { notFound: true };
}
};

0 comments on commit 9abc321

Please sign in to comment.