def import_handler(request, course_key_string): """ The restful handler for importing a course. GET html: return html page for import page json: not supported POST or PUT json: import a course via the .tar.gz file specified in request.FILES """ courselike_key = CourseKey.from_string(course_key_string) library = isinstance(courselike_key, LibraryLocator) if library: root_name = LIBRARY_ROOT successful_url = reverse_library_url('library_handler', courselike_key) context_name = 'context_library' courselike_module = modulestore().get_library(courselike_key) import_func = import_library_from_xml else: root_name = COURSE_ROOT successful_url = reverse_course_url('course_handler', courselike_key) context_name = 'context_course' courselike_module = modulestore().get_course(courselike_key) import_func = import_course_from_xml return _import_handler(request, courselike_key, root_name, successful_url, context_name, courselike_module, import_func)
def test_manage_library_users(self): """ Simple test that the Library "User Access" view works. Also tests that we can use the REST API to assign a user to a library. """ library = LibraryFactory.create() extra_user, _ = self.create_non_staff_user() manage_users_url = reverse_library_url('manage_library_users', unicode(library.location.library_key)) response = self.client.get(manage_users_url) self.assertEqual(response.status_code, 200) # extra_user has not been assigned to the library so should not show up in the list: self.assertNotIn(extra_user.username, response.content) # Now add extra_user to the library: user_details_url = reverse_course_url( 'course_team_handler', library.location.library_key, kwargs={'email': extra_user.email} ) edit_response = self.client.ajax_post(user_details_url, {"role": LibraryUserRole.ROLE}) self.assertIn(edit_response.status_code, (200, 204)) # Now extra_user should apear in the list: response = self.client.get(manage_users_url) self.assertEqual(response.status_code, 200) self.assertIn(extra_user.username, response.content)
def manage_library_users(request, library_key_string): """ Studio UI for editing the users within a library. Uses the /course_team/:library_key/:user_email/ REST API to make changes. """ library_key = CourseKey.from_string(library_key_string) if not isinstance(library_key, LibraryLocator): raise Http404 # This is not a library user_perms = get_user_permissions(request.user, library_key) if not user_perms & STUDIO_VIEW_USERS: raise PermissionDenied() library = modulestore().get_library(library_key) if library is None: raise Http404 # Segment all the users explicitly associated with this library, ensuring each user only has one role listed: instructors = set(CourseInstructorRole(library_key).users_with_role()) staff = set(CourseStaffRole(library_key).users_with_role()) - instructors users = set(LibraryUserRole(library_key).users_with_role()) - instructors - staff all_users = instructors | staff | users return render_to_response('manage_users_lib.html', { 'context_library': library, 'staff': staff, 'instructors': instructors, 'users': users, 'all_users': all_users, 'allow_actions': bool(user_perms & STUDIO_EDIT_ROLES), 'library_key': unicode(library_key), 'lib_users_url': reverse_library_url('manage_library_users', library_key_string), })
def import_handler(request, course_key_string): """ The restful handler for importing a course. GET html: return html page for import page json: not supported POST or PUT json: import a course via the .tar.gz file specified in request.FILES """ courselike_key = CourseKey.from_string(course_key_string) library = isinstance(courselike_key, LibraryLocator) if library: root_name = LIBRARY_ROOT successful_url = reverse_library_url('library_handler', courselike_key) context_name = 'context_library' courselike_module = modulestore().get_library(courselike_key) import_func = import_library_from_xml else: root_name = COURSE_ROOT successful_url = reverse_course_url('course_handler', courselike_key) context_name = 'context_course' courselike_module = modulestore().get_course(courselike_key) import_func = import_course_from_xml return _import_handler( request, courselike_key, root_name, successful_url, context_name, courselike_module, import_func )
def export(request, course_key_string): """ Trigger the async export job https://github.com/edx/edx-platform/blob/open-release/juniper.master/cms/djangoapps/contentstore/views/import_export.py#L290 POST /sn-api/courses/<course_key>/export/ """ course_key = CourseKey.from_string(course_key_string) if isinstance(course_key, LibraryLocator): courselike_module = modulestore().get_library(course_key) context = { 'context_library': courselike_module, 'courselike_home_url': reverse_library_url("library_handler", course_key), 'library': True } else: courselike_module = modulestore().get_course(course_key) if courselike_module is None: raise Http404 context = { 'context_course': courselike_module, 'courselike_home_url': reverse_course_url("course_handler", course_key), 'library': False } context['status_url'] = reverse_course_url('export_status_handler', course_key) export_olx.delay(request.user.id, course_key_string, request.LANGUAGE_CODE) return Response({'ExportStatus': 1})
def test_manage_library_users(self): """ Simple test that the Library "User Access" view works. Also tests that we can use the REST API to assign a user to a library. """ library = LibraryFactory.create() extra_user, _ = self.create_non_staff_user() manage_users_url = reverse_library_url( 'manage_library_users', text_type(library.location.library_key)) response = self.client.get(manage_users_url) self.assertEqual(response.status_code, 200) # extra_user has not been assigned to the library so should not show up in the list: self.assertNotIn(binary_type(extra_user.username), response.content) # Now add extra_user to the library: user_details_url = reverse_course_url( 'course_team_handler', library.location.library_key, kwargs={'email': extra_user.email}) edit_response = self.client.ajax_post(user_details_url, {"role": LibraryUserRole.ROLE}) self.assertIn(edit_response.status_code, (200, 204)) # Now extra_user should apear in the list: response = self.client.get(manage_users_url) self.assertEqual(response.status_code, 200) self.assertIn(binary_type(extra_user.username), response.content)
def export_handler(request, course_key_string): """ The restful handler for exporting a course. GET html: return html page for import page application/x-tgz: return tar.gz file containing exported course json: not supported Note that there are 2 ways to request the tar.gz file. The request header can specify application/x-tgz via HTTP_ACCEPT, or a query parameter can be used (?_accept=application/x-tgz). If the tar.gz file has been requested but the export operation fails, an HTML page will be returned which describes the error. """ course_key = CourseKey.from_string(course_key_string) export_url = reverse_course_url('export_handler', course_key) if not has_course_author_access(request.user, course_key): raise PermissionDenied() if isinstance(course_key, LibraryLocator): courselike_module = modulestore().get_library(course_key) context = { 'context_library': courselike_module, 'courselike_home_url': reverse_library_url("library_handler", course_key), 'library': True } else: courselike_module = modulestore().get_course(course_key) context = { 'context_course': courselike_module, 'courselike_home_url': reverse_course_url("course_handler", course_key), 'library': False } context['export_url'] = export_url + '?_accept=application/x-tgz' # an _accept URL parameter will be preferred over HTTP_ACCEPT in the header. requested_format = request.REQUEST.get( '_accept', request.META.get('HTTP_ACCEPT', 'text/html')) if 'application/x-tgz' in requested_format: try: tarball = create_export_tarball(courselike_module, course_key, context) except SerializationError: return render_to_response('export.html', context) return send_tarball(tarball) elif 'text/html' in requested_format: return render_to_response('export.html', context) else: # Only HTML or x-tgz request formats are supported (no JSON). return HttpResponse(status=406)
def _create_library(request): """ Helper method for creating a new library. """ if not auth.has_access(request.user, CourseCreatorRole()): log.exception(u"User %s tried to create a library without permission", request.user.username) raise PermissionDenied() display_name = None try: display_name = request.json['display_name'] org = request.json['org'] library = request.json.get('number', None) if library is None: library = request.json['library'] store = modulestore() with store.default_store(ModuleStoreEnum.Type.split): new_lib = store.create_library( org=org, library=library, user_id=request.user.id, fields={"display_name": display_name}, ) # Give the user admin ("Instructor") role for this library: add_instructor(new_lib.location.library_key, request.user, request.user) except KeyError as error: log.exception("Unable to create library - missing required JSON key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library - missing required field '{field}'". format(field=error.message)) }) except InvalidKeyError as error: log.exception("Unable to create library - invalid key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library '{name}'.\n\n{err}").format( name=display_name, err=error.message) }) except DuplicateCourseError: log.exception( "Unable to create library - one already exists with the same key.") return JsonResponseBadRequest({ 'ErrMsg': _('There is already a library defined with the same ' 'organization and library code. Please ' 'change your library code so that it is unique within your organization.' ) }) lib_key_str = unicode(new_lib.location.library_key) return JsonResponse({ 'url': reverse_library_url('library_handler', lib_key_str), 'library_key': lib_key_str, })
def _create_library(request): """ Helper method for creating a new library. """ display_name = None try: display_name = request.json['display_name'] org = request.json['org'] library = request.json.get('number', None) # [COLARAZ_CUSTOM] if not request.user.is_superuser and not org in configuration_helpers.get_value('course_org_filter'): log.exception('Unable to create library - invalid organization ({}).'.format(org)) return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library '{}'.\n\n{} is not a valid organization.").format(display_name, org) }) if library is None: library = request.json['library'] store = modulestore() with store.default_store(ModuleStoreEnum.Type.split): new_lib = store.create_library( org=org, library=library, user_id=request.user.id, fields={"display_name": display_name}, ) # Give the user admin ("Instructor") role for this library: add_instructor(new_lib.location.library_key, request.user, request.user) except KeyError as error: log.exception("Unable to create library - missing required JSON key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library - missing required field '{field}'").format(field=text_type(error)) }) except InvalidKeyError as error: log.exception("Unable to create library - invalid key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library '{name}'.\n\n{err}").format(name=display_name, err=text_type(error)) }) except DuplicateCourseError: log.exception("Unable to create library - one already exists with the same key.") return JsonResponseBadRequest({ 'ErrMsg': _( 'There is already a library defined with the same ' 'organization and library code. Please ' 'change your library code so that it is unique within your organization.' ) }) lib_key_str = unicode(new_lib.location.library_key) return JsonResponse({ 'url': reverse_library_url('library_handler', lib_key_str), 'library_key': lib_key_str, })
def export_handler(request, course_key_string): """ The restful handler for exporting a course. GET html: return html page for import page application/x-tgz: return tar.gz file containing exported course json: not supported Note that there are 2 ways to request the tar.gz file. The request header can specify application/x-tgz via HTTP_ACCEPT, or a query parameter can be used (?_accept=application/x-tgz). If the tar.gz file has been requested but the export operation fails, an HTML page will be returned which describes the error. """ course_key = CourseKey.from_string(course_key_string) export_url = reverse_course_url('export_handler', course_key) if not has_course_author_access(request.user, course_key): raise PermissionDenied() if isinstance(course_key, LibraryLocator): courselike_module = modulestore().get_library(course_key) context = { 'context_library': courselike_module, 'courselike_home_url': reverse_library_url("library_handler", course_key), 'library': True } else: courselike_module = modulestore().get_course(course_key) if courselike_module is None: raise Http404 context = { 'context_course': courselike_module, 'courselike_home_url': reverse_course_url("course_handler", course_key), 'library': False } context['export_url'] = export_url + '?_accept=application/x-tgz' # an _accept URL parameter will be preferred over HTTP_ACCEPT in the header. requested_format = request.GET.get('_accept', request.META.get('HTTP_ACCEPT', 'text/html')) if 'application/x-tgz' in requested_format: try: tarball = create_export_tarball(courselike_module, course_key, context) except SerializationError: return render_to_response('export.html', context) return send_tarball(tarball) elif 'text/html' in requested_format: return render_to_response('export.html', context) else: # Only HTML or x-tgz request formats are supported (no JSON). return HttpResponse(status=406)
def library_blocks_view(library, user, response_format): """ The main view of a course's content library. Shows all the XBlocks in the library, and allows adding/editing/deleting them. Can be called with response_format="json" to get a JSON-formatted list of the XBlocks in the library along with library metadata. Assumes that read permissions have been checked before calling this. """ assert isinstance(library.location.library_key, LibraryLocator) assert isinstance(library.location, LibraryUsageLocator) children = library.children if response_format == "json": # The JSON response for this request is short and sweet: prev_version = library.runtime.course_entry.structure[ 'previous_version'] return JsonResponse({ "display_name": library.display_name, "library_id": unicode(library.location.library_key), "version": unicode(library.runtime.course_entry.course_key.version), "previous_version": unicode(prev_version) if prev_version else None, "blocks": [unicode(x) for x in children], }) can_edit = has_studio_write_access(user, library.location.library_key) xblock_info = create_xblock_info(library, include_ancestor_info=False, graders=[]) component_templates = get_component_templates( library, library=True) if can_edit else [] return render_to_response( 'library.html', { 'can_edit': can_edit, 'context_library': library, 'component_templates': json.dumps(component_templates), 'xblock_info': xblock_info, 'templates': CONTAINER_TEMPATES, 'lib_users_url': reverse_library_url('manage_library_users', unicode(library.location.library_key)), })
def export_handler(request, course_key_string): """ The restful handler for exporting a course. GET html: return html page for import page json: not supported POST Start a Celery task to export the course The Studio UI uses a POST request to start the export asynchronously, with a link appearing on the page once it's ready. """ course_key = CourseKey.from_string(course_key_string) if not has_course_author_access(request.user, course_key): raise PermissionDenied() if isinstance(course_key, LibraryLocator): courselike_module = modulestore().get_library(course_key) context = { 'context_library': courselike_module, 'courselike_home_url': reverse_library_url("library_handler", course_key), 'library': True } else: courselike_module = modulestore().get_course(course_key) if courselike_module is None: raise Http404 context = { 'context_course': courselike_module, 'courselike_home_url': reverse_course_url("course_handler", course_key), 'library': False } context['status_url'] = reverse_course_url('export_status_handler', course_key) # an _accept URL parameter will be preferred over HTTP_ACCEPT in the header. requested_format = request.GET.get( '_accept', request.META.get('HTTP_ACCEPT', 'text/html')) if request.method == 'POST': export_olx.delay(request.user.id, course_key_string, request.LANGUAGE_CODE) return JsonResponse({'ExportStatus': 1}) elif 'text/html' in requested_format: return render_to_response('export.html', context) else: # Only HTML request format is supported (no JSON). return HttpResponse(status=406)
def _can_access_library(self, library): """ Use the normal studio library URL to check if we have access `library` can be a LibraryLocator or the library's root XBlock """ if isinstance(library, (basestring, LibraryLocator)): lib_key = library else: lib_key = library.location.library_key response = self.client.get(reverse_library_url("library_handler", unicode(lib_key))) self.assertIn(response.status_code, (200, 302, 403)) return response.status_code == 200
def _can_access_library(self, library): """ Use the normal studio library URL to check if we have access `library` can be a LibraryLocator or the library's root XBlock """ if isinstance(library, (six.string_types, LibraryLocator)): lib_key = library else: lib_key = library.location.library_key response = self.client.get(reverse_library_url('library_handler', six.text_type(lib_key))) self.assertIn(response.status_code, (200, 302, 403)) return response.status_code == 200
def _create_library(request): """ Helper method for creating a new library. """ if not auth.has_access(request.user, CourseCreatorRole()): log.exception(u"User %s tried to create a library without permission", request.user.username) raise PermissionDenied() display_name = None try: display_name = request.json['display_name'] org = request.json['org'] library = request.json.get('number', None) if library is None: library = request.json['library'] store = modulestore() with store.default_store(ModuleStoreEnum.Type.split): new_lib = store.create_library( org=org, library=library, user_id=request.user.id, fields={"display_name": display_name}, ) # Give the user admin ("Instructor") role for this library: add_instructor(new_lib.location.library_key, request.user, request.user) except KeyError as error: log.exception("Unable to create library - missing required JSON key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library - missing required field '{field}'".format(field=error.message)) }) except InvalidKeyError as error: log.exception("Unable to create library - invalid key.") return JsonResponseBadRequest({ "ErrMsg": _("Unable to create library '{name}'.\n\n{err}").format(name=display_name, err=error.message) }) except DuplicateCourseError: log.exception("Unable to create library - one already exists with the same key.") return JsonResponseBadRequest({ 'ErrMsg': _( 'There is already a library defined with the same ' 'organization and library code. Please ' 'change your library code so that it is unique within your organization.' ) }) lib_key_str = unicode(new_lib.location.library_key) return JsonResponse({ 'url': reverse_library_url('library_handler', lib_key_str), 'library_key': lib_key_str, })
def _assert_library_link_present(response, library): """ Asserts there's a valid library link on libraries tab. """ parsed_html = lxml.html.fromstring(response.content) library_link_elements = parsed_html.find_class('library-link') self.assertEqual(len(library_link_elements), 1) link = library_link_elements[0] self.assertEqual( link.get("href"), reverse_library_url('library_handler', library.location.library_key), ) # now test that url outline_response = self.client.get(link.get("href"), {}, HTTP_ACCEPT='text/html') self.assertEqual(outline_response.status_code, 200)
def export_handler(request, course_key_string): """ The restful handler for exporting a course. GET html: return html page for import page json: not supported POST Start a Celery task to export the course The Studio UI uses a POST request to start the export asynchronously, with a link appearing on the page once it's ready. """ course_key = CourseKey.from_string(course_key_string) if not has_course_author_access(request.user, course_key): raise PermissionDenied() if isinstance(course_key, LibraryLocator): courselike_module = modulestore().get_library(course_key) context = { 'context_library': courselike_module, 'courselike_home_url': reverse_library_url("library_handler", course_key), 'library': True } else: courselike_module = modulestore().get_course(course_key) if courselike_module is None: raise Http404 context = { 'context_course': courselike_module, 'courselike_home_url': reverse_course_url("course_handler", course_key), 'library': False } context['status_url'] = reverse_course_url('export_status_handler', course_key) # an _accept URL parameter will be preferred over HTTP_ACCEPT in the header. requested_format = request.GET.get('_accept', request.META.get('HTTP_ACCEPT', 'text/html')) if request.method == 'POST': export_olx.delay(request.user.id, course_key_string, request.LANGUAGE_CODE) return JsonResponse({'ExportStatus': 1}) elif 'text/html' in requested_format: return render_to_response('export.html', context) else: # Only HTML request format is supported (no JSON). return HttpResponse(status=406)
def format_library_for_view(library, this_user=None): """ Return a dict of the data which the view requires for each library """ if this_user: user = this_user else: user = request.user return { 'display_name': library.display_name, 'library_key': unicode(library.location.library_key), 'url': reverse_library_url('library_handler', unicode(library.location.library_key)), 'org': library.display_org_with_default, 'number': library.display_number_with_default, 'can_edit': has_studio_write_access(user, library.location.library_key), }
def test_libraries_on_course_index(self): """ Test getting the list of libraries from the course listing page """ # Add a library: lib1 = LibraryFactory.create() index_url = "/home/" index_response = self.client.get(index_url, {}, HTTP_ACCEPT="text/html") parsed_html = lxml.html.fromstring(index_response.content) library_link_elements = parsed_html.find_class("library-link") self.assertEqual(len(library_link_elements), 1) link = library_link_elements[0] self.assertEqual(link.get("href"), reverse_library_url("library_handler", lib1.location.library_key)) # now test that url outline_response = self.client.get(link.get("href"), {}, HTTP_ACCEPT="text/html") self.assertEqual(outline_response.status_code, 200)
def manage_library_users(request, library_key_string): """ Studio UI for editing the users within a library. Uses the /course_team/:library_key/:user_email/ REST API to make changes. """ library_key = CourseKey.from_string(library_key_string) if not isinstance(library_key, LibraryLocator): raise Http404 # This is not a library user_perms = get_user_permissions(request.user, library_key) if not user_perms & STUDIO_VIEW_USERS: raise PermissionDenied() library = modulestore().get_library(library_key) if library is None: raise Http404 # Segment all the users explicitly associated with this library, ensuring each user only has one role listed: instructors = set(CourseInstructorRole(library_key).users_with_role()) staff = set(CourseStaffRole(library_key).users_with_role()) - instructors users = set( LibraryUserRole(library_key).users_with_role()) - instructors - staff formatted_users = [] for user in instructors: formatted_users.append(user_with_role(user, 'instructor')) for user in staff: formatted_users.append(user_with_role(user, 'staff')) for user in users: formatted_users.append(user_with_role(user, 'library_user')) return render_to_response( 'manage_users_lib.html', { 'context_library': library, 'users': formatted_users, 'allow_actions': bool(user_perms & STUDIO_EDIT_ROLES), 'library_key': unicode(library_key), 'lib_users_url': reverse_library_url('manage_library_users', library_key_string), 'show_children_previews': library.show_children_previews })
def xblock_studio_url(xblock, parent_xblock=None): """ Returns the Studio editing URL for the specified xblock. """ if not xblock_has_own_studio_page(xblock, parent_xblock): return None category = xblock.category if category == 'course': return reverse_course_url('course_handler', xblock.location.course_key) elif category in ('chapter', 'sequential'): return u'{url}?show={usage_key}'.format( url=reverse_course_url('course_handler', xblock.location.course_key), usage_key=urllib.quote(unicode(xblock.location)) ) elif category == 'library': library_key = xblock.location.course_key return reverse_library_url('library_handler', library_key) else: return reverse_usage_url('container_handler', xblock.location)
def xblock_studio_url(xblock, parent_xblock=None): """ Returns the Studio editing URL for the specified xblock. """ if not xblock_has_own_studio_page(xblock, parent_xblock): return None category = xblock.category if category == "course": return reverse_course_url("course_handler", xblock.location.course_key) elif category in ("chapter", "sequential"): return u"{url}?show={usage_key}".format( url=reverse_course_url("course_handler", xblock.location.course_key), usage_key=urllib.quote(unicode(xblock.location)), ) elif category == "library": library_key = xblock.location.course_key return reverse_library_url("library_handler", library_key) else: return reverse_usage_url("container_handler", xblock.location)
def import_handler(request, course_key_string): """ The restful handler for importing a course. GET html: return html page for import page json: not supported POST or PUT json: import a course via the .tar.gz file specified in request.FILES """ courselike_key = CourseKey.from_string(course_key_string) library = isinstance(courselike_key, LibraryLocator) if library: successful_url = reverse_library_url('library_handler', courselike_key) context_name = 'context_library' courselike_module = modulestore().get_library(courselike_key) else: successful_url = reverse_course_url('course_handler', courselike_key) context_name = 'context_course' courselike_module = modulestore().get_course(courselike_key) if not has_course_author_access(request.user, courselike_key): raise PermissionDenied() if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'): if request.method == 'GET': raise NotImplementedError('coming soon') else: return _write_chunk(request, courselike_key) elif request.method == 'GET': # assume html status_url = reverse_course_url("import_status_handler", courselike_key, kwargs={'filename': "fillerName"}) return render_to_response( 'import.html', { context_name: courselike_module, 'successful_import_redirect_url': successful_url, 'import_status_url': status_url, 'library': isinstance(courselike_key, LibraryLocator) }) else: return HttpResponseNotFound()
def import_handler(request, course_key_string): """ The restful handler for the import page. GET html: return html page for import page """ courselike_key = CourseKey.from_string(course_key_string) library = isinstance(courselike_key, LibraryLocator) if library: successful_url = reverse_library_url("library_handler", courselike_key) courselike_module = modulestore().get_library(courselike_key) context_name = "context_library" else: successful_url = reverse_course_url("course_handler", courselike_key) courselike_module = modulestore().get_course(courselike_key) context_name = "context_course" if not has_course_author_access(request.user, courselike_key): raise PermissionDenied() return render_to_response( "import.html", { context_name: courselike_module, "successful_import_redirect_url": successful_url, "import_status_url": reverse("course_import_status_handler", kwargs={ "course_key_string": unicode(courselike_key), "filename": "fillerName" }), "import_url": reverse("course_import_export_handler", kwargs={ "course_key_string": unicode(courselike_key), }), "library": library })
def import_handler(request, course_key_string): """ The restful handler for importing a course. GET html: return html page for import page json: not supported POST or PUT json: import a course via the .tar.gz file specified in request.FILES """ courselike_key = CourseKey.from_string(course_key_string) library = isinstance(courselike_key, LibraryLocator) if library: successful_url = reverse_library_url('library_handler', courselike_key) context_name = 'context_library' courselike_module = modulestore().get_library(courselike_key) else: successful_url = reverse_course_url('course_handler', courselike_key) context_name = 'context_course' courselike_module = modulestore().get_course(courselike_key) if not has_course_author_access(request.user, courselike_key): raise PermissionDenied() if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'): if request.method == 'GET': raise NotImplementedError('coming soon') else: return _write_chunk(request, courselike_key) elif request.method == 'GET': # assume html status_url = reverse_course_url( "import_status_handler", courselike_key, kwargs={'filename': "fillerName"} ) return render_to_response('import.html', { context_name: courselike_module, 'successful_import_redirect_url': successful_url, 'import_status_url': status_url, 'library': isinstance(courselike_key, LibraryLocator) }) else: return HttpResponseNotFound()
def import_handler(request, course_key_string): """ The restful handler for the import page. GET html: return html page for import page """ courselike_key = CourseKey.from_string(course_key_string) library = isinstance(courselike_key, LibraryLocator) if library: successful_url = reverse_library_url("library_handler", courselike_key) courselike_module = modulestore().get_library(courselike_key) context_name = "context_library" else: successful_url = reverse_course_url("course_handler", courselike_key) courselike_module = modulestore().get_course(courselike_key) context_name = "context_course" if not has_course_author_access(request.user, courselike_key): raise PermissionDenied() return render_to_response("import.html", { context_name: courselike_module, "successful_import_redirect_url": successful_url, "import_status_url": reverse( "course_import_status_handler", kwargs={ "course_key_string": unicode(courselike_key), "filename": "fillerName" } ), "import_url": reverse( "course_import_export_handler", kwargs={ "course_key_string": unicode(courselike_key), } ), "library": library })
def test_libraries_on_course_index(self): """ Test getting the list of libraries from the course listing page """ # Add a library: lib1 = LibraryFactory.create() index_url = '/home/' index_response = self.client.get(index_url, {}, HTTP_ACCEPT='text/html') parsed_html = lxml.html.fromstring(index_response.content) library_link_elements = parsed_html.find_class('library-link') self.assertEqual(len(library_link_elements), 1) link = library_link_elements[0] self.assertEqual( link.get("href"), reverse_library_url('library_handler', lib1.location.library_key), ) # now test that url outline_response = self.client.get(link.get("href"), {}, HTTP_ACCEPT='text/html') self.assertEqual(outline_response.status_code, 200)
def library_blocks_view(library, user, response_format): """ The main view of a course's content library. Shows all the XBlocks in the library, and allows adding/editing/deleting them. Can be called with response_format="json" to get a JSON-formatted list of the XBlocks in the library along with library metadata. Assumes that read permissions have been checked before calling this. """ assert isinstance(library.location.library_key, LibraryLocator) assert isinstance(library.location, LibraryUsageLocator) children = library.children if response_format == "json": # The JSON response for this request is short and sweet: prev_version = library.runtime.course_entry.structure['previous_version'] return JsonResponse({ "display_name": library.display_name, "library_id": unicode(library.location.library_key), "version": unicode(library.runtime.course_entry.course_key.version), "previous_version": unicode(prev_version) if prev_version else None, "blocks": [unicode(x) for x in children], }) can_edit = has_studio_write_access(user, library.location.library_key) xblock_info = create_xblock_info(library, include_ancestor_info=False, graders=[]) component_templates = get_component_templates(library, library=True) if can_edit else [] return render_to_response('library.html', { 'can_edit': can_edit, 'context_library': library, 'component_templates': json.dumps(component_templates), 'xblock_info': xblock_info, 'templates': CONTAINER_TEMPATES, 'lib_users_url': reverse_library_url('manage_library_users', unicode(library.location.library_key)), })
def export_handler(request, course_key_string): """ The restful handler for exporting a course. GET html: return html page for import page application/x-tgz: return tar.gz file containing exported course json: not supported POST Start a Celery task to export the course Note that there are 3 ways to request the tar.gz file. The Studio UI uses a POST request to start the export asynchronously, with a link appearing on the page once it's ready. Additionally, for backwards compatibility reasons the request header can specify application/x-tgz via HTTP_ACCEPT, or a query parameter can be used (?_accept=application/x-tgz); this will export the course synchronously and return the resulting file (unless the request times out for a large course). If the tar.gz file has been requested but the export operation fails, the import page will be returned including a description of the error. """ course_key = CourseKey.from_string(course_key_string) if not has_course_author_access(request.user, course_key): raise PermissionDenied() if isinstance(course_key, LibraryLocator): courselike_module = modulestore().get_library(course_key) context = { 'context_library': courselike_module, 'courselike_home_url': reverse_library_url("library_handler", course_key), 'library': True } else: courselike_module = modulestore().get_course(course_key) if courselike_module is None: raise Http404 context = { 'context_course': courselike_module, 'courselike_home_url': reverse_course_url("course_handler", course_key), 'library': False } context['status_url'] = reverse_course_url('export_status_handler', course_key) # an _accept URL parameter will be preferred over HTTP_ACCEPT in the header. requested_format = request.GET.get('_accept', request.META.get('HTTP_ACCEPT', 'text/html')) if request.method == 'POST': export_olx.delay(request.user.id, course_key_string, request.LANGUAGE_CODE) return JsonResponse({'ExportStatus': 1}) elif 'application/x-tgz' in requested_format: try: tarball = create_export_tarball(courselike_module, course_key, context) return send_tarball(tarball) except SerializationError: return render_to_response('export.html', context) elif 'text/html' in requested_format: return render_to_response('export.html', context) else: # Only HTML or x-tgz request formats are supported (no JSON). return HttpResponse(status=406)
def container_handler(request, usage_key_string): """ The restful handler for container xblock requests. GET html: returns the HTML page for editing a container json: not currently supported """ if "lib-block-v1" in usage_key_string: try: usage_key = UsageKey.from_string(usage_key_string) except InvalidKeyError: raise Http404 try: library_key_string = re.sub('lib-block-v1:(.*)\+type@.*', 'library-v1:\\1', usage_key_string) log.error("LIBRARY_KEY_STRING: %s", str(library_key_string)) library_key = CourseKey.from_string(library_key_string) log.error("LIBRARY_KEY: %s", str(library_key)) library = modulestore().get_library(library_key) except InvalidKeyError: raise Http404 xblock = modulestore().get_item(usage_key) is_unit_page = is_unit(xblock) xblock_info = create_xblock_info(xblock, include_ancestor_info=False, graders=[]) component_templates = get_component_templates(library) ancestor_xblocks = [] parent = get_parent_xblock(xblock) action = request.GET.get('action', 'view') is_unit_page = is_unit(xblock) unit = xblock if is_unit_page else None while parent and parent.category != 'course': if unit is None and is_unit(parent): unit = parent ancestor_xblocks.append(parent) parent = get_parent_xblock(parent) ancestor_xblocks.reverse() # Fetch the XBlock info for use by the container page. Note that it includes information # about the block's ancestors and siblings for use by the Unit Outline. xblock_info = create_xblock_info(xblock, include_ancestor_info=is_unit_page) if is_unit_page: add_container_page_publishing_info(xblock, xblock_info) # need to figure out where this item is in the list of children as the # preview will need this index = 1 return render_to_response( 'library_advanced_component.html', { #'context_course': course, # Needed only for display of menus at top of page. 'context_library': library, 'action': action, 'xblock': xblock, 'xblock_locator': xblock.location, 'unit': unit, 'new_unit_category': 'vertical', 'outline_url': '{url}?format=concise'.format( url=reverse_library_url('library_handler', library_key)), 'ancestor_xblocks': ancestor_xblocks, 'component_templates': component_templates, 'xblock_info': xblock_info, 'templates': CONTAINER_TEMPLATES }) elif 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): try: usage_key = UsageKey.from_string(usage_key_string) except InvalidKeyError: # Raise Http404 on invalid 'usage_key_string' raise Http404 with modulestore().bulk_operations(usage_key.course_key): try: course, xblock, lms_link, preview_lms_link = _get_item_in_course( request, usage_key) except ItemNotFoundError: return HttpResponseBadRequest() component_templates = get_component_templates(course) ancestor_xblocks = [] parent = get_parent_xblock(xblock) action = request.GET.get('action', 'view') is_unit_page = is_unit(xblock) unit = xblock if is_unit_page else None while parent and parent.category != 'course': if unit is None and is_unit(parent): unit = parent ancestor_xblocks.append(parent) parent = get_parent_xblock(parent) ancestor_xblocks.reverse() assert unit is not None, "Could not determine unit page" subsection = get_parent_xblock(unit) assert subsection is not None, "Could not determine parent subsection from unit " + unicode( unit.location) section = get_parent_xblock(subsection) assert section is not None, "Could not determine ancestor section from unit " + unicode( unit.location) # Fetch the XBlock info for use by the container page. Note that it includes information # about the block's ancestors and siblings for use by the Unit Outline. xblock_info = create_xblock_info( xblock, include_ancestor_info=is_unit_page) if is_unit_page: add_container_page_publishing_info(xblock, xblock_info) # need to figure out where this item is in the list of children as the # preview will need this index = 1 for child in subsection.get_children(): if child.location == unit.location: break index += 1 return render_to_response( 'container.html', { 'context_course': course, # Needed only for display of menus at top of page. 'action': action, 'xblock': xblock, 'xblock_locator': xblock.location, 'unit': unit, 'is_unit_page': is_unit_page, 'subsection': subsection, 'section': section, 'new_unit_category': 'vertical', 'outline_url': '{url}?format=concise'.format( url=reverse_course_url('course_handler', course.id)), 'ancestor_xblocks': ancestor_xblocks, 'component_templates': component_templates, 'xblock_info': xblock_info, 'draft_preview_link': preview_lms_link, 'published_preview_link': lms_link, 'templates': CONTAINER_TEMPLATES }) else: return HttpResponseBadRequest("Only supports HTML requests")
def export_handler(request, course_key_string): """ The restful handler for exporting a course. GET html: return html page for import page application/x-tgz: return tar.gz file containing exported course json: not supported POST Start a Celery task to export the course Note that there are 3 ways to request the tar.gz file. The Studio UI uses a POST request to start the export asynchronously, with a link appearing on the page once it's ready. Additionally, for backwards compatibility reasons the request header can specify application/x-tgz via HTTP_ACCEPT, or a query parameter can be used (?_accept=application/x-tgz); this will export the course synchronously and return the resulting file (unless the request times out for a large course). If the tar.gz file has been requested but the export operation fails, the import page will be returned including a description of the error. """ course_key = CourseKey.from_string(course_key_string) if not has_course_author_access(request.user, course_key): raise PermissionDenied() if isinstance(course_key, LibraryLocator): courselike_module = modulestore().get_library(course_key) context = { 'context_library': courselike_module, 'courselike_home_url': reverse_library_url("library_handler", course_key), 'library': True } else: courselike_module = modulestore().get_course(course_key) if courselike_module is None: raise Http404 context = { 'context_course': courselike_module, 'courselike_home_url': reverse_course_url("course_handler", course_key), 'library': False } context['status_url'] = reverse_course_url('export_status_handler', course_key) # an _accept URL parameter will be preferred over HTTP_ACCEPT in the header. requested_format = request.GET.get( '_accept', request.META.get('HTTP_ACCEPT', 'text/html')) if request.method == 'POST': export_olx.delay(request.user.id, course_key_string, request.LANGUAGE_CODE) return JsonResponse({'ExportStatus': 1}) elif 'application/x-tgz' in requested_format: try: tarball = create_export_tarball(courselike_module, course_key, context) return send_tarball(tarball) except SerializationError: return render_to_response('export.html', context) elif 'text/html' in requested_format: return render_to_response('export.html', context) else: # Only HTML or x-tgz request formats are supported (no JSON). return HttpResponse(status=406)
def export_handler(request, course_key_string): """ The restful handler for the export page. GET html: return html page for import page """ error = request.GET.get("error", None) error_message = request.GET.get("error_message", None) failed_module = request.GET.get("failed_module", None) unit = request.GET.get("unit", None) courselike_key = CourseKey.from_string(course_key_string) library = isinstance(courselike_key, LibraryLocator) if library: successful_url = reverse_library_url("library_handler", courselike_key) courselike_module = modulestore().get_library(courselike_key) context_name = "context_library" else: successful_url = reverse_course_url("course_handler", courselike_key) courselike_module = modulestore().get_course(courselike_key) context_name = "context_course" if not has_course_author_access(request.user, courselike_key): raise PermissionDenied() export_url = reverse("course_import_export_handler", kwargs={ "course_key_string": unicode(courselike_key), }) + "?accept=application/x-tgz" export_url += "&{0}".format( urlencode({ "redirect": reverse_course_url("export_handler", unicode(courselike_key)) })) if unit: try: edit_unit_url = reverse_usage_url("container_handler", unit) except (InvalidKeyError, AttributeError): log.error("Invalid parent key supplied to export view: %s", unit) return render_to_response( "export.html", { context_name: courselike_module, "export_url": export_url, "raw_err_msg": _("An invalid parent key was supplied: \"{supplied_key}\" " "is not a valid course unit.").format(supplied_key=unit), "library": library }) else: edit_unit_url = "" if error: return render_to_response( 'export.html', { context_name: courselike_module, "export_url": export_url, "in_err": error, "unit": unit, "failed_module": failed_module, "edit_unit_url": edit_unit_url, "course_home_url": successful_url, "raw_err_msg": error_message, "library": library }) else: return render_to_response( "export.html", { context_name: courselike_module, "export_url": export_url, "library": library })
def playlist_handler(request, course_key_string): #log.info("test from playlist") store = modulestore() all_libraries = [] libraries_name = [] libraries_modules = [] for library in store.get_libraries(): all_libraries.append(library) for library in all_libraries: libraries_name.append(library.display_name) #log.info(library.children) modules = [library.display_name] for children in library.children: display_name = store.get_item(children, 1).display_name modules.append(str(display_name) + "&" + str(children)) #log.info(children) libraries_modules.append(modules) #log.info(libraries_modules) course_key = CourseKey.from_string(course_key_string) export_url = reverse_course_url('playlist_handler', course_key) if not has_course_author_access(request.user, course_key): raise PermissionDenied() if isinstance(course_key, LibraryLocator): courselike_module = modulestore().get_library(course_key) context = { 'context_library': courselike_module, 'courselike_home_url': reverse_library_url("library_handler", course_key), 'library': True } else: courselike_module = modulestore().get_course(course_key) if courselike_module is None: raise Http404 context = { 'context_course': courselike_module, 'courselike_home_url': reverse_course_url("course_handler", course_key), 'library': False } context['export_url'] = export_url + '?_accept=application/x-tgz' name_string = libraries_name[0] for i in range(1,len(libraries_name)): name_string += "&" + libraries_name[i] context['libraries_display_name'] = name_string context['libraries_module'] = libraries_modules #log.info(context) # an _accept URL parameter will be preferred over HTTP_ACCEPT in the header. requested_format = request.GET.get('_accept', request.META.get('HTTP_ACCEPT', 'text/html')) if 'application/x-tgz' in requested_format: try: tarball = create_export_tarball(courselike_module, course_key, context) except SerializationError: return render_to_response('playlist.html', context) return send_tarball(tarball) elif 'text/html' in requested_format: return render_to_response('playlist.html', context) else: # Only HTML or x-tgz request formats are supported (no JSON). return HttpResponse(status=406)
def export_handler(request, course_key_string): """ The restful handler for the export page. GET html: return html page for import page """ error = request.GET.get("error", None) error_message = request.GET.get("error_message", None) failed_module = request.GET.get("failed_module", None) unit = request.GET.get("unit", None) courselike_key = CourseKey.from_string(course_key_string) library = isinstance(courselike_key, LibraryLocator) if library: successful_url = reverse_library_url("library_handler", courselike_key) courselike_module = modulestore().get_library(courselike_key) context_name = "context_library" else: successful_url = reverse_course_url("course_handler", courselike_key) courselike_module = modulestore().get_course(courselike_key) context_name = "context_course" if not has_course_author_access(request.user, courselike_key): raise PermissionDenied() export_url = reverse( "course_import_export_handler", kwargs={ "course_key_string": unicode(courselike_key), } ) + "?accept=application/x-tgz" export_url += "&{0}".format( urlencode({ "redirect": reverse_course_url( "export_handler", unicode(courselike_key) ) }) ) if unit: try: edit_unit_url = reverse_usage_url("container_handler", unit) except (InvalidKeyError, AttributeError): log.error("Invalid parent key supplied to export view: %s", unit) return render_to_response("export.html", { context_name: courselike_module, "export_url": export_url, "raw_err_msg": _( "An invalid parent key was supplied: \"{supplied_key}\" " "is not a valid course unit." ).format(supplied_key=unit), "library": library }) else: edit_unit_url = "" if error: return render_to_response('export.html', { context_name: courselike_module, "export_url": export_url, "in_err": error, "unit": unit, "failed_module": failed_module, "edit_unit_url": edit_unit_url, "course_home_url": successful_url, "raw_err_msg": error_message, "library": library }) else: return render_to_response("export.html", { context_name: courselike_module, "export_url": export_url, "library": library })