Skip to content

Commit e6c780d

Browse files
committed
added GH Action for docker
1 parent b782011 commit e6c780d

11 files changed

Lines changed: 194 additions & 18 deletions

File tree

.DS_Store

6 KB
Binary file not shown.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: Publish Docker image to Docker Hub
2+
on:
3+
[workflow_dispatch:]
4+
5+
jobs:
6+
publish_images:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Checkout
10+
uses: actions/checkout@v4
11+
- name: Build image
12+
run: docker build ./api/ -t echelonkay/devops-qr-code-api:latest
13+
- name: push image to docker hub
14+
run: |
15+
docker push echelonkay/devops-qr-code-api:latest

README.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,36 @@ It generates QR Codes for the provided URL, the front-end is in NextJS and the A
1616
The API code exists in the `api` directory. You can run the API server locally:
1717

1818
- Clone this repo
19+
- Create a AWS User with AmazonS3FullAccess
20+
- Create a S3 Bucket and select ACL enable for public access, Uncheck block bucket.
1921
- Make sure you are in the `api` directory
20-
- Create a virtualenv by typing in the following command: `python -m venv .venv`
21-
- Install the required packages: `pip install -r requirements.txt`
22+
- Create a virtualenv by typing in the following command: `python3 -m venv .venv`
23+
- Run command `source .venv/bin`
24+
- Run command `source .venv/bin/activate`
25+
- Install the required packages: `pip install -r requirements.txt` 'or pip install fastapi uvicorn boto3 python-dotenv pytest qrcode'
2226
- Create a `.env` file, and add you AWS Access and Secret key, check `.env.example`
27+
- and Save the Access & secret key, cat the `.env` to verify.
2328
- Also, change the BUCKET_NAME to your S3 bucket name in `main.py`
2429
- Run the API server: `uvicorn main:app --reload`
2530
- Your API Server should be running on port `http://localhost:8000`
2631

32+
### optional- Troubleshoting S3 bucket
33+
### you might add Bucket policy
34+
35+
{
36+
"Version": "2012-10-17",
37+
"Statement": [
38+
{
39+
"Sid": "PublicReadGetObject",
40+
"Effect": "Allow",
41+
"Principal": "*",
42+
"Action": "s3:GetObject",
43+
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*" # Add bucket name
44+
}
45+
]
46+
}
47+
48+
2749
### Front-end
2850

2951
The front-end code exits in the `front-end-nextjs` directory. You can run the front-end server locally:

api/*

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from fastapi import FastAPI, HTTPException
2+
from fastapi.middleware.cors import CORSMiddleware
3+
import qrcode
4+
import boto3
5+
import os
6+
from io import BytesIO
7+
8+
# Loading Environment variable (AWS Access Key and Secret Key)
9+
from dotenv import load_dotenv
10+
load_dotenv()
11+
12+
app = FastAPI()
13+
14+
# Allowing CORS for local testing
15+
origins = [
16+
"http://localhost:3000"
17+
]
18+
19+
app.add_middleware(
20+
CORSMiddleware,
21+
allow_origins=origins,
22+
allow_methods=["*"],
23+
allow_headers=["*"],
24+
)
25+
26+
# AWS S3 Configuration
27+
s3 = boto3.client(
28+
's3',
29+
aws_access_key_id= os.getenv("AWS_ACCESS_KEY"),
30+
aws_secret_access_key= os.getenv("AWS_SECRET_KEY"))
31+
32+
bucket_name = 'capstone-qr-code-bucket' # Add your bucket name here
33+
34+
@app.post("/generate-qr/")
35+
async def generate_qr(url: str):
36+
# Generate QR Code
37+
qr = qrcode.QRCode(
38+
version=1,
39+
error_correction=qrcode.constants.ERROR_CORRECT_L,
40+
box_size=10,
41+
border=4,
42+
)
43+
qr.add_data(url)
44+
qr.make(fit=True)
45+
46+
img = qr.make_image(fill_color="black", back_color="white")
47+
48+
# Save QR Code to BytesIO object
49+
img_byte_arr = BytesIO()
50+
img.save(img_byte_arr, format='PNG')
51+
img_byte_arr.seek(0)
52+
53+
# Generate file name for S3
54+
file_name = f"qr_codes/{url.split('//')[-1]}.png"
55+
56+
try:
57+
# Upload to S3
58+
s3.put_object(Bucket=bucket_name, Key=file_name, Body=img_byte_arr, ContentType='image/png', ACL='public-read')
59+
60+
# Generate the S3 URL
61+
s3_url = f"https://{bucket_name}.s3.amazonaws.com/{file_name}"
62+
return {"qr_code_url": s3_url}
63+
except Exception as e:
64+
raise HTTPException(status_code=500, detail=str(e))
65+

api/.DS_Store

6 KB
Binary file not shown.

api/.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
AWS_ACCESS_KEY=Your-AWS-Access-Key
2-
AWS_SECRET_KEY=Your-AWS-Secret-Access-Key
1+
#AWS_ACCESS_KEY=Your-AWS-Access-Key
2+
#AWS_SECRET_KEY=Your-AWS-Secret-Access-Key

api/Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Use the official image as a parent image
2+
FROM python:3.9
3+
4+
# Set the working directory in the container
5+
WORKDIR /urs/src/app
6+
7+
# Copy the dependencies file to the working directory
8+
COPY requirements.txt ./
9+
10+
# Install any needed packages specified in requirements.txt
11+
RUN pip install --no-cache-dir -r requirements.txt
12+
13+
# Copy the content of the local src directory to the working directory
14+
COPY . .
15+
16+
# Run the application
17+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

api/main.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
import boto3
55
import os
66
from io import BytesIO
7-
8-
# Loading Environment variable (AWS Access Key and Secret Key)
97
from dotenv import load_dotenv
8+
9+
# Load environment variables (AWS Access Key and Secret Key)
1010
load_dotenv()
1111

1212
app = FastAPI()
1313

1414
# Allowing CORS for local testing
1515
origins = [
16-
"http://localhost:3000"
16+
"http://localhost:3000" # Update with your frontend URL if needed
1717
]
1818

1919
app.add_middleware(
@@ -26,10 +26,11 @@
2626
# AWS S3 Configuration
2727
s3 = boto3.client(
2828
's3',
29-
aws_access_key_id= os.getenv("AWS_ACCESS_KEY"),
30-
aws_secret_access_key= os.getenv("AWS_SECRET_KEY"))
29+
aws_access_key_id=os.getenv("AWS_ACCESS_KEY"),
30+
aws_secret_access_key=os.getenv("AWS_SECRET_KEY")
31+
)
3132

32-
bucket_name = 'YOUR_BUCKET_NAME' # Add your bucket name here
33+
bucket_name = 'capstone-qr-code-bucket' # Replace with your S3 bucket name
3334

3435
@app.post("/generate-qr/")
3536
async def generate_qr(url: str):
@@ -54,12 +55,18 @@ async def generate_qr(url: str):
5455
file_name = f"qr_codes/{url.split('//')[-1]}.png"
5556

5657
try:
57-
# Upload to S3
58-
s3.put_object(Bucket=bucket_name, Key=file_name, Body=img_byte_arr, ContentType='image/png', ACL='public-read')
58+
# Upload to S3 (removed ACL='public-read' as it caused the error)
59+
s3.put_object(
60+
Bucket=bucket_name,
61+
Key=file_name,
62+
Body=img_byte_arr,
63+
ContentType='image/png'
64+
)
5965

6066
# Generate the S3 URL
6167
s3_url = f"https://{bucket_name}.s3.amazonaws.com/{file_name}"
6268
return {"qr_code_url": s3_url}
69+
6370
except Exception as e:
64-
raise HTTPException(status_code=500, detail=str(e))
65-
71+
# Log error and raise HTTPException
72+
raise HTTPException(status_code=500, detail=f"Error generating QR code: {str(e)}")

api/test_main.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
client = TestClient(app)
55

66
def test_generate_qr():
7-
url = "http://example.com"
7+
url = "https://example.com" # Use a valid URL here
88
response = client.post("/generate-qr/", json={"url": url})
9-
9+
10+
# Check that the response status code is 200 (OK)
1011
assert response.status_code == 200
12+
13+
# Check that the response contains the 'qr_code_url' field
1114
assert "qr_code_url" in response.json()
1215

1316
def test_generate_qr_invalid_url():
14-
url = "invalid-url"
17+
url = "invalid-url" # Invalid URL
1518
response = client.post("/generate-qr/", json={"url": url})
1619

17-
assert response.status_code == 422 # FastAPI validation error
20+
# FastAPI validation should return status 422 for invalid input
21+
assert response.status_code == 422

front-end-nextjs/Dockerfile

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Use the official lightweight Node.js 18 image
2+
FROM node:18-alpine AS base
3+
4+
# Set the working directory in the container
5+
WORKDIR /app
6+
7+
# Copy the package files
8+
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
9+
10+
# Copy the install-dependencies.sh script
11+
COPY install-dependencies.sh ./
12+
13+
# Install dependencies using the script
14+
RUN ./install-dependencies.sh
15+
16+
# Copy the rest of the application code
17+
COPY . .
18+
19+
# Expose the application port
20+
EXPOSE 3000
21+
22+
# Start the application
23+
CMD ["npm", "start"]
24+
25+
# Build the Next.js app
26+
RUN npm run build
27+
28+
# Expose the build folder
29+
COPY .next ./.next

0 commit comments

Comments
 (0)