MukeshKapoor25 commited on
Commit
6fc0261
·
1 Parent(s): 2d94b24
.env CHANGED
@@ -1,6 +1,10 @@
1
  WASABI_BUCKET=bloom-associates
2
- AWS_ACCESS_KEY_ID=bloom-backend-user
3
- AWS_SECRET_ACCESS_KEY=DPSE24FU9UCACAXMYSFO
4
  REGION_NAME=ap-southeast-1
5
- ENDPOINT_URL=https://s3.us-east-1.wasabisys.com
 
 
 
 
6
 
 
1
  WASABI_BUCKET=bloom-associates
2
+ AWS_ACCESS_KEY_ID=DPSE24FU9UCACAXMYSFO
3
+ AWS_SECRET_ACCESS_KEY=l4JymOwzqTB6DozzWyrXw62ah0zD6BznCj9Lp3Lf
4
  REGION_NAME=ap-southeast-1
5
+ ENDPOINT_URL=https://s3.ap-southeast-1.wasabisys.com
6
+ SECRET_KEY=6a2b3c4d5e6f7g8h9i0j
7
+
8
+
9
+
10
 
app/api/v1/__pycache__/auth_routes.cpython-313.pyc ADDED
Binary file (1.55 kB). View file
 
app/api/v1/auth_routes.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, HTTPException, status, Depends, Form
2
+ from jose import jwt
3
+ from datetime import datetime, timedelta
4
+ from settings import SECRET_KEY, ALGORITHM
5
+
6
+ router = APIRouter(prefix="/auth", tags=["Authentication"])
7
+
8
+ # Hardcoded test user
9
+ USERS_DB = {
10
+ "admin@example.com": {
11
+ "password": "admin123",
12
+ "merchant_id": "MERCHANT001",
13
+ "user_id": "admin"
14
+ }
15
+ }
16
+
17
+ @router.post("/login")
18
+ def login(username: str = Form(...), password: str = Form(...)):
19
+ user = USERS_DB.get(username)
20
+ if not user or user["password"] != password:
21
+ raise HTTPException(status_code=401, detail="Invalid credentials")
22
+
23
+ token_data = {
24
+ "sub": user["user_id"],
25
+ "merchant_id": user["merchant_id"],
26
+ "exp": datetime.utcnow() + timedelta(hours=2)
27
+ }
28
+
29
+ access_token = jwt.encode(token_data, SECRET_KEY, algorithm=ALGORITHM)
30
+ return {"access_token": access_token, "token_type": "bearer"}
app/api/v1/media_routes.py CHANGED
@@ -1,13 +1,17 @@
1
- from fastapi import APIRouter, UploadFile, File, HTTPException
2
  from app.services.media_service import upload_file_to_s3, generate_presigned_url, delete_s3_object
 
3
 
4
  router = APIRouter(prefix="/media", tags=["Media"])
5
 
 
6
  @router.post("/upload")
7
- async def upload(file: UploadFile = File(...)):
8
- if not file.content_type.startswith(("image/", "application/")):
9
- raise HTTPException(status_code=400, detail="Invalid file type")
10
- return upload_file_to_s3(file)
 
 
11
 
12
  @router.get("/presigned-url")
13
  async def get_url(key: str):
 
1
+ from fastapi import APIRouter, UploadFile, File, Depends
2
  from app.services.media_service import upload_file_to_s3, generate_presigned_url, delete_s3_object
3
+ from app.dependencies.auth import get_current_user
4
 
5
  router = APIRouter(prefix="/media", tags=["Media"])
6
 
7
+
8
  @router.post("/upload")
9
+ async def upload_file(
10
+ file: UploadFile = File(...),
11
+ current_user: dict = Depends(get_current_user)
12
+ ):
13
+ merchant_id = current_user["merchant_id"]
14
+ return upload_file_to_s3(file, tenant_id=merchant_id)
15
 
16
  @router.get("/presigned-url")
17
  async def get_url(key: str):
app/app.py CHANGED
@@ -1,6 +1,8 @@
1
  from fastapi import FastAPI
2
- from app.api.v1 import media_routes
3
 
4
  app = FastAPI(title="Insightfy Media Service")
5
 
6
- app.include_router(media_routes.router)
 
 
 
1
  from fastapi import FastAPI
2
+ from app.api.v1 import media_routes, auth_routes
3
 
4
  app = FastAPI(title="Insightfy Media Service")
5
 
6
+ app.include_router(media_routes.router)
7
+
8
+ app.include_router(auth_routes.router)
app/dependencies/__pycache__/auth.cpython-313.pyc ADDED
Binary file (1.12 kB). View file
 
app/dependencies/auth.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import Depends
2
+ from fastapi.security import OAuth2PasswordBearer
3
+ from app.utils.jwt import decode_jwt_token
4
+ from settings import SECRET_KEY, ALGORITHM
5
+
6
+
7
+ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")
8
+
9
+ def get_current_user(token: str = Depends(oauth2_scheme)) -> dict:
10
+ try:
11
+ payload = decode_jwt_token(token)
12
+ return {
13
+ "user_id": payload["sub"],
14
+ "merchant_id": payload["merchant_id"],
15
+ "role": payload.get("role", "user")
16
+ }
17
+ except Exception:
18
+ raise HTTPException(
19
+ status_code=status.HTTP_401_UNAUTHORIZED,
20
+ detail="Invalid authentication credentials",
21
+ )
app/services/media_service.py CHANGED
@@ -1,14 +1,36 @@
1
  import boto3
 
 
2
  from fastapi import UploadFile
3
  from settings import WASABI_BUCKET, WASABI_CONFIG
4
- import uuid
5
 
6
  s3 = boto3.client("s3", **WASABI_CONFIG)
7
 
8
- def upload_file_to_s3(file: UploadFile):
9
- key = f"uploads/{uuid.uuid4()}_{file.filename}"
10
- s3.upload_fileobj(file.file, WASABI_BUCKET, key)
11
- return {"key": key, "url": generate_presigned_url(key)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  def generate_presigned_url(key: str, expiration: int = 3600):
14
  return s3.generate_presigned_url(
 
1
  import boto3
2
+ import uuid
3
+
4
  from fastapi import UploadFile
5
  from settings import WASABI_BUCKET, WASABI_CONFIG
6
+ from app.utils.compress import optimize_image, generate_thumbnail
7
 
8
  s3 = boto3.client("s3", **WASABI_CONFIG)
9
 
10
+
11
+
12
+ def upload_file_to_s3(file: UploadFile, tenant_id: str):
13
+ original_ext = os.path.splitext(file.filename)[-1] or ".jpg"
14
+ unique_id = str(uuid.uuid4())
15
+
16
+ # Optimize and upload main image
17
+ optimized_image = optimize_image(file)
18
+ key_image = f"{tenant_id}/uploads/{unique_id}{original_ext}"
19
+ s3.upload_fileobj(optimized_image, WASABI_BUCKET, key_image)
20
+
21
+ # Reset file and generate thumbnail
22
+ file.file.seek(0)
23
+ thumbnail = generate_thumbnail(file)
24
+ key_thumb = f"{tenant_id}/uploads/thumbnails/{unique_id}_thumb{original_ext}"
25
+ s3.upload_fileobj(thumbnail, WASABI_BUCKET, key_thumb)
26
+
27
+ return {
28
+ "key": key_image,
29
+ "url": generate_presigned_url(key_image),
30
+ "thumbnail_key": key_thumb,
31
+ "thumbnail_url": generate_presigned_url(key_thumb)
32
+ }
33
+
34
 
35
  def generate_presigned_url(key: str, expiration: int = 3600):
36
  return s3.generate_presigned_url(
app/utils/__pycache__/compress.cpython-313.pyc ADDED
Binary file (1.44 kB). View file
 
app/utils/__pycache__/jwt.cpython-313.pyc ADDED
Binary file (734 Bytes). View file
 
app/utils/compress.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ from io import BytesIO
3
+ from fastapi import UploadFile
4
+
5
+
6
+ # 🔧 Optimize image (resize + compress)
7
+ def optimize_image(file: UploadFile, max_size=(1024, 1024), quality=75) -> BytesIO:
8
+ image = Image.open(file.file)
9
+ image = image.convert("RGB")
10
+ image.thumbnail(max_size)
11
+ output = BytesIO()
12
+ image.save(output, format="JPEG", quality=quality, optimize=True)
13
+ output.seek(0)
14
+ return output
15
+
16
+ # 🖼️ Generate thumbnail
17
+ def generate_thumbnail(file: UploadFile, size=(200, 200)) -> BytesIO:
18
+ image = Image.open(file.file)
19
+ image = image.convert("RGB")
20
+ image.thumbnail(size)
21
+ output = BytesIO()
22
+ image.save(output, format="JPEG", quality=70, optimize=True)
23
+ output.seek(0)
24
+ return output
app/utils/jwt.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from jose import jwt, JWTError
2
+
3
+ SECRET_KEY = "your-super-secret-key"
4
+ ALGORITHM = "HS256"
5
+
6
+ def decode_jwt_token(token: str) -> dict:
7
+ try:
8
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
9
+ return payload
10
+ except JWTError:
11
+ raise ValueError("Invalid token")
requirements.txt CHANGED
@@ -2,4 +2,6 @@ fastapi
2
  boto3
3
  uvicorn
4
  python-multipart
5
- python-dotenv
 
 
 
2
  boto3
3
  uvicorn
4
  python-multipart
5
+ python-dotenv
6
+ pillow
7
+ python-jose
settings.py CHANGED
@@ -4,8 +4,6 @@ import os
4
 
5
  load_dotenv()
6
 
7
-
8
-
9
  #WASABI_BUCKET = "bloom-associates"
10
 
11
  WASABI_BUCKET = os.getenv("WASABI_BUCKET", "bloom-associates")
@@ -17,4 +15,7 @@ WASABI_CONFIG = {
17
  "region_name": os.getenv("REGION_NAME", "us-east-1"),
18
  "endpoint_url": os.getenv("ENDPOINT_URL", "https://s3.us-east-1.wasabisys.com")
19
 
20
- }
 
 
 
 
4
 
5
  load_dotenv()
6
 
 
 
7
  #WASABI_BUCKET = "bloom-associates"
8
 
9
  WASABI_BUCKET = os.getenv("WASABI_BUCKET", "bloom-associates")
 
15
  "region_name": os.getenv("REGION_NAME", "us-east-1"),
16
  "endpoint_url": os.getenv("ENDPOINT_URL", "https://s3.us-east-1.wasabisys.com")
17
 
18
+ }
19
+
20
+ SECRET_KEY = os.getenv("SECRET_KEY", "your-super-secret-key")
21
+ ALGORITHM = os.getenv("ALGORITHM", "HS256")