diff --git a/.changeset/dont-deploy-prod-at-4am.md b/.changeset/dont-deploy-prod-at-4am.md new file mode 100644 index 000000000..84027b407 --- /dev/null +++ b/.changeset/dont-deploy-prod-at-4am.md @@ -0,0 +1,5 @@ +--- +"web": minor +--- + +fix: import course error diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000..eb79dd995 --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,19 @@ +{ + "mode": "exit", + "tag": "beta", + "initialVersions": { + "admin-api": "1.3.1", + "admin-web": "1.3.0", + "api": "1.9.1", + "reg-scraper": "1.5.1", + "web": "1.11.0", + "web-e2e": "0.3.0", + "@cgr/codegen": "1.5.0", + "@cgr/course-utils": "1.3.0", + "@cgr/project-config": "1.3.0", + "@cgr/schema": "1.5.0" + }, + "changesets": [ + "dont-deploy-prod-at-4am" + ] +} diff --git a/apps/web/CHANGELOG.md b/apps/web/CHANGELOG.md index 7c125a42a..d3cd0cf71 100644 --- a/apps/web/CHANGELOG.md +++ b/apps/web/CHANGELOG.md @@ -1,5 +1,37 @@ # web +## 1.12.0-beta.0 + +### Minor Changes + +- e105063: fix: import course error + +## 1.11.0 + +### Minor Changes + +- af8c1e2: fix: disable referrer check +- af8c1e2: feat: schedule import +- af8c1e2: feat: schedule import part 2 + +## 1.11.0-beta.2 + +### Minor Changes + +- b80e54d: feat: schedule import part 2 + +## 1.11.0-beta.1 + +### Minor Changes + +- cd80cac: feat: schedule import + +## 1.11.0-beta.0 + +### Minor Changes + +- ef01a7c: fix: disable referrer check + ## 1.10.1 ### Patch Changes diff --git a/apps/web/package.json b/apps/web/package.json index e15ba3e4d..3d05fe34e 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "web", - "version": "1.10.1", + "version": "1.12.0-beta.0", "private": true, "scripts": { "dev": "next dev -p 4200", diff --git a/apps/web/src/pages/[studyProgram]/schedule/import/index.tsx b/apps/web/src/pages/[studyProgram]/schedule/import/index.tsx index d4060d625..fa7b68a4c 100644 --- a/apps/web/src/pages/[studyProgram]/schedule/import/index.tsx +++ b/apps/web/src/pages/[studyProgram]/schedule/import/index.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react' -import { ApolloClient, NormalizedCacheObject, isApolloError } from '@apollo/client' +import { ApolloClient, NormalizedCacheObject } from '@apollo/client' import { observer } from 'mobx-react' import { GetServerSidePropsContext, GetServerSidePropsResult } from 'next' import { useRouter } from 'next/router' @@ -32,9 +32,10 @@ interface ScheduleItem { interface ImportPageProps { items: ScheduleItem[] + errorMessage: string[] } -function ImportSchedulePage({ items }: ImportPageProps) { +function ImportSchedulePage({ items, errorMessage }: ImportPageProps) { const router = useRouter() const { buildLink } = useLinkBuilder() @@ -46,64 +47,86 @@ function ImportSchedulePage({ items }: ImportPageProps) { items.forEach(({ course, sectionNo }) => { courseCartStore.addItem(course, sectionNo) }) - router.replace(buildLink(`/schedule`)) + + if (errorMessage.length === 0) router.replace(buildLink(`/schedule`)) } fn() - }, [items, router, buildLink]) + }, [items, router, buildLink, errorMessage]) + + return ( + <> + + + {errorMessage.length > 0 && ( +
+

ERROR

- return +
    + {errorMessage.map((msg, i) => ( +
  • {msg}
  • + ))} +
+
+ )} + + ) } // TODO: research security issues for importing from other 3rd party data sources -const whitelistedOrigins = ['https://esc.eng.chula.ac.th', 'http://localhost:8000'] +// const whitelistedOrigins = ['https://esc.eng.chula.ac.th', 'http://localhost:8000'] export async function getServerSideProps( context: GetServerSidePropsContext ): Promise> { - const referer = context.req.headers.referer as string - const isFromWhitelistedOrigins = whitelistedOrigins.some((origin) => { - return typeof referer === 'string' && referer.startsWith(origin) - }) - if (!isFromWhitelistedOrigins) { - return { - notFound: true, - } - } - try { - const client = createApolloServerClient() - const q = context.query - const courseGroup = parseCourseGroup(q) - const itemsQuery = (q.items as string) ?? '' - const rawItems = itemsQuery - .split(',') - .map((it) => { - if (it.length === 0) { - return null - } - const parts = it.split(':') - if (parts.length !== 2) { - throw new Error('expected 2 parts for each item') - } - return { - courseNo: parts[0], - sectionNo: parts[1], - } - }) - .filter((it) => it !== null) as RawScheduleItem[] - const items = await Promise.all(rawItems.map((it) => fetchItem(client, courseGroup, it))) - return { - props: { - items, - }, - } - } catch (e: unknown) { - if (isApolloError(e as Error)) { + // const referer = context.req.headers.referer as string + // const isFromWhitelistedOrigins = whitelistedOrigins.some((origin) => { + // return typeof referer === 'string' && referer.startsWith(origin) + // }) + // if (!isFromWhitelistedOrigins) { + // return { + // notFound: true, + // } + // } + const client = createApolloServerClient() + const q = context.query + const courseGroup = parseCourseGroup(q) + const itemsQuery = (q.items as string) ?? '' + + const errorMessage: string[] = [] + + const rawItems = itemsQuery + .split(',') + .map((it) => { + if (it.length === 0) { + return null + } + const parts = it.split(':') + if (parts.length !== 2) { + errorMessage.push(`expected 2 parts for each item: ${it}`) + } return { - notFound: true, + courseNo: parts[0], + sectionNo: parts[1], } - } else { - throw e - } + }) + .filter((it) => it !== null) as RawScheduleItem[] + + const items = ( + await Promise.all( + rawItems.map((it) => { + return fetchItem(client, courseGroup, it).catch(() => { + errorMessage.push(`error fetching item: ${it.courseNo} ${it.sectionNo}`) + return null + }) + }) + ) + ).filter((x) => x !== null) as ScheduleItem[] + + return { + props: { + items, + errorMessage, + }, } }