diff --git a/.github/workflows/step_setup_and_build.yaml b/.github/workflows/step_setup_and_build.yaml
index a584c741f..ebc336bd7 100644
--- a/.github/workflows/step_setup_and_build.yaml
+++ b/.github/workflows/step_setup_and_build.yaml
@@ -64,6 +64,7 @@ jobs:
HOSTED_ZONE_ID: ${{ secrets.HOSTED_ZONE_ID }}
CERTIFICATE_ARN: ${{ secrets.CERTIFICATE_ARN }}
MONGODB_URI_PROD: ${{ secrets.MONGODB_URI_PROD }}
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
PR_NUM: ${{ github.event.pull_request.number }}
# cdk env variables
API_SUB_DOMAIN: ${{ env.apiSubDomain }}
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index d72a3a765..a70b7b362 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -51,6 +51,7 @@ jobs:
HOSTED_ZONE_ID: ${{ secrets.HOSTED_ZONE_ID }}
CERTIFICATE_ARN: ${{ secrets.CERTIFICATE_ARN }}
MONGODB_URI_PROD: ${{ secrets.MONGODB_URI_PROD }}
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
PR_NUM: ${{ github.event.pull_request.number }}
# CDK environment variables.
diff --git a/apps/antalmanac/src/components/Map/Map.tsx b/apps/antalmanac/src/components/Map/Map.tsx
index 2f33e5715..5ec52f9a6 100644
--- a/apps/antalmanac/src/components/Map/Map.tsx
+++ b/apps/antalmanac/src/components/Map/Map.tsx
@@ -14,13 +14,12 @@ import locationIds from '$lib/location_ids';
import buildingCatalogue from '$lib/buildingCatalogue';
import type { Building } from '$lib/buildingCatalogue';
import type { CourseEvent } from '$components/Calendar/CourseCalendarEvent';
-
-const ACCESS_TOKEN = 'pk.eyJ1IjoicGVkcmljIiwiYSI6ImNsZzE0bjk2ajB0NHEzanExZGFlbGpwazIifQ.l14rgv5vmu5wIMgOUUhUXw';
+import { MAPBOX_PROXY_TILES_ENDPOINT } from '$lib/api/endpoints';
const ATTRIBUTION_MARKUP =
'© OpenStreetMap contributors | Images from UCI Map';
-const url = `https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=${ACCESS_TOKEN}`;
+const url = `${MAPBOX_PROXY_TILES_ENDPOINT}/{z}/{x}/{y}`;
const WORK_WEEK = ['All', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
const FULL_WEEK = ['All', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
diff --git a/apps/antalmanac/src/components/Map/Routes.tsx b/apps/antalmanac/src/components/Map/Routes.tsx
index 81ee659cd..597e15f83 100644
--- a/apps/antalmanac/src/components/Map/Routes.tsx
+++ b/apps/antalmanac/src/components/Map/Routes.tsx
@@ -4,8 +4,7 @@ import type { LatLngTuple } from 'leaflet';
import 'leaflet-routing-machine';
import { createElementHook, createElementObject, useLeafletContext } from '@react-leaflet/core';
import type { LeafletContextInterface } from '@react-leaflet/core';
-
-const ACCESS_TOKEN = 'pk.eyJ1IjoicGVkcmljIiwiYSI6ImNsZzE0bjk2ajB0NHEzanExZGFlbGpwazIifQ.l14rgv5vmu5wIMgOUUhUXw';
+import { MAPBOX_PROXY_DIRECTIONS_ENDPOINT } from '$lib/api/endpoints';
interface ClassRoutesProps {
/**
@@ -40,12 +39,14 @@ function createRouter(props: ClassRoutesProps, context: LeafletContextInterface)
const waypoints = latLngTuples.map((latLngTuple) => L.latLng(latLngTuple));
const routerControl = L.Routing.control({
- router: L.Routing.mapbox(ACCESS_TOKEN, {
+ router: L.Routing.mapbox('', {
/**
* Default is mapbox/driving. More options:
* @see {@link https://docs.mapbox.com/api/navigation/directions/#routing-profiles}
*/
profile: 'mapbox/walking',
+
+ serviceUrl: MAPBOX_PROXY_DIRECTIONS_ENDPOINT,
}),
/**
diff --git a/apps/antalmanac/src/lib/api/endpoints.ts b/apps/antalmanac/src/lib/api/endpoints.ts
index 3cb2298e0..673b2cae8 100644
--- a/apps/antalmanac/src/lib/api/endpoints.ts
+++ b/apps/antalmanac/src/lib/api/endpoints.ts
@@ -4,7 +4,7 @@ function endpointTransform(path: string) {
return `https://${import.meta.env.VITE_ENDPOINT}.api.antalmanac.com${path}`;
}
if (import.meta.env.VITE_LOCAL_SERVER) {
- return `http://localhost:8080${path}`;
+ return `http://localhost:3000${path}`;
}
return import.meta.env.MODE === 'development'
? `https://dev.api.antalmanac.com${path}`
@@ -13,6 +13,8 @@ function endpointTransform(path: string) {
export const LOOKUP_NOTIFICATIONS_ENDPOINT = endpointTransform('/api/notifications/lookupNotifications');
export const REGISTER_NOTIFICATIONS_ENDPOINT = endpointTransform('/api/notifications/registerNotifications');
+export const MAPBOX_PROXY_DIRECTIONS_ENDPOINT = endpointTransform('/mapbox/directions');
+export const MAPBOX_PROXY_TILES_ENDPOINT = endpointTransform('/mapbox/tiles');
// PeterPortal API
export const PETERPORTAL_GRAPHQL_ENDPOINT = 'https://api-next.peterportal.org/v1/graphql';
diff --git a/apps/backend/.env.sample b/apps/backend/.env.sample
index f76d05f0d..c935e3941 100644
--- a/apps/backend/.env.sample
+++ b/apps/backend/.env.sample
@@ -9,3 +9,6 @@ USERDATA_TABLE_NAME=tablename
# Provided by Lambda when running on AWS.
AWS_REGION=us-east-1
+
+# For Mapbox API
+MAPBOX_ACCESS_TOKEN=pk.abc123
\ No newline at end of file
diff --git a/apps/backend/src/env.ts b/apps/backend/src/env.ts
index 53ba01944..a1e7db140 100644
--- a/apps/backend/src/env.ts
+++ b/apps/backend/src/env.ts
@@ -7,6 +7,7 @@ const Environment = type([
USERDATA_TABLE_NAME: 'string',
AA_MONGODB_URI: 'string',
AWS_REGION: 'string',
+ MAPBOX_ACCESS_TOKEN: 'string',
'PR_NUM?': 'number',
},
'|>',
diff --git a/apps/backend/src/index.ts b/apps/backend/src/index.ts
index be9483e82..d94d02db6 100644
--- a/apps/backend/src/index.ts
+++ b/apps/backend/src/index.ts
@@ -4,13 +4,15 @@ import type { CorsOptions } from 'cors';
import { createExpressMiddleware } from '@trpc/server/adapters/express';
import AppRouter from './routers';
import createContext from './context';
-import connectToMongoDB from '$db/mongodb';
import env from './env';
+import connectToMongoDB from '$db/mongodb';
const corsOptions: CorsOptions = {
origin: ['https://antalmanac.com', 'https://www.antalmanac.com', 'https://icssc-projects.github.io/AntAlmanac'],
};
+const MAPBOX_API_URL = 'https://api.mapbox.com';
+
const PORT = 3000;
export async function start(corsEnabled = false) {
@@ -20,6 +22,25 @@ export async function start(corsEnabled = false) {
app.use(cors(corsEnabled ? corsOptions : undefined));
app.use(express.json());
+ app.use('/mapbox/directions/*', async (req, res) => {
+ const searchParams = new URLSearchParams(req.query as any);
+ searchParams.set('access_token', env.MAPBOX_ACCESS_TOKEN);
+ const url = `${MAPBOX_API_URL}/directions/v5/${req.params[0]}?${searchParams.toString()}`;
+ const result = await fetch(url).then((res) => res.text());
+ res.send(result);
+ });
+
+ app.use('/mapbox/tiles/*', async (req, res) => {
+ const searchParams = new URLSearchParams(req.query as any);
+ searchParams.set('access_token', env.MAPBOX_ACCESS_TOKEN);
+ const url = `${MAPBOX_API_URL}/styles/v1/mapbox/streets-v11/tiles/${req.params[0]}?${searchParams.toString()}`;
+ const result = await fetch(url).then((res) => res.blob());
+ res.type(result.type)
+ result.arrayBuffer().then((buf) => {
+ res.send(Buffer.from(buf))
+ });
+ });
+
app.use(
'/trpc',
createExpressMiddleware({
diff --git a/apps/cdk/.env.sample b/apps/cdk/.env.sample
index 5983407c2..7ef2814d6 100644
--- a/apps/cdk/.env.sample
+++ b/apps/cdk/.env.sample
@@ -1,2 +1,3 @@
MONGODB_URI_DEV=dev uri
-MONGODB_URI_PROD=prod uri
\ No newline at end of file
+MONGODB_URI_PROD=prod uri
+MAPBOX_ACCESS_TOKEN=pk.abc123
\ No newline at end of file
diff --git a/apps/cdk/lib/app.ts b/apps/cdk/lib/app.ts
index 1e345a641..65897253a 100644
--- a/apps/cdk/lib/app.ts
+++ b/apps/cdk/lib/app.ts
@@ -6,41 +6,30 @@ import FrontendStack from './frontend'
const app = new App({ autoSynth: true })
// Check environmental variables
-if (
- !process.env.CERTIFICATE_ARN ||
- !process.env.HOSTED_ZONE_ID ||
- !process.env.MONGODB_URI_PROD
-) {
+if (!process.env.CERTIFICATE_ARN || !process.env.HOSTED_ZONE_ID || !process.env.MONGODB_URI_PROD) {
throw new Error('Missing environmental variables')
}
// Deploy staging
if (process.env.PR_NUM) {
const env: Environment = { region: 'us-east-1' }
- new FrontendStack(
- app,
- `antalmanac-frontend-staging-${process.env.PR_NUM}`,
- {
+ new FrontendStack(app, `antalmanac-frontend-staging-${process.env.PR_NUM}`, {
+ env,
+ stage: 'staging',
+ certificateArn: process.env.CERTIFICATE_ARN,
+ hostedZoneId: process.env.HOSTED_ZONE_ID,
+ prNum: process.env.PR_NUM,
+ })
+ if (process.env.apiSubDomain !== 'dev') {
+ new BackendStack(app, `antalmanac-backend-staging-${process.env.PR_NUM}`, {
env,
stage: 'staging',
certificateArn: process.env.CERTIFICATE_ARN,
hostedZoneId: process.env.HOSTED_ZONE_ID,
+ mongoDbUriProd: process.env.MONGODB_URI_PROD,
+ mapboxAccessToken: process.env.MAPBOX_ACCESS_TOKEN,
prNum: process.env.PR_NUM,
- },
- )
- if (process.env.apiSubDomain !== 'dev') {
- new BackendStack(
- app,
- `antalmanac-backend-staging-${process.env.PR_NUM}`,
- {
- env,
- stage: 'staging',
- certificateArn: process.env.CERTIFICATE_ARN,
- hostedZoneId: process.env.HOSTED_ZONE_ID,
- mongoDbUriProd: process.env.MONGODB_URI_PROD,
- prNum: process.env.PR_NUM,
- },
- )
+ })
}
}
@@ -60,6 +49,7 @@ else {
certificateArn: process.env.CERTIFICATE_ARN,
hostedZoneId: process.env.HOSTED_ZONE_ID,
mongoDbUriProd: process.env.MONGODB_URI_PROD,
+ mapboxAccessToken: process.env.MAPBOX_ACCESS_TOKEN,
})
// prod frontend is deployed on GitHub Pages
if (stage !== 'prod') {
diff --git a/apps/cdk/lib/backend.ts b/apps/cdk/lib/backend.ts
index 39e019a45..715f8954e 100644
--- a/apps/cdk/lib/backend.ts
+++ b/apps/cdk/lib/backend.ts
@@ -11,6 +11,7 @@ import { transformUrl } from './helpers'
export interface BackendProps extends StackProps {
stage: string
mongoDbUriProd: string
+ mapboxAccessToken: string
hostedZoneId: string
certificateArn: string
prNum?: string
@@ -20,39 +21,32 @@ export default class BackendStack extends Stack {
constructor(scope: Construct, id: string, props: BackendProps) {
super(scope, id, props)
- const userDataDDB = new dynamnodb.Table(
- this,
- `antalmanac-userdata-ddb-${props.stage}`,
- {
- partitionKey: {
- name: 'id',
- type: dynamnodb.AttributeType.STRING,
- },
- billingMode: dynamnodb.BillingMode.PAY_PER_REQUEST,
- removalPolicy:
- props.stage === 'dev' || props.stage === 'prod'
- ? RemovalPolicy.RETAIN
- : RemovalPolicy.DESTROY,
+ const userDataDDB = new dynamnodb.Table(this, `antalmanac-userdata-ddb-${props.stage}`, {
+ partitionKey: {
+ name: 'id',
+ type: dynamnodb.AttributeType.STRING,
},
- )
+ billingMode: dynamnodb.BillingMode.PAY_PER_REQUEST,
+ removalPolicy:
+ props.stage === 'dev' || props.stage === 'prod'
+ ? RemovalPolicy.RETAIN
+ : RemovalPolicy.DESTROY,
+ })
- const api = new lambda.Function(
- this,
- `antalmanac-api-${props.stage}-lambda`,
- {
- runtime: lambda.Runtime.NODEJS_18_X,
- code: lambda.Code.fromAsset('../backend/dist'),
- handler: 'lambda.handler',
- timeout: Duration.seconds(5),
- memorySize: 256,
- environment: {
- // We don't need dev database because we will never write to it
- AA_MONGODB_URI: props.mongoDbUriProd,
- STAGE: props.stage,
- USERDATA_TABLE_NAME: userDataDDB.tableName,
- },
+ const api = new lambda.Function(this, `antalmanac-api-${props.stage}-lambda`, {
+ runtime: lambda.Runtime.NODEJS_18_X,
+ code: lambda.Code.fromAsset('../backend/dist'),
+ handler: 'lambda.handler',
+ timeout: Duration.seconds(5),
+ memorySize: 256,
+ environment: {
+ // We don't need dev database because we will never write to it
+ AA_MONGODB_URI: props.mongoDbUriProd,
+ STAGE: props.stage,
+ USERDATA_TABLE_NAME: userDataDDB.tableName,
+ MAPBOX_ACCESS_TOKEN: props.mapboxAccessToken,
},
- )
+ })
userDataDDB.grantReadWriteData(api)
@@ -82,16 +76,10 @@ export default class BackendStack extends Stack {
},
)
- new route53.ARecord(
- this,
- `antalmanac-backend-a-record-${props.stage}`,
- {
- zone: zone,
- recordName: transformUrl('api', props),
- target: route53.RecordTarget.fromAlias(
- new targets.ApiGateway(apiGateway),
- ),
- },
- )
+ new route53.ARecord(this, `antalmanac-backend-a-record-${props.stage}`, {
+ zone: zone,
+ recordName: transformUrl('api', props),
+ target: route53.RecordTarget.fromAlias(new targets.ApiGateway(apiGateway)),
+ })
}
}