mirror of
https://github.com/mediacms-io/mediacms.git
synced 2026-02-04 06:22:59 -05:00
d
This commit is contained in:
102
lti/filter_embed.py
Normal file
102
lti/filter_embed.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# TODO JUST AN F EXAMPLEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
|
||||
"""
|
||||
Filter Embed Token API for MediaCMS
|
||||
|
||||
Provides signed embed tokens for Moodle filter-based embeds
|
||||
without requiring full LTI launch flow
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import time
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from files.models import Media
|
||||
|
||||
from .models import LTIPlatform
|
||||
|
||||
|
||||
@method_decorator(csrf_exempt, name='dispatch')
|
||||
class FilterEmbedTokenView(View):
|
||||
"""
|
||||
Generate a signed embed token for Moodle filter embeds
|
||||
|
||||
This bypasses the full LTI launch flow which doesn't work for filters
|
||||
"""
|
||||
|
||||
def post(self, request):
|
||||
"""Handle token request from Moodle filter"""
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
|
||||
media_token = data.get('media_token')
|
||||
user_id = data.get('user_id') # noqa: F841
|
||||
# user_email and user_name reserved for future RBAC implementation
|
||||
client_id = data.get('client_id')
|
||||
timestamp = data.get('timestamp')
|
||||
signature = data.get('signature')
|
||||
|
||||
if not all([media_token, user_id, client_id, signature, timestamp]):
|
||||
return JsonResponse({'error': 'Missing required parameters'}, status=400)
|
||||
|
||||
# Check timestamp is recent (within 5 minutes)
|
||||
if abs(time.time() - timestamp) > 300:
|
||||
return JsonResponse({'error': 'Request expired'}, status=400)
|
||||
|
||||
# Verify platform exists
|
||||
try:
|
||||
LTIPlatform.objects.get(client_id=client_id)
|
||||
except LTIPlatform.DoesNotExist:
|
||||
return JsonResponse({'error': 'Invalid client'}, status=403)
|
||||
|
||||
# Get shared secret from platform or settings
|
||||
# Option 1: Store it in LTIPlatform model (add a field)
|
||||
# Option 2: Use Django settings
|
||||
from django.conf import settings
|
||||
|
||||
shared_secret = getattr(settings, 'FILTER_EMBED_SHARED_SECRET', None)
|
||||
|
||||
if not shared_secret:
|
||||
return JsonResponse({'error': 'Server not configured for filter embeds'}, status=500)
|
||||
|
||||
# Verify signature
|
||||
payload_copy = data.copy()
|
||||
del payload_copy['signature']
|
||||
expected_sig = hmac.new(shared_secret.encode(), json.dumps(payload_copy).encode(), hashlib.sha256).hexdigest()
|
||||
|
||||
if not hmac.compare_digest(signature, expected_sig):
|
||||
return JsonResponse({'error': 'Invalid signature'}, status=403)
|
||||
|
||||
# Get media
|
||||
try:
|
||||
media = Media.objects.get(friendly_token=media_token)
|
||||
except Media.DoesNotExist:
|
||||
return JsonResponse({'error': 'Media not found'}, status=404)
|
||||
|
||||
# Check if media is public/unlisted (allow) or private (would need RBAC check)
|
||||
# For now, allow public and unlisted
|
||||
if media.state not in ['public', 'unlisted']:
|
||||
# TODO: Implement RBAC check here based on cmid/course context
|
||||
return JsonResponse({'error': 'Access denied'}, status=403)
|
||||
|
||||
# Generate embed URL (simple embed, no auth needed for public/unlisted)
|
||||
embed_url = request.build_absolute_uri(reverse('get_embed') + f'?m={media_token}')
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
'embed_url': embed_url,
|
||||
'media_token': media_token,
|
||||
'title': media.title,
|
||||
}
|
||||
)
|
||||
|
||||
except json.JSONDecodeError:
|
||||
return JsonResponse({'error': 'Invalid JSON'}, status=400)
|
||||
except Exception as e:
|
||||
return JsonResponse({'error': str(e)}, status=500)
|
||||
@@ -4,7 +4,7 @@ LTI 1.3 URL Configuration for MediaCMS
|
||||
|
||||
from django.urls import path
|
||||
|
||||
from . import deep_linking, views
|
||||
from . import deep_linking, filter_embed, views
|
||||
|
||||
app_name = 'lti'
|
||||
|
||||
@@ -23,4 +23,6 @@ urlpatterns = [
|
||||
path('sync/<int:platform_id>/<str:context_id>/', views.ManualSyncView.as_view(), name='manual_sync'),
|
||||
# TinyMCE integration (reuses select-media with mode=tinymce parameter)
|
||||
path('tinymce-embed/<str:friendly_token>/', views.TinyMCEGetEmbedView.as_view(), name='tinymce_embed'),
|
||||
# Filter embed token API
|
||||
path('api/v1/get-filter-embed-token/', filter_embed.FilterEmbedTokenView.as_view(), name='filter_embed_token'),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user