From befc1f0efa3433c7f24efcf3d72738eaae1c8ab1 Mon Sep 17 00:00:00 2001 From: Markos Gogoulos Date: Tue, 10 Feb 2026 09:16:55 +0200 Subject: [PATCH] fixes --- .../media-page/ViewerInfoContent.js | 2 +- lti/admin.py | 47 --------- lti/urls.py | 4 - lti/views.py | 95 +------------------ 4 files changed, 2 insertions(+), 146 deletions(-) diff --git a/frontend/src/static/js/components/media-page/ViewerInfoContent.js b/frontend/src/static/js/components/media-page/ViewerInfoContent.js index 53fc1118..212ff37f 100755 --- a/frontend/src/static/js/components/media-page/ViewerInfoContent.js +++ b/frontend/src/static/js/components/media-page/ViewerInfoContent.js @@ -274,7 +274,7 @@ export default function ViewerInfoContent(props) { - {!inEmbeddedApp() && } + ); } diff --git a/lti/admin.py b/lti/admin.py index fd92ce65..8fdfc793 100644 --- a/lti/admin.py +++ b/lti/admin.py @@ -13,7 +13,6 @@ from .models import ( LTIToolKeys, LTIUserMapping, ) -from .services import LTINRPSClient @admin.register(LTIPlatform) @@ -52,7 +51,6 @@ class LTIResourceLinkAdmin(admin.ModelAdmin): list_display = ['context_title', 'platform', 'category_link', 'rbac_group_link'] list_filter = ['platform'] search_fields = ['context_id', 'context_title', 'resource_link_id'] - actions = ['sync_course_members'] fieldsets = ( ('Platform', {'fields': ('platform',)}), @@ -75,51 +73,6 @@ class LTIResourceLinkAdmin(admin.ModelAdmin): rbac_group_link.short_description = 'RBAC Group' - def sync_course_members(self, request, queryset): - """Sync course members from LMS using NRPS""" - synced_count = 0 - failed_count = 0 - - for resource_link in queryset: - try: - # Check if NRPS is enabled - if not resource_link.platform.enable_nrps: - messages.warning(request, f'NRPS is disabled for platform: {resource_link.platform.name}') - failed_count += 1 - continue - - # Check if RBAC group exists - if not resource_link.rbac_group: - messages.warning(request, f'No RBAC group for: {resource_link.context_title}') - failed_count += 1 - continue - - # Get last successful launch for NRPS endpoint - last_launch = LTILaunchLog.objects.filter(platform=resource_link.platform, resource_link=resource_link, success=True).order_by('-created_at').first() - - if not last_launch: - messages.warning(request, f'No launch data for: {resource_link.context_title}') - failed_count += 1 - continue - - # Perform NRPS sync - nrps_client = LTINRPSClient(resource_link.platform, last_launch.claims) - result = nrps_client.sync_members_to_rbac_group(resource_link.rbac_group) - synced_count += result.get('synced', 0) - messages.success(request, f'Synced {result.get("synced", 0)} members for: {resource_link.context_title}') - - except Exception as e: - messages.error(request, f'Error syncing {resource_link.context_title}: {str(e)}') - failed_count += 1 - - # Summary message - if synced_count > 0: - self.message_user(request, f'Successfully synced members from {queryset.count() - failed_count} course(s). Total members: {synced_count}', messages.SUCCESS) - if failed_count > 0: - self.message_user(request, f'{failed_count} course(s) failed to sync', messages.WARNING) - - sync_course_members.short_description = 'Sync course members from LMS (NRPS)' - @admin.register(LTIUserMapping) class LTIUserMappingAdmin(admin.ModelAdmin): diff --git a/lti/urls.py b/lti/urls.py index 31b25b2a..c5200b1b 100644 --- a/lti/urls.py +++ b/lti/urls.py @@ -19,8 +19,4 @@ urlpatterns = [ # LTI-authenticated pages path('my-media/', views.MyMediaLTIView.as_view(), name='my_media'), path('embed//', views.EmbedMediaLTIView.as_view(), name='embed_media'), - # Manual sync - path('sync///', views.ManualSyncView.as_view(), name='manual_sync'), - # TinyMCE integration (reuses select-media with mode=tinymce parameter) - path('tinymce-embed//', views.TinyMCEGetEmbedView.as_view(), name='tinymce_embed'), ] diff --git a/lti/views.py b/lti/views.py index e6c25cce..9334278e 100644 --- a/lti/views.py +++ b/lti/views.py @@ -29,13 +29,8 @@ from jwcrypto import jwk from pylti1p3.exception import LtiException from pylti1p3.message_launch import MessageLaunch from pylti1p3.oidc_login import OIDCLogin -from rest_framework import status -from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response -from rest_framework.views import APIView from files.models import Media -from rbac.models import RBACMembership from .adapters import DjangoRequest, DjangoSessionService, DjangoToolConfig from .handlers import ( @@ -46,8 +41,7 @@ from .handlers import ( validate_lti_session, ) from .keys import get_jwks -from .models import LTILaunchLog, LTIPlatform, LTIResourceLink, LTIToolKeys -from .services import LTINRPSClient +from .models import LTILaunchLog, LTIPlatform, LTIToolKeys logger = logging.getLogger(__name__) @@ -611,90 +605,3 @@ class EmbedMediaLTIView(View): return JsonResponse({'error': 'Access denied', 'message': 'You do not have permission to view this media'}, status=403) return HttpResponseRedirect(f"/embed?m={friendly_token}&mode=embed_mode") - - -class ManualSyncView(APIView): - """ - Manual NRPS sync for course members/roles - - Endpoint: POST /lti/sync/// - Requires: User must be manager in the course RBAC group - """ - - permission_classes = [IsAuthenticated] - - def post(self, request, platform_id, context_id): - """Manually trigger NRPS sync""" - try: - platform = get_object_or_404(LTIPlatform, id=platform_id) - - resource_link = LTIResourceLink.objects.filter(platform=platform, context_id=context_id).first() - - if not resource_link: - return Response({'error': 'Context not found', 'message': f'No resource link found for context {context_id}'}, status=status.HTTP_404_NOT_FOUND) - - rbac_group = resource_link.rbac_group - if not rbac_group: - return Response({'error': 'No RBAC group', 'message': 'This context does not have an associated RBAC group'}, status=status.HTTP_400_BAD_REQUEST) - - is_manager = RBACMembership.objects.filter(user=request.user, rbac_group=rbac_group, role='manager').exists() - - if not is_manager: - return Response({'error': 'Insufficient permissions', 'message': 'You must be a course manager to sync members'}, status=status.HTTP_403_FORBIDDEN) - - if not platform.enable_nrps: - return Response({'error': 'NRPS disabled', 'message': 'Names and Role Provisioning Service is disabled for this platform'}, status=status.HTTP_400_BAD_REQUEST) - - last_launch = LTILaunchLog.objects.filter(platform=platform, resource_link=resource_link, success=True).order_by('-created_at').first() - - if not last_launch: - return Response({'error': 'No launch data', 'message': 'No successful launch data found for NRPS'}, status=status.HTTP_400_BAD_REQUEST) - - nrps_client = LTINRPSClient(platform, last_launch.claims) - result = nrps_client.sync_members_to_rbac_group(rbac_group) - - return Response( - { - 'status': 'success', - 'message': f'Successfully synced {result["synced"]} members', - 'synced_count': result['synced'], - 'removed_count': result.get('removed', 0), - 'synced_at': result['synced_at'], - }, - status=status.HTTP_200_OK, - ) - - except Exception as e: - return Response({'error': 'Sync failed', 'message': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - -@method_decorator(xframe_options_exempt, name='dispatch') -class TinyMCEGetEmbedView(View): - """ - API endpoint to get embed code for a specific media item (for TinyMCE integration). - - Returns JSON with the embed code for the requested media. - Requires: User must be logged in (via LTI session) - """ - - def get(self, request, friendly_token): - """Get embed code for the specified media.""" - if not request.user.is_authenticated: - return JsonResponse({'error': 'Authentication required'}, status=401) - - media = Media.objects.filter(friendly_token=friendly_token).first() - - if not media: - return JsonResponse({'error': 'Media not found'}, status=404) - - embed_url = request.build_absolute_uri(reverse('get_embed') + f'?m={friendly_token}') - - embed_code = f'' - - return JsonResponse( - { - 'embedCode': embed_code, - 'title': media.title, - 'thumbnail': media.thumbnail_url if hasattr(media, 'thumbnail_url') else '', - } - )