def create_new_course(request): """ Create a new course """ if not is_user_in_creator_group(request.user): raise PermissionDenied() org = request.POST.get("org") number = request.POST.get("number") display_name = request.POST.get("display_name") try: dest_location = Location("i4x", org, number, "course", Location.clean(display_name)) except InvalidLocationError as error: return JsonResponse( {"ErrMsg": "Unable to create course '{name}'.\n\n{err}".format(name=display_name, err=error.message)} ) # see if the course already exists existing_course = None try: existing_course = modulestore("direct").get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return JsonResponse({"ErrMsg": "There is already a course defined with this name."}) course_search_location = ["i4x", dest_location.org, dest_location.course, "course", None] courses = modulestore().get_items(course_search_location) if len(courses) > 0: return JsonResponse( {"ErrMsg": "There is already a course defined with the same organization and course number."} ) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {"display_name": display_name} modulestore("direct").create_and_save_xmodule(dest_location, metadata=metadata) new_course = modulestore("direct").get_item(dest_location) # clone a default 'about' overview module as well dest_about_location = dest_location.replace(category="about", name="overview") overview_template = AboutDescriptor.get_template("overview.yaml") modulestore("direct").create_and_save_xmodule( dest_about_location, system=new_course.system, definition_data=overview_template.get("data") ) initialize_course_tabs(new_course) create_all_course_groups(request.user, new_course.location) # seed the forums seed_permissions_roles(new_course.location.course_id) return JsonResponse({"id": new_course.location.url()})
def create_course(self, org, offering, user_id=None, fields=None, **kwargs): """ Creates and returns the course. Args: org (str): the organization that owns the course offering (str): the name of the course offering user_id: id of the user creating the course fields (dict): Fields to set on the course at initialization kwargs: Any optional arguments understood by a subset of modulestores to customize instantiation Returns: a CourseDescriptor Raises: InvalidLocationError: If a course with the same org and offering already exists """ course, _, run = offering.partition('/') course_id = SlashSeparatedCourseKey(org, course, run) # Check if a course with this org/course has been defined before (case-insensitive) course_search_location = SON([ ('_id.tag', 'i4x'), ('_id.org', re.compile(u'^{}$'.format(course_id.org), re.IGNORECASE)), ('_id.course', re.compile(u'^{}$'.format(course_id.course), re.IGNORECASE)), ('_id.category', 'course'), ]) courses = self.collection.find(course_search_location, fields=('_id')) if courses.count() > 0: raise InvalidLocationError( "There are already courses with the given org and course id: {}" .format([course['_id'] for course in courses])) location = course_id.make_usage_key('course', course_id.run) course = self.create_and_save_xmodule(location, fields=fields, **kwargs) # clone a default 'about' overview module as well about_location = location.replace(category='about', name='overview') overview_template = AboutDescriptor.get_template('overview.yaml') self.create_and_save_xmodule( about_location, system=course.system, definition_data=overview_template.get('data')) return course
def create_course(self, org, offering, user_id=None, fields=None, **kwargs): """ Creates and returns the course. Args: org (str): the organization that owns the course offering (str): the name of the course offering user_id: id of the user creating the course fields (dict): Fields to set on the course at initialization kwargs: Any optional arguments understood by a subset of modulestores to customize instantiation Returns: a CourseDescriptor Raises: InvalidLocationError: If a course with the same org and offering already exists """ course, _, run = offering.partition('/') course_id = SlashSeparatedCourseKey(org, course, run) # Check if a course with this org/course has been defined before (case-insensitive) course_search_location = SON([ ('_id.tag', 'i4x'), ('_id.org', re.compile(u'^{}$'.format(course_id.org), re.IGNORECASE)), ('_id.course', re.compile(u'^{}$'.format(course_id.course), re.IGNORECASE)), ('_id.category', 'course'), ]) courses = self.collection.find(course_search_location, fields=('_id')) if courses.count() > 0: raise InvalidLocationError( "There are already courses with the given org and course id: {}".format([ course['_id'] for course in courses ])) location = course_id.make_usage_key('course', course_id.run) course = self.create_and_save_xmodule(location, user_id, fields=fields, **kwargs) # clone a default 'about' overview module as well about_location = location.replace( category='about', name='overview' ) overview_template = AboutDescriptor.get_template('overview.yaml') self.create_and_save_xmodule( about_location, user_id, definition_data=overview_template.get('data'), runtime=course.system ) return course
def create_new_course(request): """ Create a new course. Returns the URL for the course overview page. """ if not auth.has_access(request.user, CourseCreatorRole()): raise PermissionDenied() org = request.json.get('org') number = request.json.get('number') display_name = request.json.get('display_name') run = request.json.get('run') try: dest_location = Location(u'i4x', org, number, u'course', run) except InvalidLocationError as error: return JsonResponse({ "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format( name=display_name, err=error.message)}) # see if the course already exists existing_course = None try: existing_course = modulestore('direct').get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return JsonResponse({ 'ErrMsg': _( '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.' ), 'OrgErrMsg': _( 'Please change either the organization or ' 'course number so that it is unique.' ), 'CourseErrMsg': _( 'Please change either the organization or ' 'course number so that it is unique.' ), }) # dhm: this query breaks the abstraction, but I'll fix it when I do my suspended refactoring of this # file for new locators. get_items should accept a query rather than requiring it be a legal location course_search_location = bson.son.SON({ '_id.tag': 'i4x', # cannot pass regex to Location constructor; thus this hack # pylint: disable=E1101 '_id.org': re.compile(u'^{}$'.format(dest_location.org), re.IGNORECASE | re.UNICODE), # pylint: disable=E1101 '_id.course': re.compile(u'^{}$'.format(dest_location.course), re.IGNORECASE | re.UNICODE), '_id.category': 'course', }) courses = modulestore().collection.find(course_search_location, fields=('_id')) if courses.count() > 0: return JsonResponse({ 'ErrMsg': _( 'There is already a course defined with the same ' 'organization and course number. Please ' 'change at least one field to be unique.'), 'OrgErrMsg': _( 'Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _( 'Please change either the organization or ' 'course number so that it is unique.'), }) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {'display_name': display_name} modulestore('direct').create_and_save_xmodule( dest_location, metadata=metadata ) new_course = modulestore('direct').get_item(dest_location) # clone a default 'about' overview module as well dest_about_location = dest_location.replace( category='about', name='overview' ) overview_template = AboutDescriptor.get_template('overview.yaml') modulestore('direct').create_and_save_xmodule( dest_about_location, system=new_course.system, definition_data=overview_template.get('data') ) initialize_course_tabs(new_course, request.user) new_location = loc_mapper().translate_location(new_course.location.course_id, new_course.location, False, True) # can't use auth.add_users here b/c it requires request.user to already have Instructor perms in this course # however, we can assume that b/c this user had authority to create the course, the user can add themselves CourseInstructorRole(new_location).add_users(request.user) auth.add_users(request.user, CourseStaffRole(new_location), request.user) # seed the forums seed_permissions_roles(new_course.location.course_id) # auto-enroll the course creator in the course so that "View Live" will # work. CourseEnrollment.enroll(request.user, new_course.location.course_id) return JsonResponse({'url': new_location.url_reverse("course/", "")})
] ) courses = self.collection.find(course_search_location, fields=("_id")) if courses.count() > 0: raise InvalidLocationError( "There are already courses with the given org and course id: {}".format( [course["_id"] for course in courses] ) ) location = course_id.make_usage_key("course", course_id.run) course = self.create_and_save_xmodule(location, user_id, fields=fields, **kwargs) # clone a default 'about' overview module as well about_location = location.replace(category="about", name="overview") overview_template = AboutDescriptor.get_template("overview.yaml") self.create_and_save_xmodule( about_location, user_id, definition_data=overview_template.get("data"), runtime=course.system ) return course def create_xmodule(self, location, definition_data=None, metadata=None, runtime=None, fields={}): """ Create the new xmodule but don't save it. Returns the new module. :param location: a Location--must have a category :param definition_data: can be empty. The initial definition_data for the kvs :param metadata: can be empty, the initial metadata for the kvs :param runtime: if you already have an xblock from the course, the xblock.runtime value :param fields: a dictionary of field names and values for the new xmodule
def create_new_course(request): """ Create a new course. Returns the URL for the course overview page. """ if not auth.has_access(request.user, CourseCreatorRole()): raise PermissionDenied() org = request.json.get('org') number = request.json.get('number') display_name = request.json.get('display_name') run = request.json.get('run') # allow/disable unicode characters in course_id according to settings if not settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID'): if _has_non_ascii_characters(org) or _has_non_ascii_characters( number) or _has_non_ascii_characters(run): return JsonResponse( { 'error': _('Special characters not allowed in organization, course number, and course run.' ) }, status=400) try: dest_location = Location(u'i4x', org, number, u'course', run) except InvalidLocationError as error: return JsonResponse({ "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format( name=display_name, err=error.message) }) # see if the course already exists existing_course = None try: existing_course = modulestore('direct').get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return JsonResponse({ 'ErrMsg': _('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.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) # dhm: this query breaks the abstraction, but I'll fix it when I do my suspended refactoring of this # file for new locators. get_items should accept a query rather than requiring it be a legal location course_search_location = bson.son.SON({ '_id.tag': 'i4x', # cannot pass regex to Location constructor; thus this hack # pylint: disable=E1101 '_id.org': re.compile(u'^{}$'.format(dest_location.org), re.IGNORECASE | re.UNICODE), # pylint: disable=E1101 '_id.course': re.compile(u'^{}$'.format(dest_location.course), re.IGNORECASE | re.UNICODE), '_id.category': 'course', }) courses = modulestore().collection.find(course_search_location, fields=('_id')) if courses.count() > 0: return JsonResponse({ 'ErrMsg': _('There is already a course defined with the same ' 'organization and course number. Please ' 'change at least one field to be unique.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {'display_name': display_name} # Set a unique wiki_slug for newly created courses. To maintain active wiki_slugs for existing xml courses this # cannot be changed in CourseDescriptor. wiki_slug = "{0}.{1}.{2}".format(dest_location.org, dest_location.course, dest_location.name) definition_data = {'wiki_slug': wiki_slug} modulestore('direct').create_and_save_xmodule( dest_location, definition_data=definition_data, metadata=metadata) new_course = modulestore('direct').get_item(dest_location) # clone a default 'about' overview module as well dest_about_location = dest_location.replace(category='about', name='overview') overview_template = AboutDescriptor.get_template('overview.yaml') modulestore('direct').create_and_save_xmodule( dest_about_location, system=new_course.system, definition_data=overview_template.get('data')) initialize_course_tabs(new_course, request.user) new_location = loc_mapper().translate_location( new_course.location.course_id, new_course.location, False, True) # can't use auth.add_users here b/c it requires request.user to already have Instructor perms in this course # however, we can assume that b/c this user had authority to create the course, the user can add themselves CourseInstructorRole(new_location).add_users(request.user) auth.add_users(request.user, CourseStaffRole(new_location), request.user) # seed the forums seed_permissions_roles(new_course.location.course_id) # auto-enroll the course creator in the course so that "View Live" will # work. CourseEnrollment.enroll(request.user, new_course.location.course_id) _users_assign_default_role(new_course.location) return JsonResponse({'url': new_location.url_reverse("course/", "")})
def create_new_course(request): """ Create a new course """ if not is_user_in_creator_group(request.user): raise PermissionDenied() org = request.POST.get('org') number = request.POST.get('number') display_name = request.POST.get('display_name') run = request.POST.get('run') try: dest_location = Location('i4x', org, number, 'course', run) except InvalidLocationError as error: return JsonResponse({ "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format( name=display_name, err=error.message)}) # see if the course already exists existing_course = None try: existing_course = modulestore('direct').get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return JsonResponse({ 'ErrMsg': _('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.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) course_search_location = ['i4x', dest_location.org, dest_location.course, 'course', None ] courses = modulestore().get_items(course_search_location) if len(courses) > 0: return JsonResponse({ 'ErrMsg': _('There is already a course defined with the same ' 'organization and course number. Please ' 'change at least one field to be unique.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {'display_name': display_name} modulestore('direct').create_and_save_xmodule( dest_location, metadata=metadata ) new_course = modulestore('direct').get_item(dest_location) # clone a default 'about' overview module as well dest_about_location = dest_location.replace( category='about', name='overview' ) overview_template = AboutDescriptor.get_template('overview.yaml') modulestore('direct').create_and_save_xmodule( dest_about_location, system=new_course.system, definition_data=overview_template.get('data') ) initialize_course_tabs(new_course) create_all_course_groups(request.user, new_course.location) # seed the forums seed_permissions_roles(new_course.location.course_id) # auto-enroll the course creator in the course so that "View Live" will # work. CourseEnrollment.enroll(request.user, new_course.location.course_id) return JsonResponse({'id': new_course.location.url()})
def create_new_course(request): """ Create a new course. Returns the URL for the course overview page. """ if not is_user_in_creator_group(request.user): raise PermissionDenied() org = request.json.get('org') number = request.json.get('number') display_name = request.json.get('display_name') run = request.json.get('run') try: dest_location = Location('i4x', org, number, 'course', run) except InvalidLocationError as error: return JsonResponse({ "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format( name=display_name, err=error.message)}) # see if the course already exists existing_course = None try: existing_course = modulestore('direct').get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return JsonResponse({ 'ErrMsg': _( '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.' ), 'OrgErrMsg': _( 'Please change either the organization or ' 'course number so that it is unique.' ), 'CourseErrMsg': _( 'Please change either the organization or ' 'course number so that it is unique.' ), }) # dhm: this query breaks the abstraction, but I'll fix it when I do my suspended refactoring of this # file for new locators. get_items should accept a query rather than requiring it be a legal location course_search_location = bson.son.SON({ '_id.tag': 'i4x', # cannot pass regex to Location constructor; thus this hack '_id.org': re.compile('^{}$'.format(dest_location.org), re.IGNORECASE), '_id.course': re.compile('^{}$'.format(dest_location.course), re.IGNORECASE), '_id.category': 'course', }) courses = modulestore().collection.find(course_search_location, fields=('_id')) if courses.count() > 0: return JsonResponse({ 'ErrMsg': _( 'There is already a course defined with the same ' 'organization and course number. Please ' 'change at least one field to be unique.'), 'OrgErrMsg': _( 'Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _( 'Please change either the organization or ' 'course number so that it is unique.'), }) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {'display_name': display_name} modulestore('direct').create_and_save_xmodule( dest_location, metadata=metadata ) new_course = modulestore('direct').get_item(dest_location) # clone a default 'about' overview module as well dest_about_location = dest_location.replace( category='about', name='overview' ) overview_template = AboutDescriptor.get_template('overview.yaml') modulestore('direct').create_and_save_xmodule( dest_about_location, system=new_course.system, definition_data=overview_template.get('data') ) initialize_course_tabs(new_course) new_location = loc_mapper().translate_location(new_course.location.course_id, new_course.location, False, True) create_all_course_groups(request.user, new_location) # seed the forums seed_permissions_roles(new_course.location.course_id) # auto-enroll the course creator in the course so that "View Live" will # work. CourseEnrollment.enroll(request.user, new_course.location.course_id) return JsonResponse({'url': new_location.url_reverse("course/", "")})
def create_new_course(request): """ Create a new course """ if not is_user_in_creator_group(request.user): raise PermissionDenied() org = request.POST.get('org') number = request.POST.get('number') display_name = request.POST.get('display_name') run = request.POST.get('run') try: dest_location = Location('i4x', org, number, 'course', run) except InvalidLocationError as error: return JsonResponse({ "ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format( name=display_name, err=error.message)}) # see if the course already exists existing_course = None try: existing_course = modulestore('direct').get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return JsonResponse({ 'ErrMsg': _('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.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) # dhm: this query breaks the abstraction, but I'll fix it when I do my suspended refactoring of this # file for new locators. get_items should accept a query rather than requiring it be a legal location course_search_location = bson.son.SON({ '_id.tag': 'i4x', # cannot pass regex to Location constructor; thus this hack '_id.org': re.compile(dest_location.org, re.IGNORECASE), '_id.course': re.compile(dest_location.course, re.IGNORECASE), '_id.category': 'course', }) courses = modulestore().collection.find(course_search_location, fields=('_id')) if courses.count() > 0: return JsonResponse({ 'ErrMsg': _('There is already a course defined with the same ' 'organization and course number. Please ' 'change at least one field to be unique.'), 'OrgErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), 'CourseErrMsg': _('Please change either the organization or ' 'course number so that it is unique.'), }) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {'display_name': display_name} modulestore('direct').create_and_save_xmodule( dest_location, metadata=metadata ) new_course = modulestore('direct').get_item(dest_location) # clone a default 'about' overview module as well dest_about_location = dest_location.replace( category='about', name='overview' ) overview_template = AboutDescriptor.get_template('overview.yaml') modulestore('direct').create_and_save_xmodule( dest_about_location, system=new_course.system, definition_data=overview_template.get('data') ) initialize_course_tabs(new_course) create_all_course_groups(request.user, new_course.location) # seed the forums seed_permissions_roles(new_course.location.course_id) # auto-enroll the course creator in the course so that "View Live" will # work. CourseEnrollment.enroll(request.user, new_course.location.course_id) return JsonResponse({'id': new_course.location.url()})
def create_new_course(request): """ Create a new course. Returns the URL for the course overview page. """ if not is_user_in_creator_group(request.user): raise PermissionDenied() org = request.json.get("org") number = request.json.get("number") display_name = request.json.get("display_name") run = request.json.get("run") try: dest_location = Location("i4x", org, number, "course", run) except InvalidLocationError as error: return JsonResponse( {"ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(name=display_name, err=error.message)} ) # see if the course already exists existing_course = None try: existing_course = modulestore("direct").get_item(dest_location) except ItemNotFoundError: pass if existing_course is not None: return JsonResponse( { "ErrMsg": _( "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." ), "OrgErrMsg": _("Please change either the organization or " "course number so that it is unique."), "CourseErrMsg": _("Please change either the organization or " "course number so that it is unique."), } ) # dhm: this query breaks the abstraction, but I'll fix it when I do my suspended refactoring of this # file for new locators. get_items should accept a query rather than requiring it be a legal location course_search_location = bson.son.SON( { "_id.tag": "i4x", # cannot pass regex to Location constructor; thus this hack "_id.org": re.compile("^{}$".format(dest_location.org), re.IGNORECASE), "_id.course": re.compile("^{}$".format(dest_location.course), re.IGNORECASE), "_id.category": "course", } ) courses = modulestore().collection.find(course_search_location, fields=("_id")) if courses.count() > 0: return JsonResponse( { "ErrMsg": _( "There is already a course defined with the same " "organization and course number. Please " "change at least one field to be unique." ), "OrgErrMsg": _("Please change either the organization or " "course number so that it is unique."), "CourseErrMsg": _("Please change either the organization or " "course number so that it is unique."), } ) # instantiate the CourseDescriptor and then persist it # note: no system to pass if display_name is None: metadata = {} else: metadata = {"display_name": display_name} modulestore("direct").create_and_save_xmodule(dest_location, metadata=metadata) new_course = modulestore("direct").get_item(dest_location) # clone a default 'about' overview module as well dest_about_location = dest_location.replace(category="about", name="overview") overview_template = AboutDescriptor.get_template("overview.yaml") modulestore("direct").create_and_save_xmodule( dest_about_location, system=new_course.system, definition_data=overview_template.get("data") ) initialize_course_tabs(new_course) new_location = loc_mapper().translate_location(new_course.location.course_id, new_course.location, False, True) create_all_course_groups(request.user, new_location) # seed the forums seed_permissions_roles(new_course.location.course_id) # auto-enroll the course creator in the course so that "View Live" will # work. CourseEnrollment.enroll(request.user, new_course.location.course_id) return JsonResponse({"url": new_location.url_reverse("course/", "")})