TheDeepDas commited on
Commit
54fe70d
Β·
1 Parent(s): a3dd63c

cloudinary upload

Browse files
.env CHANGED
@@ -1,3 +1,6 @@
1
  JWT_SECRET_KEY=change_this_secret_in_production
2
  MONGODB_URI=mongodb+srv://deepdblm_db_user:IqLKnKhwLLSOP1Ka@cluster0.0u1vpow.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0
3
- ALLOWED_ORIGINS=http://localhost:8080,https://marine-pollution-detection.vercel.app
 
 
 
 
1
  JWT_SECRET_KEY=change_this_secret_in_production
2
  MONGODB_URI=mongodb+srv://deepdblm_db_user:IqLKnKhwLLSOP1Ka@cluster0.0u1vpow.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0
3
+ ALLOWED_ORIGINS=http://localhost:8080,https://marine-pollution-detection.vercel.app
4
+ CLOUDINARY_CLOUD_NAME=dler9jdjf
5
+ CLOUDINARY_API_KEY=414766445792264
6
+ CLOUDINARY_API_SECRET=kV133xtcDbxh4tEMvk5CS4WFx1U
app/__pycache__/config.cpython-311.pyc CHANGED
Binary files a/app/__pycache__/config.cpython-311.pyc and b/app/__pycache__/config.cpython-311.pyc differ
 
app/__pycache__/main.cpython-311.pyc CHANGED
Binary files a/app/__pycache__/main.cpython-311.pyc and b/app/__pycache__/main.cpython-311.pyc differ
 
app/config.py CHANGED
@@ -1,6 +1,7 @@
1
  from functools import lru_cache
2
  from typing import List, Union
3
  import os
 
4
 
5
  from pydantic_settings import BaseSettings
6
 
@@ -14,6 +15,11 @@ class Settings(BaseSettings):
14
  access_token_expire_minutes: int = 60 * 24
15
  allowed_origins: Union[str, List[str]] = "http://localhost:5173"
16
 
 
 
 
 
 
17
  # Hugging Face Spaces specific settings
18
  space_id: str = os.getenv("SPACE_ID", "")
19
 
 
1
  from functools import lru_cache
2
  from typing import List, Union
3
  import os
4
+ import cloudinary
5
 
6
  from pydantic_settings import BaseSettings
7
 
 
15
  access_token_expire_minutes: int = 60 * 24
16
  allowed_origins: Union[str, List[str]] = "http://localhost:5173"
17
 
18
+ # Cloudinary settings
19
+ cloudinary_cloud_name: str
20
+ cloudinary_api_key: str
21
+ cloudinary_api_secret: str
22
+
23
  # Hugging Face Spaces specific settings
24
  space_id: str = os.getenv("SPACE_ID", "")
25
 
app/main.py CHANGED
@@ -1,5 +1,7 @@
1
  import logging
2
  from contextlib import asynccontextmanager
 
 
3
 
4
  from fastapi import FastAPI
5
  from fastapi.middleware.cors import CORSMiddleware
@@ -8,6 +10,14 @@ from .config import get_settings
8
  from .database import get_collection, test_connection
9
  from .routers import auth, incidents
10
 
 
 
 
 
 
 
 
 
11
  logger = logging.getLogger(__name__)
12
 
13
 
@@ -35,6 +45,21 @@ async def setup_database_indexes():
35
  @asynccontextmanager
36
  async def lifespan(app: FastAPI):
37
  # Startup
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  await setup_database_indexes()
39
  yield
40
  # Shutdown (if needed in future)
 
1
  import logging
2
  from contextlib import asynccontextmanager
3
+ import cloudinary
4
+ import sys
5
 
6
  from fastapi import FastAPI
7
  from fastapi.middleware.cors import CORSMiddleware
 
10
  from .database import get_collection, test_connection
11
  from .routers import auth, incidents
12
 
13
+ # Configure logging
14
+ logging.basicConfig(
15
+ level=logging.INFO,
16
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
17
+ handlers=[
18
+ logging.StreamHandler(sys.stdout)
19
+ ]
20
+ )
21
  logger = logging.getLogger(__name__)
22
 
23
 
 
45
  @asynccontextmanager
46
  async def lifespan(app: FastAPI):
47
  # Startup
48
+ settings = get_settings()
49
+
50
+ # Initialize Cloudinary
51
+ try:
52
+ # Use environment variables from settings
53
+ cloudinary.config(
54
+ cloud_name=settings.cloudinary_cloud_name,
55
+ api_key=settings.cloudinary_api_key,
56
+ api_secret=settings.cloudinary_api_secret,
57
+ secure=True
58
+ )
59
+ logger.info("Cloudinary initialized successfully with cloud name: %s", settings.cloudinary_cloud_name)
60
+ except Exception as e:
61
+ logger.error(f"Cloudinary initialization failed: {e}")
62
+
63
  await setup_database_indexes()
64
  yield
65
  # Shutdown (if needed in future)
app/routers/__pycache__/incidents.cpython-311.pyc CHANGED
Binary files a/app/routers/__pycache__/incidents.cpython-311.pyc and b/app/routers/__pycache__/incidents.cpython-311.pyc differ
 
app/routers/incidents.py CHANGED
@@ -45,7 +45,16 @@ async def classify_incident_report(
45
  incident_class, severity = classification_result
46
  confidence_scores = None
47
 
48
- image_path = await store_image(image)
 
 
 
 
 
 
 
 
 
49
 
50
  document = {
51
  "name": name,
 
45
  incident_class, severity = classification_result
46
  confidence_scores = None
47
 
48
+ # Upload image to Cloudinary
49
+ image_path = None
50
+ if image:
51
+ image_path = await store_image(image)
52
+ if not image_path:
53
+ # If Cloudinary upload fails, raise an error since we're not using local fallback
54
+ raise HTTPException(
55
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
56
+ detail="Failed to upload image to cloud storage"
57
+ )
58
 
59
  document = {
60
  "name": name,
app/services/fallback_storage.py CHANGED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Fallback storage service for when Cloudinary uploads fail.
3
+ This provides a more controlled way to handle local storage fallback.
4
+ """
5
+ from pathlib import Path
6
+ from typing import Optional
7
+ import logging
8
+ from uuid import uuid4
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ # Define fallback upload directories
13
+ FALLBACK_PATHS = [
14
+ Path(__file__).resolve().parent.parent / "uploads",
15
+ Path("/tmp/uploads"),
16
+ Path("/app/uploads")
17
+ ]
18
+
19
+ # Find a usable directory
20
+ FALLBACK_DIR = None
21
+ for path in FALLBACK_PATHS:
22
+ try:
23
+ path.mkdir(exist_ok=True, parents=True)
24
+ FALLBACK_DIR = path
25
+ logger.info(f"Fallback storage directory ready: {FALLBACK_DIR}")
26
+ break
27
+ except Exception as e:
28
+ logger.warning(f"Cannot use {path} for fallback storage: {e}")
29
+ continue
30
+
31
+ if FALLBACK_DIR is None:
32
+ logger.error("Could not create any fallback storage directory")
33
+ FALLBACK_DIR = Path("/tmp") # Last resort fallback
34
+
35
+
36
+ async def store_file_locally(file_content: bytes, original_filename: str) -> Optional[str]:
37
+ """
38
+ Store a file in the local filesystem as a fallback when cloud storage fails
39
+
40
+ Args:
41
+ file_content: The binary content of the file
42
+ original_filename: The original filename
43
+
44
+ Returns:
45
+ Relative path to the stored file or None if storage failed
46
+ """
47
+ try:
48
+ # Create a unique filename
49
+ file_extension = Path(original_filename).suffix
50
+ filename = f"{uuid4().hex}{file_extension}"
51
+ file_path = FALLBACK_DIR / filename
52
+
53
+ # Write the file
54
+ file_path.write_bytes(file_content)
55
+ logger.info(f"File saved to fallback storage: {file_path}")
56
+
57
+ # Return a relative path that can be used in URLs
58
+ return str(Path("uploads") / filename)
59
+ except Exception as e:
60
+ logger.error(f"Failed to save file to fallback storage: {e}")
61
+ return None
app/services/incidents.py CHANGED
@@ -2,38 +2,18 @@ from pathlib import Path
2
  from typing import Optional
3
  from uuid import uuid4
4
  import logging
 
 
 
 
5
 
6
  from ..database import get_collection
 
7
 
8
  logger = logging.getLogger(__name__)
9
 
10
  INCIDENTS_COLLECTION = "incidents"
11
 
12
- # Try multiple upload directory locations
13
- upload_paths = [
14
- Path(__file__).resolve().parent.parent / "uploads",
15
- Path("/tmp/uploads"),
16
- Path("/app/uploads")
17
- ]
18
-
19
- UPLOAD_DIR = None
20
- for path in upload_paths:
21
- try:
22
- path.mkdir(exist_ok=True, parents=True)
23
- UPLOAD_DIR = path
24
- logger.info(f"Upload directory ready: {UPLOAD_DIR}")
25
- break
26
- except PermissionError:
27
- logger.warning(f"Cannot create upload directory at {path}")
28
- continue
29
- except Exception as e:
30
- logger.warning(f"Error creating upload directory at {path}: {e}")
31
- continue
32
-
33
- if UPLOAD_DIR is None:
34
- logger.error("Could not create any upload directory")
35
- UPLOAD_DIR = Path("/tmp") # Fallback to /tmp
36
-
37
 
38
  async def save_incident_document(document: dict) -> dict:
39
  collection = get_collection(INCIDENTS_COLLECTION)
@@ -57,16 +37,54 @@ async def get_all_incidents() -> list:
57
 
58
 
59
  async def store_image(upload_file) -> Optional[str]:
 
 
 
 
60
  if upload_file is None:
61
  return None
62
-
63
- UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
64
- file_extension = Path(upload_file.filename).suffix
65
- filename = f"{uuid4().hex}{file_extension}"
66
- file_path = UPLOAD_DIR / filename
67
-
68
- contents = await upload_file.read()
69
- file_path.write_bytes(contents)
70
-
71
- await upload_file.close()
72
- return str(Path("uploads") / filename)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  from typing import Optional
3
  from uuid import uuid4
4
  import logging
5
+ import cloudinary
6
+ import cloudinary.uploader
7
+ import tempfile
8
+ import os
9
 
10
  from ..database import get_collection
11
+ from ..config import get_settings
12
 
13
  logger = logging.getLogger(__name__)
14
 
15
  INCIDENTS_COLLECTION = "incidents"
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  async def save_incident_document(document: dict) -> dict:
19
  collection = get_collection(INCIDENTS_COLLECTION)
 
37
 
38
 
39
  async def store_image(upload_file) -> Optional[str]:
40
+ """
41
+ Store an uploaded image using Cloudinary only.
42
+ No local fallback - if Cloudinary upload fails, the function will return None.
43
+ """
44
  if upload_file is None:
45
  return None
46
+
47
+ temp_path = None
48
+ try:
49
+ logger.info(f"Starting image upload to Cloudinary for file: {upload_file.filename}")
50
+
51
+ # Read the file content
52
+ contents = await upload_file.read()
53
+ logger.info(f"Read {len(contents)} bytes from uploaded file")
54
+
55
+ # Create a temporary file to use with Cloudinary
56
+ with tempfile.NamedTemporaryFile(delete=False, suffix=Path(upload_file.filename).suffix) as temp_file:
57
+ temp_path = temp_file.name
58
+ temp_file.write(contents)
59
+ logger.info(f"Wrote content to temporary file: {temp_path}")
60
+
61
+ # Upload to Cloudinary - ensuring we use the right resource type
62
+ logger.info("Starting Cloudinary upload...")
63
+
64
+ # Add resource_type=auto to handle different file types correctly
65
+ upload_result = cloudinary.uploader.upload(
66
+ temp_path,
67
+ folder="marine_guard_incidents",
68
+ resource_type="auto"
69
+ )
70
+
71
+ # Return the Cloudinary URL
72
+ cloudinary_url = upload_result["secure_url"]
73
+ logger.info(f"Cloudinary upload successful. URL: {cloudinary_url}")
74
+
75
+ await upload_file.close()
76
+ return cloudinary_url
77
+
78
+ except Exception as e:
79
+ logger.error(f"Failed to upload image to Cloudinary: {e}", exc_info=True)
80
+ if upload_file:
81
+ await upload_file.close()
82
+ return None
83
+ finally:
84
+ # Always clean up the temporary file
85
+ if temp_path and os.path.exists(temp_path):
86
+ try:
87
+ os.unlink(temp_path)
88
+ logger.info(f"Deleted temporary file: {temp_path}")
89
+ except Exception as e:
90
+ logger.error(f"Failed to delete temporary file: {e}")
app/uploads/222544d2e2e44e8d812becab341d74ef.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ This is a test image file for the API
app/uploads/becb6a146b764fd6a50cb2b1305ccba6.jpg ADDED
create_test_user.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+
4
+ # API endpoint for user signup
5
+ API_URL = "http://localhost:8000/api/auth/signup"
6
+
7
+ def create_test_user():
8
+ """Create a test user for API testing"""
9
+ try:
10
+ # Prepare the user data
11
+ user_data = {
12
+ "email": "testuser@example.com",
13
+ "password": "Password123!",
14
+ "display_name": "Test User",
15
+ "organization": "Test Org",
16
+ "role": "citizen"
17
+ }
18
+
19
+ # Make the API request
20
+ print(f"Creating test user at {API_URL}")
21
+ response = requests.post(
22
+ API_URL,
23
+ data=json.dumps(user_data),
24
+ headers={"Content-Type": "application/json"}
25
+ )
26
+
27
+ # Process the response
28
+ if response.status_code == 200:
29
+ result = response.json()
30
+ print("User created successfully!")
31
+ print(f"Token: {result.get('access_token')[:15]}...")
32
+ print(f"User ID: {result.get('user', {}).get('id')}")
33
+ return result
34
+ else:
35
+ print(f"API request failed with status code {response.status_code}")
36
+ print(f"Response: {response.text}")
37
+ return None
38
+ except Exception as e:
39
+ print(f"Error creating test user: {e}")
40
+ return None
41
+
42
+ if __name__ == "__main__":
43
+ print("Creating test user for Marine Guard API")
44
+ create_test_user()
debug_cloudinary.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cloudinary
3
+ import cloudinary.uploader
4
+ from dotenv import load_dotenv
5
+ import logging
6
+
7
+ # Configure logging
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
+
11
+ # Load environment variables
12
+ load_dotenv()
13
+
14
+ # Configure Cloudinary
15
+ cloudinary.config(
16
+ cloud_name=os.getenv("CLOUDINARY_CLOUD_NAME"),
17
+ api_key=os.getenv("CLOUDINARY_API_KEY"),
18
+ api_secret=os.getenv("CLOUDINARY_API_SECRET"),
19
+ secure=True
20
+ )
21
+
22
+ def test_cloudinary_config():
23
+ print("Cloudinary configuration:")
24
+ print(f"Cloud name: {cloudinary.config().cloud_name}")
25
+ print(f"API key: {cloudinary.config().api_key}")
26
+ print(f"API secret: {'*' * len(cloudinary.config().api_secret) if cloudinary.config().api_secret else 'Not set'}")
27
+
28
+ def upload_test_image():
29
+ try:
30
+ # Create a test file
31
+ test_file_path = "cloudinary_test.txt"
32
+ with open(test_file_path, "w") as f:
33
+ f.write("Test content for Cloudinary upload")
34
+
35
+ # Upload to Cloudinary
36
+ print("Uploading test file to Cloudinary...")
37
+ upload_result = cloudinary.uploader.upload(
38
+ test_file_path,
39
+ folder="marine_guard_test",
40
+ resource_type="auto" # Let Cloudinary auto-detect the resource type
41
+ )
42
+
43
+ print(f"Upload successful! URL: {upload_result.get('secure_url')}")
44
+ print(f"Public ID: {upload_result.get('public_id')}")
45
+ print(f"Resource type: {upload_result.get('resource_type')}")
46
+
47
+ # Clean up the test file
48
+ os.unlink(test_file_path)
49
+ print(f"Deleted local test file: {test_file_path}")
50
+
51
+ return upload_result
52
+
53
+ except Exception as e:
54
+ logger.error(f"Error uploading to Cloudinary: {e}", exc_info=True)
55
+ if os.path.exists(test_file_path):
56
+ os.unlink(test_file_path)
57
+ return None
58
+
59
+ if __name__ == "__main__":
60
+ print("Testing detailed Cloudinary configuration and upload")
61
+ test_cloudinary_config()
62
+ result = upload_test_image()
63
+ if result:
64
+ print("βœ… Cloudinary upload test PASSED")
65
+ else:
66
+ print("❌ Cloudinary upload test FAILED")
list_incidents.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+
4
+ # API endpoint for incident listing
5
+ API_URL = "http://localhost:8000/api/incidents/list"
6
+
7
+ def get_token():
8
+ """Get a JWT token by authenticating with the API"""
9
+ try:
10
+ login_url = "http://localhost:8000/api/auth/login"
11
+ login_data = {
12
+ "email": "testuser@example.com",
13
+ "password": "Password123!"
14
+ }
15
+
16
+ response = requests.post(login_url, data=json.dumps(login_data),
17
+ headers={"Content-Type": "application/json"})
18
+
19
+ if response.status_code == 200:
20
+ token = response.json().get("access_token")
21
+ print(f"Authentication successful.")
22
+ return token
23
+ else:
24
+ print(f"Authentication failed with status code {response.status_code}")
25
+ print(response.text)
26
+ return None
27
+ except Exception as e:
28
+ print(f"Error getting token: {e}")
29
+ return None
30
+
31
+ def list_incidents():
32
+ """List all incidents for the authenticated user"""
33
+ token = get_token()
34
+ if not token:
35
+ print("No token available, cannot proceed")
36
+ return
37
+
38
+ try:
39
+ print(f"Fetching incidents from {API_URL}")
40
+ response = requests.get(
41
+ API_URL,
42
+ headers={"Authorization": f"Bearer {token}"}
43
+ )
44
+
45
+ if response.status_code == 200:
46
+ incidents = response.json().get("incidents", [])
47
+ print(f"Found {len(incidents)} incidents")
48
+
49
+ # Print details of each incident
50
+ for i, incident in enumerate(incidents):
51
+ print(f"\nIncident {i + 1}:")
52
+ print(f" ID: {incident.get('id')}")
53
+ print(f" Type: {incident.get('incident_class')}")
54
+ print(f" Severity: {incident.get('severity')}")
55
+ print(f" Created: {incident.get('created_at')}")
56
+
57
+ # Check if image path is a Cloudinary URL
58
+ image_path = incident.get('image_path')
59
+ if image_path:
60
+ if 'cloudinary.com' in image_path:
61
+ print(f" Image: Cloudinary URL - {image_path}")
62
+ else:
63
+ print(f" Image: Local path - {image_path}")
64
+ else:
65
+ print(" No image attached")
66
+
67
+ return incidents
68
+ else:
69
+ print(f"API request failed with status code {response.status_code}")
70
+ print(f"Response: {response.text}")
71
+ return None
72
+ except Exception as e:
73
+ print(f"Error listing incidents: {e}")
74
+ return None
75
+
76
+ if __name__ == "__main__":
77
+ print("Listing incidents from Marine Guard API")
78
+ list_incidents()
test_api_cloudinary.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import json
4
+ import sys
5
+ from pathlib import Path
6
+ from dotenv import load_dotenv
7
+
8
+ # Load environment variables from .env file
9
+ load_dotenv()
10
+
11
+ # API endpoint for incident classification
12
+ API_URL = "http://localhost:8000/api/incidents/classify"
13
+
14
+ # JWT token (replace with your actual token)
15
+ JWT_TOKEN = "" # Set this to test with your token
16
+
17
+ def get_token():
18
+ """Get a JWT token by authenticating with the API"""
19
+ try:
20
+ login_url = "http://localhost:8000/api/auth/login"
21
+ login_data = {
22
+ "email": "testuser@example.com", # Using our newly created test user
23
+ "password": "Password123!" # Using the password for the test user
24
+ }
25
+
26
+ response = requests.post(login_url, data=json.dumps(login_data),
27
+ headers={"Content-Type": "application/json"})
28
+
29
+ if response.status_code == 200:
30
+ token = response.json().get("access_token")
31
+ print(f"Authentication successful. Token: {token[:15]}..." if token else "No token in response")
32
+ return token
33
+ else:
34
+ print(f"Authentication failed with status code {response.status_code}")
35
+ print(response.text)
36
+ return None
37
+ except Exception as e:
38
+ print(f"Error getting token: {e}")
39
+ return None
40
+
41
+ def create_test_image():
42
+ """Create a test image file"""
43
+ # Check if we're in the right directory
44
+ current_dir = Path.cwd()
45
+ print(f"Current directory: {current_dir}")
46
+
47
+ # Create a directory for test files if it doesn't exist
48
+ test_dir = current_dir / "test_files"
49
+ test_dir.mkdir(exist_ok=True)
50
+
51
+ # Path to the test image file
52
+ test_image_path = test_dir / "test_image.txt"
53
+
54
+ # Write some content to the file
55
+ with open(test_image_path, "w") as f:
56
+ f.write("This is a test image file for the API")
57
+
58
+ print(f"Created test file at {test_image_path}")
59
+ return test_image_path
60
+
61
+ def test_report_incident_with_image():
62
+ """Test reporting an incident with an image"""
63
+
64
+ # Create a test image
65
+ image_path = create_test_image()
66
+
67
+ # Get a token if not provided
68
+ token = JWT_TOKEN or get_token()
69
+ if not token:
70
+ print("No token available, cannot proceed with test")
71
+ return
72
+
73
+ try:
74
+ # Prepare the form data
75
+ form_data = {
76
+ "description": "Test incident with image upload to Cloudinary",
77
+ "name": "Cloudinary Test",
78
+ "latitude": "37.7749",
79
+ "longitude": "-122.4194"
80
+ }
81
+
82
+ # Prepare the file
83
+ with open(image_path, "rb") as image_file:
84
+ files = {"image": ("test_image.txt", image_file, "text/plain")}
85
+
86
+ # Make the API request
87
+ print(f"Sending request to {API_URL}")
88
+ response = requests.post(
89
+ API_URL,
90
+ data=form_data,
91
+ files=files,
92
+ headers={"Authorization": f"Bearer {token}"}
93
+ )
94
+
95
+ # Process the response
96
+ if response.status_code == 200:
97
+ print("Incident report successful!")
98
+ print(f"Response: {response.json()}")
99
+ return response.json()
100
+ else:
101
+ print(f"API request failed with status code {response.status_code}")
102
+ print(f"Response: {response.text}")
103
+ return None
104
+ except Exception as e:
105
+ print(f"Error testing incident report API: {e}")
106
+ return None
107
+ finally:
108
+ # Clean up test image
109
+ try:
110
+ if os.path.exists(image_path):
111
+ os.remove(image_path)
112
+ print(f"Removed test file: {image_path}")
113
+ except Exception as e:
114
+ print(f"Error cleaning up test file: {e}")
115
+
116
+ if __name__ == "__main__":
117
+ print("Testing Marine Guard Incident API with Cloudinary Integration")
118
+ test_report_incident_with_image()
test_cloudinary.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cloudinary
3
+ import cloudinary.uploader
4
+ from dotenv import load_dotenv
5
+
6
+ # Load environment variables from .env file
7
+ load_dotenv()
8
+
9
+ # Configure Cloudinary
10
+ cloudinary.config(
11
+ cloud_name=os.getenv("CLOUDINARY_CLOUD_NAME"),
12
+ api_key=os.getenv("CLOUDINARY_API_KEY"),
13
+ api_secret=os.getenv("CLOUDINARY_API_SECRET"),
14
+ secure=True
15
+ )
16
+
17
+ def test_cloudinary_upload():
18
+ """Test Cloudinary upload functionality"""
19
+ try:
20
+ # Try to upload a simple text as a test
21
+ # Create a simple test file
22
+ test_file = "test_image.txt"
23
+ with open(test_file, "w") as f:
24
+ f.write("This is a test file for Cloudinary upload")
25
+
26
+ # Upload to Cloudinary
27
+ print("Uploading to Cloudinary...")
28
+ result = cloudinary.uploader.upload(
29
+ test_file,
30
+ folder="marine_guard_test",
31
+ public_id="test_upload"
32
+ )
33
+
34
+ print(f"Upload successful! URL: {result['secure_url']}")
35
+ print(f"Full result: {result}")
36
+
37
+ # Clean up the test file
38
+ os.remove(test_file)
39
+ return True
40
+
41
+ except Exception as e:
42
+ print(f"Error testing Cloudinary upload: {e}")
43
+ return False
44
+
45
+ if __name__ == "__main__":
46
+ print("Testing Cloudinary configuration")
47
+ print(f"Cloud name: {os.getenv('CLOUDINARY_CLOUD_NAME')}")
48
+ print(f"API key: {os.getenv('CLOUDINARY_API_KEY')}")
49
+ print(f"API secret: {os.getenv('CLOUDINARY_API_SECRET')[:3]}...")
50
+
51
+ test_result = test_cloudinary_upload()
52
+ print(f"Test {'successful' if test_result else 'failed'}")
test_cloudinary_improved.py ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import json
4
+ from pathlib import Path
5
+ from dotenv import load_dotenv
6
+ import random
7
+
8
+ # Load environment variables
9
+ load_dotenv()
10
+
11
+ # API endpoint for incident classification
12
+ API_URL = "http://localhost:8000/api/incidents/classify"
13
+
14
+ def get_token():
15
+ """Get a JWT token by authenticating with the API"""
16
+ try:
17
+ login_url = "http://localhost:8000/api/auth/login"
18
+ login_data = {
19
+ "email": "testuser@example.com",
20
+ "password": "Password123!"
21
+ }
22
+
23
+ response = requests.post(login_url, data=json.dumps(login_data),
24
+ headers={"Content-Type": "application/json"})
25
+
26
+ if response.status_code == 200:
27
+ token = response.json().get("access_token")
28
+ print(f"Authentication successful. Token: {token[:15]}...")
29
+ return token
30
+ else:
31
+ print(f"Authentication failed with status code {response.status_code}")
32
+ print(response.text)
33
+ return None
34
+ except Exception as e:
35
+ print(f"Error getting token: {e}")
36
+ return None
37
+
38
+ def create_test_image():
39
+ """Create a test image file - we'll use a .jpg extension but with text content for testing"""
40
+ # Create a directory for test files if it doesn't exist
41
+ test_dir = Path("test_files")
42
+ test_dir.mkdir(exist_ok=True)
43
+
44
+ # Use a .jpg extension to make sure Cloudinary tries to process it properly
45
+ test_image_path = test_dir / f"test_image_{random.randint(1000, 9999)}.jpg"
46
+
47
+ # Write some content to the file
48
+ with open(test_image_path, "w") as f:
49
+ f.write("This is a fake image file for testing Cloudinary uploads")
50
+
51
+ print(f"Created test file at {test_image_path}")
52
+ return test_image_path
53
+
54
+ def report_incident_with_image():
55
+ """Report an incident with an image via the API"""
56
+ # Create a test image
57
+ image_path = create_test_image()
58
+
59
+ # Get a token
60
+ token = get_token()
61
+ if not token:
62
+ print("No token available, cannot proceed with test")
63
+ return False
64
+
65
+ try:
66
+ # Prepare the form data
67
+ form_data = {
68
+ "description": "Testing Cloudinary integration with improved logging",
69
+ "name": "Cloudinary Test",
70
+ "latitude": "37.7749",
71
+ "longitude": "-122.4194"
72
+ }
73
+
74
+ # Prepare the file
75
+ with open(image_path, "rb") as image_file:
76
+ files = {"image": (image_path.name, image_file, "image/jpeg")}
77
+
78
+ # Make the API request
79
+ print(f"Sending request to {API_URL}")
80
+ response = requests.post(
81
+ API_URL,
82
+ data=form_data,
83
+ files=files,
84
+ headers={"Authorization": f"Bearer {token}"}
85
+ )
86
+
87
+ # Process the response
88
+ if response.status_code == 200:
89
+ print("Incident report successful!")
90
+ print(f"Response: {response.json()}")
91
+
92
+ # Get the incident ID from the response
93
+ incident_id = response.json().get("incident_id")
94
+ print(f"Created incident with ID: {incident_id}")
95
+
96
+ # Now check the incident details to see if Cloudinary URL was used
97
+ if incident_id:
98
+ return check_incident_image(token, incident_id)
99
+ return True
100
+ else:
101
+ print(f"API request failed with status code {response.status_code}")
102
+ print(f"Response: {response.text}")
103
+ return False
104
+ except Exception as e:
105
+ print(f"Error testing incident report API: {e}")
106
+ return False
107
+ finally:
108
+ # Clean up test image
109
+ try:
110
+ if image_path.exists():
111
+ image_path.unlink()
112
+ print(f"Removed test file: {image_path}")
113
+ except Exception as e:
114
+ print(f"Error cleaning up test file: {e}")
115
+
116
+ def check_incident_image(token, incident_id):
117
+ """Check if the incident has a Cloudinary image URL"""
118
+ try:
119
+ # Get the list of incidents
120
+ list_url = "http://localhost:8000/api/incidents/list"
121
+ print(f"Fetching incidents to check for Cloudinary URL...")
122
+
123
+ response = requests.get(
124
+ list_url,
125
+ headers={"Authorization": f"Bearer {token}"}
126
+ )
127
+
128
+ if response.status_code == 200:
129
+ incidents = response.json().get("incidents", [])
130
+
131
+ # Find our incident
132
+ for incident in incidents:
133
+ if incident.get("id") == incident_id:
134
+ image_path = incident.get("image_path")
135
+ print(f"Found incident. Image path: {image_path}")
136
+
137
+ if image_path and "cloudinary.com" in image_path:
138
+ print("βœ… SUCCESS: Image was uploaded to Cloudinary!")
139
+ return True
140
+ else:
141
+ print("❌ FAILED: Image was not uploaded to Cloudinary")
142
+ return False
143
+
144
+ print(f"Couldn't find incident with ID: {incident_id}")
145
+ return False
146
+ else:
147
+ print(f"Failed to fetch incidents list: {response.status_code}")
148
+ print(response.text)
149
+ return False
150
+ except Exception as e:
151
+ print(f"Error checking incident: {e}")
152
+ return False
153
+
154
+ if __name__ == "__main__":
155
+ print("Testing Marine Guard incident reporting with Cloudinary integration")
156
+ success = report_incident_with_image()
157
+ print(f"Test {'PASSED' if success else 'FAILED'}")
test_cloudinary_mandatory.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Test script for Cloudinary-only image storage in the Marine Guard API.
3
+ This script ensures that:
4
+ 1. We can authenticate with the API
5
+ 2. We can upload an image which gets stored in Cloudinary
6
+ 3. We can retrieve the incident which contains the Cloudinary URL
7
+ """
8
+ import os
9
+ import requests
10
+ import json
11
+ from pathlib import Path
12
+ import random
13
+ import time
14
+ from dotenv import load_dotenv
15
+
16
+ # Load environment variables
17
+ load_dotenv()
18
+
19
+ # API endpoint for incident classification
20
+ API_URL = "http://localhost:8000/api/incidents/classify"
21
+ API_LIST_URL = "http://localhost:8000/api/incidents/list"
22
+ API_LOGIN_URL = "http://localhost:8000/api/auth/login"
23
+
24
+ def authenticate():
25
+ """Authenticate with the API and get a JWT token"""
26
+ try:
27
+ login_data = {
28
+ "email": "testuser@example.com",
29
+ "password": "Password123!"
30
+ }
31
+
32
+ print(f"Authenticating with the API at {API_LOGIN_URL}...")
33
+ response = requests.post(API_LOGIN_URL, json=login_data)
34
+
35
+ if response.status_code == 200:
36
+ token = response.json().get("access_token")
37
+ print("βœ… Authentication successful!")
38
+ return token
39
+ else:
40
+ print(f"❌ Authentication failed with status code {response.status_code}")
41
+ print(response.text)
42
+ return None
43
+ except Exception as e:
44
+ print(f"❌ Error during authentication: {e}")
45
+ return None
46
+
47
+ def create_test_file():
48
+ """Create a test file to upload"""
49
+ test_dir = Path("test_files")
50
+ test_dir.mkdir(exist_ok=True)
51
+
52
+ # Use a .txt extension since we just need any file that Cloudinary can handle
53
+ file_path = test_dir / f"cloudinary_test_{random.randint(1000, 9999)}.txt"
54
+
55
+ # Write simple text content
56
+ with open(file_path, "w") as f:
57
+ f.write("This is a test file for Cloudinary upload in Marine Guard API")
58
+
59
+ print(f"Created test file at: {file_path}")
60
+ return file_path
61
+
62
+ def report_incident():
63
+ """Report an incident with an image via the API"""
64
+ token = authenticate()
65
+ if not token:
66
+ print("Cannot proceed with test - authentication failed")
67
+ return False
68
+
69
+ # Create a test image file
70
+ image_path = create_test_file()
71
+
72
+ try:
73
+ # Prepare the form data
74
+ form_data = {
75
+ "description": "Cloudinary-only storage test with JPG image",
76
+ "name": "Cloudinary Storage Test",
77
+ "latitude": "42.3601",
78
+ "longitude": "-71.0589"
79
+ }
80
+
81
+ # Prepare the file for upload
82
+ with open(image_path, "rb") as image_file:
83
+ files = {"image": (image_path.name, image_file, "text/plain")}
84
+
85
+ # Make the API request
86
+ print(f"Reporting incident to {API_URL}...")
87
+ response = requests.post(
88
+ API_URL,
89
+ data=form_data,
90
+ files=files,
91
+ headers={"Authorization": f"Bearer {token}"}
92
+ )
93
+
94
+ # Check the response
95
+ if response.status_code == 200:
96
+ result = response.json()
97
+ incident_id = result.get("incident_id")
98
+ print(f"βœ… Incident reported successfully! ID: {incident_id}")
99
+
100
+ # Verify that the image was uploaded to Cloudinary
101
+ return verify_cloudinary_upload(token, incident_id)
102
+ else:
103
+ print(f"❌ Incident reporting failed with status code {response.status_code}")
104
+ print(f"Error details: {response.text}")
105
+ return False
106
+ except Exception as e:
107
+ print(f"❌ Error reporting incident: {e}")
108
+ return False
109
+ finally:
110
+ # Clean up the test file
111
+ if os.path.exists(image_path):
112
+ os.unlink(image_path)
113
+ print(f"Deleted test file: {image_path}")
114
+
115
+ def verify_cloudinary_upload(token, incident_id):
116
+ """Verify that the incident has a Cloudinary URL for its image"""
117
+ try:
118
+ print(f"Fetching incident details to verify Cloudinary URL...")
119
+ # Short delay to ensure the incident is saved in the database
120
+ time.sleep(1)
121
+
122
+ response = requests.get(
123
+ API_LIST_URL,
124
+ headers={"Authorization": f"Bearer {token}"}
125
+ )
126
+
127
+ if response.status_code == 200:
128
+ incidents = response.json().get("incidents", [])
129
+ for incident in incidents:
130
+ if incident.get("id") == incident_id:
131
+ image_path = incident.get("image_path")
132
+
133
+ if image_path and "cloudinary.com" in image_path:
134
+ print(f"βœ… SUCCESS: Image was uploaded to Cloudinary!")
135
+ print(f"Cloudinary URL: {image_path}")
136
+ return True
137
+ else:
138
+ print(f"❌ FAILED: Image does not have a Cloudinary URL")
139
+ print(f"Image path: {image_path}")
140
+ return False
141
+
142
+ print(f"❌ FAILED: Could not find incident with ID {incident_id}")
143
+ return False
144
+ else:
145
+ print(f"❌ FAILED: Could not fetch incidents list. Status: {response.status_code}")
146
+ print(response.text)
147
+ return False
148
+ except Exception as e:
149
+ print(f"❌ Error verifying Cloudinary upload: {e}")
150
+ return False
151
+
152
+ if __name__ == "__main__":
153
+ print("=" * 60)
154
+ print("MARINE GUARD API - CLOUDINARY-ONLY STORAGE TEST")
155
+ print("=" * 60)
156
+
157
+ success = report_incident()
158
+
159
+ print("\nTEST SUMMARY")
160
+ print("=" * 60)
161
+ print(f"Cloudinary storage test: {'βœ… PASSED' if success else '❌ FAILED'}")
162
+ print("=" * 60)
test_files/cloudinary_test_7574.jpg ADDED
test_image.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ This is a test file for Cloudinary upload