diff --git a/cms/djangoapps/contentstore/features/signup.feature b/cms/djangoapps/contentstore/features/signup.feature index 6b3f09553001..d8912c3f6101 100644 --- a/cms/djangoapps/contentstore/features/signup.feature +++ b/cms/djangoapps/contentstore/features/signup.feature @@ -26,4 +26,4 @@ Feature: CMS.Sign in And I visit the url "/signin?next=http://www.google.com/" When I fill in and submit the signin form And I wait for "2" seconds - Then I should see that the path is "/" + Then I should see that the path is "/course" diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index ea8df5818eed..5e5b423618c6 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -133,7 +133,7 @@ def check_components_on_page(self, component_types, expected_types): # just pick one vertical descriptor = store.get_items(Location('i4x', 'edX', 'simple', 'vertical', None, None))[0] - resp = self.client.get(reverse('edit_unit', kwargs={'location': descriptor.location.url()})) + resp = self.client.get_html(reverse('edit_unit', kwargs={'location': descriptor.location.url()})) self.assertEqual(resp.status_code, 200) for expected in expected_types: @@ -158,7 +158,7 @@ def test_malformed_edit_unit_request(self): descriptor = store.get_items(Location('i4x', 'edX', 'simple', 'vertical', None, None))[0] location = descriptor.location.replace(name='.' + descriptor.location.name) - resp = self.client.get(reverse('edit_unit', kwargs={'location': location.url()})) + resp = self.client.get_html(reverse('edit_unit', kwargs={'location': location.url()})) self.assertEqual(resp.status_code, 400) def check_edit_unit(self, test_course_name): @@ -167,7 +167,7 @@ def check_edit_unit(self, test_course_name): for descriptor in modulestore().get_items(Location(None, None, 'vertical', None, None)): print "Checking ", descriptor.location.url() print descriptor.__class__, descriptor.location - resp = self.client.get(reverse('edit_unit', kwargs={'location': descriptor.location.url()})) + resp = self.client.get_html(reverse('edit_unit', kwargs={'location': descriptor.location.url()})) self.assertEqual(resp.status_code, 200) def lockAnAsset(self, content_store, course_location): @@ -457,7 +457,7 @@ def test_module_preview_in_whitelist(self): # also try a custom response which will trigger the 'is this course in whitelist' logic problem_module_location = Location(['i4x', 'edX', 'toy', 'vertical', 'vertical_test', None]) url = reverse('preview_component', kwargs={'location': problem_module_location.url()}) - resp = self.client.get(url) + resp = self.client.get_html(url) self.assertEqual(resp.status_code, 200) def test_video_module_caption_asset_path(self): @@ -470,7 +470,7 @@ def test_video_module_caption_asset_path(self): # also try a custom response which will trigger the 'is this course in whitelist' logic video_module_location = Location(['i4x', 'edX', 'toy', 'video', 'sample_video', None]) url = reverse('preview_component', kwargs={'location': video_module_location.url()}) - resp = self.client.get(url) + resp = self.client.get_html(url) self.assertEqual(resp.status_code, 200) self.assertContains(resp, 'data-caption-asset-path="/c4x/edX/toy/asset/subs_"') @@ -831,7 +831,7 @@ def test_illegal_draft_crud_ops(self): self.assertRaises(InvalidVersionError, draft_store.unpublish, location) def test_bad_contentstore_request(self): - resp = self.client.get('http://localhost:8001/c4x/CDX/123123/asset/&images_circuits_Lab7Solution2.png') + resp = self.client.get_html('http://localhost:8001/c4x/CDX/123123/asset/&images_circuits_Lab7Solution2.png') self.assertEqual(resp.status_code, 400) def test_rewrite_nonportable_links_on_import(self): @@ -1022,7 +1022,7 @@ def check_import(self, module_store, root_dir, draft_store, content_store, stub_ # the service in non-draft aware if getattr(descriptor, 'is_draft', False): print "Checking {0}....".format(descriptor.location.url()) - resp = self.client.get(reverse('edit_unit', kwargs={'location': descriptor.location.url()})) + resp = self.client.get_html(reverse('edit_unit', kwargs={'location': descriptor.location.url()})) self.assertEqual(resp.status_code, 200) # verify that we have the content in the draft store as well @@ -1205,7 +1205,7 @@ def test_course_handouts_rewrites(self): handout_location = Location(['i4x', 'edX', 'toy', 'course_info', 'handouts']) # get module info - resp = self.client.get(reverse('module_info', kwargs={'module_location': handout_location})) + resp = self.client.get_html(reverse('module_info', kwargs={'module_location': handout_location})) # make sure we got a successful response self.assertEqual(resp.status_code, 200) @@ -1392,7 +1392,7 @@ def test_forum_unseeding_with_multiple_courses(self): def test_create_course_duplicate_course(self): """Test new course creation - error path""" - self.client.ajax_post(reverse('create_new_course'), self.course_data) + self.client.ajax_post('/course', self.course_data) self.assert_course_creation_failed('There is already a course defined with the same organization, course number, and course run. Please change either organization or course number to be unique.') def assert_course_creation_failed(self, error_message): @@ -1401,7 +1401,7 @@ def assert_course_creation_failed(self, error_message): """ course_id = _get_course_id(self.course_data) initially_enrolled = CourseEnrollment.is_enrolled(self.user, course_id) - resp = self.client.ajax_post(reverse('create_new_course'), self.course_data) + resp = self.client.ajax_post('/course', self.course_data) self.assertEqual(resp.status_code, 200) data = parse_json(resp) self.assertEqual(data['ErrMsg'], error_message) @@ -1411,7 +1411,7 @@ def assert_course_creation_failed(self, error_message): def test_create_course_duplicate_number(self): """Test new course creation - error path""" - self.client.ajax_post(reverse('create_new_course'), self.course_data) + self.client.ajax_post('/course', self.course_data) self.course_data['display_name'] = 'Robot Super Course Two' self.course_data['run'] = '2013_Summer' @@ -1420,13 +1420,13 @@ def test_create_course_duplicate_number(self): def test_create_course_case_change(self): """Test new course creation - error path due to case insensitive name equality""" self.course_data['number'] = 'capital' - self.client.ajax_post(reverse('create_new_course'), self.course_data) + self.client.ajax_post('/course', self.course_data) cache_current = self.course_data['org'] self.course_data['org'] = self.course_data['org'].lower() self.assert_course_creation_failed('There is already a course defined with the same organization and course number. Please change at least one field to be unique.') self.course_data['org'] = cache_current - self.client.ajax_post(reverse('create_new_course'), self.course_data) + self.client.ajax_post('/course', self.course_data) cache_current = self.course_data['number'] self.course_data['number'] = self.course_data['number'].upper() self.assert_course_creation_failed('There is already a course defined with the same organization and course number. Please change at least one field to be unique.') @@ -1435,14 +1435,14 @@ def test_course_substring(self): """ Test that a new course can be created whose name is a substring of an existing course """ - self.client.ajax_post(reverse('create_new_course'), self.course_data) + self.client.ajax_post('/course', self.course_data) cache_current = self.course_data['number'] self.course_data['number'] = '{}a'.format(self.course_data['number']) - resp = self.client.ajax_post(reverse('create_new_course'), self.course_data) + resp = self.client.ajax_post('/course', self.course_data) self.assertEqual(resp.status_code, 200) self.course_data['number'] = cache_current self.course_data['org'] = 'a{}'.format(self.course_data['org']) - resp = self.client.ajax_post(reverse('create_new_course'), self.course_data) + resp = self.client.ajax_post('/course', self.course_data) self.assertEqual(resp.status_code, 200) def test_create_course_with_bad_organization(self): @@ -1485,13 +1485,13 @@ def assert_course_permission_denied(self): """ Checks that the course did not get created due to a PermissionError. """ - resp = self.client.ajax_post(reverse('create_new_course'), self.course_data) + resp = self.client.ajax_post('/course', self.course_data) self.assertEqual(resp.status_code, 403) def test_course_index_view_with_no_courses(self): """Test viewing the index page with no courses""" # Create a course so there is something to view - resp = self.client.get(reverse('index')) + resp = self.client.get_html('/course') self.assertContains( resp, '

My Courses

', @@ -1513,7 +1513,7 @@ def test_item_factory(self): def test_course_index_view_with_course(self): """Test viewing the index page with an existing course""" CourseFactory.create(display_name='Robot Super Educational Course') - resp = self.client.get(reverse('index')) + resp = self.client.get_html('/course') self.assertContains( resp, '

Robot Super Educational Course

', @@ -1590,7 +1590,7 @@ def test_cms_imported_course_walkthrough(self): # go to various pages # import page - resp = self.client.get(new_location.url_reverse('import/', ''), HTTP_ACCEPT='text/html') + resp = self.client.get_html(new_location.url_reverse('import/', '')) self.assertEqual(resp.status_code, 200) # export page @@ -1602,7 +1602,7 @@ def test_cms_imported_course_walkthrough(self): # course team url = new_location.url_reverse('course_team/', '') - resp = self.client.get(url, HTTP_ACCEPT='text/html') + resp = self.client.get_html(url) self.assertEqual(resp.status_code, 200) # course info @@ -1628,18 +1628,18 @@ def test_cms_imported_course_walkthrough(self): # assets_handler (HTML for full page content) url = new_location.url_reverse('assets/', '') - resp = self.client.get(url, HTTP_ACCEPT='text/html') + resp = self.client.get_html(url) self.assertEqual(resp.status_code, 200) # go look at a subsection page subsection_location = loc.replace(category='sequential', name='test_sequence') - resp = self.client.get(reverse('edit_subsection', + resp = self.client.get_html(reverse('edit_subsection', kwargs={'location': subsection_location.url()})) self.assertEqual(resp.status_code, 200) # go look at the Edit page unit_location = loc.replace(category='vertical', name='test_vertical') - resp = self.client.get(reverse('edit_unit', + resp = self.client.get_html(reverse('edit_unit', kwargs={'location': unit_location.url()})) self.assertEqual(resp.status_code, 200) @@ -1853,7 +1853,7 @@ def _show_course_overview(self, location): Show the course overview page. """ new_location = loc_mapper().translate_location(location.course_id, location, False, True) - return self.client.get(new_location.url_reverse('course/', ''), HTTP_ACCEPT='text/html') + return self.client.get_html(new_location.url_reverse('course/', '')) @override_settings(MODULESTORE=TEST_MODULESTORE) @@ -1927,7 +1927,7 @@ def _create_course(test, course_data): course_id = _get_course_id(course_data) new_location = loc_mapper().translate_location(course_id, CourseDescriptor.id_to_location(course_id), False, True) - response = test.client.ajax_post(reverse('create_new_course'), course_data) + response = test.client.ajax_post('/course', course_data) test.assertEqual(response.status_code, 200) data = parse_json(response) test.assertNotIn('ErrMsg', data) diff --git a/cms/djangoapps/contentstore/tests/test_course_index.py b/cms/djangoapps/contentstore/tests/test_course_index.py index 44a115518c98..1fcdb6f040b9 100644 --- a/cms/djangoapps/contentstore/tests/test_course_index.py +++ b/cms/djangoapps/contentstore/tests/test_course_index.py @@ -31,7 +31,7 @@ def check_index_and_outline(self, authed_client): """ Test getting the list of courses and then pulling up their outlines """ - index_url = reverse('contentstore.views.index') + index_url = '/course' index_response = authed_client.get(index_url, {}, HTTP_ACCEPT='text/html') parsed_html = lxml.html.fromstring(index_response.content) course_link_eles = parsed_html.find_class('course-link') diff --git a/cms/djangoapps/contentstore/tests/test_i18n.py b/cms/djangoapps/contentstore/tests/test_i18n.py index 9e7a2df8b2f9..c156f3f4cf43 100644 --- a/cms/djangoapps/contentstore/tests/test_i18n.py +++ b/cms/djangoapps/contentstore/tests/test_i18n.py @@ -1,12 +1,11 @@ from unittest import skip -from django.core.urlresolvers import reverse from django.contrib.auth.models import User -from django.test.client import Client from django.test.utils import override_settings from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from contentstore.tests.modulestore_config import TEST_MODULESTORE +from contentstore.tests.utils import AjaxEnabledTestClient @override_settings(MODULESTORE=TEST_MODULESTORE) @@ -45,10 +44,10 @@ def setUp(self): def test_course_plain_english(self): """Test viewing the index page with no courses""" - self.client = Client() + self.client = AjaxEnabledTestClient() self.client.login(username=self.uname, password=self.password) - resp = self.client.get(reverse('index')) + resp = self.client.get_html('/course') self.assertContains(resp, '

My Courses

', status_code=200, @@ -56,10 +55,10 @@ def test_course_plain_english(self): def test_course_explicit_english(self): """Test viewing the index page with no courses""" - self.client = Client() + self.client = AjaxEnabledTestClient() self.client.login(username=self.uname, password=self.password) - resp = self.client.get(reverse('index'), + resp = self.client.get_html('/course', {}, HTTP_ACCEPT_LANGUAGE='en' ) @@ -80,10 +79,10 @@ def test_course_explicit_english(self): @skip def test_course_with_accents(self): """Test viewing the index page with no courses""" - self.client = Client() + self.client = AjaxEnabledTestClient() self.client.login(username=self.uname, password=self.password) - resp = self.client.get(reverse('index'), + resp = self.client.get_html('/course', {}, HTTP_ACCEPT_LANGUAGE='fr' ) diff --git a/cms/djangoapps/contentstore/tests/tests.py b/cms/djangoapps/contentstore/tests/tests.py index eddf5ab25ab1..7ac99e9a64ca 100644 --- a/cms/djangoapps/contentstore/tests/tests.py +++ b/cms/djangoapps/contentstore/tests/tests.py @@ -1,9 +1,8 @@ -from django.test.client import Client from django.test.utils import override_settings from django.core.cache import cache from django.core.urlresolvers import reverse -from contentstore.tests.utils import parse_json, user, registration +from contentstore.tests.utils import parse_json, user, registration, AjaxEnabledTestClient from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from contentstore.tests.test_course_settings import CourseTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -82,12 +81,12 @@ def setUp(self): self.email = 'a@b.com' self.pw = 'xyz' self.username = 'testuser' - self.client = Client() + self.client = AjaxEnabledTestClient() # clear the cache so ratelimiting won't affect these tests cache.clear() def check_page_get(self, url, expected): - resp = self.client.get(url) + resp = self.client.get_html(url) self.assertEqual(resp.status_code, expected) return resp @@ -152,20 +151,20 @@ def test_login_link_on_activation_age(self): def test_private_pages_auth(self): """Make sure pages that do require login work.""" auth_pages = ( - reverse('index'), + '/course', ) # These are pages that should just load when the user is logged in # (no data needed) simple_auth_pages = ( - reverse('index'), + '/course', ) # need an activated user self.test_create_account() # Create a new session - self.client = Client() + self.client = AjaxEnabledTestClient() # Not logged in. Should redirect to login. print('Not logged in') @@ -184,7 +183,7 @@ def test_private_pages_auth(self): def test_index_auth(self): # not logged in. Should return a redirect. - resp = self.client.get(reverse('index')) + resp = self.client.get_html('/course') self.assertEqual(resp.status_code, 302) # Logged in should work. diff --git a/cms/djangoapps/contentstore/tests/utils.py b/cms/djangoapps/contentstore/tests/utils.py index 7387c71655b3..68782a818176 100644 --- a/cms/djangoapps/contentstore/tests/utils.py +++ b/cms/djangoapps/contentstore/tests/utils.py @@ -30,12 +30,24 @@ def registration(email): class AjaxEnabledTestClient(Client): + """ + Convenience class to make testing easier. + """ def ajax_post(self, path, data=None, content_type="application/json", **kwargs): + """ + Convenience method for client post which serializes the data into json and sets the accept type + to json + """ if not isinstance(data, basestring): data = json.dumps(data or {}) kwargs.setdefault("HTTP_X_REQUESTED_WITH", "XMLHttpRequest") return self.post(path=path, data=data, content_type=content_type, **kwargs) + def get_html(self, path, data=None, follow=False, **extra): + """ + Convenience method for client.get which sets the accept type to html + """ + return self.get(path, data or {}, follow, HTTP_ACCEPT="text/html", **extra) @override_settings(MODULESTORE=TEST_MODULESTORE) class CourseTestCase(ModuleStoreTestCase): diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 21f3b9cdc514..2a84d369a119 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -3,9 +3,11 @@ """ import json import random -from django.utils.translation import ugettext as _ import string # pylint: disable=W0402 +import re +import bson +from django.utils.translation import ugettext as _ from django.contrib.auth.decorators import login_required from django_future.csrf import ensure_csrf_cookie from django.conf import settings @@ -16,6 +18,7 @@ from util.json_request import JsonResponse from mitxmako.shortcuts import render_to_response +from xmodule.error_module import ErrorDescriptor from xmodule.modulestore.django import modulestore, loc_mapper from xmodule.modulestore.inheritance import own_metadata from xmodule.contentstore.content import StaticContent @@ -49,9 +52,9 @@ from xmodule.html_module import AboutDescriptor from xmodule.modulestore.locator import BlockUsageLocator -import re -import bson -__all__ = ['create_new_course', 'course_info', 'course_handler', +from course_creators.views import get_course_creator_status, add_user_with_status_unrequested + +__all__ = ['course_info', 'course_handler', 'course_info_updates', 'get_course_settings', 'course_config_graders_page', 'course_config_advanced_page', @@ -69,11 +72,12 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid= will typically be a 'course' object but may not be especially as we support modules. GET - html: return html page overview for the given course + html: return course listing page if not given a course id + html: return html page overview for the given course if given a course id json: return json representing the course branch's index entry as well as dag w/ all of the children replaced w/ json docs where each doc has {'_id': , 'display_name': , 'children': } POST - json: create (or update?) this course or branch in this course for this user, return resulting json + json: create a course, return resulting json descriptor (same as in GET course/...). Leaving off /branch/draft would imply create the course w/ default branches. Cannot change the structure contents ('_id', 'display_name', 'children') but can change the index entry. @@ -86,13 +90,13 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid= if 'application/json' in request.META.get('HTTP_ACCEPT', 'application/json'): if request.method == 'GET': raise NotImplementedError('coming soon') + elif request.method == 'POST': # not sure if this is only post. If one will have ids, it goes after access + return create_new_course(request) elif not has_access( request.user, BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, usage_id=block) ): raise PermissionDenied() - elif request.method == 'POST': - raise NotImplementedError() elif request.method == 'PUT': raise NotImplementedError() elif request.method == 'DELETE': @@ -100,11 +104,64 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid= else: return HttpResponseBadRequest() elif request.method == 'GET': # assume html - return course_index(request, course_id, branch, version_guid, block) + if course_id is None: + return course_listing(request) + else: + return course_index(request, course_id, branch, version_guid, block) else: return HttpResponseNotFound() +@login_required +@ensure_csrf_cookie +def course_listing(request): + """ + List all courses available to the logged in user + """ + courses = modulestore('direct').get_items(['i4x', None, None, 'course', None]) + + # filter out courses that we don't have access too + def course_filter(course): + """ + Get courses to which this user has access + """ + return (has_access(request.user, course.location) + # pylint: disable=fixme + # TODO remove this condition when templates purged from db + and course.location.course != 'templates' + and course.location.org != '' + and course.location.course != '' + and course.location.name != '') + courses = filter(course_filter, courses) + + def format_course_for_view(course): + """ + return tuple of the data which the view requires for each course + """ + # published = false b/c studio manipulates draft versions not b/c the course isn't pub'd + course_loc = loc_mapper().translate_location( + course.location.course_id, course.location, published=False, add_entry_if_missing=True + ) + return ( + course.display_name, + # note, couldn't get django reverse to work; so, wrote workaround + course_loc.url_reverse('course/', ''), + get_lms_link_for_item( + course.location + ), + course.display_org_with_default, + course.display_number_with_default, + course.location.name + ) + + return render_to_response('index.html', { + 'courses': [format_course_for_view(c) for c in courses if not isinstance(c, ErrorDescriptor)], + 'user': request.user, + 'request_course_creator_url': reverse('contentstore.views.request_course_creator'), + 'course_creator_status': _get_course_creator_status(request.user), + }) + + @login_required @ensure_csrf_cookie def course_index(request, course_id, branch, version_guid, block): @@ -142,7 +199,6 @@ def course_index(request, course_id, branch, version_guid, block): }) -@login_required @expect_json def create_new_course(request): """ @@ -756,3 +812,28 @@ def textbook_by_id(request, org, course, name, tid): own_metadata(course_module) ) return JsonResponse() + + +def _get_course_creator_status(user): + """ + Helper method for returning the course creator status for a particular user, + taking into account the values of DISABLE_COURSE_CREATION and ENABLE_CREATOR_GROUP. + + If the user passed in has not previously visited the index page, it will be + added with status 'unrequested' if the course creator group is in use. + """ + if user.is_staff: + course_creator_status = 'granted' + elif settings.MITX_FEATURES.get('DISABLE_COURSE_CREATION', False): + course_creator_status = 'disallowed_for_this_site' + elif settings.MITX_FEATURES.get('ENABLE_CREATOR_GROUP', False): + course_creator_status = get_course_creator_status(user) + if course_creator_status is None: + # User not grandfathered in as an existing user, has not previously visited the dashboard page. + # Add the user to the course creator admin table with status 'unrequested'. + add_user_with_status_unrequested(user) + course_creator_status = get_course_creator_status(user) + else: + course_creator_status = 'granted' + + return course_creator_status diff --git a/cms/djangoapps/contentstore/views/public.py b/cms/djangoapps/contentstore/views/public.py index 2f74df1d8ca1..fafd563c7852 100644 --- a/cms/djangoapps/contentstore/views/public.py +++ b/cms/djangoapps/contentstore/views/public.py @@ -9,7 +9,6 @@ from mitxmako.shortcuts import render_to_response from external_auth.views import ssl_login_shortcut -from .user import index __all__ = ['signup', 'old_login_redirect', 'login_page', 'howitworks'] @@ -46,6 +45,6 @@ def login_page(request): def howitworks(request): "Proxy view" if request.user.is_authenticated(): - return index(request) + return redirect('/course') else: return render_to_response('howitworks.html', {}) diff --git a/cms/djangoapps/contentstore/views/user.py b/cms/djangoapps/contentstore/views/user.py index 67d26f1e5e9e..6f2a2fbdec9f 100644 --- a/cms/djangoapps/contentstore/views/user.py +++ b/cms/djangoapps/contentstore/views/user.py @@ -1,7 +1,6 @@ import json from django.conf import settings from django.core.exceptions import PermissionDenied -from django.core.urlresolvers import reverse from django.contrib.auth.models import User, Group from django.contrib.auth.decorators import login_required from django.views.decorators.http import require_http_methods @@ -9,17 +8,12 @@ from django.views.decorators.http import require_POST from django_future.csrf import ensure_csrf_cookie from mitxmako.shortcuts import render_to_response -from django.core.context_processors import csrf from xmodule.modulestore.django import modulestore, loc_mapper -from xmodule.error_module import ErrorDescriptor -from contentstore.utils import get_lms_link_for_item from util.json_request import JsonResponse from auth.authz import ( STAFF_ROLE_NAME, INSTRUCTOR_ROLE_NAME, get_course_groupname_for_role) -from course_creators.views import ( - get_course_creator_status, add_user_with_status_unrequested, - user_requested_access) +from course_creators.views import user_requested_access from .access import has_access @@ -28,51 +22,7 @@ from django.http import HttpResponseNotFound -__all__ = ['index', 'request_course_creator', 'course_team_handler'] - - -@login_required -@ensure_csrf_cookie -def index(request): - """ - List all courses available to the logged in user - """ - courses = modulestore('direct').get_items(['i4x', None, None, 'course', None]) - - # filter out courses that we don't have access too - def course_filter(course): - return (has_access(request.user, course.location) - # TODO remove this condition when templates purged from db - and course.location.course != 'templates' - and course.location.org != '' - and course.location.course != '' - and course.location.name != '') - courses = filter(course_filter, courses) - - def format_course_for_view(course): - # published = false b/c studio manipulates draft versions not b/c the course isn't pub'd - course_loc = loc_mapper().translate_location( - course.location.course_id, course.location, published=False, add_entry_if_missing=True - ) - return ( - course.display_name, - # note, couldn't get django reverse to work; so, wrote workaround - course_loc.url_reverse('course/', ''), - get_lms_link_for_item( - course.location - ), - course.display_org_with_default, - course.display_number_with_default, - course.location.name - ) - - return render_to_response('index.html', { - 'courses': [format_course_for_view(c) for c in courses if not isinstance(c, ErrorDescriptor)], - 'user': request.user, - 'request_course_creator_url': reverse('contentstore.views.request_course_creator'), - 'course_creator_status': _get_course_creator_status(request.user), - 'csrf': csrf(request)['csrf_token'] - }) +__all__ = ['request_course_creator', 'course_team_handler'] @require_POST @@ -254,27 +204,3 @@ def _course_team_user(request, location, email): return JsonResponse() - -def _get_course_creator_status(user): - """ - Helper method for returning the course creator status for a particular user, - taking into account the values of DISABLE_COURSE_CREATION and ENABLE_CREATOR_GROUP. - - If the user passed in has not previously visited the index page, it will be - added with status 'unrequested' if the course creator group is in use. - """ - if user.is_staff: - course_creator_status = 'granted' - elif settings.MITX_FEATURES.get('DISABLE_COURSE_CREATION', False): - course_creator_status = 'disallowed_for_this_site' - elif settings.MITX_FEATURES.get('ENABLE_CREATOR_GROUP', False): - course_creator_status = get_course_creator_status(user) - if course_creator_status is None: - # User not grandfathered in as an existing user, has not previously visited the dashboard page. - # Add the user to the course creator admin table with status 'unrequested'. - add_user_with_status_unrequested(user) - course_creator_status = get_course_creator_status(user) - else: - course_creator_status = 'granted' - - return course_creator_status diff --git a/cms/static/js/index.js b/cms/static/js/index.js index c84abdf127af..d8a6903763c2 100644 --- a/cms/static/js/index.js +++ b/cms/static/js/index.js @@ -32,7 +32,7 @@ require(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"], 'run': run }); - $.postJSON('/create_new_course', { + $.postJSON('/course', { 'org': org, 'number': number, 'display_name': display_name, diff --git a/cms/templates/index.html b/cms/templates/index.html index 82183c10b77f..110c335f2950 100644 --- a/cms/templates/index.html +++ b/cms/templates/index.html @@ -212,7 +212,6 @@

${_('Your Course Creator Request Status:')}

-
diff --git a/cms/templates/signup.html b/cms/templates/signup.html index 1bc13c856a0f..d9a733ae4712 100644 --- a/cms/templates/signup.html +++ b/cms/templates/signup.html @@ -124,7 +124,7 @@

${_("I've never authored a course online before. Is there he submit_data, function(json) { if(json.success) { - location.href = "${reverse('index')}"; + location.href = "${'/course'}"; } else { $('#register_error').html(json.value).stop().addClass('is-shown'); } diff --git a/cms/urls.py b/cms/urls.py index 98a9e60d49f9..811efc18e1e3 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -30,7 +30,6 @@ url(r'^create_draft$', 'contentstore.views.create_draft', name='create_draft'), url(r'^publish_draft$', 'contentstore.views.publish_draft', name='publish_draft'), url(r'^unpublish_unit$', 'contentstore.views.unpublish_unit', name='unpublish_unit'), - url(r'^create_new_course', 'contentstore.views.create_new_course', name='create_new_course'), url(r'^reorder_static_tabs', 'contentstore.views.reorder_static_tabs', name='reorder_static_tabs'), url(r'^(?P[^/]+)/(?P[^/]+)/export/(?P[^/]+)$', @@ -116,12 +115,11 @@ urlpatterns += patterns( 'contentstore.views', - url(r'^course$', 'index', name='index'), url(r'^request_course_creator$', 'request_course_creator'), # (?ix) == ignore case and verbose (multiline regex) - url(r'(?ix)^course/{}$'.format(parsers.URL_RE_SOURCE), 'course_handler'), - url(r'(?ix)^checklists/{}(/)?(?P\d+)?$'.format(parsers.URL_RE_SOURCE), 'checklists_handler'), url(r'(?ix)^course_team/{}(/)?(?P.+)?$'.format(parsers.URL_RE_SOURCE), 'course_team_handler'), + url(r'(?ix)^course($|/){}$'.format(parsers.URL_RE_SOURCE), 'course_handler'), + url(r'(?ix)^checklists/{}(/)?(?P\d+)?$'.format(parsers.URL_RE_SOURCE), 'checklists_handler'), url(r'(?ix)^orphan/{}$'.format(parsers.URL_RE_SOURCE), 'orphan'), url(r'(?ix)^assets/{}(/)?(?P.+)?$'.format(parsers.URL_RE_SOURCE), 'assets_handler'), url(r'(?ix)^import/{}$'.format(parsers.URL_RE_SOURCE), 'import_handler'), diff --git a/common/djangoapps/student/tests/test_userstanding.py b/common/djangoapps/student/tests/test_userstanding.py index 730984c91875..19fe957ab766 100644 --- a/common/djangoapps/student/tests/test_userstanding.py +++ b/common/djangoapps/student/tests/test_userstanding.py @@ -53,7 +53,7 @@ def setUp(self): try: self.some_url = reverse('dashboard') except NoReverseMatch: - self.some_url = reverse('index') + self.some_url = '/course' # since it's only possible to disable accounts from lms, we're going # to skip tests for cms