def handle(self, *args, **options): """ Collect all blocks from a course that are "importable" and write them to the a blockstore library. """ # Search for the library. try: contentlib_api.get_library(options['library-key']) except contentlib_api.ContentLibraryNotFound as exc: raise CommandError("The library specified does not exist: " f"{options['library-key']}") from exc # Validate the method and its arguments, instantiate the openedx client. if options['method'] == 'api': if options['oauth_creds_file']: with options['oauth_creds_file'] as creds_f: oauth_key, oauth_secret = [v.strip() for v in creds_f.readlines()] elif options['oauth_creds']: oauth_key, oauth_secret = options['oauth_creds'] else: raise CommandError("Method 'api' requires one of the " "--oauth-* options, and none was specified.") edx_client = contentlib_api.EdxApiImportClient( options['lms_url'], options['studio_url'], oauth_key, oauth_secret, library_key=options['library-key'], ) elif options['method'] == 'modulestore': edx_client = contentlib_api.EdxModulestoreImportClient( library_key=options['library-key'], ) else: raise CommandError(f"Method not supported: {options['method']}") failed_blocks = [] def on_progress(block_key, block_num, block_count, exception=None): self.stdout.write(f"{block_num}/{block_count}: {block_key}: ", ending='') # In case stdout is a term and line buffered: self.stdout.flush() if exception: self.stdout.write(self.style.ERROR('❌')) log.error('Failed to import block: %s', block_key, exc_info=exception) failed_blocks.append(block_key) else: self.stdout.write(self.style.SUCCESS('✓')) edx_client.import_blocks_from_course(options['course-key'], on_progress) if failed_blocks: self.stdout.write(self.style.ERROR(f"❌ {len(failed_blocks)} failed:")) for key in failed_blocks: self.stdout.write(self.style.ERROR(str(key)))
def get(self, request, lib_key_str): """ Get a specific content library """ key = LibraryLocatorV2.from_string(lib_key_str) api.require_permission_for_library_key(key, request.user, permissions.CAN_VIEW_THIS_CONTENT_LIBRARY) result = api.get_library(key) return Response(ContentLibraryMetadataSerializer(result).data)
def patch(self, request, lib_key_str): """ Update a content library """ key = LibraryLocatorV2.from_string(lib_key_str) api.require_permission_for_library_key(key, request.user, permissions.CAN_EDIT_THIS_CONTENT_LIBRARY) serializer = ContentLibraryUpdateSerializer(data=request.data, partial=True) serializer.is_valid(raise_exception=True) api.update_library(key, **serializer.validated_data) result = api.get_library(key) return Response(ContentLibraryMetadataSerializer(result).data)
def patch(self, request, lib_key_str): """ Update a content library """ key = LibraryLocatorV2.from_string(lib_key_str) api.require_permission_for_library_key(key, request.user, permissions.CAN_EDIT_THIS_CONTENT_LIBRARY) serializer = ContentLibraryUpdateSerializer(data=request.data, partial=True) serializer.is_valid(raise_exception=True) data = dict(serializer.validated_data) if 'type' in data: data['library_type'] = data.pop('type') try: api.update_library(key, **data) except api.IncompatibleTypesError as err: raise ValidationError({'type': str(err)}) result = api.get_library(key) return Response(ContentLibraryMetadataSerializer(result).data)