Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
working-directory: ${{ github.workspace }}
- name: Test Suite
run: |
export DOCUMENTED=1
export MBUS_URL=https://mbus.bustime.mock.mb.thething.fyi/
export RIDE_URL=https://ride.bustime.mock.mb.thething.fyi/
npm start &
Expand Down Expand Up @@ -59,7 +60,7 @@ jobs:
- name: Build Docs
run: npx typedoc --entryPointStrategy expand ./src --treatWarningsAsErrors
working-directory: ${{ github.workspace }}
- name: Sync files
- name: Sync Files
uses: SamKirkland/FTP-Deploy-Action@v4.4.0
with:
server: ${{ secrets.FTP_SERVER }}
Expand All @@ -68,3 +69,30 @@ jobs:
password: ${{ secrets.FTP_PASSWORD }}
local-dir: ${{ github.workspace }}/docs/
server-dir: ${{ github.ref }}/typedoc/

OpenAPI:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v6
- name: NPM Install
run: npm i
working-directory: ${{ github.workspace }}
- name: Build Spec
run: |
export DOCUMENTED=1
export DOCUMENTED_OUTPUT_FILE=openapi/spec.json
export DOCUMENTED_EXIT_ON_OUTPUT=1
mkdir openapi
npm start
working-directory: ${{ github.workspace }}
- name: Sync Files
uses: SamKirkland/FTP-Deploy-Action@v4.4.0
with:
server: ${{ secrets.FTP_SERVER }}
port: ${{ secrets.FTP_PORT }}
username: ${{ secrets.FTP_USERNAME }}
password: ${{ secrets.FTP_PASSWORD }}
local-dir: ${{ github.workspace }}/openapi/
server-dir: ${{ github.ref }}/openapi/

3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package-lock.json
.env
.vscode/
src/assets/walkingCache.json
/docs/
/docs/
*.log
6 changes: 5 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import express from "express";

import mbus from "./routes/api"
import * as documented from "./routes/documented";

const app = express();

app.use(express.json());
app.use("/mbus/api/v3", mbus);
documented.addRouter(documented.globalContext, app, "/mbus/api/v3", mbus);
app.use("/docs", express.static("docs"));

const PORT = process.env.PORT || 3000;


app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
if (documented.ENABLED) {
documented.outputDocsFor(documented.globalContext);
}
});
109 changes: 49 additions & 60 deletions src/routes/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as journeyService from '../services/journey';
import * as reminderService from '../services/reminder';
import * as graphBuilder from '../services/graphBuilder';
import { startBackgroundJobs } from '../jobs';
import * as documented from "./documented";

/**
* Express router for the MBus API v3.
Expand Down Expand Up @@ -431,7 +432,7 @@ export function getStartupInfo(req: express.Request, res: express.Response) {
res.json({
min_supported_version: "2.0.0",
why_update_message: { title: "Update Needed", subtitle: "You need to update to the latest version for the app to work properly." },
persistant_message: { title: "", subtitle: ""},
persistant_message: { title: "", subtitle: "" },
one_time_message: { title: "", subtitle: "" },
bus_image_version: "1",
});
Expand Down Expand Up @@ -487,22 +488,12 @@ router.get('/get-key-stops', getKeyStops);
// Notifications / Reminders

const SetReminderBody = z.object({ token: z.string(), stpid: z.string(), rtid: z.string(), thresh: z.number() });
/**
* @param req - Express request, expects `SetReminderBody` in the body
* @param res - Express response, error message as string if error occurs
*/
export function setReminder(req: express.Request, res: express.Response) {
const result = SetReminderBody.safeParse(req.body);
if (!result.success) {
res.status(400);
res.send(result.error.message);
} else {
const { token, stpid, rtid, thresh } = result.data;
documented.addPostRoute(
documented.globalContext, router, '/setReminder', { ...documented.emptyFormat, reqBody: SetReminderBody },
(_, __, { token, stpid, rtid, thresh }) => {
const info = reminderService.infoToUseForRoute(rtid);
if (info === null) {
res.status(400);
res.send(`Invalid route ${rtid}`);
return;
return documented.makeFailureResponse(400, `Invalid route ${rtid}`);
}
const { reminderSubscriptions, predsByStopId } = info;
reminderSubscriptions.add(
Expand All @@ -512,11 +503,9 @@ export function setReminder(req: express.Request, res: express.Response) {
predsByStopId,
Date.now(),
);
res.sendStatus(200);
return documented.makeSuccessResponse({});
}

}
router.post('/setReminder', setReminder);
);

const UnsetReminderBody = z.object({ token: z.string(), stpid: z.string(), rtid: z.string() });
/**
Expand All @@ -529,7 +518,7 @@ export function unsetReminder(req: express.Request, res: express.Response) {
res.status(400);
res.send(result.error.message);
} else {
const { token ,stpid, rtid } = result.data;
const { token, stpid, rtid } = result.data;
const info = reminderService.infoToUseForRoute(rtid);
if (info === null) {
res.status(400);
Expand Down Expand Up @@ -567,47 +556,47 @@ export function swapToken(req: express.Request, res: express.Response) {
}
router.post('/swapToken', swapToken);

export interface ActiveReminderInfo {
stpid: string
rtid: string
thresh: number | null
eta: number | null
};
const Token = z.string().meta({ id: "Token" })
const ActiveReminder = z.object({
stpid: z.string(),
rtid: z.string(),
thresh: z.number().nullable(),
eta: z.number().nullable(),
}).meta({ id: "Reminder" });

/**
* @param req - Express request, token is path encoded
* @param res - Express response
*/
export function activeRemindersForToken(
req: express.Request,
res: express.Response<{ reminders: Array<ActiveReminderInfo> }>
) {
const subscriptionInfo = (r: reminderService.PreThreshold | reminderService.PostThreshold):
ActiveReminderInfo =>
documented.addGetRoute(
documented.globalContext, router, '/activeReminders/:token',
{
return {
stpid: r.event.stpid,
rtid: r.event.rtid,
thresh: r.stage === 0 ? r.thresh : null,
eta: r.stage === 0 ? r.candidateVidPredPrev : r.vidPredPrev
params: z.object({ token: Token }),
query: z.object(),
resBody: z.object({ reminders: z.array(ActiveReminder) }),
},
({ token }, _) => {
const regTok = reminderService.registrationToken(token);
const subscriptionInfo = (r: reminderService.PreThreshold | reminderService.PostThreshold) => {
return {
stpid: r.event.stpid,
rtid: r.event.rtid,
thresh: r.stage === 0 ? r.thresh : null,
eta: r.stage === 0 ? r.candidateVidPredPrev : r.vidPredPrev
};
};
};
const token = reminderService.registrationToken(req.params.registrationToken);
console.log(`Got request for active reminders of ${token}`);
res.status(200);
const universityReminders = reminderService
.universityReminderSubscriptions
.activeRemindersFor(token)
.map(subscriptionInfo);
const rideReminders = reminderService
.rideReminderSubscriptions
.activeRemindersFor(token)
.map(subscriptionInfo);
res.send({
reminders: universityReminders.concat(rideReminders)
});
}
router.get('/activeReminders/:registrationToken', activeRemindersForToken);
console.log(`Got request for active reminders of ${token}`);
const universityReminders = reminderService
.universityReminderSubscriptions
.activeRemindersFor(regTok)
.map(subscriptionInfo);
const rideReminders = reminderService
.rideReminderSubscriptions
.activeRemindersFor(regTok)
.map(subscriptionInfo);
return documented.makeSuccessResponse({ reminders: universityReminders.concat(rideReminders) });
},
{
summary: "active reminders",
description: `big long description idk, gets the reminders associated with a **registration token**, which is gotten from fcm or smth`
},
)

const ModifyRemindersBody = z.object({
token: z.string(),
Expand Down Expand Up @@ -645,7 +634,7 @@ export function modifyReminders(req: express.Request, res: express.Response) {
reminderService.registrationToken(token),
predsByStopId,
Date.now()
);
);
} else {
reminderSubscriptions.remove(
event, reminderService.registrationToken(token)
Expand All @@ -670,7 +659,7 @@ export function notifyMeLater(req: express.Request, res: express.Response) {
}
setTimeout(() => {
console.log(`sending test push notification to ${registrationToken}`);
reminderService.sendNotifToAll({ title: "hi", body: "hello world!"}, new Set([registrationToken]));
reminderService.sendNotifToAll({ title: "hi", body: "hello world!" }, new Set([registrationToken]));
}, 0);
res.sendStatus(200);
}
Expand Down
Loading