This is a public, versioned, RESTful API for importing and exporting full course content. The code was initially ripped from the existing import/export API in the CMS contentstore djangoapp and wrapped in Django Rest Framework view classes. It's a new djangoapp in the openedx directory which is largely an abstraction off the CMS Import/Export views. This PR includes configuration changes. Most notably, Studio is configured to serve the OAuth2 provider alongside the LMS. This is the initial thread on the code list: https://groups.google.com/forum/#!msg/edx-code/DmnHWmly25A/ZqjD1zb4o7oJ And this thread contains another description of the changes: https://groups.google.com/d/msg/edx-code/6dP9SEKsmqQ/Pvyn8fBDx68J There are a numerous non-covered lines, all of which are missing coverage in the CMS API this was ported from. They're mostly error conditions, such as handling of multipart file upload errors.
208 lines
9.1 KiB
Python
208 lines
9.1 KiB
Python
from django.conf import settings
|
|
from django.conf.urls import patterns, include, url
|
|
|
|
# There is a course creators admin table.
|
|
from ratelimitbackend import admin
|
|
admin.autodiscover()
|
|
|
|
# pylint: disable=bad-continuation
|
|
|
|
# Pattern to match a library key only
|
|
LIBRARY_KEY_PATTERN = r'(?P<library_key_string>library-v1:[^/+]+\+[^/+]+)'
|
|
|
|
urlpatterns = patterns(
|
|
'',
|
|
|
|
url(r'^transcripts/upload$', 'contentstore.views.upload_transcripts', name='upload_transcripts'),
|
|
url(r'^transcripts/download$', 'contentstore.views.download_transcripts', name='download_transcripts'),
|
|
url(r'^transcripts/check$', 'contentstore.views.check_transcripts', name='check_transcripts'),
|
|
url(r'^transcripts/choose$', 'contentstore.views.choose_transcripts', name='choose_transcripts'),
|
|
url(r'^transcripts/replace$', 'contentstore.views.replace_transcripts', name='replace_transcripts'),
|
|
url(r'^transcripts/rename$', 'contentstore.views.rename_transcripts', name='rename_transcripts'),
|
|
url(r'^transcripts/save$', 'contentstore.views.save_transcripts', name='save_transcripts'),
|
|
|
|
url(r'^preview/xblock/(?P<usage_key_string>.*?)/handler/(?P<handler>[^/]*)(?:/(?P<suffix>.*))?$',
|
|
'contentstore.views.preview_handler', name='preview_handler'),
|
|
|
|
url(r'^xblock/(?P<usage_key_string>.*?)/handler/(?P<handler>[^/]*)(?:/(?P<suffix>.*))?$',
|
|
'contentstore.views.component_handler', name='component_handler'),
|
|
|
|
url(r'^xblock/resource/(?P<block_type>[^/]*)/(?P<uri>.*)$',
|
|
'contentstore.views.xblock.xblock_resource', name='xblock_resource_url'),
|
|
|
|
# temporary landing page for a course
|
|
url(r'^edge/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$',
|
|
'contentstore.views.landing', name='landing'),
|
|
|
|
url(r'^not_found$', 'contentstore.views.not_found', name='not_found'),
|
|
url(r'^server_error$', 'contentstore.views.server_error', name='server_error'),
|
|
|
|
# temporary landing page for edge
|
|
url(r'^edge$', 'contentstore.views.edge', name='edge'),
|
|
# noop to squelch ajax errors
|
|
url(r'^event$', 'contentstore.views.event', name='event'),
|
|
|
|
url(r'^xmodule/', include('pipeline_js.urls')),
|
|
url(r'^heartbeat$', include('heartbeat.urls')),
|
|
|
|
url(r'^user_api/', include('openedx.core.djangoapps.user_api.legacy_urls')),
|
|
)
|
|
|
|
# User creation and updating views
|
|
urlpatterns += patterns(
|
|
'',
|
|
|
|
url(r'^create_account$', 'student.views.create_account', name='create_account'),
|
|
url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account', name='activate'),
|
|
|
|
# ajax view that actually does the work
|
|
url(r'^login_post$', 'student.views.login_user', name='login_post'),
|
|
url(r'^logout$', 'student.views.logout_user', name='logout'),
|
|
)
|
|
|
|
# restful api
|
|
urlpatterns += patterns(
|
|
'contentstore.views',
|
|
|
|
url(r'^$', 'howitworks', name='homepage'),
|
|
url(r'^howitworks$', 'howitworks'),
|
|
url(r'^signup$', 'signup', name='signup'),
|
|
url(r'^signin$', 'login_page', name='login'),
|
|
url(r'^request_course_creator$', 'request_course_creator'),
|
|
|
|
url(r'^course_team/{}(?:/(?P<email>.+))?$'.format(settings.COURSELIKE_KEY_PATTERN), 'course_team_handler'),
|
|
url(r'^course_info/{}$'.format(settings.COURSE_KEY_PATTERN), 'course_info_handler'),
|
|
url(
|
|
r'^course_info_update/{}/(?P<provided_id>\d+)?$'.format(settings.COURSE_KEY_PATTERN),
|
|
'course_info_update_handler'
|
|
),
|
|
url(r'^home/?$', 'course_listing', name='home'),
|
|
url(
|
|
r'^course/{}/search_reindex?$'.format(settings.COURSE_KEY_PATTERN),
|
|
'course_search_index_handler',
|
|
name='course_search_index_handler'
|
|
),
|
|
url(r'^course/{}?$'.format(settings.COURSE_KEY_PATTERN), 'course_handler', name='course_handler'),
|
|
url(r'^course_notifications/{}/(?P<action_state_id>\d+)?$'.format(settings.COURSE_KEY_PATTERN),
|
|
'course_notifications_handler'),
|
|
url(r'^course_rerun/{}$'.format(settings.COURSE_KEY_PATTERN), 'course_rerun_handler', name='course_rerun_handler'),
|
|
url(r'^container/{}$'.format(settings.USAGE_KEY_PATTERN), 'container_handler'),
|
|
url(r'^checklists/{}/(?P<checklist_index>\d+)?$'.format(settings.COURSE_KEY_PATTERN), 'checklists_handler'),
|
|
url(r'^orphan/{}$'.format(settings.COURSE_KEY_PATTERN), 'orphan_handler'),
|
|
url(r'^assets/{}/{}?$'.format(settings.COURSE_KEY_PATTERN, settings.ASSET_KEY_PATTERN), 'assets_handler'),
|
|
url(r'^import/{}$'.format(settings.COURSELIKE_KEY_PATTERN), 'import_handler'),
|
|
url(r'^export/{}$'.format(settings.COURSELIKE_KEY_PATTERN), 'export_handler'),
|
|
url(r'^xblock/outline/{}$'.format(settings.USAGE_KEY_PATTERN), 'xblock_outline_handler'),
|
|
url(r'^xblock/container/{}$'.format(settings.USAGE_KEY_PATTERN), 'xblock_container_handler'),
|
|
url(r'^xblock/{}/(?P<view_name>[^/]+)$'.format(settings.USAGE_KEY_PATTERN), 'xblock_view_handler'),
|
|
url(r'^xblock/{}?$'.format(settings.USAGE_KEY_PATTERN), 'xblock_handler'),
|
|
url(r'^tabs/{}$'.format(settings.COURSE_KEY_PATTERN), 'tabs_handler'),
|
|
url(r'^settings/details/{}$'.format(settings.COURSE_KEY_PATTERN), 'settings_handler'),
|
|
url(r'^settings/grading/{}(/)?(?P<grader_index>\d+)?$'.format(settings.COURSE_KEY_PATTERN), 'grading_handler'),
|
|
url(r'^settings/advanced/{}$'.format(settings.COURSE_KEY_PATTERN), 'advanced_settings_handler'),
|
|
url(r'^textbooks/{}$'.format(settings.COURSE_KEY_PATTERN), 'textbooks_list_handler'),
|
|
url(r'^textbooks/{}/(?P<textbook_id>\d[^/]*)$'.format(settings.COURSE_KEY_PATTERN), 'textbooks_detail_handler'),
|
|
url(r'^videos/{}$'.format(settings.COURSE_KEY_PATTERN), 'videos_handler'),
|
|
url(r'^video_encodings_download/{}$'.format(settings.COURSE_KEY_PATTERN), 'video_encodings_download'),
|
|
url(r'^group_configurations/{}$'.format(settings.COURSE_KEY_PATTERN), 'group_configurations_list_handler'),
|
|
url(r'^group_configurations/{}/(?P<group_configuration_id>\d+)(/)?(?P<group_id>\d+)?$'.format(
|
|
settings.COURSE_KEY_PATTERN), 'group_configurations_detail_handler'),
|
|
|
|
url(r'^api/val/v0/', include('edxval.urls')),
|
|
|
|
# Import/Export API
|
|
url(r'^api/import_export/v1/', include('openedx.core.djangoapps.import_export.urls')),
|
|
)
|
|
|
|
JS_INFO_DICT = {
|
|
'domain': 'djangojs',
|
|
# We need to explicitly include external Django apps that are not in LOCALE_PATHS.
|
|
'packages': ('openassessment',),
|
|
}
|
|
|
|
urlpatterns += patterns(
|
|
'',
|
|
# Serve catalog of localized strings to be rendered by Javascript
|
|
url(r'^i18n.js$', 'django.views.i18n.javascript_catalog', JS_INFO_DICT),
|
|
)
|
|
|
|
if settings.FEATURES.get('ENABLE_CONTENT_LIBRARIES'):
|
|
urlpatterns += (
|
|
url(r'^library/{}?$'.format(LIBRARY_KEY_PATTERN),
|
|
'contentstore.views.library_handler', name='library_handler'),
|
|
url(r'^library/{}/team/$'.format(LIBRARY_KEY_PATTERN),
|
|
'contentstore.views.manage_library_users', name='manage_library_users'),
|
|
)
|
|
|
|
if settings.FEATURES.get('ENABLE_EXPORT_GIT'):
|
|
urlpatterns += (url(
|
|
r'^export_git/{}$'.format(
|
|
settings.COURSE_KEY_PATTERN,
|
|
),
|
|
'contentstore.views.export_git',
|
|
name='export_git',
|
|
),)
|
|
|
|
if settings.FEATURES.get('ENABLE_SERVICE_STATUS'):
|
|
urlpatterns += patterns(
|
|
'',
|
|
url(r'^status/', include('service_status.urls')),
|
|
)
|
|
|
|
if settings.FEATURES.get('AUTH_USE_CAS'):
|
|
urlpatterns += (
|
|
url(r'^cas-auth/login/$', 'external_auth.views.cas_login', name="cas-login"),
|
|
url(r'^cas-auth/logout/$', 'django_cas.views.logout', {'next_page': '/'}, name="cas-logout"),
|
|
)
|
|
|
|
|
|
if settings.FEATURES.get('ENABLE_OAUTH2_PROVIDER'):
|
|
urlpatterns += (
|
|
url(r'^oauth2/', include('oauth2_provider.urls', namespace='oauth2')),
|
|
)
|
|
|
|
urlpatterns += patterns('', url(r'^admin/', include(admin.site.urls)),)
|
|
|
|
# enable automatic login
|
|
if settings.FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING'):
|
|
urlpatterns += (
|
|
url(r'^auto_auth$', 'student.views.auto_auth'),
|
|
)
|
|
|
|
# enable entrance exams
|
|
if settings.FEATURES.get('ENTRANCE_EXAMS'):
|
|
urlpatterns += (
|
|
url(r'^course/{}/entrance_exam/?$'.format(settings.COURSE_KEY_PATTERN), 'contentstore.views.entrance_exam'),
|
|
)
|
|
|
|
# Enable Web/HTML Certificates
|
|
if settings.FEATURES.get('CERTIFICATES_HTML_VIEW'):
|
|
urlpatterns += (
|
|
url(r'^certificates/activation/{}/'.format(settings.COURSE_KEY_PATTERN),
|
|
'contentstore.views.certificates.certificate_activation_handler'),
|
|
url(r'^certificates/{}/(?P<certificate_id>\d+)/signatories/(?P<signatory_id>\d+)?$'.format(
|
|
settings.COURSE_KEY_PATTERN), 'contentstore.views.certificates.signatory_detail_handler'),
|
|
url(r'^certificates/{}/(?P<certificate_id>\d+)?$'.format(settings.COURSE_KEY_PATTERN),
|
|
'contentstore.views.certificates.certificates_detail_handler'),
|
|
url(r'^certificates/{}$'.format(settings.COURSE_KEY_PATTERN),
|
|
'contentstore.views.certificates.certificates_list_handler')
|
|
)
|
|
|
|
if settings.DEBUG:
|
|
try:
|
|
from .urls_dev import urlpatterns as dev_urlpatterns
|
|
urlpatterns += dev_urlpatterns
|
|
except ImportError:
|
|
pass
|
|
|
|
# Custom error pages
|
|
# pylint: disable=invalid-name
|
|
handler404 = 'contentstore.views.render_404'
|
|
handler500 = 'contentstore.views.render_500'
|
|
|
|
# display error page templates, for testing purposes
|
|
urlpatterns += (
|
|
url(r'404', handler404),
|
|
url(r'500', handler500),
|
|
)
|