add hardcoded door "onboardingflag" for automated onboarding process
This commit is contained in:
parent
512feb0268
commit
33d7764ca2
10
packages/doorman-api/src/common/TTLHelper.ts
Normal file
10
packages/doorman-api/src/common/TTLHelper.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export function isTTLInFuture(item?: { TTL: number }) {
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ttl is a UTC ms time
|
||||
const ttl = item.TTL || 0;
|
||||
|
||||
return parseInt("" + ttl) > Date.now();
|
||||
}
|
||||
@ -18,8 +18,8 @@ export const InfoRequestSchema = z.object({
|
||||
door: z.string().optional(),
|
||||
buzzer: z.string().optional(),
|
||||
})
|
||||
.partial()
|
||||
.refine(data => data.buzzer || data.door, 'Buzzer or door must be provided');
|
||||
.partial()
|
||||
.refine(data => data.buzzer || data.door, 'Buzzer or door must be provided');
|
||||
|
||||
export type InfoRequest = z.infer<typeof InfoRequestSchema>;
|
||||
export interface InfoRequestTwilio extends ServerlessEventObject<InfoRequest, UserAgentHeader> { };
|
||||
@ -75,7 +75,7 @@ export const handler: ServerlessFunctionSignature<TwilioContext, InfoRequestTwil
|
||||
setResponseJson(response, 200, body);
|
||||
} else {
|
||||
const lock = await db.entities.lockStatus.findById(getLockStatusID(door));
|
||||
const status = isLockOpen(lock) ? DoorStatus.OPEN: DoorStatus.CLOSED;
|
||||
const status = isLockOpen(lock) ? DoorStatus.OPEN : DoorStatus.CLOSED;
|
||||
|
||||
const body: InfoResponseUI = InfoResponseUISchema.parse({
|
||||
...config,
|
||||
@ -83,7 +83,7 @@ export const handler: ServerlessFunctionSignature<TwilioContext, InfoRequestTwil
|
||||
door,
|
||||
status,
|
||||
})
|
||||
|
||||
|
||||
// respond to UI
|
||||
setResponseJson(response, 200, body);
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import { withMetrics } from "../../../common/DoormanHandler";
|
||||
import { z } from "zod";
|
||||
import { setResponseJson } from "../../../utils/responseUtils";
|
||||
import zu from "zod_utilz";
|
||||
import { ONBOARDING_DOOR_NAME } from "../../../schema/DoorConfig";
|
||||
|
||||
export const StatusRequestSchema = z.object({
|
||||
door: z.string(),
|
||||
@ -49,7 +50,10 @@ export const handler: ServerlessFunctionSignature<TwilioContext, StatusRequestTw
|
||||
|
||||
setResponseJson(response, 200, body);
|
||||
|
||||
await db.entities.lockStatus.deleteById(getLockStatusID(door));
|
||||
// this hardcoded door, keep open for timeout
|
||||
if (door !== ONBOARDING_DOOR_NAME) {
|
||||
await db.entities.lockStatus.deleteById(getLockStatusID(door));
|
||||
}
|
||||
} else {
|
||||
const body = StatusResponseSchema.parse({
|
||||
status: DoorStatus.CLOSED,
|
||||
|
||||
@ -2,7 +2,7 @@ import { readdirSync } from "node:fs";
|
||||
import path from "path";
|
||||
|
||||
const paths = [
|
||||
'./src/functions/api/door'
|
||||
'./src/functions/api/door',
|
||||
];
|
||||
|
||||
const functionFiles = paths.map(path => readdirSync(path).map(file => path + "/" + file)).flat();
|
||||
@ -15,7 +15,7 @@ console.log("functions to build:", functionFiles);
|
||||
const bundledModules = ['dynabridge', 'zod_utilz'];
|
||||
|
||||
const externalModules = Object.keys(require('../package.json').dependencies)
|
||||
.filter(dep => !bundledModules.includes(dep));
|
||||
.filter(dep => !bundledModules.includes(dep));
|
||||
|
||||
console.log("Explicitly bundling dependencies", bundledModules);
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { CreateTableCommand, DynamoDBClient, KeyType, PutItemCommand, ScalarAttributeType } from "@aws-sdk/client-dynamodb";
|
||||
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb";
|
||||
import { DoorAlias, DoorAliasEntity, DoorAliasSchema, getDoorAliasID } from "../schema/DoorAlias";
|
||||
import { DoorConfig } from "../schema/DoorConfig";
|
||||
import { DoorConfig, getDoorConfigID, ONBOARDING_DOOR_NAME, ONBOARDING_DOOR_PIN } from "../schema/DoorConfig";
|
||||
|
||||
import DynamoDbLocal from "dynamodb-local";
|
||||
import { sleep } from "bun";
|
||||
@ -76,6 +76,20 @@ const doorConfig: DoorConfig = {
|
||||
greeting: "test door",
|
||||
};
|
||||
|
||||
// for onboarding mode
|
||||
const onboardingDoorConfig: DoorConfig = {
|
||||
PK: "door-" + ONBOARDING_DOOR_NAME,
|
||||
SK: "config",
|
||||
buzzer: "nil",
|
||||
pressKey: "nil",
|
||||
discordUsers: [],
|
||||
fallbackNumbers: [],
|
||||
pin: ONBOARDING_DOOR_PIN,
|
||||
buzzerCode: "nil",
|
||||
timeout: 15 * 60,
|
||||
greeting: "INTERNAL USE - for onboarding new door",
|
||||
};
|
||||
|
||||
try {
|
||||
await document.put({
|
||||
TableName: tableName,
|
||||
@ -86,6 +100,12 @@ try {
|
||||
TableName: tableName,
|
||||
Item: doorAlias,
|
||||
});
|
||||
|
||||
await document.put({
|
||||
TableName: tableName,
|
||||
Item: onboardingDoorConfig,
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
console.error("failed seeding table", e);
|
||||
}
|
||||
|
||||
@ -5,6 +5,9 @@ import { randomUUID } from "crypto";
|
||||
export const DOOR_CONFIG_SK = "config";
|
||||
export const EDIT_DOOR_CONFIG_SK = "config-update";
|
||||
|
||||
export const ONBOARDING_DOOR_NAME = "onboardingflag";
|
||||
export const ONBOARDING_DOOR_PIN = "1234";
|
||||
|
||||
export const DoorConfigSchema = z.object({
|
||||
// keys
|
||||
PK: z.string().startsWith("door-", "Invalid door key"),
|
||||
@ -59,7 +62,7 @@ export const editDoorToDoorConfig = (updateDoor: EditDoorConfig): DoorConfig =>
|
||||
};
|
||||
|
||||
delete newItem.approvalId;
|
||||
|
||||
|
||||
return newItem;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { z } from "zod";
|
||||
import { DynaBridgeEntity } from 'dynabridge';
|
||||
import { isTTLInFuture } from "../common/TTLHelper";
|
||||
|
||||
export const LOCK_STATUS_SK = "lock";
|
||||
|
||||
@ -24,10 +25,7 @@ export const LockStatusEntity: DynaBridgeEntity<LockStatus> = {
|
||||
};
|
||||
|
||||
export const isLockOpen = (lock?: LockStatus) => {
|
||||
// ttl is a UTC ms time for how long it is unlocked
|
||||
const ttl = lock?.TTL || 0;
|
||||
|
||||
return parseInt("" + ttl) > Date.now();
|
||||
return isTTLInFuture(lock);
|
||||
};
|
||||
|
||||
export const createLockStatusWithTimeout = (door: string, timeoutSeconds: number, fingerprint: any): LockStatus => {
|
||||
|
||||
@ -2,6 +2,8 @@ import { describe, test, expect } from "bun:test";
|
||||
import { buzzerUrl, buzzerNumber, baseUrl, doorName, key } from "./testCommon";
|
||||
import { DoorStatus } from "../src/types/DoorStatus";
|
||||
import { InfoResponseUI } from "../src/functions/api/door/info";
|
||||
import { ONBOARDING_DOOR_NAME, ONBOARDING_DOOR_PIN } from "../src/schema/DoorConfig";
|
||||
import { StatusResponse } from "../src/functions/api/door/status";
|
||||
|
||||
if (process.env.STAGE !== 'staging') {
|
||||
process.exit(0);
|
||||
@ -33,3 +35,38 @@ describe("buzzer client works", () => {
|
||||
expect(infoResp.status).toBe(DoorStatus.CLOSED);
|
||||
});
|
||||
});
|
||||
|
||||
// CAVEAT, this door is currently manually created, for the purposes of automated onboarding flow
|
||||
describe("onboardingflag door should exist", () => {
|
||||
test("onboarding door exists", async () => {
|
||||
// door info
|
||||
const authResp = await fetch(baseUrl + `/api/door/info?door=${ONBOARDING_DOOR_NAME}`);
|
||||
expect(authResp.status).toBe(200);
|
||||
|
||||
const door = (await authResp.json()) as InfoResponseUI;
|
||||
expect(door.timeout).toBe(15 * 60);
|
||||
|
||||
// this may be flaky, it would fail when a user is onboarding and we are deploying
|
||||
expect(door.status).toBe(DoorStatus.CLOSED);
|
||||
});
|
||||
|
||||
test("onboarding door does not close after status check", async () => {
|
||||
let authResp = await fetch(baseUrl + `/api/door/auth?door=${ONBOARDING_DOOR_NAME}&key=${ONBOARDING_DOOR_PIN}`);
|
||||
expect(authResp.status).toBe(200);
|
||||
|
||||
let statusResp = await fetch(baseUrl + `/api/door/status?door=${ONBOARDING_DOOR_NAME}`).then(res => res.json()) as StatusResponse;
|
||||
expect(statusResp.status).toBe(DoorStatus.OPEN);
|
||||
|
||||
// open again
|
||||
statusResp = await fetch(baseUrl + `/api/door/status?door=${ONBOARDING_DOOR_NAME}`).then(res => res.json()) as StatusResponse;
|
||||
expect(statusResp.status).toBe(DoorStatus.OPEN);
|
||||
|
||||
// close it
|
||||
authResp = await fetch(baseUrl + `/api/door/auth?door=${ONBOARDING_DOOR_NAME}&key=${ONBOARDING_DOOR_PIN}`);
|
||||
expect(authResp.status).toBe(200);
|
||||
|
||||
// door should now be closed
|
||||
const infoResp = await fetch(baseUrl + `/api/door/info?door=${ONBOARDING_DOOR_NAME}`).then(res => res.json()) as InfoResponseUI;
|
||||
expect(infoResp.status).toBe(DoorStatus.CLOSED);
|
||||
})
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user