brian-rud / osu-cs467-citizen-science

A repository for OSU's Computer Science Capstone Course
MIT License
0 stars 1 forks source link

Allow user to add project image thumbnails #12

Open beteivap opened 2 years ago

beteivap commented 2 years ago

When creating a project, the user would have the ability to upload an image to display as the project's thumbnail. Image would be stored and retrieved from a Cloud Storage Bucket (AWS S3).

Montana commented 2 years ago

Images will trigger events and process thumbnails to other buckets that are specified in this code I made, there's also conditionals you can make, I've made notations in this Python script that will trigger an event and process thumbnails as you wanted @beteivap. Remember these are all placeholders and shouldn't be used, this is purely for foundational purposes.

from __future__ import print_function

import boto3

import os
import sys

from PIL import Image
import PIL.Image

BASE_WIDTH = 250
BASE_HEIGHT = 250
s3_client = boto3.client("s3")

def process_image_percent(width, height):
    if width < BASE_WIDTH or height < BASE_HEIGHT:
        return [width, height]
    if width > height:
        width_percent = BASE_WIDTH / float(width)
        resize_height = int((float(height) * float(width_percent)))
        return [BASE_WIDTH, resize_height]
    else:
        height_percent = BASE_HEIGHT / float(height)
        resize_width = int((float(width) * float(height_percent)))
        return [resize_width, BASE_HEIGHT]

def image_thumbnail(image_path, resized_path):

    image = Image.open(image_path)
    resize_img = process_image_percent(image.size[0], image.size[1])

    thumbnail = image.resize((resize_img[0], resize_img[1]), PIL.Image.ANTIALIAS)
    thumbnail.save(resized_path, image.format)

def handler(event, context):
    for record in event["Records"]:
        event_action = record["eventName"]
        method = event_action.split(":")[1]
        bucket = record["s3"]["bucket"]["name"]
        key = record["s3"]["object"]["key"]

        file_name = os.path.basename(key)
        if not file_name.lower().endswith(("png", "jpg", "jpeg")):
            print("Filetype not valid for thumbnail")
            return "Filetype not valid for thumbnail"

        download_path = "/tmp/{}".format(file_name)
        upload_path = "/tmp/resized-{}".format(file_name)

        # Download thumbnails to the /tmp folder

        if method == "Put" or method == "CompleteMultipartUpload":
            print("put thumbnail to s3 bucket")
            s3_client.download_file(bucket, key, download_path)

        # Save the thumbnail image to the upload_path

            image_thumbnail(download_path, upload_path)
            s3_client.upload_file(
                upload_path, "{bucket_name}-thumbnail".format(bucket_name=bucket), key
            )
            return "put thumbnail successfully"

        elif method == "Delete":
            print("delete thumbnail from s3 bucket")
            s3_client.delete_object(
                Bucket="{bucket_name}-thumbnail".format(bucket_name=bucket), Key=key
            )
            return "delete thumbnail successfully"

        else:
            return "receive not match method, nothing to do"

Here's a bash script I made. Make sure you invoke the shebang line in the beginning #!/bin/bash. I've entitled it deploy.sh, and did a quick test and it did exactly what you appealed in your issue Paldin.

#!/bin/bash
rm -r aws-lambda-s3-thumbnail.zip
cd aws-lambda-s3-thumbnail/ || exit

rm -rf venv
virtualenv venv
source venv/bin/activate
pip install -r requirement.txt

zip -9 ../aws-lambda-s3-thumbnail.zip handler.py
cd venv/lib/python2.7/site-packages/ || exit
zip -r9 ../../../../../aws-lambda-s3-thumbnail.zip *
cd ../../../../../

bucket_name="upload-image"

echo '{
    "LambdaFunctionConfigurations": [
        {
            "LambdaFunctionArn": "<lambda_function_arn>",
            "Id": "aws-object-created-id",
                "Events": [
                    "s3:ObjectCreated:*"
                ]
        },
        {
            "LambdaFunctionArn": "<lambda_function_arn>",
            "Id": "aws-object-removed-id",
            "Events": [
                "s3:ObjectRemoved:*"
            ]
        }
    ]
}' > notification.json

serverless deploy
aws lambda add-permission --function-name <lambda_function_arn> --statement-id 1 --action "lambda:InvokeFunction" --principal "s3.amazonaws.com" --source-arn "arn:aws:s3:::${bucket_name}"
aws s3api put-bucket-notification-configuration --bucket ${bucket_name} --notification-configuration file://notification.json
)

These are obvious placeholders, and should be replaced with your own S3 bucket information e.g. $[bucket_name]. Here's a file that also should be present entitled serverless.yml:

service: wSign-thumbnail

provider:
  name: aws
  stage: thumbnail
  region: ap-northeast-1
  profile: myProfile

package:
  artifact: aws-lambda-s3-thumbnail.zip

functions:
  thumbnail:
    handler: handler.handler
    name: thumbnail
    description: thumbnail upload image
    runtime: python2.7
    memorySize: 256
    timeout: 90

Cheers, Montana Mendy