urls.py 27 KB
Newer Older
Piotr Mitros committed
1
from django.conf import settings
2
from django.conf.urls import patterns, include, url
Diana Huang committed
3
from ratelimitbackend import admin
4
from django.conf.urls.static import static
5

6
import django.contrib.auth.views
7 8
from microsite_configuration import microsite

Piotr Mitros committed
9
# Uncomment the next two lines to enable the admin:
10
if settings.DEBUG or settings.FEATURES.get('ENABLE_DJANGO_ADMIN_SITE'):
11
    admin.autodiscover()
Piotr Mitros committed
12

David Baumgold committed
13
urlpatterns = ('',  # nopep8
14 15
    # certificate view
    url(r'^update_certificate$', 'certificates.views.update_certificate'),
16
    url(r'^request_certificate$', 'certificates.views.request_certificate'),
Calen Pennington committed
17
    url(r'^$', 'branding.views.index', name="root"),   # Main marketing page, or redirect to courseware
18
    url(r'^dashboard$', 'student.views.dashboard', name="dashboard"),
19 20
    url(r'^login_ajax$', 'student.views.login_user', name="login"),
    url(r'^login_ajax/(?P<error>[^/]*)$', 'student.views.login_user'),
21 22
    url(r'^login$', 'student.views.signin_user', name="signin_user"),
    url(r'^register$', 'student.views.register_user', name="register_user"),
23

24
    url(r'^admin_dashboard$', 'dashboard.views.dashboard'),
25

26
    url(r'^change_email$', 'student.views.change_email_request', name="change_email"),
27
    url(r'^email_confirm/(?P<key>[^/]*)$', 'student.views.confirm_email_change'),
28
    url(r'^change_name$', 'student.views.change_name_request', name="change_name"),
29 30 31
    url(r'^accept_name_change$', 'student.views.accept_name_change'),
    url(r'^reject_name_change$', 'student.views.reject_name_change'),
    url(r'^pending_name_changes$', 'student.views.pending_name_changes'),
32
    url(r'^event$', 'track.views.user_track'),
33
    url(r'^segmentio/event$', 'track.views.segmentio.segmentio_event'),
Calen Pennington committed
34
    url(r'^t/(?P<template>[^/]*)$', 'static_template_view.views.index'),   # TODO: Is this used anymore? What is STATIC_GRAB?
35

36
    url(r'^accounts/login$', 'student.views.accounts_login', name="accounts_login"),
37 38 39 40
    url(r'^accounts/manage_user_standing', 'student.views.manage_user_standing',
        name='manage_user_standing'),
    url(r'^accounts/disable_account_ajax$', 'student.views.disable_account_ajax',
        name="disable_account_ajax"),
41

42
    url(r'^logout$', 'student.views.logout_user', name='logout'),
43
    url(r'^create_account$', 'student.views.create_account', name='create_account'),
44 45
    url(r'^activate/(?P<key>[^/]*)$', 'student.views.activate_account', name="activate"),

46
    url(r'^password_reset/$', 'student.views.password_reset', name='password_reset'),
47 48
    ## Obsolete Django views for password resets
    ## TODO: Replace with Mako-ized views
49 50 51 52 53
    url(r'^password_change/$', django.contrib.auth.views.password_change,
        name='auth_password_change'),
    url(r'^password_change_done/$', django.contrib.auth.views.password_change_done,
        name='auth_password_change_done'),
    url(r'^password_reset_confirm/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/$',
54
        'student.views.password_reset_confirm_wrapper',
Piotr Mitros committed
55
        name='auth_password_reset_confirm'),
56
    url(r'^password_reset_complete/$', django.contrib.auth.views.password_reset_complete,
Piotr Mitros committed
57
        name='auth_password_reset_complete'),
58
    url(r'^password_reset_done/$', django.contrib.auth.views.password_reset_done,
Piotr Mitros committed
59
        name='auth_password_reset_done'),
60

61
    url(r'^heartbeat$', include('heartbeat.urls')),
62

63
    url(r'^user_api/', include('openedx.core.djangoapps.user_api.urls')),
64

65 66
    url(r'^notifier_api/', include('notifier_api.urls')),

67 68
    url(r'^lang_pref/', include('lang_pref.urls')),

69
    url(r'^i18n/', include('django.conf.urls.i18n')),
70 71

    url(r'^embargo$', 'student.views.embargo', name="embargo"),
72

73 74
    # Feedback Form endpoint
    url(r'^submit_feedback$', 'util.views.submit_feedback'),
75

76
    # Enrollment API RESTful endpoints
77
    url(r'^api/enrollment/v1/', include('enrollment.urls')),
78

79 80 81
    # CourseInfo API RESTful endpoints
    url(r'^api/course/details/v0/', include('course_about.urls')),

82
)
83

84 85 86
if settings.FEATURES["ENABLE_MOBILE_REST_API"]:
    urlpatterns += (
        url(r'^api/mobile/v0.5/', include('mobile_api.urls')),
87 88
        # Video Abstraction Layer used to allow video teams to manage video assets
        # independently of courseware. https://github.com/edx/edx-val
89 90 91
        url(r'^api/val/v0/', include('edxval.urls')),
    )

92
# if settings.FEATURES.get("MULTIPLE_ENROLLMENT_ROLES"):
93 94 95 96
urlpatterns += (
    url(r'^verify_student/', include('verify_student.urls')),
    url(r'^course_modes/', include('course_modes.urls')),
)
97 98


99 100
js_info_dict = {
    'domain': 'djangojs',
101 102
    # We need to explicitly include external Django apps that are not in LOCALE_PATHS.
    'packages': ('openassessment',),
103 104 105 106 107 108 109
}

urlpatterns += (
    # Serve catalog of localized strings to be rendered by Javascript
    url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)

Carson Gee committed
110 111 112 113 114 115
# sysadmin dashboard, to see what courses are loaded, to delete & load courses
if settings.FEATURES["ENABLE_SYSADMIN_DASHBOARD"]:
    urlpatterns += (
        url(r'^sysadmin/', include('dashboard.sysadmin_urls')),
    )

116
urlpatterns += (
117
    url(r'^support/', include('dashboard.support_urls')),
118 119
)

120 121
#Semi-static views (these need to be rendered and have the login bar, but don't change)
urlpatterns += (
122
    url(r'^404$', 'static_template_view.views.render',
123
        {'template': '404.html'}, name="404"),
Piotr Mitros committed
124 125
)

126 127 128 129 130
# Favicon
favicon_path = microsite.get_value('favicon_path', settings.FAVICON_PATH)
urlpatterns += ((
    r'^favicon\.ico$',
    'django.views.generic.simple.redirect_to',
131
    {'url': settings.STATIC_URL + favicon_path}
132 133
),)

134
# Semi-static views only used by edX, not by themes
135
if not settings.FEATURES["USE_CUSTOM_THEME"]:
136
    urlpatterns += (
137 138 139 140 141 142 143 144 145 146
        url(r'^blog$', 'static_template_view.views.render',
            {'template': 'blog.html'}, name="blog"),
        url(r'^contact$', 'static_template_view.views.render',
            {'template': 'contact.html'}, name="contact"),
        url(r'^donate$', 'static_template_view.views.render',
            {'template': 'donate.html'}, name="donate"),
        url(r'^faq$', 'static_template_view.views.render',
            {'template': 'faq.html'}, name="faq"),
        url(r'^help$', 'static_template_view.views.render',
            {'template': 'help.html'}, name="help_edx"),
147 148
        url(r'^jobs$', 'static_template_view.views.render',
            {'template': 'jobs.html'}, name="jobs"),
149 150 151 152
        url(r'^news$', 'static_template_view.views.render',
            {'template': 'news.html'}, name="news"),
        url(r'^press$', 'static_template_view.views.render',
            {'template': 'press.html'}, name="press"),
153 154 155 156 157 158 159
        url(r'^media-kit$', 'static_template_view.views.render',
            {'template': 'media-kit.html'}, name="media-kit"),

        # TODO: (bridger) The copyright has been removed until it is updated for edX
        # url(r'^copyright$', 'static_template_view.views.render',
        #     {'template': 'copyright.html'}, name="copyright"),

160
        # Press releases
161
        url(r'^press/([_a-zA-Z0-9-]+)$', 'static_template_view.views.render_press_release', name='press_release'),
162
    )
163 164 165 166 167 168 169 170 171

# Only enable URLs for those marketing links actually enabled in the
# settings. Disable URLs by marking them as None.
for key, value in settings.MKTG_URL_LINK_MAP.items():
    # Skip disabled URLs
    if value is None:
        continue

    # These urls are enabled separately
172
    if key == "ROOT" or key == "COURSES":
173 174 175 176 177 178 179 180
        continue

    # Make the assumptions that the templates are all in the same dir
    # and that they all match the name of the key (plus extension)
    template = "%s.html" % key.lower()

    # To allow theme templates to inherit from default templates,
    # prepend a standard prefix
181
    if settings.FEATURES["USE_CUSTOM_THEME"]:
182 183 184 185
        template = "theme-" + template

    # Make the assumption that the URL we want is the lowercased
    # version of the map key
186
    urlpatterns += (url(r'^%s$' % key.lower(),
187 188 189 190
                        'static_template_view.views.render',
                        {'template': template}, name=value),)


191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
# Multicourse wiki (Note: wiki urls must be above the courseware ones because of
# the custom tab catch-all)
if settings.WIKI_ENABLED:
    from wiki.urls import get_pattern as wiki_pattern
    from django_notify.urls import get_pattern as notify_pattern

    urlpatterns += (
        # First we include views from course_wiki that we use to override the default views.
        # They come first in the urlpatterns so they get resolved first
        url('^wiki/create-root/$', 'course_wiki.views.root_create', name='root_create'),
        url(r'^wiki/', include(wiki_pattern())),
        url(r'^notify/', include(notify_pattern())),

        # These urls are for viewing the wiki in the context of a course. They should
        # never be returned by a reverse() so they come after the other url patterns
206
        url(r'^courses/{}/course_wiki/?$'.format(settings.COURSE_ID_PATTERN),
207
            'course_wiki.views.course_wiki_redirect', name="course_wiki"),
208
        url(r'^courses/{}/wiki/'.format(settings.COURSE_KEY_REGEX), include(wiki_pattern())),
209 210
    )

Piotr Mitros committed
211
if settings.COURSEWARE_ENABLED:
212
    urlpatterns += (
213
        url(r'^courses/{}/jump_to/(?P<location>.*)$'.format(settings.COURSE_ID_PATTERN),
214
            'courseware.views.jump_to', name="jump_to"),
215
        url(r'^courses/{}/jump_to_id/(?P<module_id>.*)$'.format(settings.COURSE_ID_PATTERN),
216
            'courseware.views.jump_to_id', name="jump_to_id"),
217
        url(r'^courses/{course_key}/xblock/{usage_key}/handler/(?P<handler>[^/]*)(?:/(?P<suffix>.*))?$'.format(course_key=settings.COURSE_ID_PATTERN, usage_key=settings.USAGE_ID_PATTERN),
218 219
            'courseware.module_render.handle_xblock_callback',
            name='xblock_handler'),
220
        url(r'^courses/{course_key}/xblock/{usage_key}/handler_noauth/(?P<handler>[^/]*)(?:/(?P<suffix>.*))?$'.format(course_key=settings.COURSE_ID_PATTERN, usage_key=settings.USAGE_ID_PATTERN),
221 222
            'courseware.module_render.handle_xblock_callback_noauth',
            name='xblock_handler_noauth'),
223 224 225
        url(r'xblock/resource/(?P<block_type>[^/]+)/(?P<uri>.*)$',
            'courseware.module_render.xblock_resource',
            name='xblock_resource_url'),
226

227 228 229 230 231 232 233 234
        # Software Licenses

        # TODO: for now, this is the endpoint of an ajax replay
        # service that retrieve and assigns license numbers for
        # software assigned to a course. The numbers have to be loaded
        # into the database.
        url(r'^software-licenses$', 'licenses.views.user_software_license', name="user_software_license"),

235
        url(r'^courses/{}/xqueue/(?P<userid>[^/]*)/(?P<mod_id>.*?)/(?P<dispatch>[^/]*)$'.format(settings.COURSE_ID_PATTERN),
236 237
            'courseware.module_render.xqueue_callback',
            name='xqueue_callback'),
238 239
        url(r'^change_setting$', 'student.views.change_setting',
            name='change_setting'),
240

241
        # TODO: These views need to be updated before they work
242
        url(r'^calculate$', 'util.views.calculate'),
243 244 245
        # TODO: We should probably remove the circuit package. I believe it was only used in the old way of saving wiki circuits for the wiki
        # url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'),
        # url(r'^save_circuit/(?P<circuit>[^/]*)$', 'circuit.views.save_circuit'),
246

247
        url(r'^courses/?$', 'branding.views.courses', name="courses"),
248
        url(r'^change_enrollment$',
249
            'student.views.change_enrollment', name="change_enrollment"),
250
        url(r'^change_email_settings$', 'student.views.change_email_settings', name="change_email_settings"),
251

252
        #About the course
253
        url(r'^courses/{}/about$'.format(settings.COURSE_ID_PATTERN),
254
            'courseware.views.course_about', name="about_course"),
255
        #View for mktg site (kept for backwards compatibility TODO - remove before merge to master)
256
        url(r'^courses/{}/mktg-about$'.format(settings.COURSE_ID_PATTERN),
John Jarvis committed
257
            'courseware.views.mktg_course_about', name="mktg_about_course"),
258
        #View for mktg site
259
        url(r'^mktg/{}/?$'.format(settings.COURSE_ID_PATTERN),
260 261
            'courseware.views.mktg_course_about', name="mktg_about_course"),

262
        #Inside the course
263
        url(r'^courses/{}/$'.format(settings.COURSE_ID_PATTERN),
264
            'courseware.views.course_info', name="course_root"),
265
        url(r'^courses/{}/info$'.format(settings.COURSE_ID_PATTERN),
266
            'courseware.views.course_info', name="info"),
267
        url(r'^courses/{}/syllabus$'.format(settings.COURSE_ID_PATTERN),
Calen Pennington committed
268
            'courseware.views.syllabus', name="syllabus"),   # TODO arjun remove when custom tabs in place, see courseware/courses.py
269

270 271 272 273
        #Survey associated with a course
        url(r'^courses/{}/survey$'.format(settings.COURSE_ID_PATTERN),
            'courseware.views.course_survey', name="course_survey"),

274
        url(r'^courses/{}/book/(?P<book_index>\d+)/$'.format(settings.COURSE_ID_PATTERN),
275
            'staticbook.views.index', name="book"),
276
        url(r'^courses/{}/book/(?P<book_index>\d+)/(?P<page>\d+)$'.format(settings.COURSE_ID_PATTERN),
277
            'staticbook.views.index', name="book"),
Brian Wilson committed
278

279
        url(r'^courses/{}/pdfbook/(?P<book_index>\d+)/$'.format(settings.COURSE_ID_PATTERN),
Brian Wilson committed
280
            'staticbook.views.pdf_index', name="pdf_book"),
281
        url(r'^courses/{}/pdfbook/(?P<book_index>\d+)/(?P<page>\d+)$'.format(settings.COURSE_ID_PATTERN),
282
            'staticbook.views.pdf_index', name="pdf_book"),
Brian Wilson committed
283

284
        url(r'^courses/{}/pdfbook/(?P<book_index>\d+)/chapter/(?P<chapter>\d+)/$'.format(settings.COURSE_ID_PATTERN),
285
            'staticbook.views.pdf_index', name="pdf_book"),
286
        url(r'^courses/{}/pdfbook/(?P<book_index>\d+)/chapter/(?P<chapter>\d+)/(?P<page>\d+)$'.format(settings.COURSE_ID_PATTERN),
287
            'staticbook.views.pdf_index', name="pdf_book"),
Brian Wilson committed
288

289
        url(r'^courses/{}/htmlbook/(?P<book_index>\d+)/$'.format(settings.COURSE_ID_PATTERN),
290
            'staticbook.views.html_index', name="html_book"),
291
        url(r'^courses/{}/htmlbook/(?P<book_index>\d+)/chapter/(?P<chapter>\d+)/$'.format(settings.COURSE_ID_PATTERN),
292
            'staticbook.views.html_index', name="html_book"),
293

294
        url(r'^courses/{}/courseware/?$'.format(settings.COURSE_ID_PATTERN),
295
            'courseware.views.index', name="courseware"),
296
        url(r'^courses/{}/courseware/(?P<chapter>[^/]*)/$'.format(settings.COURSE_ID_PATTERN),
297
            'courseware.views.index', name="courseware_chapter"),
298
        url(r'^courses/{}/courseware/(?P<chapter>[^/]*)/(?P<section>[^/]*)/$'.format(settings.COURSE_ID_PATTERN),
299
            'courseware.views.index', name="courseware_section"),
300
        url(r'^courses/{}/courseware/(?P<chapter>[^/]*)/(?P<section>[^/]*)/(?P<position>[^/]*)/?$'.format(settings.COURSE_ID_PATTERN),
301
            'courseware.views.index', name="courseware_position"),
Brian Wilson committed
302

303
        url(r'^courses/{}/progress$'.format(settings.COURSE_ID_PATTERN),
304
            'courseware.views.progress', name="progress"),
305
        # Takes optional student_id for instructor use--shows profile as that student sees it.
306
        url(r'^courses/{}/progress/(?P<student_id>[^/]*)/$'.format(settings.COURSE_ID_PATTERN),
307
            'courseware.views.progress', name="student_progress"),
308

309
        # For the instructor
310
        url(r'^courses/{}/instructor$'.format(settings.COURSE_ID_PATTERN),
311
            'instructor.views.instructor_dashboard.instructor_dashboard_2', name="instructor_dashboard"),
312 313
        url(r'^courses/{}/set_course_mode_price$'.format(settings.COURSE_ID_PATTERN),
            'instructor.views.instructor_dashboard.set_course_mode_price', name="set_course_mode_price"),
314
        url(r'^courses/{}/instructor/api/'.format(settings.COURSE_ID_PATTERN),
315
            include('instructor.views.api_urls')),
316 317 318 319 320 321 322 323
        url(r'^courses/{}/remove_coupon$'.format(settings.COURSE_ID_PATTERN),
            'instructor.views.coupons.remove_coupon', name="remove_coupon"),
        url(r'^courses/{}/add_coupon$'.format(settings.COURSE_ID_PATTERN),
            'instructor.views.coupons.add_coupon', name="add_coupon"),
        url(r'^courses/{}/update_coupon$'.format(settings.COURSE_ID_PATTERN),
            'instructor.views.coupons.update_coupon', name="update_coupon"),
        url(r'^courses/{}/get_coupon_info$'.format(settings.COURSE_ID_PATTERN),
            'instructor.views.coupons.get_coupon_info', name="get_coupon_info"),
324

325
        # see ENABLE_INSTRUCTOR_LEGACY_DASHBOARD section for legacy dash urls
326

327
        # Open Ended grading views
328
        url(r'^courses/{}/staff_grading$'.format(settings.COURSE_ID_PATTERN),
329
            'open_ended_grading.views.staff_grading', name='staff_grading'),
330
        url(r'^courses/{}/staff_grading/get_next$'.format(settings.COURSE_ID_PATTERN),
331
            'open_ended_grading.staff_grading_service.get_next', name='staff_grading_get_next'),
332
        url(r'^courses/{}/staff_grading/save_grade$'.format(settings.COURSE_ID_PATTERN),
333
            'open_ended_grading.staff_grading_service.save_grade', name='staff_grading_save_grade'),
334
        url(r'^courses/{}/staff_grading/get_problem_list$'.format(settings.COURSE_ID_PATTERN),
335
            'open_ended_grading.staff_grading_service.get_problem_list', name='staff_grading_get_problem_list'),
336

337
        # Open Ended problem list
338
        url(r'^courses/{}/open_ended_problems$'.format(settings.COURSE_ID_PATTERN),
339
            'open_ended_grading.views.student_problem_list', name='open_ended_problems'),
340 341

        # Open Ended flagged problem list
342
        url(r'^courses/{}/open_ended_flagged_problems$'.format(settings.COURSE_ID_PATTERN),
343
            'open_ended_grading.views.flagged_problem_list', name='open_ended_flagged_problems'),
344
        url(r'^courses/{}/open_ended_flagged_problems/take_action_on_flags$'.format(settings.COURSE_ID_PATTERN),
345
            'open_ended_grading.views.take_action_on_flags', name='open_ended_flagged_problems_take_action'),
Calen Pennington committed
346

347
        # Cohorts management
348 349
        url(r'^courses/{}/cohorts/(?P<cohort_id>[0-9]+)?$'.format(settings.COURSE_KEY_PATTERN),
            'openedx.core.djangoapps.course_groups.views.cohort_handler', name="cohorts"),
350
        url(r'^courses/{}/cohorts/(?P<cohort_id>[0-9]+)$'.format(settings.COURSE_KEY_PATTERN),
351
            'openedx.core.djangoapps.course_groups.views.users_in_cohort',
352
            name="list_cohort"),
353
        url(r'^courses/{}/cohorts/(?P<cohort_id>[0-9]+)/add$'.format(settings.COURSE_KEY_PATTERN),
354
            'openedx.core.djangoapps.course_groups.views.add_users_to_cohort',
355
            name="add_to_cohort"),
356
        url(r'^courses/{}/cohorts/(?P<cohort_id>[0-9]+)/delete$'.format(settings.COURSE_KEY_PATTERN),
357
            'openedx.core.djangoapps.course_groups.views.remove_user_from_cohort',
358
            name="remove_from_cohort"),
359
        url(r'^courses/{}/cohorts/debug$'.format(settings.COURSE_KEY_PATTERN),
360
            'openedx.core.djangoapps.course_groups.views.debug_cohort_mgmt',
361 362
            name="debug_cohort_mgmt"),

363
        # Open Ended Notifications
364
        url(r'^courses/{}/open_ended_notifications$'.format(settings.COURSE_ID_PATTERN),
365
            'open_ended_grading.views.combined_notifications', name='open_ended_notifications'),
366

367
        url(r'^courses/{}/peer_grading$'.format(settings.COURSE_ID_PATTERN),
368
            'open_ended_grading.views.peer_grading', name='peer_grading'),
369

370 371
        url(r'^courses/{}/notes$'.format(settings.COURSE_ID_PATTERN), 'notes.views.notes', name='notes'),
        url(r'^courses/{}/notes/'.format(settings.COURSE_ID_PATTERN), include('notes.urls')),
372

373
        # LTI endpoints listing
374
        url(r'^courses/{}/lti_rest_endpoints/'.format(settings.COURSE_ID_PATTERN),
375
            'courseware.views.get_course_lti_endpoints', name='lti_rest_endpoints'),
376 377 378 379

        # Student account and profile
        url(r'^account/', include('student_account.urls')),
        url(r'^profile/', include('student_profile.urls')),
380 381 382 383

        # Student Notes
        url(r'^courses/{}/edxnotes'.format(settings.COURSE_ID_PATTERN),
            include('edxnotes.urls'), name="edxnotes_endpoints"),
384
    )
385

386
    # allow course staff to change to student view of courseware
387
    if settings.FEATURES.get('ENABLE_MASQUERADE'):
388
        urlpatterns += (
389 390
            url(r'^courses/{}/masquerade$'.format(settings.COURSE_KEY_PATTERN),
                'courseware.masquerade.handle_ajax', name="masquerade_update"),
391 392
        )

393
    # discussion forums live within courseware, so courseware must be enabled first
394
    if settings.FEATURES.get('ENABLE_DISCUSSION_SERVICE'):
395
        urlpatterns += (
396
            url(r'^courses/{}/discussion/'.format(settings.COURSE_ID_PATTERN),
397 398 399
                include('django_comment_client.urls')),
            url(r'^notification_prefs/enable/', 'notification_prefs.views.ajax_enable'),
            url(r'^notification_prefs/disable/', 'notification_prefs.views.ajax_disable'),
400
            url(r'^notification_prefs/status/', 'notification_prefs.views.ajax_status'),
401 402
            url(r'^notification_prefs/unsubscribe/(?P<token>[a-zA-Z0-9-_=]+)/',
                'notification_prefs.views.set_subscription', {'subscribe': False}, name="unsubscribe_forum_update"),
403
            url(r'^notification_prefs/resubscribe/(?P<token>[a-zA-Z0-9-_=]+)/',
404
                'notification_prefs.views.set_subscription', {'subscribe': True}, name="resubscribe_forum_update"),
David Baumgold committed
405
        )
406 407
    urlpatterns += (
        # This MUST be the last view in the courseware--it's a catch-all for custom tabs.
408
        url(r'^courses/{}/(?P<tab_slug>[^/]+)/$'.format(settings.COURSE_ID_PATTERN),
409
            'courseware.views.static_tab', name="static_tab"),
David Baumgold committed
410
    )
411

412
    if settings.FEATURES.get('ENABLE_STUDENT_HISTORY_VIEW'):
413
        urlpatterns += (
414
            url(r'^courses/{}/submission_history/(?P<student_username>[^/]*)/(?P<location>.*?)$'.format(settings.COURSE_ID_PATTERN),
415 416 417 418
                'courseware.views.submission_history',
                name='submission_history'),
        )

419

420
if settings.COURSEWARE_ENABLED and settings.FEATURES.get('ENABLE_INSTRUCTOR_LEGACY_DASHBOARD'):
421
    urlpatterns += (
422
        url(r'^courses/{}/legacy_instructor_dash$'.format(settings.COURSE_ID_PATTERN),
423
            'instructor.views.legacy.instructor_dashboard', name="instructor_dashboard_legacy"),
424
    )
425

426 427
if settings.FEATURES.get('CLASS_DASHBOARD'):
    urlpatterns += (
428
        url(r'^class_dashboard/', include('class_dashboard.urls')),
429 430
    )

431
if settings.DEBUG or settings.FEATURES.get('ENABLE_DJANGO_ADMIN_SITE'):
432
    ## Jasmine and admin
433
    urlpatterns += (url(r'^admin/', include(admin.site.urls)),)
434

435
if settings.FEATURES.get('AUTH_USE_OPENID'):
ichuang committed
436 437
    urlpatterns += (
        url(r'^openid/login/$', 'django_openid_auth.views.login_begin', name='openid-login'),
438
        url(r'^openid/complete/$', 'external_auth.views.openid_login_complete', name='openid-complete'),
ichuang committed
439
        url(r'^openid/logo.gif$', 'django_openid_auth.views.logo', name='openid-logo'),
440 441
    )

442
if settings.FEATURES.get('AUTH_USE_SHIB'):
443 444 445 446
    urlpatterns += (
        url(r'^shib-login/$', 'external_auth.views.shib_login', name='shib-login'),
    )

447
if settings.FEATURES.get('AUTH_USE_CAS'):
448 449 450 451 452
    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"),
    )

453
if settings.FEATURES.get('RESTRICT_ENROLL_BY_REG_METHOD'):
454
    urlpatterns += (
455
        url(r'^course_specific_login/{}/$'.format(settings.COURSE_ID_PATTERN),
456
            'external_auth.views.course_specific_login', name='course-specific-login'),
457
        url(r'^course_specific_register/{}/$'.format(settings.COURSE_ID_PATTERN),
458 459 460 461
            'external_auth.views.course_specific_register', name='course-specific-register'),

    )

462 463
# Shopping cart
urlpatterns += (
464
    url(r'^shoppingcart/', include('shoppingcart.urls')),
465 466
)

467 468 469 470
# Survey Djangoapp
urlpatterns += (
    url(r'^survey/', include('survey.urls')),
)
471

472
if settings.FEATURES.get('AUTH_USE_OPENID_PROVIDER'):
473
    urlpatterns += (
474
        url(r'^openid/provider/login/$', 'external_auth.views.provider_login', name='openid-provider-login'),
475
        url(r'^openid/provider/login/(?:.+)$', 'external_auth.views.provider_identity', name='openid-provider-login-identity'),
476 477
        url(r'^openid/provider/identity/$', 'external_auth.views.provider_identity', name='openid-provider-identity'),
        url(r'^openid/provider/xrds/$', 'external_auth.views.provider_xrds', name='openid-provider-xrds')
478
    )
ichuang committed
479

480 481 482 483 484 485
if settings.FEATURES.get('ENABLE_OAUTH2_PROVIDER'):
    urlpatterns += (
        url(r'^oauth2/', include('oauth2_provider.urls', namespace='oauth2')),
    )


486
if settings.FEATURES.get('ENABLE_LMS_MIGRATION'):
487 488 489
    urlpatterns += (
        url(r'^migrate/modules$', 'lms_migration.migrate.manage_modulestores'),
        url(r'^migrate/reload/(?P<reload_dir>[^/]+)$', 'lms_migration.migrate.manage_modulestores'),
490
        url(r'^migrate/reload/(?P<reload_dir>[^/]+)/(?P<commit_id>[^/]+)$', 'lms_migration.migrate.manage_modulestores'),
491 492
        url(r'^gitreload$', 'lms_migration.migrate.gitreload'),
        url(r'^gitreload/(?P<reload_dir>[^/]+)$', 'lms_migration.migrate.gitreload'),
David Baumgold committed
493
    )
494

495
if settings.FEATURES.get('ENABLE_SQL_TRACKING_LOGS'):
496 497
    urlpatterns += (
        url(r'^event_logs$', 'track.views.view_tracking_log'),
498
        url(r'^event_logs/(?P<args>.+)$', 'track.views.view_tracking_log'),
David Baumgold committed
499
    )
500

501
if settings.FEATURES.get('ENABLE_SERVICE_STATUS'):
502 503 504 505
    urlpatterns += (
        url(r'^status/', include('service_status.urls')),
    )

506
if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):
507 508 509 510
    urlpatterns += (
        url(r'^instructor_task_status/$', 'instructor_task.views.instructor_task_status', name='instructor_task_status'),
    )

511
if settings.FEATURES.get('RUN_AS_ANALYTICS_SERVER_ENABLED'):
512
    urlpatterns += (
Juho Kim committed
513
        url(r'^edinsights_service/', include('edinsights.core.urls')),
514
    )
515
    import edinsights.core.registry
516

Victor Shnayder committed
517 518 519 520 521 522
# FoldIt views
urlpatterns += (
    # The path is hardcoded into their app...
    url(r'^comm/foldit_ops', 'foldit.views.foldit_ops', name="foldit_ops"),
)

523
if settings.FEATURES.get('ENABLE_DEBUG_RUN_PYTHON'):
524
    urlpatterns += (
525
        url(r'^debug/run_python$', 'debug.views.run_python'),
526
    )
527

528
urlpatterns += (
529
    url(r'^debug/show_parameters$', 'debug.views.show_parameters'),
530 531
)

532
# Crowdsourced hinting instructor manager.
533
if settings.FEATURES.get('ENABLE_HINTER_INSTRUCTOR_VIEW'):
534
    urlpatterns += (
535
        url(r'^courses/{}/hint_manager$'.format(settings.COURSE_ID_PATTERN),
536 537 538
            'instructor.hint_manager.hint_manager', name="hint_manager"),
    )

539
# enable automatic login
540
if settings.FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING'):
541
    urlpatterns += (
542
        url(r'^auto_auth$', 'student.views.auto_auth'),
543 544
    )

545 546 547 548
# Third-party auth.
if settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH'):
    urlpatterns += (
        url(r'', include('third_party_auth.urls')),
549
        url(r'^login_oauth_token/(?P<backend>[^/]+)/$', 'student.views.login_oauth_token'),
550 551
    )

552

553 554
urlpatterns = patterns(*urlpatterns)

555
if settings.DEBUG:
556
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
557

558 559 560
    # in debug mode, allow any template to be rendered (most useful for UX reference templates)
    urlpatterns += url(r'^template/(?P<template>.+)$', 'debug.views.show_reference_template'),

561
#Custom error pages
562 563
handler404 = 'static_template_view.views.render_404'
handler500 = 'static_template_view.views.render_500'
564 565 566 567 568 569

# display error page templates, for testing purposes
urlpatterns += (
    url(r'404', handler404),
    url(r'500', handler500),
)