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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ node_modules
# CDK asset staging directory
.cdk.staging
cdk.out
.DS_Store
26 changes: 26 additions & 0 deletions lambdas/feedback/getUploadImageSignedUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Lambda that returns a signed URL for uploading an image to S3.
* The frontend will use this URL to upload the image directly to S3.
* and store it with the feedback form data.
*/

import { APIGatewayProxyHandler, APIGatewayProxyEvent } from "aws-lambda";
import { S3 } from "aws-sdk";
import * as uuid from "uuid";

export const handler: APIGatewayProxyHandler = async (
event: APIGatewayProxyEvent
) => {
const s3 = new S3();
const params = {
Bucket: process.env.BUCKET_NAME!,
Key: `${uuid.v4()}.jpeg`,
ContentType: "image/jpeg",
};
Comment on lines +16 to +18

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we confirmed about the file type will be always jpeg?


const url = await s3.getSignedUrlPromise("putObject", params);

return {
statusCode: 200,
body: JSON.stringify({ url }),
};
};
13 changes: 12 additions & 1 deletion lib/cdk-ishihara.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { getLambdaSimpleApi } from "./resources/lambda-api-get-plates";
import {
getLambdaApiSaveFeedback,
getFeedbackTable,
getUploadImageLambda,
getFeedbackImageBucket,
} from "./resources/save-feedback-resources";
import { createAPIGateway } from "./resources/api-gateway-get-plates";
import { createFeedbackGatewayApi } from "./resources/api-gateway-feedback";
Expand All @@ -31,12 +33,21 @@ export class CdkIshiharaStack extends Stack {

//--- Fedback resources -----
const feedbackTable = getFeedbackTable(this);
const feedbackImageBucket = getFeedbackImageBucket(this);
// Lambda used to generate signed url to upload image to s3
const feedbackImageUploadUrlLambda = getUploadImageLambda(this, {
environment: {
BUCKET_NAME: feedbackImageBucket.bucketName,
},
});

const feedbackLambda = getLambdaApiSaveFeedback(this, {
environment: { TABLE_NAME: feedbackTable.tableName },
});

feedbackTable.grantReadWriteData(feedbackLambda);

feedbackImageBucket.grantReadWrite(feedbackImageUploadUrlLambda);
//--- End feedback resources -----
configureEventBridgeCron(this, plateGenerator);

const hostedZone = getHostedZone(this);
Expand Down
35 changes: 27 additions & 8 deletions lib/resources/save-feedback-resources.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
/* create cdk resources for feedback feature (lambda and dynamodb table) */

import { Table, TableProps } from "aws-cdk-lib/aws-dynamodb";
import {
Function,
FunctionProps,
Runtime,
Code,
} from "aws-cdk-lib/aws-lambda";
import { Function, FunctionProps, Runtime, Code } from "aws-cdk-lib/aws-lambda";
import { Construct } from "constructs";
import { getNamespace } from "../util";
import { AttributeType } from "aws-cdk-lib/aws-dynamodb";

import { Bucket, BucketAccessControl, HttpMethods } from "aws-cdk-lib/aws-s3";


export function getFeedbackTable(scope: Construct, props?: TableProps): Table {
return new Table(scope, `FeedbackTable${getNamespace()}`, {
partitionKey: {
Expand All @@ -26,7 +20,7 @@ export function getFeedbackTable(scope: Construct, props?: TableProps): Table {

export function getLambdaApiSaveFeedback(
scope: Construct,
//optional
//optional
props?: Partial<FunctionProps>
): Function {
return new Function(scope, `LambdaApiSaveFeedback${getNamespace()}`, {
Expand All @@ -36,3 +30,28 @@ export function getLambdaApiSaveFeedback(
...props,
});
}

export function getUploadImageLambda(
scope: Construct,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any test coverage?

props?: Partial<FunctionProps>
): Function {
return new Function(scope, `LambdaUploadImage${getNamespace()}`, {
runtime: Runtime.NODEJS_14_X,
handler: "uploadImage.handler",
code: Code.fromAsset("lambdas/getUploadImageSignedUrl"),
...props,
});
}

export function getFeedbackImageBucket(scope: Construct): Bucket {
return new Bucket(scope, `FeedbackImageBucket${getNamespace()}`, {
accessControl: BucketAccessControl.PRIVATE,
cors: [
{
allowedOrigins: ["*"],
allowedMethods: [HttpMethods.GET, HttpMethods.PUT, HttpMethods.HEAD],
},
],
bucketName: `feedback-image-${getNamespace()}`,
});
}