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 django.urls import path
|
||||||
|
|
||||||
from . import deep_linking, views
|
from . import deep_linking, filter_embed, views
|
||||||
|
|
||||||
app_name = 'lti'
|
app_name = 'lti'
|
||||||
|
|
||||||
@@ -23,4 +23,6 @@ urlpatterns = [
|
|||||||
path('sync/<int:platform_id>/<str:context_id>/', views.ManualSyncView.as_view(), name='manual_sync'),
|
path('sync/<int:platform_id>/<str:context_id>/', views.ManualSyncView.as_view(), name='manual_sync'),
|
||||||
# TinyMCE integration (reuses select-media with mode=tinymce parameter)
|
# TinyMCE integration (reuses select-media with mode=tinymce parameter)
|
||||||
path('tinymce-embed/<str:friendly_token>/', views.TinyMCEGetEmbedView.as_view(), name='tinymce_embed'),
|
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