Skip to content

Commit

Permalink
call out to Octopus Imaging API from database-bridge-lambda in `cre…
Browse files Browse the repository at this point in the history
…ateItem` mutation if the `type` is `imaging-request`
  • Loading branch information
twrichards committed May 24, 2024
1 parent 0d7dd60 commit b6d17a8
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 16 deletions.
86 changes: 86 additions & 0 deletions cdk/lib/__snapshots__/stack.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4007,6 +4007,39 @@ $util.toJson($ctx.result)",
"Endpoint",
],
},
"OCTOPUS_API_LAMBDA_FUNCTION_NAME": Object {
"Fn::Select": Array [
6,
Object {
"Fn::Split": Array [
":",
Object {
"Fn::Join": Array [
"",
Array [
"arn:",
Object {
"Ref": "AWS::Partition",
},
":lambda:",
Object {
"Ref": "AWS::Region",
},
":",
Object {
"Ref": "AWS::AccountId",
},
":function:",
Object {
"Fn::ImportValue": "octopus-api-TEST-function-name",
},
],
],
},
],
},
],
},
"STACK": "workflow",
"STAGE": "TEST",
},
Expand Down Expand Up @@ -4166,6 +4199,59 @@ $util.toJson($ctx.result)",
],
},
},
Object {
"Action": "lambda:InvokeFunction",
"Effect": "Allow",
"Resource": Array [
Object {
"Fn::Join": Array [
"",
Array [
"arn:",
Object {
"Ref": "AWS::Partition",
},
":lambda:",
Object {
"Ref": "AWS::Region",
},
":",
Object {
"Ref": "AWS::AccountId",
},
":function:",
Object {
"Fn::ImportValue": "octopus-api-TEST-function-name",
},
],
],
},
Object {
"Fn::Join": Array [
"",
Array [
"arn:",
Object {
"Ref": "AWS::Partition",
},
":lambda:",
Object {
"Ref": "AWS::Region",
},
":",
Object {
"Ref": "AWS::AccountId",
},
":function:",
Object {
"Fn::ImportValue": "octopus-api-TEST-function-name",
},
":*",
],
],
},
],
},
],
"Version": "2012-10-17",
},
Expand Down
9 changes: 9 additions & 0 deletions cdk/lib/stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,12 @@ export class PinBoardStack extends GuStack {
`Allow ${databaseSecurityGroupName} to connect to the ${databaseProxy.dbProxyName}`
);

const octopusApiLambda = lambda.Function.fromFunctionName(
this,
"OctopusApiLambda",
Fn.importValue(`octopus-api-${this.stage}-function-name`)
);

const pinboardDatabaseBridgeLambda = new lambda.Function(
this,
DATABASE_BRIDGE_LAMBDA_BASENAME,
Expand All @@ -290,6 +296,8 @@ export class PinBoardStack extends GuStack {
STACK: this.stack,
APP,
[ENVIRONMENT_VARIABLE_KEYS.databaseHostname]: databaseHostname,
[ENVIRONMENT_VARIABLE_KEYS.octopusApiLambdaFunctionName]:
octopusApiLambda.functionName,
},
functionName: getDatabaseBridgeLambdaFunctionName(this.stage as Stage),
code: lambda.Code.fromBucket(
Expand All @@ -302,6 +310,7 @@ export class PinBoardStack extends GuStack {
}
);
databaseProxy.grantConnect(pinboardDatabaseBridgeLambda);
octopusApiLambda.grantInvoke(pinboardDatabaseBridgeLambda);

const databaseJumpHostASGName = getDatabaseJumpHostAsgName(
this.stage as Stage
Expand Down
2 changes: 1 addition & 1 deletion client/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
gqlSetWebPushSubscriptionForUser,
} from "../gql";
import { Item, MyUser, User } from "shared/graphql/graphql";
import { ItemWithParsedPayload } from "./types/ItemWithParsedPayload";
import { ItemWithParsedPayload } from "shared/types/ItemWithParsedPayload";
import { HiddenIFrameForServiceWorker } from "./pushNotificationPreferences";
import { GlobalStateProvider } from "./globalState";
import { Floaty } from "./floaty";
Expand Down
3 changes: 1 addition & 2 deletions client/src/itemInputBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,7 @@ export const ItemInputBox = ({
payloadToBeSent?.type === IMAGING_REQUEST_ITEM_TYPE
? message
: message?.trim() || payloadToBeSent;
if (!isAsGridPayloadLoading && hasSomethingToSend
) {
if (!isAsGridPayloadLoading && hasSomethingToSend) {
sendItem();
}
event.preventDefault();
Expand Down
6 changes: 3 additions & 3 deletions client/src/push-notifications/serviceWorker.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { ItemWithParsedPayload } from "../types/ItemWithParsedPayload";
import { ItemWithParsedPayload } from "shared/types/ItemWithParsedPayload";
import {
EXPAND_PINBOARD_QUERY_PARAM,
OPEN_PINBOARD_QUERY_PARAM,
PINBOARD_ITEM_ID_QUERY_PARAM,
} from "../../../shared/constants";
import { extractNameFromEmail } from "../../../shared/util";
} from "shared/constants";
import { extractNameFromEmail } from "shared/util";

const toolsDomain = self.location.hostname.replace("pinboard.", "");

Expand Down
5 changes: 0 additions & 5 deletions client/src/types/ItemWithParsedPayload.ts

This file was deleted.

1 change: 1 addition & 0 deletions database-bridge-lambda/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"watch": "ts-node-dev --respawn run.ts"
},
"devDependencies": {
"@aws-sdk/client-lambda": "^3.299.0",
"ts-node-dev": "^1.0.0"
},
"dependencies": {
Expand Down
47 changes: 47 additions & 0 deletions database-bridge-lambda/src/imagingRequestCallout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { getEnvironmentVariableOrThrow } from "shared/environmentVariables";
import { ItemWithParsedPayload } from "shared/types/ItemWithParsedPayload";
import { InvokeCommand, LambdaClient, LogType } from "@aws-sdk/client-lambda";
import { standardAwsConfig } from "shared/awsIntegration";

const lambda = new LambdaClient(standardAwsConfig);
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();

export const performImagingRequest = async (item: ItemWithParsedPayload) => {
const gridId = (item.payload?.embeddableUrl as string)?.split("/").pop();
if (!gridId) {
throw new Error(`Couldn't extract grid ID from payload: ${item.payload}`);
}
const imagingRequestBody = {
workflowId: item.pinboardId,
pinboardItemId: item.id,
lastUser: item.userEmail,
notes: item.message, //TODO check for 256 max (probably limit in UI too)
requestType: item.payload?.requestType, // TODO tighten this up
gridId,
// composerId: TODO lookup somehow
// pubDate TODO scheduled launch vs some date field in workflow - what's worse wrong date or no date?
// section TODO lookup somehow
// story group name TODO (synced from InCopy most likely, if available)
};
console.log("Performing imaging request", imagingRequestBody);

const octopusLambdaFunctionName = getEnvironmentVariableOrThrow(
"octopusApiLambdaFunctionName"
);

const octopusResponse = await lambda.send(
new InvokeCommand({
FunctionName: octopusLambdaFunctionName,
Payload: textEncoder.encode(JSON.stringify(imagingRequestBody)),
LogType: LogType.None, //TODO consider whether we tail the octopus logs as pinboard logs
})
);

console.log(
"Imaging request complete",
JSON.parse(textDecoder.decode(octopusResponse.Payload))
);

// FIXME return something from octopusResponse.Payload
};
23 changes: 18 additions & 5 deletions database-bridge-lambda/src/sql/Item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import {
EditItemInput,
Item,
PinboardIdWithClaimCounts,
} from "../../../shared/graphql/graphql";
import { Sql } from "../../../shared/database/types";
import { Range } from "../../../shared/types/grafanaType";
} from "shared/graphql/graphql";
import { Sql } from "shared/database/types";
import { Range } from "shared/types/grafanaType";
import { performImagingRequest } from "../imagingRequestCallout";
import { IMAGING_REQUEST_ITEM_TYPE } from "shared/octopusImaging";
import { ItemWithParsedPayload } from "shared/types/ItemWithParsedPayload";

const fragmentIndividualMentionsToMentionHandles = (
sql: Sql,
Expand Down Expand Up @@ -59,10 +62,20 @@ export const createItem = async (
args: { input: CreateItemInput },
userEmail: string
) =>
sql`
sql.begin(async (sql) => {
const insertResult = (await sql`
INSERT INTO "Item" ${sql({ userEmail, ...args.input })}
RETURNING ${fragmentItemFields(sql, userEmail)}
`.then((rows) => rows[0]);
`.then((rows) => rows[0])) as ItemWithParsedPayload;
if (
insertResult.type === IMAGING_REQUEST_ITEM_TYPE &&
insertResult.payload
) {
// if this throws, the SQL transaction should be rolled back
await performImagingRequest(insertResult); //TODO return/store octopus ID
}
return insertResult;
});

export const editItem = async (
sql: Sql,
Expand Down
1 change: 1 addition & 0 deletions shared/environmentVariables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const ENVIRONMENT_VARIABLE_KEYS = {
graphqlEndpoint: "GRAPHQL_ENDPOINT",
sentryDSN: "SENTRY_DSN",
databaseHostname: "DATABASE_HOSTNAME",
octopusApiLambdaFunctionName: "OCTOPUS_API_LAMBDA_FUNCTION_NAME",
};

export const getEnvironmentVariableOrThrow = (
Expand Down
5 changes: 5 additions & 0 deletions shared/types/ItemWithParsedPayload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Item } from "../graphql/graphql";

export type ItemWithParsedPayload = Omit<Item, "payload"> & {
payload: Record<string, unknown> | null | undefined;
};
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9189,6 +9189,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "database-bridge-lambda@workspace:database-bridge-lambda"
dependencies:
"@aws-sdk/client-lambda": "npm:^3.299.0"
postgres: "npm:^3.2.4"
ts-node-dev: "npm:^1.0.0"
languageName: unknown
Expand Down

0 comments on commit b6d17a8

Please sign in to comment.