Skip to content

Commit

Permalink
Merge pull request #9 from QuanticSchool/working
Browse files Browse the repository at this point in the history
Final client and gateway versions
  • Loading branch information
John-J-Riehl authored Jun 10, 2022
2 parents de83bcf + 91213db commit 448f33d
Show file tree
Hide file tree
Showing 20 changed files with 373 additions and 74 deletions.
1 change: 0 additions & 1 deletion api-gateway/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
/api-gateway-env
application.zip
1 change: 1 addition & 0 deletions api-gateway/.platform/nginx/conf.d/proxy.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
client_max_body_size 10M;
12 changes: 2 additions & 10 deletions api-gateway/apis.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,10 @@
"api_type": "HTTP",
"Access-Control-Allow-Origin": ["*"],
"integrations": [
{"type": "lambda", "region": "us-east-1", "function": "im-health-check"},
{"type": "lambda", "region": "us-east-1", "function": "im-post-meme"},
{"type": "lambda", "region": "us-east-1", "function": "im-get-thumbnails"},
{"type": "lambda", "region": "us-east-1", "function": "im-get-meme"},
{"type": "lambda", "region": "us-east-1", "function": "im-put-like"}
{"type": "lambda", "region": "us-east-1", "function": "im-health-check"}
],
"routes": [
{"method": "GET", "path": "/health-check", "integration_target": "im-health-check"},
{"method": "POST", "path": "/", "integration_target": "im-post-meme"},
{"method": "GET", "path": "/thumbnails", "integration_target": "im-get-thumbnails"},
{"method": "GET", "path": "/{id}", "integration_target": "im-get-meme"},
{"method": "PUT", "path": "/{id}", "integration_target": "im-put-like"}
{"method": "GET", "path": "/health-check", "integration_target": "im-health-check"}
]
}
]
6 changes: 3 additions & 3 deletions api-gateway/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ def __call__(self, **path_params):
Payload=json.dumps(payload)
)

# now send the response. note that flask_cors does not include
# CORS headers on responses without bodies.
return lambda_response["Payload"].read(), lambda_response["StatusCode"]
# now send the response.
response_payload = json.loads(lambda_response["Payload"].read())
return response_payload["body"], response_payload["statusCode"]

# code to test the gateway and client locally follows
#if self.function == "im-get-thumbnails":
Expand Down
Binary file removed api-gateway/application.zip
Binary file not shown.
1 change: 1 addition & 0 deletions back-end/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/python
14 changes: 14 additions & 0 deletions back-end/delete_meme.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import json
import boto3

def lambda_handler(event, context):
# event should be as follows: { "memeId": <string> }

# delete the appropriate DynamoDB records from im-memes and im-likes

# delete the meme and thumbnail files

return {
'statusCode': 200,
'body': json.dumps("")
}
51 changes: 51 additions & 0 deletions back-end/get_meme.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import json
import boto3
import base64
import io
import time
from PIL import Image

def lambda_handler(event, context):
# the meme id is in path parameters
meme_id =

# get entry from the database
dynamodb =
memes_table =

db_entry = memes_table.

try:
entry =
except :
# return an error code if the meme's not in the database

# now get the meme from S3
s3 =
bucket =
meme =

# test to see if the meme file exists

# create an in memory file and download the image data into it
in_mem_file = io.BytesIO()
meme.

# load the meme as an image to get its type
image = Image.open(in_mem_file)

# get the list of likes for this meme
likes_table =
db_likes = likes_table.

# extract the user names into a list
likes = [item["userName"] for item in db_likes["Items"]]

# return success code and the meme
return {
"statusCode": 200,
"body": json.dumps({
"imageUrl": (f"data:image/{image.format};base64,"
+ base64.b64encode(in_mem_file.getvalue()).decode("utf-8")),
})
}
53 changes: 53 additions & 0 deletions back-end/get_thumbnails.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import json
import boto3
import base64
import io
import time

def lambda_handler(event, context):
# get a Lambda client for the im-delete-meme function

# get the S3 bucket
s3 =
bucket =

# get entries from the database
dynamodb =
table =
db_memes =
memes =

# build the response for each entry. id, userName, and timePosted
# simply pass through. we compute timeToLive from timeToDie and
# generate the data URL using PIL and base64
time_now = int(time.time())
thumbnails = []

for meme in memes:
thumbnail = dict()

# get the thumbnail image from S3
thumbnail_image = bucket.Object(f"thumbnails/{meme['id']}")

# skip this thumbnail if the image isn't present or it's past its
# time to die

# load the image into an in-memory file object
in_mem_file = io.BytesIO()
thumbnail_image.

# now write the image into the thumbnail as a base64 data URL
# base 64 conversion code courtesy of https://stackoverflow.com/a/68989496/4062628
thumbnail["imageUrl"] = (
"data:image/jpeg;base64,"
+ base64.b64encode(in_mem_file.getvalue()).decode("utf-8"))
in_mem_file.close()

# build the thumnail's metadata
thumbnail["timeToLive"] =
thumbnail["timePosted"] =
thumbnail["userName"] =
thumbnail["id"] =
thumbnails.append(thumbnail)

# return the thumbnails
7 changes: 7 additions & 0 deletions back-end/health_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import json

def lambda_handler(event, context):
return {
"statusCode": 200,
"body": json.dumps("All your meme are belong to us.")
}
71 changes: 71 additions & 0 deletions back-end/post_meme.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import json
import uuid
import time
import base64
import io
from PIL import Image

# need to import one more library here

def lambda_handler(event, context):
# get the meme data from the event body
meme_data =

# the data URL format is "data:image/<format>;base64,<data>" so we split
# the data from the header, then the extension from the header
header, data = meme_data["image"].split(";base64,")
extension = header.split("image/")[-1]

if extension not in ("bmp", "gif", "jpeg", "png", "tiff"):
# return a status code 400 error

# use Pillow (https://pillow.readthedocs.io/en/stable/index.html)
# to load the image and save it and its thumbnail in S3. the file's
# name will be its ID, which we generate as a random UUID
id = uuid.uuid4().hex

# base 64 conversion code courtesy of https://stackoverflow.com/a/68989496/4062628
# save PIL image to S3 courtesy of https://stackoverflow.com/a/56241877/4062628

# get the PIL image from the base64 data, then save it in an in-memory
# file-like object
image = Image.open(io.BytesIO(base64.decodebytes(bytes(data, "utf-8"))))
in_mem_file = io.BytesIO()
image.save(in_mem_file, format=image.format)
in_mem_file.seek(0)

# now write it to the S3 bucket
s3 =
bucket =
bucket.

# make a thumbnail and repeat the process above
image.thumbnail((200, 200))
in_mem_file = io.BytesIO()

# JPG doesn't support an alpha channel, so we need to remove it
# if it exists. conversion courtesy of
# https://stackoverflow.com/a/49255449/4062628
if image.mode in ("RGBA", "P"):
image = image.convert("RGB")

image.save(in_mem_file, format="jpeg")
in_mem_file.seek(0)
bucket.

# write the entry to the database
posted = int(time.time()) # current epoch time in seconds
timeToDie = posted + 24 * 60 * 60
db_entry = {
"id": id,
"userName": meme_data["userName"],
"timePosted": posted,
"timeToDie": timeToDie
}

dynamodb =
table =
table.

# return success code and id of the meme

16 changes: 16 additions & 0 deletions back-end/put_like.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import json
import boto3
import time

def lambda_handler(event, context):
# get the meme_id, event_body, and user_name

# verify the meme is in the database

# find out whether this user has liked this meme already

# add the like to im-likes

# add to the item's timeToDie

# return success
2 changes: 1 addition & 1 deletion client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/coverage

# production
#/build
/build

# misc
.DS_Store
Expand Down
12 changes: 6 additions & 6 deletions client/build/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"files": {
"main.css": "/static/css/main.80c75857.css",
"main.js": "/static/js/main.bf0fb87e.js",
"main.css": "/static/css/main.fd848717.css",
"main.js": "/static/js/main.92eed466.js",
"index.html": "/index.html",
"main.80c75857.css.map": "/static/css/main.80c75857.css.map",
"main.bf0fb87e.js.map": "/static/js/main.bf0fb87e.js.map"
"main.fd848717.css.map": "/static/css/main.fd848717.css.map",
"main.92eed466.js.map": "/static/js/main.92eed466.js.map"
},
"entrypoints": [
"static/css/main.80c75857.css",
"static/js/main.bf0fb87e.js"
"static/css/main.fd848717.css",
"static/js/main.92eed466.js"
]
}
2 changes: 1 addition & 1 deletion client/build/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="A web app to find memes that will live in immortality."/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/manifest.json"/><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"><title>Immortal Memes!</title><script defer="defer" src="/static/js/main.bf0fb87e.js"></script><link href="/static/css/main.80c75857.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="A web app to find memes that will live in immortality."/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/manifest.json"/><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"><title>Immortal Memes!</title><script defer="defer" src="/static/js/main.92eed466.js"></script><link href="/static/css/main.fd848717.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
2 changes: 0 additions & 2 deletions client/build/static/css/main.80c75857.css

This file was deleted.

1 change: 0 additions & 1 deletion client/build/static/css/main.80c75857.css.map

This file was deleted.

Loading

0 comments on commit 448f33d

Please sign in to comment.