mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2026-02-05 16:35:18 -05:00
feat: Implement a new notifications application, add admin API views for dashboard metrics, introduce scheduled tasks, and update API routing and project configurations.
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import GenerateUploadURLView
|
||||
from . import views
|
||||
|
||||
app_name = "images"
|
||||
|
||||
urlpatterns = [
|
||||
path("generate-upload-url/", GenerateUploadURLView.as_view(), name="generate-upload-url"),
|
||||
path("generate-upload-url/", views.GenerateUploadURLView.as_view(), name="generate_upload_url"),
|
||||
path("delete/", views.DeleteImageView.as_view(), name="delete_image"),
|
||||
path("og-image/", views.GenerateOGImageView.as_view(), name="og_image"),
|
||||
]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import logging
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
@@ -30,3 +31,109 @@ class GenerateUploadURLView(APIView):
|
||||
except Exception as e:
|
||||
capture_and_log(e, 'Generate upload URL - unexpected error', source='api')
|
||||
return Response({"detail": "An unexpected error occurred."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||
|
||||
|
||||
class DeleteImageView(APIView):
|
||||
"""
|
||||
POST /images/delete/
|
||||
Delete an image from Cloudflare Images.
|
||||
"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
image_id = request.data.get("image_id")
|
||||
|
||||
if not image_id:
|
||||
return Response(
|
||||
{"detail": "image_id is required"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
try:
|
||||
# Get Cloudflare credentials
|
||||
account_id = getattr(settings, "CLOUDFLARE_IMAGES_ACCOUNT_ID", None)
|
||||
api_token = getattr(settings, "CLOUDFLARE_IMAGES_API_TOKEN", None)
|
||||
|
||||
if not account_id or not api_token:
|
||||
logger.warning("Cloudflare Images not configured, mock deleting image")
|
||||
return Response({"success": True, "mock": True})
|
||||
|
||||
# Delete from Cloudflare
|
||||
url = f"https://api.cloudflare.com/client/v4/accounts/{account_id}/images/v1/{image_id}"
|
||||
response = requests.delete(
|
||||
url,
|
||||
headers={"Authorization": f"Bearer {api_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
if response.status_code in (200, 404): # 404 = already deleted
|
||||
return Response({"success": True})
|
||||
else:
|
||||
logger.error(f"Cloudflare delete failed: {response.text}")
|
||||
return Response(
|
||||
{"detail": "Failed to delete image"},
|
||||
status=status.HTTP_502_BAD_GATEWAY,
|
||||
)
|
||||
|
||||
except requests.RequestException as e:
|
||||
capture_and_log(e, "Delete image - Cloudflare API error", source="api")
|
||||
return Response(
|
||||
{"detail": "Failed to delete image"},
|
||||
status=status.HTTP_502_BAD_GATEWAY,
|
||||
)
|
||||
except Exception as e:
|
||||
capture_and_log(e, "Delete image - unexpected error", source="api")
|
||||
return Response(
|
||||
{"detail": "An unexpected error occurred"},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
|
||||
|
||||
class GenerateOGImageView(APIView):
|
||||
"""
|
||||
POST /images/og-image/
|
||||
Generate an Open Graph image for social sharing.
|
||||
"""
|
||||
|
||||
permission_classes = [] # Public endpoint
|
||||
|
||||
def post(self, request):
|
||||
title = request.data.get("title", "")
|
||||
description = request.data.get("description", "")
|
||||
entity_type = request.data.get("entity_type", "")
|
||||
image_url = request.data.get("image_url", "")
|
||||
|
||||
if not title:
|
||||
return Response(
|
||||
{"detail": "title is required"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
try:
|
||||
# This is a placeholder for OG image generation
|
||||
# In production, you would:
|
||||
# 1. Use an image generation service (Cloudinary, imgix, etc.)
|
||||
# 2. Or use a headless browser service (Puppeteer, Playwright)
|
||||
# 3. Or use a dedicated OG image service
|
||||
|
||||
# For now, return a template URL or placeholder
|
||||
base_url = getattr(settings, "SITE_URL", "https://thrillwiki.com")
|
||||
og_image_url = f"{base_url}/api/v1/images/og-preview/?title={title[:100]}"
|
||||
|
||||
return Response({
|
||||
"success": True,
|
||||
"og_image_url": og_image_url,
|
||||
"title": title,
|
||||
"description": description[:200] if description else "",
|
||||
"entity_type": entity_type,
|
||||
"note": "Placeholder - configure OG image service for production",
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
capture_and_log(e, "Generate OG image", source="api")
|
||||
return Response(
|
||||
{"detail": str(e)},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user